diff options
author | Koen Kooi <koen@openembedded.org> | 2006-06-03 09:22:51 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2006-06-03 09:22:51 +0000 |
commit | 026444ac01583e5ee3efbf9884b8e4f4ed978daf (patch) | |
tree | d0c243ea6577905d7d099b03c575b75967e41498 | |
parent | fe2c0499391cae013f559d0376a86868a3614f8b (diff) |
linux-ezx: fix patching brokenness:
* OE uses quilt by default, so we can use it two times in a row
* I'm too lazy to fix it properly for the .1% of OE users that do INHERIT += "patcher"
* The ezx patchset is one jumbo patch now
~lart mickeyl for breaking nearly everybodies build
-rw-r--r-- | packages/linux/linux-ezx/ezx6-jumbo.patch | 75179 | ||||
-rw-r--r-- | packages/linux/linux-ezx_2.6.16.13.bb | 6 |
2 files changed, 75182 insertions, 3 deletions
diff --git a/packages/linux/linux-ezx/ezx6-jumbo.patch b/packages/linux/linux-ezx/ezx6-jumbo.patch new file mode 100644 index 0000000000..5068c51180 --- /dev/null +++ b/packages/linux/linux-ezx/ezx6-jumbo.patch @@ -0,0 +1,75179 @@ +diff -Nurd linux-2.6.16.orig/arch/alpha/kernel/setup.c linux-2.6.16/arch/alpha/kernel/setup.c +--- linux-2.6.16.orig/arch/alpha/kernel/setup.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/alpha/kernel/setup.c 2006-06-03 11:14:55.220494464 +0200 +@@ -24,6 +24,7 @@ + #include <linux/config.h> /* CONFIG_ALPHA_LCA etc */ + #include <linux/mc146818rtc.h> + #include <linux/console.h> ++#include <linux/cpu.h> + #include <linux/errno.h> + #include <linux/init.h> + #include <linux/string.h> +@@ -477,6 +478,22 @@ + #undef PFN_PHYS + #undef PFN_MAX + ++static int __init ++register_cpus(void) ++{ ++ int i; ++ ++ for_each_possible_cpu(i) { ++ struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) ++ return -ENOMEM; ++ register_cpu(p, i, NULL); ++ } ++ return 0; ++} ++ ++arch_initcall(register_cpus); ++ + void __init + setup_arch(char **cmdline_p) + { +diff -Nurd linux-2.6.16.orig/arch/alpha/kernel/smp.c linux-2.6.16/arch/alpha/kernel/smp.c +--- linux-2.6.16.orig/arch/alpha/kernel/smp.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/alpha/kernel/smp.c 2006-06-03 11:14:55.221494312 +0200 +@@ -439,7 +439,7 @@ + if ((cpu->flags & 0x1cc) == 0x1cc) { + smp_num_probed++; + /* Assume here that "whami" == index */ +- cpu_set(i, cpu_possible_map); ++ cpu_set(i, cpu_present_mask); + cpu->pal_revision = boot_cpu_palrev; + } + +@@ -450,9 +450,8 @@ + } + } else { + smp_num_probed = 1; +- cpu_set(boot_cpuid, cpu_possible_map); ++ cpu_set(boot_cpuid, cpu_present_mask); + } +- cpu_present_mask = cpumask_of_cpu(boot_cpuid); + + printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", + smp_num_probed, cpu_possible_map.bits[0]); +@@ -488,9 +487,8 @@ + smp_prepare_boot_cpu(void) + { + /* +- * Mark the boot cpu (current cpu) as both present and online ++ * Mark the boot cpu (current cpu) as online + */ +- cpu_set(smp_processor_id(), cpu_present_mask); + cpu_set(smp_processor_id(), cpu_online_map); + } + +diff -Nurd linux-2.6.16.orig/arch/alpha/lib/strncpy.S linux-2.6.16/arch/alpha/lib/strncpy.S +--- linux-2.6.16.orig/arch/alpha/lib/strncpy.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/alpha/lib/strncpy.S 2006-06-03 11:14:55.221494312 +0200 +@@ -43,8 +43,8 @@ + + .align 4 + $multiword: +- subq $24, 1, $2 # clear the final bits in the prev word +- or $2, $24, $2 ++ subq $27, 1, $2 # clear the final bits in the prev word ++ or $2, $27, $2 + zapnot $1, $2, $1 + subq $18, 1, $18 + +@@ -70,8 +70,8 @@ + bne $18, 0b + + 1: ldq_u $1, 0($16) # clear the leading bits in the final word +- subq $27, 1, $2 +- or $2, $27, $2 ++ subq $24, 1, $2 ++ or $2, $24, $2 + + zap $1, $2, $1 + stq_u $1, 0($16) +diff -Nurd linux-2.6.16.orig/arch/arm/boot/compressed/head.S linux-2.6.16/arch/arm/boot/compressed/head.S +--- linux-2.6.16.orig/arch/arm/boot/compressed/head.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/boot/compressed/head.S 2006-06-03 11:14:56.249338056 +0200 +@@ -10,6 +10,7 @@ + #include <linux/config.h> + #include <linux/linkage.h> + ++#define DEBUG + /* + * Debugging stuff + * +@@ -111,6 +112,11 @@ + mov r0, r0 + .endr + ++ inituart r10, r11 ++ ++ mov r1, #0x300 @ mach_id 0x363 is official EZX ++ orr r1, r1, #0x63 @ bootloader JUMP doesn't set r1 ++ + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address +@@ -137,6 +143,10 @@ + teqp pc, #0x0c000003 @ turn off interrupts + #endif + ++ addruart r11 ++ mov r10, #'d' ++ senduart r10, r11 ++ + /* + * Note that some cache flushing and other stuff may + * be needed here - is there an Angel SWI call for this? +diff -Nurd linux-2.6.16.orig/arch/arm/boot/compressed/head-xscale.S linux-2.6.16/arch/arm/boot/compressed/head-xscale.S +--- linux-2.6.16.orig/arch/arm/boot/compressed/head-xscale.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/boot/compressed/head-xscale.S 2006-06-03 11:14:56.249338056 +0200 +@@ -54,3 +54,6 @@ + str r1, [r0, #0x18] + #endif + ++#ifdef CONFIG_ARCH_EZX ++ mov r7, #MACH_TYPE_EZX ++#endif +diff -Nurd linux-2.6.16.orig/arch/arm/configs/ezx_680_defconfig linux-2.6.16/arch/arm/configs/ezx_680_defconfig +--- linux-2.6.16.orig/arch/arm/configs/ezx_680_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/configs/ezx_680_defconfig 2006-06-03 11:14:56.006374992 +0200 +@@ -0,0 +1,1146 @@ ++# ++# 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_ADVANCED_OPTIONS=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_ADIFCC is not set ++# 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_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_IOP3XX is not set ++# CONFIG_ARCH_IXP1200 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_OMAP is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK 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_ADSBITSY 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_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_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 ++ ++# ++# PXA250/210 based Implementations ++# ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_MAINSTONE is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++ ++# ++# Motorola EZX Platform Implementations ++# ++CONFIG_ARCH_EZX_E680=y ++# CONFIG_ARCH_EZX_A780 is not set ++CONFIG_ARCH_EZX=y ++CONFIG_CPU_BULVERDE=y ++CONFIG_XSCALE_WMMX=y ++ ++# ++# 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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++ ++# ++# Processor Type ++# ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++CONFIG_CPU_XSCALE=y ++CONFIG_CPU_32v5=y ++ ++# ++# Processor Features ++# ++# CONFIG_ARM_THUMB is not set ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_XSCALE_BDI2000 is not set ++CONFIG_DISCONTIGMEM=y ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_KERNEL_START_BOOL is not set ++CONFIG_KERNEL_START=0xc0000000 ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++# CONFIG_CPU_VOLTAGE is not set ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++# CONFIG_PCMCIA is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_MAX_USER_RT_PRIO=100 ++CONFIG_MAX_RT_PRIO=0 ++# CONFIG_XIP_ROM is not set ++ ++# ++# At least one math emulation must be selected ++# ++# CONFIG_FPE_NWFPE is not set ++# CONFIG_FPE_FASTFPE is not set ++# CONFIG_EMBEDDED_OOM_KILLER is not set ++# CONFIG_CPU_BIG_ENDIAN is not set ++# CONFIG_NO_SWAP is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_MULTITHREADED_CORES is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_PM=y ++# CONFIG_DPM is not set ++# CONFIG_DPM_STATS is not set ++# CONFIG_DPM_OPT_STATS is not set ++# CONFIG_DPM_TRACE is not set ++CONFIG_APM=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=3e00 rootfstype=cramfs ip=off" ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_PREEMPT is not set ++ ++# ++# 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_BOOTLDR_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 is not set ++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=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++# CONFIG_MTD_CFI_B4 is not set ++# CONFIG_MTD_CFI_B8 is not set ++CONFIG_MTD_CFI_I1=y ++# CONFIG_MTD_CFI_I2 is not set ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_CSTM_MIPS_IXX is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_IQ80321 is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_FORTUNET 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_LUBBOCK is not set ++# CONFIG_MTD_BULVERDE is not set ++CONFIG_MTD_EZX=y ++# CONFIG_MTD_BRH is not set ++# CONFIG_MTD_OMAP is not set ++# CONFIG_MTD_OMAP_0 is not set ++# CONFIG_MTD_OMAP_1 is not set ++# CONFIG_MTD_XT2000 is not set ++# CONFIG_MTD_PCI is not set ++# CONFIG_MTD_PCMCIA is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BLK_STATS is not set ++ ++# ++# EZX ROFLASH device ++# ++CONFIG_ARCH_EZX_ROFLASH=y ++# CONFIG_L18_DEBUG 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 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=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD 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 ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++ ++# ++# ++# ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++# CONFIG_NET_ETHERNET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_E1000 is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++# CONFIG_PPP_BSDCOMP is not set ++CONFIG_PPPOE=m ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# 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_IDE_MODES 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=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_ADCM2700=y ++CONFIG_I2C_A780_CAMERA=n ++CONFIG_I2C_OV9640=n ++CONFIG_I2C_OV9650=n ++CONFIG_I2C_MT9M111=n ++CONFIG_I2C_ADCM3800=n ++# CONFIG_I2C_MAINBOARD is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_PROC 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 ++# CONFIG_L3_BIT_OMAP_GPIO is not set ++ ++# ++# Other L3 adapters ++# ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++CONFIG_LINUX_LED=y ++# CONFIG_CPCI735_LED is not set ++CONFIG_PXA_E680_LED=y ++# CONFIG_AMD_PM768 is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_RTC=y ++# CONFIG_X1226_RTC is not set ++# CONFIG_RV5C387_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++# CONFIG_BULVERDE_SRAM_DEV is not set ++ ++# ++# Multimedia devices ++# ++CONFIG_VIDEO_DEV=y ++ ++# ++# Video For Linux ++# ++# CONFIG_VIDEO_PROC_FS is not set ++# CONFIG_I2C_PARPORT is not set ++ ++# ++# Video Adapters ++# ++# CONFIG_VIDEO_OMAP is not set ++# CONFIG_VIDEO_PMS is not set ++# CONFIG_VIDEO_CPIA is not set ++# CONFIG_VIDEO_SAA5249 is not set ++# CONFIG_TUNER_3036 is not set ++# CONFIG_VIDEO_STRADIS is not set ++# CONFIG_VIDEO_ZORAN is not set ++# CONFIG_VIDEO_ZORAN_BUZ is not set ++# CONFIG_VIDEO_ZORAN_DC10 is not set ++# CONFIG_VIDEO_ZORAN_LML33 is not set ++# CONFIG_VIDEO_ZR36120 is not set ++# CONFIG_VIDEO_MEYE is not set ++CONFIG_PXA_CAMERA=y ++CONFIG_CAMERA_ADCM2700=y ++CONFIG_CAMERA_OV9640=n ++CONFIG_CAMERA_OV9650=n ++CONFIG_CAMERA_MT9M111=n ++CONFIG_CAMERA_ADCM3800=n ++# CONFIG_VIDEO_CYBERPRO is not set ++ ++# ++# Radio Adapters ++# ++# CONFIG_RADIO_GEMTEK_PCI is not set ++# CONFIG_RADIO_MAXIRADIO is not set ++# CONFIG_RADIO_MAESTRO is not set ++# CONFIG_RADIO_MIROPCM20 is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_FS_POSIX_ACL is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=y ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_CRAMFS=y ++# CONFIG_CRAMFS_LINEAR is not set ++# CONFIG_CRAMFS_LINEAR_XIP is not set ++# CONFIG_ROOT_CRAMFS_LINEAR is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# 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_RT is not set ++# CONFIG_XFS_QUOTA is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED 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=y ++# 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=y ++# 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=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++CONFIG_NLS_UTF8=y ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_PXA_18BPP is not set ++# CONFIG_FB_PXA_VGA is not set ++CONFIG_FB_PXA_QVGA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_MQ200 is not set ++# CONFIG_FB_IT8181 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_ALI5455 is not set ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_FORTE is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++# CONFIG_SOUND_PXA_AC97 is not set ++# CONFIG_SOUND_VIBRATOR is not set ++CONFIG_SOUND_SSP_DRIVER=y ++# CONFIG_SOUND_TVMIXER is not set ++MAKE_FTR_HAPTICS=y ++ ++# ++# 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 ++# CONFIG_MCP_UCB1400_TS is not set ++# CONFIG_KEYPAD_A780 is not set ++CONFIG_KEYPAD_E680=y ++# CONFIG_KEYLIGHT_A780 is not set ++CONFIG_FMRADIO_E680=y ++ ++# ++# USB support ++# ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++# CONFIG_USB_DEVICEFS is not set ++# CONFIG_USB_BANDWIDTH is not set ++# CONFIG_USB_LONG_TIMEOUT is not set ++# CONFIG_USB_EHCI_HCD is not set ++# CONFIG_USB_UHCI is not set ++# CONFIG_USB_UHCI_ALT is not set ++CONFIG_USB_OHCI=y ++CONFIG_USB_OHCI_WMMX=y ++# CONFIG_USB_NON_PCI_OHCI is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_BLUETOOTH is not set ++# CONFIG_USB_MIDI is not set ++# CONFIG_USB_STORAGE is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_DPCM is not set ++# CONFIG_USB_STORAGE_HP8200e is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_HID is not set ++# CONFIG_USB_HIDINPUT is not set ++# CONFIG_USB_HIDDEV is not set ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_AIPTEK is not set ++# CONFIG_USB_WACOM is not set ++# CONFIG_USB_DC2XX is not set ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_SCANNER is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_HPUSBSCSI is not set ++# CONFIG_USB_IBMCAM is not set ++# CONFIG_USB_OV511 is not set ++# CONFIG_USB_PWC is not set ++# CONFIG_USB_SE401 is not set ++# CONFIG_USB_STV680 is not set ++# CONFIG_USB_VICAM is not set ++# CONFIG_USB_DSBR is not set ++# CONFIG_USB_DABUSB is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_CDCETHER is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_USS720 is not set ++ ++# ++# USB Serial Converter support ++# ++# CONFIG_USB_SERIAL is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_AUERSWALD is not set ++# CONFIG_USB_TIGL is not set ++# CONFIG_USB_BRLVGER is not set ++# CONFIG_USB_LCD is not set ++CONFIG_IPC_USB=y ++ ++#DSP LOG BP->AP ++CONFIG_DSPLOG_USB=y ++ ++# ++# USB clients (devices, not hosts) ++# ++CONFIG_USBD=y ++# CONFIG_USBD_HIGH_SPEED is not set ++CONFIG_USBD_NO_SERIAL_NUMBER=y ++CONFIG_USBD_MAXPOWER=250 ++CONFIG_USBD_PROCFS=y ++CONFIG_USBD_PROCFSM=y ++ ++# ++# Network Function ++# ++CONFIG_USBD_NETWORK=y ++CONFIG_USBD_NETWORK_VENDORID=22b8 ++CONFIG_USBD_NETWORK_PRODUCTID=600c ++CONFIG_USBD_NETWORK_BCDDEVICE=0000 ++CONFIG_USBD_NETWORK_MANUFACTURER="Motorola" ++CONFIG_USBD_NETWORK_PRODUCT_NAME="Motorola USBLAN" ++CONFIG_USBD_NETWORK_BLAN=y ++CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg" ++CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf" ++CONFIG_USBD_NETWORK_BLAN_CRC=y ++# CONFIG_USBD_NETWORK_BLAN_PADBEFORE is not set ++# CONFIG_USBD_NETWORK_BLAN_PADAFTER is not set ++# CONFIG_USBD_NETWORK_BLAN_FERMAT is not set ++# CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME is not set ++# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set ++# CONFIG_USBD_NETWORK_BLAN_NONBRIDGED is not set ++# CONFIG_USBD_NETWORK_SAFE is not set ++# CONFIG_USBD_NETWORK_CDC is not set ++# CONFIG_USBD_NETWORK_BASIC is not set ++# CONFIG_USBD_NETWORK_BASIC2 is not set ++# CONFIG_USBD_NETWORK_START_SINGLE is not set ++# CONFIG_USBD_NETWORK_EP0TEST is not set ++ ++# ++# CDC ACM Function ++# ++CONFIG_USBD_ACM=y ++CONFIG_USBD_ACM_VENDORID=22b8 ++CONFIG_USBD_ACM_PRODUCTID=3802 ++CONFIG_USBD_ACM_BCDDEVICE=0000 ++CONFIG_USBD_ACM_MANUFACTURER="Motorola" ++CONFIG_USBD_ACM_PRODUCT_NAME="Motorola USB Modem" ++CONFIG_USBD_ACM_DESC="Acm Cfg" ++CONFIG_USBD_ACM_COMM_INTF="Comm Intf" ++CONFIG_USBD_ACM_DATA_INTF="Data Intf" ++# CONFIG_USBD_ACM_TRACE is not set ++ ++ ++# ++# CDC USB Mass storage Function ++# ++CONFIG_USBD_STORAGE=y ++CONFIG_USBD_STORAGE_VENDORID=0x22B8 ++CONFIG_USBD_STORAGE_PRODUCTID=0x600D ++CONFIG_USBD_STORAGE_OUT_ENDPOINT=1 ++CONFIG_USBD_STORAGE_OUT_PKTSIZE=64 ++CONFIG_USBD_STORAGE_IN_ENDPOINT=2 ++CONFIG_USBD_STORAGE_IN_PKTSIZE=64 ++ ++# ++# Random Mouse Function ++# ++# CONFIG_USBD_MOUSE is not set ++ ++# ++# Cottula/Dalhart (Xscale) support ++# ++# CONFIG_USBD_PXA_BUS is not set ++ ++# ++# Bulverde (Xscale) support ++# ++CONFIG_USBD_WMMX_BUS=y ++# CONFIG_USBD_BI_REGISTER_TRACE is not set ++CONFIG_USBD_BI_DELAY_ENABLE=y ++ ++# ++# PST Function ++# ++CONFIG_USBD_PST=y ++CONFIG_USBD_PST_VENDORID=22b8 ++CONFIG_USBD_PST_PRODUCTID=6009 ++CONFIG_USBD_PST_BCDDEVICE=0001 ++# ++# CFG11 Function ++# ++CONFIG_USBD_CFG11=y ++CONFIG_USBD_CFG11_VENDORID=22b8 ++CONFIG_USBD_CFG11_PRODUCTID=6004 ++CONFIG_USBD_CFG11_BCDDEVICE=0001 ++CONFIG_USBD_CFG11_MANUFACTURER="Belcarra" ++CONFIG_USBD_CFG11_PRODUCT_NAME="Belcarra" ++ ++ ++# ++# DSPLog Function ++# ++CONFIG_USBD_DSP_LOG=y ++CONFIG_USBD_DSP_LOG_VENDORID=22b8 ++CONFIG_USBD_DSP_LOG_PRODUCTID=6009 ++CONFIG_USBD_DSP_LOG_BCDDEVICE=0001 ++ ++ ++# ++# Motorola Network Monitor USB Driver ++# ++CONFIG_USBD_NM=y ++CONFIG_USBD_NM_VENDORID=22b8 ++CONFIG_USBD_NM_PRODUCTID=1004 ++CONFIG_USBD_NM_BCDDEVICE=0002 ++ ++ ++# ++# Kernel tracing ++# ++# CONFIG_TRACE is not set ++# CONFIG_TRACE_BOOT is not set ++ ++# ++# Montavista System Tuning Tools ++# ++# CONFIG_KFI is not set ++# CONFIG_KFI_STATIC_RUN is not set ++# CONFIG_ILATENCY is not set ++# CONFIG_PREEMPT_TIMES is not set ++# CONFIG_MEMORY_ACCOUNTING is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set ++# CONFIG_KGDB is not set ++# CONFIG_KGDB_SERIAL is not set ++# CONFIG_KGDB_CONSOLE is not set ++# CONFIG_KGDB_SYSRQ is not set ++# CONFIG_KGDB_MORE is not set ++# CONFIG_PANIC_LOG is not set ++# CONFIG_CONTEXT_CAP is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m +diff -Nurd linux-2.6.16.orig/arch/arm/configs/ezx_680i_defconfig linux-2.6.16/arch/arm/configs/ezx_680i_defconfig +--- linux-2.6.16.orig/arch/arm/configs/ezx_680i_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/configs/ezx_680i_defconfig 2006-06-03 11:14:56.016373472 +0200 +@@ -0,0 +1,1177 @@ ++# ++# 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_ADVANCED_OPTIONS=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_ADIFCC is not set ++# 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_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_IOP3XX is not set ++# CONFIG_ARCH_IXP1200 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_SHARK is not set ++ ++# ++# PXA250/210 based Implementations ++# ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_MAINSTONE is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++ ++# ++# Motorola EZX Platform Implementations ++# ++CONFIG_ARCH_EZX_E680=y ++# CONFIG_ARCH_EZX_A780 is not set ++CONFIG_ARCH_EZX=y ++CONFIG_CPU_BULVERDE=y ++CONFIG_XSCALE_WMMX=y ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++ ++# ++# Processor Type ++# ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++CONFIG_CPU_XSCALE=y ++CONFIG_CPU_32v5=y ++ ++# ++# Processor Features ++# ++# CONFIG_ARM_THUMB is not set ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_XSCALE_BDI2000 is not set ++CONFIG_DISCONTIGMEM=y ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++CONFIG_KERNEL_START=0xc0000000 ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++# CONFIG_CPU_VOLTAGE is not set ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++# CONFIG_PCMCIA is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_MAX_USER_RT_PRIO=100 ++CONFIG_MAX_RT_PRIO=0 ++# CONFIG_XIP_ROM is not set ++ ++# ++# At least one math emulation must be selected ++# ++# CONFIG_FPE_NWFPE is not set ++# CONFIG_FPE_FASTFPE is not set ++# CONFIG_EMBEDDED_OOM_KILLER is not set ++# CONFIG_NO_SWAP is not set ++# CONFIG_CPU_BIG_ENDIAN is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_MULTITHREADED_CORES is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_PM=y ++# CONFIG_DPM is not set ++# CONFIG_DPM_STATS is not set ++# CONFIG_DPM_OPT_STATS is not set ++# CONFIG_DPM_TRACE is not set ++CONFIG_APM=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=3e00 rootfstype=cramfs ip=off" ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_PREEMPT is not set ++ ++# ++# 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_BOOTLDR_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 is not set ++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=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++# CONFIG_MTD_CFI_B4 is not set ++# CONFIG_MTD_CFI_B8 is not set ++CONFIG_MTD_CFI_I1=y ++# CONFIG_MTD_CFI_I2 is not set ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_CSTM_MIPS_IXX is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_IQ80321 is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_FORTUNET 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_LUBBOCK is not set ++# CONFIG_MTD_BULVERDE is not set ++CONFIG_MTD_EZX=y ++# CONFIG_MTD_BRH is not set ++# CONFIG_MTD_OMAP is not set ++# CONFIG_MTD_OMAP_0 is not set ++# CONFIG_MTD_OMAP_1 is not set ++# CONFIG_MTD_XT2000 is not set ++# CONFIG_MTD_PCI is not set ++# CONFIG_MTD_PCMCIA is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BLK_STATS is not set ++ ++# ++# EZX ROFLASH device ++# ++CONFIG_ARCH_EZX_ROFLASH=y ++# CONFIG_L18_DEBUG 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 is not set ++# CONFIG_NETLINK_DEV is not set ++CONFIG_NETFILTER=y ++# CONFIG_NETFILTER_DEBUG 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=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++ ++# ++# IP: Netfilter Configuration ++# ++# CONFIG_IP_NF_CONNTRACK is not set ++# CONFIG_IP_NF_QUEUE is not set ++# CONFIG_IP_NF_IPTABLES is not set ++# CONFIG_IP_NF_ARPTABLES is not set ++# CONFIG_IP_NF_COMPAT_IPCHAINS is not set ++# CONFIG_IP_NF_COMPAT_IPFWADM is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++ ++# ++# ++# ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++# CONFIG_NET_ETHERNET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_E1000 is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++# CONFIG_PPP_BSDCOMP is not set ++CONFIG_PPPOE=m ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# 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_IDE_MODES 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=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_ADCM2700=y ++# CONFIG_I2C_A780_CAMERA is not set ++# CONFIG_I2C_MAINBOARD is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_PROC 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 ++# CONFIG_L3_BIT_OMAP_GPIO is not set ++ ++# ++# Other L3 adapters ++# ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++CONFIG_LINUX_LED=y ++# CONFIG_CPCI735_LED is not set ++CONFIG_PXA_E680_LED=y ++# CONFIG_AMD_PM768 is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_RTC=y ++# CONFIG_X1226_RTC is not set ++# CONFIG_RV5C387_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++# CONFIG_BULVERDE_SRAM_DEV is not set ++ ++# ++# Multimedia devices ++# ++CONFIG_VIDEO_DEV=y ++ ++# ++# Video For Linux ++# ++# CONFIG_VIDEO_PROC_FS is not set ++# CONFIG_I2C_PARPORT is not set ++ ++# ++# Video Adapters ++# ++# CONFIG_VIDEO_OMAP is not set ++# CONFIG_VIDEO_PMS is not set ++# CONFIG_VIDEO_CPIA is not set ++# CONFIG_VIDEO_SAA5249 is not set ++# CONFIG_TUNER_3036 is not set ++# CONFIG_VIDEO_STRADIS is not set ++# CONFIG_VIDEO_ZORAN is not set ++# CONFIG_VIDEO_ZORAN_BUZ is not set ++# CONFIG_VIDEO_ZORAN_DC10 is not set ++# CONFIG_VIDEO_ZORAN_LML33 is not set ++# CONFIG_VIDEO_ZR36120 is not set ++# CONFIG_VIDEO_MEYE is not set ++CONFIG_PXA_CAMERA=y ++ ++# ++# camera sensor type ++# ++CONFIG_CAMERA_ADCM2700=y ++# CONFIG_CAMERA_MT9M111 is not set ++# CONFIG_CAMERA_OV9640 is not set ++# CONFIG_CAMERA_OV9650 is not set ++# CONFIG_CAMERA_ADCM3800 is not set ++ ++# ++# camera sensor type end ++# ++# CONFIG_VIDEO_CYBERPRO is not set ++ ++# ++# Radio Adapters ++# ++# CONFIG_RADIO_GEMTEK_PCI is not set ++# CONFIG_RADIO_MAXIRADIO is not set ++# CONFIG_RADIO_MAESTRO is not set ++# CONFIG_RADIO_MIROPCM20 is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_FS_POSIX_ACL is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=y ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_CRAMFS=y ++# CONFIG_CRAMFS_LINEAR is not set ++# CONFIG_CRAMFS_LINEAR_XIP is not set ++# CONFIG_ROOT_CRAMFS_LINEAR is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# 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_RT is not set ++# CONFIG_XFS_QUOTA is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED 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=y ++# 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=y ++# 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=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++CONFIG_NLS_UTF8=y ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_PXA_18BPP is not set ++# CONFIG_FB_PXA_19BPP is not set ++# CONFIG_FB_PXA_24BPP is not set ++# CONFIG_FB_PXA_25BPP is not set ++# CONFIG_FB_PXA_VGA is not set ++CONFIG_FB_PXA_QVGA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_MQ200 is not set ++# CONFIG_FB_IT8181 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++CONFIG_FBCON_CFB24=y ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_ALI5455 is not set ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++CONFIG_SOUND_MIDI=m ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_FORTE is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++# CONFIG_SOUND_PXA_AC97 is not set ++# CONFIG_SOUND_VIBRATOR is not set ++CONFIG_SOUND_SSP_DRIVER=y ++# CONFIG_SOUND_TVMIXER is not set ++MAKE_FTR_HAPTICS=y ++ ++# ++# 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 ++# CONFIG_MCP_UCB1400_TS is not set ++# CONFIG_KEYPAD_A780 is not set ++CONFIG_KEYPAD_E680=y ++# CONFIG_KEYLIGHT_A780 is not set ++CONFIG_FMRADIO_E680=y ++ ++# ++# USB support ++# ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++ ++# ++# Miscellaneous USB options ++# ++# CONFIG_USB_DEVICEFS is not set ++# CONFIG_USB_BANDWIDTH is not set ++# CONFIG_USB_LONG_TIMEOUT is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_EHCI_HCD is not set ++# CONFIG_USB_UHCI is not set ++# CONFIG_USB_UHCI_ALT is not set ++CONFIG_USB_OHCI=y ++CONFIG_USB_OHCI_WMMX=y ++# CONFIG_USB_NON_PCI_OHCI is not set ++ ++# ++# USB Device Class drivers ++# ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_BLUETOOTH is not set ++# CONFIG_USB_MIDI is not set ++ ++# ++# SCSI support is needed for USB Storage ++# ++# CONFIG_USB_STORAGE is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_DPCM is not set ++# CONFIG_USB_STORAGE_HP8200e is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++ ++# ++# USB Human Interface Devices (HID) ++# ++# CONFIG_USB_HID is not set ++# CONFIG_USB_HIDINPUT is not set ++# CONFIG_USB_HIDDEV is not set ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_AIPTEK is not set ++# CONFIG_USB_WACOM is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_DC2XX is not set ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_SCANNER is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_HPUSBSCSI is not set ++ ++# ++# USB Multimedia devices ++# ++# CONFIG_USB_IBMCAM is not set ++# CONFIG_USB_OV511 is not set ++# CONFIG_USB_PWC is not set ++# CONFIG_USB_SE401 is not set ++# CONFIG_USB_STV680 is not set ++# CONFIG_USB_VICAM is not set ++# CONFIG_USB_DSBR is not set ++# CONFIG_USB_DABUSB is not set ++ ++# ++# USB Network adaptors ++# ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_CDCETHER is not set ++# CONFIG_USB_USBNET is not set ++ ++# ++# USB port drivers ++# ++# CONFIG_USB_USS720 is not set ++ ++# ++# USB Serial Converter support ++# ++# CONFIG_USB_SERIAL is not set ++ ++# ++# USB Miscellaneous drivers ++# ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_AUERSWALD is not set ++# CONFIG_USB_TIGL is not set ++# CONFIG_USB_BRLVGER is not set ++# CONFIG_USB_LCD is not set ++ ++# ++# USB IPC driver ++# ++CONFIG_IPC_USB=y ++ ++# ++# USB DSPLOG driver ++# ++CONFIG_DSPLOG_USB=y ++ ++# ++# USB clients (devices, not hosts) ++# ++CONFIG_USBD=y ++ ++# ++# ++# ++# CONFIG_USBD_HIGH_SPEED is not set ++CONFIG_USBD_NO_SERIAL_NUMBER=y ++CONFIG_USBD_MAXPOWER=250 ++ ++# ++# ++# ++CONFIG_USBD_PROCFS=y ++CONFIG_USBD_PROCFSM=y ++ ++# ++# Function Drivers ++# ++ ++# ++# Network Function ++# ++CONFIG_USBD_NETWORK=y ++CONFIG_USBD_NETWORK_VENDORID=22b8 ++CONFIG_USBD_NETWORK_PRODUCTID=600c ++CONFIG_USBD_NETWORK_BCDDEVICE=0000 ++CONFIG_USBD_NETWORK_MANUFACTURER="Motorola" ++CONFIG_USBD_NETWORK_PRODUCT_NAME="Motorola USBLAN" ++ ++# ++# ++# ++CONFIG_USBD_NETWORK_BLAN=y ++CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg" ++CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf" ++CONFIG_USBD_NETWORK_BLAN_CRC=y ++# CONFIG_USBD_NETWORK_BLAN_PADBEFORE is not set ++# CONFIG_USBD_NETWORK_BLAN_PADAFTER is not set ++# CONFIG_USBD_NETWORK_BLAN_FERMAT is not set ++# CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME is not set ++# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set ++# CONFIG_USBD_NETWORK_BLAN_NONBRIDGED is not set ++ ++# ++# ++# ++# CONFIG_USBD_NETWORK_SAFE is not set ++# CONFIG_USBD_NETWORK_CDC is not set ++# CONFIG_USBD_NETWORK_BASIC is not set ++# CONFIG_USBD_NETWORK_BASIC2 is not set ++ ++# ++# ++# ++# CONFIG_USBD_NETWORK_START_SINGLE is not set ++# CONFIG_USBD_NETWORK_EP0TEST is not set ++ ++# ++# CDC ACM Function ++# ++CONFIG_USBD_ACM=y ++CONFIG_USBD_ACM_VENDORID=22b8 ++CONFIG_USBD_ACM_PRODUCTID=3802 ++CONFIG_USBD_ACM_BCDDEVICE=0000 ++CONFIG_USBD_ACM_MANUFACTURER="Motorola" ++CONFIG_USBD_ACM_PRODUCT_NAME="Motorola USB Modem" ++CONFIG_USBD_ACM_DESC="Acm Cfg" ++CONFIG_USBD_ACM_COMM_INTF="Comm Intf" ++CONFIG_USBD_ACM_DATA_INTF="Data Intf" ++# CONFIG_USBD_ACM_TRACE is not set ++ ++# ++# ++# ++ ++# ++# Random Mouse Function ++# ++# CONFIG_USBD_MOUSE is not set ++ ++# ++# Mass Storage Function ++# ++CONFIG_USBD_STORAGE=y ++CONFIG_USBD_STORAGE_VENDORID=22B8 ++CONFIG_USBD_STORAGE_PRODUCTID=600D ++CONFIG_USBD_STORAGE_OUT_ENDPOINT=1 ++CONFIG_USBD_STORAGE_OUT_PKTSIZE=64 ++CONFIG_USBD_STORAGE_IN_ENDPOINT=2 ++CONFIG_USBD_STORAGE_IN_PKTSIZE=64 ++ ++# ++# Bus Interface ++# ++ ++# ++# Cottula/Dalhart (Xscale) support ++# ++# CONFIG_USBD_PXA_BUS is not set ++ ++# ++# Bulverde (Xscale) support ++# ++CONFIG_USBD_WMMX_BUS=y ++# CONFIG_USBD_BI_REGISTER_TRACE is not set ++CONFIG_USBD_BI_DELAY_ENABLE=y ++ ++# ++# PST Function ++# ++CONFIG_USBD_PST=y ++CONFIG_USBD_PST_VENDORID=22b8 ++CONFIG_USBD_PST_PRODUCTID=6009 ++CONFIG_USBD_PST_BCDDEVICE=0001 ++ ++# ++# cfg11 Function ++# ++CONFIG_USBD_CFG11=y ++CONFIG_USBD_CFG11_VENDORID=22b8 ++CONFIG_USBD_CFG11_PRODUCTID=6004 ++CONFIG_USBD_CFG11_BCDDEVICE=0001 ++CONFIG_USBD_CFG11_MANUFACTURER="Belcarra" ++CONFIG_USBD_CFG11_PRODUCT_NAME="Belcarra" ++ ++# ++# Motorola DSP Log Function ++# ++CONFIG_USBD_DSP_LOG=y ++CONFIG_USBD_DSP_LOG_VENDORID=22b8 ++CONFIG_USBD_DSP_LOG_PRODUCTID=6009 ++CONFIG_USBD_DSP_LOG_BCDDEVICE=0001 ++ ++# ++# Motorola Network Monitor USB Function ++# ++CONFIG_USBD_NM=y ++CONFIG_USBD_NM_VENDORID=22b8 ++CONFIG_USBD_NM_PRODUCTID=1004 ++CONFIG_USBD_NM_BCDDEVICE=0002 ++ ++# ++# MMC/SD Card support ++# ++CONFIG_MMC=m ++CONFIG_MMC_DEBUG=y ++CONFIG_MMC_DEBUG_VERBOSE=0 ++ ++# ++# MMC Controllers device drivers ++# ++CONFIG_EZX_MMC=m ++ ++# ++# Kernel tracing ++# ++# CONFIG_TRACE is not set ++# CONFIG_TRACE_BOOT is not set ++ ++# ++# Montavista System Tuning Tools ++# ++# CONFIG_KFI is not set ++# CONFIG_KFI_STATIC_RUN is not set ++# CONFIG_ILATENCY is not set ++# CONFIG_PREEMPT_TIMES is not set ++# CONFIG_MEMORY_ACCOUNTING is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set ++# CONFIG_KGDB is not set ++# CONFIG_KGDB_SERIAL is not set ++# CONFIG_KGDB_CONSOLE is not set ++# CONFIG_KGDB_SYSRQ is not set ++# CONFIG_KGDB_MORE is not set ++# CONFIG_PANIC_LOG is not set ++# CONFIG_CONTEXT_CAP is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m +diff -Nurd linux-2.6.16.orig/arch/arm/configs/ezx_780_defconfig linux-2.6.16/arch/arm/configs/ezx_780_defconfig +--- linux-2.6.16.orig/arch/arm/configs/ezx_780_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/configs/ezx_780_defconfig 2006-06-03 11:14:56.018373168 +0200 +@@ -0,0 +1,1053 @@ ++# ++# Automatically generated by make menuconfig: 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_ADVANCED_OPTIONS=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_ADIFCC is not set ++# 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_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_IOP3XX is not set ++# CONFIG_ARCH_IXP1200 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_SHARK is not set ++ ++# ++# PXA250/210 based Implementations ++# ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_MAINSTONE is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++ ++# ++# Motorola EZX Platform Implementations ++# ++# CONFIG_ARCH_EZX_E680 is not set ++CONFIG_ARCH_EZX_A780=y ++CONFIG_ARCH_EZX=y ++CONFIG_CPU_BULVERDE=y ++CONFIG_XSCALE_WMMX=y ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++CONFIG_CPU_XSCALE=y ++CONFIG_CPU_32v5=y ++# CONFIG_ARM_THUMB is not set ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_XSCALE_BDI2000 is not set ++CONFIG_DISCONTIGMEM=y ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_KERNEL_START_BOOL is not set ++CONFIG_KERNEL_START=0xc0000000 ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++# CONFIG_CPU_VOLTAGE is not set ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++# CONFIG_PCMCIA is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_MAX_USER_RT_PRIO=100 ++CONFIG_MAX_RT_PRIO=0 ++# CONFIG_XIP_ROM is not set ++# CONFIG_FPE_NWFPE is not set ++# CONFIG_FPE_FASTFPE is not set ++# CONFIG_EMBEDDED_OOM_KILLER is not set ++# CONFIG_NO_SWAP is not set ++# CONFIG_CPU_BIG_ENDIAN is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_MULTITHREADED_CORES is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_PM=y ++# CONFIG_DPM is not set ++# CONFIG_DPM_STATS is not set ++# CONFIG_DPM_OPT_STATS is not set ++# CONFIG_DPM_TRACE is not set ++CONFIG_APM=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=3e00 rootfstype=cramfs ip=off" ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_PREEMPT is not set ++ ++# ++# 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_BOOTLDR_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++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 is not set ++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=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++# CONFIG_MTD_CFI_B4 is not set ++# CONFIG_MTD_CFI_B8 is not set ++CONFIG_MTD_CFI_I1=y ++# CONFIG_MTD_CFI_I2 is not set ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_CSTM_MIPS_IXX is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_IQ80321 is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_FORTUNET 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_LUBBOCK is not set ++# CONFIG_MTD_BULVERDE is not set ++CONFIG_MTD_EZX=y ++# CONFIG_MTD_BRH is not set ++# CONFIG_MTD_OMAP is not set ++# CONFIG_MTD_OMAP_0 is not set ++# CONFIG_MTD_OMAP_1 is not set ++# CONFIG_MTD_XT2000 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 ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BLK_STATS is not set ++ ++# ++# EZX ROFLASH device ++# ++CONFIG_ARCH_EZX_ROFLASH=y ++# CONFIG_L18_DEBUG 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 is not set ++# CONFIG_NETLINK_DEV is not set ++CONFIG_NETFILTER=y ++# 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=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD 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 ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# Netfilter options ++ ++CONFIG_NETFILTER_DEBUG=N ++CONFIG_IP_NF_CONNTRACK=N ++CONFIG_IP_NF_QUEUE=N ++CONFIG_IP_NF_IPTABLES=N ++CONFIG_IP_NF_ARPTABLES=N ++CONFIG_IP_NF_COMPAT_IPCHAINS=N ++CONFIG_IP_NF_COMPAT_IPFWADM=N ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++# CONFIG_NET_ETHERNET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_E1000 is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++# CONFIG_PPP_BSDCOMP is not set ++CONFIG_PPPOE=m ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# 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_IDE_MODES 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=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_ADCM2700=n ++CONFIG_I2C_A780_CAMERA=y ++CONFIG_I2C_OV9640=y ++CONFIG_I2C_OV9650=y ++CONFIG_I2C_MT9M111=y ++CONFIG_I2C_ADCM3800=y ++# CONFIG_I2C_MAINBOARD is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_PROC 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 ++# CONFIG_L3_BIT_OMAP_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_LINUX_LED is not set ++# CONFIG_CPCI735_LED is not set ++# CONFIG_PXA_E680_LED is not set ++# CONFIG_AMD_PM768 is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_RTC=y ++# CONFIG_X1226_RTC is not set ++# CONFIG_RV5C387_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++# CONFIG_BULVERDE_SRAM_DEV is not set ++ ++# ++# Multimedia devices ++# ++CONFIG_VIDEO_DEV=y ++ ++# ++# Video For Linux ++# ++# CONFIG_VIDEO_PROC_FS is not set ++# CONFIG_I2C_PARPORT is not set ++# CONFIG_VIDEO_OMAP is not set ++# CONFIG_VIDEO_PMS is not set ++# CONFIG_VIDEO_CPIA is not set ++# CONFIG_VIDEO_SAA5249 is not set ++# CONFIG_TUNER_3036 is not set ++# CONFIG_VIDEO_STRADIS is not set ++# CONFIG_VIDEO_ZORAN is not set ++# CONFIG_VIDEO_ZORAN_BUZ is not set ++# CONFIG_VIDEO_ZORAN_DC10 is not set ++# CONFIG_VIDEO_ZORAN_LML33 is not set ++# CONFIG_VIDEO_ZR36120 is not set ++# CONFIG_VIDEO_MEYE is not set ++CONFIG_PXA_CAMERA=y ++# CONFIG_CAMERA_ADCM2700 is not set ++CONFIG_CAMERA_OV9640=y ++CONFIG_CAMERA_OV9650=y ++CONFIG_CAMERA_MT9M111=y ++CONFIG_CAMERA_ADCM3800=y ++# CONFIG_VIDEO_CYBERPRO is not set ++ ++# ++# Radio Adapters ++# ++# CONFIG_RADIO_GEMTEK_PCI is not set ++# CONFIG_RADIO_MAXIRADIO is not set ++# CONFIG_RADIO_MAESTRO is not set ++# CONFIG_RADIO_MIROPCM20 is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_FS_POSIX_ACL is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=y ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_CRAMFS=y ++# CONFIG_CRAMFS_LINEAR is not set ++# CONFIG_CRAMFS_LINEAR_XIP is not set ++# CONFIG_ROOT_CRAMFS_LINEAR is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# 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_RT is not set ++# CONFIG_XFS_QUOTA is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED 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=y ++# 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=y ++# 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=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++CONFIG_NLS_UTF8=y ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_PXA_18BPP is not set ++# CONFIG_FB_PXA_19BPP is not set ++# CONFIG_FB_PXA_24BPP is not set ++# CONFIG_FB_PXA_25BPP is not set ++# CONFIG_FB_PXA_VGA is not set ++CONFIG_FB_PXA_QVGA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_MQ200 is not set ++# CONFIG_FB_IT8181 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++CONFIG_FBCON_CFB24=y ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_ALI5455 is not set ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_MIDI is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_FORTE is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++# CONFIG_SOUND_PXA_AC97 is not set ++CONFIG_SOUND_VIBRATOR=y ++CONFIG_SOUND_SSP_DRIVER=y ++# CONFIG_SOUND_TVMIXER is not set ++# MAKE_FTR_HAPTICS 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 ++# CONFIG_MCP_UCB1400_TS is not set ++CONFIG_KEYPAD_A780=y ++# CONFIG_KEYPAD_E680 is not set ++CONFIG_KEYLIGHT_A780=y ++ ++# ++# USB support ++# ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++# CONFIG_USB_DEVICEFS is not set ++# CONFIG_USB_BANDWIDTH is not set ++# CONFIG_USB_LONG_TIMEOUT is not set ++# CONFIG_USB_EHCI_HCD is not set ++# CONFIG_USB_UHCI is not set ++# CONFIG_USB_UHCI_ALT is not set ++CONFIG_USB_OHCI=y ++CONFIG_USB_OHCI_WMMX=y ++# CONFIG_USB_NON_PCI_OHCI is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_BLUETOOTH is not set ++# CONFIG_USB_MIDI is not set ++# CONFIG_USB_STORAGE is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_DPCM is not set ++# CONFIG_USB_STORAGE_HP8200e is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_HID is not set ++# CONFIG_USB_HIDINPUT is not set ++# CONFIG_USB_HIDDEV is not set ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_AIPTEK is not set ++# CONFIG_USB_WACOM is not set ++# CONFIG_USB_DC2XX is not set ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_SCANNER is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_HPUSBSCSI is not set ++# CONFIG_USB_IBMCAM is not set ++# CONFIG_USB_OV511 is not set ++# CONFIG_USB_PWC is not set ++# CONFIG_USB_SE401 is not set ++# CONFIG_USB_STV680 is not set ++# CONFIG_USB_VICAM is not set ++# CONFIG_USB_DSBR is not set ++# CONFIG_USB_DABUSB is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_CDCETHER is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_USS720 is not set ++ ++# ++# USB Serial Converter support ++# ++# CONFIG_USB_SERIAL is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_AUERSWALD is not set ++# CONFIG_USB_TIGL is not set ++# CONFIG_USB_BRLVGER is not set ++# CONFIG_USB_LCD is not set ++CONFIG_IPC_USB=y ++ ++#DSP LOG BP->AP ++CONFIG_DSPLOG_USB=y ++ ++# ++# USB clients (devices, not hosts) ++# ++CONFIG_USBD=y ++# CONFIG_USBD_HIGH_SPEED is not set ++CONFIG_USBD_NO_SERIAL_NUMBER=y ++CONFIG_USBD_MAXPOWER=250 ++CONFIG_USBD_PROCFS=y ++CONFIG_USBD_PROCFSM=y ++ ++# ++# Network Function ++# ++CONFIG_USBD_NETWORK=y ++CONFIG_USBD_NETWORK_VENDORID=22b8 ++CONFIG_USBD_NETWORK_PRODUCTID=600c ++CONFIG_USBD_NETWORK_BCDDEVICE=0000 ++CONFIG_USBD_NETWORK_MANUFACTURER="Motorola" ++CONFIG_USBD_NETWORK_PRODUCT_NAME="Motorola USBLAN" ++CONFIG_USBD_NETWORK_BLAN=y ++CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg" ++CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf" ++CONFIG_USBD_NETWORK_BLAN_CRC=y ++# CONFIG_USBD_NETWORK_BLAN_PADBEFORE is not set ++# CONFIG_USBD_NETWORK_BLAN_PADAFTER is not set ++# CONFIG_USBD_NETWORK_BLAN_FERMAT is not set ++# CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME is not set ++# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set ++# CONFIG_USBD_NETWORK_BLAN_NONBRIDGED is not set ++# CONFIG_USBD_NETWORK_SAFE is not set ++# CONFIG_USBD_NETWORK_CDC is not set ++# CONFIG_USBD_NETWORK_BASIC is not set ++# CONFIG_USBD_NETWORK_BASIC2 is not set ++# CONFIG_USBD_NETWORK_START_SINGLE is not set ++# CONFIG_USBD_NETWORK_EP0TEST is not set ++ ++# ++# CDC ACM Function ++# ++CONFIG_USBD_ACM=y ++CONFIG_USBD_ACM_VENDORID=22b8 ++CONFIG_USBD_ACM_PRODUCTID=3802 ++CONFIG_USBD_ACM_BCDDEVICE=0000 ++CONFIG_USBD_ACM_MANUFACTURER="Motorola" ++CONFIG_USBD_ACM_PRODUCT_NAME="Motorola USB Modem" ++CONFIG_USBD_ACM_DESC="Acm Cfg" ++CONFIG_USBD_ACM_COMM_INTF="Comm Intf" ++CONFIG_USBD_ACM_DATA_INTF="Data Intf" ++# CONFIG_USBD_ACM_TRACE is not set ++ ++# ++# CDC USB Mass storage Function ++# ++CONFIG_USBD_STORAGE=y ++CONFIG_USBD_STORAGE_VENDORID=0x22B8 ++CONFIG_USBD_STORAGE_PRODUCTID=0x604C ++CONFIG_USBD_STORAGE_OUT_ENDPOINT=1 ++CONFIG_USBD_STORAGE_OUT_PKTSIZE=64 ++CONFIG_USBD_STORAGE_IN_ENDPOINT=2 ++CONFIG_USBD_STORAGE_IN_PKTSIZE=64 ++ ++# ++# Random Mouse Function ++# ++# CONFIG_USBD_MOUSE is not set ++ ++# ++# Cottula/Dalhart (Xscale) support ++# ++# CONFIG_USBD_PXA_BUS is not set ++ ++# ++# Bulverde (Xscale) support ++# ++CONFIG_USBD_WMMX_BUS=y ++# CONFIG_USBD_BI_REGISTER_TRACE is not set ++CONFIG_USBD_BI_DELAY_ENABLE=y ++ ++# ++# PST Function ++# ++CONFIG_USBD_PST=y ++CONFIG_USBD_PST_VENDORID=22b8 ++CONFIG_USBD_PST_PRODUCTID=6009 ++CONFIG_USBD_PST_BCDDEVICE=0001 ++ ++# ++#CFG11 Function ++# ++CONFIG_USBD_CFG11=y ++CONFIG_USBD_CFG11_VENDORID=22b8 ++CONFIG_USBD_CFG11_PRODUCTID=6004 ++CONFIG_USBD_CFG11_BCDDEVICE=0001 ++CONFIG_USBD_CFG11_MANUFACTURER="Belcarra" ++CONFIG_USBD_CFG11_PRODUCT_NAME="Belcarra" ++# ++# DSPLog Function ++# ++CONFIG_USBD_DSP_LOG=y ++CONFIG_USBD_DSP_LOG_VENDORID=22b8 ++CONFIG_USBD_DSP_LOG_PRODUCTID=6009 ++CONFIG_USBD_DSP_LOG_BCDDEVICE=0001 ++ ++# ++# Motorola Network Monitor USB Driver ++# ++CONFIG_USBD_NM=y ++CONFIG_USBD_NM_VENDORID=22b8 ++CONFIG_USBD_NM_PRODUCTID=1004 ++CONFIG_USBD_NM_BCDDEVICE=0002 ++ ++ ++# ++# MMC/SD Card support ++# ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++CONFIG_EZX_MMC=y ++ ++# ++# Kernel tracing ++# ++# CONFIG_TRACE is not set ++# CONFIG_TRACE_BOOT is not set ++ ++# ++# Montavista System Tuning Tools ++# ++# CONFIG_KFI is not set ++# CONFIG_KFI_STATIC_RUN is not set ++# CONFIG_ILATENCY is not set ++# CONFIG_PREEMPT_TIMES is not set ++# CONFIG_MEMORY_ACCOUNTING is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set ++# CONFIG_KGDB is not set ++# CONFIG_KGDB_SERIAL is not set ++# CONFIG_KGDB_CONSOLE is not set ++# CONFIG_KGDB_SYSRQ is not set ++# CONFIG_KGDB_MORE is not set ++# CONFIG_PANIC_LOG is not set ++# CONFIG_CONTEXT_CAP is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m +diff -Nurd linux-2.6.16.orig/arch/arm/configs/ezx_780ramdisk_defconfig linux-2.6.16/arch/arm/configs/ezx_780ramdisk_defconfig +--- linux-2.6.16.orig/arch/arm/configs/ezx_780ramdisk_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/configs/ezx_780ramdisk_defconfig 2006-06-03 11:14:56.019373016 +0200 +@@ -0,0 +1,1054 @@ ++# ++# Automatically generated by make menuconfig: 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_ADVANCED_OPTIONS=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_ADIFCC is not set ++# 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_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_IOP3XX is not set ++# CONFIG_ARCH_IXP1200 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_SHARK is not set ++ ++# ++# PXA250/210 based Implementations ++# ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_MAINSTONE is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++ ++# ++# Motorola EZX Platform Implementations ++# ++# CONFIG_ARCH_EZX_E680 is not set ++CONFIG_ARCH_EZX_A780=y ++CONFIG_ARCH_EZX=y ++CONFIG_CPU_BULVERDE=y ++CONFIG_XSCALE_WMMX=y ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++CONFIG_CPU_XSCALE=y ++CONFIG_CPU_32v5=y ++# CONFIG_ARM_THUMB is not set ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_XSCALE_BDI2000 is not set ++CONFIG_DISCONTIGMEM=y ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_KERNEL_START_BOOL is not set ++CONFIG_KERNEL_START=0xc0000000 ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++# CONFIG_CPU_VOLTAGE is not set ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++# CONFIG_PCMCIA is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_MAX_USER_RT_PRIO=100 ++CONFIG_MAX_RT_PRIO=0 ++# CONFIG_XIP_ROM is not set ++# CONFIG_FPE_NWFPE is not set ++# CONFIG_FPE_FASTFPE is not set ++# CONFIG_EMBEDDED_OOM_KILLER is not set ++# CONFIG_NO_SWAP is not set ++# CONFIG_CPU_BIG_ENDIAN is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_MULTITHREADED_CORES is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_PM=y ++# CONFIG_DPM is not set ++# CONFIG_DPM_STATS is not set ++# CONFIG_DPM_OPT_STATS is not set ++# CONFIG_DPM_TRACE is not set ++CONFIG_APM=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/ram0 init=/linuxrc initrd=0xa0400000,0x400000 ip=off console=ttyS2, 115200n8" ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_PREEMPT is not set ++ ++# ++# 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_BOOTLDR_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++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 is not set ++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=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++# CONFIG_MTD_CFI_B4 is not set ++# CONFIG_MTD_CFI_B8 is not set ++CONFIG_MTD_CFI_I1=y ++# CONFIG_MTD_CFI_I2 is not set ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_CSTM_MIPS_IXX is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_IQ80321 is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_FORTUNET 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_LUBBOCK is not set ++# CONFIG_MTD_BULVERDE is not set ++CONFIG_MTD_EZX=y ++# CONFIG_MTD_BRH is not set ++# CONFIG_MTD_OMAP is not set ++# CONFIG_MTD_OMAP_0 is not set ++# CONFIG_MTD_OMAP_1 is not set ++# CONFIG_MTD_XT2000 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 ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_BLK_STATS=y ++ ++# ++# EZX ROFLASH device ++# ++CONFIG_ARCH_EZX_ROFLASH=y ++# CONFIG_L18_DEBUG 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 is not set ++# CONFIG_NETLINK_DEV is not set ++CONFIG_NETFILTER=y ++# 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=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD 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 ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# Netfilter options ++ ++CONFIG_NETFILTER_DEBUG=N ++CONFIG_IP_NF_CONNTRACK=N ++CONFIG_IP_NF_QUEUE=N ++CONFIG_IP_NF_IPTABLES=N ++CONFIG_IP_NF_ARPTABLES=N ++CONFIG_IP_NF_COMPAT_IPCHAINS=N ++CONFIG_IP_NF_COMPAT_IPFWADM=N ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++# CONFIG_NET_ETHERNET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_E1000 is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++# CONFIG_PPP_BSDCOMP is not set ++CONFIG_PPPOE=m ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# 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_IDE_MODES 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=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_ADCM2700=n ++CONFIG_I2C_A780_CAMERA=y ++CONFIG_I2C_OV9640=y ++CONFIG_I2C_OV9650=y ++CONFIG_I2C_MT9M111=y ++CONFIG_I2C_ADCM3800=y ++# CONFIG_I2C_MAINBOARD is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_PROC 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 ++# CONFIG_L3_BIT_OMAP_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_LINUX_LED is not set ++# CONFIG_CPCI735_LED is not set ++# CONFIG_PXA_E680_LED is not set ++# CONFIG_AMD_PM768 is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_RTC=y ++# CONFIG_X1226_RTC is not set ++# CONFIG_RV5C387_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++# CONFIG_BULVERDE_SRAM_DEV is not set ++ ++# ++# Multimedia devices ++# ++CONFIG_VIDEO_DEV=y ++ ++# ++# Video For Linux ++# ++# CONFIG_VIDEO_PROC_FS is not set ++# CONFIG_I2C_PARPORT is not set ++# CONFIG_VIDEO_OMAP is not set ++# CONFIG_VIDEO_PMS is not set ++# CONFIG_VIDEO_CPIA is not set ++# CONFIG_VIDEO_SAA5249 is not set ++# CONFIG_TUNER_3036 is not set ++# CONFIG_VIDEO_STRADIS is not set ++# CONFIG_VIDEO_ZORAN is not set ++# CONFIG_VIDEO_ZORAN_BUZ is not set ++# CONFIG_VIDEO_ZORAN_DC10 is not set ++# CONFIG_VIDEO_ZORAN_LML33 is not set ++# CONFIG_VIDEO_ZR36120 is not set ++# CONFIG_VIDEO_MEYE is not set ++CONFIG_PXA_CAMERA=y ++# CONFIG_CAMERA_ADCM2700 is not set ++CONFIG_CAMERA_OV9640=y ++CONFIG_CAMERA_OV9650=y ++CONFIG_CAMERA_MT9M111=y ++CONFIG_CAMERA_ADCM3800=y ++# CONFIG_VIDEO_CYBERPRO is not set ++ ++# ++# Radio Adapters ++# ++# CONFIG_RADIO_GEMTEK_PCI is not set ++# CONFIG_RADIO_MAXIRADIO is not set ++# CONFIG_RADIO_MAESTRO is not set ++# CONFIG_RADIO_MIROPCM20 is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_FS_POSIX_ACL is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=y ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_CRAMFS=y ++# CONFIG_CRAMFS_LINEAR is not set ++# CONFIG_CRAMFS_LINEAR_XIP is not set ++# CONFIG_ROOT_CRAMFS_LINEAR is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++CONFIG_ROMFS_FS=y ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_XFS_RT is not set ++# CONFIG_XFS_QUOTA is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED 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=y ++# 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=y ++# 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=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++CONFIG_NLS_UTF8=y ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_PXA_18BPP is not set ++# CONFIG_FB_PXA_19BPP is not set ++# CONFIG_FB_PXA_24BPP is not set ++# CONFIG_FB_PXA_25BPP is not set ++# CONFIG_FB_PXA_VGA is not set ++CONFIG_FB_PXA_QVGA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_MQ200 is not set ++# CONFIG_FB_IT8181 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++CONFIG_FBCON_CFB24=y ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_ALI5455 is not set ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_MIDI is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_FORTE is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++# CONFIG_SOUND_PXA_AC97 is not set ++CONFIG_SOUND_VIBRATOR=y ++CONFIG_SOUND_SSP_DRIVER=y ++# CONFIG_SOUND_TVMIXER is not set ++# MAKE_FTR_HAPTICS 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 ++# CONFIG_MCP_UCB1400_TS is not set ++CONFIG_KEYPAD_A780=y ++# CONFIG_KEYPAD_E680 is not set ++CONFIG_KEYLIGHT_A780=y ++ ++# ++# USB support ++# ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++# CONFIG_USB_DEVICEFS is not set ++# CONFIG_USB_BANDWIDTH is not set ++# CONFIG_USB_LONG_TIMEOUT is not set ++# CONFIG_USB_EHCI_HCD is not set ++# CONFIG_USB_UHCI is not set ++# CONFIG_USB_UHCI_ALT is not set ++CONFIG_USB_OHCI=y ++CONFIG_USB_OHCI_WMMX=y ++# CONFIG_USB_NON_PCI_OHCI is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_BLUETOOTH is not set ++# CONFIG_USB_MIDI is not set ++# CONFIG_USB_STORAGE is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_DPCM is not set ++# CONFIG_USB_STORAGE_HP8200e is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_HID is not set ++# CONFIG_USB_HIDINPUT is not set ++# CONFIG_USB_HIDDEV is not set ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_AIPTEK is not set ++# CONFIG_USB_WACOM is not set ++# CONFIG_USB_DC2XX is not set ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_SCANNER is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_HPUSBSCSI is not set ++# CONFIG_USB_IBMCAM is not set ++# CONFIG_USB_OV511 is not set ++# CONFIG_USB_PWC is not set ++# CONFIG_USB_SE401 is not set ++# CONFIG_USB_STV680 is not set ++# CONFIG_USB_VICAM is not set ++# CONFIG_USB_DSBR is not set ++# CONFIG_USB_DABUSB is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_CDCETHER is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_USS720 is not set ++ ++# ++# USB Serial Converter support ++# ++# CONFIG_USB_SERIAL is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_AUERSWALD is not set ++# CONFIG_USB_TIGL is not set ++# CONFIG_USB_BRLVGER is not set ++# CONFIG_USB_LCD is not set ++CONFIG_IPC_USB=y ++ ++#DSP LOG BP->AP ++CONFIG_DSPLOG_USB=y ++ ++# ++# USB clients (devices, not hosts) ++# ++CONFIG_USBD=y ++# CONFIG_USBD_HIGH_SPEED is not set ++CONFIG_USBD_NO_SERIAL_NUMBER=y ++CONFIG_USBD_MAXPOWER=250 ++CONFIG_USBD_PROCFS=y ++CONFIG_USBD_PROCFSM=y ++ ++# ++# Network Function ++# ++CONFIG_USBD_NETWORK=y ++CONFIG_USBD_NETWORK_VENDORID=22b8 ++CONFIG_USBD_NETWORK_PRODUCTID=600c ++CONFIG_USBD_NETWORK_BCDDEVICE=0000 ++CONFIG_USBD_NETWORK_MANUFACTURER="Motorola" ++CONFIG_USBD_NETWORK_PRODUCT_NAME="Motorola USBLAN" ++CONFIG_USBD_NETWORK_BLAN=y ++CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg" ++CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf" ++CONFIG_USBD_NETWORK_BLAN_CRC=y ++# CONFIG_USBD_NETWORK_BLAN_PADBEFORE is not set ++# CONFIG_USBD_NETWORK_BLAN_PADAFTER is not set ++# CONFIG_USBD_NETWORK_BLAN_FERMAT is not set ++# CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME is not set ++# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set ++# CONFIG_USBD_NETWORK_BLAN_NONBRIDGED is not set ++# CONFIG_USBD_NETWORK_SAFE is not set ++# CONFIG_USBD_NETWORK_CDC is not set ++# CONFIG_USBD_NETWORK_BASIC is not set ++# CONFIG_USBD_NETWORK_BASIC2 is not set ++# CONFIG_USBD_NETWORK_START_SINGLE is not set ++# CONFIG_USBD_NETWORK_EP0TEST is not set ++ ++# ++# CDC ACM Function ++# ++CONFIG_USBD_ACM=y ++CONFIG_USBD_ACM_VENDORID=22b8 ++CONFIG_USBD_ACM_PRODUCTID=3802 ++CONFIG_USBD_ACM_BCDDEVICE=0000 ++CONFIG_USBD_ACM_MANUFACTURER="Motorola" ++CONFIG_USBD_ACM_PRODUCT_NAME="Motorola USB Modem" ++CONFIG_USBD_ACM_DESC="Acm Cfg" ++CONFIG_USBD_ACM_COMM_INTF="Comm Intf" ++CONFIG_USBD_ACM_DATA_INTF="Data Intf" ++# CONFIG_USBD_ACM_TRACE is not set ++ ++# ++# CDC USB Mass storage Function ++# ++CONFIG_USBD_STORAGE=y ++CONFIG_USBD_STORAGE_VENDORID=0x22B8 ++CONFIG_USBD_STORAGE_PRODUCTID=0x604C ++CONFIG_USBD_STORAGE_OUT_ENDPOINT=1 ++CONFIG_USBD_STORAGE_OUT_PKTSIZE=64 ++CONFIG_USBD_STORAGE_IN_ENDPOINT=2 ++CONFIG_USBD_STORAGE_IN_PKTSIZE=64 ++ ++# ++# Random Mouse Function ++# ++# CONFIG_USBD_MOUSE is not set ++ ++# ++# Cottula/Dalhart (Xscale) support ++# ++# CONFIG_USBD_PXA_BUS is not set ++ ++# ++# Bulverde (Xscale) support ++# ++CONFIG_USBD_WMMX_BUS=y ++# CONFIG_USBD_BI_REGISTER_TRACE is not set ++CONFIG_USBD_BI_DELAY_ENABLE=y ++ ++# ++# PST Function ++# ++CONFIG_USBD_PST=y ++CONFIG_USBD_PST_VENDORID=22b8 ++CONFIG_USBD_PST_PRODUCTID=6009 ++CONFIG_USBD_PST_BCDDEVICE=0001 ++ ++# ++#CFG11 Function ++# ++CONFIG_USBD_CFG11=y ++CONFIG_USBD_CFG11_VENDORID=22b8 ++CONFIG_USBD_CFG11_PRODUCTID=6004 ++CONFIG_USBD_CFG11_BCDDEVICE=0001 ++CONFIG_USBD_CFG11_MANUFACTURER="Belcarra" ++CONFIG_USBD_CFG11_PRODUCT_NAME="Belcarra" ++# ++# DSPLog Function ++# ++CONFIG_USBD_DSP_LOG=y ++CONFIG_USBD_DSP_LOG_VENDORID=22b8 ++CONFIG_USBD_DSP_LOG_PRODUCTID=6009 ++CONFIG_USBD_DSP_LOG_BCDDEVICE=0001 ++ ++# ++# Motorola Network Monitor USB Driver ++# ++CONFIG_USBD_NM=y ++CONFIG_USBD_NM_VENDORID=22b8 ++CONFIG_USBD_NM_PRODUCTID=1004 ++CONFIG_USBD_NM_BCDDEVICE=0002 ++ ++ ++# ++# MMC/SD Card support ++# ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++CONFIG_EZX_MMC=y ++ ++# ++# Kernel tracing ++# ++# CONFIG_TRACE is not set ++# CONFIG_TRACE_BOOT is not set ++ ++# ++# Montavista System Tuning Tools ++# ++# CONFIG_KFI is not set ++# CONFIG_KFI_STATIC_RUN is not set ++# CONFIG_ILATENCY is not set ++# CONFIG_PREEMPT_TIMES is not set ++# CONFIG_MEMORY_ACCOUNTING is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set ++# CONFIG_KGDB is not set ++# CONFIG_KGDB_SERIAL is not set ++# CONFIG_KGDB_CONSOLE is not set ++# CONFIG_KGDB_SYSRQ is not set ++# CONFIG_KGDB_MORE is not set ++# CONFIG_PANIC_LOG is not set ++# CONFIG_CONTEXT_CAP is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m +diff -Nurd linux-2.6.16.orig/arch/arm/Kconfig linux-2.6.16/arch/arm/Kconfig +--- linux-2.6.16.orig/arch/arm/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/Kconfig 2006-06-03 11:14:55.887393080 +0200 +@@ -832,3 +832,5 @@ + source "crypto/Kconfig" + + source "lib/Kconfig" ++ ++source "drivers/dpm/Kconfig" +diff -Nurd linux-2.6.16.orig/arch/arm/kernel/apm.c linux-2.6.16/arch/arm/kernel/apm.c +--- linux-2.6.16.orig/arch/arm/kernel/apm.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/kernel/apm.c 2006-06-03 11:14:56.250337904 +0200 +@@ -605,3 +605,7 @@ + wake_up_interruptible(&kapmd_wait); + } + EXPORT_SYMBOL(apm_queue_event); ++ ++void pm_do_poweroff(void) ++{ /* FIXME */ ++} +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/dpm-pxa27x.c linux-2.6.16/arch/arm/mach-pxa/dpm-pxa27x.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/dpm-pxa27x.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/dpm-pxa27x.c 2006-06-03 11:14:55.929386696 +0200 +@@ -0,0 +1,2110 @@ ++/* ++ * arch/arm/mach-pxa/dpm-pxa27x.c DPM support for Intel PXA27x ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, 2005 MontaVista Software <source@mvista.com>. ++ * ++ * Includes code from David Burrage, Alexandre Rusev, and Todd Poynor, ++ * based on DPM code by Matthew Locke, Dmitry Chigirev and Bishop Brock. ++ * ++ * Includes cpufreq/ipm code by Chao Xie and Cain Yuan ++ * Copyright (C) 2003-2004 Intel Corporation. ++ */ ++ ++#include <linux/config.h> ++ ++#include <linux/dpm.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++ ++#include <linux/delay.h> ++ ++#include <asm/uaccess.h> ++#include <asm/pgtable.h> ++#include <asm/pgalloc.h> ++#include <asm/hardware.h> ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/system.h> ++#include <asm/arch/dpm.h> ++#include <asm/mach/time.h> ++ ++static int saved_loops_per_jiffy = 0; ++static int saved_cpu_freq = 0; ++ ++#define CCCR_CPDIS_BIT_ON (1 << 31) ++#define CCCR_PPDIS_BIT_ON (1 << 30) ++#define CCCR_CPDIS_BIT_OFF (0 << 31) ++#define CCCR_PPDIS_BIT_OFF (0 << 30) ++#define CCCR_PLL_EARLY_EN_BIT_ON (1 << 26) ++#define CCSR_CPLL_LOCKED (1 << 29) ++#define CCSR_PPLL_LOCKED (1 << 28) ++ ++/* CLKCFG ++ | 31------------------------------------------- | 3 | 2 | 1 | 0 | ++ | --------------------------------------------- | B | HT | F | T | ++*/ ++#define CLKCFG_B_BIT (1 << 3) ++#define CLKCFG_HT_BIT (1 << 2) ++#define CLKCFG_F_BIT (1 << 1) ++#define CLKCFG_T_BIT 1 ++ ++#define PLL_L_MAX 31 ++#define PLL_N_MAX 8 ++ ++/* The MIN for L is 2 in the Yellow Book tables, but L=1 really means ++ 13M mode, so L min includes 1 */ ++#define PLL_L_MIN 1 ++#define PLL_N_MIN 2 ++ ++#define CCLKCFG_TURBO 0x1 ++#define CCLKCFG_FCS 0x2 ++ ++#define L_NUM 31 /* 30 different L numbers. */ ++#define N_NUM 7 /* 7 N numbers. */ ++ ++#define BLVD_MIN_FREQ 13000 ++/* latest PowerPoint documentation indicates 624000*/ ++#define BLVD_MAX_FREQ 520000 ++ ++#define MAX_VOL 1400 /* in mV. */ ++#define MIN_VOL 850 /* in Mv. */ ++ ++#define MDREFR_DRI 0xFFF ++#define MSC0_RDF (0xF << 20) ++#define MSC0_RDN (0xF << 24) ++#define MSC0_RRR (0x7 << 12) ++#define MDREFR_RFU 0xC0200000 ++#define MDCNFG_DTC0 (0x3 << 8) ++#define MDCNFG_DTC2 (0x3 << 24) ++ ++/* memory timing (MSC0,DTC,DRI) constants (see Blob and Intel BBU sources) */ ++#define XLLI_MSC0_13 0x11101110 ++#define XLLI_MSC0_19 0x11101110 ++#define XLLI_MSC0_26 0x11201120 /* 26 MHz setting */ ++#define XLLI_MSC0_32 0x11201120 ++#define XLLI_MSC0_39 0x11301130 /* 39 MHz setting */ ++#define XLLI_MSC0_45 0x11301130 ++#define XLLI_MSC0_52 0x11401140 /* @ 52 MHz setting */ ++#define XLLI_MSC0_58 0x11401140 ++#define XLLI_MSC0_65 0x11501150 /* @ 65 MHz setting */ ++#define XLLI_MSC0_68 0x11501150 ++#define XLLI_MSC0_71 0x11501150 /* @ 71.5 MHz setting */ ++#define XLLI_MSC0_74 0x11601160 ++#define XLLI_MSC0_78 0x12601260 /* @ 78 MHz setting */ ++#define XLLI_MSC0_81 0x12601260 ++#define XLLI_MSC0_84 0x12601260 /* @ 84.5 MHz setting */ ++#define XLLI_MSC0_87 0x12701270 ++#define XLLI_MSC0_91 0x12701270 /* 91 MHz setting */ ++#define XLLI_MSC0_94 0x12701270 /* 94.2 MHz setting */ ++#define XLLI_MSC0_97 0x12701270 /* 97.5 MHz setting */ ++#define XLLI_MSC0_100 0x12801280 /* 100.7 MHz setting */ ++#define XLLI_MSC0_104 0x12801280 /* 104 MHz setting */ ++#define XLLI_MSC0_110 0x12901290 ++#define XLLI_MSC0_117 0x13901390 /* 117 MHz setting */ ++#define XLLI_MSC0_124 0x13A013A0 ++#define XLLI_MSC0_130 0x13A013A0 /* 130 MHz setting */ ++#define XLLI_MSC0_136 0x13B013B0 ++#define XLLI_MSC0_143 0x13B013B0 ++#define XLLI_MSC0_149 0x13C013C0 ++#define XLLI_MSC0_156 0x14C014C0 ++#define XLLI_MSC0_162 0x14C014C0 ++#define XLLI_MSC0_169 0x14C014C0 ++#define XLLI_MSC0_175 0x14C014C0 ++#define XLLI_MSC0_182 0x14C014C0 ++#define XLLI_MSC0_188 0x14C014C0 ++#define XLLI_MSC0_195 0x15C015C0 ++#define XLLI_MSC0_201 0x15D015D0 ++#define XLLI_MSC0_208 0x15D015D0 ++ ++/* DTC settings depend on 16/32 bit SDRAM we have (32 is chosen) */ ++#define XLLI_DTC_13 0x00000000 ++#define XLLI_DTC_19 0x00000000 ++#define XLLI_DTC_26 0x00000000 ++#define XLLI_DTC_32 0x00000000 ++#define XLLI_DTC_39 0x00000000 ++#define XLLI_DTC_45 0x00000000 ++#define XLLI_DTC_52 0x00000000 ++#define XLLI_DTC_58 0x01000100 ++#define XLLI_DTC_65 0x01000100 ++#define XLLI_DTC_68 0x01000100 ++#define XLLI_DTC_71 0x01000100 ++#define XLLI_DTC_74 0x01000100 ++#define XLLI_DTC_78 0x01000100 ++#define XLLI_DTC_81 0x01000100 ++#define XLLI_DTC_84 0x01000100 ++#define XLLI_DTC_87 0x01000100 ++#define XLLI_DTC_91 0x02000200 ++#define XLLI_DTC_94 0x02000200 ++#define XLLI_DTC_97 0x02000200 ++#define XLLI_DTC_100 0x02000200 ++#define XLLI_DTC_104 0x02000200 ++/* 110-208 MHz setting - SDCLK Halved*/ ++#define XLLI_DTC_110 0x01000100 ++#define XLLI_DTC_117 0x01000100 ++#define XLLI_DTC_124 0x01000100 ++#define XLLI_DTC_130 0x01000100 ++#define XLLI_DTC_136 0x01000100 ++#define XLLI_DTC_143 0x01000100 ++#define XLLI_DTC_149 0x01000100 ++#define XLLI_DTC_156 0x01000100 ++#define XLLI_DTC_162 0x01000100 ++#define XLLI_DTC_169 0x01000100 ++#define XLLI_DTC_175 0x01000100 ++/* 182-208 MHz setting - SDCLK Halved - Close to edge, so bump up */ ++#define XLLI_DTC_182 0x02000200 ++#define XLLI_DTC_188 0x02000200 ++#define XLLI_DTC_195 0x02000200 ++#define XLLI_DTC_201 0x02000200 ++#define XLLI_DTC_208 0x02000200 ++ ++/* Optimal values for DRI (refreash interval) settings for ++ * various MemClk settings (MDREFR) ++ */ ++#define XLLI_DRI_13 0x002 ++#define XLLI_DRI_19 0x003 ++#define XLLI_DRI_26 0x005 ++#define XLLI_DRI_32 0x006 ++#define XLLI_DRI_39 0x008 ++#define XLLI_DRI_45 0x00A ++#define XLLI_DRI_52 0x00B ++#define XLLI_DRI_58 0x00D ++#define XLLI_DRI_65 0x00E ++#define XLLI_DRI_68 0x00F ++#define XLLI_DRI_71 0x010 ++#define XLLI_DRI_74 0x011 ++#define XLLI_DRI_78 0x012 ++#define XLLI_DRI_81 0x012 ++#define XLLI_DRI_84 0x013 ++#define XLLI_DRI_87 0x014 ++#define XLLI_DRI_91 0x015 ++#define XLLI_DRI_94 0x016 ++#define XLLI_DRI_97 0x016 ++#define XLLI_DRI_100 0x017 ++#define XLLI_DRI_104 0x018 ++#define XLLI_DRI_110 0x01A ++#define XLLI_DRI_117 0x01B ++#define XLLI_DRI_124 0x01D ++#define XLLI_DRI_130 0x01E ++#define XLLI_DRI_136 0x020 ++#define XLLI_DRI_143 0x021 ++#define XLLI_DRI_149 0x023 ++#define XLLI_DRI_156 0x025 ++#define XLLI_DRI_162 0x026 ++#define XLLI_DRI_169 0x028 ++#define XLLI_DRI_175 0x029 ++#define XLLI_DRI_182 0x02B ++#define XLLI_DRI_188 0x02D ++#define XLLI_DRI_195 0x02E ++#define XLLI_DRI_201 0x030 ++#define XLLI_DRI_208 0x031 ++ ++ ++ ++/* timings for memory controller set up (masked values) */ ++struct mem_timings{ ++ unsigned int msc0; /* for MSC0 */ ++ unsigned int dtc; /* for MDCNFG */ ++ unsigned int dri; /* for MDREFR */ ++}; ++ ++static unsigned int cpufreq_matrix[N_NUM][L_NUM + 1]; ++static volatile int *ramstart; ++ ++#define CP15R0_REV_MASK 0x0000000f ++#define PXA270_C5 0x7 ++ ++static u32 chiprev; ++static int mvdt_size; ++ ++struct MvDAC { ++ unsigned int mv; ++ unsigned int DACIn; ++} *mvDACtable; ++ ++/* ++ * Transfer desired mv to required DAC value. ++ * Vcore = 1.3v - ( 712uv * DACIn ) ++ */ ++static struct MvDAC table_c0[] = { ++ {1425, 0}, ++ {1400, 69}, ++ {1300, 248}, ++ {1200, 428}, ++ {1100, 601}, ++ {1000, 777}, ++ {950, 872}, ++ {868, 1010}, ++ {861, 0xFFFFFFFF}, ++}; ++ ++/* ++ * Transfer desired mv to required DAC value, update for new boards, ++ * according to "Intel PXA27x Processor Developer's Kit User's Guide, ++ * April 2004, Revision 4.001" ++ * Vcore = 1.5V - (587uV * DAC(input)). ++ */ ++static struct MvDAC table_c5[] = { ++ {1500, 0}, ++ {1484,25}, ++ {1471,50}, ++ {1456,75}, ++ {1441,100}, ++ {1427,125}, ++ {1412,150}, ++ {1397,175}, ++ {1383,200}, ++ {1368,225}, ++ {1353,250}, ++ {1339,275}, ++ {1323,300}, ++ {1309,325}, ++ {1294,350}, ++ {1280,375}, ++ {1265,400}, ++ {1251,425}, ++ {1236,450}, ++ {1221,475}, ++ {1207,500}, ++ {1192,525}, ++ {1177,550}, ++ {1162,575}, ++ {1148,600}, ++ {1133,625}, ++ {1118,650}, ++ {1104,675}, ++ {1089,700}, ++ {1074,725}, ++ {1060,750}, ++ {1045,775}, ++ {1030,800}, ++ {1016,825}, ++ {1001,850}, ++ {986,875}, ++ {972,900}, ++ {957,925}, ++ {942,950}, ++ {928,975}, ++ {913,1000}, ++ {899, 1023}, ++}; ++ ++static unsigned int mv2DAC(unsigned int mv) ++{ ++ int i, num = mvdt_size; ++ ++ if (mvDACtable[0].mv <= mv) { /* Max or bigger */ ++ /* Return the first one */ ++ return mvDACtable[0].DACIn; ++ } ++ ++ if (mvDACtable[num - 1].mv >= mv) { /* Min or smaller */ ++ /* Return the last one */ ++ return mvDACtable[num - 1].DACIn; ++ } ++ ++ /* The biggest and smallest value cases are covered, now the ++ loop may skip those */ ++ for (i = 1; i <= (num - 1); i++) { ++ if ((mvDACtable[i].mv >= mv) && (mvDACtable[i + 1].mv < mv)) { ++ return mvDACtable[i].DACIn; ++ } ++ } ++ ++ /* Should never get here */ ++ return 0; ++} ++ ++static void clr_all_sqc(void) ++{ ++ int i = 0; ++ for (i = 0; i < 32; i++) ++ PCMD(i) &= ~PCMD_SQC; ++} ++ ++static void clr_all_mbc(void) ++{ ++ int i = 0; ++ for (i = 0; i < 32; i++) ++ PCMD(i) &= ~PCMD_MBC; ++} ++ ++static void clr_all_dce(void) ++{ ++ int i = 0; ++ for (i = 0; i < 32; i++) ++ PCMD(i) &= ~PCMD_DCE; ++} ++ ++static void set_mbc_bit(int ReadPointer, int NumOfBytes) ++{ ++ PCMD0 |= PCMD_MBC; ++ PCMD1 |= PCMD_MBC; ++} ++ ++static void set_lc_bit(int ReadPointer, int NumOfBytes) ++{ ++ PCMD0 |= PCMD_LC; ++ PCMD1 |= PCMD_LC; ++ PCMD2 |= PCMD_LC; ++} ++ ++static void set_cmd_data(unsigned char *DataArray, int StartPoint, int size) ++{ ++ PCMD0 &= 0xFFFFFF00; ++ PCMD0 |= DataArray[0]; ++ PCMD1 &= 0xFFFFFF00; ++ PCMD1 |= DataArray[1]; ++ PCMD2 &= 0xFFFFFF00; ++ PCMD2 |= DataArray[2]; ++} ++ ++/* coupled indicates that this VCS is to be coupled with a FCS */ ++static void power_change_cmd(unsigned int DACValue, int coupled) ++{ ++ unsigned char dataArray[3]; ++ ++ dataArray[0] = 0; /* Command 0 */ ++ dataArray[1] = (DACValue & 0x000000FF); /* data LSB */ ++ dataArray[2] = (DACValue & 0x0000FF00) >> 8; /* data MSB */ ++ ++ PVCR = 0; ++ ++ PCFR &= ~PCFR_FVC; ++ PVCR &= 0xFFFFF07F; /* no delay is necessary */ ++ PVCR &= 0xFFFFFF80; /* clear slave address */ ++ PVCR |= 0x20; /* set slave address */ ++ ++ PVCR &= 0xFE0FFFFF; /* clear read pointer 0 */ ++ PVCR |= 0; ++ ++ /* DCE and SQC are not necessary for single command */ ++ clr_all_sqc(); ++ clr_all_dce(); ++ ++ clr_all_mbc(); ++ set_mbc_bit(0, 2); ++ ++ /* indicate the last byte of this command is holded in this register */ ++ PCMD2 &= ~PCMD_MBC; ++ ++ /* indicate this is the first command and last command also */ ++ set_lc_bit(0, 3); ++ ++ /* programming the command data bit */ ++ set_cmd_data(dataArray, 0, 2); ++ ++ if (coupled) { ++ /* Enable Power I2C and FVC */ ++ PCFR |= (PCFR_PI2CEN | PCFR_FVC); ++ } else { ++ /* Enable Power I2C */ ++ PCFR |= PCFR_PI2CEN; ++ } ++} ++ ++static void change_voltage(void) ++{ ++ unsigned long flags; ++ unsigned int unused; ++ ++ ++ local_irq_save(flags); ++ ++ __asm__ __volatile__("\n\ ++ @ WOKAROUND - Core hangs on voltage change at different\n\ ++ @ alignments and at different core clock frequencies\n\ ++ @ To ensure that no external fetches occur, we want to store the next\n\ ++ @ several instructions that occur after the voltage change inside\n\ ++ @ the cache. The load dependency stall near the retry label ensures \n\ ++ @ that any outstanding instruction cacheline loads are complete before \n\ ++ @ the mcr instruction is executed on the 2nd pass. This procedure \n\ ++ @ ensures us that the internal bus will not be busy. \n\ ++ \n\ ++ b 2f \n\ ++ nop \n\ ++ .align 5 \n\ ++2: \n\ ++ ldr r0, [%1] @ APB register read and compare \n\ ++ cmp r0, #0 @ fence for pending slow apb reads \n\ ++ \n\ ++ mov r0, #8 @ VC bit for PWRMODE \n\ ++ movs r1, #1 @ don't execute mcr on 1st pass \n\ ++ \n\ ++ @ %1 points to uncacheable memory to force memory read \n\ ++ \n\ ++retry: \n\ ++ ldreq r3, [%2] @ only stall on the 2nd pass\n\ ++ cmpeq r3, #0 @ cmp causes fence on mem transfers\n\ ++ cmp r1, #0 @ is this the 2nd pass? \n\ ++ mcreq p14, 0, r0, c7, c0, 0 @ write to PWRMODE on 2nd pass only \n\ ++ \n\ ++ @ Read VC bit until it is 0, indicates that the VoltageChange is done.\n\ ++ @ On first pass, we never set the VC bit, so it will be clear already.\n\ ++ \n\ ++VoltageChange_loop: \n\ ++ mrc p14, 0, r3, c7, c0, 0 \n\ ++ tst r3, #0x8 \n\ ++ bne VoltageChange_loop \n\ ++ \n\ ++ subs r1, r1, #1 @ update conditional execution counter\n\ ++ beq retry":"=&r"(unused) ++ :"r"(&CCCR), "r"(ramstart) ++ :"r0", "r1", "r3"); ++ ++ local_irq_restore(flags); ++} ++ ++void vm_setvoltage(unsigned int DACValue) ++{ ++ power_change_cmd(DACValue, 0 /* not-coupled */ ); ++ /* Execute voltage change sequence */ ++ change_voltage(); /* set VC on the PWRMODE on CP14 */ ++} ++ ++static void set_voltage(unsigned int mv) ++{ ++ vm_setvoltage(mv2DAC(mv)); ++} ++ ++static int vcs_init(void) ++{ ++ /* we distinguish new and old boards by proc chip ++ * revision, we assume new boards have C5 proc ++ * revision and we use the new table (table_c5) for them, ++ * for all other boards we use the old table (table_c0). ++ * Note, the logics won't work and inaccurate voltage ++ * will be set if C5 proc installed to old board ++ * and vice versa. ++ */ ++ ++ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); ++ ++ chiprev &= CP15R0_REV_MASK; ++ ++ if (chiprev == PXA270_C5) { ++ mvDACtable = table_c5; ++ mvdt_size = sizeof(table_c5) / sizeof(struct MvDAC); ++ } else { ++ mvDACtable = table_c0; ++ mvdt_size = sizeof(table_c0) / sizeof(struct MvDAC); ++ } ++ ++ CKEN |= 0x1 << 15; ++ CKEN |= 0x1 << 14; ++ PCFR = PCFR_PI2CEN; ++ return 0; ++} ++ ++static void initialize_freq_matrix(void) ++{ ++ int n, l; ++ ++ memset(&cpufreq_matrix, 0, sizeof(cpufreq_matrix)); ++ ++ for (n = 2; n < N_NUM + 2; n++) { ++ for (l = 2; l <= L_NUM; l++) { ++ cpufreq_matrix[n - 2][l - 2] = (13 * n * l / 2) * 1000; ++ if (cpufreq_matrix[n - 2][l - 2] > BLVD_MAX_FREQ) ++ cpufreq_matrix[n - 2][l - 2] = 0; ++ } ++ } ++} ++ ++/* ++ This should be called with a valid freq point that was ++ obtained via validate_speed ++*/ ++static void set_freq(unsigned int CLKCFGValue) ++{ ++ unsigned long flags; ++ unsigned int unused; ++ unsigned int fcsbits = 0xe3dfeff; ++ volatile int v; ++ ++ local_irq_save(flags); ++ ++ /* ++ force a tlb fault to get the mapping into the tlb ++ (otherwise this will occur below when the sdram is turned off and ++ something-bad(tm) will happen) ++ */ ++ ++ v = *(volatile unsigned long *)ramstart; ++ *(volatile unsigned long *)ramstart = v; ++ ++ __asm__ __volatile__(" \n\ ++ ldr r4, [%1] @load MDREFR \n\ ++ mcr p14, 0, %2, c6, c0, 0 @ set CCLKCFG[FCS] \n\ ++ ldr r5, [%3] \n\ ++ and r4, r4, r5 \n\ ++ str r4, [%1] @restore \n\ ++ ":"=&r"(unused) ++ :"r"(&MDREFR), "r"(CLKCFGValue), "r"(&fcsbits) ++ :"r4", "r5"); ++ ++ local_irq_restore(flags); ++} ++ ++static int get_freq(void) ++{ ++ unsigned int freq, n, l, ccsr; ++ ++ ccsr = CCSR; ++ ++ l = ccsr & CCCR_L_MASK; /* Get L */ ++ n = (ccsr & CCCR_N_MASK) >> 7; /* Get 2N */ ++ ++ if (n < 2) ++ n = 2; ++ ++ /* Shift to divide by 2 because N is really 2N */ ++ freq = (13000 * l * n) >> 1; /* in kHz */ ++ ++ return freq; ++} ++ ++static unsigned int read_clkcfg(void) ++{ ++ unsigned int value = 0; ++ unsigned int un_used; ++ ++ __asm__ __volatile__("mrc p14, 0, %1, c6, c0, 0": "=&r"(un_used):"r"(value)); ++ ++ return value; ++} ++ ++static int init_freqs(void) ++{ ++ int cpu_ver; ++ ++ asm volatile ("mrc%? p15, 0, %0, c0, c0":"=r" (cpu_ver)); ++ ++ /* ++ Bulverde A0: 0x69054110, ++ A1: 0x69054111 ++ */ ++ if ((cpu_ver & 0x0000f000) >> 12 == 4 && ++ (cpu_ver & 0xffff0000) >> 16 == 0x6905) { ++ /* It is a PXA27x chip. */ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int freq_init(void) ++{ ++ unsigned int freq; ++ ++ /* ++ * In order to turn the sdram back on (see below) we need to ++ * r/w the sdram. We need to do this without the cache and ++ * write buffer in the way. So, we temporarily ioremap the ++ * first page of sdram as uncached i/o memory and use the ++ * aliased address ++ */ ++ ++ /* map the first page of sdram to an uncached virtual page */ ++ ramstart = (int *)ioremap(PHYS_OFFSET, 4096); ++ ++ if (! ramstart) { ++ printk(KERN_ERR "PXA27x DPM: ioremap of first page failed."); ++ return -1; ++ } ++ ++ initialize_freq_matrix(); ++ ++ if (init_freqs()) { ++ freq = get_freq(); /* in kHz */ ++ printk(KERN_INFO "PXA27x DPM: Initial frequency is %dkHz.\n", freq); ++ return 0; ++ } ++ ++ return -1; ++} ++ ++void freq_cleanup(void) ++{ ++ /* unmap the page we used*/ ++ iounmap((void *)ramstart); ++} ++ ++static unsigned long ++calculate_memclk(unsigned long cccr, unsigned long clkcfg) ++{ ++ unsigned long M, memclk; ++ u32 L; ++ ++ L = cccr & 0x1f; ++ if (cccr & (1 << 25)) { ++ if (clkcfg & CLKCFG_B_BIT) ++ memclk = (L*13); ++ else ++ memclk = (L*13)/2; ++ } ++ else { ++ if (L <= 10) M = 1; ++ else if (L <= 20) M = 2; ++ else M = 4; ++ ++ memclk = (L*13)/M; ++ } ++ ++ return memclk; ++} ++ ++static unsigned long ++calculate_new_memclk(struct dpm_regs *regs) ++{ ++ return calculate_memclk(regs->cccr, regs->clkcfg); ++} ++ ++static unsigned long ++calculate_cur_memclk(void) ++{ ++ unsigned long cccr = CCCR; ++ return calculate_memclk(cccr, read_clkcfg()); ++} ++ ++/* Returns optimal timings for memory controller ++ * a - [A] ++ * b - [B] ++ * l - value of L ++ */ ++static struct mem_timings get_optimal_mem_timings(int a, int b, int l){ ++ struct mem_timings ret = { ++ .msc0 = 0, ++ .dtc = 0, ++ .dri = 0, ++ }; ++ ++ if(a!=0 && b==0){ ++ switch(l){ ++ case 2: ++ ret.msc0 = XLLI_MSC0_13; ++ ret.dtc = XLLI_DTC_13; ++ ret.dri = XLLI_DRI_13; ++ break; ++ case 3: ++ ret.msc0 = XLLI_MSC0_19; ++ ret.dtc = XLLI_DTC_19; ++ ret.dri = XLLI_DRI_19; ++ break; ++ case 4: ++ ret.msc0 = XLLI_MSC0_26; ++ ret.dtc = XLLI_DTC_26; ++ ret.dri = XLLI_DRI_26; ++ break; ++ case 5: ++ ret.msc0 = XLLI_MSC0_32; ++ ret.dtc = XLLI_DTC_32; ++ ret.dri = XLLI_DRI_32; ++ break; ++ case 6: ++ ret.msc0 = XLLI_MSC0_39; ++ ret.dtc = XLLI_DTC_39; ++ ret.dri = XLLI_DRI_39; ++ break; ++ case 7: ++ ret.msc0 = XLLI_MSC0_45; ++ ret.dtc = XLLI_DTC_45; ++ ret.dri = XLLI_DRI_45; ++ break; ++ case 8: ++ ret.msc0 = XLLI_MSC0_52; ++ ret.dtc = XLLI_DTC_52; ++ ret.dri = XLLI_DRI_52; ++ break; ++ case 9: ++ ret.msc0 = XLLI_MSC0_58; ++ ret.dtc = XLLI_DTC_58; ++ ret.dri = XLLI_DRI_58; ++ break; ++ case 10: ++ ret.msc0 = XLLI_MSC0_65; ++ ret.dtc = XLLI_DTC_65; ++ ret.dri = XLLI_DRI_65; ++ break; ++ /* ++ * L11 - L20 ARE THE SAME for A0Bx ++ */ ++ case 11: ++ ret.msc0 = XLLI_MSC0_71; ++ ret.dtc = XLLI_DTC_71; ++ ret.dri = XLLI_DRI_71; ++ break; ++ case 12: ++ ret.msc0 = XLLI_MSC0_78; ++ ret.dtc = XLLI_DTC_78; ++ ret.dri = XLLI_DRI_78; ++ break; ++ case 13: ++ ret.msc0 = XLLI_MSC0_84; ++ ret.dtc = XLLI_DTC_84; ++ ret.dri = XLLI_DRI_84; ++ break; ++ case 14: ++ ret.msc0 = XLLI_MSC0_91; ++ ret.dtc = XLLI_DTC_91; ++ ret.dri = XLLI_DRI_91; ++ break; ++ case 15: ++ ret.msc0 = XLLI_MSC0_97; ++ ret.dtc = XLLI_DTC_97; ++ ret.dri = XLLI_DRI_97; ++ break; ++ case 16: ++ ret.msc0 = XLLI_MSC0_104; ++ ret.dtc = XLLI_DTC_104; ++ ret.dri = XLLI_DRI_104; ++ break; ++ case 17: ++ ret.msc0 = XLLI_MSC0_110; ++ ret.dtc = XLLI_DTC_110; ++ ret.dri = XLLI_DRI_110; ++ break; ++ case 18: ++ ret.msc0 = XLLI_MSC0_117; ++ ret.dtc = XLLI_DTC_117; ++ ret.dri = XLLI_DRI_117; ++ break; ++ case 19: ++ ret.msc0 = XLLI_MSC0_124; ++ ret.dtc = XLLI_DTC_124; ++ ret.dri = XLLI_DRI_124; ++ break; ++ case 20: ++ ret.msc0 = XLLI_MSC0_130; ++ ret.dtc = XLLI_DTC_130; ++ ret.dri = XLLI_DRI_130; ++ break; ++ case 21: ++ ret.msc0 = XLLI_MSC0_136; ++ ret.dtc = XLLI_DTC_136; ++ ret.dri = XLLI_DRI_136; ++ break; ++ case 22: ++ ret.msc0 = XLLI_MSC0_143; ++ ret.dtc = XLLI_DTC_143; ++ ret.dri = XLLI_DRI_143; ++ break; ++ case 23: ++ ret.msc0 = XLLI_MSC0_149; ++ ret.dtc = XLLI_DTC_149; ++ ret.dri = XLLI_DRI_149; ++ break; ++ case 24: ++ ret.msc0 = XLLI_MSC0_156; ++ ret.dtc = XLLI_DTC_156; ++ ret.dri = XLLI_DRI_156; ++ break; ++ case 25: ++ ret.msc0 = XLLI_MSC0_162; ++ ret.dtc = XLLI_DTC_162; ++ ret.dri = XLLI_DRI_162; ++ break; ++ case 26: ++ ret.msc0 = XLLI_MSC0_169; ++ ret.dtc = XLLI_DTC_169; ++ ret.dri = XLLI_DRI_169; ++ break; ++ case 27: ++ ret.msc0 = XLLI_MSC0_175; ++ ret.dtc = XLLI_DTC_175; ++ ret.dri = XLLI_DRI_175; ++ break; ++ case 28: ++ ret.msc0 = XLLI_MSC0_182; ++ ret.dtc = XLLI_DTC_182; ++ ret.dri = XLLI_DRI_182; ++ break; ++ case 29: ++ ret.msc0 = XLLI_MSC0_188; ++ ret.dtc = XLLI_DTC_188; ++ ret.dri = XLLI_DRI_188; ++ break; ++ case 30: ++ ret.msc0 = XLLI_MSC0_195; ++ ret.dtc = XLLI_DTC_195; ++ ret.dri = XLLI_DRI_195; ++ break; ++ case 31: ++ ret.msc0 = XLLI_MSC0_201; ++ ret.dtc = XLLI_DTC_201; ++ ret.dri = XLLI_DRI_201; ++ } ++ ++ }else if(a!=0 && b!=0){ ++ switch(l){ ++ case 2: ++ ret.msc0 = XLLI_MSC0_26; ++ ret.dtc = XLLI_DTC_26; ++ ret.dri = XLLI_DRI_26; ++ break; ++ case 3: ++ ret.msc0 = XLLI_MSC0_39; ++ ret.dtc = XLLI_DTC_39; ++ ret.dri = XLLI_DRI_39; ++ break; ++ case 4: ++ ret.msc0 = XLLI_MSC0_52; ++ ret.dtc = XLLI_DTC_52; ++ ret.dri = XLLI_DRI_52; ++ break; ++ case 5: ++ ret.msc0 = XLLI_MSC0_65; ++ ret.dtc = XLLI_DTC_65; ++ ret.dri = XLLI_DRI_65; ++ break; ++ case 6: ++ ret.msc0 = XLLI_MSC0_78; ++ ret.dtc = XLLI_DTC_78; ++ ret.dri = XLLI_DRI_78; ++ break; ++ case 7: ++ ret.msc0 = XLLI_MSC0_91; ++ ret.dtc = XLLI_DTC_91; ++ ret.dri = XLLI_DRI_91; ++ break; ++ case 8: ++ ret.msc0 = XLLI_MSC0_104; ++ ret.dtc = XLLI_DTC_104; ++ ret.dri = XLLI_DRI_104; ++ break; ++ case 9: ++ ret.msc0 = XLLI_MSC0_117; ++ ret.dtc = XLLI_DTC_117; ++ ret.dri = XLLI_DRI_117; ++ break; ++ case 10: ++ ret.msc0 = XLLI_MSC0_130; ++ ret.dtc = XLLI_DTC_130; ++ ret.dri = XLLI_DRI_130; ++ break; ++ case 11: ++ ret.msc0 = XLLI_MSC0_143; ++ ret.dtc = XLLI_DTC_143; ++ ret.dri = XLLI_DRI_143; ++ break; ++ case 12: ++ ret.msc0 = XLLI_MSC0_156; ++ ret.dtc = XLLI_DTC_156; ++ ret.dri = XLLI_DRI_156; ++ break; ++ case 13: ++ ret.msc0 = XLLI_MSC0_169; ++ ret.dtc = XLLI_DTC_169; ++ ret.dri = XLLI_DRI_169; ++ break; ++ case 14: ++ ret.msc0 = XLLI_MSC0_182; ++ ret.dtc = XLLI_DTC_182; ++ ret.dri = XLLI_DRI_182; ++ break; ++ case 15: ++ ret.msc0 = XLLI_MSC0_195; ++ ret.dtc = XLLI_DTC_195; ++ ret.dri = XLLI_DRI_195; ++ break; ++ case 16: ++ ret.msc0 = XLLI_MSC0_208; ++ ret.dtc = XLLI_DTC_208; ++ ret.dri = XLLI_DRI_208; ++ } ++ }else{ ++ /* A0Bx */ ++ switch(l){ ++ case 2: ++ ret.msc0 = XLLI_MSC0_26; ++ ret.dtc = XLLI_DTC_26; ++ ret.dri = XLLI_DRI_26; ++ break; ++ case 3: ++ ret.msc0 = XLLI_MSC0_39; ++ ret.dtc = XLLI_DTC_39; ++ ret.dri = XLLI_DRI_39; ++ break; ++ case 4: ++ ret.msc0 = XLLI_MSC0_52; ++ ret.dtc = XLLI_DTC_52; ++ ret.dri = XLLI_DRI_52; ++ break; ++ case 5: ++ ret.msc0 = XLLI_MSC0_65; ++ ret.dtc = XLLI_DTC_65; ++ ret.dri = XLLI_DRI_65; ++ break; ++ case 6: ++ ret.msc0 = XLLI_MSC0_78; ++ ret.dtc = XLLI_DTC_78; ++ ret.dri = XLLI_DRI_78; ++ break; ++ case 7: ++ ret.msc0 = XLLI_MSC0_91; ++ ret.dtc = XLLI_DTC_91; ++ ret.dri = XLLI_DRI_91; ++ break; ++ case 8: ++ ret.msc0 = XLLI_MSC0_104; ++ ret.dtc = XLLI_DTC_104; ++ ret.dri = XLLI_DRI_104; ++ break; ++ case 9: ++ ret.msc0 = XLLI_MSC0_117; ++ ret.dtc = XLLI_DTC_117; ++ ret.dri = XLLI_DRI_117; ++ break; ++ case 10: ++ ret.msc0 = XLLI_MSC0_130; ++ ret.dtc = XLLI_DTC_130; ++ ret.dri = XLLI_DRI_130; ++ break; ++ case 11: ++ ret.msc0 = XLLI_MSC0_71; ++ ret.dtc = XLLI_DTC_71; ++ ret.dri = XLLI_DRI_71; ++ break; ++ case 12: ++ ret.msc0 = XLLI_MSC0_78; ++ ret.dtc = XLLI_DTC_78; ++ ret.dri = XLLI_DRI_78; ++ break; ++ case 13: ++ ret.msc0 = XLLI_MSC0_84; ++ ret.dtc = XLLI_DTC_84; ++ ret.dri = XLLI_DRI_84; ++ break; ++ case 14: ++ ret.msc0 = XLLI_MSC0_91; ++ ret.dtc = XLLI_DTC_91; ++ ret.dri = XLLI_DRI_91; ++ break; ++ case 15: ++ ret.msc0 = XLLI_MSC0_97; ++ ret.dtc = XLLI_DTC_97; ++ ret.dri = XLLI_DRI_97; ++ break; ++ case 16: ++ ret.msc0 = XLLI_MSC0_104; ++ ret.dtc = XLLI_DTC_104; ++ ret.dri = XLLI_DRI_104; ++ break; ++ case 17: ++ ret.msc0 = XLLI_MSC0_110; ++ ret.dtc = XLLI_DTC_110; ++ ret.dri = XLLI_DRI_110; ++ break; ++ case 18: ++ ret.msc0 = XLLI_MSC0_117; ++ ret.dtc = XLLI_DTC_117; ++ ret.dri = XLLI_DRI_117; ++ break; ++ case 19: ++ ret.msc0 = XLLI_MSC0_124; ++ ret.dtc = XLLI_DTC_124; ++ ret.dri = XLLI_DRI_124; ++ break; ++ case 20: ++ ret.msc0 = XLLI_MSC0_130; ++ ret.dtc = XLLI_DTC_130; ++ ret.dri = XLLI_DRI_130; ++ break; ++ case 21: ++ ret.msc0 = XLLI_MSC0_68; ++ ret.dtc = XLLI_DTC_68; ++ ret.dri = XLLI_DRI_68; ++ break; ++ case 22: ++ ret.msc0 = XLLI_MSC0_71; ++ ret.dtc = XLLI_DTC_71; ++ ret.dri = XLLI_DRI_71; ++ break; ++ case 23: ++ ret.msc0 = XLLI_MSC0_74; ++ ret.dtc = XLLI_DTC_74; ++ ret.dri = XLLI_DRI_74; ++ break; ++ case 24: ++ ret.msc0 = XLLI_MSC0_78; ++ ret.dtc = XLLI_DTC_78; ++ ret.dri = XLLI_DRI_78; ++ break; ++ case 25: ++ ret.msc0 = XLLI_MSC0_81; ++ ret.dtc = XLLI_DTC_81; ++ ret.dri = XLLI_DRI_81; ++ break; ++ case 26: ++ ret.msc0 = XLLI_MSC0_84; ++ ret.dtc = XLLI_DTC_84; ++ ret.dri = XLLI_DRI_84; ++ break; ++ case 27: ++ ret.msc0 = XLLI_MSC0_87; ++ ret.dtc = XLLI_DTC_87; ++ ret.dri = XLLI_DRI_87; ++ break; ++ case 28: ++ ret.msc0 = XLLI_MSC0_91; ++ ret.dtc = XLLI_DTC_91; ++ ret.dri = XLLI_DRI_91; ++ break; ++ case 29: ++ ret.msc0 = XLLI_MSC0_94; ++ ret.dtc = XLLI_DTC_94; ++ ret.dri = XLLI_DRI_94; ++ break; ++ case 30: ++ ret.msc0 = XLLI_MSC0_97; ++ ret.dtc = XLLI_DTC_97; ++ ret.dri = XLLI_DRI_97; ++ break; ++ case 31: ++ ret.msc0 = XLLI_MSC0_100; ++ ret.dtc = XLLI_DTC_100; ++ ret.dri = XLLI_DRI_100; ++ } ++ } ++ ++ return ret; ++} ++ ++static void assign_optimal_mem_timings( ++ unsigned int* msc0_reg, ++ unsigned int* mdrefr_reg, ++ unsigned int* mdcnfg_reg, ++ int a, int b, int l ++ ) ++{ ++ unsigned int msc0_reg_tmp = (*msc0_reg); ++ unsigned int mdrefr_reg_tmp = (*mdrefr_reg); ++ unsigned int mdcnfg_reg_tmp = (*mdcnfg_reg); ++ struct mem_timings timings = get_optimal_mem_timings(a,b,l); ++ ++ /* clear bits which are set by get_optimal_mem_timings*/ ++ msc0_reg_tmp &= ~(MSC0_RDF & MSC0_RDN & MSC0_RRR); ++ mdrefr_reg_tmp &= ~(MDREFR_RFU & MDREFR_DRI); ++ mdcnfg_reg_tmp &= ~(MDCNFG_DTC0 & MDCNFG_DTC2); ++ ++ /* prepare appropriate timings */ ++ msc0_reg_tmp |= timings.msc0; ++ mdrefr_reg_tmp |= timings.dri; ++ mdcnfg_reg_tmp |= timings.dtc; ++ ++ /* set timings (all bits one time) */ ++ (*msc0_reg) = msc0_reg_tmp; ++ (*mdrefr_reg) = mdrefr_reg_tmp; ++ (*mdcnfg_reg) = mdcnfg_reg_tmp; ++} ++ ++static void set_mdrefr_value(u32 new_mdrefr){ ++ unsigned long s, old_mdrefr, errata62; ++ old_mdrefr = MDREFR; ++ /* E62 (28007106.pdf): Memory controller may hang while clearing ++ * MDREFR[K1DB2] or MDREFR[K2DB2] ++ */ ++ errata62 = ++ (((old_mdrefr & MDREFR_K1DB2) != 0) && ((new_mdrefr & MDREFR_K1DB2) == 0)) || ++ (((old_mdrefr & MDREFR_K2DB2) != 0) && ((new_mdrefr & MDREFR_K2DB2) == 0)); ++ ++ if(errata62){ ++ unsigned long oscr_0 = OSCR; ++ unsigned long oscr_1 = oscr_0; ++ /* Step 1 - disable interrupts */ ++ local_irq_save(s); ++ /* Step 2 - leave KxDB2, but set MDREFR[DRI] (bits 0-11) to ++ * 0xFFF ++ */ ++ MDREFR = MDREFR | MDREFR_DRI; ++ /* Step 3 - read MDREFR one time */ ++ MDREFR; ++ /* Step 4 - wait 1.6167us ++ * (3.25MHz clock increments OSCR0 7 times) ++ */ ++ while(oscr_1-oscr_0 < 7){ ++ cpu_relax(); ++ oscr_1 = OSCR; ++ } ++ ++ } ++ ++ /* Step 5 - clear K1DB1 and/or K2DB2, and set MDREFR[DRI] to ++ * proper value at the same time ++ */ ++ ++ /*Set MDREFR as if no errata workaround is needed*/ ++ MDREFR = new_mdrefr; ++ ++ if(errata62){ ++ /* Step 6 - read MDREFR one time*/ ++ MDREFR; ++ /* Step 7 - enable interrupts*/ ++ local_irq_restore(s); ++ } ++} ++ ++static void scale_cpufreq(struct dpm_regs *regs) ++{ ++ unsigned long new_memclk, cur_memclk; ++ u32 new_mdrefr, cur_mdrefr, read_mdrefr; ++ u32 new_msc0, new_mdcnfg; ++ int set_mdrefr = 0, scaling_up = 0; ++ int l, a, b; ++ ++ l = regs->cccr & CCCR_L_MASK; /* Get L */ ++ b = (regs->clkcfg >> 3) & 0x1; ++ a = (regs->cccr >> 25) & 0x1; /* cccr[A]: bit 25 */ ++ cur_memclk = calculate_cur_memclk(); ++ new_memclk = calculate_new_memclk(regs); ++ ++ new_mdrefr = cur_mdrefr = MDREFR; ++ new_msc0 = MSC0; ++ new_mdcnfg = MDCNFG; ++ ++ if (new_memclk != cur_memclk) { ++ new_mdrefr &= ~( MDREFR_K0DB2 | MDREFR_K0DB4 | ++ MDREFR_K1DB2 | MDREFR_K2DB2 ); ++ ++ if ((new_memclk > 52) && (new_memclk <= 104)) { ++ /* SDCLK0 = MEMCLK/2, SDCLK1,SDCLK2 = MEMCLK */ ++ new_mdrefr |= MDREFR_K0DB2; ++ } ++ else if (new_memclk > 104){ ++ /* SDCLK0 = MEMCLK/4, SDCLK1 and SDCLK2 = MEMCLK/2 */ ++ new_mdrefr |= (MDREFR_K0DB4 | MDREFR_K1DB2 | MDREFR_K2DB2); ++ } ++ ++ /* clock increasing or decreasing? */ ++ if (new_memclk > cur_memclk) scaling_up = 1; ++ } ++ ++ /* set MDREFR if necessary */ ++ if (new_mdrefr != cur_mdrefr){ ++ set_mdrefr = 1; ++ /* also adjust timings as long as we change MDREFR value */ ++ assign_optimal_mem_timings( ++ &new_msc0, ++ &new_mdrefr, ++ &new_mdcnfg, ++ a,b,l ++ ); ++ } ++ ++ /* if memclk is scaling up, set MDREFR before freq change ++ * (2800002.pdf:6.5.1.4) ++ */ ++ if (set_mdrefr && scaling_up) { ++ MSC0 = new_msc0; ++ set_mdrefr_value(new_mdrefr); ++ MDCNFG = new_mdcnfg; ++ read_mdrefr = MDREFR; ++ } ++ ++ CCCR = regs->cccr; ++ set_freq(regs->clkcfg); ++ ++ /* if memclk is scaling down, set MDREFR after freq change ++ * (2800002.pdf:6.5.1.4) ++ */ ++ if (set_mdrefr && !scaling_up) { ++ MSC0 = new_msc0; ++ set_mdrefr_value(new_mdrefr); ++ MDCNFG = new_mdcnfg; ++ read_mdrefr = MDREFR; ++ } ++} ++ ++static void scale_voltage(struct dpm_regs *regs) ++{ ++ set_voltage(regs->voltage); ++} ++ ++static void scale_voltage_coupled(struct dpm_regs *regs) ++{ ++ power_change_cmd(mv2DAC(regs->voltage), 1 /* coupled */ ); ++} ++ ++static void calculate_lcd_freq(struct dpm_md_opt *opt) ++{ ++ int k = 1; /* lcd divisor */ ++ ++ /* L is verified to be between PLL_L_MAX and PLL_L_MIN in ++ dpm_bulverde_init_opt(). ++ */ ++ if (opt->l == -1) { ++ opt->lcd = -1; ++ return; ++ } ++ ++ if (opt->l > 16) { ++ /* When L=17-31, K=4 */ ++ k = 4; ++ } else if (opt->l > 7) { ++ /* When L=8-16, K=2 */ ++ k = 2; ++ } ++ ++ /* Else, when L=2-7, K=1 */ ++ ++ opt->lcd = 13000 * opt->l / k; ++} ++ ++static void calculate_reg_values(struct dpm_md_opt *opt) ++{ ++ int f = 0; /* frequency change bit */ ++ int turbo = 0; /* turbo mode bit; depends on N value */ ++ ++ opt->regs.voltage = opt->v; ++ ++/* ++ CCCR: ++ ++ A: Alternate setting for MEMC clock ++ 0 = MEM clock frequency as specified in user guide table ++ 1 = MEM clock frq = System Bus Frequency ++ ++ CLKCFG: ++ ++ B = Fast-Bus Mode 0: System Bus is half of run-mode ++ 1: System Bus is equal to run-mode ++ NOTE: only allowed when L <= 16 ++ ++ HT = Half-Turbo 0: core frequency = run or turbo, depending on T bit ++ 1: core frequency = turbo frequency / 2 ++ NOTE: only allowed when 2N = 6 or 2N = 8 ++ ++ F = Frequency change ++ 0: No frequency change is performed ++ 1: Do frequency-change ++ ++ T = Turbo Mode 0: CPU operates at run Frequency ++ 1: CPU operates at Turbo Frequency (when n2 > 2) ++*/ ++ /* Set the CLKCFG with B, T, and HT */ ++ if (opt->b != -1 && opt->n != -1) { ++ f = 1; ++ ++ /*When 2N=2, Turbo Mode equals Run Mode, so it ++ does not really matter if this is >2 or >=2 ++ */ ++ if (opt->n > 2) { ++ turbo = 0x1; ++ } ++ opt->regs.clkcfg = (opt->b << 3) + (f << 1) + turbo; ++ } else { ++ f = 0x1; ++ opt->regs.clkcfg = (f << 1); ++ } ++ ++ /* ++ What about when 2N=0 ... it is not defined by the yellow ++ book ++ */ ++ if (opt->n != -1) { ++ /* 2N is 4 bits, L is 5 bits */ ++ opt->regs.cccr = ((opt->n & 0xF) << 7) + (opt->l & 0x1F); ++ } ++ ++ if (opt->cccra > 0) { ++ /* Turn on the CCCR[A] bit */ ++ opt->regs.cccr |= (1 << 25); ++ } ++ ++ if(opt->cpll_enabled == 0) { ++ opt->regs.cccr |= (CCCR_CPDIS_BIT_ON); ++ } ++ if(opt->ppll_enabled == 0) { ++ opt->regs.cccr |= (CCCR_PPDIS_BIT_ON); ++ } ++ ++} ++ ++static int init_opt(struct dpm_opt *opt) ++{ ++ int v = -1; ++ int l = -1; ++ int n2 = -1; ++ int b = -1; ++ int half_turbo = -1; ++ int cccra = -1; ++ int cpll_enabled = -1; ++ int ppll_enabled = -1; ++ int sleep_mode = -1; ++ struct dpm_md_opt *md_opt = NULL; ++ ++ v = opt->pp[DPM_MD_V]; ++ l = opt->pp[DPM_MD_PLL_L]; ++ n2 = opt->pp[DPM_MD_PLL_N]; /* 2*N */ ++ b = opt->pp[DPM_MD_PLL_B]; /* Fast bus mode bit. */ ++ half_turbo = opt->pp[DPM_MD_HALF_TURBO]; ++ cccra = opt->pp[DPM_MD_CCCRA]; /* Alternate setting ++ for the MEM clock */ ++ cpll_enabled = opt->pp[DPM_MD_CPLL_ON]; ++ ppll_enabled = opt->pp[DPM_MD_PPLL_ON]; ++ sleep_mode = opt->pp[DPM_MD_SLEEP_MODE]; ++ ++ md_opt = &opt->md_opt; ++ ++ /* Up-front error checking. If we fail any of these, then the ++ whole operating point is suspect and therefore invalid. ++ */ ++ ++ /*PXA27x manual ("Yellow book") 3.5.5 (Table 3-7) states that CPLL-"On" and ++ *PPLL-"Off" ++ *configuration is forbidden (all others seam to be OK for "B0") ++ *for "C0" boards we suppose that this configuration is also enabled. ++ *PXA27x manual ("Yellow book") also states at 3.5.7.1 (page 3-25) ++ *that "CCCR[PPDIS] and CCCR[CPDIS] must always be identical and ++ *changed together". "If PLLs are to be turned off using xPDIS then ++ *set xPDIS before frequency change and clear xPDIS after frequency ++ *change" ++ */ ++ ++ if( (l > PLL_L_MIN) && ( cpll_enabled == 0 ) ){ ++ printk(KERN_WARNING ++ "DPM: when l>0 (NOT 13M mode) CPLL must be On \n"); ++ return -EINVAL; ++ } ++ if( (cpll_enabled>0) && (ppll_enabled==0) ){ ++ printk(KERN_WARNING ++ "DPM: illegal combination CPLL=On PPLL=Off\n"); ++ return -EINVAL; ++ } ++ ++ /* Check if voltage is correct */ ++ if(v < -1){ ++ printk(KERN_WARNING ++ "DPM: incorrect voltage %d\n", ++ v); ++ return -EINVAL; ++ } ++ ++ if ((l != -1) && (n2 != -1)) { ++ if (((l && n2) == 0) && (l || n2) != 0) { ++ /* If one of L or N2 is 0, but they are not both 0 */ ++ printk(KERN_WARNING ++ "DPM: L/N (%d/%d) must both be 0 or both be non-zero\n", ++ l, n2); ++ return -EINVAL; ++ } ++ ++ /* Standard range checking */ ++ if (((l > 0) && (n2 > 0)) && /* Don't complain about 0, it means sleep */ ++ ((l > PLL_L_MAX) || ++ (n2 > PLL_N_MAX) || (l < PLL_L_MIN) || (n2 < PLL_N_MIN))) { ++ /* Range checking */ ++ printk(KERN_WARNING ++ "DPM: L/N (%d/%d) out of range, L=1-31, N=2-8 \n", ++ l, n2); ++ return -EINVAL; ++ } ++ ++ /* If this is for 13M mode, do some more checking */ ++ if (l == PLL_L_MIN) { ++ /* ++ NOTE: the Yellow Book does not require any ++ particular setting for N, but we think it really ++ should be 2 ++ */ ++ if (n2 != 2) { ++ printk(KERN_WARNING ++ "DPM: When L=1 (13M Mode), N must be 2 (%d)\n", ++ n2); ++ return -EINVAL; ++ } ++ ++ if ((cpll_enabled != 0) && (cpll_enabled != -1)) { ++ printk(KERN_WARNING ++ "DPM: When L=1 (13M Mode), CPLL must be OFF (%d)\n", ++ cpll_enabled); ++ return -EINVAL; ++ } ++ ++ /* Page 3-32, section 3.5.7.5.2 of the Yellow Book ++ says, "Notes: Other bits in the CLKCFG can not be ++ changed while entering or exiting the 13M ++ mode. While in 13M mode, it is illegal to write to ++ CLKCFG's B, HT, or T bits" ++ */ ++ if ((b > 0) || (half_turbo > 0)) { ++ printk(KERN_WARNING ++ "DPM: When L=1 (13M Mode), B (%d) and " ++ "Half-Turbo (%d) must be off\n", b, half_turbo); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ if (half_turbo > 1) { ++ printk(KERN_WARNING "DPM: Half-Turbo must be 0 or 1 (%d)\n", ++ half_turbo); ++ return -EINVAL; ++ } ++ ++ if (b > 1) { ++ printk(KERN_WARNING ++ "DPM: Fast-Bus Mode (B) must be 0 or 1 (%d)\n", b); ++ return -EINVAL; ++ } ++ ++ /* 2800002.pdf 3.5.7.1 It is illegal to set B if CCCR[CPDIS] is set. */ ++ if( cpll_enabled==0 && b == 1){ ++ printk(KERN_WARNING ++ "DPM: fast bus (b=%d) must both be 0 if CPLL is Off\n", ++ b); ++ return -EINVAL; ++ } ++ ++ if (cccra > 1) { ++ printk(KERN_WARNING ++ "DPM: CCCR[A] (alternate MEMC clock) must be 0 or 1 (%d)\n", ++ cccra); ++ return -EINVAL; ++ } ++ ++ /* This (when CCCR[A] is on and FastBus is on, L must be <=16) ++ is explicitly stated in text at the bottom of one of the ++ CPU frequency tables--the one where CCCR[A] is on */ ++ if ((b == 1) && (cccra == 1) && (l > 16)) { ++ printk(KERN_WARNING ++ "DPM: when B=1 and CCCR[A]=1, L must be <= 16 (L is %d)\n", ++ l); ++ return -EINVAL; ++ } ++ ++ /* This one is not explicitly stated the Yellow Book as a bad ++ thing (as the previous restriction is), but according to ++ the CPU frequency tables, fast bus mode *cannot* be ++ supported, even when CCCR[A] is not 1. ++ */ ++ if ((b == 1) && (l > 16)) { ++ printk(KERN_WARNING ++ "DPM: when B=1, L must be <= 16 (L is %d)\n", l); ++ return -EINVAL; ++ } ++ ++ if (n2 != -1) { ++ if ((half_turbo == 1) && (n2 != 6) && (n2 != 8)) { ++ printk(KERN_WARNING ++ "DPM: Half Turbo only allowed when N2 is 6 or 8\n" ++ "(N2 is %d)\n", n2); ++ return -EINVAL; ++ } ++ } ++ ++ /* Check Sleep Mode versus modes from pm.h ++ NOTE: CPUMODE_SENSE is not implemented. ++ */ ++ if ((l == 0) && (n2 == 0) && (sleep_mode != -1) && ++ (sleep_mode != CPUMODE_STANDBY) && ++ (sleep_mode != CPUMODE_SLEEP) && ++ (sleep_mode != CPUMODE_DEEPSLEEP)) { ++ printk(KERN_WARNING ++ "DPM: Sleep Mode value %d is not allowed" ++ " (only %d, %d, or %d) l=%d n2=%d\n", ++ sleep_mode, ++ CPUMODE_STANDBY, CPUMODE_SLEEP, CPUMODE_DEEPSLEEP, ++ l, n2); ++ return -EINVAL; ++ } ++ ++ /* save the values for this operating point */ ++ md_opt->v = v; ++ md_opt->l = l; ++ md_opt->n = n2; ++ md_opt->b = b; ++ md_opt->cccra = cccra; ++ md_opt->half_turbo = half_turbo; ++ md_opt->cpll_enabled = cpll_enabled; ++ md_opt->ppll_enabled = ppll_enabled; ++ md_opt->sleep_mode = sleep_mode; ++ calculate_lcd_freq(md_opt); ++ ++ if ((md_opt->l == -1) || (md_opt->n == -1)) { ++ md_opt->cpu = -1; ++ } else { ++ /* shift 1 to divide by 2 because opt->n is 2*N */ ++ md_opt->cpu = (13000 * md_opt->l * md_opt->n) >> 1; ++ if (md_opt->half_turbo == 1) { ++ /* divide by 2 */ ++ md_opt->cpu = md_opt->cpu >> 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void fully_define_opt(struct dpm_md_opt *cur, struct dpm_md_opt *new) ++{ ++ if (new->v == -1) ++ new->v = cur->v; ++ if (new->l == -1) ++ new->l = cur->l; ++ if (new->n == -1) ++ new->n = cur->n; ++ if (new->b == -1) ++ new->b = cur->b; ++ if (new->half_turbo == -1) ++ new->half_turbo = cur->half_turbo; ++ if (new->cccra == -1) ++ new->cccra = cur->cccra; ++ if (new->cpll_enabled == -1) ++ new->cpll_enabled = cur->cpll_enabled; ++ if (new->ppll_enabled == -1) ++ new->ppll_enabled = cur->ppll_enabled; ++ if (new->sleep_mode == -1) ++ new->sleep_mode = cur->sleep_mode; ++ ++ if (new->n > 2) { ++ new->turbo = 1; ++ /* turbo mode: 13K * L * (N/2) ++ Shift at the end to divide N by 2 for Turbo mode or ++ by 4 for Half-Turbo mode ) ++ */ ++ new->cpu = (13000 * new->l * new->n) >> ++ ((new->half_turbo == 1) ? 2 : 1); ++ } else { ++ new->turbo = 0; ++ /* run mode */ ++ new->cpu = 13000 * new->l; ++ } ++ /* lcd freq is derived from L */ ++ calculate_lcd_freq(new); ++ calculate_reg_values(new); ++ /* We want to keep a baseline loops_per_jiffy/cpu-freq ratio ++ to work off of for future calculations, especially when ++ emerging from sleep when there is no current cpu frequency ++ to calculate from (because cpu-freq of 0 means sleep). ++ */ ++ if (!saved_loops_per_jiffy) { ++ saved_loops_per_jiffy = loops_per_jiffy; ++ saved_cpu_freq = cur->cpu; ++ } ++ ++ if (new->cpu) { ++ /* Normal change (not sleep), just compute. Always use ++ the "baseline" lpj and freq */ ++ new->lpj = ++ dpm_compute_lpj(saved_loops_per_jiffy, saved_cpu_freq, ++ new->cpu); ++ } else { ++ /* If sleeping, keep the old LPJ */ ++ new->lpj = loops_per_jiffy; ++ } ++} ++ ++static void xpll_on(struct dpm_regs *regs) ++{ ++ int tmp_cccr, tmp_ccsr; ++ int new_cpllon=0, new_ppllon=0, cur_cpllon=0; ++ int cur_ppllon=0, start_cpll=0, start_ppll=0; ++ ++ tmp_ccsr = CCSR; ++ ++ if ((regs->cccr & CCCR_CPDIS_BIT_ON) == 0) ++ new_cpllon = 1; ++ if ((regs->cccr & CCCR_PPDIS_BIT_ON) == 0) ++ new_ppllon = 1; ++ if (((tmp_ccsr >> 31) & 0x1) == 0) ++ cur_cpllon = 1; ++ if (((tmp_ccsr >> 30) & 0x1) == 0) ++ cur_ppllon = 1; ++ ++ if ((new_cpllon == 1) && (cur_cpllon == 0)) ++ start_cpll=1; ++ ++ if ((new_ppllon == 1) && (cur_ppllon == 0)) ++ start_ppll=1; ++ ++ if ((start_cpll == 0) && (start_ppll == 0)) ++ return; ++ ++ /* NOTE: the Yellow Book says that exiting 13M mode requires a ++ PLL relock, which takes at least 120uS, so the book suggests ++ the OS could use a timer to keep busy until it is time to ++ check the CCSR bits which must happen before changing the ++ frequency back. ++ ++ For now, we'll just loop. ++ */ ++ ++ /* From Yellow Book, page 3-31, section 3.5.7.5 13M Mode ++ ++ Exiting 13M Mode: ++ ++ 1. Remain in 13M mode, but early enable the PLL via ++ CCCR[CPDIS, PPDIS]=11, and CCCR[PLL_EARLY_EN]=1. Doing ++ so will allow the PLL to be started early. ++ ++ 2. Read CCCR and compare to make sure that the data was ++ correctly written. ++ ++ 3. Check to see if CCS[CPLOCK] and CCSR[PPLOCK] bits are ++ both set. Once these bits are both high, the PLLs are ++ locked and you may move on. ++ ++ 4. Note that the CPU is still in 13M mode, but the PLLs are ++ started. ++ ++ 5. Exit from 13M mode by writing CCCR[CPDIS, PPDIS]=00, but ++ maintain CCCR[PLL_EARLY_EN]=1. This bit will be cleared ++ by the imminent frequency change. ++ */ ++ ++ /* Step 1 */ ++ tmp_cccr = CCCR; ++ ++ if (start_cpll) ++ tmp_cccr |= CCCR_CPDIS_BIT_ON; ++ ++ if(start_ppll) ++ tmp_cccr |= CCCR_PPDIS_BIT_ON; ++ ++ tmp_cccr |= CCCR_PLL_EARLY_EN_BIT_ON; ++ CCCR = tmp_cccr; ++ ++ /* Step 2 */ ++ tmp_cccr = CCCR; ++ ++#ifdef DEBUG ++ if ((tmp_cccr & CCCR_PLL_EARLY_EN_BIT_ON) != CCCR_PLL_EARLY_EN_BIT_ON) ++ printk(KERN_WARNING ++ "DPM: Warning: PLL_EARLY_EN is NOT on\n"); ++ ++ if ((start_cpll==1) && ++ ((tmp_cccr & CCCR_CPDIS_BIT_ON) != CCCR_CPDIS_BIT_ON)) ++ printk(KERN_WARNING ++ "DPM: Warning: CPDIS is NOT on\n"); ++ ++ if ((start_ppll==1) && ++ (tmp_cccr & CCCR_PPDIS_BIT_ON) != CCCR_PPDIS_BIT_ON) ++ printk(KERN_WARNING ++ "DPM: Warning: PPDIS is NOT on\n"); ++#endif ++ ++ /* Step 3 */ ++ { ++ /* Note: the point of this is to "wait" for the lock ++ bits to be set; the Yellow Book says this may take ++ a while, but observation indicates that it is ++ instantaneous. ++ */ ++ ++ long volatile int i = 0; ++ ++ int cpll_complete=1; ++ int ppll_complete=1; ++ ++ if (start_cpll == 1) ++ cpll_complete=0; ++ ++ if (start_ppll == 1) ++ ppll_complete=0; ++ ++ /*loop arbitrary big value to prevent looping forever */ ++ for (i = 0; i < 999999; i++) { ++ tmp_ccsr = CCSR; ++ ++ if (tmp_ccsr & CCSR_CPLL_LOCKED) ++ cpll_complete=1; ++ ++ if (tmp_ccsr & CCSR_PPLL_LOCKED) ++ ppll_complete=1; ++ ++ if ((cpll_complete == 1) && (ppll_complete == 1)) ++ break; ++ } ++ } ++ ++ /* Step 4: NOP */ ++ ++ /* Step 5 ++ Clear the PLL disable bits - do NOT do it here. ++ */ ++ ++ /* But leave EARLY_EN on; it will be cleared by the frequency change */ ++ regs->cccr |= CCCR_PLL_EARLY_EN_BIT_ON; ++ ++ /* ++ Step 6: Now go continue on with frequency change ++ We do this step later as if voltage is too low, ++ we must ensure that it rised up before entereng to higher ++ freq mode or simultaniously. ++ */ ++} ++ ++static int set_opt(struct dpm_opt *curop, struct dpm_opt *newop) ++{ ++ struct dpm_md_opt *cur, *new; ++ int current_n = (CCSR & CCCR_N_MASK) >> 7; ++ int set_opt_flags = 0; ++ unsigned int cccr, clkcfg = 0; ++ unsigned long s; ++ ++#define SET_OPT_CPUFREQ (1 << 0) ++#define SET_OPT_VOLTAGE (1 << 1) ++#define SET_OPT_TURBO_ON (1 << 2) ++#define SET_OPT_TURBO_OFF (1 << 3) ++#define SET_OPT_TURBO (SET_OPT_TURBO_ON | SET_OPT_TURBO_OFF) ++ ++ pr_debug("set_opt: %s => %s\n", curop->name, newop->name); ++ ++ cur = &curop->md_opt; ++ new = &newop->md_opt; ++ fully_define_opt(cur, new); ++ ++ if (new->regs.voltage != cur->regs.voltage) ++ set_opt_flags |= SET_OPT_VOLTAGE; ++ ++ if (new->cpu) { ++ if ((new->regs.cccr != cur->regs.cccr) || ++ (new->regs.clkcfg != cur->regs.clkcfg)) { ++ ++ /* Find out if it is *just* a turbo bit change */ ++ ++ if ((cur->l == new->l) && ++ (cur->cccra == new->cccra) && ++ (cur->b == new->b) && ++ (cur->half_turbo == new->half_turbo)) { ++ /* If the real, current N is a turbo freq and ++ the new N is not a turbo freq, then set ++ TURBO_OFF and do not change N. ++ */ ++ if ((cur->n > 1) && (new->n == 2)) ++ set_opt_flags |= SET_OPT_TURBO_OFF; ++ ++ /* Else if the current operating point's N is ++ not-turbo and the new N is the desired ++ destination N, then set TURBO_ON ++ */ ++ else if ((cur->n == 2) && (new->n == current_n)) { ++ /* Desired N must be what is current ++ set in the CCCR/CCSR. ++ */ ++ set_opt_flags |= SET_OPT_TURBO_ON; ++ } ++ /* Else, fall through to regular FCS */ ++ } ++ ++ if (!(set_opt_flags & SET_OPT_TURBO)) { ++ /* It this is not a Turbo bit only change, it ++ must be a regular FCS. ++ */ ++ set_opt_flags |= SET_OPT_CPUFREQ; ++ } ++ loops_per_jiffy = new->lpj; ++ } ++ ++ local_irq_save(s); ++ ++ /* If exiting 13M mode (turn on PLL(s)), do some extra work ++ before changing the CPU frequency or voltage. ++ We may turn on a combination of PLLs supported by hardware ++ only. Otherwise xpll_on(...) hang the system. ++ */ ++ ++ if ((!cur->cpll_enabled && new->cpll_enabled) || ++ (!cur->ppll_enabled && new->ppll_enabled)) ++ xpll_on(&new->regs); ++ ++ /* In accordance with Yellow Book section 3.7.6.3, "Coupling ++ Voltage Change with Frequency Change", always set the ++ voltage first (setting the FVC bit in the PCFR) and then do ++ the frequency change ++ */ ++ ++ if (set_opt_flags & SET_OPT_VOLTAGE) { ++ if (set_opt_flags & SET_OPT_CPUFREQ) ++ /* coupled voltage & freq change */ ++ scale_voltage_coupled(&new->regs); ++ else ++ /* Scale CPU voltage un-coupled with freq */ ++ scale_voltage(&new->regs); ++ } ++ ++ if (set_opt_flags & SET_OPT_CPUFREQ) /* Scale CPU freq */ ++ scale_cpufreq(&new->regs); ++ ++ if ((set_opt_flags & SET_OPT_VOLTAGE) && ++ (set_opt_flags & SET_OPT_CPUFREQ)) ++ PCFR &= ~PCFR_FVC; ++ ++ if (set_opt_flags & SET_OPT_TURBO) { ++ clkcfg = read_clkcfg(); ++ ++ /* Section 3.5.7 of the Yellow Book says that the F ++ bit will be left on after a FCS, so we need to ++ explicitly clear it. But do not change the B bit. ++ */ ++ ++ clkcfg &= ~(CLKCFG_F_BIT); ++ ++ if (set_opt_flags & SET_OPT_TURBO_ON) ++ clkcfg = clkcfg | (CLKCFG_T_BIT); ++ else ++ clkcfg = clkcfg & ~(CLKCFG_T_BIT); ++ ++ /* enable */ ++ set_freq(clkcfg); ++ } ++ ++ if (new->half_turbo != cur->half_turbo) { ++ if ((set_opt_flags & SET_OPT_CPUFREQ) || ++ (set_opt_flags & SET_OPT_VOLTAGE)) { ++ /* ++ From the Yellow Book, p 3-106: ++ ++ "Any two writes to CLKCFG or PWRMODE ++ registers must be separated by six 13-MHz ++ cycles. This requirement is achieved by ++ doing the write to the CLKCFG or POWERMODE ++ register, performing a read of CCCR, and ++ then comparing the value in the CLKCFG or ++ POWERMODE register to the written value ++ until it matches." ++ ++ Since the setting of half turbo is a ++ separate write to CLKCFG, we need to adhere ++ to this requirement. ++ */ ++ ++ cccr = CCCR; ++ clkcfg = read_clkcfg(); ++ while (clkcfg != new->regs.clkcfg) ++ clkcfg = read_clkcfg(); ++ } ++ ++ if (clkcfg == 0) ++ clkcfg = new->regs.clkcfg; ++ ++ /* Turn off f-bit. ++ ++ According to the Yellow Book, page 3-23, "If only ++ HT is set, F is clear, and B is not altered, then ++ the core PLL is not stopped." */ ++ ++ clkcfg = clkcfg & ~(CLKCFG_F_BIT); ++ ++ /* set half turbo bit */ ++ ++ if (new->half_turbo) ++ clkcfg = clkcfg | (CLKCFG_HT_BIT); ++ else ++ clkcfg = clkcfg & ~(CLKCFG_HT_BIT); ++ ++ /* enable */ ++ ++ set_freq(clkcfg); ++ loops_per_jiffy = new->lpj; ++ } ++ ++ local_irq_restore(s); ++ ++ } else { ++ ++ /* ++ * A sleep operating point. ++ */ ++ ++#ifdef CONFIG_PM ++ /* NOTE: voltage needs i2c, so be sure to change ++ voltage BEFORE* calling device_suspend ++ */ ++ ++ if (set_opt_flags & SET_OPT_VOLTAGE) ++ /* Scale CPU voltage un-coupled with freq */ ++ scale_voltage(&new->regs); ++ ++ if (new->sleep_mode == CPUMODE_STANDBY) ++ pm_suspend(PM_SUSPEND_STANDBY); ++ else if (new->sleep_mode == CPUMODE_DEEPSLEEP) ++ ; // not supported upstream yet ++ else ++ pm_suspend(PM_SUSPEND_MEM); ++ ++ /* Here when we wake up. */ ++#endif /*CONFIG_PM*/ ++ ++ /* Recursive call to switch back to to task state. */ ++ dpm_set_os(DPM_TASK_STATE); ++ } ++ ++#ifdef CONFIG_DPM_STATS ++ dpm_update_stats(&newop->stats, &dpm_active_opt->stats); ++#endif ++ dpm_active_opt = newop; ++ mb(); ++ ++ /* Devices only need to scale on a core frequency ++ change. Half-Turbo changes are separate from the regular ++ frequency changes, so Half-Turbo changes do not need to ++ trigger a device recalculation. ++ ++ NOTE: turbo-mode-only changes could someday also be ++ optimized like Half-Turbo (to not trigger a device ++ recalc). ++ */ ++ ++ if (new->cpu && (set_opt_flags & SET_OPT_CPUFREQ)) ++ /* Normal change (not sleep), just compute. Always use ++ the "baseline" lpj and freq */ ++ dpm_driver_scale(SCALE_POSTCHANGE, newop); ++ ++ return 0; ++} ++ ++/* Fully determine the current machine-dependent operating point, and fill in a ++ structure presented by the caller. This should only be called when the ++ dpm_sem is held. This call can return an error if the system is currently at ++ an operating point that could not be constructed by dpm_md_init_opt(). */ ++ ++static int get_opt(struct dpm_opt *opt) ++{ ++ unsigned int tmp_cccr; ++ unsigned int cpdis; ++ unsigned int ppdis; ++ struct dpm_md_opt *md_opt = &opt->md_opt; ++ ++ /* You should read CCSR to see what's up...but there is no A ++ bit in the CCSR, so we'll grab it from the CCCR. ++ */ ++ tmp_cccr = CCCR; ++ md_opt->cccra = (tmp_cccr >> 25) & 0x1; /* cccr[A]: bit 25 */ ++ ++ /* NOTE: the current voltage is not obtained, but will be left ++ as 0 in the opt which will mean no voltage change at all. ++ */ ++ ++ md_opt->regs.cccr = CCSR; ++ ++ md_opt->l = md_opt->regs.cccr & CCCR_L_MASK; /* Get L */ ++ md_opt->n = (md_opt->regs.cccr & CCCR_N_MASK) >> 7; /* Get 2N */ ++ ++ /* This should never really be less than 2 */ ++ if (md_opt->n < 2) { ++ md_opt->n = 2; ++ } ++ ++ md_opt->regs.clkcfg = read_clkcfg(); ++ md_opt->b = (md_opt->regs.clkcfg >> 3) & 0x1; /* Fast Bus (b): bit 3 */ ++ md_opt->turbo = md_opt->regs.clkcfg & 0x1; /* Turbo is bit 1 */ ++ md_opt->half_turbo = (md_opt->regs.clkcfg >> 2) & 0x1; /* HalfTurbo: bit 2 */ ++ ++ calculate_lcd_freq(md_opt); ++ ++ /* are any of the PLLs is on? */ ++ cpdis = ((md_opt->regs.cccr >> 31) & 0x1); ++ ppdis = ((md_opt->regs.cccr >> 30) & 0x1); ++ /* Newer revisions still require that if CPLL is On ++ then PPLL must also be On. ++ */ ++ if ((cpdis == 0) && (ppdis != 0)) { ++ /* CPLL=On PPLL=Off is NOT supported with hardware. ++ NOTE:"B0"-revision has even more restrictive requirments ++ to PLLs ++ */ ++ printk("DPM: cpdis and ppdis are not in sync!\n"); ++ } ++ ++ md_opt->cpll_enabled = (cpdis == 0); ++ md_opt->ppll_enabled = (ppdis == 0); ++ ++ /* Shift 1 to divide by 2 (because opt->n is really 2*N */ ++ if (md_opt->turbo) { ++ md_opt->cpu = (13000 * md_opt->l * md_opt->n) >> 1; ++ } else { ++ /* turbo bit is off, so skip N multiplier (no matter ++ what N really is) and use Run frequency (13K * L) ++ */ ++ md_opt->cpu = 13000 * md_opt->l; ++ } ++ ++ return 0; ++} ++ ++/**************************************************************************** ++ * DPM Idle Handler ++ ****************************************************************************/ ++ ++static void (*orig_idle) (void); ++ ++static void dpm_pxa27x_idle(void) ++{ ++ extern void default_idle(void); ++ ++ if (orig_idle) ++ orig_idle(); ++ else { ++ /* ++ * arch/arm/kernel/process.c: default_idle() ++ * do be sure to watch for updates :( ++ */ ++ ++ local_irq_disable(); ++ if (!need_resched()) { ++ timer_dyn_reprogram(); ++ arch_idle(); ++ } ++ local_irq_enable(); ++ } ++} ++ ++/**************************************************************************** ++ * Initialization/Exit ++ ****************************************************************************/ ++ ++extern void (*pm_idle) (void); ++ ++static void startup(void) ++{ ++ orig_idle = pm_idle; ++ pm_idle = dpm_idle; ++} ++ ++static void cleanup(void) ++{ ++ pm_idle = orig_idle; ++} ++ ++static int __init dpm_pxa27x_init(void) ++{ ++ printk("PXA27x Dynamic Power Management\n"); ++ ++ if (freq_init()) { ++ printk("PXA27x DPM init failed\n"); ++ return -1; ++ } ++ ++ vcs_init(); ++ dpm_md.init_opt = init_opt; ++ dpm_md.set_opt = set_opt; ++ dpm_md.get_opt = get_opt; ++ dpm_md.check_constraint = dpm_default_check_constraint; ++ dpm_md.idle = dpm_pxa27x_idle; ++ dpm_md.startup = startup; ++ dpm_md.cleanup = cleanup; ++ return 0; ++} ++ ++static void __exit dpm_pxa27x_exit(void){ ++ freq_cleanup(); ++} ++ ++__initcall(dpm_pxa27x_init); ++__exitcall(dpm_pxa27x_exit); +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/ezx.c linux-2.6.16/arch/arm/mach-pxa/ezx.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/ezx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/ezx.c 2006-06-03 11:14:57.125204904 +0200 +@@ -0,0 +1,881 @@ ++/* ++ * linux/arch/arm/mach-ezx/a780.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Zhuang Xiaofan ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola 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 <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/bitops.h> ++#include <linux/mmc/host.h> ++#include <linux/fb.h> ++#include <linux/apm_bios.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++#include <linux/input.h> ++#include <linux/spi/spi.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/arch/mmc.h> ++#include <asm/arch/udc.h> ++#include <asm/arch/ohci.h> ++#include <asm/arch/kbd.h> ++#include <asm/arch/pxafb.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx.h> ++#include <asm/arch/spi.h> ++ ++#include "generic.h" ++#include <linux/tty.h> ++#include <linux/apm_bios.h> ++ ++#include "../../../drivers/misc/ezx/ezx-emu.h" ++ ++#define FIRST_STEP 2 ++#define LAST_STEP 3 ++#define BP_RDY_TIMEOUT 0x000c0000 ++ ++extern void usb_send_readurb(void); ++extern void pm_do_poweroff(void); ++ ++/* Bluetooth stuff */ ++void ezx_bt_wakeup(int on) ++{ ++ printk(KERN_NOTICE "switching BT wakeup %d\n", on); ++ if (on) ++ set_GPIO(GPIO_BT_WAKEUP); ++ else ++ clr_GPIO(GPIO_BT_WAKEUP); ++} ++EXPORT_SYMBOL(ezx_bt_wakeup); ++ ++void ezx_bt_reset(int on) ++{ ++ printk(KERN_NOTICE "switching BT reset %d\n", on); ++ if (on) ++ set_GPIO(GPIO_BT_RESET); ++ else ++ clr_GPIO(GPIO_BT_RESET); ++} ++EXPORT_SYMBOL(ezx_bt_reset); ++ ++/* check power down condition */ ++inline void check_power_off(void) ++{ ++ if (!(GPIO_is_high(GPIO_BB_WDI2))) { ++#ifdef CONFIG_PM ++ pm_do_poweroff(); ++#endif ++ } ++} ++ ++/* OHCI Controller */ ++ ++static int ezx_ohci_init(struct device *dev) ++{ ++ /* for A780 support (connected with Neptune) */ ++ pxa_gpio_mode(GPIO30_USB_P3_2); /* GPIO30 - USB_P3_2/ICL_TXENB */ ++ pxa_gpio_mode(GPIO31_USB_P3_6); /* GPIO31 - USB_P3_6/ICL_VPOUT */ ++ pxa_gpio_mode(GPIO90_USB_P3_5); /* GPIO90 - USB_P3_5/ICL_VPIN */ ++ pxa_gpio_mode(GPIO91_USB_P3_1); /* GPIO91 - USB_P3_1/ICL_XRXD */ ++ pxa_gpio_mode(GPIO56_USB_P3_4); /* GPIO56 - USB_P3_4/ICL_VMOUT */ ++ pxa_gpio_mode(GPIO113_USB_P3_3);/* GPIO113 - USB_P3_3/ICL_VMIN */ ++ UP3OCR = 0x00000002; ++ ++ UHCHR = UHCHR & ~(UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); ++ ++ return 0; ++} ++ ++static struct pxaohci_platform_data ezx_ohci_platform_data = { ++ .port_mode = PMM_NPS_MODE, ++ .init = ezx_ohci_init, ++}; ++ ++/* MMC/SD Device */ ++ ++static struct pxamci_platform_data ezx_mci_platform_data; ++ ++static int ezx_mci_init(struct device *dev, ++ irqreturn_t (*ezx_detect_int)(int, void *, struct pt_regs *), ++ void *data) ++{ ++ int err; ++ printk("%s entered\n", __FUNCTION__); ++ ++ /* Setup GPIO for PXA27x MMC/SD controller */ ++ pxa_gpio_mode(GPIO32_MMCCLK_MD); ++ pxa_gpio_mode(GPIO112_MMCCMD_MD); ++ pxa_gpio_mode(GPIO92_MMCDAT0_MD); ++ pxa_gpio_mode(GPIO109_MMCDAT1_MD); ++ pxa_gpio_mode(GPIO110_MMCDAT2_MD); ++ pxa_gpio_mode(GPIO111_MMCDAT3_MD); ++ ++ ezx_pcap_mmcsd_power(1); ++ ++ ezx_mci_platform_data.detect_delay = msecs_to_jiffies(250); ++ ++ err = request_irq(0x49, ezx_detect_int, SA_INTERRUPT, ++ "MMC card detect", data); ++ if (err) { ++ printk(KERN_ERR "ezx_mci_detect: MMC/SD: can't request " ++ "MMC card detect IRQ\n"); ++ return -1; ++ } ++ ++ set_GPIO_IRQ_edge(0x0b, GPIO_BOTH_EDGES); ++ ++ return 0; ++} ++ ++static int ezx_mci_get_ro(struct device *dev) ++{ ++ printk("%s entered\n", __FUNCTION__); ++#if defined(CONFIG_PXA_EZX_E680) ++ /* this is only e680, i guess */ ++ // return GPIO_is_high(96+4); ++ return (GPLR3 & 0x800); ++#else ++ return 0; ++#endif ++} ++ ++#if defined(CONFIG_PXA_EZX_A780) ++static u_int8_t mmc_voltage[] = { ++ [MMC_VDD_160] = 5, ++ [MMC_VDD_170] = 5, ++ [MMC_VDD_180] = 6, ++ [MMC_VDD_190] = 6, ++ [MMC_VDD_200] = 7, ++ [MMC_VDD_210] = 7, ++ [MMC_VDD_220] = 8, ++ [MMC_VDD_230] = 8, ++ [MMC_VDD_240] = 9, ++ [MMC_VDD_250] = 9, ++ [MMC_VDD_260] = 10, ++ [MMC_VDD_270] = 10, ++ [MMC_VDD_280] = 11, ++ [MMC_VDD_290] = 11, ++ [MMC_VDD_300] = 12, ++ [MMC_VDD_310] = 12, ++ [MMC_VDD_320] = 13, ++ [MMC_VDD_330] = 13, ++ [MMC_VDD_340] = 14, ++ [MMC_VDD_350] = 14, ++ [MMC_VDD_360] = 15, ++}; ++#elif defined(CONFIG_PXA_EZX_E680) ++static u_int8_t mmc_voltage[] = { ++ [MMC_VDD_160] = 3, ++ [MMC_VDD_170] = 3, ++ [MMC_VDD_180] = 3, ++ [MMC_VDD_190] = 3, ++ [MMC_VDD_200] = 3, ++ [MMC_VDD_210] = 3, ++ [MMC_VDD_220] = 3, ++ [MMC_VDD_230] = 3, ++ [MMC_VDD_240] = 3, ++ [MMC_VDD_250] = 3, ++ [MMC_VDD_260] = 3, ++ [MMC_VDD_270] = 3, ++ [MMC_VDD_280] = 3, ++ [MMC_VDD_290] = 3, ++ [MMC_VDD_300] = 3, ++ [MMC_VDD_310] = 3, ++ [MMC_VDD_320] = 3, ++ [MMC_VDD_330] = 3, ++ [MMC_VDD_340] = 3, ++ [MMC_VDD_350] = 3, ++ [MMC_VDD_360] = 3, ++ ++}; ++#endif ++ ++static void ezx_mci_setpower(struct device *dev, unsigned int vdd) ++{ ++ printk("%s(vdd=%u) entered\n", __FUNCTION__, vdd); ++ if (vdd <= MMC_VDD_360) ++ SSP_PCAP_MMCSD_voltage(mmc_voltage[vdd]); ++ ++ ezx_pcap_mmcsd_power(1); ++} ++ ++static void ezx_mci_exit(struct device *dev, void *data) ++{ ++ printk("%s entered\n", __FUNCTION__); ++ ezx_pcap_mmcsd_power(0); ++ free_irq(0x49, data); ++} ++ ++static struct pxamci_platform_data ezx_mci_platform_data = { ++#if defined(CONFIG_PXA_EZX_E680) ++ .ocr_mask = MMC_VDD_27_28, ++#elif defined(CONFIG_PXA_EZX_A780) ++ .ocr_mask = MMC_VDD_160_165|MMC_VDD_18_19|MMC_VDD_20_21 ++ |MMC_VDD_22_23|MMC_VDD_24_25|MMC_VDD_26_27 ++ |MMC_VDD_28_29|MMC_VDD_30_31|MMC_VDD_32_33 ++ |MMC_VDD_34_35|MMC_VDD_35_36, ++#endif ++ .init = ezx_mci_init, ++ .get_ro = ezx_mci_get_ro, ++ .setpower = ezx_mci_setpower, ++ .exit = ezx_mci_exit, ++}; ++ ++/* USB Device Controller */ ++ ++static int udc_connected_status; ++ ++static void ezx_udc_command(int cmd) ++{ ++ switch (cmd) { ++ case PXA2XX_UDC_CMD_DISCONNECT: ++ printk(KERN_NOTICE "USB cmd disconnect\n"); ++ pcap_switch_off_usb(); ++ udc_connected_status = 0; ++ break; ++ case PXA2XX_UDC_CMD_CONNECT: ++ printk(KERN_NOTICE "USB cmd connect\n"); ++ pcap_switch_on_usb(); ++ udc_connected_status = 1; ++ break; ++ } ++} ++ ++static int ezx_udc_is_connected(void) ++{ ++ return udc_connected_status; ++} ++ ++static struct pxa2xx_udc_mach_info ezx_udc_info __initdata = { ++ .udc_is_connected = ezx_udc_is_connected, ++ .udc_command = ezx_udc_command, ++}; ++ ++/* pxafb */ ++ ++#define BKLIGHT_PRESCALE 2 ++#define BKLIGHT_PERIOD 49 ++#define DEFAULT_DUTYCYCLE 25 ++#define MAX_DUTYCYCLE (BKLIGHT_PERIOD+1) ++#define MIN_DUTYCYCLE 0 ++ ++static void pxafb_backlight_power(int on) ++{ ++ if (on) { ++ CKEN |= CKEN0_PWM0; ++ PWM_CTRL0 = BKLIGHT_PRESCALE; ++ PWM_PERVAL0 = BKLIGHT_PERIOD; ++ PWM_PWDUTY0 = DEFAULT_DUTYCYCLE; ++ ++ GPDR0 |= 0x00010000; //PWM0 is GPIO16 ++ pxa_gpio_mode(GPIO16_PWM0_MD); ++ } else { ++ PWM_PWDUTY0 = 0; ++ GAFR0_U &= 0xfffffffc; ++ GPDR0 &= 0xfffeffff; /* set gpio16 (pwm0) as input */ ++ CKEN &= ~CKEN0_PWM0; ++ PWM_PWDUTY0 = MIN_DUTYCYCLE; ++ } ++} ++ ++//#define mdelay(x) udelay((x)*1000) ++ ++static void pxafb_lcd_power(int on) ++{ ++ if (on) { ++ mdelay(1); ++ GPSR3 = 0x00100000; ++ mdelay(10); ++ GPCR3 = 0x00100000; ++ GPDR3 |= 0x00100000; ++ } else { ++ GPSR3 = 0x00100000; ++ PGSR3 |= 0x00100000; ++ mdelay(41); ++ LCCR0 &= ~LCCR0_LDM; /* disable lcd disable done interrupt */ ++ LCCR0 |= LCCR0_DIS; /* normal disable lcd */ ++ mdelay(18); ++ } ++} ++ ++static struct pxafb_mach_info ezx_fb_info __initdata = { ++ .pixclock = 150000, ++ .xres = 240, ++ .yres = 320, ++ .bpp = 16, ++ ++ .hsync_len = 10, ++ .left_margin = 20, ++ .right_margin = 10, ++ ++ .vsync_len = 2, ++ .upper_margin = 3, ++ .lower_margin = 2, ++ ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ ++ .lccr0 = 0x002008F8, ++ .lccr3 = 0x0430FF09, ++ ++ .pxafb_backlight_power = &pxafb_backlight_power, ++ .pxafb_lcd_power = &pxafb_lcd_power, ++}; ++ ++ ++/* backlight for lcd */ ++ ++static struct resource ezx_backlight_resources[] = { ++}; ++ ++static struct platform_device ezx_backlight_device = { ++ .name = "ezx-lcd-backlight", ++ .id = -1, ++ .resource = ezx_backlight_resources, ++ .num_resources = ARRAY_SIZE(ezx_backlight_resources), ++}; ++ ++/* keyboard */ ++ ++#if defined(CONFIG_PXA_EZX_V700) ++#error "kbd matrix still needs to be converted to new row/col layout" ++static unsigned char ezx_keycode[] = { ++ /* col 0 */ ++ KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, ++ KEYPAD_POUND, KEY_0, KEY_9, 0, ++ /* col 1 */ ++ KEY_2, KEY_4, KEY_6, KEY_8, ++ KEY_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, 0, ++ /* col 2 */ ++ KEY_MENU, KEY_1, KEY_3, KEY_5, ++ KEY_KPASTERISK, KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, ++ /* col 3 */ ++ KEY_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, ++ KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, 0, ++}; ++static unsigned char ezx_direct_keycode[] = { ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++}; ++#elif defined(CONFIG_PXA_EZX_E680_P4A) ++#error "kbd matrix still needs to be converted to new row/col layout" ++static unsigned char ezx_keycode[] = { ++ /* col 0 */ ++ KEY_UP, KEY_DOWN, KEY_LEFT, 0, 0, 0, 0, 0, ++ /* col 1 */ ++ KEY_RIGHT, KEY_CENTER, KEY_HOME, 0, 0, 0, 0, 0, ++ /* col 2 */ ++ KEYPAD_GAME_R, 0, KEYPAD_GAME_L, 0, 0, 0, 0, 0, ++ /* col 3 */ ++ KEY_A, KEY_B, 0, 0, 0, 0, 0, 0, ++}; ++static unsigned char ezx_direct_keycode[] = { ++ KEY_CAMERA, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEY_POWER, ++ KEYPAD_NONE, ++}; ++#elif defined(CONFIG_PXA_EZX_E680) ++#error "kbd matrix still needs to be converted to new row/col layout" ++static unsigned char ezx_keycode[] = { ++ /* col 0 */ ++ KEY_UP, KEY_DOWN, 0, 0, 0, 0, 0, 0, ++ /* col 1 */ ++ KEY_RIGHT, KEY_LEFT, 0, 0, 0, 0, 0, 0, ++ /* col 2 */ ++ 0, KEYPAD_GAME_R, 0, 0, 0, 0, 0, 0, ++ /* col 3 */ ++ KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, 0, 0, 0, 0, 0, ++}; ++static unsigned char ezx_direct_keycode[] = { ++ KEY_CAMERA, ++ KEYPAD_NONE, ++ KEYPAD_NONE, ++ KEYPAD_A, ++ KEY_POWER, ++ KEYPAD_B, ++}; ++#elif defined(CONFIG_PXA_EZX_A780) ++static unsigned char ezx_keycode[] = { ++ /* row 0 */ ++ KEY_KPENTER, KEY_MENU, KEY_CANCEL, KEY_PAGEUP, KEY_UP, ++ /* row 1 */ ++ KEY_KP1, KEY_KP2, KEY_KP3, KEY_ENTER, KEY_KPENTER, /*center joypad */ ++ /* row 2 */ ++ KEY_KP4, KEY_KP5, KEY_KP6, KEY_PAGEDOWN, KEY_PHONE, ++ /* row 3 */ ++ KEY_KP7, KEY_KP8, KEY_KP9, KEY_PHONE, KEY_LEFT, ++ /* row 4 */ ++ KEY_KPASTERISK, KEY_KP0, KEY_KPDOT, KEY_PAGEDOWN, KEY_DOWN, ++}; ++static unsigned char ezx_direct_keycode[] = { ++ KEY_CAMERA, ++}; ++#else ++#error "no EZX subarchitecture defined !?!" ++#endif ++ ++static int ezx_kbd_init(void) ++{ ++#if defined(CONFIG_PXA_EZX_E680_P4A) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_PXA_EZX_E680) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++#elif defined (CONFIG_PXA_EZX_A780) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ ++#endif ++} ++ ++ ++static struct pxakbd_platform_data ezx_kbd_platform_data = { ++ .init = &ezx_kbd_init, ++ .scan_interval = HZ/40, ++ .matrix = { ++ .keycode = &ezx_keycode, ++#if defined(CONFIG_ARCH_EXZ_E680_P4A) ++ .cols = 4, ++ .rows = 3, ++#elif defined(CONFIG_PXA_EZX_E680) ++ .cols = 4, ++ .rows = 3, ++#elif defined(CONFIG_PXA_EZX_A780) ++ .cols = 5, ++ .rows = 5, ++#endif ++ }, ++ .direct = { ++ .keycode = &ezx_direct_keycode, ++#if defined(CONFIG_PXA_EZX_E680_P4A) ++ .num = 4, ++#elif defined(CONFIG_PXA_EZX_E680) ++ .num = 5, ++#elif defined(CONFIG_PXA_EZX_A780) ++ .num = 1, ++#endif ++ }, ++}; ++ ++/* touch screen */ ++ ++/* SPI master devices */ ++ ++static int ezx_spi_init(unsigned int num) ++{ ++ switch (num) { ++ case 1: ++ pxa_gpio_mode(GPIO24_SFRM_MD); ++ pxa_gpio_mode(GPIO25_STXD_MD); ++ pxa_gpio_mode(GPIO26_SRXD_MD); ++ pxa_gpio_mode(GPIO29_SCLK_MD); ++ break; ++ case 2: ++ pxa_gpio_mode(GPIO22_SCLK2_MD); ++ pxa_gpio_mode(GPIO37_SFRM2_MD); ++ pxa_gpio_mode(GPIO38_STXD2_MD); ++ pxa_gpio_mode(GPIO88_SRXD2_MD); ++ break; ++ case 3: ++ pxa_gpio_mode(GPIO52_SCLK3_MD); ++ pxa_gpio_mode(GPIO83_SFRM3_MD); ++ pxa_gpio_mode(GPIO81_STXD3_MD); ++ pxa_gpio_mode(GPIO89_SRXD3_MD); ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static struct pxa_spi_data ezx_spi_data = { ++ .init = &ezx_spi_init, ++}; ++ ++/* SPI/SSP controller devices */ ++ ++static struct spi_board_info spi_board_info[] __initdata = { ++ { ++ .modalias = "ezx-pcap", ++ .max_speed_hz = 13000000, ++ .bus_num = 1, ++ .irq = IRQ_GPIO1, ++ }, { ++ .modalias = "ezx-snd", ++ .max_speed_hz = 8000000, ++ .bus_num = 2, ++ }, { ++ .modalias = "ezx-snd", ++ .max_speed_hz = 8000000, ++ .bus_num = 3, ++ }, ++}; ++ ++static int step = FIRST_STEP; ++void handshake(void) ++{ ++ /* step 1: check MCU_INT_SW or BP_RDY is low (now it is checked in apboot) */ ++ if (step == 1) { ++ int timeout = BP_RDY_TIMEOUT; ++ ++ /* config MCU_INT_SW, BP_RDY as input */ ++ GPDR(GPIO_MCU_INT_SW) &= ~GPIO_bit(GPIO_MCU_INT_SW); ++ GPDR(GPIO_BP_RDY) &= ~GPIO_bit(GPIO_BP_RDY); ++ ++ while ( timeout -- ) { ++ if ( (!(GPIO_is_high(GPIO_MCU_INT_SW))) ++ || (!(GPIO_is_high(GPIO_BP_RDY))) ) { ++ step ++; ++ break; ++ } ++ ++ check_power_off(); ++ } ++ } ++ ++ /* step 2: wait BP_RDY is low */ ++ if (step == 2) { ++ if (!(GPIO_is_high(GPIO_BP_RDY))) { ++ ++ /* config MCU_INT_SW as output */ ++ pxa_gpio_mode(GPIO_MCU_INT_SW | GPIO_OUT); ++ clr_GPIO(GPIO_MCU_INT_SW); ++ ++ step ++; ++ } ++ } ++ ++ /* step 3: wait BP_RDY is high */ ++ if (step == 3) { ++ if (GPIO_is_high(GPIO_BP_RDY)) { ++ step ++; ++ //FIXME delay_bklight(); ++ set_GPIO(GPIO_MCU_INT_SW); ++ } ++ } ++} ++ ++#ifdef CONFIG_APM ++static unsigned long idle_limit = 0; ++int pm_handle_irq(int irq) ++{ ++ ++ //FIXME: extern unsigned long idle_limit; ++ //FIXME: extern int can_idle, can_sleep; ++ static unsigned long tmp_jiffy; /* for temporary store of jiffies */ ++ ++ /* ++ * if idle_limit is zero, never enter idle. ++ * if not OS timer, reset idle timer count ++ */ ++ if (idle_limit == 0) { ++ tmp_jiffy = jiffies; ++ return irq; ++ } ++#if 0 ++ if (irq != IRQ_OST0) { ++ tmp_jiffy = jiffies; ++ can_idle = 0; ++ can_sleep = 0; ++ } else if (jiffies > tmp_jiffy + idle_limit) { ++ ++ /* ++ * I think this is enough to prevent from reentering here ++ * due to jiffies will be stoped ++ */ ++ tmp_jiffy = jiffies; ++ ++ /* if pm idle timer expired, queue event */ ++ apm_queue_event(KRNL_PROC_INACT); ++ can_idle = 1; ++ } ++#endif ++ ++ return irq; ++} ++ ++irqreturn_t bp_wdi_intr(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ apm_queue_event(KRNL_BP_WDI); ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction bp_wdi_irq = { ++ .name = "BP wdi", ++ .handler = &bp_wdi_intr, ++}; ++#endif ++ ++int handshake_pass(void) ++{ ++ return (step > LAST_STEP); ++} ++ ++static irqreturn_t bp_rdy_intr(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ static int usbipc_ready = 0; ++ ++ if (!usbipc_ready) { ++ handshake(); ++ if (handshake_pass()) { ++ disable_irq(IRQ_GPIO(GPIO_BB_WDI2)); ++ ++ /* set bp_rdy handle for usb ipc */ ++ set_GPIO_IRQ_edge(GPIO_BP_RDY, GPIO_FALLING_EDGE); ++ usbipc_ready = 1; ++ } ++ } else ++ // FIXME usb_send_readurb(); ++ {} ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction bp_rdy_irq = { ++ .name = "BP rdy", ++ .handler = bp_rdy_intr, ++}; ++ ++static irqreturn_t bp_wdi2_intr(int irq, void *dev_id, struct pt_regs *regs) ++{ ++#ifdef CONFIG_PM ++ pm_do_poweroff(); ++#endif ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction bp_wdi2_irq = { ++ .name = "BP wdi2", ++ .handler = bp_wdi2_intr, ++}; ++ ++ ++static struct resource ezx_bp_resources[] = { ++ [0] = { ++ .start = GPIO_BP_RDY, ++ .end = GPIO_BP_RDY, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [1] = { ++ .start = GPIO_BB_WDI2, ++ .end = GPIO_BB_WDI2, ++ .flags = IORESOURCE_IRQ, ++ }, ++#ifdef CONFIG_APM ++ [2] = { ++ .start = GPIO_BB_WDI, ++ .end = GPIO_BB_WDI, ++ .flags = IORESOURCE_IRQ, ++ }, ++#endif ++}; ++ ++static struct platform_device ezx_bp_device = { ++ .name = "ezx-bp", ++ .dev = { ++ //.parent = ++ //.platform_data = ++ }, ++ .id = -1, ++ .num_resources = ARRAY_SIZE(ezx_bp_resources), ++ .resource = ezx_bp_resources, ++}; ++ ++static void __init ezx_init_gpio_irq(void) ++{ ++#ifdef CONFIG_APM ++ set_GPIO_IRQ_edge(GPIO_BB_WDI, GPIO_FALLING_EDGE); ++ setup_irq(IRQ_GPIO(GPIO_BB_WDI), &bp_wdi_irq); ++#endif ++ set_GPIO_IRQ_edge(GPIO_BP_RDY, GPIO_BOTH_EDGES); ++ setup_irq(IRQ_GPIO(GPIO_BP_RDY), &bp_rdy_irq); ++ ++ set_GPIO_IRQ_edge(GPIO_BB_WDI2, GPIO_FALLING_EDGE); ++ setup_irq(IRQ_GPIO(GPIO_BB_WDI2), &bp_wdi2_irq); ++} ++ ++static void __init a780_init_irq(void) ++{ ++ pxa_init_irq(); ++ ++ /* init ezx specfic gpio irq */ ++ ezx_init_gpio_irq(); ++ ++ check_power_off(); ++ handshake(); ++ if (handshake_pass()) { ++ disable_irq(IRQ_GPIO(GPIO_BP_RDY)); ++ disable_irq(IRQ_GPIO(GPIO_BB_WDI2)); ++ } ++} ++ ++static struct platform_device *devices[] __initdata = { ++ &ezx_bp_device, ++}; ++ ++static void __init ++fixup_a780(struct machine_desc *desc, struct tag *tag, ++ char **cmdline, struct meminfo *mi) ++{ ++ screen_info.orig_video_cols = 30; ++ screen_info.orig_video_lines = 80; ++} ++ ++static void __init a780_init(void) ++{ ++ CKEN = CKEN9_OSTIMER | CKEN22_MEMC | CKEN5_STUART; ++ ++ /* set BB_RESET PIN out put high */ ++ pxa_gpio_mode(GPIO_BB_RESET|GPIO_OUT); ++ set_GPIO(GPIO_BB_RESET); ++ ++ pxa_gpio_mode(GPIO_ICL_FFRXD_MD); ++ pxa_gpio_mode(GPIO_ICL_FFTXD_MD); ++ pxa_gpio_mode(GPIO_ICL_FFCTS_MD); ++ pxa_gpio_mode(GPIO_ICL_FFRTS_MD); ++ ++ pxa_gpio_mode(GPIO42_BTRXD_MD); ++ pxa_gpio_mode(GPIO43_BTTXD_MD); ++ pxa_gpio_mode(GPIO44_BTCTS_MD); ++ pxa_gpio_mode(GPIO45_BTRTS_MD); ++ ++ /* clear EMU MUX1/MUX2 (low) to close the audio path to EMU */ ++ pxa_gpio_mode(GPIO_EMU_MUX1|GPIO_OUT); ++ clr_GPIO(GPIO_EMU_MUX1); ++ pxa_gpio_mode(GPIO_EMU_MUX2|GPIO_OUT); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++#if defined(CONFIG_PXA_EZX_E680) ++ pxa_gpio_mode(GPIO46_STRXD_MD); ++ pxa_gpio_mode(GPIO47_STTXD_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0xc000f803; // disable usb 0xdc00f803; ++ PFER = 0x0000f803; ++ PRER = 0x00001802; ++ // keypad wakeup (PKWR,PGSR3) should be in keypad.c ++ PGSR0 = 0x00000010; ++ PGSR1 = 0x02800000; ++ PGSR2 = 0x00040000; ++ PGSR3 = 0x00000000; ++ PCFR = PCFR_DC_EN | PCFR_FS | PCFR_FP | PCFR_OPDE; ++ PSLR = 0x05800f00; ++ ++#elif defined(CONFIG_PXA_EZX_A780) ++ ++ /* Standard UART */ ++ pxa_gpio_mode(GPIO46_STRXD_MD); ++ pxa_gpio_mode(GPIO47_STTXD_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0xc0007803; // disable usb, GPIO15 NC ++ PFER = 0x00007803; ++ PRER = 0x00001802; ++ // keypad wakeup (PKWR,PGSR3) should be in keypad.c ++ PGSR0 = 0x00000010; ++ PGSR1 = 0x02800000; ++ PGSR2 = 0x00040000; ++ PGSR3 = 0x00000008; ++ PCFR = PCFR_DC_EN | PCFR_FS | PCFR_FP | PCFR_OPDE; ++ PSLR = 0x05800f00; ++ ++#endif ++ set_pxa_fb_info(&ezx_fb_info); ++ pxa_set_udc_info(&ezx_udc_info); ++ pxa_set_mci_info(&ezx_mci_platform_data); ++ pxa_set_ohci_info(&ezx_ohci_platform_data); ++ pxa_set_kbd_info(&ezx_kbd_platform_data); ++ ++ ssp_pcap_init(); ++ ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ ++ /* enable this line when you want to run FFUART on the USB plug */ ++ //emu_switch_to(EMU_SWITCH_TO_UART); ++ /* enable this line when you want to output power on the USB plug */ ++ //SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_MSTR_EN); ++ ++ platform_add_devices(devices, ARRAY_SIZE(devices)); ++ ++#ifdef CONFIG_PXA_SPI ++ /* register all three SPI busses */ ++ pxa_register_spi(1, &ezx_spi_data); ++ //pxa_register_spi(2, &ezx_spi_data); ++ //pxa_register_spi(3, &ezx_spi_data); ++ ++ /* register information about SPI slaves attached to SPI */ ++ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); ++#endif ++} ++ ++MACHINE_START(EZX, "Motorola Ezx Platform") ++ /* Maintainer: Harald Welte <laforge@gnumonks.org> */ ++ .phys_ram = 0xa0000000, ++ .phys_io = 0x40000000, ++ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, ++ .boot_params = 0xa0000100, ++ .fixup = fixup_a780, ++ .map_io = pxa_map_io, ++ .init_irq = a780_init_irq, ++ .timer = &pxa_timer, ++ .init_machine = a780_init, ++MACHINE_END +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/ezx-compat.c linux-2.6.16/arch/arm/mach-pxa/ezx-compat.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/ezx-compat.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/ezx-compat.c 2006-06-03 11:14:56.251337752 +0200 +@@ -0,0 +1,24 @@ ++ ++int set_GPIO_IRQ_edge(int irq, int type) ++{ ++ int mytype; ++ ++ switch (type) { ++ case GPIO_FALLING_EDGE: ++ mytype = IRQT_FALLING; ++ break; ++ case GPIO_RISING_EDGE: ++ mytype = IRQT_RISING; ++ break; ++ case GPIO_BOTH_EDGES: ++ mytype = IRQT_BOTHEDGE; ++ break; ++ default: ++ return -EINVAL; ++ break; ++ } ++ ++ return set_irq_type(irq, mytype); ++} ++ ++ +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/ezx-pcap.c linux-2.6.16/arch/arm/mach-pxa/ezx-pcap.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/ezx-pcap.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/ezx-pcap.c 2006-06-03 11:14:57.124205056 +0200 +@@ -0,0 +1,483 @@ ++/* Driver for Motorola PCAP2 as present in EZX phones ++ * ++ * This is both a SPI device driver for PCAP itself, as well as ++ * an IRQ demultiplexer for handling PCAP generated events such as ++ * headphone jack sense by downstream drivers. ++ * ++ * (C) 2006 by Harald Welte <laforge@openezx.org> ++ */ ++ ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/kernel_stat.h> ++#include <linux/spi/spi.h> ++ ++#include <asm/arch/ezx-pcap.h> ++#include <asm/arch/irqs.h> ++#include <asm/mach/irq.h> ++ ++#if 0 ++#define DEBUGP(x, args...) printk(x, ## args) ++#else ++#define DEBUGP(x, args...) ++#endif ++ ++/* lowlevel functions for register access */ ++ ++static struct { ++ struct spi_transfer transfer; ++ u_int32_t rx_buf; ++ u_int32_t tx_buf; ++ spinlock_t lock; /* lock protecting transfer + buffers */ ++} pcap_spi; ++ ++/* this is a static pointer to the PCAP spi device. We can keep this around ++ * since it wouldn't make sense to have two PCAP devices in a single phone ++ * anyway */ ++static struct spi_device *pcap_spi_dev; ++ ++int ezx_pcap_write(u_int8_t reg_num, u_int32_t value) ++{ ++ int ret; ++ u_int32_t frame; ++ ++ value &= SSP_PCAP_REGISTER_VALUE_MASK; ++ ++ spin_lock(&pcap_spi.lock); ++ ++ pcap_spi.tx_buf = value | SSP_PCAP_REGISTER_WRITE_OP_BIT ++ |(reg_num<<SSP_PCAP_REGISTER_ADDRESS_SHIFT); ++ ++ /* we need to disable IRQ_GPIO1 because it's hardirq handler will ++ * in turn want to use SPI to get the real interrupt source */ ++ local_irq_disable(); ++ //disable_irq(IRQ_GPIO1); ++ ret = spi_sync_nosleep_x(pcap_spi_dev, &pcap_spi.transfer); ++ //enable_irq(IRQ_GPIO1); ++ local_irq_enable(); ++ ++ spin_unlock(&pcap_spi.lock); ++ ++ return ret; ++ ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_write); ++ ++int ezx_pcap_read(u_int8_t reg_num, u_int32_t *value) ++{ ++ int ret; ++ u_int32_t frame; ++ ++ *value &= SSP_PCAP_REGISTER_VALUE_MASK; ++ ++ spin_lock(&pcap_spi.lock); ++ ++ ++ pcap_spi.tx_buf = SSP_PCAP_REGISTER_READ_OP_BIT ++ | (reg_num<<SSP_PCAP_REGISTER_ADDRESS_SHIFT); ++ ++ /* we need to disable IRQ_GPIO1 because it's hardirq handler will ++ * in turn want to use SPI to get the real interrupt source */ ++ local_irq_disable(); ++ //disable_irq(IRQ_GPIO1); ++ ret = spi_sync_nosleep_x(pcap_spi_dev, &pcap_spi.transfer); ++ //enable_irq(IRQ_GPIO1); ++ local_irq_enable(); ++ ++ if (ret >= 0) ++ *value = pcap_spi.rx_buf; ++ ++ spin_unlock(&pcap_spi.lock); ++ ++ return ret; ++ ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_read); ++ ++int ezx_pcap_bit_set(u_int32_t sspPcapBit, u_int8_t to) ++{ ++ int ret; ++ u_int32_t tmp; ++ u_int32_t bit = (sspPcapBit & SSP_PCAP_REGISTER_VALUE_MASK); ++ u_int8_t reg_num = (sspPcapBit & SSP_PCAP_REGISTER_ADDRESS_MASK) ++ >> SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ ret = ezx_pcap_read(reg_num, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ if (to == 0) ++ tmp &= ~bit; ++ else ++ tmp |= bit; ++ ++ return ezx_pcap_write(reg_num, tmp); ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_bit_set); ++ ++int ezx_pcap_read_bit(u_int32_t bit) ++{ ++ int ret; ++ u_int32_t tmp; ++ u_int8_t reg_num = (bit & SSP_PCAP_REGISTER_ADDRESS_MASK) ++ >> SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ ret = ezx_pcap_read(reg_num, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ return tmp & (bit & SSP_PCAP_REGISTER_VALUE_MASK); ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_read_bit); ++ ++int ezx_pcap_vibrator_level() ++{ ++ /* FIXME */ ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_vibrator_level); ++ ++ ++static int ezx_pcap_init(void) ++{ ++ /* initialize our transfer structure */ ++ memset(&pcap_spi, 0, sizeof(pcap_spi)); ++ pcap_spi.transfer.tx_buf = &pcap_spi.tx_buf; ++ pcap_spi.transfer.rx_buf = &pcap_spi.rx_buf; ++ pcap_spi.transfer.len = 4; ++ ++ return 0; ++ ++ /* FIXME: resolve the spi_master and configure it apropriately */ ++ ++ /* initialize registers */ ++ /* FIXME: this should be board-level, not chip-level */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL, 1); ++ ezx_pcap_vibrator_level(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ ezx_pcap_vibrator_level(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ ++ /* set SW1 sleep to keep SW1 1.3v in sync mode */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11, 0); ++ /* SW1 active in sync mode */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01, 0); ++ /* at SW1 -core voltage to 1.30V */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS, 0); ++ ++ /* when STANDY2 PIN ACTIVE (high) set V3-- sram V8 -- pll off */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V3_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR, 0); ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V8_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR, 0); ++ ++ /* when STANDY2 PIN ACTIVE (high) set V4-- lcd only for e680 V6 --- ++ * camera for e680 */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V4_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR, 1); ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V6_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR, 0); ++ ++ /* set Vc to low power mode when AP sleep */ ++ //SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY); ++ ++ /* set VAUX2 to voltage 2.775V and low power mode when AP sleep */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0, 0); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR, 1); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 1); ++ ++#ifdef FIXME ++ PGSR(GPIO34_TXENB) |= GPIO_bit(GPIO34_TXENB); ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V )) ++ { ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_ATTACHED,NULL); ++ } ++ else ++ { ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_DETACHED,NULL); ++ } ++#endif ++ return 0; ++} ++ ++ ++/* MMC/SD specific functions */ ++ ++int ezx_pcap_mmcsd_power(int on) ++{ ++ if (on) { ++#if defined(CONFIG_PXA_EZX_E680) ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 1); ++#else ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN, 1); ++#endif ++ } else { ++#if defined(CONFIG_PXA_EZX_E680) ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN, 0); ++#else ++ return ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN, 0); ++#endif ++ } ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_mmcsd_power); ++ ++/* IRQ Handling */ ++ ++/* Array indexed by BIT POSITION of PCAP register, returns IRQ number */ ++static unsigned int pcap2irq[] = { ++ [0] = EZX_IRQ_ADCDONE, ++ [1] = EZX_IRQ_TS, ++ [2] = 0, /* 1HZ */ ++ [3] = 0, /* WI */ ++ [4] = 0, /* WI */ ++ [5] = 0, /* TODA */ ++ [6] = EZX_IRQ_USB4V, ++ [7] = 0, /* ONOFF */ ++ [8] = 0, /* ONOFF2 */ ++ [9] = EZX_IRQ_USB1V, ++ [10] = 0, /* MOBPORT */ ++ [11] = EZX_IRQ_MIC, ++ [12] = EZX_IRQ_HEADJACK, ++ [13] = 0, /* ST */ ++ [14] = 0, /* PC */ ++ [15] = 0, /* WARM */ ++ [16] = 0, /* EOL */ ++ [17] = 0, /* CLK */ ++ [18] = 0, /* SYS_RST */ ++ [19] = 0, ++ [20] = EZX_IRQ_ADCDONE2, ++ [21] = 0, /* SOFT_RESET */ ++ [22] = 0, /* MNEXB */ ++}; ++ ++/* Array indexed by IRQ NUMBER, returns PCAP absolute value */ ++static unsigned int irq2pcap[] = { ++ [EZX_IRQ_ADCDONE] = SSP_PCAP_ADJ_BIT_ISR_ADCDONEI, ++ [EZX_IRQ_TS] = SSP_PCAP_ADJ_BIT_ISR_TSI, ++ [EZX_IRQ_USB4V] = SSP_PCAP_ADJ_BIT_ISR_USB4VI, ++ [EZX_IRQ_USB1V] = SSP_PCAP_ADJ_BIT_ISR_USB1VI, ++ [EZX_IRQ_HEADJACK] = SSP_PCAP_ADJ_BIT_ISR_A1I, ++ [EZX_IRQ_MIC] = SSP_PCAP_ADJ_BIT_ISR_MB2I, ++ [EZX_IRQ_ADCDONE2] = SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I, ++}; ++ ++static void pcap_ack_irq(unsigned int irq) ++{ ++ DEBUGP("%s: %u\n", __FUNCTION__, irq); ++ ezx_pcap_write(SSP_PCAP_ADJ_ISR_REGISTER, irq2pcap[irq]); ++} ++ ++static void pcap_mask_irq(unsigned int irq) ++{ ++ u_int32_t reg; ++ ++ DEBUGP("%s: %u\n", __FUNCTION__, irq); ++ ++ /* this needs to be atomic... but we're not on SMP so it is */ ++ ezx_pcap_read(SSP_PCAP_ADJ_MSR_REGISTER, ®); ++ reg |= irq2pcap[irq]; ++ ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, reg); ++} ++ ++static void pcap_unmask_irq(unsigned int irq) ++{ ++ u_int32_t tmp; ++ DEBUGP("%s: %u\n", __FUNCTION__, irq); ++ ++ /* this needs to be atomic... but we're not on SMP so it is */ ++ ezx_pcap_read(SSP_PCAP_ADJ_MSR_REGISTER, &tmp); ++ tmp &= ~irq2pcap[irq]; ++ ezx_pcap_write(SSP_PCAP_ADJ_MSR_REGISTER, tmp); ++} ++ ++static struct irqchip pcap_chip = { ++ .ack = pcap_ack_irq, ++ .mask = pcap_mask_irq, ++ .unmask = pcap_unmask_irq, ++}; ++ ++/* handler for interrupt received from PCAP via GPIO */ ++static void pcap_irq_demux_handler(unsigned int irq, struct irqdesc *desc, ++ struct pt_regs *regs) ++{ ++ int i; ++ const unsigned int cpu = smp_processor_id(); ++ u_int32_t reg; ++ ++ DEBUGP("%s(%u,,) entered\n", __FUNCTION__, irq); ++ ++ desc->triggered = 1; ++ ++ if (unlikely(desc->running || desc->disable_depth)) ++ goto running; ++ ++ //desc->chip->ack(irq); ++ desc->running = 1; ++ kstat_cpu(cpu).irqs[irq]++; ++ ++ do { ++ if (desc->pending && !desc->disable_depth) { ++ DEBUGP("dealing with pending IRQ, unmasking\n"); ++ desc->pending = 0; ++ desc->chip->unmask(irq); ++ } ++ ++ ezx_pcap_read(SSP_PCAP_ADJ_ISR_REGISTER, ®); ++ DEBUGP("%s: ISR=0x%08x\n", __FUNCTION__, reg); ++ desc->chip->ack(irq); ++ ++ for (i = ARRAY_SIZE(pcap2irq)-1; i >= 0; i--) { ++ unsigned int irq = pcap2irq[i]; ++ if (irq == 0) ++ continue; ++ ++ if (reg & (1 << i)) { ++ struct irqdesc *subdesc; ++ DEBUGP("found irq %u\n", irq); ++ subdesc = irq_desc + irq; ++ desc_handle_irq(irq, subdesc, regs); ++ } ++ } ++ ++ } while (desc->pending && !desc->disable_depth); ++ ++ desc->running = 0; ++ return; ++ ++running: ++ DEBUGP("irq busy (running=%u, disable_depth=%d), masking it off\n", ++ desc->running, desc->disable_depth); ++ desc->pending = 1; ++ desc->chip->mask(irq); ++ desc->chip->ack(irq); ++} ++ ++ ++/* SPI protocol driver initialization */ ++ ++static struct resource pcap_ts_resources[] = { ++ { ++ .start = EZX_IRQ_ADCDONE2, ++ .end = EZX_IRQ_ADCDONE2, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = EZX_IRQ_TS, ++ .end = EZX_IRQ_TS, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static struct platform_device pcap_ts_device = { ++ .name = "pcap-ts", ++ .id = -1, ++ .resource = &pcap_ts_resources, ++ .num_resources = ARRAY_SIZE(pcap_ts_resources), ++}; ++ ++struct ezx_pcap { ++ int foo; ++}; ++ ++static int __devinit ezx_pcap_probe(struct spi_device *spi) ++{ ++ unsigned int ret, irq; ++ struct ezx_pcap *chip; ++ ++ printk("%s entered\n", __FUNCTION__); ++ ++ chip = kzalloc(sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return ENOMEM; ++ ++ dev_set_drvdata(&spi->dev, chip); ++ ++ ret = ezx_pcap_init(); ++ if (ret < 0) { ++ printk("error %d during ezx_pcap_init()\n", ret); ++ return ret; ++ } ++ ++ pcap_spi_dev = spi; ++ ++ set_irq_type(IRQ_GPIO1, IRQT_RISING); ++ /* set up interrupt demultiplexing code for PCAP2 irqs */ ++ for (irq = EZX_IRQ(0); irq <= EZX_IRQ(6); irq++) { ++ set_irq_chip(irq, &pcap_chip); ++ set_irq_handler(irq, do_edge_IRQ); ++ set_irq_flags(irq, IRQF_VALID); ++ } ++ set_irq_chained_handler(IRQ_GPIO1, pcap_irq_demux_handler); ++ ++ platform_device_register(&pcap_ts_device); ++ ++ return 0; ++} ++ ++static int __devexit ezx_pcap_remove(struct spi_device *spi) ++{ ++ int irq; ++ struct ezx_pcap *chip = dev_get_drvdata(&spi->dev); ++ ++ printk("%s entered\n", __FUNCTION__); ++ ++ pcap_spi_dev = NULL; ++ ++ /* remove interrupt demultiplexing code for PCAP2 irqs */ ++ set_irq_chained_handler(IRQ_GPIO1, NULL); ++ ++ for (irq = EZX_IRQ(0); irq <= EZX_IRQ(6); irq++) { ++ set_irq_chip(irq, NULL); ++ set_irq_handler(irq, NULL); ++ set_irq_flags(irq, 0); ++ } ++ ++ dev_set_drvdata(&spi->dev, NULL); ++ ++ kfree(chip); ++ ++ return 0; ++} ++ ++static struct spi_driver ezx_pcap_driver = { ++ .driver = { ++ .name = "ezx-pcap", ++ .bus = &spi_bus_type, ++ .owner = THIS_MODULE, ++ }, ++ ++ .probe = ezx_pcap_probe, ++ .remove = __devexit_p(ezx_pcap_remove), ++}; ++ ++ ++static int __init pcap_init(void) ++{ ++ return spi_register_driver(&ezx_pcap_driver); ++} ++ ++static void __exit pcap_fini(void) ++{ ++ spi_unregister_driver(&ezx_pcap_driver); ++} ++ ++module_init(pcap_init); ++module_exit(pcap_fini); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); ++MODULE_DESCRIPTION("SPI Driver for Motorola PCAP2"); ++ +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/ezx_ssp.c linux-2.6.16/arch/arm/mach-pxa/ezx_ssp.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/ezx_ssp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/ezx_ssp.c 2006-06-03 11:14:56.896239712 +0200 +@@ -0,0 +1,80 @@ ++/* New driver for Motorola's PCAP2 (Power Control and Clock Peripheral) ++ * ++ * (C) 2006 by Harald Welte <laforge@openezx.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++ ++#include <asm/arch/ssp.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/exz-pcap.h> ++ ++static struct ssp_dev ezx_pcap_ssp_dev; ++static struct ssp_state ezx_pcap_ssp_state; ++ ++int ezx_pcap_write_reg(int reg, u_int32_t value) ++{ ++ u_int_32_t cmd = SSP_PCAP_REGISTER_READ_OP_BIT | ++ (reg << SSP_PCAP_REGISTER_ADDRESS_SHIFT); ++ ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_write_reg); ++ ++int ezx_pcap_read_reg(int reg, u_int32_t *value) ++{ ++ ++} ++EXPORT_SYMBOL_GPL(ezx_pcap_read_reg); ++ ++ ++ ++ ++static int __init ezx_ssp_probe(struct platform_device *dev) ++{ ++ int ret; ++ ++ /* gpio? */ ++ ++ ret = ssp_init(&ezx_pcap_ssp_dev, ezx_machinfo->port, 0); ++ if (ret) ++ printk(KERN_ERR "Unable to register SSP handler!\n"); ++ else { ++ ssp_disable(&ezx_pcap_ssp_dev); ++ ssp_config(&ezx_pcap_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x0f)), 0, 0, FIXME_Clock); ++ ssp_enable(&ezx_pcap_ssp_dev); ++ } ++ ++ return ret; ++} ++ ++static int ezx_ssp_remove(struct platform_device *dev) ++{ ++ ssp_exit(&ezx_pcap_ssp_dev); ++ return 0; ++} ++ ++static struct platform_driver ezxssp_driver = { ++ .probe = ezx_ssp_probe, ++ .remove = ezx_ssp_remove, ++ .driver = { ++ .name = "ezx-ssp", ++ }, ++}; ++ ++int __init ezx_ssp_init(void) ++{ ++ return platform_driver_register(&ezxssp_driver); ++} ++ ++arch_initcall(ezx_ssp_init); +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/generic.c linux-2.6.16/arch/arm/mach-pxa/generic.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/generic.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/generic.c 2006-06-03 11:14:56.976227552 +0200 +@@ -37,6 +37,7 @@ + #include <asm/arch/mmc.h> + #include <asm/arch/irda.h> + #include <asm/arch/i2c.h> ++#include <asm/arch/kbd.h> + + #include "generic.h" + +@@ -319,6 +320,31 @@ + pxaficp_device.dev.platform_data = info; + } + ++static struct resource pxa_kbd_resources[] = { ++ { ++ .start = IRQ_KEYPAD, ++ .end = IRQ_KEYPAD, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = 0x41500000, ++ .end = 0x4150004c, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static struct platform_device kbd_device = { ++ .name = "pxa-keyboard", ++ .id = -1, ++ .resource = pxa_kbd_resources, ++ .num_resources = ARRAY_SIZE(pxa_kbd_resources), ++}; ++ ++void __init pxa_set_kbd_info(struct pxakbd_platform_data *info) ++{ ++ kbd_device.dev.platform_data = info; ++} ++ + static struct platform_device *devices[] __initdata = { + &pxamci_device, + &udc_device, +@@ -329,6 +355,7 @@ + &pxaficp_device, + &i2c_device, + &i2s_device, ++ &kbd_device, + }; + + static int __init pxa_init(void) +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/irq.c linux-2.6.16/arch/arm/mach-pxa/irq.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/irq.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/irq.c 2006-06-03 11:14:56.253337448 +0200 +@@ -25,6 +25,8 @@ + #include "generic.h" + + ++#include "ezx-compat.c" ++ + /* + * This is for peripheral IRQs internal to the PXA chip. + */ +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/Kconfig linux-2.6.16/arch/arm/mach-pxa/Kconfig +--- linux-2.6.16.orig/arch/arm/mach-pxa/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/Kconfig 2006-06-03 11:14:57.173197608 +0200 +@@ -1,5 +1,10 @@ + if ARCH_PXA + ++config PXA_EZX ++ bool ++ #select PXA_SPI ++ #select PXA_EZX_PCAP ++ + menu "Intel PXA2xx Implementations" + + choice +@@ -30,6 +35,18 @@ + SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa) + handheld computer. + ++config PXA_EZX_E680 ++ bool "Motorola E680 GSM Phone" ++ select PXA27x ++ select IWMMXT ++ select PXA_EZX ++ ++config PXA_EZX_A780 ++ bool "Motorola A780 GSM Phone" ++ select PXA27x ++ select IWMMXT ++ select PXA_EZX ++ + endchoice + + if PXA_SHARPSL +@@ -127,4 +144,17 @@ + tristate + help + Enable support for PXA2xx SSP ports ++ ++config PXA_SPI ++ tristate "SPI controller driver for PXA2xx" ++ help ++ Enable support for PXA2xx SPI ++ ++config PXA_EZX_PCAP ++ tristate "SPI protocol driver for PCAP2" ++ ++config PXA_EZX_PCAP_EMU ++ depends on PXA_EZX_PCAP ++ tristate "PCAP2 EMU" ++ + endif +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/Makefile linux-2.6.16/arch/arm/mach-pxa/Makefile +--- linux-2.6.16.orig/arch/arm/mach-pxa/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/Makefile 2006-06-03 11:14:57.174197456 +0200 +@@ -5,7 +5,7 @@ + # Common support (must be linked before board specific support) + obj-y += generic.o irq.o dma.o time.o + obj-$(CONFIG_PXA25x) += pxa25x.o +-obj-$(CONFIG_PXA27x) += pxa27x.o ++obj-$(CONFIG_PXA27x) += pxa27x.o sram.o + + # Specific board support + obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o +@@ -16,6 +16,7 @@ + obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o + obj-$(CONFIG_MACH_POODLE) += poodle.o + obj-$(CONFIG_MACH_TOSA) += tosa.o ++obj-$(CONFIG_PXA_EZX) += ezx.o #ezx_ssp.o + + # Support for blinky lights + led-y := leds.o +@@ -28,7 +29,11 @@ + # Misc features + obj-$(CONFIG_PM) += pm.o sleep.o + obj-$(CONFIG_PXA_SSP) += ssp.o ++obj-$(CONFIG_PXA_SPI) += spi.o ++obj-$(CONFIG_PXA_EZX_PCAP) += ezx-pcap.o ++obj-$(CONFIG_PXA_EZX_PCAP_EMU) += pcap-emu.o + + ifeq ($(CONFIG_PXA27x),y) + obj-$(CONFIG_PM) += standby.o ++obj-$(CONFIG_DPM) += dpm-pxa27x.o + endif +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/pcap-emu.c linux-2.6.16/arch/arm/mach-pxa/pcap-emu.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/pcap-emu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/pcap-emu.c 2006-06-03 11:14:57.174197456 +0200 +@@ -0,0 +1,52 @@ ++#include <linux/kernel.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++ ++ ++static irqreturn_t emu_irq(int irq, void *data, struct pt_regs *regs) ++{ ++ printk("emu_irq(%u) entered: ", irq); ++ ++ switch (irq) { ++ case EZX_IRQ_USB4V: ++ printk("usb 4v\n"); ++ break; ++ case EZX_IRQ_USB1V: ++ printk("usb 1v\n"); ++ break; ++ case EZX_IRQ_MIC: ++ printk("mic\n"); ++ break; ++ case EZX_IRQ_HEADJACK: ++ printk("headjack\n"); ++ break; ++ default: ++ printk("unknown\n"); ++ break; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++int init(void) ++{ ++ request_irq(EZX_IRQ_USB4V, &emu_irq, SA_INTERRUPT, "usb 4v", NULL); ++ request_irq(EZX_IRQ_USB1V, &emu_irq, SA_INTERRUPT, "usb 1v", NULL); ++ request_irq(EZX_IRQ_MIC, &emu_irq, SA_INTERRUPT, "mic", NULL); ++ request_irq(EZX_IRQ_HEADJACK, &emu_irq, SA_INTERRUPT, "headjack", NULL); ++ ++ return 0; ++} ++ ++void fini(void) ++{ ++ free_irq(EZX_IRQ_HEADJACK, NULL); ++ free_irq(EZX_IRQ_MIC, NULL); ++ free_irq(EZX_IRQ_USB1V, NULL); ++ free_irq(EZX_IRQ_USB4V, NULL); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/spi.c linux-2.6.16/arch/arm/mach-pxa/spi.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/spi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/spi.c 2006-06-03 11:14:57.126204752 +0200 +@@ -0,0 +1,506 @@ ++#include <linux/config.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/workqueue.h> ++#include <linux/platform_device.h> ++ ++#include <linux/spi/spi.h> ++#include <linux/interrupt.h> ++ ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/spi.h> ++ ++/* */ ++struct pxa_master { ++ struct workqueue_struct *workqueue; ++ struct work_struct work; ++ ++ atomic_t busy; ++ spinlock_t lock; ++ struct list_head queue; ++ ++ struct spi_master *master; ++ ++ int port; ++}; ++ ++static void ssp_enable(unsigned int port) ++{ ++ SSCR0_P(port) |= SSCR0_SSE; ++} ++ ++static void ssp_disable(unsigned int port) ++{ ++ SSCR0_P(port) &= ~SSCR0_SSE; ++} ++ ++/* low level utility functions, mainly copied from arch/arm/mach-pxa/ssp.c */ ++static int ssp_config(unsigned int port, u_int32_t mode, u_int32_t flags, ++ u_int32_t psp_flags, u_int32_t speed) ++{ ++ SSCR1_P(port) = flags; ++ SSCR0_P(port) = 0; ++ SSCR0_P(port) = (speed | mode); ++ SSPSP_P(port) = psp_flags; ++ ++ return 0; ++} ++ ++static int ssp_write_word(unsigned int port, u32 data) ++{ ++ while (!(SSSR_P(port) & SSSR_TNF)) ++ cpu_relax(); ++ ++ SSDR_P(port) = data; ++ return 0; ++} ++ ++static u_int32_t ssp_read_word(unsigned int port) ++{ ++ while (!(SSSR_P(port) & SSSR_RNE)) ++ cpu_relax(); ++ ++ return SSDR_P(port); ++} ++ ++static irqreturn_t pxa_spi_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ struct pxa_master *pm = (struct pxa_master *) dev_id; ++ struct spi_master *master = pm->master; ++ unsigned int status = SSSR_P(pm->port); ++ ++ SSSR_P(pm->port) = status; /* clear status bits */ ++ ++ if (status & SSSR_ROR) ++ printk(KERN_WARNING "SPI(%d): receiver overrun\n", pm->port); ++ if (status & SSSR_TUR) ++ printk(KERN_WARNING "SPI(%d): transmitter underrun\n", ++ pm->port); ++ ++ if (status & SSSR_BCE) ++ printk(KERN_WARNING "SPI(%d): bit count error\n", pm->port); ++ ++ return IRQ_HANDLED; ++} ++ ++static int pxa_spi_setup(struct spi_device *spi) ++{ ++ struct pxa_master *pm; ++ u_int32_t mode, flags, div; ++ ++ if (!spi->max_speed_hz) ++ return -EINVAL; ++ ++ if (spi->bits_per_word == 0) ++ spi->bits_per_word = 32; ++ ++ if (spi->bits_per_word < 4 || ++ spi->bits_per_word > 32) ++ return -EINVAL; ++ ++ pm = spi_master_get_devdata(spi->master); ++ ++ mode = SSCR0_Motorola | SSCR0_SSE; ++ flags = SSCR1_TxTresh(1) | SSCR1_RxTresh(1); //| SSCR1_RIE; ++ ++ /* clock phase and polarity */ ++ if (spi->mode & SPI_CPHA) ++ flags |= SSCR1_SPH; ++ if (spi->mode & SPI_CPOL) ++ flags |= SSCR1_SPO; ++ ++ /* word size */ ++ if (spi->bits_per_word <= 16) ++ mode |= SSCR0_DataSize(spi->bits_per_word); ++ else ++ mode |= SSCR0_EDSS | SSCR0_DataSize(spi->bits_per_word >> 1); ++ ++#define PXA27x_SPI_CLOCK (13*1000*1000) ++ div = PXA27x_SPI_CLOCK / spi->max_speed_hz; ++ ++ return ssp_config(pm->port, mode, flags, 0, SSCR0_SerClkDiv(div)); ++ return 0; ++} ++ ++/* just add an SPI transfer to the workqueue */ ++static int pxa_spi_transfer(struct spi_device *spi, struct spi_message *msg) ++{ ++ struct pxa_master *pm; ++ unsigned long flags; ++ ++ pm = spi_master_get_devdata(spi->master); ++ ++ spin_lock_irqsave(&pm->lock, flags); ++ ++ list_add_tail(&msg->queue, &pm->queue); ++ queue_work(pm->workqueue, &pm->work); ++ ++ spin_unlock_irqrestore(&pm->lock, flags); ++ ++ return 0; ++} ++ ++static int pxa_spi_transfer_x(struct spi_device *spi, struct spi_transfer *t); ++ ++/* the actualy workqueue dequeueing workhorse */ ++static void pxa_spi_work(void *_pxa_master) ++{ ++ struct pxa_master *pm = _pxa_master; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pm->lock, flags); ++ atomic_inc(&pm->busy); ++ ++ while (!list_empty(&pm->queue)) { ++ struct spi_message *m; ++ struct spi_device *spi; ++ struct spi_transfer *t = NULL; ++ int status = 0, cs_change = 0; ++ ++ m = container_of(pm->queue.next, struct spi_message, queue); ++ list_del_init(&m->queue); ++ spin_unlock_irqrestore(&pm->lock, flags); ++ ++ spi = m->spi; ++ cs_change = 1; ++ ++ list_for_each_entry(t, &m->transfers, transfer_list) { ++ ++#ifdef LATER ++ if (cs_change) { ++ pm->chipselect(spi, BITBANG_CS_ACTIVE); ++ } ++ cs_change = t->cs_change; ++#endif ++ ++ if (!t->tx_buf && !t->rx_buf && t->len) { ++ status = -EINVAL; ++ break; ++ } ++ ++ if (t->len) { ++ if (!m->is_dma_mapped) ++ t->rx_dma = t->tx_dma = 0; ++ status = pxa_spi_transfer_x(spi, t); ++ } ++ if (status != t->len) { ++ if (status > 0) ++ status = -EMSGSIZE; ++ break; ++ } ++ m->actual_length += status; ++ status = 0; ++ ++ if (t->delay_usecs) ++ udelay(t->delay_usecs); ++ ++ if (!cs_change) ++ continue; ++ if (t->transfer_list.next == &m->transfers) ++ break; ++ ++#ifdef LATER ++ pm->chipselect(spi, BITBANG_CS_INACTIVE); ++#endif ++ } ++ ++ m->status = status; ++ m->complete(m->context); ++ ++#ifdef LATER ++ if (!(status == 0 && cs_change)) ++ pm->chipselect(spi, BITBANG_CS_INACTIVE); ++#endif ++ ++ spin_lock_irqsave(&pm->lock, flags); ++ } ++ atomic_dec(&pm->busy); ++ spin_unlock_irqrestore(&pm->lock, flags); ++} ++ ++/* actually transfer a given message */ ++static int pxa_spi_transfer_x(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct spi_master *master = spi->master; ++ struct pxa_master *pm = spi_master_get_devdata(master); ++ unsigned int i, n; ++ ++ ssp_enable(pm->port); ++ ++ /* calculate number of bytes per fifo-write/read */ ++ n = spi->bits_per_word / 8; ++ if (spi->bits_per_word % 8) ++ n++; ++ ++ /* FIXME: What about endianness? */ ++ for (i = 0; i < t->len; i += n) { ++ u_int32_t tx, rx; ++ const unsigned char *tx_buf = t->tx_buf; ++ unsigned char *rx_buf = t->rx_buf; ++ switch (n) { ++ case 1: ++ tx = tx_buf[i]; ++ ssp_write_word(pm->port, tx); ++ rx = ssp_read_word(pm->port); ++ rx_buf[i] = rx & 0xff; ++ rx_buf[i+1] = rx >> 8; ++ break; ++ case 3: ++ tx = tx_buf[i] | tx_buf[i+1] << 8 | tx_buf[i+2] << 16; ++ ssp_write_word(pm->port, tx); ++ rx = ssp_read_word(pm->port); ++ rx_buf[i] = rx & 0xff; ++ rx_buf[i+1] = rx >> 8; ++ rx_buf[i+2] = rx >> 16; ++ break; ++ case 4: ++ tx = tx_buf[i] | tx_buf[i+1] << 8; ++ tx |= tx_buf[i+2] << 16 | tx_buf[i+3] << 24; ++ ssp_write_word(pm->port, tx); ++ rx = ssp_read_word(pm->port); ++ rx_buf[i] = rx & 0xff; ++ rx_buf[i+1] = (rx >> 8) & 0xff; ++ rx_buf[i+2] = (rx >> 16) & 0xff; ++ rx_buf[i+3] = (rx >> 24) & 0xff; ++ break; ++ } ++ } ++ //ssp_disable(pm->port); ++ ++ return 0; ++} ++ ++int spi_sync_nosleep_x(struct spi_device *spi, struct spi_transfer *t) ++{ ++ return pxa_spi_transfer_x(spi, t); ++} ++EXPORT_SYMBOL(spi_sync_nosleep_x); ++ ++static void pxa_spi_cleanup(const struct spi_device *spi) ++{ ++ //FIXME; ++} ++ ++/* non-standard really-synchronous non-sleeping SPI handling */ ++static int spi_sync_xfer_nosleep(struct spi_device *spi, struct spi_message *m) ++{ ++ //return pxa_spi_transfer_x(spi, x); ++ return -EINVAL; ++} ++ ++static int pxa_spi_probe(struct platform_device *pdev) ++{ ++ struct resource *mem_res; ++ struct pxa_master *pm; ++ struct spi_master *master; ++ int ret = -ENOMEM; ++ ++ pm = kzalloc(sizeof(*pm), GFP_KERNEL); ++ if (!pm) ++ return ret; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(*pm)); ++ if (!master) ++ goto out_pm; ++ ++ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem_res) { ++ ret = -EINVAL; ++ goto out_mem; ++ } ++ ++ /* request register memory region */ ++ if (!request_mem_region(mem_res->start, mem_res->end - mem_res->start, ++ "pxa-spi")) { ++ ret = -EBUSY; ++ goto out_master; ++ } ++ ++ ret = request_irq(platform_get_irq(pdev, 0), pxa_spi_interrupt, ++ 0, "pxa-spi", pm); ++ if (ret < 0) ++ goto out_mem; ++ ++ pm->master = master; ++ /* FIXME: this is still PXA27x specific */ ++ switch (mem_res->start) { ++ case 0x41000000: ++ pm->port = 1; ++ break; ++ case 0x47000000: ++ pm->port = 2; ++ break; ++ case 0x49000000: ++ pm->port = 3; ++ break; ++ default: ++ ret = -EINVAL; ++ goto out_irq; ++ } ++ INIT_WORK(&pm->work, pxa_spi_work, pm); ++ spin_lock_init(&pm->lock); ++ INIT_LIST_HEAD(&pm->queue); ++ ++ pm->workqueue = create_singlethread_workqueue( ++ master->cdev.dev->bus_id); ++ if (!pm->workqueue) { ++ printk("can't create workqueue\n"); ++ ret = -EBUSY; ++ goto out_irq; ++ } ++ ++ master->cleanup = &pxa_spi_cleanup; ++ master->setup = &pxa_spi_setup; ++ master->transfer = &pxa_spi_transfer; ++ master->transfer_nosleep = &spi_sync_xfer_nosleep; ++ master->bus_num = pm->port; ++ spi_master_set_devdata(master, pm); ++ ++ /* FIXME: this is still PXA27x specific */ ++ if (pm->port == 1) ++ pxa_set_cken(CKEN23_SSP1, 1); ++ else if (pm->port == 2) ++ pxa_set_cken(CKEN3_SSP2, 1); ++ else ++ pxa_set_cken(CKEN4_SSP3, 1); ++ ++ ret = spi_register_master(master); ++ if (ret < 0) { ++ printk("failing to register master\n"); ++ goto out_workqueue; ++ } ++ ++ platform_set_drvdata(pdev, pm); ++ ++ return 0; ++ ++out_workqueue: ++ destroy_workqueue(pm->workqueue); ++out_irq: ++ free_irq(platform_get_irq(pdev, 0), &pxa_spi_interrupt); ++out_mem: ++ release_mem_region(mem_res->start, mem_res->end-mem_res->start); ++out_master: ++ spi_master_put(master); ++out_pm: ++ kfree(pm); ++ ++ return ret; ++} ++ ++static int pxa_spi_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver pxa_spi_driver = { ++ .probe = pxa_spi_probe, ++ .remove = pxa_spi_remove, ++ .driver = { ++ .name = "pxa-spi", ++ }, ++}; ++ ++static int __init pxa_spi_init(void) ++{ ++ return platform_driver_register(&pxa_spi_driver); ++} ++ ++static void __exit pxa_spi_fini(void) ++{ ++ platform_driver_unregister(&pxa_spi_driver); ++} ++ ++module_init(pxa_spi_init); ++module_exit(pxa_spi_fini); ++ ++/* SPI/SSP master (controller) platform devices, registered by board-level init ++ * code calling pxa_register_spi() */ ++ ++/* FIXME: this is still PXA27x specific */ ++static struct resource pxa_spi1_resources[] = { ++ { ++ .start = 0x41000000, //SSCR0_P1 ++ .end = 0x4100003f, //SSACD_P1 ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_SSP, ++ .end = IRQ_SSP, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++static struct resource pxa_spi2_resources[] = { ++ { ++ .start = 0x41700000, //SSCR0_P2, ++ .end = 0x4170003f, //SSACD_P2, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_SSP2, ++ .end = IRQ_SSP2, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++static struct resource pxa_spi3_resources[] = { ++ { ++ .start = 0x41900000, //SSCR0_P3, ++ .end = 0x4190003f, //SSACD_P3, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .start = IRQ_SSP3, ++ .end = IRQ_SSP3, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device pxa_spi_devices[] = { ++ { ++ .name = "pxa-spi", ++ .dev = { ++ }, ++ .id = -1, ++ .resource = pxa_spi1_resources, ++ .num_resources = ARRAY_SIZE(pxa_spi1_resources), ++ },{ ++ .name = "pxa-spi", ++ .dev = { ++ }, ++ .id = -1, ++ .resource = pxa_spi2_resources, ++ .num_resources = ARRAY_SIZE(pxa_spi2_resources), ++ },{ ++ .name = "pxa-spi", ++ .dev = { ++ }, ++ .id = -1, ++ .resource = pxa_spi3_resources, ++ .num_resources = ARRAY_SIZE(pxa_spi3_resources), ++ }, ++}; ++ ++void pxa_register_spi(unsigned int n, struct pxa_spi_data *pdata) ++{ ++ if (n < 1 || n > 3) { ++ printk(KERN_WARNING "Board init code tries to use non-" ++ "existing SPI Bus %u\n", n); ++ return; ++ } ++ ++ /* n = 1..3, we need 0..2 */ ++ n--; ++ ++ pxa_spi_devices[n].dev.platform_data = pdata; ++ platform_device_register(&pxa_spi_devices[n]); ++ ++ /* Setup GPIO alternate functions */ ++ if (pdata->init) ++ pdata->init(n); ++} ++EXPORT_SYMBOL_GPL(pxa_register_spi); ++ ++MODULE_DESCRIPTION("New PXA SPI/SSP driver"); ++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/arch/arm/mach-pxa/sram.c linux-2.6.16/arch/arm/mach-pxa/sram.c +--- linux-2.6.16.orig/arch/arm/mach-pxa/sram.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/arm/mach-pxa/sram.c 2006-06-03 11:14:56.253337448 +0200 +@@ -0,0 +1,104 @@ ++/* ++ * linux/arch/arm/mach-wmmx/sram.c ++ * ++ * Bulverde Internal Memory stuff ++ * ++ * Created: Sep 05, 2003 ++ * Copyright: MontaVista Software 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/spinlock.h> ++ ++#include <asm/system.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/arch-pxa/pxa-regs.h> ++ ++#define SRAM_MEM_VIRT io_p2v(SRAM_MEM_PHYS) ++ ++#define SRAM_DELAY_STANDBY_TIME 255 ++ ++static spinlock_t sram_spinlock; ++static volatile int sram_locked = 0; ++ ++static int __init sram_init (void) { ++ /* Enable clock */ ++ pxa_set_cken(CKEN20_IM, 1); ++ ++ /* All the banks are ++ * - Automatic wakeup enabled ++ * - Enter Stand-by after 255 ms ++ */ ++ IMPMCR = IMPMCR_PC3_AUTO_MODE | ++ IMPMCR_PC2_AUTO_MODE | ++ IMPMCR_PC1_AUTO_MODE | ++ IMPMCR_PC0_AUTO_MODE | ++ IMPMCR_AW3 | IMPMCR_AW2 | ++ IMPMCR_AW1 | IMPMCR_AW0 | ++ SRAM_DELAY_STANDBY_TIME; ++ ++ return 0; ++} ++ ++int sram_access_obtain(unsigned long *pmem, unsigned long *psize) { ++ ++ int flags; ++ ++ spin_lock_irqsave(&sram_spinlock, flags); ++ ++ if (sram_locked != 0) { ++ spin_unlock_irqrestore(&sram_spinlock, flags); ++ return -EAGAIN; ++ } ++ ++ sram_locked = 1; ++ ++ spin_unlock_irqrestore(&sram_spinlock, flags); ++ ++ *pmem = SRAM_MEM_VIRT; ++ *psize = SRAM_SIZE; ++ ++ return 0; ++} ++ ++int sram_access_release(unsigned long *pmem, unsigned long *psize) ++{ ++ if ((*pmem != SRAM_MEM_VIRT) || ++ (*psize != SRAM_SIZE)){ ++ return -EINVAL; ++ } ++ ++ *pmem = 0; ++ *psize = 0; ++ ++ sram_locked = 0; ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(sram_access_obtain); ++EXPORT_SYMBOL(sram_access_release); ++ ++__initcall(sram_init); ++ +diff -Nurd linux-2.6.16.orig/arch/arm/mm/init.c linux-2.6.16/arch/arm/mm/init.c +--- linux-2.6.16.orig/arch/arm/mm/init.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/arm/mm/init.c 2006-06-03 11:14:56.254337296 +0200 +@@ -230,6 +230,10 @@ + #endif + if (res_size) + reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size); ++#ifdef CONFIG_ARCH_EZX ++ /* reserve the first page memory for exiting sleep and user off */ ++ reserve_bootmem_node(pgdat, PHYS_OFFSET, PAGE_SIZE); ++#endif + } + + void __init build_mem_type_table(void); +diff -Nurd linux-2.6.16.orig/arch/i386/Kconfig linux-2.6.16/arch/i386/Kconfig +--- linux-2.6.16.orig/arch/i386/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/Kconfig 2006-06-03 11:14:55.888392928 +0200 +@@ -908,6 +908,7 @@ + endmenu + + source "arch/i386/kernel/cpu/cpufreq/Kconfig" ++source "arch/i386/kernel/cpu/dpm/Kconfig" + + endmenu + +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/apm.c linux-2.6.16/arch/i386/kernel/apm.c +--- linux-2.6.16.orig/arch/i386/kernel/apm.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/apm.c 2006-06-03 11:14:55.223494008 +0200 +@@ -1081,7 +1081,7 @@ + break; + } + +- if (error == APM_NOT_ENGAGED && state != APM_STATE_READY) { ++ if (error == APM_NOT_ENGAGED) { + static int tried; + int eng_error; + if (tried++ == 0) { +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/amd.c linux-2.6.16/arch/i386/kernel/cpu/amd.c +--- linux-2.6.16.orig/arch/i386/kernel/cpu/amd.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/amd.c 2006-06-03 11:14:55.223494008 +0200 +@@ -207,6 +207,8 @@ + set_bit(X86_FEATURE_K7, c->x86_capability); + break; + } ++ if (c->x86 >= 6) ++ set_bit(X86_FEATURE_FXSAVE_LEAK, c->x86_capability); + + display_cacheinfo(c); + +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/cpufreq/Kconfig linux-2.6.16/arch/i386/kernel/cpu/cpufreq/Kconfig +--- linux-2.6.16.orig/arch/i386/kernel/cpu/cpufreq/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/cpufreq/Kconfig 2006-06-03 11:14:55.240491424 +0200 +@@ -203,6 +203,7 @@ + config X86_LONGHAUL + tristate "VIA Cyrix III Longhaul" + select CPU_FREQ_TABLE ++ depends on BROKEN + help + This adds the CPUFreq driver for VIA Samuel/CyrixIII, + VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c linux-2.6.16/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +--- linux-2.6.16.orig/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c 2006-06-03 11:14:55.240491424 +0200 +@@ -244,7 +244,7 @@ + for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if ((i<2) && (has_N44_O17_errata[policy->cpu])) + p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; +- else if (has_N60_errata[policy->cpu] && p4clockmod_table[i].frequency < 2000000) ++ else if (has_N60_errata[policy->cpu] && ((stock_freq * i)/8) < 2000000) + p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; + else + p4clockmod_table[i].frequency = (stock_freq * i)/8; +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c linux-2.6.16/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +--- linux-2.6.16.orig/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c 2006-06-03 11:14:55.241491272 +0200 +@@ -75,7 +75,9 @@ + __asm__ __volatile__( + "out %%al, (%%dx)\n" + : "=D" (result) +- : "a" (command), "b" (function), "c" (0), "d" (smi_port), "D" (0), "S" (magic) ++ : "a" (command), "b" (function), "c" (0), "d" (smi_port), ++ "D" (0), "S" (magic) ++ : "memory" + ); + + dprintk("result is %x\n", result); +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/centrino_dpm.c linux-2.6.16/arch/i386/kernel/cpu/dpm/centrino_dpm.c +--- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/centrino_dpm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/dpm/centrino_dpm.c 2006-06-03 11:14:55.890392624 +0200 +@@ -0,0 +1,133 @@ ++/* ++ * 2003 (c) MontaVista Software, Inc. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ * ++ * Based on speedstep-centrino.c by Jeremy Fitzhardinge <jeremy@goop.org> ++ */ ++ ++#include <linux/config.h> ++#include <linux/dpm.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++ ++#include <asm/msr.h> ++#include <asm/processor.h> ++#include <asm/cpufeature.h> ++ ++/* Extract clock in kHz from PERF_CTL value */ ++static unsigned extract_clock(unsigned msr) ++{ ++ msr = (msr >> 8) & 0xff; ++ return msr * 100000; ++} ++ ++/* Return the current CPU frequency in kHz */ ++static unsigned get_cur_freq(void) ++{ ++ unsigned l, h; ++ ++ rdmsr(MSR_IA32_PERF_STATUS, l, h); ++ return extract_clock(l); ++} ++ ++static int ++dpm_centrino_init_opt(struct dpm_opt *opt) ++{ ++ int v = opt->pp[DPM_MD_V]; ++ int cpu = opt->pp[DPM_MD_CPU_FREQ]; ++ ++ struct dpm_md_opt *md_opt = &opt->md_opt; ++ ++ md_opt->v = v; ++ md_opt->cpu = cpu; ++ return 0; ++} ++ ++/* Fully determine the current machine-dependent operating point, and fill in a ++ structure presented by the caller. This should only be called when the ++ dpm_sem is held. This call can return an error if the system is currently at ++ an operating point that could not be constructed by dpm_md_init_opt(). */ ++ ++static int ++dpm_centrino_get_opt(struct dpm_opt *opt) ++{ ++ struct dpm_md_opt *md_opt = &opt->md_opt; ++ ++ md_opt->v = 100; /* TODO. */ ++ md_opt->cpu = get_cur_freq(); ++ return 0; ++} ++ ++static int ++dpm_centrino_set_opt(struct dpm_md_opt *md_opt) ++{ ++ unsigned int msr = 0, oldmsr, h, mask = 0; ++ ++ if (md_opt->cpu != -1) { ++ msr |= ((md_opt->cpu)/100) << 8; ++ mask |= 0xff00; ++ } ++ ++ if (md_opt->v != -1) { ++ msr |= ((md_opt->v - 700) / 16); ++ mask |= 0xff; ++ } ++ ++ rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); ++ ++ if (msr == (oldmsr & mask)) ++ return 0; ++ ++ /* all but 16 LSB are "reserved", so treat them with ++ care */ ++ oldmsr &= ~mask; ++ msr &= mask; ++ oldmsr |= msr; ++ ++ wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); ++ return 0; ++} ++ ++static int dpm_centrino_startup(void) ++{ ++ struct cpuinfo_x86 *cpu = cpu_data; ++ unsigned l, h; ++ ++ if (!cpu_has(cpu, X86_FEATURE_EST)) ++ return -ENODEV; ++ ++ /* Check to see if Enhanced SpeedStep is enabled, and try to ++ enable it if not. */ ++ rdmsr(MSR_IA32_MISC_ENABLE, l, h); ++ ++ if (!(l & (1<<16))) { ++ l |= (1<<16); ++ wrmsr(MSR_IA32_MISC_ENABLE, l, h); ++ ++ /* check to see if it stuck */ ++ rdmsr(MSR_IA32_MISC_ENABLE, l, h); ++ if (!(l & (1<<16))) { ++ printk(KERN_INFO "DPM: Couldn't enable Enhanced SpeedStep\n"); ++ return -ENODEV; ++ } ++ } ++ ++ return 0; ++} ++ ++int __init dpm_centrino_init(void) ++{ ++ printk("Dynamic Power Management for Intel Centrino Enhanced SpeedStep.\n"); ++ ++ dpm_bd.startup = dpm_centrino_startup; ++ dpm_bd.init_opt = dpm_centrino_init_opt; ++ dpm_bd.get_opt = dpm_centrino_get_opt; ++ dpm_bd.set_opt = dpm_centrino_set_opt; ++ return 0; ++} ++ ++__initcall(dpm_centrino_init); +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/Kconfig linux-2.6.16/arch/i386/kernel/cpu/dpm/Kconfig +--- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/dpm/Kconfig 2006-06-03 11:14:55.889392776 +0200 +@@ -0,0 +1,10 @@ ++# ++# Dynamic Power Management ++# ++ ++source "drivers/dpm/Kconfig" ++ ++config DPM_CENTRINO ++ tristate "DPM for Intel Centrino Enhanced Speedstep" ++ depends on DPM ++ default n +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/Makefile linux-2.6.16/arch/i386/kernel/cpu/dpm/Makefile +--- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/dpm/Makefile 2006-06-03 11:14:55.889392776 +0200 +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_DPM) += x86_dpm.o ++obj-$(CONFIG_DPM_CENTRINO) += centrino_dpm.o ++ +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/x86_dpm.c linux-2.6.16/arch/i386/kernel/cpu/dpm/x86_dpm.c +--- linux-2.6.16.orig/arch/i386/kernel/cpu/dpm/x86_dpm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/dpm/x86_dpm.c 2006-06-03 11:14:55.890392624 +0200 +@@ -0,0 +1,133 @@ ++/* ++ * 2003 (c) MontaVista Software, Inc. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ */ ++ ++#include <linux/config.h> ++#include <linux/dpm.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++ ++#include <asm/page.h> ++#include <asm/uaccess.h> ++ ++struct dpm_bd dpm_bd; ++ ++static int ++dpm_x86_init_opt(struct dpm_opt *opt) ++{ ++ return dpm_bd.init_opt ? dpm_bd.init_opt(opt) : -1; ++} ++ ++/* Fully determine the current machine-dependent operating point, and fill in a ++ structure presented by the caller. This should only be called when the ++ dpm_sem is held. This call can return an error if the system is currently at ++ an operating point that could not be constructed by dpm_md_init_opt(). */ ++ ++static unsigned long loops_per_jiffy_ref = 0; ++ ++static int ++dpm_x86_get_opt(struct dpm_opt *opt) ++{ ++ return dpm_bd.get_opt ? dpm_bd.get_opt(opt) : -1; ++} ++ ++int ++dpm_x86_set_opt(struct dpm_opt *cur, struct dpm_opt *new) ++{ ++ struct cpuinfo_x86 *cpu = cpu_data; ++ ++ if (! new->md_opt.cpu) { ++#ifdef CONFIG_PM ++ pm_suspend(PM_SUSPEND_STANDBY); ++ ++ /* Here when we wake up. Recursive call to switch back to ++ * to task state. ++ */ ++ ++ dpm_set_os(DPM_TASK_STATE); ++#endif ++ return 0; ++ } ++ ++ if (dpm_bd.set_opt){ ++ dpm_bd.set_opt(&new->md_opt); ++ ++ }else{ ++ return -1; ++ } ++ ++ if (cur->md_opt.cpu && new->md_opt.cpu){ ++ loops_per_jiffy_ref = cpu->loops_per_jiffy; ++ cpu->loops_per_jiffy = ++ dpm_compute_lpj(loops_per_jiffy_ref , ++ cur->md_opt.cpu, ++ new->md_opt.cpu); ++ ++ loops_per_jiffy = cpu->loops_per_jiffy; ++ if (cpu_khz) ++ cpu_khz = dpm_compute_lpj(cpu_khz, ++ cur->md_opt.cpu, ++ new->md_opt.cpu); ++ } ++ return 0; ++} ++ ++/* ++ * idle loop ++ */ ++ ++static void (*orig_idle)(void); ++ ++void dpm_x86_idle(void) ++{ ++ extern void default_idle(void); ++ ++ if (orig_idle) ++ orig_idle(); ++ else ++ default_idle(); ++} ++ ++/**************************************************************************** ++ * Initialization/Exit ++ ****************************************************************************/ ++ ++void ++dpm_x86_startup(void) ++{ ++ orig_idle = pm_idle; ++ pm_idle = dpm_idle; ++ ++ if (dpm_bd.startup) ++ dpm_bd.startup(); ++} ++ ++void ++dpm_x86_cleanup(void) ++{ ++ pm_idle = orig_idle; ++ ++ if (dpm_bd.cleanup) ++ dpm_bd.cleanup(); ++} ++ ++int __init ++dpm_x86_init(void) ++{ ++ printk("Dynamic Power Management for x86.\n"); ++ ++ dpm_md.init_opt = dpm_x86_init_opt; ++ dpm_md.set_opt = dpm_x86_set_opt; ++ dpm_md.get_opt = dpm_x86_get_opt; ++ dpm_md.idle = dpm_x86_idle; ++ dpm_md.startup = dpm_x86_startup; ++ dpm_md.cleanup = dpm_x86_cleanup; ++ return 0; ++} ++__initcall(dpm_x86_init); +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/cpu/Makefile linux-2.6.16/arch/i386/kernel/cpu/Makefile +--- linux-2.6.16.orig/arch/i386/kernel/cpu/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/cpu/Makefile 2006-06-03 11:14:55.888392928 +0200 +@@ -17,3 +17,4 @@ + + obj-$(CONFIG_MTRR) += mtrr/ + obj-$(CONFIG_CPU_FREQ) += cpufreq/ ++obj-$(CONFIG_DPM) += dpm/ +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/dmi_scan.c linux-2.6.16/arch/i386/kernel/dmi_scan.c +--- linux-2.6.16.orig/arch/i386/kernel/dmi_scan.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/dmi_scan.c 2006-06-03 11:14:55.241491272 +0200 +@@ -106,7 +106,7 @@ + struct dmi_device *dev; + + for (i = 0; i < count; i++) { +- char *d = ((char *) dm) + (i * 2); ++ char *d = (char *)(dm + 1) + (i * 2); + + /* Skip disabled device */ + if ((*d & 0x80) == 0) +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/process.c linux-2.6.16/arch/i386/kernel/process.c +--- linux-2.6.16.orig/arch/i386/kernel/process.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/process.c 2006-06-03 11:14:55.891392472 +0200 +@@ -58,6 +58,8 @@ + #include <asm/tlbflush.h> + #include <asm/cpu.h> + ++#include <linux/dpm.h> ++ + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + + static int hlt_counter; +@@ -697,6 +699,7 @@ + + disable_tsc(prev_p, next_p); + ++ dpm_set_os(next_p->dpm_state); + return prev_p; + } + +diff -Nurd linux-2.6.16.orig/arch/i386/kernel/vm86.c linux-2.6.16/arch/i386/kernel/vm86.c +--- linux-2.6.16.orig/arch/i386/kernel/vm86.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/vm86.c 2006-06-03 11:14:55.242491120 +0200 +@@ -43,6 +43,7 @@ + #include <linux/smp_lock.h> + #include <linux/highmem.h> + #include <linux/ptrace.h> ++#include <linux/audit.h> + + #include <asm/uaccess.h> + #include <asm/io.h> +@@ -252,6 +253,7 @@ + static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk) + { + struct tss_struct *tss; ++ long eax; + /* + * make sure the vm86() system call doesn't try to do anything silly + */ +@@ -305,13 +307,19 @@ + tsk->thread.screen_bitmap = info->screen_bitmap; + if (info->flags & VM86_SCREEN_BITMAP) + mark_screen_rdonly(tsk->mm); ++ __asm__ __volatile__("xorl %eax,%eax; movl %eax,%fs; movl %eax,%gs\n\t"); ++ __asm__ __volatile__("movl %%eax, %0\n" :"=r"(eax)); ++ ++ /*call audit_syscall_exit since we do not exit via the normal paths */ ++ if (unlikely(current->audit_context)) ++ audit_syscall_exit(current, AUDITSC_RESULT(eax), eax); ++ + __asm__ __volatile__( +- "xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t" + "movl %0,%%esp\n\t" + "movl %1,%%ebp\n\t" + "jmp resume_userspace" + : /* no outputs */ +- :"r" (&info->regs), "r" (task_thread_info(tsk)) : "ax"); ++ :"r" (&info->regs), "r" (task_thread_info(tsk))); + /* we never return here */ + } + +diff -Nurd linux-2.6.16.orig/arch/m32r/kernel/m32r_ksyms.c linux-2.6.16/arch/m32r/kernel/m32r_ksyms.c +--- linux-2.6.16.orig/arch/m32r/kernel/m32r_ksyms.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/m32r/kernel/m32r_ksyms.c 2006-06-03 11:14:55.242491120 +0200 +@@ -38,10 +38,6 @@ + EXPORT_SYMBOL(__delay); + EXPORT_SYMBOL(__const_udelay); + +-EXPORT_SYMBOL(__get_user_1); +-EXPORT_SYMBOL(__get_user_2); +-EXPORT_SYMBOL(__get_user_4); +- + EXPORT_SYMBOL(strpbrk); + EXPORT_SYMBOL(strstr); + +diff -Nurd linux-2.6.16.orig/arch/m32r/kernel/setup.c linux-2.6.16/arch/m32r/kernel/setup.c +--- linux-2.6.16.orig/arch/m32r/kernel/setup.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/m32r/kernel/setup.c 2006-06-03 11:14:55.243490968 +0200 +@@ -9,6 +9,7 @@ + + #include <linux/config.h> + #include <linux/init.h> ++#include <linux/kernel.h> + #include <linux/stddef.h> + #include <linux/fs.h> + #include <linux/sched.h> +@@ -218,8 +219,6 @@ + extern unsigned long setup_memory(void); + #endif /* CONFIG_DISCONTIGMEM */ + +-#define M32R_PCC_PCATCR 0x00ef7014 /* will move to m32r.h */ +- + void __init setup_arch(char **cmdline_p) + { + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); +@@ -268,15 +267,14 @@ + paging_init(); + } + +-static struct cpu cpu[NR_CPUS]; ++static struct cpu cpu_devices[NR_CPUS]; + + static int __init topology_init(void) + { +- int cpu_id; ++ int i; + +- for (cpu_id = 0; cpu_id < NR_CPUS; cpu_id++) +- if (cpu_possible(cpu_id)) +- register_cpu(&cpu[cpu_id], cpu_id, NULL); ++ for_each_present_cpu(i) ++ register_cpu(&cpu_devices[i], i, NULL); + + return 0; + } +diff -Nurd linux-2.6.16.orig/arch/m32r/kernel/smpboot.c linux-2.6.16/arch/m32r/kernel/smpboot.c +--- linux-2.6.16.orig/arch/m32r/kernel/smpboot.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/m32r/kernel/smpboot.c 2006-06-03 11:14:55.243490968 +0200 +@@ -39,8 +39,10 @@ + * Martin J. Bligh : Added support for multi-quad systems + */ + ++#include <linux/module.h> + #include <linux/config.h> + #include <linux/init.h> ++#include <linux/kernel.h> + #include <linux/mm.h> + #include <linux/smp_lock.h> + #include <linux/irq.h> +@@ -72,11 +74,15 @@ + + /* Bitmask of currently online CPUs */ + cpumask_t cpu_online_map; ++EXPORT_SYMBOL(cpu_online_map); + + cpumask_t cpu_bootout_map; + cpumask_t cpu_bootin_map; +-cpumask_t cpu_callout_map; + static cpumask_t cpu_callin_map; ++cpumask_t cpu_callout_map; ++EXPORT_SYMBOL(cpu_callout_map); ++cpumask_t cpu_possible_map = CPU_MASK_ALL; ++EXPORT_SYMBOL(cpu_possible_map); + + /* Per CPU bogomips and other parameters */ + struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned; +@@ -110,7 +116,6 @@ + + void smp_prepare_boot_cpu(void); + void smp_prepare_cpus(unsigned int); +-static void smp_tune_scheduling(void); + static void init_ipi_lock(void); + static void do_boot_cpu(int); + int __cpu_up(unsigned int); +@@ -177,6 +182,9 @@ + } + for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++) + physid_set(phys_id, phys_cpu_present_map); ++#ifndef CONFIG_HOTPLUG_CPU ++ cpu_present_map = cpu_possible_map; ++#endif + + show_mp_info(nr_cpu); + +@@ -186,7 +194,6 @@ + * Setup boot CPU information + */ + smp_store_cpu_info(0); /* Final full version of the data */ +- smp_tune_scheduling(); + + /* + * If SMP should be disabled, then really disable it! +@@ -230,11 +237,6 @@ + Dprintk("Boot done.\n"); + } + +-static void __init smp_tune_scheduling(void) +-{ +- /* Nothing to do. */ +-} +- + /* + * init_ipi_lock : Initialize IPI locks. + */ +@@ -629,4 +631,3 @@ + physid_2_cpu[phys_id] = -1; + cpu_2_physid[cpu_id] = -1; + } +- +diff -Nurd linux-2.6.16.orig/arch/m32r/lib/getuser.S linux-2.6.16/arch/m32r/lib/getuser.S +--- linux-2.6.16.orig/arch/m32r/lib/getuser.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/m32r/lib/getuser.S 1970-01-01 01:00:00.000000000 +0100 +@@ -1,88 +0,0 @@ +-/* +- * __get_user functions. +- * +- * (C) Copyright 2001 Hirokazu Takata +- * +- * These functions have a non-standard call interface +- * to make them more efficient, especially as they +- * return an error value in addition to the "real" +- * return value. +- */ +- +-#include <linux/config.h> +- +-/* +- * __get_user_X +- * +- * Inputs: r0 contains the address +- * +- * Outputs: r0 is error code (0 or -EFAULT) +- * r1 contains zero-extended value +- * +- * These functions should not modify any other registers, +- * as they get called from within inline assembly. +- */ +- +-#ifdef CONFIG_ISA_DUAL_ISSUE +- +- .text +- .balign 4 +- .globl __get_user_1 +-__get_user_1: +-1: ldub r1, @r0 || ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __get_user_2 +-__get_user_2: +-2: lduh r1, @r0 || ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __get_user_4 +-__get_user_4: +-3: ld r1, @r0 || ldi r0, #0 +- jmp r14 +- +-bad_get_user: +- ldi r1, #0 || ldi r0, #-14 +- jmp r14 +- +-#else /* not CONFIG_ISA_DUAL_ISSUE */ +- +- .text +- .balign 4 +- .globl __get_user_1 +-__get_user_1: +-1: ldub r1, @r0 +- ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __get_user_2 +-__get_user_2: +-2: lduh r1, @r0 +- ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __get_user_4 +-__get_user_4: +-3: ld r1, @r0 +- ldi r0, #0 +- jmp r14 +- +-bad_get_user: +- ldi r1, #0 +- ldi r0, #-14 +- jmp r14 +- +-#endif /* not CONFIG_ISA_DUAL_ISSUE */ +- +-.section __ex_table,"a" +- .long 1b,bad_get_user +- .long 2b,bad_get_user +- .long 3b,bad_get_user +-.previous +- +- .end +diff -Nurd linux-2.6.16.orig/arch/m32r/lib/Makefile linux-2.6.16/arch/m32r/lib/Makefile +--- linux-2.6.16.orig/arch/m32r/lib/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/m32r/lib/Makefile 2006-06-03 11:14:55.244490816 +0200 +@@ -2,6 +2,6 @@ + # Makefile for M32R-specific library files.. + # + +-lib-y := checksum.o ashxdi3.o memset.o memcpy.o getuser.o \ +- putuser.o delay.o strlen.o usercopy.o csum_partial_copy.o ++lib-y := checksum.o ashxdi3.o memset.o memcpy.o \ ++ delay.o strlen.o usercopy.o csum_partial_copy.o + +diff -Nurd linux-2.6.16.orig/arch/m32r/lib/putuser.S linux-2.6.16/arch/m32r/lib/putuser.S +--- linux-2.6.16.orig/arch/m32r/lib/putuser.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/m32r/lib/putuser.S 1970-01-01 01:00:00.000000000 +0100 +@@ -1,84 +0,0 @@ +-/* +- * __put_user functions. +- * +- * (C) Copyright 1998 Linus Torvalds +- * (C) Copyright 2001 Hirokazu Takata +- * +- * These functions have a non-standard call interface +- * to make them more efficient. +- */ +- +-#include <linux/config.h> +- +-/* +- * __put_user_X +- * +- * Inputs: r0 contains the address +- * r1 contains the value +- * +- * Outputs: r0 is error code (0 or -EFAULT) +- * r1 is corrupted (will contain "current_task"). +- * +- * These functions should not modify any other registers, +- * as they get called from within inline assembly. +- */ +- +-#ifdef CONFIG_ISA_DUAL_ISSUE +- +- .text +- .balign 4 +- .globl __put_user_1 +-__put_user_1: +-1: stb r1, @r0 || ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __put_user_2 +-__put_user_2: +-2: sth r1, @r0 || ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __put_user_4 +-__put_user_4: +-3: st r1, @r0 || ldi r0, #0 +- jmp r14 +- +-bad_put_user: +- ldi r0, #-14 || jmp r14 +- +-#else /* not CONFIG_ISA_DUAL_ISSUE */ +- +- .text +- .balign 4 +- .globl __put_user_1 +-__put_user_1: +-1: stb r1, @r0 +- ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __put_user_2 +-__put_user_2: +-2: sth r1, @r0 +- ldi r0, #0 +- jmp r14 +- +- .balign 4 +- .globl __put_user_4 +-__put_user_4: +-3: st r1, @r0 +- ldi r0, #0 +- jmp r14 +- +-bad_put_user: +- ldi r0, #-14 +- jmp r14 +- +-#endif /* not CONFIG_ISA_DUAL_ISSUE */ +- +-.section __ex_table,"a" +- .long 1b,bad_put_user +- .long 2b,bad_put_user +- .long 3b,bad_put_user +-.previous +diff -Nurd linux-2.6.16.orig/arch/mips/kernel/branch.c linux-2.6.16/arch/mips/kernel/branch.c +--- linux-2.6.16.orig/arch/mips/kernel/branch.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/mips/kernel/branch.c 2006-06-03 11:14:55.252489600 +0200 +@@ -184,7 +184,7 @@ + bit = (insn.i_format.rt >> 2); + bit += (bit != 0); + bit += 23; +- switch (insn.i_format.rt) { ++ switch (insn.i_format.rt & 3) { + case 0: /* bc1f */ + case 2: /* bc1fl */ + if (~fcr31 & (1 << bit)) +diff -Nurd linux-2.6.16.orig/arch/mips/mm/c-r4k.c linux-2.6.16/arch/mips/mm/c-r4k.c +--- linux-2.6.16.orig/arch/mips/mm/c-r4k.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/mips/mm/c-r4k.c 2006-06-03 11:14:55.253489448 +0200 +@@ -154,7 +154,8 @@ + + static inline void tx49_blast_icache32_page_indexed(unsigned long page) + { +- unsigned long start = page; ++ unsigned long indexmask = current_cpu_data.icache.waysize - 1; ++ unsigned long start = INDEX_BASE + (page & indexmask); + unsigned long end = start + PAGE_SIZE; + unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; + unsigned long ws_end = current_cpu_data.icache.ways << +diff -Nurd linux-2.6.16.orig/arch/powerpc/kernel/pci_64.c linux-2.6.16/arch/powerpc/kernel/pci_64.c +--- linux-2.6.16.orig/arch/powerpc/kernel/pci_64.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/powerpc/kernel/pci_64.c 2006-06-03 11:14:55.254489296 +0200 +@@ -78,6 +78,7 @@ + + /* Cached ISA bridge dev. */ + struct pci_dev *ppc64_isabridge_dev = NULL; ++EXPORT_SYMBOL_GPL(ppc64_isabridge_dev); + + static void fixup_broken_pcnet32(struct pci_dev* dev) + { +diff -Nurd linux-2.6.16.orig/arch/powerpc/kernel/setup_64.c linux-2.6.16/arch/powerpc/kernel/setup_64.c +--- linux-2.6.16.orig/arch/powerpc/kernel/setup_64.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/powerpc/kernel/setup_64.c 2006-06-03 11:14:55.255489144 +0200 +@@ -256,12 +256,10 @@ + /* + * Initialize stab / SLB management except on iSeries + */ +- if (!firmware_has_feature(FW_FEATURE_ISERIES)) { +- if (cpu_has_feature(CPU_FTR_SLB)) +- slb_initialize(); +- else +- stab_initialize(lpaca->stab_real); +- } ++ if (cpu_has_feature(CPU_FTR_SLB)) ++ slb_initialize(); ++ else if (!firmware_has_feature(FW_FEATURE_ISERIES)) ++ stab_initialize(lpaca->stab_real); + + DBG(" <- early_setup()\n"); + } +diff -Nurd linux-2.6.16.orig/arch/powerpc/kernel/signal_64.c linux-2.6.16/arch/powerpc/kernel/signal_64.c +--- linux-2.6.16.orig/arch/powerpc/kernel/signal_64.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/powerpc/kernel/signal_64.c 2006-06-03 11:14:55.256488992 +0200 +@@ -213,7 +213,7 @@ + /* Default to using normal stack */ + newsp = regs->gpr[1]; + +- if (ka->sa.sa_flags & SA_ONSTACK) { ++ if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) { + if (! on_sig_stack(regs->gpr[1])) + newsp = (current->sas_ss_sp + current->sas_ss_size); + } +diff -Nurd linux-2.6.16.orig/arch/x86_64/ia32/Makefile linux-2.6.16/arch/x86_64/ia32/Makefile +--- linux-2.6.16.orig/arch/x86_64/ia32/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/x86_64/ia32/Makefile 2006-06-03 11:14:55.256488992 +0200 +@@ -27,5 +27,5 @@ + $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE + $(call if_changed,syscall) + +-AFLAGS_vsyscall-sysenter.o = -m32 +-AFLAGS_vsyscall-syscall.o = -m32 ++AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32 ++AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32 +diff -Nurd linux-2.6.16.orig/arch/x86_64/kernel/entry.S linux-2.6.16/arch/x86_64/kernel/entry.S +--- linux-2.6.16.orig/arch/x86_64/kernel/entry.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/x86_64/kernel/entry.S 2006-06-03 11:14:55.258488688 +0200 +@@ -180,6 +180,10 @@ + * + * XXX if we had a free scratch register we could save the RSP into the stack frame + * and report it properly in ps. Unfortunately we haven't. ++ * ++ * When user can change the frames always force IRET. That is because ++ * it deals with uncanonical addresses better. SYSRET has trouble ++ * with them due to bugs in both AMD and Intel CPUs. + */ + + ENTRY(system_call) +@@ -254,7 +258,10 @@ + xorl %esi,%esi # oldset -> arg2 + call ptregscall_common + 1: movl $_TIF_NEED_RESCHED,%edi +- jmp sysret_check ++ /* Use IRET because user could have changed frame. This ++ works because ptregscall_common has called FIXUP_TOP_OF_STACK. */ ++ cli ++ jmp int_with_check + + badsys: + movq $-ENOSYS,RAX-ARGOFFSET(%rsp) +@@ -280,7 +287,8 @@ + call syscall_trace_leave + RESTORE_TOP_OF_STACK %rbx + RESTORE_REST +- jmp ret_from_sys_call ++ /* Use IRET because user could have changed frame */ ++ jmp int_ret_from_sys_call + CFI_ENDPROC + + /* +@@ -408,25 +416,9 @@ + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 + SAVE_REST +- movq %r11, %r15 +- CFI_REGISTER rip, r15 + FIXUP_TOP_OF_STACK %r11 + call sys_execve +- GET_THREAD_INFO(%rcx) +- bt $TIF_IA32,threadinfo_flags(%rcx) +- CFI_REMEMBER_STATE +- jc exec_32bit + RESTORE_TOP_OF_STACK %r11 +- movq %r15, %r11 +- CFI_REGISTER rip, r11 +- RESTORE_REST +- pushq %r11 +- CFI_ADJUST_CFA_OFFSET 8 +- CFI_REL_OFFSET rip, 0 +- ret +- +-exec_32bit: +- CFI_RESTORE_STATE + movq %rax,RAX(%rsp) + RESTORE_REST + jmp int_ret_from_sys_call +diff -Nurd linux-2.6.16.orig/arch/x86_64/kernel/pci-gart.c linux-2.6.16/arch/x86_64/kernel/pci-gart.c +--- linux-2.6.16.orig/arch/x86_64/kernel/pci-gart.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/x86_64/kernel/pci-gart.c 2006-06-03 11:14:55.258488688 +0200 +@@ -114,10 +114,6 @@ + static void free_iommu(unsigned long offset, int size) + { + unsigned long flags; +- if (size == 1) { +- clear_bit(offset, iommu_gart_bitmap); +- return; +- } + spin_lock_irqsave(&iommu_bitmap_lock, flags); + __clear_bit_string(iommu_gart_bitmap, offset, size); + spin_unlock_irqrestore(&iommu_bitmap_lock, flags); +diff -Nurd linux-2.6.16.orig/arch/x86_64/kernel/process.c linux-2.6.16/arch/x86_64/kernel/process.c +--- linux-2.6.16.orig/arch/x86_64/kernel/process.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/x86_64/kernel/process.c 2006-06-03 11:14:55.259488536 +0200 +@@ -527,8 +527,6 @@ + int cpu = smp_processor_id(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + +- unlazy_fpu(prev_p); +- + /* + * Reload esp0, LDT and the page table pointer: + */ +@@ -591,6 +589,12 @@ + prev->userrsp = read_pda(oldrsp); + write_pda(oldrsp, next->userrsp); + write_pda(pcurrent, next_p); ++ ++ /* This must be here to ensure both math_state_restore() and ++ kernel_fpu_begin() work consistently. ++ And the AMD workaround requires it to be after DS reload. */ ++ unlazy_fpu(prev_p); ++ + write_pda(kernelstack, + task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); + +diff -Nurd linux-2.6.16.orig/arch/x86_64/kernel/setup.c linux-2.6.16/arch/x86_64/kernel/setup.c +--- linux-2.6.16.orig/arch/x86_64/kernel/setup.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/arch/x86_64/kernel/setup.c 2006-06-03 11:14:55.260488384 +0200 +@@ -909,6 +909,10 @@ + if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)) + set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); + ++ /* Enable workaround for FXSAVE leak */ ++ if (c->x86 >= 6) ++ set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability); ++ + r = get_model_name(c); + if (!r) { + switch (c->x86) { +diff -Nurd linux-2.6.16.orig/block/genhd.c linux-2.6.16/block/genhd.c +--- linux-2.6.16.orig/block/genhd.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/block/genhd.c 2006-06-03 11:14:55.261488232 +0200 +@@ -16,8 +16,6 @@ + #include <linux/kobj_map.h> + #include <linux/buffer_head.h> + +-#define MAX_PROBE_HASH 255 /* random */ +- + static struct subsystem block_subsys; + + static DECLARE_MUTEX(block_subsys_sem); +@@ -30,108 +28,29 @@ + struct blk_major_name *next; + int major; + char name[16]; +-} *major_names[MAX_PROBE_HASH]; ++} *major_names[BLKDEV_MAJOR_HASH_SIZE]; + + /* index in the above - for now: assume no multimajor ranges */ + static inline int major_to_index(int major) + { +- return major % MAX_PROBE_HASH; +-} +- +-struct blkdev_info { +- int index; +- struct blk_major_name *bd; +-}; +- +-/* +- * iterate over a list of blkdev_info structures. allows +- * the major_names array to be iterated over from outside this file +- * must be called with the block_subsys_sem held +- */ +-void *get_next_blkdev(void *dev) +-{ +- struct blkdev_info *info; +- +- if (dev == NULL) { +- info = kmalloc(sizeof(*info), GFP_KERNEL); +- if (!info) +- goto out; +- info->index=0; +- info->bd = major_names[info->index]; +- if (info->bd) +- goto out; +- } else { +- info = dev; +- } +- +- while (info->index < ARRAY_SIZE(major_names)) { +- if (info->bd) +- info->bd = info->bd->next; +- if (info->bd) +- goto out; +- /* +- * No devices on this chain, move to the next +- */ +- info->index++; +- info->bd = (info->index < ARRAY_SIZE(major_names)) ? +- major_names[info->index] : NULL; +- if (info->bd) +- goto out; +- } +- +-out: +- return info; +-} +- +-void *acquire_blkdev_list(void) +-{ +- down(&block_subsys_sem); +- return get_next_blkdev(NULL); +-} +- +-void release_blkdev_list(void *dev) +-{ +- up(&block_subsys_sem); +- kfree(dev); ++ return major % BLKDEV_MAJOR_HASH_SIZE; + } + ++#ifdef CONFIG_PROC_FS + +-/* +- * Count the number of records in the blkdev_list. +- * must be called with the block_subsys_sem held +- */ +-int count_blkdev_list(void) ++void blkdev_show(struct seq_file *f, off_t offset) + { +- struct blk_major_name *n; +- int i, count; +- +- count = 0; ++ struct blk_major_name *dp; + +- for (i = 0; i < ARRAY_SIZE(major_names); i++) { +- for (n = major_names[i]; n; n = n->next) +- count++; ++ if (offset < BLKDEV_MAJOR_HASH_SIZE) { ++ down(&block_subsys_sem); ++ for (dp = major_names[offset]; dp; dp = dp->next) ++ seq_printf(f, "%3d %s\n", dp->major, dp->name); ++ up(&block_subsys_sem); + } +- +- return count; +-} +- +-/* +- * extract the major and name values from a blkdev_info struct +- * passed in as a void to *dev. Must be called with +- * block_subsys_sem held +- */ +-int get_blkdev_info(void *dev, int *major, char **name) +-{ +- struct blkdev_info *info = dev; +- +- if (info->bd == NULL) +- return 1; +- +- *major = info->bd->major; +- *name = info->bd->name; +- return 0; + } + ++#endif /* CONFIG_PROC_FS */ + + int register_blkdev(unsigned int major, const char *name) + { +diff -Nurd linux-2.6.16.orig/.config linux-2.6.16/.config +--- linux-2.6.16.orig/.config 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/.config 2006-06-03 11:14:57.009222536 +0200 +@@ -0,0 +1,1298 @@ ++# ++# Automatically generated make config: don't edit ++# Linux kernel version: 2.6.16.13 ++# Thu May 18 19:40:25 2006 ++# ++CONFIG_ARM=y ++CONFIG_MMU=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_ARCH_MTD_XIP=y ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++ ++# ++# General setup ++# ++CONFIG_LOCALVERSION="-ezx6" ++# CONFIG_LOCALVERSION_AUTO is not set ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++# CONFIG_POSIX_MQUEUE is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_AUDIT is not set ++# CONFIG_IKCONFIG is not set ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_UID16=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_EMBEDDED=y ++CONFIG_KALLSYMS=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_KALLSYMS_EXTRA_PASS=y ++CONFIG_HOTPLUG=y ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++CONFIG_ELF_CORE=y ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_EPOLL=y ++# CONFIG_SHMEM is not set ++CONFIG_CC_ALIGN_FUNCTIONS=0 ++CONFIG_CC_ALIGN_LABELS=0 ++CONFIG_CC_ALIGN_LOOPS=0 ++CONFIG_CC_ALIGN_JUMPS=0 ++CONFIG_SLAB=y ++CONFIG_TINY_SHMEM=y ++CONFIG_BASE_SMALL=0 ++# CONFIG_SLOB is not set ++CONFIG_OBSOLETE_INTERMODULE=m ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODULE_FORCE_UNLOAD=y ++CONFIG_OBSOLETE_MODPARM=y ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++# CONFIG_KMOD is not set ++ ++# ++# Block layer ++# ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y ++# CONFIG_IOSCHED_AS is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_IOSCHED_CFQ is not set ++# CONFIG_DEFAULT_AS is not set ++# CONFIG_DEFAULT_DEADLINE is not set ++# CONFIG_DEFAULT_CFQ is not set ++CONFIG_DEFAULT_NOOP=y ++CONFIG_DEFAULT_IOSCHED="noop" ++ ++# ++# System Type ++# ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_IOP3XX is not set ++# CONFIG_ARCH_IXP4XX is not set ++# CONFIG_ARCH_IXP2000 is not set ++# CONFIG_ARCH_L7200 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_S3C2410 is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_LH7A40X is not set ++# CONFIG_ARCH_OMAP is not set ++# CONFIG_ARCH_VERSATILE is not set ++# CONFIG_ARCH_REALVIEW is not set ++# CONFIG_ARCH_IMX is not set ++# CONFIG_ARCH_H720X is not set ++# CONFIG_ARCH_AAEC2000 is not set ++# CONFIG_ARCH_AT91RM9200 is not set ++CONFIG_PXA_EZX=y ++ ++# ++# Intel PXA2xx Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_MACH_MAINSTONE is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_PXA_SHARPSL is not set ++# CONFIG_PXA_EZX_E680 is not set ++CONFIG_PXA_EZX_A780=y ++CONFIG_PXA27x=y ++CONFIG_IWMMXT=y ++CONFIG_PXA_SPI=y ++CONFIG_PXA_EZX_PCAP=y ++CONFIG_PXA_EZX_PCAP_EMU=m ++ ++# ++# Processor Type ++# ++CONFIG_CPU_32=y ++CONFIG_CPU_XSCALE=y ++CONFIG_CPU_32v5=y ++CONFIG_CPU_ABRT_EV5T=y ++CONFIG_CPU_CACHE_VIVT=y ++CONFIG_CPU_TLB_V4WBI=y ++ ++# ++# Processor Features ++# ++CONFIG_ARM_THUMB=y ++CONFIG_XSCALE_PMU=y ++ ++# ++# Bus support ++# ++ ++# ++# PCCARD (PCMCIA/CardBus) support ++# ++# CONFIG_PCCARD is not set ++ ++# ++# Kernel Features ++# ++# CONFIG_PREEMPT is not set ++# CONFIG_NO_IDLE_HZ is not set ++# CONFIG_AEABI is not set ++# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++# CONFIG_DISCONTIGMEM_MANUAL is not set ++# CONFIG_SPARSEMEM_MANUAL is not set ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++# CONFIG_SPARSEMEM_STATIC is not set ++CONFIG_SPLIT_PTLOCK_CPUS=4096 ++CONFIG_ALIGNMENT_TRAP=y ++ ++# ++# Boot options ++# ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++CONFIG_CMDLINE="mem=32M root=/dev/mmcblk0p1 rootfstype=ext3 rootdelay=1 ip=192.168.1.2:192.168.1.10:192.168.1.10:255.255.255.0:ezx:usb0:off console=ttyS2,115200n8 console=tty0" ++# CONFIG_XIP_KERNEL is not set ++ ++# ++# Floating point emulation ++# ++ ++# ++# At least one emulation must be selected ++# ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_NWFPE_XP is not set ++# CONFIG_FPE_FASTFPE is not set ++ ++# ++# Userspace binary formats ++# ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_ARTHUR is not set ++ ++# ++# Power management options ++# ++CONFIG_PM=y ++CONFIG_PM_LEGACY=y ++# CONFIG_PM_DEBUG is not set ++CONFIG_APM=y ++ ++# ++# Networking ++# ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++# CONFIG_NETDEBUG is not set ++CONFIG_PACKET=m ++CONFIG_PACKET_MMAP=y ++CONFIG_UNIX=m ++CONFIG_XFRM=y ++CONFIG_XFRM_USER=m ++CONFIG_NET_KEY=m ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_FIB_HASH=y ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++CONFIG_INET_AH=m ++CONFIG_INET_ESP=m ++CONFIG_INET_IPCOMP=m ++CONFIG_INET_TUNNEL=m ++CONFIG_INET_DIAG=m ++CONFIG_INET_TCP_DIAG=m ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_BIC=y ++ ++# ++# IP: Virtual Server Configuration ++# ++# CONFIG_IP_VS is not set ++CONFIG_IPV6=m ++# CONFIG_IPV6_PRIVACY is not set ++CONFIG_INET6_AH=m ++CONFIG_INET6_ESP=m ++CONFIG_INET6_IPCOMP=m ++CONFIG_INET6_TUNNEL=m ++CONFIG_IPV6_TUNNEL=m ++CONFIG_NETFILTER=y ++# CONFIG_NETFILTER_DEBUG is not set ++ ++# ++# Core Netfilter Configuration ++# ++CONFIG_NETFILTER_NETLINK=m ++CONFIG_NETFILTER_NETLINK_QUEUE=m ++CONFIG_NETFILTER_NETLINK_LOG=m ++CONFIG_NETFILTER_XTABLES=m ++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m ++CONFIG_NETFILTER_XT_TARGET_MARK=m ++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m ++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m ++CONFIG_NETFILTER_XT_MATCH_COMMENT=m ++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m ++CONFIG_NETFILTER_XT_MATCH_DCCP=m ++CONFIG_NETFILTER_XT_MATCH_HELPER=m ++CONFIG_NETFILTER_XT_MATCH_LENGTH=m ++CONFIG_NETFILTER_XT_MATCH_LIMIT=m ++CONFIG_NETFILTER_XT_MATCH_MAC=m ++CONFIG_NETFILTER_XT_MATCH_MARK=m ++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m ++CONFIG_NETFILTER_XT_MATCH_REALM=m ++CONFIG_NETFILTER_XT_MATCH_SCTP=m ++CONFIG_NETFILTER_XT_MATCH_STATE=m ++CONFIG_NETFILTER_XT_MATCH_STRING=m ++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m ++ ++# ++# IP: Netfilter Configuration ++# ++CONFIG_IP_NF_CONNTRACK=m ++# CONFIG_IP_NF_CT_ACCT is not set ++# CONFIG_IP_NF_CONNTRACK_MARK is not set ++CONFIG_IP_NF_CONNTRACK_EVENTS=y ++CONFIG_IP_NF_CONNTRACK_NETLINK=m ++CONFIG_IP_NF_CT_PROTO_SCTP=m ++CONFIG_IP_NF_FTP=m ++CONFIG_IP_NF_IRC=m ++CONFIG_IP_NF_NETBIOS_NS=m ++CONFIG_IP_NF_TFTP=m ++CONFIG_IP_NF_AMANDA=m ++CONFIG_IP_NF_PPTP=m ++# CONFIG_IP_NF_QUEUE is not set ++CONFIG_IP_NF_IPTABLES=m ++CONFIG_IP_NF_MATCH_IPRANGE=m ++CONFIG_IP_NF_MATCH_MULTIPORT=m ++CONFIG_IP_NF_MATCH_TOS=m ++CONFIG_IP_NF_MATCH_RECENT=m ++CONFIG_IP_NF_MATCH_ECN=m ++CONFIG_IP_NF_MATCH_DSCP=m ++CONFIG_IP_NF_MATCH_AH_ESP=m ++CONFIG_IP_NF_MATCH_TTL=m ++CONFIG_IP_NF_MATCH_OWNER=m ++CONFIG_IP_NF_MATCH_ADDRTYPE=m ++CONFIG_IP_NF_MATCH_HASHLIMIT=m ++CONFIG_IP_NF_MATCH_POLICY=m ++CONFIG_IP_NF_FILTER=m ++CONFIG_IP_NF_TARGET_REJECT=m ++CONFIG_IP_NF_TARGET_LOG=m ++CONFIG_IP_NF_TARGET_ULOG=m ++CONFIG_IP_NF_TARGET_TCPMSS=m ++CONFIG_IP_NF_NAT=m ++CONFIG_IP_NF_NAT_NEEDED=y ++CONFIG_IP_NF_TARGET_MASQUERADE=m ++CONFIG_IP_NF_TARGET_REDIRECT=m ++CONFIG_IP_NF_TARGET_NETMAP=m ++CONFIG_IP_NF_TARGET_SAME=m ++CONFIG_IP_NF_NAT_SNMP_BASIC=m ++CONFIG_IP_NF_NAT_IRC=m ++CONFIG_IP_NF_NAT_FTP=m ++CONFIG_IP_NF_NAT_TFTP=m ++CONFIG_IP_NF_NAT_AMANDA=m ++CONFIG_IP_NF_NAT_PPTP=m ++CONFIG_IP_NF_MANGLE=m ++CONFIG_IP_NF_TARGET_TOS=m ++# CONFIG_IP_NF_TARGET_ECN is not set ++CONFIG_IP_NF_TARGET_DSCP=m ++CONFIG_IP_NF_TARGET_TTL=m ++CONFIG_IP_NF_RAW=m ++CONFIG_IP_NF_ARPTABLES=m ++CONFIG_IP_NF_ARPFILTER=m ++CONFIG_IP_NF_ARP_MANGLE=m ++ ++# ++# IPv6: Netfilter Configuration (EXPERIMENTAL) ++# ++# CONFIG_IP6_NF_QUEUE is not set ++CONFIG_IP6_NF_IPTABLES=m ++CONFIG_IP6_NF_MATCH_RT=m ++CONFIG_IP6_NF_MATCH_OPTS=m ++CONFIG_IP6_NF_MATCH_FRAG=m ++CONFIG_IP6_NF_MATCH_HL=m ++CONFIG_IP6_NF_MATCH_MULTIPORT=m ++CONFIG_IP6_NF_MATCH_OWNER=m ++CONFIG_IP6_NF_MATCH_IPV6HEADER=m ++CONFIG_IP6_NF_MATCH_AHESP=m ++CONFIG_IP6_NF_MATCH_EUI64=m ++CONFIG_IP6_NF_MATCH_POLICY=m ++CONFIG_IP6_NF_FILTER=m ++CONFIG_IP6_NF_TARGET_LOG=m ++CONFIG_IP6_NF_TARGET_REJECT=m ++CONFIG_IP6_NF_MANGLE=m ++CONFIG_IP6_NF_TARGET_HL=m ++CONFIG_IP6_NF_RAW=m ++ ++# ++# DCCP Configuration (EXPERIMENTAL) ++# ++# CONFIG_IP_DCCP is not set ++ ++# ++# SCTP Configuration (EXPERIMENTAL) ++# ++# CONFIG_IP_SCTP is not set ++ ++# ++# TIPC Configuration (EXPERIMENTAL) ++# ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# CONFIG_LLC2 is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++CONFIG_NET_CLS_ROUTE=y ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_IRDA is not set ++CONFIG_BT=m ++CONFIG_BT_L2CAP=m ++CONFIG_BT_SCO=m ++CONFIG_BT_RFCOMM=m ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=m ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=m ++ ++# ++# Bluetooth device drivers ++# ++CONFIG_BT_HCIUSB=m ++CONFIG_BT_HCIUSB_SCO=y ++CONFIG_BT_HCIUART=m ++CONFIG_BT_HCIUART_H4=y ++CONFIG_BT_HCIUART_BCSP=y ++CONFIG_BT_HCIBCM203X=m ++CONFIG_BT_HCIBPA10X=m ++CONFIG_BT_HCIBFUSB=m ++CONFIG_BT_HCIVHCI=m ++CONFIG_IEEE80211=m ++# CONFIG_IEEE80211_DEBUG is not set ++CONFIG_IEEE80211_CRYPT_WEP=m ++CONFIG_IEEE80211_CRYPT_CCMP=m ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_STANDALONE=y ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++CONFIG_FW_LOADER=m ++# CONFIG_DEBUG_DRIVER is not set ++ ++# ++# Connector - unified userspace <-> kernelspace linker ++# ++CONFIG_CONNECTOR=m ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=m ++CONFIG_MTD_DEBUG=y ++CONFIG_MTD_DEBUG_VERBOSE=3 ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_REDBOOT_PARTS is not set ++# CONFIG_MTD_CMDLINE_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=m ++CONFIG_MTD_BLOCK=m ++# CONFIG_MTD_BLOCK_RO is not set ++CONFIG_FTL=m ++CONFIG_NFTL=m ++CONFIG_NFTL_RW=y ++CONFIG_INFTL=m ++CONFIG_RFD_FTL=m ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=m ++CONFIG_MTD_JEDECPROBE=m ++CONFIG_MTD_GEN_PROBE=m ++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=y ++# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set ++CONFIG_MTD_CFI_I1=y ++# CONFIG_MTD_CFI_I2 is not set ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++# CONFIG_MTD_OTP is not set ++CONFIG_MTD_CFI_INTELEXT=m ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++CONFIG_MTD_CFI_UTIL=m ++# 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_XIP=y ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_COMPLEX_MAPPINGS is not set ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_SHARP_SL is not set ++CONFIG_MTD_PXA27x=m ++# CONFIG_MTD_PLATRAM is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_DATAFLASH is not set ++# CONFIG_MTD_M25P80 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_PHRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++# CONFIG_MTD_BLOCK2MTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++CONFIG_MTD_DOC2001PLUS=m ++CONFIG_MTD_DOCPROBE=m ++CONFIG_MTD_DOCECC=m ++# CONFIG_MTD_DOCPROBE_ADVANCED is not set ++CONFIG_MTD_DOCPROBE_ADDRESS=0 ++ ++# ++# NAND Flash Device Drivers ++# ++CONFIG_MTD_NAND=m ++# CONFIG_MTD_NAND_VERIFY_WRITE is not set ++# CONFIG_MTD_NAND_H1900 is not set ++CONFIG_MTD_NAND_IDS=m ++CONFIG_MTD_NAND_DISKONCHIP=m ++CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y ++CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x0 ++# CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH is not set ++# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set ++# CONFIG_MTD_NAND_SHARPSL is not set ++# CONFIG_MTD_NAND_NANDSIM is not set ++ ++# ++# OneNAND Flash Device Drivers ++# ++# CONFIG_MTD_ONENAND is not set ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Plug and Play support ++# ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=m ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_UB is not set ++# CONFIG_BLK_DEV_RAM is not set ++CONFIG_BLK_DEV_RAM_COUNT=16 ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_ARCH_EZX_ROFLASH is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++# CONFIG_RAID_ATTRS is not set ++# CONFIG_SCSI is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++CONFIG_MD=y ++# CONFIG_BLK_DEV_MD is not set ++CONFIG_BLK_DEV_DM=m ++CONFIG_DM_CRYPT=m ++# CONFIG_DM_SNAPSHOT is not set ++# CONFIG_DM_MIRROR is not set ++# CONFIG_DM_ZERO is not set ++# CONFIG_DM_MULTIPATH is not set ++ ++# ++# Fusion MPT device support ++# ++# CONFIG_FUSION is not set ++ ++# ++# IEEE 1394 (FireWire) support ++# ++ ++# ++# I2O device support ++# ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++ ++# ++# PHY device support ++# ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++# CONFIG_NET_ETHERNET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++ ++# ++# Ethernet (10000 Mbit) ++# ++ ++# ++# Token Ring devices ++# ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++CONFIG_PPP_MPPE=m ++# CONFIG_PPPOE is not set ++# CONFIG_SLIP is not set ++# CONFIG_SHAPER is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++ ++# ++# Userland interfaces ++# ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_TSDEV=m ++CONFIG_INPUT_TSDEV_SCREEN_X=240 ++CONFIG_INPUT_TSDEV_SCREEN_Y=320 ++CONFIG_INPUT_EVDEV=m ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++CONFIG_INPUT_KEYBOARD=y ++# CONFIG_KEYBOARD_ATKBD is not set ++# CONFIG_KEYBOARD_SUNKBD is not set ++# CONFIG_KEYBOARD_LKKBD is not set ++# CONFIG_KEYBOARD_XTKBD is not set ++# CONFIG_KEYBOARD_NEWTON is not set ++CONFIG_KEYBOARD_PXA=y ++CONFIG_INPUT_MOUSE=y ++# CONFIG_MOUSE_PS2 is not set ++# CONFIG_MOUSE_SERIAL is not set ++# CONFIG_MOUSE_VSXXXAA is not set ++# CONFIG_INPUT_JOYSTICK is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_TOUCHSCREEN_ADS7846 is not set ++# CONFIG_TOUCHSCREEN_GUNZE is not set ++# CONFIG_TOUCHSCREEN_ELO is not set ++# CONFIG_TOUCHSCREEN_MTOUCH is not set ++# CONFIG_TOUCHSCREEN_MK712 is not set ++CONFIG_TOUCHSCREEN_PCAP=m ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++CONFIG_SERIO=m ++# CONFIG_SERIO_SERPORT is not set ++# CONFIG_SERIO_LIBPS2 is not set ++# CONFIG_SERIO_RAW is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_PXA=y ++CONFIG_SERIAL_PXA_CONSOLE=y ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++CONFIG_UNIX98_PTYS=y ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=256 ++ ++# ++# IPMI ++# ++# CONFIG_IPMI_HANDLER is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++CONFIG_SA1100_RTC=y ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_LINUX_LED is not set ++# CONFIG_BULVERDE_SRAM_DEV is not set ++ ++# ++# TPM devices ++# ++# CONFIG_TCG_TPM is not set ++# CONFIG_TELCLOCK is not set ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++CONFIG_I2C_CHARDEV=y ++ ++# ++# I2C Algorithms ++# ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++# CONFIG_I2C_ALGOPCA is not set ++ ++# ++# I2C Hardware Bus support ++# ++CONFIG_I2C_PXA=y ++CONFIG_I2C_PXA_SLAVE=y ++# CONFIG_I2C_PARPORT_LIGHT is not set ++# CONFIG_I2C_STUB is not set ++# CONFIG_I2C_PCA_ISA is not set ++ ++# ++# Miscellaneous I2C Chip support ++# ++# CONFIG_SENSORS_DS1337 is not set ++# CONFIG_SENSORS_DS1374 is not set ++# CONFIG_SENSORS_EEPROM is not set ++# CONFIG_SENSORS_PCF8574 is not set ++# CONFIG_SENSORS_PCA9539 is not set ++# CONFIG_SENSORS_PCF8591 is not set ++# CONFIG_SENSORS_RTC8564 is not set ++# CONFIG_SENSORS_MAX6875 is not set ++# CONFIG_RTC_X1205_I2C is not set ++# CONFIG_I2C_ADCM2700 is not set ++# CONFIG_I2C_A780_CAMERA is not set ++# CONFIG_I2C_DEBUG_CORE is not set ++# CONFIG_I2C_DEBUG_ALGO is not set ++# CONFIG_I2C_DEBUG_BUS is not set ++# CONFIG_I2C_DEBUG_CHIP is not set ++ ++# ++# SPI support ++# ++CONFIG_SPI=y ++CONFIG_SPI_DEBUG=y ++CONFIG_SPI_MASTER=y ++ ++# ++# SPI Master Controller Drivers ++# ++CONFIG_SPI_BITBANG=m ++ ++# ++# SPI Protocol Masters ++# ++ ++# ++# Dallas's 1-wire bus ++# ++# CONFIG_W1 is not set ++ ++# ++# Hardware Monitoring support ++# ++# CONFIG_HWMON is not set ++# CONFIG_HWMON_VID is not set ++ ++# ++# Misc devices ++# ++ ++# ++# Motorola EZX devices ++# ++# CONFIG_KEYPAD_A780 is not set ++# CONFIG_KEYPAD_E680 is not set ++# CONFIG_KEYLIGHT_A780 is not set ++# CONFIG_FMRADIO_E680 is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# Digital Video Broadcasting Devices ++# ++# CONFIG_DVB is not set ++ ++# ++# Graphics support ++# ++CONFIG_FB=y ++CONFIG_FB_CFB_FILLRECT=y ++CONFIG_FB_CFB_COPYAREA=y ++CONFIG_FB_CFB_IMAGEBLIT=y ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_MODE_HELPERS is not set ++CONFIG_FB_TILEBLITTING=y ++# CONFIG_FB_S1D13XXX is not set ++CONFIG_FB_PXA=y ++CONFIG_FB_PXA_PARAMETERS=y ++# CONFIG_FB_VIRTUAL is not set ++ ++# ++# Console display driver support ++# ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set ++CONFIG_FONTS=y ++# CONFIG_FONT_8x8 is not set ++# CONFIG_FONT_8x16 is not set ++# CONFIG_FONT_6x11 is not set ++# CONFIG_FONT_7x14 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++# CONFIG_FONT_ACORN_8x8 is not set ++CONFIG_FONT_MINI_4x6=y ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_SUN12x22 is not set ++# CONFIG_FONT_10x18 is not set ++ ++# ++# Logo configuration ++# ++CONFIG_LOGO=y ++CONFIG_LOGO_LINUX_MONO=y ++CONFIG_LOGO_LINUX_VGA16=y ++CONFIG_LOGO_LINUX_CLUT224=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_BACKLIGHT_CLASS_DEVICE=m ++CONFIG_BACKLIGHT_DEVICE=y ++CONFIG_LCD_CLASS_DEVICE=m ++CONFIG_LCD_DEVICE=y ++ ++# ++# Sound ++# ++# CONFIG_SOUND is not set ++ ++# ++# USB support ++# ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB_ARCH_HAS_OHCI=y ++CONFIG_USB=m ++# CONFIG_USB_DEBUG is not set ++ ++# ++# Miscellaneous USB options ++# ++# CONFIG_USB_DEVICEFS is not set ++# CONFIG_USB_BANDWIDTH is not set ++# CONFIG_USB_DYNAMIC_MINORS is not set ++# CONFIG_USB_SUSPEND is not set ++# CONFIG_USB_OTG is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_ISP116X_HCD is not set ++CONFIG_USB_OHCI_HCD=m ++# CONFIG_USB_OHCI_BIG_ENDIAN is not set ++CONFIG_USB_OHCI_LITTLE_ENDIAN=y ++# CONFIG_USB_SL811_HCD is not set ++ ++# ++# USB Device Class drivers ++# ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++ ++# ++# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' ++# ++ ++# ++# may also be needed; see USB_STORAGE Help for more information ++# ++# CONFIG_USB_STORAGE is not set ++CONFIG_USB_LIBUSUAL=y ++ ++# ++# USB Input Devices ++# ++# CONFIG_USB_HID is not set ++ ++# ++# USB HID Boot Protocol drivers ++# ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_AIPTEK is not set ++# CONFIG_USB_WACOM is not set ++# CONFIG_USB_ACECAD is not set ++# CONFIG_USB_KBTAB is not set ++# CONFIG_USB_POWERMATE is not set ++# CONFIG_USB_MTOUCH is not set ++# CONFIG_USB_ITMTOUCH is not set ++# CONFIG_USB_EGALAX is not set ++# CONFIG_USB_YEALINK is not set ++# CONFIG_USB_XPAD is not set ++# CONFIG_USB_ATI_REMOTE is not set ++# CONFIG_USB_ATI_REMOTE2 is not set ++# CONFIG_USB_KEYSPAN_REMOTE is not set ++# CONFIG_USB_APPLETOUCH is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_MDC800 is not set ++ ++# ++# USB Multimedia devices ++# ++# CONFIG_USB_DABUSB is not set ++ ++# ++# Video4Linux support is needed for USB Multimedia device support ++# ++ ++# ++# USB Network Adapters ++# ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_USBNET is not set ++CONFIG_USB_MON=y ++ ++# ++# USB port drivers ++# ++ ++# ++# USB Serial Converter support ++# ++# CONFIG_USB_SERIAL is not set ++ ++# ++# USB Miscellaneous drivers ++# ++# CONFIG_USB_EMI62 is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_AUERSWALD is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_LEGOTOWER is not set ++# CONFIG_USB_LCD is not set ++# CONFIG_USB_LED is not set ++# CONFIG_USB_CYTHERM is not set ++# CONFIG_USB_PHIDGETKIT is not set ++# CONFIG_USB_PHIDGETSERVO is not set ++# CONFIG_USB_IDMOUSE is not set ++# CONFIG_USB_LD is not set ++ ++# ++# USB DSL modem support ++# ++ ++# ++# USB Gadget Support ++# ++CONFIG_USB_GADGET=y ++CONFIG_USB_GADGET_DEBUG_FILES=y ++CONFIG_USB_GADGET_SELECTED=y ++# CONFIG_USB_GADGET_NET2280 is not set ++# CONFIG_USB_GADGET_PXA2XX is not set ++CONFIG_USB_GADGET_PXA27X=y ++CONFIG_USB_PXA27X=y ++# CONFIG_USB_PXA27X_DMA is not set ++# CONFIG_USB_GADGET_GOKU is not set ++# CONFIG_USB_GADGET_LH7A40X is not set ++# CONFIG_USB_GADGET_OMAP is not set ++# CONFIG_USB_GADGET_DUMMY_HCD is not set ++# CONFIG_USB_GADGET_DUALSPEED is not set ++# CONFIG_USB_ZERO is not set ++CONFIG_USB_ETH=y ++# CONFIG_USB_ETH_RNDIS is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FILE_STORAGE is not set ++# CONFIG_USB_G_SERIAL is not set ++ ++# ++# MMC/SD Card support ++# ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_PXA=y ++ ++# ++# File systems ++# ++# CONFIG_EXT2_FS is not set ++CONFIG_EXT3_FS=y ++# CONFIG_EXT3_FS_XATTR is not set ++CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_MINIX_FS is not set ++CONFIG_ROMFS_FS=m ++# CONFIG_INOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_DNOTIFY is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_FUSE_FS is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_VFAT_FS=m ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_SYSFS=y ++# CONFIG_TMPFS is not set ++# CONFIG_HUGETLB_PAGE is not set ++CONFIG_RAMFS=y ++CONFIG_RELAYFS_FS=m ++CONFIG_CONFIGFS_FS=m ++ ++# ++# Miscellaneous filesystems ++# ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_CRAMFS=y ++# CONFIG_VXFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++ ++# ++# Network File Systems ++# ++CONFIG_NFS_FS=m ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++CONFIG_NFS_V4=y ++# CONFIG_NFS_DIRECTIO is not set ++CONFIG_NFSD=m ++CONFIG_NFSD_V3=y ++# CONFIG_NFSD_V3_ACL is not set ++# CONFIG_NFSD_V4 is not set ++CONFIG_NFSD_TCP=y ++CONFIG_LOCKD=m ++CONFIG_LOCKD_V4=y ++CONFIG_EXPORTFS=m ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=m ++CONFIG_SUNRPC_GSS=m ++CONFIG_RPCSEC_GSS_KRB5=m ++# CONFIG_RPCSEC_GSS_SPKM3 is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++# CONFIG_9P_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS=m ++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_ASCII 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 ++ ++# ++# Profiling support ++# ++# CONFIG_PROFILING is not set ++ ++# ++# Kernel hacking ++# ++# CONFIG_PRINTK_TIME is not set ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_KERNEL=y ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_DETECT_SOFTLOCKUP is not set ++# CONFIG_SCHEDSTATS is not set ++# CONFIG_DEBUG_SLAB is not set ++# CONFIG_DEBUG_MUTEXES is not set ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set ++# CONFIG_DEBUG_KOBJECT is not set ++# CONFIG_DEBUG_BUGVERBOSE is not set ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_DEBUG_FS is not set ++# CONFIG_DEBUG_VM is not set ++CONFIG_FRAME_POINTER=y ++CONFIG_FORCED_INLINING=y ++# CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_DEBUG_USER is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_ICEDCC is not set ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY is not set ++ ++# ++# Cryptographic options ++# ++CONFIG_CRYPTO=y ++CONFIG_CRYPTO_HMAC=y ++CONFIG_CRYPTO_NULL=m ++CONFIG_CRYPTO_MD4=m ++CONFIG_CRYPTO_MD5=m ++CONFIG_CRYPTO_SHA1=m ++CONFIG_CRYPTO_SHA256=m ++CONFIG_CRYPTO_SHA512=m ++CONFIG_CRYPTO_WP512=m ++CONFIG_CRYPTO_TGR192=m ++CONFIG_CRYPTO_DES=m ++CONFIG_CRYPTO_BLOWFISH=m ++CONFIG_CRYPTO_TWOFISH=m ++CONFIG_CRYPTO_SERPENT=m ++CONFIG_CRYPTO_AES=m ++CONFIG_CRYPTO_CAST5=m ++CONFIG_CRYPTO_CAST6=m ++CONFIG_CRYPTO_TEA=m ++CONFIG_CRYPTO_ARC4=m ++CONFIG_CRYPTO_KHAZAD=m ++CONFIG_CRYPTO_ANUBIS=m ++CONFIG_CRYPTO_DEFLATE=m ++CONFIG_CRYPTO_MICHAEL_MIC=m ++CONFIG_CRYPTO_CRC32C=m ++CONFIG_CRYPTO_TEST=m ++ ++# ++# Hardware crypto devices ++# ++ ++# ++# Library routines ++# ++CONFIG_CRC_CCITT=m ++CONFIG_CRC16=m ++CONFIG_CRC32=y ++CONFIG_LIBCRC32C=m ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m ++CONFIG_REED_SOLOMON=m ++CONFIG_REED_SOLOMON_DEC16=y ++CONFIG_TEXTSEARCH=y ++CONFIG_TEXTSEARCH_KMP=m ++CONFIG_TEXTSEARCH_BM=m ++CONFIG_TEXTSEARCH_FSM=m ++ ++# ++# Dynamic Power Management ++# ++# CONFIG_DPM is not set +diff -Nurd linux-2.6.16.orig/Documentation/dvb/get_dvb_firmware linux-2.6.16/Documentation/dvb/get_dvb_firmware +--- linux-2.6.16.orig/Documentation/dvb/get_dvb_firmware 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/Documentation/dvb/get_dvb_firmware 2006-06-03 11:14:55.218494768 +0200 +@@ -240,9 +240,9 @@ + } + + sub nxt2002 { +- my $sourcefile = "Broadband4PC_4_2_11.zip"; ++ my $sourcefile = "Technisat_DVB-PC_4_4_COMPACT.zip"; + my $url = "http://www.bbti.us/download/windows/$sourcefile"; +- my $hash = "c6d2ea47a8f456d887ada0cfb718ff2a"; ++ my $hash = "476befae8c7c1bb9648954060b1eec1f"; + my $outfile = "dvb-fe-nxt2002.fw"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); + +@@ -250,8 +250,8 @@ + + wgetfile($sourcefile, $url); + unzip($sourcefile, $tmpdir); +- verify("$tmpdir/SkyNETU.sys", $hash); +- extract("$tmpdir/SkyNETU.sys", 375832, 5908, $outfile); ++ verify("$tmpdir/SkyNET.sys", $hash); ++ extract("$tmpdir/SkyNET.sys", 331624, 5908, $outfile); + + $outfile; + } +diff -Nurd linux-2.6.16.orig/drivers/base/core.c linux-2.6.16/drivers/base/core.c +--- linux-2.6.16.orig/drivers/base/core.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/core.c 2006-06-03 11:14:55.892392320 +0200 +@@ -282,6 +282,8 @@ + if (parent) + klist_add_tail(&dev->knode_parent, &parent->klist_children); + ++ assert_constraints(dev->constraints); ++ + /* notify platform of device entry */ + if (platform_notify) + platform_notify(dev); +@@ -367,6 +369,8 @@ + klist_del(&dev->knode_parent); + device_remove_file(dev, &dev->uevent_attr); + ++ deassert_constraints(dev->constraints); ++ + /* Notify the platform of the removal, in case they + * need to do anything... + */ +diff -Nurd linux-2.6.16.orig/drivers/base/cpu.c linux-2.6.16/drivers/base/cpu.c +--- linux-2.6.16.orig/drivers/base/cpu.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/cpu.c 2006-06-03 11:14:55.261488232 +0200 +@@ -141,7 +141,7 @@ + return error; + } + +-struct sys_device *get_cpu_sysdev(int cpu) ++struct sys_device *get_cpu_sysdev(unsigned cpu) + { + if (cpu < NR_CPUS) + return cpu_sys_devices[cpu]; +diff -Nurd linux-2.6.16.orig/drivers/base/firmware_class.c linux-2.6.16/drivers/base/firmware_class.c +--- linux-2.6.16.orig/drivers/base/firmware_class.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/firmware_class.c 2006-06-03 11:14:55.262488080 +0200 +@@ -211,18 +211,20 @@ + fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) + { + u8 *new_data; ++ int new_size = fw_priv->alloc_size; + + if (min_size <= fw_priv->alloc_size) + return 0; + +- new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE); ++ new_size = ALIGN(min_size, PAGE_SIZE); ++ new_data = vmalloc(new_size); + if (!new_data) { + printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); + /* Make sure that we don't keep incomplete data */ + fw_load_abort(fw_priv); + return -ENOMEM; + } +- fw_priv->alloc_size += PAGE_SIZE; ++ fw_priv->alloc_size = new_size; + if (fw_priv->fw->data) { + memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); + vfree(fw_priv->fw->data); +diff -Nurd linux-2.6.16.orig/drivers/base/node.c linux-2.6.16/drivers/base/node.c +--- linux-2.6.16.orig/drivers/base/node.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/node.c 2006-06-03 11:14:55.262488080 +0200 +@@ -106,7 +106,7 @@ + other_node = 0; + for (i = 0; i < MAX_NR_ZONES; i++) { + struct zone *z = &pg->node_zones[i]; +- for (cpu = 0; cpu < NR_CPUS; cpu++) { ++ for_each_online_cpu(cpu) { + struct per_cpu_pageset *ps = zone_pcp(z,cpu); + numa_hit += ps->numa_hit; + numa_miss += ps->numa_miss; +diff -Nurd linux-2.6.16.orig/drivers/base/power/Makefile linux-2.6.16/drivers/base/power/Makefile +--- linux-2.6.16.orig/drivers/base/power/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/power/Makefile 2006-06-03 11:14:55.892392320 +0200 +@@ -1,4 +1,4 @@ +-obj-y := shutdown.o ++obj-y := shutdown.o power-dpm.o + obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o + + ifeq ($(CONFIG_DEBUG_DRIVER),y) +diff -Nurd linux-2.6.16.orig/drivers/base/power/power-dpm.c linux-2.6.16/drivers/base/power/power-dpm.c +--- linux-2.6.16.orig/drivers/base/power/power-dpm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/base/power/power-dpm.c 2006-06-03 11:14:55.893392168 +0200 +@@ -0,0 +1,473 @@ ++/* ++ * power-dpm.c -- Dynamic Power Management LDM power hooks ++ * ++ * (c) 2003 MontaVista Software, Inc. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express or ++ * implied. ++ */ ++ ++#include <linux/device.h> ++#include <linux/pm.h> ++#include <linux/dpm.h> ++#include <linux/sched.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++ ++#include "power.h" ++ ++/* ++ * power hotplug events ++ */ ++ ++#define BUFFER_SIZE 1024 /* should be enough memory for the env */ ++#define NUM_ENVP 32 /* number of env pointers */ ++static unsigned long sequence_num; ++static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED; ++ ++void power_event(char *eventstr) ++{ ++ char *argv [3]; ++ char **envp = NULL; ++ char *buffer = NULL; ++ char *scratch; ++ int i = 0; ++ int retval; ++ unsigned long seq; ++ ++ if (!uevent_helper[0]) ++ return; ++ ++ envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); ++ if (!envp) ++ return; ++ memset (envp, 0x00, NUM_ENVP * sizeof (char *)); ++ ++ buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); ++ if (!buffer) ++ goto exit; ++ ++ argv [0] = uevent_helper; ++ argv [1] = "power"; ++ argv [2] = 0; ++ ++ /* minimal command environment */ ++ envp [i++] = "HOME=/"; ++ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ ++ scratch = buffer; ++ ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "ACTION=event") + 1; ++ ++ spin_lock(&sequence_lock); ++ seq = sequence_num++; ++ spin_unlock(&sequence_lock); ++ ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "EVENT=%s", eventstr) + 1; ++ ++ pr_debug ("%s: %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1], ++ envp[0], envp[1], envp[2], envp[3], envp[4]); ++ retval = call_usermodehelper (argv[0], argv, envp, 0); ++ if (retval) ++ pr_debug ("%s - call_usermodehelper returned %d\n", ++ __FUNCTION__, retval); ++ ++exit: ++ kfree(buffer); ++ kfree(envp); ++ return; ++} ++ ++void device_power_event(struct device * dev, char *eventstr) ++{ ++ char *argv [3]; ++ char **envp = NULL; ++ char *buffer = NULL; ++ char *scratch; ++ int i = 0; ++ int retval; ++ unsigned long seq; ++ ++ if (!uevent_helper[0]) ++ return; ++ ++ envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); ++ if (!envp) ++ return; ++ memset (envp, 0x00, NUM_ENVP * sizeof (char *)); ++ ++ buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); ++ if (!buffer) ++ goto exit; ++ ++ argv [0] = uevent_helper; ++ argv [1] = "power"; ++ argv [2] = 0; ++ ++ /* minimal command environment */ ++ envp [i++] = "HOME=/"; ++ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ ++ scratch = buffer; ++ ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "ACTION=device-event") + 1; ++ ++ spin_lock(&sequence_lock); ++ seq = sequence_num++; ++ spin_unlock(&sequence_lock); ++ ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "DEVICE=%s", dev->bus_id) + 1; ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "EVENT=%s", eventstr) + 1; ++ envp [i++] = scratch; ++ scratch += sprintf(scratch, "SUBSYSTEM=power") + 1; ++ ++ pr_debug ("%s: %s %s %s %s %s %s %s %s %2\n", __FUNCTION__, argv[0], argv[1], ++ envp[0], envp[1], envp[2], envp[3], envp[4], envp[5], ++ envp[6]); ++ retval = call_usermodehelper (argv[0], argv, envp, 0); ++ if (retval) ++ pr_debug ("%s - call_usermodehelper returned %d\n", ++ __FUNCTION__, retval); ++ ++exit: ++ kfree(buffer); ++ kfree(envp); ++ return; ++} ++ ++/* ++ * Device constraints ++ */ ++ ++#ifdef CONFIG_DPM ++LIST_HEAD(dpm_constraints); ++DECLARE_MUTEX(dpm_constraints_sem); ++ ++void assert_constraints(struct constraints *constraints) ++{ ++ if (! constraints || constraints->asserted) ++ return; ++ ++ down(&dpm_constraints_sem); ++ constraints->asserted = 1; ++ list_add_tail(&constraints->entry, &dpm_constraints); ++ up(&dpm_constraints_sem); ++ ++ /* DPM-PM-TODO: Check against DPM state. */ ++ ++} ++ ++ ++void deassert_constraints(struct constraints *constraints) ++{ ++ if (! constraints || ! constraints->asserted) ++ return; ++ ++ down(&dpm_constraints_sem); ++ constraints->asserted = 0; ++ list_del_init(&constraints->entry); ++ up(&dpm_constraints_sem); ++} ++ ++ ++EXPORT_SYMBOL(assert_constraints); ++EXPORT_SYMBOL(deassert_constraints); ++ ++static ssize_t ++constraints_show(struct device * dev, struct device_attribute *attr, ++ char * buf) ++{ ++ int i, cnt = 0; ++ ++ if (dev->constraints) { ++ for (i = 0; i < dev->constraints->count; i++) { ++ cnt += sprintf(buf + cnt,"%s: min=%d max=%d\n", ++ dpm_param_names[dev->constraints->param[i].id], ++ dev->constraints->param[i].min, ++ dev->constraints->param[i].max); ++ } ++ ++ cnt += sprintf(buf + cnt,"asserted=%s violations=%d\n", ++ dev->constraints->asserted ? ++ "yes" : "no", dev->constraints->violations); ++ } else { ++ cnt += sprintf(buf + cnt,"none\n"); ++ } ++ ++ return cnt; ++} ++ ++static ssize_t ++constraints_store(struct device * dev, struct device_attribute *attr, ++ const char * buf, size_t count) ++{ ++ int num_args, paramid, min, max; ++ int cidx; ++ const char *cp, *paramname; ++ int paramnamelen; ++ int provisional = 0; ++ int ret = 0; ++ ++ if (!dev->constraints) { ++ if (! (dev->constraints = kmalloc(sizeof(struct constraints), ++ GFP_KERNEL))) ++ return -EINVAL; ++ ++ memset(dev->constraints, 0, ++ sizeof(struct constraints)); ++ provisional = 1; ++ } ++ ++ cp = buf; ++ while((cp - buf < count) && *cp && (*cp == ' ')) ++ cp++; ++ ++ paramname = cp; ++ ++ while((cp - buf < count) && *cp && (*cp != ' ')) ++ cp++; ++ ++ paramnamelen = cp - paramname; ++ num_args = sscanf(cp, "%d %d", &min, &max); ++ ++ if (num_args != 2) { ++ printk("DPM: Need 2 integer parameters for constraint min/max.\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ for (paramid = 0; paramid < DPM_PP_NBR; paramid++) { ++ if (strncmp(paramname, dpm_param_names[paramid], paramnamelen) == 0) ++ break; ++ } ++ ++ if (paramid >= DPM_PP_NBR) { ++ printk("DPM: Unknown power parameter name in device constraints\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ for (cidx = 0; cidx < dev->constraints->count; cidx++) ++ /* ++ * If the new range overlaps an existing range, ++ * modify the existing one. ++ */ ++ ++ if ((dev->constraints->param[cidx].id == paramid) && ++ ((max == -1) || ++ (max >= dev->constraints->param[cidx].min)) && ++ ((min == -1) || ++ (min <= dev->constraints->param[cidx].max))) ++ break; ++ ++ if (cidx >= DPM_CONSTRAINT_PARAMS_MAX) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* Error if max is less than min */ ++ if (max < min) { ++ printk("DPM: Max value of the constraint should not be less than min\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ dev->constraints->param[cidx].id = paramid; ++ dev->constraints->param[cidx].max = max; ++ dev->constraints->param[cidx].min = min; ++ ++ if (cidx == dev->constraints->count) ++ dev->constraints->count++; ++ ++ /* New constraints should start off with same state as power ++ state */ ++ if (provisional && (dev->power.power_state.event == PM_EVENT_ON)) ++ assert_constraints(dev->constraints); ++ ++out: ++ ++ if (provisional && (ret < 0)) { ++ kfree(dev->constraints); ++ dev->constraints = NULL; ++ } ++ ++ return ret < 0 ? ret : count; ++} ++ ++DEVICE_ATTR(constraints,S_IWUSR | S_IRUGO, ++ constraints_show,constraints_store); ++ ++#else /* CONFIG_DPM */ ++void assert_constraints(struct constraints *constraints) ++{ ++} ++ ++void deassert_constraints(struct constraints *constraints) ++{ ++} ++#endif /* CONFIG_DPM */ ++ ++#ifdef CONFIG_DPM ++ ++/* ++ * Driver scale callbacks ++ */ ++ ++static struct notifier_block *dpm_scale_notifier_list[SCALE_MAX]; ++static DECLARE_MUTEX(dpm_scale_sem); ++ ++/* This function may be called by the platform frequency scaler before ++ or after a frequency change, in order to let drivers adjust any ++ clocks or calculations for the new frequency. */ ++ ++void dpm_driver_scale(int level, struct dpm_opt *newop) ++{ ++ if (down_trylock(&dpm_scale_sem)) ++ return; ++ ++ notifier_call_chain(&dpm_scale_notifier_list[level], level, newop); ++ up(&dpm_scale_sem); ++} ++ ++void dpm_register_scale(struct notifier_block *nb, int level) ++{ ++ down(&dpm_scale_sem); ++ notifier_chain_register(&dpm_scale_notifier_list[level], nb); ++ up(&dpm_scale_sem); ++} ++ ++void dpm_unregister_scale(struct notifier_block *nb, int level) ++{ ++ down(&dpm_scale_sem); ++ notifier_chain_unregister(&dpm_scale_notifier_list[level], nb); ++ up(&dpm_scale_sem); ++} ++ ++int dpm_constraint_rejects = 0; ++ ++ ++int ++dpm_default_check_constraint(struct constraint_param *param, ++ struct dpm_opt *opt) ++{ ++ return (opt->pp[param->id] == -1) || ++ ((param->min == -1 || opt->pp[param->id] >= param->min) && ++ (param->max == -1 || opt->pp[param->id] <= param->max)); ++} ++ ++static int ++dpm_check_a_constraint(struct constraints *constraints, struct dpm_opt *opt) ++{ ++ int i; ++ int failid = -1; ++ int ppconstraint[DPM_PP_NBR]; ++ ++ ++ if (! constraints || !constraints->asserted) ++ return 1; ++ ++ /* ++ * ppconstraint[ppid] == 0 means power param has not been checked ++ * for a constraint ++ * == -1 means power param has matched a constraint ++ * > 0 means constraint #n-1 mismatched ++ * ++ * failid == pp id of (a) failed constraint ++ */ ++ ++ memset(ppconstraint, 0, sizeof(ppconstraint)); ++ ++ for (i = 0; i < constraints->count; i++) { ++ struct constraint_param *param = &constraints->param[i]; ++ ++ if (! dpm_md_check_constraint(param, opt)) { ++ if (ppconstraint[param->id] == 0) { ++ failid = param->id; ++ ppconstraint[failid] = i+1; ++ } ++ } else ++ ppconstraint[param->id] = -1; ++ } ++ ++ if ((failid >= 0) && (ppconstraint[failid] > 0)) { ++#ifdef CONFIG_DPM_TRACE ++ struct constraint_param *param = ++ &constraints->param[ppconstraint[failid]-1]; ++ ++ dpm_trace(DPM_TRACE_CONSTRAINT_ASSERTED, ++ param->id, param->min, param->max, ++ opt); ++#endif ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int dpm_check_constraints(struct dpm_opt *opt) ++{ ++ struct list_head * entry; ++ int valid = 1; ++ ++ list_for_each(entry,&dpm_constraints) { ++ struct constraints *constraints = ++ list_entry(entry, struct constraints, entry); ++ if (!dpm_check_a_constraint(constraints, opt)) { ++ constraints->violations++; ++ dpm_constraint_rejects++; ++ valid = 0; ++ } ++ } ++ ++ return valid; ++} ++ ++int dpm_show_opconstraints(struct dpm_opt *opt, char * buf) ++{ ++#ifdef CONFIG_PM ++ struct list_head * entry; ++ int len = 0; ++ ++ list_for_each_prev(entry,&dpm_active) { ++ struct device * dev = to_device(entry); ++ ++ if (!dpm_check_a_constraint(dev->constraints, opt)) { ++ len += sprintf(buf + len, "%s/%s\n", dev->bus->name, ++ dev->bus_id); ++ } ++ } ++ ++ return len; ++#else /* CONFIG_PM */ ++ return 0; ++#endif /* CONFIG_PM */ ++} ++ ++void dpm_force_off_constrainers(struct dpm_opt *opt) ++{ ++#ifdef CONFIG_PM ++ struct list_head * entry; ++ ++ list_for_each_prev(entry,&dpm_active) { ++ struct device * dev = to_device(entry); ++ ++ if (!dpm_check_a_constraint(dev->constraints, opt)) { ++ suspend_device(dev, PMSG_SUSPEND); ++ } ++ } ++#endif ++} ++ ++EXPORT_SYMBOL(dpm_force_off_constrainers); ++#endif /* CONFIG_DPM */ ++ +diff -Nurd linux-2.6.16.orig/drivers/base/power/resume.c linux-2.6.16/drivers/base/power/resume.c +--- linux-2.6.16.orig/drivers/base/power/resume.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/power/resume.c 2006-06-03 11:14:55.894392016 +0200 +@@ -34,6 +34,8 @@ + if (dev->bus && dev->bus->resume) { + dev_dbg(dev,"resuming\n"); + error = dev->bus->resume(dev); ++ if (!error) ++ assert_constraints(dev->constraints); + } + up(&dev->sem); + return error; +diff -Nurd linux-2.6.16.orig/drivers/base/power/suspend.c linux-2.6.16/drivers/base/power/suspend.c +--- linux-2.6.16.orig/drivers/base/power/suspend.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/power/suspend.c 2006-06-03 11:14:55.894392016 +0200 +@@ -57,6 +57,9 @@ + if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { + dev_dbg(dev, "suspending\n"); + error = dev->bus->suspend(dev, state); ++ ++ if (! error) ++ deassert_constraints(dev->constraints); + } + up(&dev->sem); + return error; +diff -Nurd linux-2.6.16.orig/drivers/base/power/sysfs.c linux-2.6.16/drivers/base/power/sysfs.c +--- linux-2.6.16.orig/drivers/base/power/sysfs.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/base/power/sysfs.c 2006-06-03 11:14:55.894392016 +0200 +@@ -56,7 +56,6 @@ + + static DEVICE_ATTR(state, 0644, state_show, state_store); + +- + /* + * wakeup - Report/change current wakeup option for device + * +@@ -128,10 +127,14 @@ + + static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); + ++extern struct device_attribute dev_attr_constraints; + + static struct attribute * power_attrs[] = { + &dev_attr_state.attr, + &dev_attr_wakeup.attr, ++#ifdef CONFIG_DPM ++ &dev_attr_constraints.attr, ++#endif + NULL, + }; + static struct attribute_group pm_attr_group = { +diff -Nurd linux-2.6.16.orig/drivers/block/cciss.c linux-2.6.16/drivers/block/cciss.c +--- linux-2.6.16.orig/drivers/block/cciss.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/block/cciss.c 2006-06-03 11:14:55.264487776 +0200 +@@ -1181,6 +1181,53 @@ + return 0; + } + ++static inline void complete_buffers(struct bio *bio, int status) ++{ ++ while (bio) { ++ struct bio *xbh = bio->bi_next; ++ int nr_sectors = bio_sectors(bio); ++ ++ bio->bi_next = NULL; ++ blk_finished_io(len); ++ bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); ++ bio = xbh; ++ } ++ ++} ++ ++static void cciss_softirq_done(struct request *rq) ++{ ++ CommandList_struct *cmd = rq->completion_data; ++ ctlr_info_t *h = hba[cmd->ctlr]; ++ unsigned long flags; ++ u64bit temp64; ++ int i, ddir; ++ ++ if (cmd->Request.Type.Direction == XFER_READ) ++ ddir = PCI_DMA_FROMDEVICE; ++ else ++ ddir = PCI_DMA_TODEVICE; ++ ++ /* command did not need to be retried */ ++ /* unmap the DMA mapping for all the scatter gather elements */ ++ for(i=0; i<cmd->Header.SGList; i++) { ++ temp64.val32.lower = cmd->SG[i].Addr.lower; ++ temp64.val32.upper = cmd->SG[i].Addr.upper; ++ pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); ++ } ++ ++ complete_buffers(rq->bio, rq->errors); ++ ++#ifdef CCISS_DEBUG ++ printk("Done with %p\n", rq); ++#endif /* CCISS_DEBUG */ ++ ++ spin_lock_irqsave(&h->lock, flags); ++ end_that_request_last(rq, rq->errors); ++ cmd_free(h, cmd,1); ++ spin_unlock_irqrestore(&h->lock, flags); ++} ++ + /* This function will check the usage_count of the drive to be updated/added. + * If the usage_count is zero then the drive information will be updated and + * the disk will be re-registered with the kernel. If not then it will be +@@ -1249,6 +1296,8 @@ + + blk_queue_max_sectors(disk->queue, 512); + ++ blk_queue_softirq_done(disk->queue, cciss_softirq_done); ++ + disk->queue->queuedata = hba[ctlr]; + + blk_queue_hardsect_size(disk->queue, +@@ -2148,20 +2197,6 @@ + addQ (&(h->cmpQ), c); + } + } +- +-static inline void complete_buffers(struct bio *bio, int status) +-{ +- while (bio) { +- struct bio *xbh = bio->bi_next; +- int nr_sectors = bio_sectors(bio); +- +- bio->bi_next = NULL; +- blk_finished_io(len); +- bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); +- bio = xbh; +- } +- +-} + /* Assumes that CCISS_LOCK(h->ctlr) is held. */ + /* Zeros out the error record and then resends the command back */ + /* to the controller */ +@@ -2179,39 +2214,6 @@ + start_io(h); + } + +-static void cciss_softirq_done(struct request *rq) +-{ +- CommandList_struct *cmd = rq->completion_data; +- ctlr_info_t *h = hba[cmd->ctlr]; +- unsigned long flags; +- u64bit temp64; +- int i, ddir; +- +- if (cmd->Request.Type.Direction == XFER_READ) +- ddir = PCI_DMA_FROMDEVICE; +- else +- ddir = PCI_DMA_TODEVICE; +- +- /* command did not need to be retried */ +- /* unmap the DMA mapping for all the scatter gather elements */ +- for(i=0; i<cmd->Header.SGList; i++) { +- temp64.val32.lower = cmd->SG[i].Addr.lower; +- temp64.val32.upper = cmd->SG[i].Addr.upper; +- pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); +- } +- +- complete_buffers(rq->bio, rq->errors); +- +-#ifdef CCISS_DEBUG +- printk("Done with %p\n", rq); +-#endif /* CCISS_DEBUG */ +- +- spin_lock_irqsave(&h->lock, flags); +- end_that_request_last(rq, rq->errors); +- cmd_free(h, cmd,1); +- spin_unlock_irqrestore(&h->lock, flags); +-} +- + /* checks the status of the job and calls complete buffers to mark all + * buffers for the completed job. Note that this function does not need + * to hold the hba/queue lock. +@@ -3269,8 +3271,8 @@ + unregister_blkdev(hba[i]->major, hba[i]->devname); + clean1: + release_io_mem(hba[i]); +- free_hba(i); + hba[i]->busy_initializing = 0; ++ free_hba(i); + return(-1); + } + +diff -Nurd linux-2.6.16.orig/drivers/block/Kconfig linux-2.6.16/drivers/block/Kconfig +--- linux-2.6.16.orig/drivers/block/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/block/Kconfig 2006-06-03 11:14:56.381317992 +0200 +@@ -453,4 +453,6 @@ + This driver provides Support for ATA over Ethernet block + devices like the Coraid EtherDrive (R) Storage Blade. + ++source "drivers/block/roflash/Kconfig" ++ + endmenu +diff -Nurd linux-2.6.16.orig/drivers/block/Makefile linux-2.6.16/drivers/block/Makefile +--- linux-2.6.16.orig/drivers/block/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/block/Makefile 2006-06-03 11:14:56.382317840 +0200 +@@ -31,3 +31,4 @@ + obj-$(CONFIG_BLK_DEV_SX8) += sx8.o + obj-$(CONFIG_BLK_DEV_UB) += ub.o + ++obj-$(CONFIG_ARCH_EZX_ROFLASH) += roflash/ +diff -Nurd linux-2.6.16.orig/drivers/block/roflash/ezx_parts.c linux-2.6.16/drivers/block/roflash/ezx_parts.c +--- linux-2.6.16.orig/drivers/block/roflash/ezx_parts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/block/roflash/ezx_parts.c 2006-06-03 11:14:56.383317688 +0200 +@@ -0,0 +1,198 @@ ++/* ++ * drivers/mtd/maps/ezx_parts.c ++ * ++ * Parse multiple flash partitions in Ezx project into mtd_table or into act_roflash_table ++ * ++ * Created by Susan Gu Oct, 22 2002 ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++#include <linux/ezx_roflash.h> ++ ++extern int roflash_init(void); ++ ++extern int cfi_intelext_read_roflash(void *priv_map, unsigned long from, size_t len, size_t *retlen, u_char *buf); ++extern int cfi_intelext_read_roflash_c(void *priv_map, unsigned long from, size_t len, size_t *retlen, u_char *buf); ++roflash_area **roflash_table_pptr = NULL; ++ ++static DECLARE_MUTEX(roflash_table_mutex); ++ ++/* I know what I am doing, so setup l_x_b flag */ ++#ifdef CONFIG_ARCH_EZX_A780 ++static roflash_area fix_roflash_table[]= ++{ ++ { ++ name: "rootfs", ++ size: 0x018E0000, /* rootfs size is 24.875MB */ ++ offset: 0x00120000, ++ roflash_read: NULL, /* force read-only in cacheable mapping*/ ++ l_x_b: ROFLASH_LINEAR, ++ phys_addr: 0x00000000, ++ },{ ++ name: "NO-USE", /* language package is moved to MDOC */ ++ size: 0x00000000, ++ offset: 0x01A00000, //Susan -- correspond to the beginning of the second flash chip // ++ roflash_read: cfi_intelext_read_roflash, ++ l_x_b: ROFLASH_BLOCK, ++ phys_addr: 0xffffffff, // not use for block cramfs mount ++ },{ ++ name: "setup", ++ size: 0x00020000, ++ offset: 0x01FA0000, ++ roflash_read: cfi_intelext_read_roflash, ++ l_x_b: ROFLASH_BLOCK, ++ phys_addr: 0xffffffff, // not use for block cramfs mount ++ } ++}; ++#if (0) ++static roflash_area fix_roflash_table[]= ++{ ++ { ++ name: "rootfs", ++ size: 0x00f00000, /* rootfs size is 15MB */ ++ offset: 0x00100000, ++ roflash_read: NULL, /* force read-only in cacheable mapping*/ ++ l_x_b: ROFLASH_LINEAR_XIP, ++ phys_addr: 0x00000000, ++ },{ ++ name: "nxipapp", /* old language area is 0xAA0000 */ ++ size: 0x00AA0000, ++ offset: 0x00500000, ++ roflash_read: cfi_intelext_read_roflash, ++ l_x_b: ROFLASH_BLOCK, ++ phys_addr: 0xffffffff, // not use for block cramfs mount ++ },{ ++ name: "setup", /* setup stuff is 1MB */ ++ size: 0x00020000, ++ offset: 0x00FA0000, ++ roflash_read: cfi_intelext_read_roflash, ++ l_x_b: ROFLASH_BLOCK, ++ phys_addr: 0xffffffff, //phys_addr is not useful for block cramfs mount ++ } ++}; ++#endif ++ ++#endif ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++static roflash_area fix_roflash_table[]= ++{ ++ { ++ name: "rootfs", ++ size: 0x018E0000, /* rootfs size is 15MB */ ++ offset: 0x00120000, ++ roflash_read: NULL, /* force read-only in cacheable mapping*/ ++ l_x_b: ROFLASH_LINEAR, ++ phys_addr: 0x00000000, ++ },{ ++ name: "NO-USE", /* language package is 2MB */ ++ size: 0x00000000, ++ offset: 0x01A00000, //Susan -- correspond to the beginning of the second flash chip // ++ roflash_read: cfi_intelext_read_roflash, ++ l_x_b: ROFLASH_BLOCK, ++ phys_addr: 0xffffffff, // not use for block cramfs mount ++ },{ ++ name: "setup", /* setup stuff is 1MB */ ++ size: 0x00020000, ++ offset: 0x01FA0000, //Susan -- correspond to the beginning of the second flash chip // ++ roflash_read: cfi_intelext_read_roflash, ++ l_x_b: ROFLASH_BLOCK, ++ phys_addr: 0xffffffff, // not use for block cramfs mount ++ } ++}; ++#endif ++ ++roflash_area *act_roflash_table[MAX_ROFLASH] = {0}; ++unsigned short roflash_partitions = 0; ++ ++/* If we decide to use flash partition parse table, this function will parse the fpt - flash partition table, ++* the beginning address of fpt is defined in CONFIG_FPT_OFFSET. This function will parser out all roflash areas ++* and animation area( or re-fresh code area). ++* For roflash areas, registered them into act_roflash_table, for animation region, register it into mtd_table[6]. ++* Note ++* 6 is fixed for animation region -- /dev/mtd6 c 90 12 ++* /dev/roflash b 62 0 -- root file system ++* /dev/roflash1 b 62 1 -- language package ++* /dev/roflash2 b 62 2 -- setup stuff ++*/ ++int ezx_parse(struct map_info *chip_map) ++{ ++ return 0; // depends on discussion about DC tool ++} ++ ++int ezx_parts_parser(void) ++{ ++ int ret = 0; ++ int nrparts = 0; ++ int i = 0; ++ ++//#ifdef CONFIG_EZX_PARSER_TABLE ++// ret = ezx_parse(chip_map); ++//#else ++ down(&roflash_table_mutex); ++ ++ nrparts = sizeof(fix_roflash_table) / sizeof(roflash_area); ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk("ezx_parts_parser: nrparts is %d\n", nrparts); ++#endif ++ for ( i = 0; i < nrparts; i ++ ) ++ { ++ if (act_roflash_table[i]) ++ return -1; ++ act_roflash_table[i] = (roflash_area *)(&(fix_roflash_table[i])); ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "ezx_parts_parser: act_roflash_table[%d] = %d\n",i,(unsigned long)(act_roflash_table[i])); ++#endif ++ } ++ roflash_partitions = i; ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk("ezx_parts_parser: roflash_partitions is %d\n", roflash_partitions); ++#endif ++ ++ up(&roflash_table_mutex); ++ ++ return ret; ++} ++ ++int ezx_partition_init(void) ++{ ++ int ret = 0; ++ ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "ezx_partition_init: roflash_table_pptr = %d\n",(unsigned long)(act_roflash_table)); ++#endif ++ roflash_table_pptr = (roflash_area **)(act_roflash_table); ++ ++ if ( ret = ezx_parts_parser() ) ++ { ++ printk(KERN_NOTICE "invoke ezx_parts_parser, return %d\n", ret); ++ return -EIO; ++ } ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk("ezx_partition_init: ret of ezx_parts_parser is %d\n", ret); ++#endif ++ ++ if ( ret = roflash_init() ) ++ { ++ printk(KERN_NOTICE "invoke roflash_init, return %d\n", ret); ++ return -EIO; ++ } ++ return 0 ; ++} ++ ++ ++ ++ ++ ++ +diff -Nurd linux-2.6.16.orig/drivers/block/roflash/Kconfig linux-2.6.16/drivers/block/roflash/Kconfig +--- linux-2.6.16.orig/drivers/block/roflash/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/block/roflash/Kconfig 2006-06-03 11:14:56.382317840 +0200 +@@ -0,0 +1,7 @@ ++# ++# Emualting Flash Chip driver configuration ++# ++config ARCH_EZX_ROFLASH ++ tristate 'ROFLASH Device' ++ ++#tristate 'Debug for ROFLASH device?' ROFLASH_DEBUG_ERR +diff -Nurd linux-2.6.16.orig/drivers/block/roflash/Makefile linux-2.6.16/drivers/block/roflash/Makefile +--- linux-2.6.16.orig/drivers/block/roflash/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/block/roflash/Makefile 2006-06-03 11:14:56.383317688 +0200 +@@ -0,0 +1,15 @@ ++# ++# Makefile for VFM ++# ++# 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). ++# ++# Note 2! The CFLAGS definitions are now inherited from the ++# parent makes.. ++ ++# ++# Makefile for the kernel VSB driver. ++# ++ ++obj-$(CONFIG_ARCH_EZX_ROFLASH) += roflash.o ezx_parts.o +diff -Nurd linux-2.6.16.orig/drivers/block/roflash/roflash.c linux-2.6.16/drivers/block/roflash/roflash.c +--- linux-2.6.16.orig/drivers/block/roflash/roflash.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/block/roflash/roflash.c 2006-06-03 11:14:56.384317536 +0200 +@@ -0,0 +1,593 @@ ++/* ++ * Linux Flash read-only block device driver For Cramfs file system, support simultaneous linear + block device mounting. -- Susan Gu Mar, 15 2002 ++ * In order to resolve logo area in cachable flash mapping, add roflash_c_fops methods, that is stolen from mtdchar.c (dwmw2) ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kmod.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/vmalloc.h> ++ ++#include <asm/uaccess.h> ++#include <linux/mtd/map.h> ++#include <linux/ezx_roflash.h> ++ ++#ifdef CONFIG_PROC_FS ++#include <linux/proc_fs.h> /* For /proc/roflash_info */ ++#endif /* CONFIG_PROC_FS */ ++ ++#define MAJOR_NR ROFLASH_MAJOR ++#define DEVICE_NAME "roflash" ++#define DEVICE_REQUEST roflash_request ++#define DEVICE_NR(device) (MINOR(device)) ++#define DEVICE_ON(device) ++#define DEVICE_OFF(device) ++#define DEVICE_NO_RANDOM ++ ++#define MAJOR_NR_C 101 ++#define DEVICE_NAME_C "roflash_c" ++#include <linux/blkdev.h> ++ ++ ++/* K3 flash lowlevel */ ++#define FLASH_WORD_ALIGN_MASK 0xFFFFFFFE ++#define WIDTH_ADJUST 0x0001L /* I.E. Converts 0x90 to 0x90 */ ++#define FlashCommandRead (unsigned short)(0xFF * WIDTH_ADJUST) ++#define FlashCommandStatus (unsigned short)(0x70 * WIDTH_ADJUST) ++#define FlashStatusReady (unsigned short)(0x80 * WIDTH_ADJUST) ++ ++/* Variables used to track operational state of ROFLASH */ ++#define ROFLASH_STATUS_READY 0 ++#define ROFLASH_STATUS_NOT_READY -1 ++#define ROFLASH_BLOCK_SIZE (4096) ++static unsigned long flash_blocksizes[MAX_ROFLASH]; ++static unsigned long flash_sizes[MAX_ROFLASH]; ++ ++#ifdef CONFIG_PROC_FS ++static struct proc_dir_entry *roflash_proc_entry; ++static int roflash_read_procmem(char *, char **, off_t, int, int *, void *); ++#endif /* CONFIG_PROC_FS */ ++ ++ ++extern unsigned short roflash_partitions; ++extern struct map_info bulverde_map; ++extern unsigned long bulverde_map_cacheable; ++ ++static DEFINE_SPINLOCK(roflash_lock); ++static struct request_queue *xd_queue; ++ ++#define __KERNEL_SYSCALLS__ ++#include <linux/unistd.h> ++#include <asm/unaligned.h> ++ ++ ++void fmemoryCopy (void * dest, void * src, unsigned long bytes) ++{ ++ unsigned char *new_dest; ++ unsigned char *new_src; ++ new_dest = (unsigned char *)dest; ++ new_src = (unsigned char *)src; ++ /* while bytes to modify is not complete */ ++ while (bytes-- != 0) ++ { ++ /* update destination byte to equal src byte */ ++ *new_dest = *new_src; ++ new_dest++; ++ new_src++; ++ } ++} ++void memorySet (void * buff, unsigned long bytes, unsigned char value) ++{ ++ unsigned char * new_buff; ++ new_buff = (unsigned char *)buff; ++ /* while not at end of modification */ ++ while (bytes-- != 0) ++ { ++ /* set contents of buffer to value specified */ ++ *new_buff = value; ++ ++ /* increment to next byte */ ++ new_buff++; ++ } ++} ++ ++#if (0) ++unsigned short IntelSCSRead(unsigned long CardAddress, unsigned long Length, unsigned char * Buffer) ++{ ++ unsigned long volatile pointer; ++ unsigned short * volatile pointer0ed; ++ ++#ifdef VFM_DEBUG2 ++ if ( roflash_status == ROFLASH_STATUS_READY ) ++ { ++ printk("IntelSCSRead: PositionPtr(pointer, CardAddress);\n"); ++ printk("IntelSCSRead: pointer=%d, CardAddress=%d\n", (DWORD)pointer, (DWORD)CardAddress); ++ } ++#endif ++ pointer = (unsigned long)(DALHART_K3_BASE_ADDR + CardAddress); ++ ++ pointer0ed = (unsigned short *)((unsigned long)pointer & FLASH_WORD_ALIGN_MASK); ++#ifdef CONFIG_K3_DEBUG ++ printk("IntelSCSRead(): Reading %d bytes at 0x%lx\n",Length, pointer); ++#endif ++ ++ *pointer0ed = FlashCommandRead; /* Ensure it is in read mode */ ++ ++ /* This is assumimg that farmemory copy performs at a byte at a time */ ++ fmemoryCopy(Buffer, pointer, Length); ++ ++ return(0); ++} ++#endif ++ ++void roflash_request(request_queue_t *q) ++{ ++ unsigned short minor; ++ unsigned long offset, len, retlen; ++ unsigned short err = 0; ++ unsigned char *tmpBufPtr; ++ unsigned short nrSectors; ++ struct request *req; ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "Roflash_request(): Entered\n"); ++#endif ++ ++ while ((req = elv_next_request(q)) != NULL) { ++ unsigned block = req->sector; ++ unsigned count = req->nr_sectors; ++ struct gendisk *disk = req->rq_disk; ++ int rw = rq_data_dir(req); ++ ++ if (!(req->flags & REQ_CMD)) { ++ end_request(req, 0); ++ continue; ++ } ++ ++ if (rw != READ) { ++ printk(KERN_ERR "roflash_request(): WARNING! Unknown Request\n"); ++ end_request(req, 0); ++ } ++ ++ /* Verify minor number is in range */ ++ minor = MINOR(req->rq_dev); ++ if (minor >= roflash_partitions) ++ { ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_request(): ERROR! Out of partition range (minor = %d)\n", minor ); ++#endif ++ end_request(req, 0); ++ continue; ++ } ++ ++ /* Check if writting-request is demanded */ ++ if ( req->cmd == WRITE ) ++ { ++ printk(KERN_ERR "roflash_request: write-accessing is not allowed!\n"); ++ end_request(req, 0); ++ break; ++ } ++ ++ /* Verify sector is in range */ ++ offset = req->sector << 9; // 512 bytes per sector ++ len = req->nr_sectors << 9; // 512 bytes per sector ++ if ((offset + len) > (flash_sizes[minor] << BLOCK_SIZE_BITS)) ++ { ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_request(): ERROR! Access beyond end of partition\n" ); ++#endif ++ end_request(req, 0); ++ continue; ++ } ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_request(): minor=%d, %d sectors at sector %ld\n", minor, req->nr_sectors, req->sector); ++#endif ++ ++ /* Prepare to move data to/from the Linux buffer */ ++ nrSectors = req->nr_sectors; ++ tmpBufPtr = req->buffer; ++// blockTempBufPtr = roflashTempBuffer; -- this may cause race-condition in multiple cramfs ++ ++ roflash_area *this_area = NULL; ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_request: READ\n"); ++#endif ++// memorySet(roflashTempBuffer, len, 0x00); -- don't use the internal buffer, may exist race-conditions. ++ ++ this_area = (roflash_area *)(roflash_table_pptr[minor]); ++ err = (*this_area->roflash_read)((void *)(this_area->priv_map),(offset + this_area->offset), len, &retlen, tmpBufPtr); ++ if (err == 0) { ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR " < %x %x %x %x ...>\n",req->buffer[0],req->buffer[1],req->buffer[2],req->buffer[3]); ++#endif ++ end_request(req, 1); ++ } else { ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_request(): ERROR READ %d sectors at sector %d\n", req->nr_sectors, req->sector); ++#endif ++ end_request(req, 0); ++ } ++ } ++} ++ ++static int roflash_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++// What is the requirements? -- todo list ++ return 0; ++} ++ ++ ++static int roflash_open(struct inode * inode, struct file * filp) ++{ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_open() called, minor = %d\n", DEVICE_NR(inode->i_rdev)); ++#endif ++ if (DEVICE_NR(inode->i_rdev) >= roflash_partitions) ++ { ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "vfm_open() Failed!\n"); ++#endif ++ return -ENXIO; ++ } ++ return 0; ++} ++ ++static int roflash_release(struct inode * inode, struct file * filp) ++{ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_release() called\n"); ++#endif ++ return 0; ++} ++ ++ ++/*Susan 2.4.6 */ ++static struct block_device_operations roflash_fops = { ++ open: roflash_open, ++ release: roflash_release, ++ ioctl: roflash_ioctl, ++}; ++ ++static loff_t roflash_c_lseek (struct file *file, loff_t offset, int orig) ++{ ++ roflash_area *dev_def = (roflash_area *)(file->private_data); ++ ++ switch (orig) { ++ case 0: ++ /* SEEK_SET */ ++ file->f_pos = offset; ++ break; ++ case 1: ++ /* SEEK_CUR */ ++ file->f_pos += offset; ++ break; ++ case 2: ++ /* SEEK_END */ ++ file->f_pos = (unsigned long)(dev_def->size + offset); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (file->f_pos < 0) ++ file->f_pos = 0; ++ else if (file->f_pos >= dev_def->size) ++ file->f_pos = dev_def->size - 1; ++ ++ return file->f_pos; ++} ++ ++static int roflash_c_open(struct inode *inode, struct file *file) ++{ ++ int minor = MINOR(inode->i_rdev); ++ roflash_area *dev_def; ++ ++ if (minor >= MAX_ROFLASH) ++ return -EACCES; ++ ++ dev_def = (roflash_area *)(roflash_table_pptr[minor]); ++ ++ /* Sanity check */ ++ if (dev_def->l_x_b != ROFLASH_CHAR) ++ return -EACCES; ++ ++ /* You can't open the RO devices RW */ ++ if (file->f_mode & 2) ++ return -EACCES; ++ ++ file->private_data = dev_def; ++ ++ return 0; ++} /* mtd_open */ ++ ++static int roflash_c_close(struct inode *inode, struct file *file) ++{ ++ return 0; ++} /* mtd_close */ ++ ++/* FIXME: This _really_ needs to die. In 2.5, we should lock the ++ userspace buffer down and use it directly with readv/writev. ++*/ ++#define MAX_KMALLOC_SIZE 0x20000 ++ ++static int roflash_c_read(struct file *file, char *buf, size_t count,loff_t *ppos) ++{ ++ roflash_area *dev_def = (roflash_area *)file->private_data; ++ size_t retlen=0; ++ size_t total_retlen=0; ++ int ret=0; ++ int len; ++ char *kbuf; ++ unsigned long virt_dev_start = 0; ++ ++ if (*ppos + count > dev_def->size) ++ count = dev_def->size - *ppos; ++ ++ if (!count) ++ return 0; ++ ++ /* FIXME: Use kiovec in 2.5 to lock down the user's buffers ++ and pass them directly to the MTD functions */ ++ while (count) ++ { ++ if (count > MAX_KMALLOC_SIZE) ++ len = MAX_KMALLOC_SIZE; ++ else ++ len = count; ++ ++ kbuf=kmalloc(len,GFP_KERNEL); ++ if (!kbuf) ++ return -ENOMEM; ++ ++ //ret = (dev_def->roflash_read)( (void *)(dev_def->priv_map),(*ppos + dev_def->offset), len, &retlen, kbuf); ++ virt_dev_start = (unsigned long)(dev_def->priv_map) + dev_def->offset; ++ memcpy(kbuf,virt_dev_start + *ppos,len); ++ ++ *ppos += len; ++ if (copy_to_user(buf, kbuf, len)) ++ { ++ kfree(kbuf); ++ return -EFAULT; ++ } ++ else ++ total_retlen += len; ++ ++ count -= len; ++ buf += len; ++ ++ ++ kfree(kbuf); ++ } ++ ++ return total_retlen; ++} /* mtd_read */ ++ ++ ++static struct file_operations roflash_c_fops = { ++ owner: THIS_MODULE, ++ llseek: roflash_c_lseek, /* lseek */ ++ read: roflash_c_read, /* read */ ++ open: roflash_c_open, /* open */ ++ release: roflash_c_close, /* release */ ++}; ++ ++roflash_area *roflash_get_dev(unsigned char minor) ++{ ++ roflash_area *ret = NULL; ++ ++ if (minor < MAX_ROFLASH) ++ ret = (roflash_area *)(roflash_table_pptr[minor]); ++ ++ return ret; ++} ++ ++int __init roflash_init(void) ++{ ++ int i, size = 0; ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): Enter into this API.\n"); ++#endif ++ ++/* We should do initialization for flash chips, however, we don't need to do it ++ * twice after __init_lubbock has initialized K3 flash device */ ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init: Registering device major %d [%s]\n",ROFLASH_MAJOR,DEVICE_NAME); ++#endif ++ ++ if (register_blkdev(ROFLASH_MAJOR, DEVICE_NAME)) { ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): Could not get major %d", ROFLASH_MAJOR); ++#endif ++ return -EIO; ++ } ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): register_blkdev success\n"); ++#endif ++ ++ roflash_queue = blk_init_queue(&roflash_request, &roflash_lock); ++ if (!roflash_queue) ++ return -ENOMEM; ++ ++ struct gendisk *disk = alloc_disk(64); ++ if (!disk) ++ return -ENOMEM; ++ ++ disk->major = ROFLASH_MAJOR; ++ disk->first_minor = 0; ++ sprintf(disk->disk_name, "roflash0"); ++ sprintf(disk->devfs_name, "roflash/target0"); ++ disk->fops = &roflash_fops; ++ disk->queue = roflash_queue; ++ // set_capacity(disk, ); ++ ++ add_disk(disk); ++ ++ ++ /* We know this is invoked only once during kernel booting up, so there ++ * is not race-conditions */ ++ for (i = 0; i < roflash_partitions; i++) { ++ unsigned short lxb_flag = ((roflash_area *)(roflash_table_pptr[i]))->l_x_b; ++ ++ switch (lxb_flag) { ++ case ROFLASH_LINEAR: ++ case ROFLASH_LINEAR_XIP: ++ flash_blocksizes[i] = ROFLASH_BLOCK_SIZE; ++ size = ((roflash_area *)(roflash_table_pptr[i]))->size; ++ flash_sizes[i] = size >> BLOCK_SIZE_BITS ; ++ // The virtual address of the cacheable mapping // ++ ((roflash_area *)(roflash_table_pptr[i]))->priv_map = ++ (void *)(bulverde_map_cacheable); ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): not-char " ++ "roflash_table_pptr[%d]->size = %d\n",i,size); ++#endif ++ break; ++ case ROFLASH_BLOCK: ++ if (bulverde_map.size == 0) { ++ unregister_blkdev(ROFLASH_MAJOR, DEVICE_NAME); ++ return -EACCES; ++ } ++ ++ flash_blocksizes[i] = ROFLASH_BLOCK_SIZE; ++ size = ((roflash_area *)(roflash_table_pptr[i]))->size; ++ flash_sizes[i] = size >> BLOCK_SIZE_BITS ; ++ //The pointer to struct map_info of the noncacheable mapping // ++ ((roflash_area *)(roflash_table_pptr[i]))->priv_map = ++ (void *)(&bulverde_map); ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): not-char roflash_table_pptr[%d]->size = %d\n",i,size); ++#endif ++ break; ++ case ROFLASH_CHAR: ++ if (register_chrdev(MAJOR_NR_C, DEVICE_NAME_C, &roflash_c_fops)) { ++ printk(KERN_NOTICE "Can't allocate major number %d for " ++ "Memory Technology Devices.\n", MAJOR_NR_C); ++ ++ unregister_blkdev(ROFLASH_MAJOR, DEVICE_NAME); ++ return -EAGAIN; ++ } ++ //The virtual address of the cacheable mapping // ++ ((roflash_area *)(roflash_table_pptr[i]))->priv_map = ++ (void *)(bulverde_map_cacheable); ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): char roflash_table_pptr[%d]->size " ++ "= %d\n",i,size); ++#endif ++ break; ++ } ++ } ++ ++ blksize_size[ROFLASH_MAJOR] = flash_blocksizes; ++ blk_size[ROFLASH_MAJOR] = flash_sizes; ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): fill in blksize_size[] and blk_size[] " ++ "success\n"); ++#endif ++ //blk_init_queue(BLK_DEFAULT_QUEUE(ROFLASH_MAJOR),&roflash_request); ++ roflash_queue = blk_init_queue(&roflash_request, &roflash_lock); ++ if (!roflash_queue) ++ return -ENOMEM; ++ ++#ifdef ROFLASH_DEBUG_ERR ++ printk(KERN_ERR "roflash_init(): ROFLASH Block device: blksize_size = %d" ++ ", blk_size = %d\n",flash_blocksizes[0],flash_sizes[0]); ++#endif ++ ++#ifdef CONFIG_PROC_FS ++ /* register procfs device */ ++ if (roflash_proc_entry = create_proc_entry("roflash_info", 0, 0)) { ++ roflash_proc_entry->read_proc = roflash_read_procmem; ++ } ++ ++#endif /* CONFIG_PROC_FS */ ++ ++ for ( i = 0; i < roflash_partitions; i ++ ) { ++ printk(KERN_NOTICE "ROFLASH Driver initialized and ready for use." ++ "Size: %d Offset: %d\n", ++ ((roflash_area*)(roflash_table_pptr[i]))->size, ++ ((roflash_area*)(roflash_table_pptr[i]))->offset); ++ } ++ ++ return (0); ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++static int roflash_read_procmem(char *buf, char **start, off_t offset, int len, ++ int *eof, void *data) ++{ ++ #define LIMIT (PAGE_SIZE-80) /* don't print anymore after this size */ ++ ++ int i; ++ ++ len=0; ++ ++#if (0) ++ switch (roflash_status) ++ { ++ case ROFLASH_STATUS_NOT_READY: ++ strcpy(roflash_status_str,"Not-ready"); ++ break; ++ case ROFLASH_STATUS_READY: ++ strcpy(roflash_status_str,"Ready"); ++ break; ++ default: ++ strcpy(roflash_status_str,"Unknown!"); ++ break; ++ } ++#endif ++ ++ len += sprintf(buf+len, "ROFLASH Driver status: %s\n\n","Ready"); ++ for ( i = 0; i < roflash_partitions; i ++ ) ++ { ++ len += sprintf(buf+len, "ROFLASH area name is %s\n",((roflash_area*)(roflash_table_pptr[i]))->name); ++ len += sprintf(buf+len, "ROFLASH area size = %d bytes\n",((roflash_area*)(roflash_table_pptr[i]))->size); ++ len += sprintf(buf+len, "ROFLASH area offset = %ld bytes\n",((roflash_area*)(roflash_table_pptr[i]))->offset); ++ len += sprintf(buf+len, "ROFLASH area l_x_b(%x)\n",((roflash_area*)(roflash_table_pptr[i]))->l_x_b); ++ } ++ return len; ++} ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef MODULE ++static void __exit roflash_cleanup(void) //Susan// ++{ ++ int i; ++ int err_info = 0; ++ ++ /* For read-only flash device, we don't need to invoke fsync_dev */ ++ ++ unregister_blkdev(ROFLASH_MAJOR, DEVICE_NAME); ++ blk_cleanup_queue(BLK_DEFAULT_QUEUE(ROFLASH_MAJOR)); ++ blk_size[ROFLASH_MAJOR] = NULL; ++ blksize_size[ROFLASH_MAJOR] = NULL; ++ ++ /* For roflash char device -- sometimes, we don't have char roflash devices */ ++ for (i = 0; i < roflash_partitions; i++) ++ { ++ unsigned short lxb_flag = ((roflash_area *)(roflash_table_pptr[i]))->l_x_b; ++ ++ if (lxb_flag == ROFLASH_CHAR) ++ { ++ unregister_chrdev(MAJOR_NR_C, DEVICE_NAME_C); ++ break; ++ } ++ } ++ ++ remove_proc_entry("roflash_info",NULL); ++ ++ printk(KERN_ERR "remove roflash_info\n"); ++ ++} ++ ++module_init(roflash_init); ++module_exit(roflash_cleanup); ++ ++#endif +diff -Nurd linux-2.6.16.orig/drivers/char/agp/efficeon-agp.c linux-2.6.16/drivers/char/agp/efficeon-agp.c +--- linux-2.6.16.orig/drivers/char/agp/efficeon-agp.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/agp/efficeon-agp.c 2006-06-03 11:14:55.266487472 +0200 +@@ -64,6 +64,12 @@ + {.mask = 0x00000001, .type = 0} + }; + ++/* This function does the same thing as mask_memory() for this chipset... */ ++static inline unsigned long efficeon_mask_memory(unsigned long addr) ++{ ++ return addr | 0x00000001; ++} ++ + static struct aper_size_info_lvl2 efficeon_generic_sizes[4] = + { + {256, 65536, 0}, +@@ -251,7 +257,7 @@ + last_page = NULL; + for (i = 0; i < count; i++) { + int index = pg_start + i; +- unsigned long insert = mem->memory[i]; ++ unsigned long insert = efficeon_mask_memory(mem->memory[i]); + + page = (unsigned int *) efficeon_private.l1_table[index >> 10]; + +diff -Nurd linux-2.6.16.orig/drivers/char/cs5535_gpio.c linux-2.6.16/drivers/char/cs5535_gpio.c +--- linux-2.6.16.orig/drivers/char/cs5535_gpio.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/cs5535_gpio.c 2006-06-03 11:14:55.266487472 +0200 +@@ -241,9 +241,10 @@ + static void __exit cs5535_gpio_cleanup(void) + { + dev_t dev_id = MKDEV(major, 0); ++ ++ cdev_del(&cs5535_gpio_cdev); + unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT); +- if (gpio_base != 0) +- release_region(gpio_base, CS5535_GPIO_SIZE); ++ release_region(gpio_base, CS5535_GPIO_SIZE); + } + + module_init(cs5535_gpio_init); +diff -Nurd linux-2.6.16.orig/drivers/char/gpio_test.c linux-2.6.16/drivers/char/gpio_test.c +--- linux-2.6.16.orig/drivers/char/gpio_test.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/char/gpio_test.c 2006-06-03 11:14:56.295331064 +0200 +@@ -0,0 +1,216 @@ ++/* ++ * linux/drivers/char/gpio_test.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Jay Jia ++ * Created: April 25, 2004 ++ * Copyright: Motorola 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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/kdev_t.h> ++#include <linux/fs.h> ++#include <linux/wrapper.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <asm/arch/ezx.h> ++#include "../misc/ssp_pcap.h" ++ ++ ++#define SUCCESS 0 ++#define DEVICE_NAME "gpio_test" ++#define GPIO_TEST_IOCTL_CMD_OPS_MASK 0x000F ++#define GPIO_TEST_IOCTL_CMD_VAL_MASK 0x0080 ++#define GPIO_TEST_IOCTL_CMD_NUM_MASK 0xFF00 ++#define GPIO_TEST_IOCTL_CMD_VAL_SHIFT 7 ++#define GPIO_TEST_IOCTL_CMD_NUM_SHIFT 8 ++ ++static int Major=127; ++static unsigned char pcap_usb_ps = 0; ++static unsigned char pcap_vusb_en = 0; ++static unsigned char pcap_ov_test_on = 0; ++ ++static int gpio_test_open(struct inode *inode,struct file *file) ++{ ++ MOD_INC_USE_COUNT; ++ return SUCCESS; ++} ++ ++static int gpio_test_release(struct inode *inode,struct file *file) ++ ++{ ++ MOD_DEC_USE_COUNT; ++ return SUCCESS; ++} ++ ++ ++/******************************************************************************* ++Function Name: gpio_test_ioctl ++ ++Parameter: ++ The ioctl() accept a 2-byte command : cmd ++ Use this param as follows: ++ ++ bit 0 - 3: operation type. ++ 0x01, gpio read ++ 0x02, gpio write ++ 0x03, gpio config ++ 0x04, PCAP test ++ bit 4 -6: ++ reserved. keep ZERO ++ bit 7: ++ For gpio, write/config value. ++ For Over voltage test, ++ 0, ON ++ 1, OFF ++ bit 8 - 15: ++ For gpio, it is gpio pin number ++ For PCAP test, ++ 0x01, Over voltage test. ++ others, reserved. ++ ++Return Value: ++ For Over voltage test, ++ return 0 for success. ++ return 1 for error. ++*******************************************************************************/ ++static int gpio_test_ioctl(struct inode *inode,struct file *file,unsigned short cmd,unsigned long arg) ++{ ++ int num, val, ops, ret; ++ ++ ret = 0; ++ num = (cmd & GPIO_TEST_IOCTL_CMD_NUM_MASK) >> GPIO_TEST_IOCTL_CMD_NUM_SHIFT; ++ val = cmd & GPIO_TEST_IOCTL_CMD_VAL_MASK; ++ ops = cmd & GPIO_TEST_IOCTL_CMD_OPS_MASK; ++ ++ if(ops == 1)/*read gpio*/ ++ { ++// set_GPIO_mode(num); ++// GPDR(num) &= ~GPIO_bit(num); ++ ret = GPLR(num) & GPIO_bit(num); ++// printk("in GPIO kernel read function, num = %d and ret = %d\n",num,ret); ++ return (ret == 0) ? 0:1; ++ } ++ ++ if(ops == 2)/*write gpio*/ ++ { ++// set_GPIO_mode(num); ++// GPDR(num) |= GPIO_bit(num); ++ if( val ) ++ GPSR(num) = GPIO_bit(num); ++ else ++ GPCR(num) = GPIO_bit(num); ++ return 2; ++ } ++ ++ if(ops == 3)/*set gpio*/ ++ { ++ set_GPIO_mode(num); ++ if( val ) ++ GPDR(num) |= GPIO_bit(num); ++ else ++ GPDR(num) &= ~GPIO_bit(num); ++ return 3; ++ } ++ ++ if(ops == 4)/* PCAP test */ ++ { ++ printk("PCAP test, cmd = 0x%x.\n", cmd); ++ val = val >> GPIO_TEST_IOCTL_CMD_VAL_SHIFT; ++ switch(num) ++ { ++ case 1: /* Over Voltage test */ ++ if(val == 0) /* ON */ ++ { ++ printk("Over Voltage test ON.\n"); ++ /* backup USB_PS and VUSB_EN */ ++ pcap_ov_test_on = 1; ++ pcap_usb_ps = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); ++ pcap_vusb_en = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ /* USB_PS = 0, PCAP USB powered by VUSB_IN */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); ++ /* VUSB_EN = 1, USB tranceiver enabled */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ /* USB 1V INT mask */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM); ++ /* USB 4V INT mask */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM); ++ ret = 0; ++ } ++ else if(val == 1) /* OFF */ ++ { ++ printk("Over Voltage test OFF.\n"); ++ if(pcap_ov_test_on != 1) ++ { ++ ret = 1; /* return error */ ++ break; ++ } ++ /* restore USB_PS and VUSB_EN */ ++ if(pcap_usb_ps) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); ++ } ++ else ++ { ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); ++ } ++ if(pcap_vusb_en) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ } ++ else ++ { ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ } ++ pcap_ov_test_on = 0; ++ /* USB 1V INT unmask */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI); /* clear 1V INT status */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB1VM); ++ /* USB 4V INT unmask */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI); /* clear 4V INT status */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB4VM); ++ ret = 0; ++ } ++ else /* Unrecongized command */ ++ { ++ ret = 1; ++ } ++ break; ++ default: ++ ret = 1; ++ } ++ return ret; ++ } /* end of PCAP test */ ++} ++ ++static struct file_operations gpio_test_fops={ ++ ioctl: gpio_test_ioctl, ++ open: gpio_test_open, ++ release:gpio_test_release, ++}; ++ ++int gpio_test_init_module() ++{ ++ register_chrdev(Major, DEVICE_NAME, &gpio_test_fops); ++ return 0; ++} ++ ++void gpio_test_cleanup_module() ++{ ++ unregister_chrdev(Major,DEVICE_NAME); ++} ++ ++module_init(gpio_test_init_module); ++module_exit(gpio_test_cleanup_module); ++MODULE_AUTHOR("Jay Jia"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/char/ipmi/ipmi_bt_sm.c linux-2.6.16/drivers/char/ipmi/ipmi_bt_sm.c +--- linux-2.6.16.orig/drivers/char/ipmi/ipmi_bt_sm.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/ipmi/ipmi_bt_sm.c 2006-06-03 11:14:55.267487320 +0200 +@@ -165,7 +165,7 @@ + { + unsigned int i; + +- if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) ++ if ((size < 2) || (size > (IPMI_MAX_MSG_LENGTH - 2))) + return -1; + + if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) +diff -Nurd linux-2.6.16.orig/drivers/char/Kconfig linux-2.6.16/drivers/char/Kconfig +--- linux-2.6.16.orig/drivers/char/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/Kconfig 2006-06-03 11:14:56.753261448 +0200 +@@ -187,6 +187,7 @@ + config ISI + tristate "Multi-Tech multiport card support (EXPERIMENTAL)" + depends on SERIAL_NONSTANDARD ++ select FW_LOADER + help + This is a driver for the Multi-Tech cards which provide several + serial ports. The driver is experimental and can currently only be +@@ -695,7 +696,7 @@ + + config RTC + tristate "Enhanced Real Time Clock Support" +- depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV ++ depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARCH_PXA + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you +@@ -741,6 +742,19 @@ + via the file /proc/rtc and its behaviour is set by various ioctls on + /dev/rtc. + ++config SA1100_RTC ++ bool "SA11x0/PXA2xx RTC support" ++ depends on ARCH_SA1100 || ARCH_PXA ++ help ++ If you say Y here and create a character special file /dev/rtc with ++ major number 10 and minor number 135 using mknod ("man mknod"), you ++ will get access to the real time clock built into your SA11x0 or ++ PXA2xx CPU. It reports status information via the file /proc/rtc ++ and its behaviour is set by various ioctls on /dev/rtc. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called sa1100-rtc. ++ + config GEN_RTC + tristate "Generic /dev/rtc emulation" + depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV +@@ -1006,6 +1020,16 @@ + The mmtimer device allows direct userspace access to the + Altix system timer. + ++config LINUX_LED ++ tristate "LED support" ++ ++config PXA_E680_LED ++ tristate "E680 LED suppory" ++ depends on LINUX_LED ++ ++config BULVERDE_SRAM_DEV ++ tristate "BULVERDE Internal SRAM char device" ++ + source "drivers/char/tpm/Kconfig" + + config TELCLOCK +diff -Nurd linux-2.6.16.orig/drivers/char/led.c linux-2.6.16/drivers/char/led.c +--- linux-2.6.16.orig/drivers/char/led.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/char/led.c 2006-06-03 11:14:56.296330912 +0200 +@@ -0,0 +1,318 @@ ++/* ++ * Device driver for controlling LEDs. See linux/led.h for info on ++ * how to use this. ++ * ++ * This currently only supports mono and bicolor LEDs, but support for ++ * fancier LEDs (scrolling text or numeric LEDs, for instance) could ++ * easily be added. ++ * ++ * Corey Minyard <minyard@mvista.com> ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/miscdevice.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <linux/init.h> ++#include <linux/led.h> ++#include <linux/string.h> ++#include <linux/spinlock.h> ++ ++#define VERSION "1.0" ++ ++/* A lock that is held when manipulating LED info. */ ++static spinlock_t led_lock = SPIN_LOCK_UNLOCKED; ++ ++/* A linked list of all the LEDs registered. */ ++static struct led_reg_info *leds; ++ ++/* Register a new LED with the driver. */ ++int register_led_info(struct led_reg_info *info) ++{ ++ struct led_reg_info *led; ++ int rv = 0; ++ ++ spin_lock(&led_lock); ++ info->next = NULL; ++ led = leds; ++ if (led == NULL) ++ { ++ leds = info; ++ } ++ else ++ { ++ while (led->next != NULL) ++ { ++ if (strcmp(led->info->name, info->info->name) == 0) ++ { ++ /* Registering a duplicate. */ ++ rv = -1; ++ goto out; ++ } ++ led = led->next; ++ } ++ led->next = info; ++ } ++ MOD_INC_USE_COUNT; ++ ++out: ++ spin_unlock(&led_lock); ++ ++ return rv; ++} ++ ++/* Unregister an LED from the driver. */ ++int unregister_led_info(struct led_reg_info *info) ++{ ++ int rv = -1; ++ struct led_reg_info *led; ++ ++ if (info == NULL) ++ { ++ return -1; ++ } ++ ++ spin_lock(&led_lock); ++ led = leds; ++ if (led == info) ++ { ++ MOD_DEC_USE_COUNT; ++ leds = leds->next; ++ } ++ else ++ { ++ while (led->next != NULL) ++ { ++ if (led->next == info) ++ { ++ MOD_DEC_USE_COUNT; ++ led->next = info->next; ++ rv = 0; ++ goto out; ++ } ++ led = led->next; ++ } ++ } ++out: ++ spin_unlock(&led_lock); ++ return rv; ++} ++ ++/* Return the number of LEDs registered. */ ++static int count_leds(void) ++{ ++ struct led_reg_info *led; ++ int count = 0; ++ ++ spin_lock(&led_lock); ++ led = leds; ++ while (led != NULL) ++ { ++ count = count + 1; ++ led = led->next; ++ } ++ spin_unlock(&led_lock); ++ ++ return count; ++} ++ ++/* Find an LED by its number. Must be called with the led spin lock ++ held. */ ++static struct led_reg_info *get_led_by_num(int num) ++{ ++ struct led_reg_info *led; ++ int count = num; ++ ++ led = leds; ++ while (led != NULL) ++ { ++ if (count == 0) ++ { ++ led->info->led_num = num; ++ return led; ++ } ++ count = count - 1; ++ led = led->next; ++ } ++ ++ return NULL; ++} ++ ++/* Find an LED by its name. Must be called with the led spin lock ++ held. */ ++static struct led_reg_info *get_led_by_name(char *name) ++{ ++ struct led_reg_info *led; ++ int count = 0; ++ ++ led = leds; ++ while (led != NULL) ++ { ++ if (strcmp(name, led->info->name) == 0) ++ { ++ led->info->led_num = count; ++ return led; ++ } ++ count++; ++ led = led->next; ++ } ++ ++ return NULL; ++} ++ ++/* The IOCTL handler for the LED driver. */ ++static int led_ioctl(struct inode *inode, ++ struct file *file, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ int i; ++ struct led_reg_info *led; ++ struct led_info info; ++ struct led_op op; ++ ++ switch(cmd) ++ { ++ case LEDIOC_GETCOUNT: ++ return count_leds(); ++ ++ case LEDIOC_GETINFO_BY_NUM: ++ case LEDIOC_GETINFO_BY_NAME: ++ i = copy_from_user(&info, (void*)arg, sizeof(info)); ++ if (i) ++ { ++ return -EFAULT; ++ } ++ ++ spin_lock(&led_lock); ++ if (cmd == LEDIOC_GETINFO_BY_NUM) ++ led = get_led_by_num(info.led_num); ++ else ++ led = get_led_by_name(info.name); ++ if (led == NULL) ++ { ++ spin_unlock(&led_lock); ++ return -EINVAL; ++ } ++ ++ info.type = led->info->type; ++ info.led_num = led->info->led_num; ++ strcpy(info.name, led->info->name); ++ info.info = led->info->info; ++ i = copy_to_user((void *)arg, &info, sizeof(info)); ++ ++ spin_unlock(&led_lock); ++ ++ if (i) ++ { ++ return -EFAULT; ++ } ++ return 0; ++ ++ case LEDIOC_OP: ++ i = copy_from_user(&op, (void*)arg, sizeof(op)); ++ if (i) ++ { ++ return -EFAULT; ++ } ++ ++ spin_lock(&led_lock); ++ led = get_led_by_name(op.name); ++ if (led == NULL) ++ { ++ spin_unlock(&led_lock); ++ return -EINVAL; ++ } ++ ++ i = led->handle_led_op(led, &op); ++ if (!i) ++ { ++ i = copy_to_user((void *)arg, &op, sizeof(op)); ++ if (i) ++ { ++ i = -EFAULT; ++ } ++ } ++ spin_unlock(&led_lock); ++ ++ return i; ++ ++ default: ++ return -ENOIOCTLCMD; ++ } ++} ++ ++/* Not much to do for opening. */ ++static int led_open(struct inode *inode, struct file *file) ++{ ++ switch(MINOR(inode->i_rdev)) ++ { ++ case LED_MINOR: ++ return 0; ++ ++ default: ++ return -ENODEV; ++ } ++} ++ ++/* Closing is really easy. */ ++static int led_close(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++ ++static struct file_operations led_fops = { ++ owner: THIS_MODULE, ++ llseek: NULL, ++ read: NULL, ++ write: NULL, ++ ioctl: led_ioctl, ++ open: led_open, ++ release: led_close, ++}; ++ ++static struct miscdevice led_miscdev= ++{ ++ LED_MINOR, ++ "led", ++ &led_fops ++}; ++ ++ ++/* Remove the LED driver. */ ++static void __exit led_exit(void) ++{ ++ misc_deregister(&led_miscdev); ++} ++ ++/* Set up the LED device driver. */ ++static int __init led_init(void) ++{ ++ int ret; ++ ++ printk("generic LED driver: v%s Corey Minyard (minyard@mvista.com)\n", ++ VERSION); ++ ++ leds = NULL; ++ ret = misc_register(&led_miscdev); ++ if (ret) { ++ printk(KERN_ERR "led: can't misc_register on minor=%d\n", ++ LED_MINOR); ++ return -1; ++ } ++ return 0; ++} ++ ++module_init(led_init); ++module_exit(led_exit); ++ ++EXPORT_SYMBOL(register_led_info); ++EXPORT_SYMBOL(unregister_led_info); ++ ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/char/led_pxa_e680.c linux-2.6.16/drivers/char/led_pxa_e680.c +--- linux-2.6.16.orig/drivers/char/led_pxa_e680.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/char/led_pxa_e680.c 2006-06-03 11:14:56.297330760 +0200 +@@ -0,0 +1,596 @@ ++/*-------------------------------------------------------------------------------------------- ++// Module Name: led_pxa_e680.c ++// ++// General Description: This is the driver for E680 LED. ++//--------------------------------------------------------------------------------------------- ++// Motorola Confidential Proprietary ++// (c) Copyright Motorola 2003-2004, All Rights Reserved ++// ++// ++// Revision History: ++// Modification Tracking ++// Author (core ID) Date Number Description of Changes ++// ------------------------- ------------ ---------- ---------------------------- ++// Liu weijie (A19553) 11/01/2003 LIBdd43835 Init create ++// Wang Jamshid(a5036c) 04/29/2004 LIBee01180 fix bug,register pm call back ++*/ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <asm/errno.h> ++#include <linux/init.h> ++#include <linux/led_pxa_e680.h> ++#include <linux/pm.h> ++#include "../misc/ssp_pcap.h" ++ ++#ifdef CONFIG_E680_P4A ++#define IND_CNTL_R_BUL 79 ++#define IND_CNTL_G_BUL 18 ++#else ++#define IND_CNTL_R_BUL 46 ++#define IND_CNTL_G_BUL 47 ++#endif ++ ++#define SSP_PCAP_LED_MASK 0x000fffe0 ++#define SSP_PCAP_LED_SHIFT 5 ++ ++#define VERSION "1.0" ++ ++//#define DEBUG_LED_DRIVER ++ ++#ifdef DEBUG_LED_DRIVER ++#define PRINTK(s...) printk(s) ++#else ++#define PRINTK(s...) ++#endif ++typedef struct ++{ ++ unsigned char ind_GPIO_red; /*Indicator Red control GPIO 79: 0 active, 1 disactive*/ ++ unsigned char ind_GPIO_green; /*Indicator Green control GPIO 18: 0 active, 1 disactive*/ ++ unsigned char pcap_LEDR_en; /*pcap LEDR_EN bit value: 1 =Red LED(&Green) ++ sink circuit enabled*/ ++ unsigned char pcap_LEDG_en; /*pcap LEDG_EN bit value:1 =Green(->Blue)LED ++ sink circuit enabled*/ ++ unsigned char pcap_LEDR_CTRL; /* 4bits Sets the timing for the red(&Green) LED ++ sink circuit*/ ++ unsigned char pcap_LEDG_CTRL; /* 4bits Sets the timing for the GREEN (->Blue) LED ++ sink circuit*/ ++ unsigned char pcap_LEDR_I; /* 2 bits 00 3mA,01 4mA, 10 5mA, 11 9mA */ ++ /* sets the pulsed current level for LEDR*/ ++ unsigned char pcap_LEDG_I; ++ unsigned char pcap_SKIP_on; /*1=The ON timing sequence defined by LEDx_CTRL ++ is executed on every other cycle*/ ++}PCAP2_LED_REGISTER_VALUE; ++ ++const PCAP2_LED_REGISTER_VALUE led_register_value [LED_BOTTOM_STATE +1 ]= ++{ ++ {0x1,0x1, 0x0,0x0, 0x0,0x0, 0x0,0x0,0x0}, /*LED_OFF*/ ++ ++ /*Always On*/ ++ {0x0,0x1, 0x1,0x0, 0xc,0x0, 0x1,0x0,0x0}, /*LED_RED_ALWAYS_ON,skip off*/ ++ {0x1,0x0, 0x1,0x0, 0xc,0x0, 0x1,0x0,0x0}, /*LED_GREEN_ALWAYS_ON*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0xc, 0x0,0x0,0x0}, /*LED_BLUE_ALWAYS_ON*/ ++ {0x0,0x1, 0x1,0x1, 0xc,0xc, 0x1,0x0,0x0}, /*LED_LIGHT_RED_ALWAYS_ON*/ ++ {0x0,0x0, 0x1,0x0, 0xc,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_ALWAYS_ON*/ ++ {0x1,0x0, 0x1,0x1, 0xc,0xc, 0x1,0x0,0x0}, /*LED_LIGHT_BLUE_ALWAYS_ON*/ ++ {0x0,0x0, 0x1,0x1, 0xc,0xc, 0x1,0x0,0x0}, /*LED_WHITE_ALWAYS_ON*/ ++ ++ /* RED 5 mA current Skip OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x0}, /*LED_RED_01_ON_19_OFF,skip off*/ ++ {0x0,0x1, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x0}, /*LED_RED_02_ON_18_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x0}, /*LED_RED_05_ON_15_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x0}, /*LED_RED_025_ON_075_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x0}, /*LED_RED_025_ON_175_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x0}, /*LED_RED_005_ON_195_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x0}, /*LED_RED_05_ON_05_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x0}, /*LED_RED_05_OFF_05_ON*/ ++ {0x0,0x1, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x0}, /*LED_RED_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x0}, /*LED_RED_0125_ON_2075_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x0}, /*LED_RED_0625_OFF_0075_ON_15_OFF*/ ++ ++ /* RED Skip ON*/ ++ {0x0,0x1, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x1}, /*LED_RED_01_ON_19_OFF,skip On*/ ++ {0x0,0x1, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x1}, /*LED_RED_02_ON_18_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x1}, /*LED_RED_05_ON_15_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x1}, /*LED_RED_025_ON_075_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x1}, /*LED_RED_025_ON_175_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x1}, /*LED_RED_005_ON_195_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x1}, /*LED_RED_05_ON_05_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x1}, /*LED_RED_05_OFF_05_ON*/ ++ {0x0,0x1, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x1}, /*LED_RED_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x1}, /*LED_RED_0125_ON_2075_OFF*/ ++ {0x0,0x1, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x1}, /*LED_RED_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*GREEN Skip OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x0}, /*LED_GREEN_01_ON_19_OFF,skip off*/ ++ {0x1,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x0}, /*LED_GREEN_02_ON_18_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x0}, /*LED_GREEN_05_ON_15_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x0}, /*LED_GREEN_025_ON_075_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x0}, /*LED_GREEN_025_ON_175_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x0}, /*LED_GREEN_005_ON_195_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x0}, /*LED_GREEN_05_ON_05_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x0}, /*LED_GREEN_05_OFF_05_ON*/ ++ {0x1,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x0}, /*LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x0}, /*LED_GREEN_0125_ON_2075_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x0}, /*LED_GREEN_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*GREEN Skip ON*/ ++ {0x1,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x1}, /*LED_GREEN_01_ON_19_OFF,skip On*/ ++ {0x1,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x1}, /*LED_GREEN_02_ON_18_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x1}, /*LED_GREEN_05_ON_15_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x1}, /*LED_GREEN_025_ON_075_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x1}, /*LED_GREEN_025_ON_175_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x1}, /*LED_GREEN_005_ON_195_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x1}, /*LED_GREEN_05_ON_05_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x1}, /*LED_GREEN_05_OFF_05_ON*/ ++ {0x1,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x1}, /*LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x1}, /*LED_GREEN_0125_ON_2075_OFF*/ ++ {0x1,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x1}, /*LED_GREEN_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*BLUE 5 mA Current Skip OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x1, 0x0,0x0,0x0}, /*LED_BLUE_01_ON_19_OFF,skip off*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x2, 0x0,0x0,0x0}, /*LED_BLUE_02_ON_18_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x3, 0x0,0x0,0x0}, /*LED_BLUE_05_ON_15_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x4, 0x0,0x0,0x0}, /*LED_BLUE_025_ON_075_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x5, 0x0,0x0,0x0}, /*LED_BLUE_025_ON_175_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x6, 0x0,0x0,0x0}, /*LED_BLUE_005_ON_195_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x7, 0x0,0x0,0x0}, /*LED_BLUE_05_ON_05_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x8, 0x0,0x0,0x0}, /*LED_BLUE_05_OFF_05_ON*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x9, 0x0,0x0,0x0}, /*LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0xa, 0x0,0x0,0x0}, /*LED_BLUE_0125_ON_2075_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0xb, 0x0,0x0,0x0}, /*LED_BLUE_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*BLUE 5 mA Current Skip On*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x1, 0x0,0x0,0x1}, /*LED_BLUE_01_ON_19_OFF,skip On*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x2, 0x0,0x0,0x1}, /*LED_BLUE_02_ON_18_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x3, 0x0,0x0,0x1}, /*LED_BLUE_05_ON_15_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x4, 0x0,0x0,0x1}, /*LED_BLUE_025_ON_075_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x5, 0x0,0x0,0x1}, /*LED_BLUE_025_ON_175_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x6, 0x0,0x0,0x1}, /*LED_BLUE_005_ON_195_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x7, 0x0,0x0,0x1}, /*LED_BLUE_05_ON_05_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x8, 0x0,0x0,0x1}, /*LED_BLUE_05_OFF_05_ON*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0x9, 0x0,0x0,0x1}, /*LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0xa, 0x0,0x0,0x1}, /*LED_BLUE_0125_ON_2075_OFF*/ ++ {0x1,0x1, 0x0,0x1, 0x0,0xb, 0x0,0x0,0x1}, /*LED_BLUE_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*ORANGE 5 mA Current Skip OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_01_ON_19_OFF,skip off*/ ++ {0x0,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_02_ON_18_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_05_ON_15_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_025_ON_075_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_025_ON_175_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_005_ON_195_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_05_ON_05_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_05_OFF_05_ON*/ ++ {0x0,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_0125_ON_2075_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*ORANGE 5 mA current Skip On*/ ++ {0x0,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_01_ON_19_OFF,skip On*/ ++ {0x0,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_02_ON_18_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_05_ON_15_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_025_ON_075_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_025_ON_175_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_005_ON_195_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_05_ON_05_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_05_OFF_05_ON*/ ++ {0x0,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_0125_ON_2075_OFF*/ ++ {0x0,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_0625_OFF_0075_ON_15_OFF*/ ++ ++ /*LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF*/ ++ {0x0,0x1, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x0}, ++ /*LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF*/ ++ {0x1,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x0}, ++ /*LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF*/ ++ {0x0,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x0}, ++ ++ /*LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP*/ ++ {0x0,0x1, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x1}, ++ /*LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP*/ ++ {0x1,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x1}, ++ /*LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP*/ ++ {0x0,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x1}, ++ ++ {0, 0, 0, 0, 0, 0, 0, 0, 0} ++}; ++ ++#ifdef DEBUG_LED_DRIVER ++char LED_Name[LED_BOTTOM_STATE +1][100]= ++{ ++ "LED_OFF", ++ ++ "LED_RED_ALWAYS_ON", ++ "LED_GREEN_ALWAYS_ON", ++ "LED_BLUE_ALWAYS_ON", ++ "LED_LIGHT_RED_ALWAYS_ON", ++ "LED_ORANGE_ALWAYS_ON", ++ "LED_LIGHT_BLUE_ALWAYS_ON", ++ "LED_WHITE_ALWAYS_ON", ++ ++ "LED_RED_01_ON_19_OFF", ++ "LED_RED_02_ON_18_OFF", ++ "LED_RED_05_ON_15_OFF", ++ "LED_RED_025_ON_075_OFF", ++ "LED_RED_025_ON_175_OFF", ++ "LED_RED_005_ON_195_OFF", ++ "LED_RED_05_ON_05_OFF", ++ "LED_RED_05_OFF_05_ON", ++ "LED_RED_0125_ON_05_OFF_0075_ON_15_OFF", ++ "LED_RED_0125_ON_2075_OFF", ++ "LED_RED_0625_OFF_0075_ON_15_OFF", ++ ++ "LED_RED_01_ON_19_OFF_SKIP", ++ "LED_RED_02_ON_18_OFF_SKIP", ++ "LED_RED_05_ON_15_OFF_SKIP", ++ "LED_RED_025_ON_075_OFF_SKIP", ++ "LED_RED_025_ON_175_OFF_SKIP", ++ "LED_RED_005_ON_195_OFF_SKIP", ++ "LED_RED_05_ON_05_OFF_SKIP", ++ "LED_RED_05_OFF_05_ON_SKIP", ++ "LED_RED_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", ++ "LED_RED_0125_ON_2075_OFF_SKIP", ++ "LED_RED_0625_OFF_0075_ON_15_OFF_SKIP", ++ ++ "LED_GREEN_01_ON_19_OFF", ++ "LED_GREEN_02_ON_18_OFF", ++ "LED_GREEN_05_ON_15_OFF", ++ "LED_GREEN_025_ON_075_OFF", ++ "LED_GREEN_025_ON_175_OFF", ++ "LED_GREEN_005_ON_195_OFF", ++ "LED_GREEN_05_ON_05_OFF", ++ "LED_GREEN_05_OFF_05_ON", ++ "LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF", ++ "LED_GREEN_0125_ON_2075_OFF", ++ "LED_GREEN_0625_OFF_0075_ON_15_OFF", ++ ++ "LED_GREEN_01_ON_19_OFF_SKIP", ++ "LED_GREEN_02_ON_18_OFF_SKIP", ++ "LED_GREEN_05_ON_15_OFF_SKIP", ++ "LED_GREEN_025_ON_075_OFF_SKIP", ++ "LED_GREEN_025_ON_175_OFF_SKIP", ++ "LED_GREEN_005_ON_195_OFF_SKIP", ++ "LED_GREEN_05_ON_05_OFF_SKIP", ++ "LED_GREEN_05_OFF_05_ON_SKIP", ++ "LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", ++ "LED_GREEN_0125_ON_2075_OFF_SKIP", ++ "LED_GREEN_0625_OFF_0075_ON_15_OFF_SKIP", ++ ++ "LED_BLUE_01_ON_19_OFF", ++ "LED_BLUE_02_ON_18_OFF", ++ "LED_BLUE_05_ON_15_OFF", ++ "LED_BLUE_025_ON_075_OFF", ++ "LED_BLUE_025_ON_175_OFF", ++ "LED_BLUE_005_ON_195_OFF", ++ "LED_BLUE_05_ON_05_OFF", ++ "LED_BLUE_05_OFF_05_ON", ++ "LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF", ++ "LED_BLUE_0125_ON_2075_OFF", ++ "LED_BLUE_0625_OFF_0075_ON_15_OFF", ++ ++ "LED_BLUE_01_ON_19_OFF_SKIP", ++ "LED_BLUE_02_ON_18_OFF_SKIP", ++ "LED_BLUE_05_ON_15_OFF_SKIP", ++ "LED_BLUE_025_ON_075_OFF_SKIP", ++ "LED_BLUE_025_ON_175_OFF_SKIP", ++ "LED_BLUE_005_ON_195_OFF_SKIP", ++ "LED_BLUE_05_ON_05_OFF_SKIP", ++ "LED_BLUE_05_OFF_05_ON_SKIP", ++ "LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", ++ "LED_BLUE_0125_ON_2075_OFF_SKIP", ++ "LED_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", ++ ++ "LED_ORANGE_01_ON_19_OFF", ++ "LED_ORANGE_02_ON_18_OFF", ++ "LED_ORANGE_05_ON_15_OFF", ++ "LED_ORANGE_025_ON_075_OFF", ++ "LED_ORANGE_025_ON_175_OFF", ++ "LED_ORANGE_005_ON_195_OFF", ++ "LED_ORANGE_05_ON_05_OFF", ++ "LED_ORANGE_05_OFF_05_ON", ++ "LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF", ++ "LED_ORANGE_0125_ON_2075_OFF", ++ "LED_ORANGE_0625_OFF_0075_ON_15_OFF", ++ ++ "LED_ORANGE_01_ON_19_OFF_SKIP", ++ "LED_ORANGE_02_ON_18_OFF_SKIP", ++ "LED_ORANGE_05_ON_15_OFF_SKIP", ++ "LED_ORANGE_025_ON_075_OFF_SKIP", ++ "LED_ORANGE_025_ON_175_OFF_SKIP", ++ "LED_ORANGE_005_ON_195_OFF_SKIP", ++ "LED_ORANGE_05_ON_05_OFF_SKIP", ++ "LED_ORANGE_05_OFF_05_ON_SKIP", ++ "LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", ++ "LED_ORANGE_0125_ON_2075_OFF_SKIP", ++ "LED_ORANGE_0625_OFF_0075_ON_15_OFF_SKIP", ++ ++ "LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF", ++ "LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF", ++ "LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF", ++ ++ ++ "LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", ++ "LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", ++ "LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", ++ "" ++}; /* LED Name*/ ++#endif ++/* These are the control structures for the LEDs. */ ++static struct led_info info1; ++static struct led_reg_info led1; ++static int old_state ; ++static unsigned int old_tempValue; ++static struct pm_dev *led_pxa_pm_dev; ++/*--------------------------------------------------------------------------- ++DESCRIPTION: Set LED state. ++INPUTS: int state LED light mode. ++OUTPUTS: int 0, succesee else return error no. ++IMPORTANT NOTES: ++To prevent RED to GREEN phase timing issues, the RED and Green LED bit codes should be written ++simultaneously. Additionally, changing the timing of one or both drivers should be accomplished by first writing a ++zero to each bit location, followed by a write to both locations with the desired bits. ++ ++---------------------------------------------------------------------------*/ ++int PXA_E680_LED_set(int state) ++{ ++ unsigned char ledr_en,ledg_en,ledr_ctrl,ledg_ctrl,ledr_i,ledg_i,skip; ++ unsigned int tempValue, value =0; ++ ++ if ( state >= LED_BOTTOM_STATE) ++ { ++ PRINTK("Driver:LED The State is invalid.\n"); ++ return 1; ++ } ++ else if ( old_state == state) ++ { ++ PRINTK("Driver:LED Same to previous State %s.\n",LED_Name[state]); ++ return 0; /*Donn't need change the LED state.*/ ++ } ++ /*First Disable LED.*/ ++ if(SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,&tempValue)!= ++ SSP_PCAP_SUCCESS) ++ { ++ PRINTK("Driver:LED PCAP Read Failed.\n"); ++ return 1; ++ } ++ tempValue &= (~SSP_PCAP_LED_MASK); ++ if(SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,tempValue)!=SSP_PCAP_SUCCESS) ++ { ++ PRINTK("Driver:LED PCAP Write Failed (Clear Data).\n"); ++ return 1; ++ } ++ ++ /*Set GPIO as general I/O and as output*/ ++ set_GPIO_mode(IND_CNTL_R_BUL | GPIO_OUT); ++ set_GPIO_mode(IND_CNTL_G_BUL | GPIO_OUT); ++ ++ if (led_register_value[state].ind_GPIO_red && led_register_value[state].ind_GPIO_green) ++ { ++ /*Disable Red & Green signal*/ ++ set_GPIO(IND_CNTL_R_BUL); /*IND_CNTL_R_BUL Low active*/ ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); ++ ++ clr_GPIO(IND_CNTL_G_BUL); /*IND_CNTL_G_BUL High active*/ ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); ++ ++ PRINTK("GPIO Green Disable, Red Disable!\n"); ++ }else if ( (!led_register_value[state].ind_GPIO_red) && ++ led_register_value[state].ind_GPIO_green) ++ { ++ /*Green Disable, Red Enable*/ ++ clr_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) & (~GPIO_bit(IND_CNTL_R_BUL)); ++ ++ clr_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); ++ ++ PRINTK("GPIO Green Disable, Red Enable!\n"); ++ }else if ( led_register_value[state].ind_GPIO_red && ++ !led_register_value[state].ind_GPIO_green) ++ { ++ /*Red Disable, Green Enable*/ ++ set_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); ++ ++ set_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) | GPIO_bit(IND_CNTL_G_BUL); ++ PRINTK("GPIO Red Disable, Green Enable"); ++ }else ++ { ++ /*Red & Green enable*/ ++ clr_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) & (~GPIO_bit(IND_CNTL_R_BUL)); ++ ++ set_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) | GPIO_bit(IND_CNTL_G_BUL); ++ PRINTK("GPIO Red & Green enable!\n"); ++ } ++ PRINTK("Driver:--IND_CNTL_G_BUL:%x IND_CNTL_R_BUL:%x\n",GPIO_is_high(IND_CNTL_G_BUL), ++ GPIO_is_high(IND_CNTL_R_BUL)); ++ /* Write PCAP Peripheral Control Register*/ ++ ledr_en = led_register_value[state].pcap_LEDR_en & 0x1; ++ ledg_en = led_register_value[state].pcap_LEDG_en & 0x1; ++ ledr_ctrl = led_register_value[state].pcap_LEDR_CTRL & 0xf; ++ ledg_ctrl = led_register_value[state].pcap_LEDG_CTRL & 0xf; ++ ledr_i = led_register_value[state].pcap_LEDR_I & 0x3; ++ ledg_i = led_register_value[state].pcap_LEDG_I & 0x3; ++ skip = led_register_value[state].pcap_SKIP_on & 0x1; ++ ++ value = ( ledr_en | (ledg_en <<1) | (ledr_ctrl <<2) | (ledg_ctrl <<6) | ++ (ledr_i << 10) | (ledg_i <<12) | (skip <<14) ) & 0x7fff; ++ tempValue |= (value <<SSP_PCAP_LED_SHIFT); ++ if(SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,tempValue)==SSP_PCAP_SUCCESS) ++ { ++ PRINTK("Driver:LED write Value to PCAP:0x%x :0x%x\n",tempValue,value); ++ PRINTK("Driver:LED State To: %s\n",LED_Name[state]); ++ old_tempValue = tempValue; ++ old_state = state; ++ return 0; ++ }else ++ { ++ PRINTK("Driver:LED: Changed to State %s Failed.\n",LED_Name[state]); ++ return 1; ++ } ++} ++ ++ ++/*--------------------------------------------------------------------------- ++DESCRIPTION: reptore PGSR. ++INPUTS: old_state. ++OUTPUTS: int 0, succesee else return error no. ++IMPORTANT NOTES: ++ ++---------------------------------------------------------------------------*/ ++int PXA_E680_LED_retore_PGSR(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ unsigned int tempValue; ++ ++ ++ switch (rqst) ++ { ++ case PM_RESUME: ++ { ++ /*First Disable LED.*/ ++ if(SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,&tempValue)!= ++ SSP_PCAP_SUCCESS) ++ { ++ PRINTK("Driver:LED PCAP Read Failed.\n"); ++ return 1; ++ } ++ tempValue &= (~SSP_PCAP_LED_MASK); ++ if(SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,tempValue)!=SSP_PCAP_SUCCESS) ++ { ++ PRINTK("Driver:LED PCAP Write Failed (Clear Data).\n"); ++ return 1; ++ } ++ ++ if (led_register_value[old_state].ind_GPIO_red && led_register_value[old_state].ind_GPIO_green) ++ { ++ /*Disable Red & Green signal*/ ++ set_GPIO(IND_CNTL_R_BUL); /*IND_CNTL_R_BUL Low active*/ ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); ++ ++ clr_GPIO(IND_CNTL_G_BUL); /*IND_CNTL_G_BUL High active*/ ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); ++ ++ PRINTK("RESTORE____GPIO Green Disable, Red Disable!\n"); ++ }else if ( (!led_register_value[old_state].ind_GPIO_red) && ++ led_register_value[old_state].ind_GPIO_green) ++ { ++ /*Green Disable, Red Enable*/ ++ clr_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) & (~GPIO_bit(IND_CNTL_R_BUL)); ++ ++ clr_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); ++ ++ PRINTK("RESTORE____GPIO Green Disable, Red Enable!\n"); ++ }else if ( led_register_value[old_state].ind_GPIO_red && ++ !led_register_value[old_state].ind_GPIO_green) ++ { ++ /*Red Disable, Green Enable*/ ++ set_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); ++ ++ set_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) | GPIO_bit(IND_CNTL_G_BUL); ++ PRINTK("RESTORE____GPIO Red Disable, Green Enable"); ++ }else ++ { ++ /*Red & Green enable*/ ++ clr_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) & (~GPIO_bit(IND_CNTL_R_BUL)); ++ ++ set_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) | GPIO_bit(IND_CNTL_G_BUL); ++ PRINTK("RESTORE____GPIO Red & Green enable!\n"); ++ } ++ PRINTK("Driver:--IND_CNTL_G_BUL:%x IND_CNTL_R_BUL:%x\n",GPIO_is_high(IND_CNTL_G_BUL), ++ GPIO_is_high(IND_CNTL_R_BUL)); ++ ++ if(SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,old_tempValue)==SSP_PCAP_SUCCESS) ++ { ++ PRINTK("Driver:LED write Value to PCAP:0x%x\n",old_tempValue); ++ PRINTK("Driver:LED State To: %s\n",LED_Name[old_state]); ++ return 0; ++ }else ++ { ++ PRINTK("Driver:LED: Changed to State %s Failed.\n",LED_Name[old_state]); ++ return 1; ++ } ++ ++ break; ++ }//end of case RESUME ++ }//end of switch ++ return 0; ++}//end of function ++ ++ ++/* Handle an actual LED set*/ ++int handle_led_op(struct led_reg_info *info, ++ struct led_op *op) ++{ ++ switch (op->op) ++ { ++ case SET_LED: ++ if ( PXA_E680_LED_set(op->op_info.bicolor.color) == 0) ++ return 0; ++ else ++ return -EINVAL; ++ default: ++ PRINTK("LED:Error CMD.\n"); ++ return -EINVAL; ++ } ++} ++ ++/** ++ * PXA_E680_LED_exit: ++ * ++ * Remove the LEDs from the LED driver ++ */ ++ ++static void __exit PXA_E680_LED_exit(void) ++{ ++ pm_unregister(led_pxa_pm_dev); ++ unregister_led_info(&led1); ++} ++ ++/** ++ * PXA_E680_LED_init ++ * ++ * Register the LEDs with the LED driver. ++ */ ++ ++static int __init PXA_E680_LED_init(void) ++{ ++ info1.type = LED_TYPE_BICOLOR; ++ strcpy(info1.name, LED_E680_NAME); ++ led1.info = &info1; ++ led1.data = (void *) 0; ++ led1.handle_led_op = handle_led_op; ++ register_led_info(&led1); ++ ++ old_state = LED_OFF; ++ old_tempValue = 0; ++ led_pxa_pm_dev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, PXA_E680_LED_retore_PGSR); ++ ++ /*Set GPIO as general IO and as Output*/ ++ set_GPIO_mode(IND_CNTL_R_BUL | GPIO_OUT); ++ set_GPIO_mode(IND_CNTL_G_BUL | GPIO_OUT); ++ ++ set_GPIO(IND_CNTL_R_BUL); ++ PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); ++ ++ clr_GPIO(IND_CNTL_G_BUL); ++ PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); ++ PRINTK("PCAP2 LED driver: v%s E680\n", VERSION); ++ return 0; ++} ++ ++module_init(PXA_E680_LED_init); ++module_exit(PXA_E680_LED_exit); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/char/Makefile linux-2.6.16/drivers/char/Makefile +--- linux-2.6.16.orig/drivers/char/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/Makefile 2006-06-03 11:14:56.753261448 +0200 +@@ -61,6 +61,7 @@ + obj-$(CONFIG_HPET) += hpet.o + obj-$(CONFIG_GEN_RTC) += genrtc.o + obj-$(CONFIG_EFI_RTC) += efirtc.o ++obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o + obj-$(CONFIG_SGI_DS1286) += ds1286.o + obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o + obj-$(CONFIG_DS1302) += ds1302.o +@@ -95,6 +96,14 @@ + + obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o + obj-$(CONFIG_TCG_TPM) += tpm/ ++ ++obj-$(CONFIG_LINUX_LED) += led.o ++obj-$(CONFIG_PXA_E680_LED) += led_pxa_e680.o ++ ++obj-$(CONFIG_MAINSTONE_KEYPAD) += mstone_keypad.o ++obj-$(CONFIG_BULVERDE_SRAM_DEV) += sram.o ++ ++ + # Files generated that shall be removed upon make clean + clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c + +diff -Nurd linux-2.6.16.orig/drivers/char/mstone_keypad.c linux-2.6.16/drivers/char/mstone_keypad.c +--- linux-2.6.16.orig/drivers/char/mstone_keypad.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/char/mstone_keypad.c 2006-06-03 11:14:56.298330608 +0200 +@@ -0,0 +1,581 @@ ++/* ++ * linux/driver/char/mstone_keypad.c ++ * Keypad driver for Intel Mainstone development board ++ * ++ * Copyright (C) 2003, Intel Corporation (yu.tang@intel.com) ++ * Copyright 2003 MontaVista Software Inc. ++ * Author: MontaVista Software, Inc. ++ * source@mvista.com ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/delay.h> ++#include <linux/poll.h> ++#include <linux/spinlock.h> ++#include <linux/sem.h> ++#include <linux/miscdevice.h> ++#include <asm/system.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/hardirq.h> ++#include <asm/uaccess.h> ++#include <asm/ioctl.h> ++ ++#include <asm/arch/keypad.h> ++ ++/* Direct-KEY scan-code for Mainstone-I Board */ ++#define ROTARY_DEFAULT 0x7F ++#define NO_KEY 0xFF ++#define SCAN_CODE_SCROLL_UP 0xA ++#define SCAN_CODE_SCROLL_DOWN 0xB ++#define SCAN_CODE_ACTION 0xC ++ ++DECLARE_MUTEX(kpdrv_mutex); ++static struct kpe_queue kpe_queue; ++static int kpdrv_refcount = 0; ++ ++//#define DEBUG 1 ++#if DEBUG ++static unsigned int mstone_keypad_dbg = 1; ++#else ++#define mstone_keypad_dbg 0 ++#endif ++ ++#ifdef CONFIG_DPM ++#include <linux/device.h> ++ ++static int pxakpd_suspend(struct device *dev, u32 state, u32 level); ++static int pxakpd_resume(struct device *dev, u32 level); ++static int pxakpd_scale(struct bus_op_point *op, u32 level); ++ ++static struct device_driver pxakpd_driver_ldm = { ++ name: "pxa-kpd", ++ devclass: NULL, ++ probe: NULL, ++ suspend: pxakpd_suspend, ++ resume: pxakpd_resume, ++ scale: pxakpd_scale, ++ remove: NULL, ++ constraints: NULL, ++}; ++ ++static struct device pxakpd_device_ldm = { ++ name: "PXA Keypad", ++ bus_id: "pxakpd", ++ driver: NULL, ++ power_state: DPM_POWER_ON, ++}; ++ ++static void ++pxakpd_ldm_register(void) ++{ ++ extern void pxaopb_driver_register(struct device_driver *driver); ++ extern void pxaopb_device_register(struct device *device); ++ ++ pxaopb_driver_register(&pxakpd_driver_ldm); ++ pxaopb_device_register(&pxakpd_device_ldm); ++} ++ ++static void ++pxakpd_ldm_unregister(void) ++{ ++ extern void pxaopb_driver_unregister(struct device_driver *driver); ++ extern void pxaopb_device_unregister(struct device *device); ++ ++ pxaopb_device_unregister(&pxakpd_device_ldm); ++ pxaopb_driver_unregister(&pxakpd_driver_ldm); ++} ++ ++static int ++pxakpd_resume(struct device *dev, u32 level) ++{ ++ if (mstone_keypad_dbg) ++ printk("+++: in pxakpd_resume()\n"); ++ ++ switch (level) { ++ case RESUME_POWER_ON: ++ /* enable direct and matrix interrupts */ ++ KPC |= (KPC_DIE | KPC_MIE); ++ ++ /* enable clock to keypad */ ++ CKEN |= CKEN19_KEYPAD; ++ { ++ struct kp_event kpe; ++ unsigned char c; ++ ++ kpe.flags |= (KP_DIRECT | KP_MATRIX ); ++ c = get_scancode(&kpe); ++ if (c != NO_KEY) { ++ /* Insert it into key event list. */ ++ kpq_put(&kpe); ++ } ++ else { ++ /* We are not woke by key press. */ ++ } ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ++pxakpd_suspend(struct device *dev, u32 state, u32 level) ++{ ++ if (mstone_keypad_dbg) ++ printk("+++: in pxakpd_suspend()\n"); ++ ++ switch (level) { ++ case SUSPEND_POWER_DOWN: ++ /* disable clock to keypad */ ++ CKEN &= ~CKEN19_KEYPAD; ++ ++ /* disable direct and matrix interrupts */ ++ KPC &= ~(KPC_DIE | KPC_MIE); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ++pxakpd_scale(struct bus_op_point *op, u32 level) ++{ ++ printk("+++: in pxakpd_scale()\n"); ++ ++ return 0; ++} ++#endif /* CONFIG_DPM */ ++ ++/* Init kpe queue */ ++static void kpq_init(void) ++{ ++ kpe_queue.head = kpe_queue.tail = kpe_queue.len = 0; ++ kpe_queue.spinlock = SPIN_LOCK_UNLOCKED; ++ init_waitqueue_head(&kpe_queue.waitq); ++} ++ ++static int kpq_empty(void) ++{ ++ int flags, empty; ++ ++ spin_lock_irqsave(&kpe_queue.spinlock,flags); ++ empty = kpe_queue.len ? 0 : 1; ++ spin_unlock_irqrestore(&kpe_queue.spinlock, flags); ++ ++ return empty; ++} ++ ++static int kpq_get(struct kp_event *kpe) ++{ ++ int flags, err = 0; ++ ++ spin_lock_irqsave(&kpe_queue.spinlock, flags); ++ if (kpe_queue.head == kpe_queue.tail) { ++ printk(KERN_ERR "keypad: empty event queue, looks bad\n"); ++ err = -EAGAIN; ++ goto out; ++ } ++ memcpy(kpe, kpe_queue.kpes + kpe_queue.tail, sizeof(struct kp_event)); ++ kpe_queue.len--; ++ kpe_queue.tail = (kpe_queue.tail + 1) % MAX_KPES; ++ out: ++ spin_unlock_irqrestore(&kpe_queue.spinlock, flags); ++ return err; ++} ++ ++static void kpq_put(struct kp_event *kpe) ++{ ++ int flags; ++ ++ spin_lock_irqsave(&kpe_queue.spinlock, flags); ++ memcpy(kpe_queue.kpes + kpe_queue.head, kpe, sizeof(struct kp_event)); ++ kpe_queue.len++; ++ if (kpe_queue.len == MAX_KPES) { ++ printk(KERN_ERR "keypad: events are comes too fast, will discard next\n"); ++ kpe_queue.len--; ++ goto out; ++ } ++ kpe_queue.head = (kpe_queue.head + 1) % MAX_KPES; ++ out: ++ spin_unlock_irqrestore(&kpe_queue.spinlock, flags); ++ /* Wake up the waiting processes */ ++ wake_up_interruptible(&kpe_queue.waitq); ++} ++ ++static int kp_direct_scan(struct kp_event *kpe) ++{ ++ kpe->flags |= KP_DIRECT; ++ kpe->direct = KPDK; ++ kpe->rotary = KPREC; ++ return 0; ++} ++ ++static int kp_matrix_scan(struct kp_event *kpe) ++{ ++ KPC |= KPC_AS; ++ while (KPAS &KPAS_SO); ++ ++ kpe->flags |= KP_MATRIX; ++ kpe->matrix[0] = KPAS; ++ kpe->matrix[1] = KPASMKP0; ++ kpe->matrix[2] = KPASMKP1; ++ kpe->matrix[3] = KPASMKP2; ++ kpe->matrix[4] = KPASMKP3; ++ ++ KPC &= ~KPC_AS; ++ ++ return 0; ++} ++ ++/* Interrupt kandler for keypad */ ++static void kp_interrupt(int irq, void *ptr, struct pt_regs *regs) ++{ ++ struct kp_event kpe = {0}; ++ int flags; ++ unsigned long kpc_val; ++ ++ printk("+++: kp_interrupt()\n"); ++ ++ spin_lock_irqsave(&kpe_queue.spinlock,flags); ++ ++ /* ACK interrupt */ ++ kpc_val = KPC; ++ kpe.jiffies = jiffies; ++ ++ /* Direct interrupt */ ++ if (kpc_val & KPC_DI) ++ kp_direct_scan(&kpe); ++ ++ /* Matrix interrupt */ ++ if (kpc_val & KPC_MI) ++ kp_matrix_scan(&kpe); ++ ++ spin_unlock_irqrestore(&kpe_queue.spinlock, flags); ++ ++ if (((kpe.flags & KP_DIRECT) || (kpe.flags & KP_MATRIX)) && kpdrv_refcount) ++ kpq_put(&kpe); ++} ++ ++/* Wait for keypad event, must be in task-context */ ++int kp_wait(struct kp_event *kpe, signed int timeout) ++{ ++ int n, err = 0; ++ ++ while(1) { ++ if (!kpq_empty()) { ++ n = kpq_get(kpe); ++ if (n < 0) ++ continue; ++ break; ++ } ++ ++ /* No event available ? */ ++ if (!timeout) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ if (timeout > 0) { ++ /* Wait for timeout */ ++ timeout = interruptible_sleep_on_timeout(&kpe_queue.waitq, timeout); ++ continue; ++ } ++ else{ ++ /* Wait for kpevent/signal */ ++ while(1) { ++ interruptible_sleep_on(&kpe_queue.waitq); ++ if (kpq_empty() && !signal_pending(current)) ++ continue; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = -EINTR; ++ break; ++ } ++ } ++ } ++ return err; ++} ++ ++/* Poll for keypad event */ ++unsigned int kp_poll(struct file *file, poll_table *wait) ++{ ++ poll_wait(file, &kpe_queue.waitq, wait); ++ return kpq_empty() ? 0 : POLLIN | POLLRDNORM; ++} ++ ++static unsigned char get_scancode(struct kp_event *kpe) ++{ ++ static unsigned int curr, prev = ROTARY_DEFAULT; ++ unsigned int c; ++ ++ c = NO_KEY; ++ ++ if (kpe->flags & KP_DIRECT) { ++ ++ curr = kpe->rotary & 0xFF; ++ ++ if (kpe->rotary & KPREC_OF0) { ++ KPREC &= ~KPREC_OF0; ++ KPREC |= ROTARY_DEFAULT; ++ prev = ROTARY_DEFAULT; ++ c = SCAN_CODE_SCROLL_UP; ++ } ++ else if (kpe->rotary & KPREC_UF0) { ++ KPREC &= ~KPREC_UF0; ++ KPREC |= ROTARY_DEFAULT; ++ prev = ROTARY_DEFAULT; ++ c = SCAN_CODE_SCROLL_DOWN; ++ } ++ else if (curr > prev) { ++ c = SCAN_CODE_SCROLL_UP; ++ prev = curr; ++ } ++ else if (curr < prev) { ++ c = SCAN_CODE_SCROLL_DOWN; ++ prev = curr; ++ } ++ else if (kpe->direct & KPDK_DK2) { ++ c = SCAN_CODE_ACTION; ++ prev = curr; ++ } ++ } ++ ++ if (kpe->flags & KP_MATRIX) { ++ unsigned int count = (kpe->matrix[0] >> 26) & 0x1f; ++ ++ c = kpe->matrix[0] & 0xff; ++ ++ /* Key up */ ++ if (!count) c |= 0x80; ++ } ++ ++ return c; ++} ++ ++static ssize_t kpdrv_read(struct file * filp, char * buf, ++ size_t count, loff_t *ppos) ++{ ++ struct kp_event kpe; ++ int err,left,timeout; ++ unsigned char c; ++ ++ timeout = 0; ++ left = count; ++ do { ++ err = kp_wait(&kpe, timeout); ++ if (err) { ++ if ( left != count ) return (count-left); ++ ++ if (filp->f_flags & O_NONBLOCK) return err; ++ ++ if (timeout) return err; ++ ++ timeout = -1; ++ continue; ++ } ++ /* Parse if direct/matrix flags are set*/ ++ if ( (kpe.flags & KP_DIRECT) || (kpe.flags & KP_MATRIX) ) { ++ c = get_scancode(&kpe); ++ if (c != NO_KEY) { ++ put_user(c, buf++); ++ left --; ++ } ++ } ++ } while (left); ++ return (count-left); ++} ++ ++static int kpdrv_ioctl(struct inode *ip, struct file *fp, ++ unsigned int cmd, unsigned long arg) ++{ ++ int interval = KPKDI & 0xffff; ++ int ign = (KPC & KPC_IMKP); ++ ++ switch(cmd) { ++ case KPIOGET_INTERVAL: ++ if (copy_to_user((void*)arg, &interval, sizeof(int))) ++ return -EFAULT; ++ break; ++ case KPIOGET_IGNMULTI: ++ if (copy_to_user((void*)arg, &ign, sizeof(int))) ++ return -EFAULT; ++ break; ++ case KPIOSET_INTERVAL: ++ if (copy_from_user(&interval, (void*)arg, sizeof(int))) ++ return -EFAULT; ++ ++ /* FIXME : sighting #34833, Matrix Key interval should be >10ms */ ++ if ( (interval & 0xff) < 10) return -EINVAL; ++ ++ KPKDI &= ~0xffff; ++ KPKDI |= (interval & 0xffff); ++ break; ++ case KPIOSET_IGNMULTI: ++ if (copy_from_user(&ign, (void*)arg, sizeof(int))) ++ return -EFAULT; ++ ++ if (ign) ++ KPC |= KPC_IMKP; ++ else ++ KPC &= ~KPC_IMKP; ++ ++ break; ++ ++ default: ++ /* Unknown command */ ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static unsigned int kpdrv_poll(struct file *filp, poll_table * wait) { ++ return kp_poll(filp, wait); ++} ++ ++static int kpdrv_open(struct inode *inode, struct file *filp) ++{ ++ down(&kpdrv_mutex); ++ if (!kpdrv_refcount) ++ kpq_init(); ++ kpdrv_refcount++; ++ up(&kpdrv_mutex); ++ return 0; ++} ++ ++static int kpdrv_close(struct inode *inode, struct file *filp) ++{ ++ down(&kpdrv_mutex); ++ kpdrv_refcount--; ++ up(&kpdrv_mutex); ++ ++ return 0; ++} ++ ++static struct file_operations kpdrv_fops = { ++ owner: THIS_MODULE, ++ open: kpdrv_open, ++ release: kpdrv_close, ++ read: kpdrv_read, ++ ioctl: kpdrv_ioctl, ++ poll: kpdrv_poll, ++}; ++ ++ ++static struct miscdevice keypad_miscdevice = { ++ minor: MISC_DYNAMIC_MINOR, ++ name: "keypad", ++ fops: &kpdrv_fops ++}; ++ ++static int __init kpdrv_init(void) ++{ ++ int err; ++ ++ /* Setup gpio */ ++ set_GPIO_mode(93 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(94 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(95 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(96 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(97 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(98 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(99 | GPIO_ALT_FN_1_IN); ++ ++ set_GPIO_mode(100 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(101 | GPIO_ALT_FN_1_IN); ++ set_GPIO_mode(102 | GPIO_ALT_FN_1_IN); ++ ++ set_GPIO_mode(103 | GPIO_ALT_FN_2_OUT); ++ set_GPIO_mode(104 | GPIO_ALT_FN_2_OUT); ++ set_GPIO_mode(105 | GPIO_ALT_FN_2_OUT); ++ set_GPIO_mode(106 | GPIO_ALT_FN_2_OUT); ++ set_GPIO_mode(107 | GPIO_ALT_FN_2_OUT); ++ set_GPIO_mode(108 | GPIO_ALT_FN_2_OUT); ++ ++ /* Set keypad control register */ ++ KPC = (KPC_ASACT | (3<<26) | (4<<23)| ++ KPC_ME | (2<<6) | KPC_DEE0 | KPC_DE | ++ KPC_MS_ALL | KPC_MIE | KPC_DIE | KPC_IMKP); ++ ++ /* Set debouce time seperately for Matrix/Direct. */ ++ KPKDI= 0x010A; ++ ++ /* Set scroll wheel value to mid-point value */ ++ KPREC= 0x7F; ++ ++ /* Enable unit clock */ ++ CKEN |= CKEN19_KEYPAD; ++ ++ /* Request keypad IRQ */ ++ err = request_irq(IRQ_KEYPAD, kp_interrupt, 0, "keypad", NULL); ++ if (err) { ++ printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", ++ IRQ_KEYPAD, err); ++ /* Disable clock unit */ ++ CKEN &= ~CKEN19_KEYPAD; ++ return -ENODEV; ++ } ++ ++ /* Register driver as miscdev */ ++ err = misc_register(&keypad_miscdevice); ++ if (err) ++ printk(KERN_ERR "can't register keypad misc device, error %d\n", err); ++ else ++ printk(KERN_INFO "Intel Mainstone Keypad driver registered with minor %d\n", ++ keypad_miscdevice.minor); ++ ++#ifdef CONFIG_DPM ++ pxakpd_ldm_register(); ++#endif /* CONFIG_DPM */ ++ ++ return err; ++} ++ ++static void __exit kpdrv_exit(void) ++{ ++#ifdef CONFIG_DPM ++ pxakpd_ldm_unregister(); ++#endif /* CONFIG_DPM */ ++ ++ /* Disable clock unit */ ++ CKEN &= ~CKEN19_KEYPAD; ++ ++ /* Free keypad IRQ */ ++ free_irq(IRQ_KEYPAD, NULL); ++ ++ /* Unregister keypad device */ ++ misc_deregister(&keypad_miscdevice); ++} ++ ++module_init(kpdrv_init); ++module_exit(kpdrv_exit); ++ ++MODULE_AUTHOR("Yu Tang <yu.tang@intel.com>, source@mvista.com"); ++MODULE_DESCRIPTION("Intel Mainstone KEYPAD driver"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/char/n_tty.c linux-2.6.16/drivers/char/n_tty.c +--- linux-2.6.16.orig/drivers/char/n_tty.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/n_tty.c 2006-06-03 11:14:56.299330456 +0200 +@@ -60,6 +60,12 @@ + #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ + #define TTY_THRESHOLD_UNTHROTTLE 128 + ++#if defined(CONFIG_ARCH_EZX) && 0 ++extern int btuart_flip_flow_ctl; ++extern void rs_flip_unthrottle(struct tty_struct *tty); ++#endif ++ ++ + static inline unsigned char *alloc_buf(void) + { + gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; +@@ -957,6 +963,11 @@ + + n_tty_set_room(tty); + ++#if defined (CONFIG_ARCH_EZX) && 0 ++ if (tty && tth->driver.btuart) ++ rs_flip_unthrottle(tty); ++#endif ++ + if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { + kill_fasync(&tty->fasync, SIGIO, POLL_IN); + if (waitqueue_active(&tty->read_wait)) +diff -Nurd linux-2.6.16.orig/drivers/char/sa1100-rtc.c linux-2.6.16/drivers/char/sa1100-rtc.c +--- linux-2.6.16.orig/drivers/char/sa1100-rtc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/char/sa1100-rtc.c 2006-06-03 11:14:56.754261296 +0200 +@@ -0,0 +1,554 @@ ++/* ++ * linux/drivers/char/sa1100-rtc.c ++ * ++ * Real Time Clock interface for Linux on StrongARM SA1x00 ++ * (and XScale PXA2xx which shares the same RTC register definitions) ++ * ++ * Copyright (c) 2000 Nils Faerber ++ * ++ * Based on rtc.c by Paul Gortmaker ++ * ++ * 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. ++ * ++ * 1.02 2002-07-15 Andrew Christian <andrew.christian@hp.com> ++ * - added pm_ routines to shut off extraneous interrupts while asleep ++ * ++ * 1.01 2002-07-09 Nils Faerber <nils@kernelconcepts.de> ++ * - fixed rtc_poll() so that select() now works ++ * ++ * 1.00 2001-06-08 Nicolas Pitre <nico@cam.org> ++ * - added periodic timer capability using OSMR1 ++ * - flag compatibility with other RTC chips ++ * - permission checks for ioctls ++ * - major cleanup, partial rewrite ++ * ++ * 0.03 2001-03-07 CIH <cih@coventive.com> ++ * - Modify the bug setups RTC clock. ++ * ++ * 0.02 2001-02-27 Nils Faerber <nils@kernelconcepts.de> ++ * - removed mktime(), added alarm irq clear ++ * ++ * 0.01 2000-10-01 Nils Faerber <nils@kernelconcepts.de> ++ * - initial release ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/interrupt.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <linux/string.h> ++#include <linux/rtc.h> ++#include <linux/pm.h> ++ ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#ifdef CONFIG_ARCH_PXA ++#include <asm/arch/pxa-regs.h> ++#endif ++ ++#define DRIVER_VERSION "1.02" ++ ++#define TIMER_FREQ CLOCK_TICK_RATE ++ ++#define RTC_DEF_DIVIDER 32768 - 1 ++#define RTC_DEF_TRIM 0 ++ ++/* Those are the bits from a classic RTC we want to mimic */ ++#define RTC_IRQF 0x80 /* any of the following 3 is active */ ++#define RTC_PF 0x40 ++#define RTC_AF 0x20 ++#define RTC_UF 0x10 ++ ++static unsigned long rtc_status; ++static unsigned long rtc_irq_data; ++static unsigned long rtc_freq = 1024; ++ ++static struct fasync_struct *rtc_async_queue; ++static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); ++ ++extern spinlock_t rtc_lock; ++ ++static const unsigned char days_in_mo[] = ++ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; ++ ++#define is_leap(year) \ ++ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) ++ ++/* Converts seconds since 1970-01-01 00:00:00 to Gregorian date. */ ++static void decodetime (unsigned long t, struct rtc_time *tval) ++{ ++ long days, month, year, rem; ++ ++ days = t / 86400; ++ rem = t % 86400; ++ tval->tm_hour = rem / 3600; ++ rem %= 3600; ++ tval->tm_min = rem / 60; ++ tval->tm_sec = rem % 60; ++ tval->tm_wday = (4 + days) % 7; ++ ++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) ++ ++ year = 1970 + days / 365; ++ days -= ((year - 1970) * 365 ++ + LEAPS_THRU_END_OF (year - 1) ++ - LEAPS_THRU_END_OF (1970 - 1)); ++ if (days < 0) { ++ year -= 1; ++ days += 365 + is_leap(year); ++ } ++ tval->tm_year = year - 1900; ++ tval->tm_yday = days + 1; ++ ++ month = 0; ++ if (days >= 31) { ++ days -= 31; ++ month++; ++ if (days >= (28 + is_leap(year))) { ++ days -= (28 + is_leap(year)); ++ month++; ++ while (days >= days_in_mo[month]) { ++ days -= days_in_mo[month]; ++ month++; ++ } ++ } ++ } ++ tval->tm_mon = month; ++ tval->tm_mday = days + 1; ++} ++ ++static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned int rtsr = RTSR; ++ ++ /* clear interrupt sources */ ++ RTSR = 0; ++ RTSR = (RTSR_AL|RTSR_HZ); ++ ++ /* clear alarm interrupt if it has occurred */ ++ if (rtsr & RTSR_AL) ++ rtsr &= ~RTSR_ALE; ++ RTSR = rtsr & (RTSR_ALE|RTSR_HZE); ++ ++ /* update irq data & counter */ ++ if (rtsr & RTSR_AL) ++ rtc_irq_data |= (RTC_AF|RTC_IRQF); ++ if (rtsr & RTSR_HZ) ++ rtc_irq_data |= (RTC_UF|RTC_IRQF); ++ rtc_irq_data += 0x100; ++ ++ /* wake up waiting process */ ++ wake_up_interruptible(&rtc_wait); ++ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ /* ++ * If we match for the first time, the periodic interrupt flag won't ++ * be set. If it is, then we did wrap around (very unlikely but ++ * still possible) and compute the amount of missed periods. ++ * The match reg is updated only when the data is actually retrieved ++ * to avoid unnecessary interrupts. ++ */ ++ OSSR = OSSR_M1; /* clear match on timer1 */ ++ if (rtc_irq_data & RTC_PF) { ++ rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8; ++ } else { ++ rtc_irq_data += (0x100|RTC_PF|RTC_IRQF); ++ } ++ ++ wake_up_interruptible(&rtc_wait); ++ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); ++ return IRQ_HANDLED; ++} ++ ++static int rtc_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit (1, &rtc_status)) ++ return -EBUSY; ++ rtc_irq_data = 0; ++ return 0; ++} ++ ++static int rtc_release(struct inode *inode, struct file *file) ++{ ++ spin_lock_irq (&rtc_lock); ++ RTSR = 0; ++ RTSR = (RTSR_AL|RTSR_HZ); ++ OIER &= ~OIER_E1; ++ OSSR = OSSR_M1; ++ spin_unlock_irq (&rtc_lock); ++ rtc_status = 0; ++ return 0; ++} ++ ++static int rtc_fasync (int fd, struct file *filp, int on) ++{ ++ return fasync_helper (fd, filp, on, &rtc_async_queue); ++} ++ ++static unsigned int rtc_poll(struct file *file, poll_table *wait) ++{ ++ poll_wait (file, &rtc_wait, wait); ++ return (rtc_irq_data) ? POLLIN | POLLRDNORM : 0; ++} ++ ++ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long data; ++ ssize_t retval; ++ ++ if (count < sizeof(unsigned long)) ++ return -EINVAL; ++ ++ add_wait_queue(&rtc_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ for (;;) { ++ spin_lock_irq (&rtc_lock); ++ data = rtc_irq_data; ++ if (data != 0) { ++ rtc_irq_data = 0; ++ break; ++ } ++ spin_unlock_irq (&rtc_lock); ++ ++ if (file->f_flags & O_NONBLOCK) { ++ retval = -EAGAIN; ++ goto out; ++ } ++ ++ if (signal_pending(current)) { ++ retval = -ERESTARTSYS; ++ goto out; ++ } ++ ++ schedule(); ++ } ++ ++ if (data & RTC_PF) { ++ /* interpolate missed periods and set match for the next one */ ++ unsigned long period = TIMER_FREQ/rtc_freq; ++ unsigned long oscr = OSCR; ++ unsigned long osmr1 = OSMR1; ++ unsigned long missed = (oscr - osmr1)/period; ++ data += missed << 8; ++ OSSR = OSSR_M1; /* clear match on timer 1 */ ++ OSMR1 = osmr1 + (missed + 1)*period; ++ /* Ensure we didn't miss another match in the mean time. ++ Here we compare (match - OSCR) against 8 instead of 0 -- ++ see comment in pxa_timer_interrupt() for explanation. */ ++ while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { ++ data += 0x100; ++ OSSR = OSSR_M1; /* clear match on timer 1 */ ++ OSMR1 = osmr1 + period; ++ } ++ } ++ spin_unlock_irq (&rtc_lock); ++ ++ data -= 0x100; /* the first IRQ wasn't actually missed */ ++ ++ retval = put_user(data, (unsigned long *)buf); ++ if (!retval) ++ retval = sizeof(unsigned long); ++ ++out: ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&rtc_wait, &wait); ++ return retval; ++} ++ ++static int rtc_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct rtc_time tm, tm2; ++ ++ switch (cmd) { ++ case RTC_AIE_OFF: ++ spin_lock_irq(&rtc_lock); ++ RTSR &= ~RTSR_ALE; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ case RTC_AIE_ON: ++ spin_lock_irq(&rtc_lock); ++ RTSR |= RTSR_ALE; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ case RTC_UIE_OFF: ++ spin_lock_irq(&rtc_lock); ++ RTSR &= ~RTSR_HZE; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ case RTC_UIE_ON: ++ spin_lock_irq(&rtc_lock); ++ RTSR |= RTSR_HZE; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ case RTC_PIE_OFF: ++ spin_lock_irq(&rtc_lock); ++ OIER &= ~OIER_E1; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ case RTC_PIE_ON: ++ if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE)) ++ return -EACCES; ++ spin_lock_irq(&rtc_lock); ++ OSMR1 = TIMER_FREQ/rtc_freq + OSCR; ++ OIER |= OIER_E1; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ return 0; ++ case RTC_ALM_READ: ++ decodetime (RTAR, &tm); ++ break; ++ case RTC_ALM_SET: ++ if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2))) ++ return -EFAULT; ++ decodetime (RCNR, &tm); ++ if ((unsigned)tm2.tm_hour < 24) ++ tm.tm_hour = tm2.tm_hour; ++ if ((unsigned)tm2.tm_min < 60) ++ tm.tm_min = tm2.tm_min; ++ if ((unsigned)tm2.tm_sec < 60) ++ tm.tm_sec = tm2.tm_sec; ++ RTAR = mktime ( tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, ++ tm.tm_hour, tm.tm_min, tm.tm_sec); ++ return 0; ++ case RTC_RD_TIME: ++ decodetime (RCNR, &tm); ++ break; ++ case RTC_SET_TIME: ++ if (!capable(CAP_SYS_TIME)) ++ return -EACCES; ++ if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) ++ return -EFAULT; ++ tm.tm_year += 1900; ++ if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 || ++ tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + ++ (tm.tm_mon == 1 && is_leap(tm.tm_year))) || ++ (unsigned)tm.tm_hour >= 24 || ++ (unsigned)tm.tm_min >= 60 || ++ (unsigned)tm.tm_sec >= 60) ++ return -EINVAL; ++ RCNR = mktime ( tm.tm_year, tm.tm_mon + 1, tm.tm_mday, ++ tm.tm_hour, tm.tm_min, tm.tm_sec); ++ return 0; ++ case RTC_IRQP_READ: ++ return put_user(rtc_freq, (unsigned long *)arg); ++ case RTC_IRQP_SET: ++ if (arg < 1 || arg > TIMER_FREQ) ++ return -EINVAL; ++ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) ++ return -EACCES; ++ rtc_freq = arg; ++ return 0; ++ case RTC_EPOCH_READ: ++ return put_user (1970, (unsigned long *)arg); ++ default: ++ return -EINVAL; ++ } ++ return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; ++} ++ ++static struct file_operations rtc_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = rtc_read, ++ .poll = rtc_poll, ++ .ioctl = rtc_ioctl, ++ .open = rtc_open, ++ .release = rtc_release, ++ .fasync = rtc_fasync, ++}; ++ ++static struct miscdevice sa1100rtc_miscdev = { ++ .minor = RTC_MINOR, ++ .name = "rtc", ++ .fops = &rtc_fops ++}; ++ ++static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ char *p = page; ++ int len; ++ struct rtc_time tm; ++ ++ decodetime (RCNR, &tm); ++ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" ++ "rtc_date\t: %04d-%02d-%02d\n" ++ "rtc_epoch\t: %04d\n", ++ tm.tm_hour, tm.tm_min, tm.tm_sec, ++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1970); ++ decodetime (RTAR, &tm); ++ p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" ++ "alrm_date\t: %04d-%02d-%02d\n", ++ tm.tm_hour, tm.tm_min, tm.tm_sec, ++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); ++ p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR); ++ p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" ); ++ p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no"); ++ p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); ++ p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq); ++ ++ len = (p - page) - off; ++ if (len < 0) ++ len = 0; ++ ++ *eof = (len <= count) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++/* let's use the write interface for modifying RTTR */ ++static int rtc_write_proc(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ if (count > 15) ++ return -EINVAL; ++ if (count > 0) { ++ char lbuf[16]; ++ if (copy_from_user(lbuf, buffer, count)) ++ return -EFAULT; ++ lbuf[count] = 0; ++ RTTR = simple_strtoul(lbuf, NULL, 0); ++ } ++ return count; ++} ++ ++static int rtc_setup_interrupts(void) ++{ ++ int ret; ++ ++ ret = request_irq (IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL); ++ if (ret) { ++ printk (KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTC1Hz); ++ goto IRQ_RTC1Hz_failed; ++ } ++ ret = request_irq (IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL); ++ if (ret) { ++ printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTCAlrm); ++ goto IRQ_RTCAlrm_failed; ++ } ++ ret = request_irq (IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL); ++ if (ret) { ++ printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_OST1); ++ goto IRQ_OST1_failed; ++ } ++ ++ return 0; ++ ++IRQ_OST1_failed: ++ free_irq (IRQ_RTCAlrm, NULL); ++IRQ_RTCAlrm_failed: ++ free_irq (IRQ_RTC1Hz, NULL); ++IRQ_RTC1Hz_failed: ++ return ret; ++} ++ ++static void rtc_free_interrupts(void) ++{ ++ free_irq (IRQ_OST1, NULL); ++ free_irq (IRQ_RTCAlrm, NULL); ++ free_irq (IRQ_RTC1Hz, NULL); ++} ++ ++static struct pm_dev *rtc_pm_dev; ++ ++static int rtc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ static int suspended = 0; ++ switch (req) { ++ case PM_SUSPEND: /* Enter D1-D3 */ ++ disable_irq(IRQ_OST1); ++ disable_irq(IRQ_RTCAlrm); ++ disable_irq(IRQ_RTC1Hz); ++ suspended = 1; ++ break; ++ case PM_RESUME: /* Enter D0 */ ++ if ( suspended ) { ++ unsigned int rtsr = RTSR; ++ RTSR = 0; ++ RTSR = RTSR_HZ; ++ RTSR = rtsr & (RTSR_HZE|RTSR_ALE); ++ enable_irq(IRQ_OST1); ++ enable_irq(IRQ_RTCAlrm); ++ enable_irq(IRQ_RTC1Hz); ++ suspended = 0; ++ } ++ break; ++ } ++ return 0; ++} ++ ++static int __init rtc_init(void) ++{ ++ struct proc_dir_entry *entry; ++ int ret; ++ ++ misc_register (&sa1100rtc_miscdev); ++ entry = create_proc_entry ("driver/rtc", 0, 0); ++ if (entry) { ++ entry->read_proc = rtc_read_proc; ++ entry->write_proc = rtc_write_proc; ++ } ++ ret = rtc_setup_interrupts(); ++ if (ret) ++ goto IRQ_failed; ++ ++ printk (KERN_INFO "SA1100 Real Time Clock driver v" DRIVER_VERSION "\n"); ++ ++ /* ++ * According to the manual we should be able to let RTTR be zero ++ * and then a default diviser for a 32.768KHz clock is used. ++ * Apparently this doesn't work, at least for my SA1110 rev 5. ++ * If the clock divider is uninitialized then reset it to the ++ * default value to get the 1Hz clock. ++ */ ++ if (RTTR == 0) { ++ RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); ++ printk (KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); ++ /* The current RTC value probably doesn't make sense either */ ++ RCNR = 0; ++ } ++ ++ rtc_pm_dev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, rtc_pm_callback); ++ return 0; ++ ++IRQ_failed: ++ remove_proc_entry ("driver/rtc", NULL); ++ misc_deregister (&sa1100rtc_miscdev); ++ return ret; ++} ++ ++static void __exit rtc_exit(void) ++{ ++ pm_unregister(rtc_pm_dev); ++ rtc_free_interrupts(); ++ remove_proc_entry ("driver/rtc", NULL); ++ misc_deregister (&sa1100rtc_miscdev); ++} ++ ++module_init(rtc_init); ++module_exit(rtc_exit); ++ ++MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>"); ++MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(RTC_MINOR); +diff -Nurd linux-2.6.16.orig/drivers/char/snsc.c linux-2.6.16/drivers/char/snsc.c +--- linux-2.6.16.orig/drivers/char/snsc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/snsc.c 2006-06-03 11:14:55.267487320 +0200 +@@ -391,7 +391,8 @@ + format_module_id(devnamep, geo_module(geoid), + MODULE_FORMAT_BRIEF); + devnamep = devname + strlen(devname); +- sprintf(devnamep, "#%d", geo_slab(geoid)); ++ sprintf(devnamep, "^%d#%d", geo_slot(geoid), ++ geo_slab(geoid)); + + /* allocate sysctl device data */ + scd = kmalloc(sizeof (struct sysctl_data_s), +diff -Nurd linux-2.6.16.orig/drivers/char/sonypi.c linux-2.6.16/drivers/char/sonypi.c +--- linux-2.6.16.orig/drivers/char/sonypi.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/sonypi.c 2006-06-03 11:14:55.268487168 +0200 +@@ -1341,6 +1341,9 @@ + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; ++ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, ++ PCI_DEVICE_ID_INTEL_ICH7_1, NULL))) ++ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; + +diff -Nurd linux-2.6.16.orig/drivers/char/sram.c linux-2.6.16/drivers/char/sram.c +--- linux-2.6.16.orig/drivers/char/sram.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/char/sram.c 2006-06-03 11:14:56.299330456 +0200 +@@ -0,0 +1,194 @@ ++/* ++ * linux/drivers/char/sram.c ++ * ++ * Bulverde Internal Memory character device driver ++ * ++ * Created: Sep 05, 2003 ++ * Copyright: MontaVista Software 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/config.h> ++#include <linux/mm.h> ++#include <linux/major.h> ++#include <linux/miscdevice.h> ++#include <linux/vmalloc.h> ++#include <linux/mman.h> ++#include <linux/init.h> ++#include <linux/rwsem.h> ++ ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <asm/pgalloc.h> ++ ++#include <linux/devfs_fs_kernel.h> ++ ++static unsigned long sram_base = 0; ++static unsigned long sram_size = 0; ++ ++extern int sram_access_obtain(unsigned long *pmem, unsigned long *psize); ++extern int sram_access_release(unsigned long *pmem, unsigned long *psize); ++ ++/* ++ * This funcion reads the SRAM memory. ++ * The f_pos points to the SRAM memory location. ++ */ ++static ssize_t sram_read(struct file * file, char * buf, ++ size_t count, loff_t *ppos) { ++ unsigned long p = *ppos; ++ ssize_t read; ++ ++ if (p >= sram_size) ++ return 0; ++ ++ if (count > sram_size - p) ++ count = sram_size - p; ++ ++ read = 0; ++ ++ if (copy_to_user(buf, (char *)(sram_base + p), count)) ++ return -EFAULT; ++ ++ read += count; ++ *ppos += read; ++ ++ return read; ++} ++ ++static ssize_t sram_write(struct file * file, const char * buf, ++ size_t count, loff_t *ppos) { ++ unsigned long p = *ppos; ++ ssize_t written; ++ ++ if (p >= sram_size) ++ return 0; ++ ++ if (count > sram_size - p) ++ count = sram_size - p; ++ ++ written = 0; ++ ++ if (copy_from_user((char *)(sram_base + p), buf, count)) ++ return -EFAULT; ++ ++ written += count; ++ *ppos += written; ++ ++ return written; ++} ++ ++static int sram_mmap(struct file * file, struct vm_area_struct * vma) { ++ ++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; ++ ++ if (((file->f_flags & O_WRONLY) != 0) || ++ ((file->f_flags & O_RDWR) != 0)) { ++ vma->vm_page_prot = (pgprot_t)PAGE_SHARED; ++ } else { ++ vma->vm_page_prot = (pgprot_t)PAGE_READONLY; ++ } ++ ++ /* Do not cache SRAM memory if O_SYNC flag is set */ ++ if ((file->f_flags & O_SYNC) != 0) { ++ pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE; ++ } ++ ++ /* Don't try to swap out physical pages.. */ ++ vma->vm_flags |= VM_RESERVED | VM_LOCKED; ++ ++ if (remap_page_range(vma->vm_start, SRAM_MEM_PHYS + offset, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++ ++ ++static loff_t sram_lseek(struct file * file, loff_t offset, int orig) { ++ ++ switch (orig) { ++ case 0: ++ file->f_pos = offset; ++ break; ++ case 1: ++ file->f_pos += offset; ++ break; ++ case 2: ++ file->f_pos = SRAM_SIZE + offset; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (file->f_pos < 0) { ++ file->f_pos = 0; ++ } else if (file->f_pos > SRAM_SIZE) { ++ file->f_pos = SRAM_SIZE; ++ } ++ ++ return file->f_pos; ++} ++ ++static int sram_open(struct inode * inode, struct file * filp) { ++ return sram_access_obtain(&sram_base, &sram_size); ++} ++ ++static int sram_release(struct inode * inode, struct file * filp) { ++ return sram_access_release(&sram_base, &sram_size); ++} ++ ++ ++static struct file_operations sram_fops = { ++ llseek: sram_lseek, ++ read: sram_read, ++ write: sram_write, ++ mmap: sram_mmap, ++ open: sram_open, ++ release: sram_release, ++}; ++ ++static struct miscdevice sram_misc = { ++ minor : MISC_DYNAMIC_MINOR, ++ name : "misc/sram", ++ fops : &sram_fops, ++}; ++ ++static int __init sram_chr_init(void) { ++ if (misc_register(&sram_misc) != 0) ++ { ++ printk(KERN_ERR "Cannot register device /dev/%s\n", ++ sram_misc.name); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static void __exit sram_chr_exit(void) { ++ misc_deregister(&sram_misc); ++} ++ ++module_init(sram_chr_init) ++module_exit(sram_chr_exit) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("MontaVista Software Inc."); +diff -Nurd linux-2.6.16.orig/drivers/char/tipar.c linux-2.6.16/drivers/char/tipar.c +--- linux-2.6.16.orig/drivers/char/tipar.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/tipar.c 2006-06-03 11:14:55.269487016 +0200 +@@ -515,7 +515,7 @@ + err = PTR_ERR(tipar_class); + goto out_chrdev; + } +- if (parport_register_driver(&tipar_driver) || tp_count == 0) { ++ if (parport_register_driver(&tipar_driver)) { + printk(KERN_ERR "tipar: unable to register with parport\n"); + err = -EIO; + goto out_class; +diff -Nurd linux-2.6.16.orig/drivers/char/tlclk.c linux-2.6.16/drivers/char/tlclk.c +--- linux-2.6.16.orig/drivers/char/tlclk.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/tlclk.c 2006-06-03 11:14:55.269487016 +0200 +@@ -327,7 +327,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(received_ref_clk3a, S_IWUGO, NULL, ++static DEVICE_ATTR(received_ref_clk3a, (S_IWUSR|S_IWGRP), NULL, + store_received_ref_clk3a); + + +@@ -349,7 +349,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(received_ref_clk3b, S_IWUGO, NULL, ++static DEVICE_ATTR(received_ref_clk3b, (S_IWUSR|S_IWGRP), NULL, + store_received_ref_clk3b); + + +@@ -371,7 +371,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(enable_clk3b_output, S_IWUGO, NULL, ++static DEVICE_ATTR(enable_clk3b_output, (S_IWUSR|S_IWGRP), NULL, + store_enable_clk3b_output); + + static ssize_t store_enable_clk3a_output(struct device *d, +@@ -392,7 +392,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(enable_clk3a_output, S_IWUGO, NULL, ++static DEVICE_ATTR(enable_clk3a_output, (S_IWUSR|S_IWGRP), NULL, + store_enable_clk3a_output); + + static ssize_t store_enable_clkb1_output(struct device *d, +@@ -413,7 +413,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(enable_clkb1_output, S_IWUGO, NULL, ++static DEVICE_ATTR(enable_clkb1_output, (S_IWUSR|S_IWGRP), NULL, + store_enable_clkb1_output); + + +@@ -435,7 +435,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(enable_clka1_output, S_IWUGO, NULL, ++static DEVICE_ATTR(enable_clka1_output, (S_IWUSR|S_IWGRP), NULL, + store_enable_clka1_output); + + static ssize_t store_enable_clkb0_output(struct device *d, +@@ -456,7 +456,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(enable_clkb0_output, S_IWUGO, NULL, ++static DEVICE_ATTR(enable_clkb0_output, (S_IWUSR|S_IWGRP), NULL, + store_enable_clkb0_output); + + static ssize_t store_enable_clka0_output(struct device *d, +@@ -477,7 +477,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(enable_clka0_output, S_IWUGO, NULL, ++static DEVICE_ATTR(enable_clka0_output, (S_IWUSR|S_IWGRP), NULL, + store_enable_clka0_output); + + static ssize_t store_select_amcb2_transmit_clock(struct device *d, +@@ -519,7 +519,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(select_amcb2_transmit_clock, S_IWUGO, NULL, ++static DEVICE_ATTR(select_amcb2_transmit_clock, (S_IWUSR|S_IWGRP), NULL, + store_select_amcb2_transmit_clock); + + static ssize_t store_select_amcb1_transmit_clock(struct device *d, +@@ -560,7 +560,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(select_amcb1_transmit_clock, S_IWUGO, NULL, ++static DEVICE_ATTR(select_amcb1_transmit_clock, (S_IWUSR|S_IWGRP), NULL, + store_select_amcb1_transmit_clock); + + static ssize_t store_select_redundant_clock(struct device *d, +@@ -581,7 +581,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(select_redundant_clock, S_IWUGO, NULL, ++static DEVICE_ATTR(select_redundant_clock, (S_IWUSR|S_IWGRP), NULL, + store_select_redundant_clock); + + static ssize_t store_select_ref_frequency(struct device *d, +@@ -602,7 +602,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(select_ref_frequency, S_IWUGO, NULL, ++static DEVICE_ATTR(select_ref_frequency, (S_IWUSR|S_IWGRP), NULL, + store_select_ref_frequency); + + static ssize_t store_filter_select(struct device *d, +@@ -623,7 +623,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(filter_select, S_IWUGO, NULL, store_filter_select); ++static DEVICE_ATTR(filter_select, (S_IWUSR|S_IWGRP), NULL, store_filter_select); + + static ssize_t store_hardware_switching_mode(struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +@@ -643,7 +643,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(hardware_switching_mode, S_IWUGO, NULL, ++static DEVICE_ATTR(hardware_switching_mode, (S_IWUSR|S_IWGRP), NULL, + store_hardware_switching_mode); + + static ssize_t store_hardware_switching(struct device *d, +@@ -664,7 +664,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(hardware_switching, S_IWUGO, NULL, ++static DEVICE_ATTR(hardware_switching, (S_IWUSR|S_IWGRP), NULL, + store_hardware_switching); + + static ssize_t store_refalign (struct device *d, +@@ -684,7 +684,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(refalign, S_IWUGO, NULL, store_refalign); ++static DEVICE_ATTR(refalign, (S_IWUSR|S_IWGRP), NULL, store_refalign); + + static ssize_t store_mode_select (struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +@@ -704,7 +704,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(mode_select, S_IWUGO, NULL, store_mode_select); ++static DEVICE_ATTR(mode_select, (S_IWUSR|S_IWGRP), NULL, store_mode_select); + + static ssize_t store_reset (struct device *d, + struct device_attribute *attr, const char *buf, size_t count) +@@ -724,7 +724,7 @@ + return strnlen(buf, count); + } + +-static DEVICE_ATTR(reset, S_IWUGO, NULL, store_reset); ++static DEVICE_ATTR(reset, (S_IWUSR|S_IWGRP), NULL, store_reset); + + static struct attribute *tlclk_sysfs_entries[] = { + &dev_attr_current_ref.attr, +@@ -767,6 +767,7 @@ + printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major); + return ret; + } ++ tlclk_major = ret; + alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL); + if (!alarm_events) + goto out1; +diff -Nurd linux-2.6.16.orig/drivers/char/tty_io.c linux-2.6.16/drivers/char/tty_io.c +--- linux-2.6.16.orig/drivers/char/tty_io.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/char/tty_io.c 2006-06-03 11:14:56.301330152 +0200 +@@ -2706,7 +2706,11 @@ + } + task_lock(p); + if (p->files) { +- rcu_read_lock(); ++ /* ++ * We don't take a ref to the file, so we must ++ * hold ->file_lock instead. ++ */ ++ spin_lock(&p->files->file_lock); + fdt = files_fdtable(p->files); + for (i=0; i < fdt->max_fds; i++) { + filp = fcheck_files(p->files, i); +@@ -2721,7 +2725,7 @@ + break; + } + } +- rcu_read_unlock(); ++ spin_unlock(&p->files->file_lock); + } + task_unlock(p); + } while_each_task_pid(session, PIDTYPE_SID, p); +@@ -2772,6 +2776,14 @@ + goto out; + } + spin_lock_irqsave(&tty->buf.lock, flags); ++#if defined(CONFIG_EZX_A780) || defined(CONFIG_ARCH_EZX_E680) ++ if (tty && tty->driver.btuart && ++ ((N_TTY_BUF_SIZE - tty->read_cnt - 2) < (512 + 128))) { ++ schedule_delayed_work(&tty->flip.work, 1); ++ return; ++ } ++#endif ++ + while((tbuf = tty->buf.head) != NULL) { + while ((count = tbuf->commit - tbuf->read) != 0) { + char_buf = tbuf->char_buf_ptr + tbuf->read; +diff -Nurd linux-2.6.16.orig/drivers/dpm/dpm.c linux-2.6.16/drivers/dpm/dpm.c +--- linux-2.6.16.orig/drivers/dpm/dpm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/dpm/dpm.c 2006-06-03 11:14:55.899391256 +0200 +@@ -0,0 +1,1117 @@ ++/* ++ * drivers/dpm/policy.c Dynamic Power Management Policies ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, International Business Machines Corporation ++ * All Rights Reserved ++ * ++ * Robert Paulsen ++ * IBM Linux Technology Center ++ * rpaulsen@us.ibm.com ++ * August, 2002 ++ * ++ */ ++ ++/* TODO: ++ ++ Rethink init/enable/disable: It may be redundant and/or unsafe ++ Fix initialization and stats ++*/ ++ ++#include <linux/dpm.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/delay.h> ++#include <linux/preempt.h> ++ ++#include <asm/semaphore.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#undef TRACE ++#if defined(TRACE) ++#define trace(args...) do { printk("TRACE: "); printk(args); } while(0) ++#else ++#define trace(args...) do {} while(0) ++#endif ++ ++struct dpm_md dpm_md; ++ ++static struct dpm_opt nop_op = { ++ .name = "[nop]", ++ .flags = DPM_OP_NOP, ++}; ++ ++extern void dpm_force_off_constrainers(struct dpm_opt *opt); ++ ++unsigned long dpm_compute_lpj(unsigned long ref, u_int div, u_int mult) ++{ ++ unsigned long new_jiffy_l, new_jiffy_h; ++ ++ /* ++ * Recalculate loops_per_jiffy. We do it this way to ++ * avoid math overflow on 32-bit machines. Maybe we ++ * should make this architecture dependent? If you have ++ * a better way of doing this, please replace! ++ * ++ * new = old * mult / div ++ */ ++ new_jiffy_h = ref / div; ++ new_jiffy_l = (ref % div) / 100; ++ new_jiffy_h *= mult; ++ new_jiffy_l = new_jiffy_l * mult / div; ++ ++ return new_jiffy_h + new_jiffy_l * 100; ++} ++ ++/**************************************************************************** ++ ++DPM Synchronization and Operating Point Changes ++=============================================== ++ ++There are 2 aspects to synchronization in DPM: First, the usual requirement of ++serializing access to shared data structures, and second, the idea of ++synchronizing the operating point and the current operating state. The second ++condition arises because setting an operating point may complete asynchronously ++for a number of reasons, whereas the operating state change that causes the ++operating point change succeeds immediately. ++ ++Access to most of the global variables representing the current state of DPM ++and the current policy are protected by a spinlock, dpm_policy_lock. The use ++of this lock appears in only a few critical places. ++ ++Setting the operating point, reading the value of the current operating point ++or changing the current policy may only be done while holding the semaphore ++_dpm_lock. Access to the _dpm_lock is abstracted by the dpm_lock() and ++dpm_unlock() calls as explained below. (The semaphore should only be accessed ++this way to simplify future development). ++ ++The _dpm_lock must be held (by a call to a dpm_lock function) by any caller of ++the interfaces that set the operating point, change the policy, or enable or ++disable DPM. Note that the corresponding call to dpm_unlock() may be ++explicitly required, or implicit (see dpm_set_opt_async() below). ++ ++For simplicity, the calls that create operating points and policies also use ++dpm_lock() and dpm_unlock() to protect access to the non-active policies as ++well. Since these are normally initialization calls, this should not interfere ++with the operation of the system once initialized. ++ ++Three interfaces are provided for obtaining the _dpm_lock: ++ ++void dpm_lock(); ++int dpm_lock_interruptible(); ++int dpm_trylock(); ++ ++dpm_lock_interruptible() returns -ERESTARTSYS if the wait for the _dpm_lock was ++interrupted, and dpm_trylock() returns -EBUSY if the semaphore is currently ++held. ++ ++Once the _dpm_lock is held, two interfaces are provided for setting the ++operating point: ++ ++int dpm_set_opt_async() ++int dpm_set_opt_sync(); ++ ++Neither of these interfaces takes parameters since under DPM the operating ++point to select is always implied by the current policy and operating state. ++If the system is already at the correct operating point then no change is ++required or made. To avoid deadlock, the caller must not be holding the ++dpm_policy_lock when either of these calls is made. ++ ++dpm_set_opt_async() launches a change in the operating point that will ++potentially terminate asynchronously. This interface never blocks the caller, ++thus there is no guarantee that the system is actually running at the implied ++operating point when control returns to the caller. This call is used by ++dpm_set_os() during an operating state change. Note since this call terminates ++asynchronously, the call to dpm_unlock() is implicitly made when the operating ++point change is complete. I.e., the caller obtains the _dpm_lock with ++dpm_lock(), calls dpm_set_opt_async(), then continues. ++ ++dpm_set_opt_sync() launches a synchronous change in the operating point. This ++call will block the caller as necessary during the call, thus it can only be ++issued from a process context. When control returns to the caller, the caller ++can be sure that the implied operating point was set, and that the system is ++currently running at the correct operating point for the given policy and ++operating state. This call is used by dpm_set_policy() and the device ++constraint update code to guarantee that the change to a new policy, or changes ++to operating point classes as a result of device constraits are reflected in ++the operating point. ++ ++Note that regardless of whether an operating point change is synchrounous or ++asynchronous, it is still possible that the operating state may change during ++the call. Setting the operating point is (currently) not preemptible, ++therefore at the time that the operating point change is complete, it may no ++longer be the correct operating point for the operating state. This condition ++is always handled by the dpm_set_opt*() routines, which will launch a tasklet ++to re-synchronize the operating point to the operating state. ++ ++It is possible that due to poorly designed policies and asynchronous ++termination of operating point changes that the operating point will always lag ++behind the operating state. This is only a performance issue, not a ++correctness issue. Since a valid policy has a valid operating point for every ++operating state, and changes to the policy and changes in devices constraints ++always use dpm_set_opt_sync(), there will never be a case where the current ++operating point does not support device constraints. ++ ++****************************************************************************/ ++ ++/* curently installed policies and operating points */ ++LIST_HEAD(dpm_policies); ++LIST_HEAD(dpm_classes); ++LIST_HEAD(dpm_opts); ++ ++DECLARE_MUTEX(_dpm_lock); ++spinlock_t dpm_policy_lock = SPIN_LOCK_UNLOCKED; ++ ++/* the currently active policy */ ++struct dpm_policy *dpm_active_policy; ++ ++/* the currently active operating state, class, and operating point */ ++dpm_state_t dpm_active_state = DPM_NO_STATE; ++struct dpm_opt *dpm_active_opt; ++struct dpm_class *dpm_active_class; ++ ++/* is DPM initialized and enabled? */ ++int dpm_enabled; ++int dpm_initialized; ++ ++#ifdef CONFIG_DPM_STATS ++#include <asm/div64.h> ++ ++struct dpm_stats dpm_state_stats[DPM_STATES]; ++ ++/* ++ * Start counting DPM stats from the time DPM was enabled... in the case of ++ * operating states the stats are updated from the time userspace is started. ++ */ ++ ++void ++dpm_stats_reset(void) ++{ ++ int i; ++ ++ preempt_disable(); ++ for (i = 0; i < DPM_STATES; i++) { ++ dpm_state_stats[i].total_time = 0; ++ dpm_state_stats[i].start_time = 0; ++ dpm_state_stats[i].count = 0; ++ } ++ ++ if (dpm_active_state != DPM_NO_STATE) { ++ dpm_state_stats[dpm_active_state].start_time = dpm_time(); ++ dpm_state_stats[dpm_active_state].count = 1; ++ } ++ ++ preempt_enable(); ++} ++ ++ ++unsigned long long ++dpm_update_stats(struct dpm_stats *new, struct dpm_stats *old) ++{ ++ unsigned long long now = dpm_time(); ++ ++ if (old) ++ old->total_time += now - old->start_time; ++ ++ if (new) { ++ new->start_time = now; ++ new->count += 1; ++ } ++ ++ return now; ++} ++#else ++#define dpm_update_stats(a,b) do {} while (0) ++#define dpm_stats_reset() do {} while (0) ++#endif /* CONFIG_DPM_STATS */ ++ ++struct dpm_opt * ++dpm_choose_opt(struct dpm_policy *policy, int state) ++{ ++ struct dpm_opt *opt = NULL; ++ ++ if (policy->classopt[state].opt) { ++ opt = policy->classopt[state].opt; ++ ++ if (opt->flags & DPM_OP_FORCE) ++ dpm_force_off_constrainers(opt); ++ else if (! dpm_check_constraints(opt)) ++ opt = NULL; ++ ++ dpm_active_class = NULL; ++ } ++ else { ++ int i; ++ ++ for (i = 0; i < policy->classopt[state].class->nops; i++) { ++ if (dpm_check_constraints( ++ policy->classopt[state].class->ops[i])) { ++ opt = policy->classopt[state].class->ops[i]; ++ break; ++ } ++ } ++ ++ dpm_active_class = policy->classopt[state].class; ++ } ++ ++ return opt; ++} ++ ++ ++ ++/***************************************************************************** ++ * dpm_next_opt() returns the operating point that needs to be activated next, ++ * or NULL if the operating point is up-to-date or the DPM system is disabled. ++ * Since this call looks at the value of the current operating point, it can ++ * only be made when the _dpm_lock is held. ++ *****************************************************************************/ ++ ++static inline struct dpm_opt * ++dpm_next_opt(void) ++{ ++ struct dpm_opt *opt = NULL; ++ ++ if (! spin_trylock(&dpm_policy_lock)) ++ return NULL; ++ if (dpm_enabled && dpm_active_state != DPM_NO_STATE) { ++ opt = dpm_choose_opt(dpm_active_policy,dpm_active_state); ++ if (opt == dpm_active_opt) ++ opt = NULL; ++ } ++ spin_unlock(&dpm_policy_lock); ++ return opt; ++} ++ ++/***************************************************************************** ++ * Set the operating point implied by the current DPM policy. These calls can ++ * only be made while holding _dpm_lock, and the release of ++ * _dpm_lock is implied by the call (see below). ++ *****************************************************************************/ ++ ++static struct dpm_opt temp_opt = { name : "[System Operating Point]" }; ++ ++int ++dpm_set_opt(struct dpm_opt *new, unsigned flags) ++{ ++ int error; ++ ++ if (new->flags & DPM_OP_NOP) { ++ if (flags & DPM_UNLOCK) ++ dpm_unlock(); ++ return 0; ++ } ++ ++ /* Support for setting the operating point when DPM is not running, and ++ setting the first operating point. */ ++ ++ if (!dpm_enabled || !dpm_active_opt) { ++ if (dpm_md_get_opt(&temp_opt)) { ++ printk(KERN_ERR "dpm_default_set_opt: " ++ "DPM disabled and system " ++ "operating point is illegal!\n"); ++ ++ if (flags & DPM_UNLOCK) ++ dpm_unlock(); ++ return -EINVAL; ++ } ++ dpm_active_opt = &temp_opt; ++ dpm_active_class = NULL; ++ } ++ ++ /* ++ * Remove the IRQ disable since in some cases scheduling is needed ++ * to set an operating point (only sleep mode). The spinlock ++ * should suffice. If the machine-dependent code needs interrupts ++ * turned off during the code used for that platform for that ++ * operating point set sequence then IRQs will need to be disabled ++ * in that code instead. ++ */ ++ error = dpm_md.set_opt(dpm_active_opt, new); ++ ++ if (error == 0) { ++ dpm_update_stats(&new->stats, &dpm_active_opt->stats); ++ dpm_active_opt = new; ++ mb(); ++ } ++ ++ if (flags & DPM_UNLOCK) ++ dpm_unlock(); ++ ++ return error; ++} ++ ++/***************************************************************************** ++ * Set operating point asynchronously. The _dpm_lock will be cleared whenever ++ * the change in operating point is complete. ++ *****************************************************************************/ ++ ++int ++dpm_set_opt_async(void) ++{ ++ struct dpm_opt *opt = dpm_next_opt(); ++ ++ if (opt) { ++ dpm_trace(DPM_TRACE_SET_OPT_ASYNC, opt); ++ return dpm_set_opt(opt, DPM_UNLOCK); ++ } else { ++ dpm_trace(DPM_TRACE_SET_OPT_ASYNC, NULL); ++ dpm_unlock(); ++ return 0; ++ } ++} ++ ++/***************************************************************************** ++ * Set operating point synchronously. The caller must clear _dpm_lock after the ++ * call returns. ++ *****************************************************************************/ ++ ++int ++dpm_set_opt_sync(void) ++{ ++ struct dpm_opt *opt = dpm_next_opt(); ++ ++ if (opt) { ++ dpm_trace(DPM_TRACE_SET_OPT_SYNC, opt); ++ return dpm_set_opt(opt, DPM_SYNC); ++ } else ++ dpm_trace(DPM_TRACE_SET_OPT_SYNC, NULL); ++ return 0; ++} ++ ++/***************************************************************************** ++ * Resynchronize the operating state and the operating point without ++ * blocking. If we don't get the lock it doesn't matter, since whenever the ++ * lock holder releases the lock the resynchronization will be tried again. ++ *****************************************************************************/ ++ ++static inline void ++dpm_resync(void) ++{ ++ ++ dpm_trace(DPM_TRACE_RESYNC); ++ if (! dpm_trylock()) ++ dpm_set_opt_async(); ++} ++ ++void ++dpm_resync_task(unsigned long ignore) ++{ ++ dpm_resync(); ++} ++ ++/***************************************************************************** ++ * unlock the DPM ++ * ++ * If the operating point and operating state are not in sync when _dpm_lock is ++ * released, a tasklet is launched to resynchronize them. A tasklet is used ++ * rather than simply calling dpm_set_op directly to avoid deep recursions. ++ * (I'm not sure this has worked, though). ++ * ++ * (The locking functions are inline in dpm_policy.h) ++ * ++ * This is not static since it needs to be called from dpm_policy.c ++ *****************************************************************************/ ++ ++DECLARE_TASKLET(dpm_resync_tasklet, dpm_resync_task, 0); ++ ++void ++dpm_unlock(void) ++{ ++ int retry; ++ ++ retry = dpm_next_opt() != NULL; ++ dpm_trace(DPM_TRACE_UNLOCK, retry); ++ up(&_dpm_lock); ++ if (retry) ++ tasklet_schedule(&dpm_resync_tasklet); ++} ++ ++/***************************************************************************** ++ * Enter a new operating state for statistical purposes. Returns 1 if the new ++ * state may require a change in operating point and 0 otherwise. ++ * ++ * The normal case that occurs during task scheduling, where we go from task ++ * state to task state, is quickly ignored, as are changes to the ++ * DPM_NO_STATE and changes when DPM is not running. Otherwise, ++ * dpm_enter_state() has advertised that we are in a new state, and indicates ++ * whether an operating point change is required. ++ * ++ * Note the system invariant that the operating point always eventually ++ * catches up with changes to the operating state. This is what makes it ++ * correct here to check for common operating points. We know ++ * that if a common operating point is not the current operating point, it ++ * will be soon. ++ * ++ * The 'quick' variant (in dpm.h) is called out separately to reduce latency ++ * for critical operating state changes where the following are known: 1) The ++ * dpm_policy_lock is held and/or interrupts are properly disabled. 2) DPM is ++ * enabled. 3) The new state is neither DPM_NO_STATE nor the same as the ++ * active state. 4) Any operating point change is being handled elsewhere. ++ *****************************************************************************/ ++ ++static int ++dpm_enter_state(int new_state) ++{ ++ int ret = 0; ++ ++ if (! spin_trylock(&dpm_policy_lock)) { ++ dpm_quick_enter_state(new_state); ++ return 0; ++ } ++ ++ if ((new_state == dpm_active_state) || ++ (new_state == DPM_NO_STATE) || ++ !dpm_enabled) { ++ spin_unlock(&dpm_policy_lock); ++ return ret; ++ } ++ ++ if ((dpm_active_policy->classopt[new_state].class != ++ dpm_active_policy->classopt[dpm_active_state].class) || ++ (dpm_active_policy->classopt[new_state].opt != ++ dpm_active_policy->classopt[dpm_active_state].opt)) ++ ret = 1; ++ ++ dpm_quick_enter_state(new_state); ++ spin_unlock(&dpm_policy_lock); ++ return ret; ++} ++ ++ ++/***************************************************************************** ++ * set operating state ++ * ++ * This is used by the kernel to inform the DPM that the operating state has ++ * changed and that a new operating point should (possibly) be set as a ++ * result. ++ * ++ * If an operating point change is required it is attempted. If we can't get ++ * the lock here, then the operating point change will be activated when the ++ * current lock holder releases the lock. ++ *****************************************************************************/ ++ ++void ++dpm_set_os(dpm_state_t new_state) ++{ ++ dpm_trace(DPM_TRACE_SET_OS, new_state); ++ if (dpm_enter_state(new_state)) ++ dpm_resync(); ++} ++ ++EXPORT_SYMBOL(dpm_set_os); ++ ++/***************************************************************************** ++ * initialize the DPM ++ *****************************************************************************/ ++int ++dynamicpower_init(void) ++{ ++ trace("in dynamicpower_init\n"); ++ ++ if (dpm_initialized) { ++ trace("DPM already initialized"); ++ return -EALREADY; ++ } ++ ++ /* mutex-style semaphore for access to policies and opts */ ++ init_MUTEX(&_dpm_lock); ++ ++ dpm_active_policy = 0; /* this leaves the DPM temporarily ++ disabled until a policy is ++ activated */ ++ dpm_enabled = 0; ++ dpm_initialized = 1; ++ dpm_active_state = DPM_TASK_STATE; ++ ++ ++ trace("DPM is now initialized\n"); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * (temporarily) disable the DPM ++ *****************************************************************************/ ++int ++dynamicpower_disable(void) ++{ ++ ++ trace("in dynamicpower_disable\n"); ++ ++ if (! dpm_enabled) { ++ trace("DPM already disabled"); ++ return -EALREADY; ++ } ++ ++ dpm_lock(); ++ ++ dpm_enabled = 0; ++ dpm_md_cleanup(); ++ dpm_active_opt = NULL; ++ dpm_active_class = NULL; ++ ++ dpm_unlock(); ++ ++ trace("DPM is now disabled\n"); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * re-enable the DPM ++ * dpm_enabled = 1 implies that DPM is initialized and there is an active ++ * policy. The 'enable' call is really designed to be used after a temporary ++ * 'disable'. All that's required to start DPM is to initialize it and set a ++ * policy. ++ *****************************************************************************/ ++ ++/* Need to think through enable/disable */ ++ ++int ++dynamicpower_enable(void) ++{ ++ ++ trace("in dynamicpower_enable\n"); ++ ++ if (dpm_enabled) { ++ trace("DPM already enabled"); ++ return -EALREADY; ++ } ++ ++ dpm_lock(); ++ ++ if (dpm_active_policy) { ++ dpm_enabled = 1; ++ mb(); ++ dpm_md_startup(); ++ dpm_stats_reset(); ++ dpm_set_opt_sync(); ++ trace("DPM is now enabled\n"); ++ } else { ++ trace("No active policy, dpm_enable is ignored\n"); ++ } ++ ++ dpm_unlock(); ++ return 0; ++} ++ ++/***************************************************************************** ++ * Suspend/Resume DPM ++ * The current operating point is saved and restored. This ++ * interface is designed to be used by system suspend/resume code, to safely ++ * save/restore the DPM operating point across a system power-down, where the ++ * firmware may resume the system at a random operating point. This does not ++ * require DPM to be enabled. Note that DPM remains locked across the ++ * suspend/resume. ++ *****************************************************************************/ ++ ++static struct dpm_opt suspend_opt = { name : "[Suspended Op. Point]" }; ++struct dpm_opt *suspended_opt; ++ ++int ++dynamicpm_suspend(void) ++{ ++ int err; ++ ++ trace("in dpm_suspend\n"); ++ ++ dpm_lock(); ++ ++ if (dpm_enabled && dpm_active_opt) { ++ suspended_opt = dpm_active_opt; ++ } else { ++ suspended_opt = &suspend_opt; ++ if ((err = dpm_md_get_opt(suspended_opt))) { ++ printk(KERN_CRIT ++ "DPM can not suspend the current op. point!\n"); ++ suspended_opt = NULL; ++ return err; ++ } ++ } ++ return 0; ++} ++ ++void ++dynamicpm_resume(void) ++{ ++ trace("in dpm_resume\n"); ++ ++ if (suspended_opt) { ++ dpm_active_opt = NULL; /* Force reinitialization of DPM */ ++ dpm_active_class = NULL; ++ dpm_set_opt(suspended_opt, DPM_SYNC); ++ suspended_opt = NULL; ++ } ++ dpm_unlock(); ++} ++ ++ ++/***************************************************************************** ++ * Create a named operating point ++ * The alternate entry point can be used to create anonymous operating points ++ *****************************************************************************/ ++ ++int ++_dpm_create_opt(struct dpm_opt **p, const char *name, ++ const dpm_md_pp_t * md_pp, int npp) ++{ ++ struct dpm_opt *opt; ++ int ret; ++ ++ /* get memory for opt */ ++ if (! ++ (opt = ++ (struct dpm_opt *) kmalloc(sizeof (struct dpm_opt), GFP_KERNEL))) { ++ return -ENOMEM; ++ } ++ trace("%s @ 0x%08lx\n", name, (unsigned long)opt); ++ memset(opt, 0, sizeof(struct dpm_opt)); ++ if (!(opt->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL))) { ++ kfree(opt); ++ return -ENOMEM; ++ } ++ ++ /* initialize and validate the opt */ ++ strcpy(opt->name, name); ++ memcpy(&opt->pp, md_pp, npp * sizeof(dpm_md_pp_t)); ++ ret = dpm_md_init_opt(opt); ++ if (ret) { ++ kfree(opt->name); ++ kfree(opt); ++ return ret; ++ } ++ INIT_LIST_HEAD(&opt->list); ++ *p = opt; ++ dpm_sysfs_new_op(opt); ++ return 0; ++} ++ ++int ++dpm_create_opt(const char *name, const dpm_md_pp_t * md_pp, int npp) ++{ ++ int ret; ++ struct dpm_opt *opt; ++ ++ trace("in dpm_create_opt for \"%s\"\n", name); ++ ++ dpm_lock(); ++ ++ /* ensure name is unique */ ++ list_find(opt, name, dpm_opts, struct dpm_opt); ++ if (opt) { ++ dpm_unlock(); ++ return -EEXIST; ++ } ++ ++ /* create the opt */ ++ ret = _dpm_create_opt(&opt, name, md_pp, npp); ++ ++ /* add opt to our list */ ++ if (!ret) ++ list_add(&opt->list, &dpm_opts); ++ ++ dpm_unlock(); ++ return ret; ++} ++ ++/***************************************************************************** ++ * destroy an operating point ++ * Assumes _dpm_lock is held and the opt is no longer needed *anywhere* ++ *****************************************************************************/ ++void ++destroy_opt(struct dpm_opt *opt) ++{ ++ dpm_sysfs_destroy_op(opt); ++ list_del(&opt->list); ++ kfree(opt->name); ++ kfree(opt); ++} ++ ++/***************************************************************************** ++ * create a named class of operating points (to be used to map to an operating ++ * state) ++ *****************************************************************************/ ++ ++int ++dpm_create_class(const char *name, char **op_names, unsigned nops) ++{ ++ int i; ++ struct dpm_class *cls; ++ ++ trace("in dpm_create_class for \"%s\"\n", name); ++ ++ dpm_lock(); ++ ++ /* ensure class is not empty */ ++ if (nops == 0) { ++ dpm_unlock(); ++ return -EINVAL; ++ } ++ ++ /* ensure name is unique */ ++ list_find(cls, name, dpm_classes, struct dpm_class); ++ if (cls) { ++ dpm_unlock(); ++ return -EEXIST; ++ } ++ ++ /* get memory for class */ ++ cls = (struct dpm_class *) kmalloc(sizeof (struct dpm_class), GFP_KERNEL); ++ if (!cls) { ++ dpm_unlock(); ++ return -ENOMEM; ++ } ++ trace("%s @ 0x%08lx\n", name, (unsigned long)cls); ++ memset(cls, 0, sizeof (struct dpm_class)); ++ /* get memory for array of pointers to operating points */ ++ cls->ops = ++ (struct dpm_opt **) kmalloc(nops * sizeof (struct dpm_opt *), ++ GFP_KERNEL); ++ if (!cls->ops) { ++ kfree(cls); ++ dpm_unlock(); ++ return -ENOMEM; ++ } ++ ++ /* get memory for class name */ ++ cls->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL); ++ if (!cls->name) { ++ kfree(cls->ops); ++ kfree(cls); ++ dpm_unlock(); ++ return -ENOMEM; ++ } ++ ++ /* find named op points and put their pointers in the class */ ++ for (i = 0; i < nops; ++i) { ++ struct dpm_opt *opt; ++ list_find(opt, op_names[i], dpm_opts, struct dpm_opt); ++ if (!opt) { ++ kfree(cls->name); ++ kfree(cls->ops); ++ kfree(cls); ++ dpm_unlock(); ++ return -ENOENT; ++ } ++ cls->ops[i] = opt; ++ } ++ strcpy(cls->name, name); ++ cls->nops = nops; ++ /* add class to our list */ ++ list_add(&cls->list, &dpm_classes); ++ ++ dpm_unlock(); ++ dpm_sysfs_new_class(cls); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * destroy a class ++ * Assumes _dpm_lock is held and the class is no longer needed *anywhere* ++ *****************************************************************************/ ++void ++destroy_class(struct dpm_class *cls) ++{ ++ dpm_sysfs_destroy_class(cls); ++ list_del(&cls->list); ++ kfree(cls->ops); ++ kfree(cls->name); ++ kfree(cls); ++} ++ ++int ++dpm_map_policy_state(struct dpm_policy *policy, int state, char *classopt) ++{ ++ list_find(policy->classopt[state].opt, classopt, dpm_opts, ++ struct dpm_opt); ++ ++ if(!policy->classopt[state].opt) { ++ list_find(policy->classopt[state].class, classopt, ++ dpm_classes, struct dpm_class); ++ if(!policy->classopt[state].class) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * create power policy ++ *****************************************************************************/ ++int ++dpm_create_policy(const char *name, char **classopt_names, int nopts) ++{ ++ int i; ++ struct dpm_policy *policy; ++ ++ trace("in dpm_install_policy for \"%s\" policy\n", name); ++ ++ dpm_lock(); ++ ++ /* ensure unique name */ ++ list_find(policy, name, dpm_policies, struct dpm_policy); ++ if (policy) { ++ dpm_unlock(); ++ return -EEXIST; ++ } ++ ++ /* get memory for policy */ ++ policy = ++ (struct dpm_policy *) kmalloc(sizeof (struct dpm_policy), ++ GFP_KERNEL); ++ if (!policy) { ++ dpm_unlock(); ++ return -ENOMEM; ++ } ++ trace("%s @ 0x%08lx\n", name, (unsigned long)policy); ++ memset(policy, 0, sizeof (struct dpm_policy)); ++ /* get memory for policy name */ ++ policy->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL); ++ if (!policy->name) { ++ kfree(policy); ++ dpm_unlock(); ++ return -ENOMEM; ++ } ++ ++ /* initialize the policy */ ++ for (i = 0; i < DPM_STATES; ++i) { ++ if ((i >= nopts) || !classopt_names[i]) { ++ policy->classopt[i].opt = &nop_op; ++ } else { ++ if (dpm_map_policy_state(policy, i, classopt_names[i]) ++ < 0) { ++ kfree(policy->name); ++ kfree(policy); ++ dpm_unlock(); ++ return -ENOENT; ++ } ++ } ++ } ++ strcpy(policy->name, name); ++ ++ /* add policy to our list */ ++ list_add(&policy->list, &dpm_policies); ++ dpm_sysfs_new_policy(policy); ++ trace("installed \"%s\" policy\n", name); ++ dpm_unlock(); ++ return 0; ++} ++ ++/***************************************************************************** ++ * destroy a power policy ++ * Assumes _dpm_lock is held and the policy is no longer needed *anywhere* ++ *****************************************************************************/ ++void ++destroy_policy(struct dpm_policy *policy) ++{ ++ dpm_sysfs_destroy_policy(policy); ++ list_del(&policy->list); ++ kfree(policy->name); ++ kfree(policy); ++} ++ ++/***************************************************************************** ++ * uninstall power policy ++ *****************************************************************************/ ++int ++dpm_destroy_policy(const char *name) ++{ ++ struct dpm_policy *policy; ++ ++ trace("processing destroy request for \"%s\"\n", name); ++ ++ dpm_lock(); ++ ++ /* find the named policy */ ++ list_find(policy, name, dpm_policies, struct dpm_policy); ++ if (!policy) { ++ dpm_unlock(); ++ return -ENOENT; ++ } ++ ++ /* can't uninstall active policy */ ++ if (policy == dpm_active_policy) { ++ dpm_unlock(); ++ return -EBUSY; ++ } ++ ++ /* remove the policy */ ++ destroy_policy(policy); ++ ++ dpm_unlock(); ++ trace("destroyed \"%s\" policy\n", name); ++ return 0; ++} ++ ++/* ++ * set active power policy ++ */ ++int ++dpm_set_policy(const char *name) ++{ ++ struct dpm_policy *new_p; ++ ++ trace("in dpm_set_policy for \"%s\" policy\n", name); ++ ++ dpm_lock(); ++ ++ list_find(new_p, name, dpm_policies, struct dpm_policy); ++ if (!new_p) { ++ dpm_trace(DPM_TRACE_SET_POLICY, name, -ENOENT); ++ dpm_unlock(); ++ return -ENOENT; /* invalid name */ ++ } ++ if (new_p == dpm_active_policy) { ++ dpm_trace(DPM_TRACE_SET_POLICY, name, 0); ++ trace("\"%s\" policy already activated\n", name); ++ dpm_unlock(); ++ return 0; ++ } ++ ++ dpm_update_stats(&new_p->stats, ++ dpm_active_policy ? &dpm_active_policy->stats ++ : NULL); ++ ++ dpm_active_policy = new_p; ++ ++ if (! dpm_enabled) { ++ dpm_enabled = 1; ++ dpm_md_startup(); ++ dpm_stats_reset(); ++ } ++ ++ /* Start the policy synchronously */ ++ ++ mb(); ++ dpm_trace(DPM_TRACE_SET_POLICY, name, 0); ++ dpm_set_opt_sync(); ++ dpm_unlock(); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * set a raw op state ++ *****************************************************************************/ ++ ++int ++dpm_set_op_state(const char *name) ++{ ++ int op_state; ++ ++ for (op_state = 0; op_state < DPM_STATES; op_state++) ++ if (strcmp(dpm_state_names[op_state], name) == 0) { ++ dpm_set_os(op_state); ++ return 0; ++ } ++ ++ return -ENOENT; ++} ++ ++/***************************************************************************** ++ * terminate the DPM ++ *****************************************************************************/ ++int ++dynamicpower_terminate(void) ++{ ++ trace("in dynamicpower_terminate\n"); ++ ++ if (!dpm_initialized) ++ return 0; ++ ++ dpm_lock(); ++ ++ dpm_md_cleanup(); ++ ++ dpm_initialized = 0; ++ dpm_enabled = 0; ++ dpm_active_opt = NULL; ++ dpm_active_class = NULL; ++ ++ /* destroy all entities */ ++ while (!list_empty(&dpm_policies)) ++ destroy_policy(list_entry ++ (dpm_policies.next, struct dpm_policy, list)); ++ while (!list_empty(&dpm_opts)) ++ destroy_opt(list_entry(dpm_opts.next, struct dpm_opt, list)); ++ while (!list_empty(&dpm_classes)) ++ destroy_class(list_entry(dpm_classes.next, struct dpm_class, ++ list)); ++ ++ ++ mb(); ++ dpm_unlock(); ++ ++ trace("DPM is now terminated\n"); ++ printk("Dynamic Power Management is now terminated\n"); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(dynamicpower_init); ++EXPORT_SYMBOL(dynamicpower_terminate); ++EXPORT_SYMBOL(dynamicpower_disable); ++EXPORT_SYMBOL(dynamicpower_enable); ++EXPORT_SYMBOL(dpm_create_opt); ++EXPORT_SYMBOL(dpm_create_class); ++EXPORT_SYMBOL(dpm_create_policy); ++EXPORT_SYMBOL(dpm_destroy_policy); ++EXPORT_SYMBOL(dpm_set_policy); ++ ++/**************************************************************************** ++ * install dynamic power policy support ++ ****************************************************************************/ ++static int __init ++dpm_init_module(void) ++{ ++ int i; ++ ++ /* Set the NOP operating point params to all -1. */ ++ ++ for (i = 0; i < DPM_PP_NBR; i++) ++ nop_op.pp[i] = -1; ++ ++ trace("DPM is now installed\n"); ++ return 0; ++} ++ ++/**************************************************************************** ++ * remove dynamic power policy support ++ ****************************************************************************/ ++static void __exit ++dpm_exit_module(void) ++{ ++ /* disable power management policy system */ ++ dynamicpower_terminate(); ++ ++ trace("DPM module is now unloaded\n"); ++} ++ ++module_init(dpm_init_module); ++module_exit(dpm_exit_module); ++ ++/* ++ * Local variables: ++ * c-basic-offset: 8 ++ * End: ++ */ +diff -Nurd linux-2.6.16.orig/drivers/dpm/dpm-idle.c linux-2.6.16/drivers/dpm/dpm-idle.c +--- linux-2.6.16.orig/drivers/dpm/dpm-idle.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/dpm/dpm-idle.c 2006-06-03 11:14:55.896391712 +0200 +@@ -0,0 +1,167 @@ ++/* ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, MontaVista Software <source@mvista.com>. ++ * ++ * Based on ibm405lp_dpm.c by Bishop Brock, Copyright (C) 2002, ++ * International Business Machines Corporation. ++ */ ++ ++#include <linux/config.h> ++#include <linux/dpm.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/kmod.h> ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#include <linux/stat.h> ++#include <linux/string.h> ++ ++#include <asm/delay.h> ++#include <asm/hardirq.h> ++#include <asm/page.h> ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++/**************************************************************************** ++ * DPM Idle Handler ++ ****************************************************************************/ ++ ++/* ++ The idle handler is one of the most important parts of DPM, as very ++ significant amounts of energy are saved by moving to a low-power idle state ++ whenever possible. The basic coding of the core of this routine is simply: ++ ++ dpm_set_os(DPM_IDLE_STATE); ++ machine-dependent-idle-routine(); ++ dpm_set_os(DPM_IDLE_TASK_STATE); ++ ++ The added complexity found here is introduced to avoid unnecessary work, and ++ especially to reduce the latencies associated with going in and out of idle. ++ Idle power can be greatly reduced by moving to a very low-frequency ++ operating point, but we also need to be aware of the impact on interrupt ++ latencies. The DPM implementation of idle attempts to balance these ++ competing needs. ++ ++ We support 2 "idle" states: DPM_IDLE_TASK_STATE and DPM_IDLE_STATE. The ++ idle thread is marked as a "no-state" task, so that operating point changes ++ are not automatically made when the idle thread is scheduled. The ++ "idle-task" state is used for the majority of the idle thread. Interrupts ++ that occur during idle are handled in this state as well. The "idle" state ++ is only entered from the idle-task state, and only for the express purpose ++ of allowing an ultra-low-power operating point. ++ ++ The introduction of the idle-task state supports a stepped voltage and ++ frequency scaling at idle. On the IBM 405LP we would not want to go from, ++ e.g., 266/133 @ 1.8 V directly to 8/8 @ 1.0 V and back. Why not? Because ++ we would get "stuck" at 8MHz even though we need to wake up and resume ++ useful work, e.g., we would have to set the 266/133 operating point while ++ running at 8/8. So instead when going idle first step down to idle-task, ++ e.g., 100/50 @ 1.0 V, and then step down to e.g. 8/8 to halt. The interrupt ++ that takes us out of idle takes us back to idle-task (100/50) for interrupt ++ processing and the potential return to 266/133. ++ ++ The best policies for this implementation will be able to transition between ++ idle-task and idle without voltage scaling or driver notification. In these ++ cases the transitions are handled with minimal latency by simple frequency ++ scaling. */ ++ ++static inline void ++quick_idle(void) ++{ ++ dpm_quick_enter_state(DPM_IDLE_STATE); ++ dpm_md_idle(); ++ dpm_quick_enter_state(DPM_IDLE_TASK_STATE); ++} ++ ++static void ++full_idle(struct dpm_opt *idle_task_opt, struct dpm_opt *idle_opt) ++{ ++ dpm_quick_enter_state(DPM_IDLE_STATE); ++#ifdef CONFIG_DPM_STATS ++ dpm_update_stats(&idle_opt->stats, &idle_task_opt->stats); ++#endif ++ dpm_set_opt(idle_opt, DPM_SYNC); ++ dpm_md_idle(); ++ dpm_set_opt(idle_task_opt, DPM_SYNC); ++ dpm_quick_enter_state(DPM_IDLE_TASK_STATE); ++#ifdef CONFIG_DPM_STATS ++ dpm_update_stats(&idle_task_opt->stats, &idle_opt->stats); ++#endif ++} ++ ++ ++/* If DPM is currently disabled here we simply do the standard ++ idle wait. ++ ++ If we're not actually in DPM_IDLE_TASK_STATE, we need to go back and get ++ into this state. This could happen in rare instances - an interrupt between ++ dpm_set_os() and the critical section. ++ ++ If we are not yet at the idle-task operating point, or if there is no ++ difference between idle-task and idle, we can enter/exit the idle state ++ quickly since it's only for statistical purposes. This is also true if for ++ some reason we can't get the DPM lock, since obviously an asynchronous event ++ is going to have to occur to clear the lock, and this event is going to take ++ us out of idle. ++ ++ Otherwise the full idle shutdown is done. */ ++ ++ ++void ++dpm_idle(void) ++{ ++ unsigned long flags; ++ struct dpm_opt *idle_task_opt, *idle_opt; ++ ++ current->dpm_state = DPM_NO_STATE; ++ dpm_set_os(DPM_IDLE_TASK_STATE); ++ local_irq_save(flags); ++ ++ if (! need_resched()) { ++ if (!dpm_enabled) { ++ dpm_md_idle(); ++ ++ } else if (dpm_active_state != DPM_IDLE_TASK_STATE) { ++ ++ ++ } else { ++ idle_task_opt = dpm_choose_opt(dpm_active_policy, ++ DPM_IDLE_TASK_STATE); ++ idle_opt = dpm_choose_opt(dpm_active_policy, ++ DPM_IDLE_STATE); ++ ++ if (dpm_trylock()) { ++ dpm_md_idle(); ++ } else { ++ ++ if ((dpm_active_opt != idle_task_opt) || ++ (idle_task_opt == idle_opt)) { ++ ++ quick_idle(); ++ dpm_unlock(); ++ } else { ++ dpm_unlock(); ++ full_idle(idle_task_opt, idle_opt); ++ } ++ } ++ } ++ } ++ local_irq_restore(flags); ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/dpm/dpm-ui.c linux-2.6.16/drivers/dpm/dpm-ui.c +--- linux-2.6.16.orig/drivers/dpm/dpm-ui.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/dpm/dpm-ui.c 2006-06-03 11:14:55.897391560 +0200 +@@ -0,0 +1,1249 @@ ++/* ++ * drivers/dpm/dpm-ui.c - userspace interface to Dynamic Power Management ++ * ++ * (c) 2003 MontaVista Software, Inc. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express or ++ * implied. ++ */ ++ ++#include <linux/dpm.h> ++#include <linux/device.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++ ++/* Common sysfs/proc support */ ++ ++char *dpm_state_names[DPM_STATES] = DPM_STATE_NAMES; ++char *dpm_param_names[DPM_PP_NBR] = DPM_PARAM_NAMES; ++ ++#define MAXTOKENS 80 ++ ++static int ++tokenizer(char **tbuf, const char *userbuf, ssize_t n, char **tokptrs, ++ int maxtoks) ++{ ++ char *cp, *tok; ++ char *whitespace = " \t\r\n"; ++ int ntoks = 0; ++ ++ if (!(cp = kmalloc(n + 1, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ *tbuf = cp; ++ memcpy(cp, userbuf, n); ++ cp[n] = '\0'; ++ ++ do { ++ cp = cp + strspn(cp, whitespace); ++ tok = strsep(&cp, whitespace); ++ if ((*tok == '\0') || (ntoks == maxtoks)) ++ break; ++ tokptrs[ntoks++] = tok; ++ } while(cp); ++ ++ return ntoks; ++} ++ ++ ++/* SysFS Interface */ ++ ++#define dpm_attr(_name,_prefix) \ ++static struct subsys_attribute _prefix##_attr = { \ ++ .attr = { \ ++ .name = __stringify(_name), \ ++ .mode = 0644, \ ++ }, \ ++ .show = _prefix##_show, \ ++ .store = _prefix##_store, \ ++} ++ ++ ++static void dpm_kobj_release(struct kobject *kobj) ++{ ++ /* ++ * No sysfs/kobject state to release, DPM layer will handle the ++ * the containing object. ++ */ ++ ++ return; ++} ++ ++/* ++ * Top-level control ++ */ ++ ++static ssize_t dpm_control_show(struct subsystem * subsys, char * buf) ++{ ++ unsigned long flags; ++ ssize_t len = 0; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled) { ++ len += sprintf(buf, "disabled\n"); ++ } else { ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ len += sprintf(buf,"enabled %s %d %s %s %s\n", ++ dpm_active_policy->name, ++ dpm_active_state, ++ dpm_state_names[dpm_active_state], ++ dpm_classopt_name(dpm_active_policy, ++ dpm_active_state), ++ dpm_active_opt ? dpm_active_opt->name : "[none]"); ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ } ++ ++ dpm_unlock(); ++ return len; ++} ++ ++static ssize_t dpm_control_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ int error = 0; ++ ++ if (strncmp(buf, "init", 4) == 0) { ++ error = dynamicpower_init(); ++ } else if (strncmp(buf, "enable", 6) == 0) { ++ error = dynamicpower_enable(); ++ } else if (strncmp(buf, "disable", 7) == 0) { ++ error = dynamicpower_disable(); ++ } else if (strncmp(buf, "terminate", 9) == 0) { ++ error = dynamicpower_terminate(); ++ } else ++ error = -EINVAL; ++ ++ return error ? error : n; ++} ++ ++dpm_attr(control,dpm_control); ++ ++static struct attribute * g[] = { ++ &dpm_control_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group dpm_attr_group = { ++ .attrs = g, ++}; ++ ++decl_subsys(dpm, NULL, NULL); ++ ++/* ++ * policy ++ */ ++ ++struct dpm_policy_attribute { ++ struct attribute attr; ++ ssize_t (*show)(struct kobject * kobj, char * buf); ++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count); ++}; ++ ++#define to_policy(obj) container_of(obj,struct dpm_policy,kobj) ++#define to_policy_attr(_attr) container_of(_attr,struct dpm_policy_attribute,attr) ++ ++static struct kobject dpm_policy_kobj = { ++ .kset = &dpm_subsys.kset, ++}; ++ ++static ssize_t policy_control_show(struct subsystem * subsys, char * buf) ++{ ++ ssize_t len = 0; ++ struct list_head * p; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ len += sprintf(buf + len, "policies: "); ++ ++ list_for_each(p, &dpm_policies) { ++ len += sprintf(buf + len, "%s ", ++ ((struct dpm_policy *) ++ list_entry(p, struct dpm_policy, list))->name); ++ } ++ ++ len += sprintf(buf + len, "\n"); ++ dpm_unlock(); ++ return len; ++} ++ ++static ssize_t policy_control_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ int error = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ error = ntoks; ++ goto out; ++ } ++ ++ if (strcmp(token[0],"create") == 0) { ++ error = dpm_create_policy(token[1], &token[2], ntoks - 2); ++ } else if (strcmp(token[0],"set") == 0) { ++ if (ntoks != 2) ++ printk("dpm: policy set requires 1 policy name argument\n"); ++ else ++ error = dpm_set_policy(token[1]); ++ } else ++ error = -EINVAL; ++ ++ out: ++ if (tbuf) ++ kfree(tbuf); ++ return error ? error : n; ++} ++ ++static ssize_t active_policy_show(struct subsystem * subsys, char * buf) ++{ ++ unsigned long flags; ++ ssize_t len = 0; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled || (dpm_active_state == DPM_NO_STATE)) { ++ len += sprintf(buf + len, "[none]\n"); ++ } else { ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ len += sprintf(buf + len,"%s\n", ++ dpm_active_policy->name); ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ } ++ ++ dpm_unlock(); ++ return len; ++} ++ ++static ssize_t active_policy_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ int error = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ error = ntoks; ++ goto out; ++ } ++ ++ error = dpm_set_policy(token[0]); ++ ++ out: ++ if (tbuf) ++ kfree(tbuf); ++ return error ? error : n; ++} ++ ++dpm_attr(control,policy_control); ++dpm_attr(active,active_policy); ++ ++#ifdef CONFIG_DPM_STATS ++static ssize_t policy_stats_show(struct subsystem * subsys, char * buf) ++{ ++ int len = 0; ++ struct dpm_policy *policy; ++ struct list_head *p; ++ unsigned long long total_time; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled) { ++ dpm_unlock(); ++ len += sprintf(buf + len, "DPM IS DISABLED\n"); ++ return len; ++ } ++ ++ for (p = dpm_policies.next; p != &dpm_policies; p = p->next) { ++ policy = list_entry(p, struct dpm_policy, list); ++ len += sprintf(buf + len, "policy: %s", policy->name); ++ total_time = policy->stats.total_time; ++ if (policy == dpm_active_policy) ++ total_time += (unsigned long long) dpm_time() - ++ policy->stats.start_time; ++ len += sprintf(buf + len, " ticks: %Lu times: %lu\n", ++ (unsigned long long) dpm_time_to_usec(total_time), ++ policy->stats.count); ++ } ++ ++ dpm_unlock(); ++ return len; ++} ++ ++static ssize_t policy_stats_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ return n; ++} ++ ++dpm_attr(stats, policy_stats); ++#endif /* CONFIG_DPM_STATS */ ++ ++static ssize_t a_policy_control_show(struct kobject * kobj, char * buf) ++{ ++ struct dpm_policy *policy = to_policy(kobj); ++ ssize_t len = 0; ++ int i; ++ ++ len += sprintf(buf + len, "ops/classes: "); ++ ++ for (i = 0; i < DPM_STATES; i++) ++ len += sprintf(buf + len, "%s ", dpm_classopt_name(policy,i)); ++ ++ len += sprintf(buf + len, "\n"); ++ return len; ++} ++ ++static ssize_t a_policy_control_store(struct kobject * kobj, const char * buf, ++ size_t n) ++{ ++ struct dpm_policy *policy = to_policy(kobj); ++ int error = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ error = ntoks; ++ goto out; ++ } ++ ++ if (strcmp(token[0],"destroy") == 0) { ++ dpm_destroy_policy(policy->name); ++ } else ++ error = -EINVAL; ++ ++ out: ++ if (tbuf) ++ kfree(tbuf); ++ return error ? error : n; ++} ++ ++#define POLICY_STATE_ATTR(index) \ ++static ssize_t policy_state ## index ## _show(struct kobject * kobj, \ ++ char * buf) \ ++{ \ ++ ssize_t len = 0; \ ++ struct dpm_policy *policy = to_policy(kobj); \ ++ len += sprintf(buf + len, "%s\n", policy->classopt[index].opt ? policy->classopt[index].opt->name :policy->classopt[index].class->name ); \ ++ return len; \ ++} \ ++static ssize_t policy_state ## index ## _store(struct kobject * kobj, \ ++ const char * buf, \ ++ size_t n) \ ++{ \ ++ struct dpm_policy *policy = to_policy(kobj); \ ++ struct dpm_classopt old_classopt; \ ++ int ret; \ ++ \ ++ dpm_lock(); \ ++ old_classopt = policy->classopt[index]; \ ++ if ((ret = dpm_map_policy_state(policy,index,(char *)buf))) \ ++ policy->classopt[index] = old_classopt; \ ++ dpm_unlock(); \ ++ return ret ? -EINVAL : n; \ ++} \ ++static struct dpm_policy_attribute policy_state ## index ## _attr = { \ ++ .attr = { \ ++ .mode = 0644, \ ++ }, \ ++ .show = policy_state ## index ## _show, \ ++ .store = policy_state ## index ## _store, \ ++}; \ ++ ++#define MAX_POLICY_STATES 20 ++POLICY_STATE_ATTR(0); ++POLICY_STATE_ATTR(1); ++POLICY_STATE_ATTR(2); ++POLICY_STATE_ATTR(3); ++POLICY_STATE_ATTR(4); ++POLICY_STATE_ATTR(5); ++POLICY_STATE_ATTR(6); ++POLICY_STATE_ATTR(7); ++POLICY_STATE_ATTR(8); ++POLICY_STATE_ATTR(9); ++POLICY_STATE_ATTR(10); ++POLICY_STATE_ATTR(11); ++POLICY_STATE_ATTR(12); ++POLICY_STATE_ATTR(13); ++POLICY_STATE_ATTR(14); ++POLICY_STATE_ATTR(15); ++POLICY_STATE_ATTR(16); ++POLICY_STATE_ATTR(17); ++POLICY_STATE_ATTR(18); ++POLICY_STATE_ATTR(19); ++ ++static struct dpm_policy_attribute *policy_state_attr[MAX_POLICY_STATES] = { ++ &policy_state0_attr, ++ &policy_state1_attr, ++ &policy_state2_attr, ++ &policy_state3_attr, ++ &policy_state4_attr, ++ &policy_state5_attr, ++ &policy_state6_attr, ++ &policy_state7_attr, ++ &policy_state8_attr, ++ &policy_state9_attr, ++ &policy_state10_attr, ++ &policy_state11_attr, ++ &policy_state12_attr, ++ &policy_state13_attr, ++ &policy_state14_attr, ++ &policy_state15_attr, ++ &policy_state16_attr, ++ &policy_state17_attr, ++ &policy_state18_attr, ++ &policy_state19_attr, ++}; ++ ++static ssize_t ++policy_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ++{ ++ struct dpm_policy_attribute * policy_attr = to_policy_attr(attr); ++ ssize_t ret = 0; ++ ++ if (policy_attr->show) ++ ret = policy_attr->show(kobj,buf); ++ return ret; ++} ++ ++static ssize_t ++policy_attr_store(struct kobject * kobj, struct attribute * attr, ++ const char * buf, size_t count) ++{ ++ struct dpm_policy_attribute * policy_attr = to_policy_attr(attr); ++ ssize_t ret = 0; ++ ++ if (policy_attr->store) ++ ret = policy_attr->store(kobj,buf,count); ++ return ret; ++} ++ ++static struct dpm_policy_attribute a_policy_control_attr = { ++ .attr = { ++ .name = "control", ++ .mode = 0644, ++ }, ++ .show = a_policy_control_show, ++ .store = a_policy_control_store, ++}; ++ ++static struct sysfs_ops policy_sysfs_ops = { ++ .show = policy_attr_show, ++ .store = policy_attr_store, ++}; ++ ++static struct attribute * policy_default_attrs[] = { ++ &a_policy_control_attr.attr, ++ NULL, ++}; ++ ++static struct kobj_type ktype_policy = { ++ .release = dpm_kobj_release, ++ .sysfs_ops = &policy_sysfs_ops, ++ .default_attrs = policy_default_attrs, ++}; ++ ++void dpm_sysfs_new_policy(struct dpm_policy *policy) ++{ ++ int i; ++ ++ memset(&policy->kobj, 0, sizeof(struct kobject)); ++ policy->kobj.kset = &dpm_subsys.kset, ++ kobject_set_name(&policy->kobj,policy->name); ++ policy->kobj.parent = &dpm_policy_kobj; ++ policy->kobj.ktype = &ktype_policy; ++ kobject_register(&policy->kobj); ++ ++ for (i = 0; (i < DPM_STATES) && (i < MAX_POLICY_STATES); i++) { ++ policy_state_attr[i]->attr.name = dpm_state_names[i]; ++ sysfs_create_file(&policy->kobj, &policy_state_attr[i]->attr); ++ } ++ ++ return; ++} ++ ++void dpm_sysfs_destroy_policy(struct dpm_policy *policy) ++{ ++ kobject_unregister(&policy->kobj); ++ return; ++} ++ ++/* ++ * class ++ */ ++ ++struct dpm_class_attribute { ++ struct attribute attr; ++ ssize_t (*show)(struct kobject * kobj, char * buf); ++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count); ++}; ++ ++#define to_class(obj) container_of(obj,struct dpm_class,kobj) ++#define to_class_attr(_attr) container_of(_attr,struct dpm_class_attribute,attr) ++ ++static ssize_t class_control_show(struct subsystem * subsys, char * buf) ++{ ++ ssize_t len = 0; ++ struct list_head * p; ++ ++ len += sprintf(buf + len, "classes: "); ++ ++ list_for_each(p, &dpm_classes) { ++ len += sprintf(buf + len, "%s ", ++ ((struct dpm_class *) ++ list_entry(p, struct dpm_class, list))->name); ++ } ++ ++ len += sprintf(buf + len, "\nactive: %s\n", ++ (dpm_enabled && dpm_active_class) ? ++ dpm_active_class->name : "[none]"); ++ return len; ++} ++ ++static ssize_t class_control_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ int error = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ error = ntoks; ++ goto out; ++ } ++ ++ if (strcmp(token[0],"create") == 0) { ++ if (ntoks < 3) ++ printk("dpm: class create requires 1 name and at least one operating point argument\n"); ++ else ++ error = dpm_create_class(token[1], &token[2], ntoks-2); ++ } else ++ error = -EINVAL; ++ ++ out: ++ if (tbuf) ++ kfree(tbuf); ++ return error ? error : n; ++} ++ ++static struct kobject dpm_class_kobj = { ++ .kset = &dpm_subsys.kset, ++}; ++ ++dpm_attr(control,class_control); ++ ++static ssize_t a_class_control_show(struct kobject * kobj, char * buf) ++{ ++ ssize_t len = 0; ++ struct dpm_class *class = to_class(kobj); ++ int i; ++ ++ len += sprintf(buf + len, "ops: "); ++ ++ for (i = 0; i < class->nops; i++) ++ len += sprintf(buf + len, "%s ", class->ops[i]->name); ++ ++ ++ len += sprintf(buf + len, "\n"); ++ return len; ++} ++ ++static ssize_t a_class_control_store(struct kobject * kobj, const char * buf, ++ size_t n) ++{ ++ return n; ++} ++ ++static ssize_t ++class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ++{ ++ struct dpm_class_attribute * class_attr = to_class_attr(attr); ++ ssize_t ret = 0; ++ ++ if (class_attr->show) ++ ret = class_attr->show(kobj,buf); ++ return ret; ++} ++ ++static ssize_t ++class_attr_store(struct kobject * kobj, struct attribute * attr, ++ const char * buf, size_t count) ++{ ++ struct dpm_class_attribute * class_attr = to_class_attr(attr); ++ ssize_t ret = 0; ++ ++ if (class_attr->store) ++ ret = class_attr->store(kobj,buf,count); ++ return ret; ++} ++ ++static struct dpm_class_attribute a_class_control_attr = { ++ .attr = { ++ .name = "control", ++ .mode = 0644, ++ }, ++ .show = a_class_control_show, ++ .store = a_class_control_store, ++}; ++ ++static struct sysfs_ops class_sysfs_ops = { ++ .show = class_attr_show, ++ .store = class_attr_store, ++}; ++ ++static struct attribute * class_default_attrs[] = { ++ &a_class_control_attr.attr, ++ NULL, ++}; ++ ++static struct kobj_type ktype_class = { ++ .release = dpm_kobj_release, ++ .sysfs_ops = &class_sysfs_ops, ++ .default_attrs = class_default_attrs, ++}; ++ ++void dpm_sysfs_new_class(struct dpm_class *class) ++{ ++ memset(&class->kobj, 0, sizeof(struct kobject)); ++ class->kobj.kset = &dpm_subsys.kset, ++ kobject_set_name(&class->kobj,class->name); ++ class->kobj.parent = &dpm_class_kobj; ++ class->kobj.ktype = &ktype_class; ++ kobject_register(&class->kobj); ++ return; ++} ++ ++void dpm_sysfs_destroy_class(struct dpm_class *class) ++{ ++ kobject_unregister(&class->kobj); ++ return; ++} ++ ++ ++/* ++ * op ++ */ ++ ++struct dpm_op_attribute { ++ struct attribute attr; ++ ssize_t (*show)(struct kobject * kobj, char * buf); ++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count); ++}; ++ ++#define to_op(obj) container_of(obj,struct dpm_opt,kobj) ++#define to_op_attr(_attr) container_of(_attr,struct dpm_op_attribute,attr) ++ ++static ssize_t op_control_show(struct subsystem * subsys, char * buf) ++{ ++ unsigned long flags; ++ ssize_t len = 0; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ len += sprintf(buf + len, "active: "); ++ ++ if (!dpm_enabled) { ++ len += sprintf(buf + len, "[none]\n"); ++ } else { ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ len += sprintf(buf + len,"%s\n", ++ dpm_active_opt ? dpm_active_opt->name : "[none]"); ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ } ++ ++ dpm_unlock(); ++ ++ len += sprintf(buf + len, "params: %d\n", DPM_PP_NBR); ++ return len; ++} ++ ++static ssize_t op_control_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ int error = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ error = ntoks; ++ goto out; ++ } ++ ++ if ((strcmp(token[0],"create") == 0) && (ntoks >= 2)) { ++ dpm_md_pp_t pp[DPM_PP_NBR]; ++ int i; ++ ++ for (i = 0; i < DPM_PP_NBR; i++) { ++ if (i >= ntoks - 2) ++ pp[i] = -1; ++ else ++ pp[i] = simple_strtol(token[i + 2], ++ NULL, 0); ++ } ++ ++ error = dpm_create_opt(token[1], pp, DPM_PP_NBR); ++ } else ++ error = -EINVAL; ++ ++ out: ++ if (tbuf) ++ kfree(tbuf); ++ return error ? error : n; ++ ++} ++ ++dpm_attr(control,op_control); ++ ++#ifdef CONFIG_DPM_STATS ++static ssize_t op_stats_show(struct subsystem * subsys, char * buf) ++{ ++ int len = 0; ++ struct dpm_opt *opt; ++ struct list_head *p; ++ unsigned long long total_time; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled) { ++ dpm_unlock(); ++ len += sprintf(buf + len, "DPM IS DISABLED\n"); ++ return len; ++ } ++ ++ for (p = dpm_opts.next; p != &dpm_opts; p = p->next) { ++ opt = list_entry(p, struct dpm_opt, list); ++ len += sprintf(buf + len, "op: %s", opt->name); ++ total_time = opt->stats.total_time; ++ if (opt == dpm_active_opt) ++ total_time += (unsigned long long) dpm_time() - ++ opt->stats.start_time; ++ len += sprintf(buf + len, " ticks: %Lu times: %lu\n", ++ (unsigned long long) dpm_time_to_usec(total_time), ++ opt->stats.count); ++ } ++ ++ dpm_unlock(); ++ return len; ++} ++ ++static ssize_t op_stats_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ return n; ++} ++ ++dpm_attr(stats, op_stats); ++#endif /* CONFIG_DPM_STATS */ ++ ++ ++static struct kobject dpm_op_kobj = { ++ .kset = &dpm_subsys.kset, ++}; ++ ++static ssize_t an_op_control_show(struct kobject * kobj, char * buf) ++{ ++ ssize_t len = 0; ++ // struct dpm_opt *opt = to_op(kobj); ++ ++ len += sprintf(buf + len, "\n"); ++ return len; ++} ++ ++static ssize_t an_op_control_store(struct kobject * kobj, const char * buf, ++ size_t n) ++{ ++ return n; ++} ++ ++static struct dpm_op_attribute an_op_control_attr = { ++ .attr = { ++ .name = "control", ++ .mode = 0644, ++ }, ++ .show = an_op_control_show, ++ .store = an_op_control_store, ++}; ++ ++static ssize_t op_force_show(struct kobject * kobj, char * buf) ++{ ++ ssize_t len = 0; ++ struct dpm_opt *opt = to_op(kobj); ++ ++ len += sprintf(buf + len, "%d\n", opt->flags & DPM_OP_FORCE ? 1 : 0); ++ return len; ++} ++ ++static ssize_t op_force_store(struct kobject * kobj, const char * buf, ++ size_t n) ++{ ++ struct dpm_opt *opt = to_op(kobj); ++ ++ opt->flags = (opt->flags & ~DPM_OP_FORCE) | ++ (simple_strtol(buf, NULL, 0) ? DPM_OP_FORCE : 0); ++ return n; ++} ++ ++static struct dpm_op_attribute op_force_attr = { ++ .attr = { ++ .name = "force", ++ .mode = 0644, ++ }, ++ .show = op_force_show, ++ .store = op_force_store, ++}; ++ ++#define OP_PARAM_ATTR(index) \ ++static ssize_t op_param ## index ## _show(struct kobject * kobj, char * buf) \ ++{ \ ++ ssize_t len = 0; \ ++ struct dpm_opt *opt = to_op(kobj); \ ++ len += sprintf(buf + len, "%d\n", opt->pp[index]); \ ++ return len; \ ++} \ ++static ssize_t op_param ## index ## _store(struct kobject * kobj, const char * buf, \ ++ size_t n) \ ++{ \ ++ struct dpm_opt *opt = to_op(kobj); \ ++ int ret, oldval; \ ++ \ ++ oldval = opt->pp[index]; \ ++ opt->pp[index] = simple_strtol(buf, NULL, 0); \ ++ ret = dpm_md_init_opt(opt); \ ++ if (ret) \ ++ opt->pp[index] = oldval; \ ++ return ret ? ret : n; \ ++} \ ++static struct dpm_op_attribute op_param ## index ## _attr = { \ ++ .attr = { \ ++ .mode = 0644, \ ++ }, \ ++ .show = op_param ## index ## _show, \ ++ .store = op_param ## index ## _store, \ ++}; \ ++ ++#define MAX_OP_PARAMS 20 ++OP_PARAM_ATTR(0); ++OP_PARAM_ATTR(1); ++OP_PARAM_ATTR(2); ++OP_PARAM_ATTR(3); ++OP_PARAM_ATTR(4); ++OP_PARAM_ATTR(5); ++OP_PARAM_ATTR(6); ++OP_PARAM_ATTR(7); ++OP_PARAM_ATTR(8); ++OP_PARAM_ATTR(9); ++OP_PARAM_ATTR(10); ++OP_PARAM_ATTR(11); ++OP_PARAM_ATTR(12); ++OP_PARAM_ATTR(13); ++OP_PARAM_ATTR(14); ++OP_PARAM_ATTR(15); ++OP_PARAM_ATTR(16); ++OP_PARAM_ATTR(17); ++OP_PARAM_ATTR(18); ++OP_PARAM_ATTR(19); ++ ++static struct dpm_op_attribute *op_param_attr[MAX_OP_PARAMS] = { ++ &op_param0_attr, ++ &op_param1_attr, ++ &op_param2_attr, ++ &op_param3_attr, ++ &op_param4_attr, ++ &op_param5_attr, ++ &op_param6_attr, ++ &op_param7_attr, ++ &op_param8_attr, ++ &op_param9_attr, ++ &op_param10_attr, ++ &op_param11_attr, ++ &op_param12_attr, ++ &op_param13_attr, ++ &op_param14_attr, ++ &op_param15_attr, ++ &op_param16_attr, ++ &op_param17_attr, ++ &op_param18_attr, ++ &op_param19_attr, ++}; ++ ++static ssize_t ++op_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ++{ ++ struct dpm_op_attribute * op_attr = to_op_attr(attr); ++ ssize_t ret = 0; ++ ++ if (op_attr->show) ++ ret = op_attr->show(kobj,buf); ++ return ret; ++} ++ ++static ssize_t ++op_attr_store(struct kobject * kobj, struct attribute * attr, ++ const char * buf, size_t count) ++{ ++ struct dpm_op_attribute * op_attr = to_op_attr(attr); ++ ssize_t ret = 0; ++ ++ if (op_attr->store) ++ ret = op_attr->store(kobj,buf,count); ++ return ret; ++} ++ ++static struct sysfs_ops op_sysfs_ops = { ++ .show = op_attr_show, ++ .store = op_attr_store, ++}; ++ ++static struct attribute * op_default_attrs[] = { ++ &an_op_control_attr.attr, ++ &op_force_attr.attr, ++ NULL, ++}; ++ ++static struct kobj_type ktype_op = { ++ .release = dpm_kobj_release, ++ .sysfs_ops = &op_sysfs_ops, ++ .default_attrs = op_default_attrs, ++}; ++ ++void dpm_sysfs_new_op(struct dpm_opt *opt) ++{ ++ int i; ++ ++ memset(&opt->kobj, 0, sizeof(struct kobject)); ++ opt->kobj.kset = &dpm_subsys.kset, ++ kobject_set_name(&opt->kobj,opt->name); ++ opt->kobj.parent = &dpm_op_kobj; ++ opt->kobj.ktype = &ktype_op; ++ kobject_register(&opt->kobj); ++ ++ for (i = 0; (i < DPM_PP_NBR) && (i < MAX_OP_PARAMS); i++) { ++ op_param_attr[i]->attr.name = dpm_param_names[i]; ++ sysfs_create_file(&opt->kobj, &op_param_attr[i]->attr); ++ } ++ ++ return; ++} ++ ++void dpm_sysfs_destroy_op(struct dpm_opt *opt) ++{ ++ kobject_unregister(&opt->kobj); ++ return; ++} ++ ++ ++/* ++ * state ++ */ ++ ++ ++static ssize_t state_control_show(struct subsystem * subsys, char * buf) ++{ ++ ssize_t len = 0; ++ int i; ++ ++ len += sprintf(buf + len, "states: "); ++ ++ for (i = 0; i < DPM_STATES; i++) { ++ len += sprintf(buf + len, "%s ", dpm_state_names[i]); ++ } ++ ++ len += sprintf(buf + len, "\ntask-states: min=%s norm=%s max=%s\n", ++ dpm_state_names[DPM_TASK_STATE - DPM_TASK_STATE_LIMIT], ++ dpm_state_names[DPM_TASK_STATE], ++ dpm_state_names[DPM_TASK_STATE + DPM_TASK_STATE_LIMIT]); ++ ++ return len; ++} ++ ++static ssize_t state_control_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ return -EINVAL; ++} ++ ++static ssize_t active_state_show(struct subsystem * subsys, char * buf) ++{ ++ unsigned long flags; ++ ssize_t len = 0; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled || (dpm_active_state == DPM_NO_STATE)) { ++ len += sprintf(buf + len, "[none]\n"); ++ } else { ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ len += sprintf(buf + len,"%s\n", ++ dpm_state_names[dpm_active_state]); ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ } ++ ++ dpm_unlock(); ++ return len; ++} ++ ++static ssize_t active_state_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ int error = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ error = ntoks; ++ goto out; ++ } ++ ++ error = dpm_set_op_state(token[0]); ++ ++ out: ++ if (tbuf) ++ kfree(tbuf); ++ return error ? error : n; ++} ++ ++#ifdef CONFIG_DPM_STATS ++static ssize_t state_stats_show(struct subsystem * subsys, char * buf) ++{ ++ unsigned long flags; ++ ssize_t len = 0; ++ int i; ++ ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ ++ for (i = 0; i < DPM_STATES; i++) { ++ unsigned long long total_time = dpm_state_stats[i].total_time; ++ ++ if (i == dpm_active_state) ++ total_time += (unsigned long long) dpm_time() - ++ dpm_state_stats[i].start_time; ++ ++ len += sprintf(buf + len, "state: %s", dpm_state_names[i]); ++ len += sprintf(buf + len, " ticks: %Lu", ++ (unsigned long long) dpm_time_to_usec(total_time)); ++ len += sprintf(buf + len, " times: %lu\n", ++ dpm_state_stats[i].count); ++ } ++ ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ return len; ++} ++ ++static ssize_t state_stats_store(struct subsystem * subsys, const char * buf, ++ size_t n) ++{ ++ return n; ++} ++#endif /* CONFIG_DPM_STATS */ ++ ++static struct kobject dpm_state_kobj = { ++ .kset = &dpm_subsys.kset, ++}; ++ ++dpm_attr(control, state_control); ++dpm_attr(active, active_state); ++#ifdef CONFIG_DPM_STATS ++dpm_attr(stats, state_stats); ++#endif ++ ++struct astate { ++ int index; ++ struct kobject kobj; ++}; ++ ++struct astate_attribute { ++ struct attribute attr; ++ ssize_t (*show)(struct kobject * kobj, char * buf); ++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count); ++}; ++ ++#define to_astate(obj) container_of(obj,struct astate,kobj) ++#define to_astate_attr(_attr) container_of(_attr,struct astate_attribute,attr) ++ ++static ssize_t ++astate_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) ++{ ++ struct astate_attribute * astate_attr = to_astate_attr(attr); ++ ssize_t ret = 0; ++ ++ if (astate_attr->show) ++ ret = astate_attr->show(kobj,buf); ++ return ret; ++} ++ ++static ssize_t ++astate_attr_store(struct kobject * kobj, struct attribute * attr, ++ const char * buf, size_t count) ++{ ++ struct astate_attribute * astate_attr = to_astate_attr(attr); ++ ssize_t ret = 0; ++ ++ if (astate_attr->store) ++ ret = astate_attr->store(kobj,buf,count); ++ return ret; ++} ++ ++static int show_opconstrains(int state, char *buf) ++{ ++ struct dpm_opt *opt; ++ int len = 0; ++ ++ if (dpm_active_policy->classopt[state].opt) { ++ opt = dpm_active_policy->classopt[state].opt; ++ ++ len += dpm_show_opconstraints(opt, buf); ++ } ++ else { ++ int i; ++ ++ for (i = 0; ++ i < dpm_active_policy->classopt[state].class->nops; i++) { ++ len += dpm_show_opconstraints( ++ dpm_active_policy->classopt[state].class->ops[i], buf); ++ } ++ } ++ ++ return len; ++} ++static ssize_t astate_constraints_show(struct kobject * kobj, char * buf) ++{ ++ struct astate *astate = to_astate(kobj); ++ ssize_t len = 0; ++ ++ if (dpm_enabled && dpm_active_policy) ++ len = show_opconstrains(astate->index, buf); ++ ++ return len; ++} ++ ++static ssize_t astate_constraints_store(struct kobject * kobj, ++ const char * buf, size_t n) ++{ ++ return n; ++} ++ ++static struct astate_attribute astate_constraints_attr = { ++ .attr = { ++ .name = "constraints", ++ .mode = 0644, ++ }, ++ .show = astate_constraints_show, ++ .store = astate_constraints_store, ++}; ++ ++static struct sysfs_ops astate_sysfs_ops = { ++ .show = astate_attr_show, ++ .store = astate_attr_store, ++}; ++ ++static struct attribute * astate_default_attrs[] = { ++ &astate_constraints_attr.attr, ++ NULL, ++}; ++ ++static struct kobj_type ktype_astate = { ++ .release = dpm_kobj_release, ++ .sysfs_ops = &astate_sysfs_ops, ++ .default_attrs = astate_default_attrs, ++}; ++ ++static struct astate astate[DPM_STATES]; ++ ++/* ++ * Init ++ */ ++ ++static int __init dpm_sysfs_init(void) ++{ ++ int error, i; ++ ++ error = subsystem_register(&dpm_subsys); ++ if (!error) ++ error = sysfs_create_group(&dpm_subsys.kset.kobj,&dpm_attr_group); ++ if (!error) { ++ kobject_set_name(&dpm_policy_kobj, "policy"); ++ kobject_register(&dpm_policy_kobj); ++ sysfs_create_file(&dpm_policy_kobj, &policy_control_attr.attr); ++ sysfs_create_file(&dpm_policy_kobj, &active_policy_attr.attr); ++#ifdef CONFIG_DPM_STATS ++ sysfs_create_file(&dpm_policy_kobj, &policy_stats_attr.attr); ++#endif ++ kobject_set_name(&dpm_class_kobj, "class"); ++ kobject_register(&dpm_class_kobj); ++ sysfs_create_file(&dpm_class_kobj, &class_control_attr.attr); ++ kobject_set_name(&dpm_op_kobj, "op"); ++ kobject_register(&dpm_op_kobj); ++ sysfs_create_file(&dpm_op_kobj, &op_control_attr.attr); ++#ifdef CONFIG_DPM_STATS ++ sysfs_create_file(&dpm_op_kobj, &op_stats_attr.attr); ++#endif ++ kobject_set_name(&dpm_state_kobj, "state"); ++ kobject_register(&dpm_state_kobj); ++ sysfs_create_file(&dpm_state_kobj, &state_control_attr.attr); ++ sysfs_create_file(&dpm_state_kobj, &active_state_attr.attr); ++#ifdef CONFIG_DPM_STATS ++ sysfs_create_file(&dpm_state_kobj, &state_stats_attr.attr); ++#endif ++ ++ for (i = 0; i < DPM_STATES; i++) { ++ astate[i].index = i; ++ astate[i].kobj.kset = &dpm_subsys.kset; ++ kobject_set_name(&astate[i].kobj,dpm_state_names[i]); ++ astate[i].kobj.parent = &dpm_state_kobj; ++ astate[i].kobj.ktype = &ktype_astate; ++ kobject_register(&astate[i].kobj); ++ } ++ } ++ ++ return error; ++} ++ ++__initcall(dpm_sysfs_init); ++ ++/* /proc interface */ ++ ++int dpm_set_task_state_by_name(struct task_struct *task, char *buf, ssize_t n) ++{ ++ int task_state; ++ int ret = 0; ++ char *tbuf = NULL; ++ char *token[MAXTOKENS]; ++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); ++ ++ if (ntoks <= 0) { ++ ret = ntoks; ++ goto out; ++ } ++ ++ for (task_state = DPM_TASK_STATE - DPM_TASK_STATE_LIMIT; ++ task_state <= DPM_TASK_STATE + DPM_TASK_STATE_LIMIT; ++ task_state++) ++ if (strcmp(token[0], dpm_state_names[task_state]) == 0) { ++ task->dpm_state = task_state; ++ ++ if (task == current) ++ dpm_set_os(task_state); ++ ++ ret = 0; ++ break; ++ } ++ ++out: ++ if (tbuf) ++ kfree(tbuf); ++ ++ return ret; ++} +diff -Nurd linux-2.6.16.orig/drivers/dpm/Kconfig linux-2.6.16/drivers/dpm/Kconfig +--- linux-2.6.16.orig/drivers/dpm/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/dpm/Kconfig 2006-06-03 11:14:55.895391864 +0200 +@@ -0,0 +1,43 @@ ++# ++# Dynamic Power Management ++# ++ ++menu "Dynamic Power Management" ++ ++config DPM ++ bool "Dynamic Power Management" ++ help ++ Enable Dynamic Power Management, if implemented for your platform. ++ DPM conserves power by adjusting power parameters according to ++ system state (such as idle, running a high-power-usage task, etc.) ++ and enables associated power management features such as device ++ constraints on power parameters. DPM relies on power policy and ++ machine-dependent power operating points and such to be configured ++ from userspace after boot. ++ ++ If in doubt, say N. ++ ++config DPM_STATS ++ bool " Enable DPM Statistics Gathering" ++ depends on DPM ++ help ++ This enables gathering and reporting statistics for DPM. ++ This can be useful during development of DPM platform code or ++ in other situations where information on the operation of DPM is ++ needed. ++ ++ If in doubt, say N. ++ ++ ++config DPM_PROCFS ++ bool " Enable old DPM /proc interface (deprecated)" ++ depends on DPM && PROC_FS ++ help ++ This enables the /proc/driver/dpm interface for controlling ++ DPM. Please note that it is recommended to use the sysfs ++ interface instead (which is built automatically). ++ ++ If in doubt, say N. ++ ++endmenu ++ +diff -Nurd linux-2.6.16.orig/drivers/dpm/Makefile linux-2.6.16/drivers/dpm/Makefile +--- linux-2.6.16.orig/drivers/dpm/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/dpm/Makefile 2006-06-03 11:14:55.895391864 +0200 +@@ -0,0 +1,7 @@ ++# ++# Makefile for the kernel DPM driver. ++# ++ ++obj-$(CONFIG_DPM) += dpm.o dpm-idle.o dpm-ui.o ++obj-$(CONFIG_DPM_PROCFS) += proc.o ++ +diff -Nurd linux-2.6.16.orig/drivers/dpm/proc.c linux-2.6.16/drivers/dpm/proc.c +--- linux-2.6.16.orig/drivers/dpm/proc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/dpm/proc.c 2006-06-03 11:14:55.900391104 +0200 +@@ -0,0 +1,601 @@ ++/* ++ * drivers/dpm/proc.c Dynamic Power Management /proc ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, International Business Machines Corporation ++ * All Rights Reserved ++ * ++ * Bishop Brock ++ * IBM Research, Austin Center for Low-Power Computing ++ * bcbrock@us.ibm.com ++ * September, 2002 ++ * ++ */ ++ ++#include <linux/dpm.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <asm/semaphore.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#define DEBUG ++#ifdef DEBUG ++#define DPRINT(args...) printk(KERN_CRIT args) ++#else ++#define DPRINT(args...) do {} while (0) ++#endif ++ ++/**************************************************************************** ++ * /proc/driver/dpm interfaces ++ * ++ * NB: Some of these are borrowed from the 405LP, and may need to be made ++ * machine independent. ++ ****************************************************************************/ ++ ++/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ * /proc/driver/dpm/cmd (Write-Only) ++ * ++ * Writing a string to this file is equivalent to issuing a DPM command. ++ * Currently only one command per "write" is allowed, and there is a maximum on ++ * the number of tokens that will be accepted (PAGE_SIZE / sizeof(char *)). ++ * DPM can be initialized by a linewise copy of a configuration file to this ++ * /proc file. ++ * ++ * DPM Control ++ * ----------- ++ * ++ * init : dynamicpower_init() ++ * enable : dynamicpower_enable() ++ * disable : dynamicpower_disable() ++ * terminate : dynamicpower_terminate() ++ * ++ * Policy Control ++ * -------------- ++ * ++ * set_policy <policy> : Set the policy by name ++ * set_task_state <pid> <state> : Set the task state for a given pid, 0 = self ++ * ++ * Policy Creation ++ * --------------- ++ * ++ * create_opt <name> <pp0> ... <ppn> ++ * Create a named operating point from DPM_PP_NBR paramaters. All ++ * parameters must be given. Parameter order and meaning are machine ++ * dependent. ++ * ++ * create_class <name> <opt0> [ ... <optn> ] ++ * Create a named class from 1 or more named operating points. All ++ * operating points must be defined before the call. ++ * ++ * create_policy <name> <classopt0> [ ... <classoptn> ] ++ * Create a named policy from DPM_STATES classes or operating ++ * points. All operating points must be defined before the call. ++ * The order is machine dependent. ++ * ++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++ ++static void ++pwarn(char *command, int ntoks, char *requirement, int require) ++{ ++ printk(KERN_WARNING "/proc/driver/dpm/cmd: " ++ "Command %s requires %s%d arguments - %d were given\n", ++ command, requirement, require - 1, ntoks - 1); ++} ++ ++/***************************************************************************** ++ * set a task state ++ *****************************************************************************/ ++ ++static int ++dpm_set_task_state(pid_t pid, dpm_state_t task_state) ++{ ++ struct task_struct *p; ++ ++ if (task_state == -(DPM_TASK_STATE_LIMIT + 1)) ++ task_state = DPM_NO_STATE; ++ else if (abs(task_state) > DPM_TASK_STATE_LIMIT) { ++ dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, -EINVAL); ++ return -EINVAL; ++ } else ++ task_state += DPM_TASK_STATE; ++ ++ read_lock(&tasklist_lock); ++ ++ if (pid == 0) ++ p = current; ++ else ++ p = find_task_by_pid(pid); ++ ++ if (!p) { ++ read_unlock(&tasklist_lock); ++ dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, -ENOENT); ++ return -ENOENT; ++ } ++ ++ p->dpm_state = task_state; ++ read_unlock(&tasklist_lock); ++ ++ dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, 0); ++ ++ if (pid == 0) ++ dpm_set_os(p->dpm_state); ++ ++ ++ return 0; ++} ++ ++ ++static int ++write_proc_dpm_cmd (struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char *buf, *tok, **tokptrs; ++ char *whitespace = " \t\r\n"; ++ int ret = 0, ntoks; ++ ++ if (current->uid != 0) ++ return -EACCES; ++ if (count == 0) ++ return 0; ++ if (!(buf = kmalloc(count + 1, GFP_KERNEL))) ++ return -ENOMEM; ++ if (copy_from_user(buf, buffer, count)) { ++ ret = -EFAULT; ++ goto out0; ++ } ++ ++ buf[count] = '\0'; ++ ++ if (!(tokptrs = (char **)__get_free_page(GFP_KERNEL))) { ++ ret = -ENOMEM; ++ goto out1; ++ } ++ ++ ret = -EINVAL; ++ ntoks = 0; ++ do { ++ buf = buf + strspn(buf, whitespace); ++ tok = strsep(&buf, whitespace); ++ if (*tok == '\0') { ++ if (ntoks == 0) { ++ ret = 0; ++ goto out1; ++ } else ++ break; ++ } ++ if (ntoks == (PAGE_SIZE / sizeof(char **))) ++ goto out1; ++ tokptrs[ntoks++] = tok; ++ } while(buf); ++ ++ if (ntoks == 1) { ++ if (strcmp(tokptrs[0], "init") == 0) { ++ ret = dynamicpower_init(); ++ } else if (strcmp(tokptrs[0], "enable") == 0) { ++ ret = dynamicpower_enable(); ++ } else if (strcmp(tokptrs[0], "disable") == 0) { ++ ret = dynamicpower_disable(); ++ } else if (strcmp(tokptrs[0], "terminate") == 0) { ++ ret = dynamicpower_terminate(); ++ } ++ } else if (ntoks == 2) { ++ if (strcmp(tokptrs[0], "set_policy") == 0) ++ ret = dpm_set_policy(tokptrs[1]); ++ else if (strcmp(tokptrs[0], "set_state") == 0) ++ ret = dpm_set_op_state(tokptrs[1]); ++ } else { ++ if (strcmp(tokptrs[0], "set_task_state") == 0) { ++ if (ntoks != 3) ++ pwarn("set_task_state", ntoks, "", 3); ++ else ++ ret = dpm_set_task_state(simple_strtol(tokptrs[1], ++ NULL, 0), ++ simple_strtol(tokptrs[2], ++ NULL, 0)); ++ } else if (strcmp(tokptrs[0], "create_opt") == 0) { ++ if (ntoks != DPM_PP_NBR + 2) ++ pwarn("create_opt", ntoks, ++ "", DPM_PP_NBR + 2); ++ else { ++ dpm_md_pp_t pp[DPM_PP_NBR]; ++ int i; ++ ++ for (i = 0; i < DPM_PP_NBR; i++) ++ pp[i] = simple_strtol(tokptrs[i + 2], ++ NULL, 0); ++ ret = dpm_create_opt(tokptrs[1], pp, DPM_PP_NBR); ++ } ++ ++ } else if (strcmp(tokptrs[0], "create_class") == 0) { ++ if (ntoks < 3) ++ pwarn("create_class", ntoks, ">= ", 3); ++ else ++ ret = dpm_create_class(tokptrs[1], &tokptrs[2], ++ ntoks - 2); ++ ++ } else if (strcmp(tokptrs[0], "create_policy") == 0) { ++ if (ntoks != (DPM_STATES + 2)) ++ pwarn("create_policy", ntoks, "", ++ DPM_STATES + 2); ++ else ++ ret = dpm_create_policy(tokptrs[1], ++ &tokptrs[2], ntoks-2); ++ } ++ } ++out1: ++ free_page((unsigned long)tokptrs); ++out0: ++ kfree(buf); ++ if (ret == 0) ++ return count; ++ else ++ return ret; ++} ++ ++#ifdef CONFIG_DPM_STATS ++ ++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ * /proc/driver/dpm/stats (Read-Only) ++ * ++ * Reading this file produces the following line for each defined operating ++ * state: ++ * ++ * state_name total_time count opt_name ++ * ++ * Where: ++ * ++ * state_name = The operating state name. ++ * total_time = The 64-bit number of microseconds spent in this ++ * operating state. ++ * count = The 64-bit number of times this operating state was entered. ++ * opt_name = The name of the operating point currently assigned to this ++ * operating state. ++ * ++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++ ++static int ++sprintf_u64(char *buf, int fill, char *s, u64 ul) ++{ ++ int len = 0; ++ u32 u, l; ++ ++ u = (u32)((ul >> 32) & 0xffffffffU); ++ l = (u32)(ul & 0xffffffffU); ++ ++ len += sprintf(buf + len, s); ++ if (fill) ++ len += sprintf(buf + len, "0x%08x%08x", u, l); ++ else { ++ if (u) ++ len += sprintf(buf + len, "0x%x%x", u, l); ++ else ++ len += sprintf(buf + len, "0x%x", l); ++ } ++ return len; ++} ++ ++/***************************************************************************** ++ * get statistics for all operating states ++ *****************************************************************************/ ++ ++int ++dpm_get_os_stats(struct dpm_stats *stats) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ memcpy(stats, dpm_state_stats, DPM_STATES * sizeof (struct dpm_stats)); ++ stats[dpm_active_state].total_time += ++ dpm_time() - stats[dpm_active_state].start_time; ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ return 0; ++} ++ ++static int ++read_proc_dpm_stats(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int i, len = 0; ++ struct dpm_stats stats[DPM_STATES]; ++ ++ if (!dpm_enabled) { ++ len += sprintf(page + len, "DPM IS DISABLED\n"); ++ *eof = 1; ++ return len; ++ } ++ ++ dpm_get_os_stats(stats); ++ ++ for (i = 0; i < DPM_STATES; i++) { ++ len += sprintf(page + len, "%20s", dpm_state_names[i]); ++ len += sprintf_u64(page + len, 1, " ", ++ (u64)stats[i].total_time); ++ len += sprintf_u64(page + len, 1, " ", (u64)stats[i].count); ++ len += sprintf(page + len, " %s\n", ++ dpm_classopt_name(dpm_active_policy,i)); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ * /proc/driver/dpm/opt_stats (Read-Only) ++ * ++ * Reading this file produces the following line for each defined operating ++ * point: ++ * ++ * name total_time count ++ * ++ * Where: ++ * ++ * name = The operating point name. ++ * total_time = The 64-bit number of microseconds spent in this ++ * operating state. ++ * count = The 64-bit number of times this operating point was entered. ++ * ++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++ ++static int ++read_proc_dpm_opt_stats(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ struct dpm_opt *opt; ++ struct list_head *p; ++ unsigned long long total_time; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled) { ++ dpm_unlock(); ++ len += sprintf(page + len, "DPM IS DISABLED\n"); ++ *eof = 1; ++ return len; ++ } ++ ++ for (p = dpm_opts.next; p != &dpm_opts; p = p->next) { ++ opt = list_entry(p, struct dpm_opt, list); ++ len += sprintf(page + len, "%s", opt->name); ++ total_time = opt->stats.total_time; ++ if (opt == dpm_active_opt) ++ total_time += dpm_time() - opt->stats.start_time; ++ len += sprintf_u64(page + len, 0, " ", opt->stats.total_time); ++ len += sprintf_u64(page + len, 0, " ", opt->stats.count); ++ len += sprintf(page + len, "\n"); ++ } ++ ++ dpm_unlock(); ++ *eof = 1; ++ return len; ++} ++#endif /* CONFIG_DPM_STATS */ ++ ++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ * /proc/driver/dpm/state (Read-Only) ++ * ++ * Reading this file produces the following: ++ * ++ * policy_name os os_name os_opt_name opt_name hz ++ * ++ * Where: ++ * ++ * policy_name = The name of the current policy ++ * os = The curret operating state index ++ * os_name = The current operating state name ++ * os_opt_name = The name of the implied operating point for the policy and ++ * state. ++ * opt_name = The name of the actual operating point; may be different if ++ * the operating state and operating point are out of sync. ++ * hz = The frequency of the statistics timer ++ * ++ * If DPM is disabled the line will appear as: ++ * ++ * N/A -1 N/A N/A N/A <hz> ++ * ++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++ ++static int ++read_proc_dpm_state(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ unsigned long flags; ++ ++ int len = 0; ++ ++ if (dpm_lock_interruptible()) ++ return -ERESTARTSYS; ++ ++ if (!dpm_enabled) { ++ len += sprintf(page + len, "N/A -1 N/A N/A N/A N/A\n"); ++ } else { ++ ++ spin_lock_irqsave(&dpm_policy_lock, flags); ++ len += sprintf(page + len,"%s %d %s %s %s\n", ++ dpm_active_policy->name, ++ dpm_active_state, ++ dpm_state_names[dpm_active_state], ++ dpm_classopt_name(dpm_active_policy, ++ dpm_active_state), ++ dpm_active_opt ? dpm_active_opt->name : "none"); ++ spin_unlock_irqrestore(&dpm_policy_lock, flags); ++ } ++ ++ dpm_unlock(); ++ *eof = 1; ++ return len; ++} ++ ++ ++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ * /proc/driver/dpm/debug (Read-Only) ++ * ++ * Whatever it needs to be ++ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++ ++#ifdef DEBUG ++static int ++read_proc_dpm_debug(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += sprintf(page + len, "No DEBUG info\n"); ++ *eof = 1; ++ return len; ++} ++#endif /* DEBUG */ ++ ++static struct proc_dir_entry *proc_dpm; ++static struct proc_dir_entry *proc_dpm_cmd; ++static struct proc_dir_entry *proc_dpm_state; ++ ++#ifdef CONFIG_DPM_STATS ++static struct proc_dir_entry *proc_dpm_stats; ++static struct proc_dir_entry *proc_dpm_opt_stats; ++#endif ++ ++#ifdef DEBUG ++static struct proc_dir_entry *proc_dpm_debug; ++#endif ++ ++#ifdef CONFIG_DPM_TRACE ++static struct proc_dir_entry *proc_dpm_trace; ++#endif ++ ++static int __init ++dpm_proc_init(void) ++{ ++ proc_dpm = proc_mkdir("driver/dpm", NULL); ++ ++ if (proc_dpm) { ++ ++ proc_dpm_cmd = ++ create_proc_entry("cmd", ++ S_IWUSR, ++ proc_dpm); ++ if (proc_dpm_cmd) ++ proc_dpm_cmd->write_proc = write_proc_dpm_cmd; ++ ++ proc_dpm_state = ++ create_proc_read_entry("state", ++ S_IRUGO, ++ proc_dpm, ++ read_proc_dpm_state, ++ NULL); ++#ifdef CONFIG_DPM_STATS ++ proc_dpm_stats = ++ create_proc_read_entry("stats", ++ S_IRUGO, ++ proc_dpm, ++ read_proc_dpm_stats, ++ NULL); ++ proc_dpm_opt_stats = ++ create_proc_read_entry("opt_stats", ++ S_IRUGO, ++ proc_dpm, ++ read_proc_dpm_opt_stats, ++ NULL); ++ ++#endif /* CONFIG_DPM_STATS */ ++ ++#ifdef DEBUG ++ proc_dpm_debug = ++ create_proc_read_entry("debug", ++ S_IRUGO, ++ proc_dpm, ++ read_proc_dpm_debug, ++ NULL); ++#endif ++ ++#ifdef CONFIG_DPM_TRACE ++ proc_dpm_trace = ++ create_proc_read_entry("trace", ++ S_IWUSR | S_IRUGO, ++ proc_dpm, ++ read_proc_dpm_trace, ++ NULL); ++ if (proc_dpm_trace) ++ proc_dpm_trace->write_proc = write_proc_dpm_trace; ++#endif ++ } else { ++ printk(KERN_ERR "Attempt to create /proc/driver/dpm failed\n"); ++ ++ } ++ return 0; ++} ++ ++static void __exit ++dpm_proc_exit(void) ++{ ++ if (proc_dpm_cmd) { ++ remove_proc_entry("cmd", proc_dpm); ++ proc_dpm_cmd = NULL; ++ } ++ ++ if (proc_dpm_state) { ++ remove_proc_entry("state", proc_dpm); ++ proc_dpm_state = NULL; ++ } ++ ++#ifdef CONFIG_DPM_STATS ++ if (proc_dpm_stats) { ++ remove_proc_entry("stats", proc_dpm); ++ proc_dpm_stats = NULL; ++ } ++ ++ if (proc_dpm_opt_stats) { ++ remove_proc_entry("opt_stats", proc_dpm); ++ proc_dpm_opt_stats = NULL; ++ } ++#endif /* CONFIG_DPM_STATS */ ++ ++#ifdef DEBUG ++ if (proc_dpm_debug) { ++ remove_proc_entry("debug", proc_dpm); ++ proc_dpm_debug = NULL; ++ } ++#endif ++ ++#ifdef CONFIG_DPM_TRACE ++ if (proc_dpm_trace) { ++ remove_proc_entry("trace", proc_dpm); ++ proc_dpm_trace = NULL; ++ } ++#endif ++ ++ remove_proc_entry("driver/dpm", NULL); ++} ++ ++ ++ ++module_init(dpm_proc_init); ++module_exit(dpm_proc_exit); ++ ++/* ++ * Local variables: ++ * c-basic-offset: 8 ++ * End: ++ */ ++ +diff -Nurd linux-2.6.16.orig/drivers/edac/Kconfig linux-2.6.16/drivers/edac/Kconfig +--- linux-2.6.16.orig/drivers/edac/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/edac/Kconfig 2006-06-03 11:14:55.272486560 +0200 +@@ -71,7 +71,7 @@ + + config EDAC_E752X + tristate "Intel e752x (e7520, e7525, e7320)" +- depends on EDAC_MM_EDAC && PCI ++ depends on EDAC_MM_EDAC && PCI && HOTPLUG + help + Support for error detection and correction on the Intel + E7520, E7525, E7320 server chipsets. +diff -Nurd linux-2.6.16.orig/drivers/i2c/busses/i2c-i801.c linux-2.6.16/drivers/i2c/busses/i2c-i801.c +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-i801.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-i801.c 2006-06-03 11:14:55.272486560 +0200 +@@ -478,6 +478,11 @@ + ret = i801_transaction(); + } + ++ /* Some BIOSes don't like it when PEC is enabled at reboot or resume ++ time, so we forcibly disable it after every transaction. */ ++ if (hwpec) ++ outb_p(0, SMBAUXCTL); ++ + if(block) + return ret; + if(ret) +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/a780_camera.c linux-2.6.16/drivers/i2c/chips/a780_camera.c +--- linux-2.6.16.orig/drivers/i2c/chips/a780_camera.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/a780_camera.c 2006-06-03 11:14:56.410313584 +0200 +@@ -0,0 +1,905 @@ ++/* ++ * linux/drivers/i2c/a780_camera.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Jay Jia ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola 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 <linux/miscdevice.h> ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/videodev.h> ++#include <linux/pxa_camera.h> ++#include <linux/init.h> ++#include <linux/kdev_t.h> ++#include <asm/semaphore.h> ++ ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++ ++/* Major 10, Minor 244, /dev/camerai2c */ ++#define CAM_NAME "cami2c" ++#define CAM_MINOR 244 ++ ++#define TESTCODE ++#undef TESTCODE ++#define I2C_A780_CAMERA 0x86 ++ ++//#define DEBUG 2 ++ ++/*-----------------------------------------------------------*/ ++#define err_print(fmt, args...) printk(KERN_ERR "I2C-CAMERA in fun:%s "fmt"\n", __FUNCTION__, ##args) ++ ++#ifndef NDEBUG ++#define dbg_print(fmt, args...) printk(KERN_INFO "I2C-CAMERA in fun:%s "fmt"\n", __FUNCTION__, ##args) ++#if DEBUG > 1 ++#define ddbg_print(fmt, args...) dbg_print(fmt, ##args) ++#else ++#define ddbg_print(fmt, args...) ; ++#endif ++#else ++#define dbg_print(fmt, args...) ; ++#define ddbg_print(fmt, args...) ; ++#endif ++/*-----------------------------------------------------------*/ ++ ++#define I2C_CLIENT_NONE 100 ++#define I2C_CLIENT_MT9M111 101 ++#define I2C_CLIENT_OV9640 102 ++#define I2C_CLIENT_OV9650 103 ++#define I2C_CLIENT_ADCM3800 104 ++static int i2c_camera_client_type = I2C_CLIENT_NONE; ++static unsigned long i2c_camera_chipid = 0; ++ ++ ++static int a780_camera_adapter_attach(struct i2c_adapter *adap); ++static int a780_camera_detach(struct i2c_client *client); ++static int a780_camera_client_register(struct i2c_client *client); ++static int a780_camera_client_unregister(struct i2c_client *client); ++/* ----------------------------------------------------------------------- */ ++static struct i2c_driver driver = { ++ .name = "a780 camera driver", ++ .id = I2C_A780_CAMERA, ++ //flags: I2C_DF_DUMMY, ++ .attach_adapter = a780_camera_adapter_attach, ++ .detach_client = a780_camera_detach, ++ .owner = THIS_MODULE, ++}; ++ ++static struct i2c_adapter a780_camera_adapter = { ++ name: "a780 camera adapter", ++ id: I2C_A780_CAMERA, ++ client_register: a780_camera_client_register, ++ client_unregister: a780_camera_client_unregister, ++}; ++ ++static struct i2c_client client_template = ++{ ++ name: "(unset)", ++ adapter:&a780_camera_adapter, ++}; ++ ++struct i2c_client *a780_camera_client; ++unsigned int a780_camera_minor; ++ ++static int a780_camera_open(void) ++{ ++ //MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int a780_camera_release(void) ++{ ++ //MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++ ++int a780_camera_read(char *buf, size_t count) ++{ ++ int ret; ++ unsigned int flags; ++ ++ a780_camera_open(); ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_recv(a780_camera_client, buf, count); ++ local_irq_restore(flags); ++ a780_camera_release(); ++ return ret; ++ ++} ++ ++int a780_camera_write(const char *buf, size_t count) ++{ ++ int ret; ++ unsigned int flags; ++ ++ a780_camera_open(); ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_send(a780_camera_client, buf, count); ++ local_irq_restore(flags); ++ a780_camera_release(); ++ return ret; ++} ++ ++static int a780_camera_client_register(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++ ++static int a780_camera_client_unregister(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int a780_camera_adapter_attach(struct i2c_adapter *adap) ++{ ++ if(! (a780_camera_client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) ++ return -ENOMEM; ++ memcpy(a780_camera_client,&client_template,sizeof(struct i2c_client)); ++ a780_camera_client->adapter = adap; ++ ++ a780_camera_client->addr = 0x5D; ++ ++ i2c_attach_client(a780_camera_client); ++ return 0; ++} ++ ++static int a780_camera_detach(struct i2c_client *client) ++{ ++ i2c_detach_client(a780_camera_client); ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++static int cam_open(struct inode *inode, struct file *file) ++{ ++ if(i2c_camera_client_type == I2C_CLIENT_NONE) ++ return -EINVAL; ++ ++ //MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int i2c_camera_readw(unsigned short addr, unsigned short *pvalue); ++static int i2c_camera_readb(unsigned short addr, unsigned char *pvalue); ++static int i2c_camera_writew(unsigned short addr, unsigned short value); ++static int i2c_camera_writeb(unsigned short addr, unsigned char value); ++ ++static int cam_close(struct inode * inode, struct file *file) ++{ ++ //MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++#define DETECT_BUFLEN 256 ++static int cam_ioctl_detectid (void * arg) ++{ ++ int buflen, idlen; ++ char* id; ++ struct camera_i2c_detectid * param = arg; ++ if(copy_from_user(&buflen, &(param->buflen), sizeof(buflen))) ++ { ++ return -EFAULT; ++ } ++ if(buflen > DETECT_BUFLEN) ++ { ++ return -ENOMEM; ++ } ++ id = kmalloc(DETECT_BUFLEN, GFP_KERNEL); ++ if(id == NULL) ++ { ++ return -ENOMEM; ++ } ++ ++ idlen = 0; ++ switch(i2c_camera_client_type) ++ { ++#ifdef CONFIG_I2C_MT9M111 ++ case I2C_CLIENT_MT9M111: ++ idlen = snprintf(id, DETECT_BUFLEN-1, "%s %s %lx", ++ "MICRON", "MT9M111", i2c_camera_chipid); ++ break; ++#endif ++#ifdef CONFIG_I2C_ADCM3800 ++ case I2C_CLIENT_ADCM3800: ++ idlen = snprintf(id, DETECT_BUFLEN-1, "%s %s %lx", ++ "AGILENT", "ADCM3800", i2c_camera_chipid); ++ break; ++#endif ++#ifdef CONFIG_I2C_OV9640 ++ case I2C_CLIENT_OV9640: ++ idlen = snprintf(id, DETECT_BUFLEN-1, "%s %s %lx", ++ "OMNIVISION", "OV9640", i2c_camera_chipid); ++ break; ++#endif ++#ifdef CONFIG_I2C_OV9650 ++ case I2C_CLIENT_OV9650: ++ idlen = snprintf(id, DETECT_BUFLEN-1, "%s %s %lx", ++ "OMNIVISION", "OV9650", i2c_camera_chipid); ++ break; ++#endif ++ default: ++ break; ++ } ++ id[DETECT_BUFLEN-1] = 0; ++ idlen = strlen(id)+1; ++ if(buflen < idlen) ++ { ++ kfree(id); ++ return -ENOMEM; ++ } ++ if(copy_to_user(param->data, id, idlen)) ++ { ++ kfree(id); ++ return -EFAULT; ++ } ++ kfree(id); ++ return 0; ++} ++ ++static int cam_ioctl_register_rw (unsigned int cmd, void * arg) ++{ ++ int ret = -ENOTSUPP; ++ struct camera_i2c_register reg; ++ if(copy_from_user(®, arg, sizeof(reg))) ++ { ++ return -EFAULT; ++ } ++ switch(cmd) ++ { ++ case CAMERA_I2C_WRITEW: ++ ret=i2c_camera_writew(reg.addr, reg.value.w); ++ break; ++ case CAMERA_I2C_WRITEB: ++ ret=i2c_camera_writeb(reg.addr, reg.value.b); ++ break; ++ case CAMERA_I2C_READW: ++ if((ret=i2c_camera_readw(reg.addr, &(reg.value.w)))>=0) ++ { ++ if(copy_to_user(arg, ®, sizeof(reg))) ++ ret = -EFAULT; ++ } ++ break; ++ case CAMERA_I2C_READB: ++ if((ret=i2c_camera_readb(reg.addr, &(reg.value.b)))>=0) ++ { ++ if(copy_to_user(arg, ®, sizeof(reg))) ++ ret = -EFAULT; ++ } ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int cam_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int ret = -ENOTSUPP; ++ switch (cmd) ++ { ++ case CAMERA_I2C_WRITEW: ++ case CAMERA_I2C_WRITEB: ++ case CAMERA_I2C_READW: ++ case CAMERA_I2C_READB: ++ ret = cam_ioctl_register_rw(cmd, (void *)arg); ++ break; ++ case CAMERA_I2C_DETECTID: ++ ret = cam_ioctl_detectid((void *)arg); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static struct file_operations cam_fops = { ++ ioctl: cam_ioctl, ++ open: cam_open, ++ release: cam_close, ++}; ++ ++static struct miscdevice cam_misc_device = { ++ CAM_MINOR, ++ CAM_NAME, ++ &cam_fops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++static int a780_camera_init_module(void) ++{ ++ int res; ++ ++ res = i2c_add_driver(&driver); ++ if( res < 0 ) ++ { ++ printk("error in add i2c driver\n"); ++ return res; ++ } ++ if (misc_register (&cam_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register cam driver\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void a780_camera_cleanup_module(void) ++{ ++ i2c_del_driver(&driver); ++ misc_deregister(&cam_misc_device); ++} ++ ++ ++#ifdef CONFIG_I2C_MT9M111 ++ ++/*-----------------------------------------------------------*/ ++#define MT9M111_PAGE(a) ((u8)(((a) >> 8) & 0xFF)) ++#define MT9M111_OFFSET(a) ((u8)((a) & 0xFF)) ++ ++//#define MT9M111_LOG ++ ++#ifdef MT9M111_LOG ++#define mt9m111_dbg_print(fmt, args...) dbg_print(fmt, ##args) ++#else ++#define mt9m111_dbg_print(fmt, args...) ; ++#endif ++ ++static int mt9m111_ChangePage(unsigned char page) ++{ ++ static unsigned char old_page = 0xFF; ++ int res; ++ char tmp[3]={0xF0, 0, page}; ++ ++ if(page == old_page) ++ { ++ return 0; ++ } ++ ++ res = a780_camera_write(tmp, 3); ++ if(res < 0) ++ { ++ return res; ++ } ++ old_page = page; ++ ++ return 0; ++} ++ ++int mt9m111_read(unsigned short addr, unsigned short *pvalue) ++{ ++ unsigned char pageaddr = MT9M111_PAGE(addr); ++ unsigned char offset = MT9M111_OFFSET(addr); ++ unsigned short value; ++ int ret; ++ ++ if((ret = mt9m111_ChangePage(pageaddr)) != 0) ++ { ++ mt9m111_dbg_print("Change block address failed. block = 0x%2x", pageaddr); ++ mt9m111_dbg_print("Error code = 0x%x", ret); ++ return ret; ++ } ++ if(a780_camera_write(&offset, 1) < 0) ++ { ++ mt9m111_dbg_print("read error!"); ++ return ret; ++ } ++ ++ ret = a780_camera_read((char *)&value, 2); ++ if(ret < 0) ++ { ++ mt9m111_dbg_print("read error"); ++ return ret; ++ } ++ ++ *pvalue = (value >> 8) | (value << 8); ++ mt9m111_dbg_print("addr = 0x%04x, value = 0x%04x", addr, *pvalue); ++ return 0; ++} ++ ++int mt9m111_write(unsigned short addr, unsigned short value) ++{ ++ unsigned char pageaddr = MT9M111_PAGE(addr); ++ unsigned char offset = MT9M111_OFFSET(addr); ++ char tmp[3]={offset, (char)(value>>8), (char)(value&0xFF)}; ++ int ret; ++ ++ if((ret = mt9m111_ChangePage(pageaddr)) != 0) ++ { ++ mt9m111_dbg_print("Change block address failed. block = 0x%2x", pageaddr); ++ mt9m111_dbg_print("error code = 0x%x", ret); ++ return ret; ++ } ++ ret = a780_camera_write(tmp, 3); ++ if(ret < 0) ++ { ++ return ret; ++ } ++ mt9m111_dbg_print("addr = 0x%04x, value = 0x%04x", addr,value); ++ return 0; ++} ++ ++int i2c_mt9m111_cleanup(void) ++{ ++ i2c_camera_client_type = I2C_CLIENT_NONE; ++ return 0; ++} ++int i2c_mt9m111_init(void) ++{ ++ //unsigned short chipid; ++ a780_camera_client->addr = 0x5D; ++ ++ //mt9m111_read(0, &chipid); ++ //mt9m111_dbg_print("mt9m111 chip id is 0x%x", chipid); ++ ++ i2c_camera_client_type = I2C_CLIENT_MT9M111; ++ return 0; ++} ++ ++#endif // CONFIG_I2C_MT9M111 ++ ++#ifdef CONFIG_I2C_OV9650 ++ ++#define OV_REG_PID 0x0a ++#define OV_REG_VER 0x0b ++#define OV9650_CHIPID_M 0x96 ++#define OV9650_CHIPID_L_0 0x51 ++#define OV9650_CHIPID_L 0x52 ++ ++int i2c_ov9650_read(u8 addr, u8 *pvalue) ++{ ++ int ret; ++ ++ if((ret = a780_camera_write(&addr, 1)) < 0) ++ { ++ err_print("i2c write error code =%d", ret); ++ return -EIO; ++ } ++ ++ ret = a780_camera_read((char *)pvalue, 1); ++ if(ret < 0) ++ { ++ err_print("i2c read error code =%d", ret); ++ return -EIO; ++ } ++ ++ ddbg_print("addr = 0x%02x, value = 0x%02x", addr, *pvalue); ++ return 0; ++} ++ ++int i2c_ov9650_write(u8 addr, u8 value) ++{ ++ char tmp[2]={addr, value}; ++ int ret; ++ ++ ret = a780_camera_write(tmp, 2); ++ if(ret < 0) ++ { ++ err_print("i2c write error code =%d", ret); ++ return -EIO; ++ } ++ ++ ddbg_print("addr = 0x%02x, value = 0x%02x", addr,value); ++ return 0; ++} ++ ++int i2c_ov9650_cleanup(void) ++{ ++ i2c_camera_client_type = I2C_CLIENT_NONE; ++ return 0; ++} ++ ++int i2c_ov9650_init(void) ++{ ++ unsigned char chipid; ++ unsigned char ver; ++ // setup i2c address ++ a780_camera_client->addr = 0x30; //0x60; ++ ++ if( i2c_ov9650_read(OV_REG_PID, &chipid) < 0 ) ++ { ++ err_print("error: failed to read chipid"); ++ return -EIO; ++ } ++ if( chipid != OV9650_CHIPID_M ) ++ { ++ err_print("chip is not Omnivision"); ++ return -EIO; ++ } ++ ++ i2c_ov9650_read(OV_REG_VER, &ver); ++ dbg_print("ov chip id is 0x%x:0x%x", chipid, ver); ++ ++ if( ver != OV9650_CHIPID_L && ver != OV9650_CHIPID_L_0 ) ++ { ++ err_print("chip is not OV9650"); ++ return -EIO; ++ } ++ i2c_camera_client_type = I2C_CLIENT_OV9650; ++ i2c_camera_chipid = (chipid<<8) | ver; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_I2C_OV9640 ++int ov9640_read(u8 addr, u8 *pvalue) ++{ ++ return i2c_ov9650_read(addr, pvalue); ++} ++ ++int ov9640_write(u8 addr, u8 value) ++{ ++ return i2c_ov9650_write(addr, value); ++} ++ ++int i2c_ov9640_cleanup(void) ++{ ++ i2c_camera_client_type = I2C_CLIENT_NONE; ++ return 0; ++} ++ ++#define OV9640_CHIPID_M 0x96 ++#define OV9640_CHIPID_L 0x49 ++#define OV9640_CHIPID_L_V2 0x48 ++ ++int i2c_ov9640_init(void) ++{ ++ unsigned char chipid; ++ unsigned char ver; ++ // setup i2c address ++ a780_camera_client->addr = 0x30; //0x60; ++ ++ if( ov9640_read(OV_REG_PID, &chipid) < 0 ) ++ { ++ err_print("error: failed to read chipid"); ++ return -EIO; ++ } ++ if( chipid != OV9640_CHIPID_M ) ++ { ++ err_print("chip is not Omnivision"); ++ return -EIO; ++ } ++ ++ ov9640_read(OV_REG_VER, &ver); ++ dbg_print("ov chip id is 0x%x:0x%x", chipid, ver); ++ ++ if( ver != OV9640_CHIPID_L && ver != OV9640_CHIPID_L_V2 ) ++ { ++ err_print("chip is not OV9640"); ++ return -EIO; ++ } ++ i2c_camera_client_type = I2C_CLIENT_OV9640; ++ i2c_camera_chipid = (chipid<<8) | ver; ++ ++ return 0; ++} ++#endif // CONFIG_I2C_OV9640 ++ ++#endif // CONFIG_I2C_OV9650 ++ ++#ifdef CONFIG_I2C_ADCM3800 ++ ++#define ADCM3800_I2C_ADDR 0x56 ++#define ADCM3800_BLOCK_SWITCH_CMD 0xFE ++ ++/* Calculating the Module Block Number */ ++#define ADCM3800_BLOCK(a) ((u8)(((a) >> 7) & 0xFF)) /* register's module block address. */ ++#define ADCM3800_OFFSET(a) ((u8)(((a) << 1) & 0xFF)) /* register's offset to this block. */ ++#define ADCM3800_OFFSET_R(a) (ADCM3800_OFFSET(a)|1) /* register's offset ot this block to read*/ ++ ++static int adcm3800_ChgBlock(unsigned char block) ++{ ++ static unsigned char old_blk = 0xFF; ++ int res; ++ char tmp[2]={ADCM3800_BLOCK_SWITCH_CMD, block}; ++ ++ if(block == old_blk) ++ { ++ return 0; ++ } ++ ++ res = a780_camera_write(tmp, 2); ++ if(res < 0) ++ { ++ err_print("error code = %d", res); ++ return -EIO; ++ } ++ old_blk = block; ++ ++ return 0; ++} ++ ++int i2c_adcm3800_read_byte(unsigned short addr, unsigned char *pvalue) ++{ ++ unsigned char blockaddr = ADCM3800_BLOCK(addr); ++ unsigned char offset = ADCM3800_OFFSET_R(addr); ++ int ret; ++ ++ if((ret = adcm3800_ChgBlock(blockaddr)) != 0) ++ { ++ err_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -EIO; ++ } ++ if((ret = a780_camera_write(&offset, 1)) < 0) ++ { ++ err_print("i2c write error code =%d", ret); ++ return -EIO; ++ } ++ ++ ret = a780_camera_read((char *)pvalue, 1); ++ if(ret < 0) ++ { ++ err_print("i2c read error code = %d", ret); ++ return -EIO; ++ } ++ ddbg_print("read b: addr(0x%x) value(0x%x)", addr, *pvalue); ++ ++ return *pvalue; ++} ++ ++int i2c_adcm3800_read(unsigned short addr, unsigned short *pvalue) ++{ ++ unsigned char blockaddr = ADCM3800_BLOCK(addr); ++ unsigned char offset = ADCM3800_OFFSET_R(addr); ++ int ret; ++ ++ if((ret = adcm3800_ChgBlock(blockaddr)) != 0) ++ { ++ err_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -EIO; ++ } ++ if((ret = a780_camera_write(&offset, 1)) < 0) ++ { ++ err_print("i2c write error code =%d", ret); ++ return -EIO; ++ } ++ ++ ret = a780_camera_read((char *)pvalue, 2); ++ if(ret < 0) ++ { ++ err_print("i2c read error code = %d", ret); ++ return -EIO; ++ } ++ ddbg_print("read: addr(0x%x) value(0x%x)", addr, *pvalue); ++ ++ return *pvalue; ++} ++ ++int i2c_adcm3800_write_byte(unsigned short addr, unsigned char value) ++{ ++ unsigned char blockaddr = ADCM3800_BLOCK(addr); ++ unsigned char offset = ADCM3800_OFFSET(addr);; ++ char tmp[3]={offset, value}; ++ int ret; ++ ++ ddbg_print("write b: addr(0x%x) value(0x%x)", addr, value); ++ if((ret = adcm3800_ChgBlock(blockaddr)) != 0) ++ { ++ err_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -EIO; ++ } ++ ret = a780_camera_write(tmp, 2); ++ if(ret < 0) ++ { ++ err_print("i2c write error code = %d", ret); ++ return -EIO; ++ } ++ return 0; ++ ++} ++int i2c_adcm3800_write(unsigned short addr, unsigned short value) ++{ ++ unsigned char blockaddr = ADCM3800_BLOCK(addr); ++ unsigned char offset = ADCM3800_OFFSET(addr);; ++ char tmp[3]={offset, (char)(value&0xFF), (char)(value>>8)}; ++ int ret; ++ ++ ddbg_print("write: addr(0x%x) value(0x%x)", addr, value); ++ if((ret = adcm3800_ChgBlock(blockaddr)) != 0) ++ { ++ err_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -EIO; ++ } ++ ret = a780_camera_write(tmp, 3); ++ if(ret < 0) ++ { ++ err_print("i2c write error code = %d", ret); ++ return -EIO; ++ } ++ return 0; ++} ++ ++int i2c_adcm3800_cleanup(void) ++{ ++ i2c_camera_client_type = I2C_CLIENT_NONE; ++ return 0; ++} ++ ++#define ADCM_SREG_PID 0x0000 ++#define ADCM_EREG_PID 0x0800 ++ ++#define ADCM3800_PIPE_REV 0x0068 ++#define ADCM3800_SENSOR_REV 0x68 ++ ++int i2c_adcm3800_init(void) ++{ ++ unsigned short pid_pipe; ++ unsigned char pid_sensor; ++ a780_camera_client->addr = ADCM3800_I2C_ADDR; ++ ++ if(i2c_adcm3800_read(ADCM_SREG_PID, &pid_pipe) < 0) ++ { ++ return -EIO; ++ } ++ if(i2c_adcm3800_read_byte(ADCM_EREG_PID, &pid_sensor) < 0) ++ { ++ return -EIO; ++ } ++ ++ dbg_print("pipe id is 0x%x, sensor id is 0x%x", pid_pipe, pid_sensor); ++ if(pid_pipe != ADCM3800_PIPE_REV && pid_sensor != ADCM3800_SENSOR_REV) ++ { ++ err_print("sensor is not Agilent ADCM3800"); ++ return -EIO; ++ } ++ i2c_camera_client_type = I2C_CLIENT_ADCM3800; ++ i2c_camera_chipid = (pid_pipe<<8) | pid_sensor; ++ ++ return 0; ++} ++#endif // CONFIG_I2C_ADCM3800 ++ ++static int i2c_camera_readw(unsigned short addr, unsigned short *pvalue) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++#ifdef CONFIG_I2C_MT9M111 ++ case I2C_CLIENT_MT9M111: ++ ret = mt9m111_read(addr, pvalue); ++ break; ++#endif ++#ifdef CONFIG_I2C_ADCM3800 ++ case I2C_CLIENT_ADCM3800: ++ ret = i2c_adcm3800_read(addr, pvalue); ++ break; ++#endif ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int i2c_camera_readb(unsigned short addr, unsigned char *pvalue) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++#ifdef CONFIG_I2C_ADCM3800 ++ case I2C_CLIENT_ADCM3800: ++ ret = i2c_adcm3800_read_byte(addr, pvalue); ++ break; ++#endif ++#ifdef CONFIG_I2C_OV9640 ++ case I2C_CLIENT_OV9640: ++ ret = ov9640_read(addr, pvalue); ++ break; ++#endif ++#ifdef CONFIG_I2C_OV9650 ++ case I2C_CLIENT_OV9650: ++ ret = i2c_ov9650_read(addr, pvalue); ++ break; ++#endif ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int i2c_camera_writew(unsigned short addr, unsigned short value) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++#ifdef CONFIG_I2C_MT9M111 ++ case I2C_CLIENT_MT9M111: ++ ret = mt9m111_write(addr, value); ++ break; ++#endif ++#ifdef CONFIG_I2C_ADCM3800 ++ case I2C_CLIENT_ADCM3800: ++ ret = i2c_adcm3800_write(addr, value); ++ break; ++#endif ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int i2c_camera_writeb(unsigned short addr, unsigned char value) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++#ifdef CONFIG_I2C_ADCM3800 ++ case I2C_CLIENT_ADCM3800: ++ ret = i2c_adcm3800_write_byte(addr, value); ++ break; ++#endif ++#ifdef CONFIG_I2C_OV9640 ++ case I2C_CLIENT_OV9640: ++ ret = ov9640_write(addr, value); ++ break; ++#endif ++#ifdef CONFIG_I2C_OV9650 ++ case I2C_CLIENT_OV9650: ++ ret = i2c_ov9650_write(addr, value); ++ break; ++#endif ++ default: ++ break; ++ } ++ return ret; ++} ++ ++#ifdef CONFIG_I2C_MT9M111 ++EXPORT_SYMBOL(i2c_mt9m111_init); ++EXPORT_SYMBOL(mt9m111_write); ++EXPORT_SYMBOL(mt9m111_read); ++EXPORT_SYMBOL(i2c_mt9m111_cleanup); ++#endif ++ ++#ifdef CONFIG_I2C_OV9650 ++EXPORT_SYMBOL(i2c_ov9650_init); ++EXPORT_SYMBOL(i2c_ov9650_write); ++EXPORT_SYMBOL(i2c_ov9650_read); ++EXPORT_SYMBOL(i2c_ov9650_cleanup); ++#endif ++ ++#ifdef CONFIG_I2C_OV9640 ++EXPORT_SYMBOL(i2c_ov9640_init); ++EXPORT_SYMBOL(ov9640_write); ++EXPORT_SYMBOL(ov9640_read); ++EXPORT_SYMBOL(i2c_ov9640_cleanup); ++#endif ++ ++#ifdef CONFIG_I2C_ADCM3800 ++EXPORT_SYMBOL(i2c_adcm3800_init); ++EXPORT_SYMBOL(i2c_adcm3800_write); ++EXPORT_SYMBOL(i2c_adcm3800_read); ++EXPORT_SYMBOL(i2c_adcm3800_write_byte); ++EXPORT_SYMBOL(i2c_adcm3800_read_byte); ++EXPORT_SYMBOL(i2c_adcm3800_cleanup); ++#endif ++ ++module_init(a780_camera_init_module); ++module_exit(a780_camera_cleanup_module); ++MODULE_AUTHOR("Jay Jia"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/boomer.c linux-2.6.16/drivers/i2c/chips/boomer.c +--- linux-2.6.16.orig/drivers/i2c/chips/boomer.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/boomer.c 2006-06-03 11:14:56.411313432 +0200 +@@ -0,0 +1,175 @@ ++/* ++ * linux/drivers/i2c/boomer.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Jay Jia ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola 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. ++ * ++ * History: ++ * Jin Lihong(w20076),Motorola Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/videodev.h> ++#include <linux/init.h> ++#include <linux/kdev_t.h> ++#include <asm/semaphore.h> ++ ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++ ++ ++#define TESTCODE ++#undef TESTCODE ++#define I2C_MIXER 0x80 ++ ++static int mixer_adapter_attach(struct i2c_adapter *adap); ++static int mixer_detach(struct i2c_client *client); ++static int mixer_client_register(struct i2c_client *client); ++static int mixer_client_unregister(struct i2c_client *client); ++extern struct i2c_client *fmradio_client; ++/* ----------------------------------------------------------------------- */ ++static struct i2c_driver driver = { ++ .name = "mixer driver", ++ .id = I2C_MIXER, ++ //.flags = I2C_DF_DUMMY, ++ .attach_adapter = mixer_adapter_attach, ++ .detach_client = mixer_detach, ++ .owner = THIS_MODULE, ++}; ++ ++static struct i2c_adapter mixer_adapter = { ++ name: "Mixer adapter", ++ id: I2C_MIXER, ++ client_register: mixer_client_register, ++ client_unregister: mixer_client_unregister, ++}; ++ ++static struct i2c_client client_template = ++{ ++ name: "(unset)", ++ adapter:&mixer_adapter, ++}; ++ ++struct i2c_client *mixer_client; ++unsigned int mixer_minor; ++ ++int mixer_write(const char *buf, size_t count); ++int mixer_open(void) ++{ ++ //MOD_INC_USE_COUNT; ++ ++ ++#ifdef TESTCODE ++ char data[4]={0x18,0x7d,0xbd,0xcd}; ++ char freq[5]={0x2e,0x56,0x41,0x11,0x40}; ++ unsigned char s[5]={0, 0, 0, 0, 0}; ++ ++ mixer_write(data,4); ++// i2c_master_send(fmradio_client,freq,5); ++// printk("fmradio test code\n"); ++// mdelay(300); ++// i2c_master_recv(fmradio_client, s, 5); ++// printk("s0=%02x s1=%02x s2=%02x s3=%02x s4=%02x \n",s[0],s[1],s[2],s[3],s[4]); ++#endif ++ ++ ++ return 0; ++} ++ ++int mixer_release(void) ++{ ++ //MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++int mixer_write(const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long flags; ++ ++ mixer_open(); ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_send(mixer_client, buf, count); ++ local_irq_restore(flags); ++// printk("i2c-%d writing %d bytes.\n", mixer_minor, ret); ++ mixer_release(); ++ return ret; ++} ++ ++static int mixer_client_register(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static int mixer_client_unregister(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int mixer_adapter_attach(struct i2c_adapter *adap) ++{ ++ if(! (mixer_client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) ++ return -ENOMEM; ++ memcpy(mixer_client,&client_template,sizeof(struct i2c_client)); ++ mixer_client->adapter = adap; ++ ++ mixer_client->addr = 0x7c; ++ ++ printk("adapter %s\n",adap->name); ++ i2c_attach_client(mixer_client); ++#ifdef TESTCODE ++ mixer_open(); ++#endif ++ return 0; ++} ++ ++static int mixer_detach(struct i2c_client *client) ++{ ++ i2c_detach_client(mixer_client); ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int mixer_init_module(void) ++{ ++ int res; ++ ++ res = i2c_add_driver(&driver); ++ if( res < 0 ) ++ { ++ printk("error in add i2c driver\n"); ++ return res; ++ } ++ return 0; ++} ++ ++static void mixer_cleanup_module(void) ++{ ++ i2c_del_driver(&driver); ++} ++ ++module_init(mixer_init_module); ++module_exit(mixer_cleanup_module); ++MODULE_AUTHOR("Jay Jia"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/e680_camera.c linux-2.6.16/drivers/i2c/chips/e680_camera.c +--- linux-2.6.16.orig/drivers/i2c/chips/e680_camera.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/e680_camera.c 2006-06-03 11:14:56.412313280 +0200 +@@ -0,0 +1,668 @@ ++/* ++ * linux/drivers/i2c/e680_camera.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Jay Jia ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola 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. ++ * ++ * History: ++ * Jin Lihong(w20076),Motorola Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. ++ * ++ */ ++#include <linux/miscdevice.h> ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/videodev.h> ++#include <linux/pxa_camera.h> ++#include <linux/init.h> ++#include <linux/kdev_t.h> ++#include <asm/semaphore.h> ++ ++ ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/arch/hardware.h> ++#include "i2c-adcm2700.h" ++ ++/* Major 10, Minor 244, /dev/camerai2c */ ++#define CAM_NAME "cami2c" ++#define CAM_MINOR 244 ++ ++#define TESTCODE ++#undef TESTCODE ++#define I2C_E680_CAMERA 0x86 ++ ++#define I2C_CLIENT_NONE 0 ++#define I2C_CLIENT_ADCM2700 1 ++#define I2C_CLIENT_MT9V111 2 ++static int i2c_camera_client_type = I2C_CLIENT_NONE; ++static unsigned long i2c_camera_chipid = 0; ++#define REG_ADDRSELECT (0x01) ++#undef BLOCK(a) ++#define BLOCK(a) ((u8)(((a)>>7)&0xFF)) ++ ++static int e680_camera_adapter_attach(struct i2c_adapter *adap); ++static int e680_camera_detach(struct i2c_client *client); ++static int e680_camera_client_register(struct i2c_client *client); ++static int e680_camera_client_unregister(struct i2c_client *client); ++ ++typedef struct ++{ ++ u16 addr; ++ union {u16 word; u8 byte;}value; ++}i2c_camera_reg; ++/* ----------------------------------------------------------------------- */ ++static struct i2c_driver driver = { ++ .name = "e680 camera driver", ++ .id = I2C_E680_CAMERA, ++ //.flags = I2C_DF_DUMMY, ++ .attach_adapter = e680_camera_adapter_attach, ++ .detach_client = e680_camera_detach, ++ .owner = THIS_MODULE, ++}; ++ ++static struct i2c_adapter e680_camera_adapter = { ++ .name = "e680 camera adapter", ++ .id = I2C_E680_CAMERA, ++ .client_register = e680_camera_client_register, ++ .client_unregister = e680_camera_client_unregister, ++ .owner = THIS_MODULE, ++}; ++ ++static struct i2c_client client_template = ++{ ++ name: "(unset)", ++ adapter:&e680_camera_adapter, ++}; ++ ++struct i2c_client *e680_camera_client; ++unsigned int e680_camera_minor; ++ ++static int e680_camera_open(void) ++{ ++ //MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int e680_camera_release(void) ++{ ++ //MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++ ++int e680_camera_read(char *buf, size_t count) ++{ ++ int ret; ++ unsigned int flags; ++ ++ e680_camera_open(); ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_recv(e680_camera_client, buf, count); ++ local_irq_restore(flags); ++ e680_camera_release(); ++ return ret; ++ ++} ++ ++int e680_camera_write(const char *buf, size_t count) ++{ ++ int ret; ++ unsigned int flags; ++ ++ e680_camera_open(); ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_send(e680_camera_client, buf, count); ++ local_irq_restore(flags); ++ e680_camera_release(); ++ return ret; ++} ++ ++static int e680_camera_client_register(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++ ++static int e680_camera_client_unregister(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int e680_camera_adapter_attach(struct i2c_adapter *adap) ++{ ++ if(! (e680_camera_client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) ++ return -ENOMEM; ++ ++ memcpy(e680_camera_client,&client_template,sizeof(struct i2c_client)); ++ e680_camera_client->adapter = adap; ++ ++ /*adcm2700 i2c client address*/ ++ e680_camera_client->addr = 0x53; ++ i2c_attach_client(e680_camera_client); ++ return 0; ++} ++ ++static int e680_camera_detach(struct i2c_client *client) ++{ ++ i2c_detach_client(e680_camera_client); ++ return 0; ++} ++ ++/* ----------------------------------------------------------------------- */ ++static int cam_open(struct inode *inode, struct file *file) ++{ ++ if(i2c_camera_client_type == I2C_CLIENT_NONE) ++ return -EINVAL; ++ ++ //MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int i2c_camera_readw(unsigned short addr, unsigned short *pvalue); ++static int i2c_camera_readb(unsigned short addr, unsigned char *pvalue); ++static int i2c_camera_writew(unsigned short addr, unsigned short value); ++static int i2c_camera_writeb(unsigned short addr, unsigned char value); ++ ++static int cam_close(struct inode * inode, struct file *file) ++{ ++ //MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++#define DETECT_BUFLEN 256 ++static int cam_ioctl_detectid (void * arg) ++{ ++ int buflen, idlen; ++ char* id; ++ struct camera_i2c_detectid * param = arg; ++ if(copy_from_user(&buflen, &(param->buflen), sizeof(buflen))) ++ { ++ return -EFAULT; ++ } ++ if(buflen > DETECT_BUFLEN) ++ { ++ return -ENOMEM; ++ } ++ id = kmalloc(DETECT_BUFLEN, GFP_KERNEL); ++ if(id == NULL) ++ { ++ return -ENOMEM; ++ } ++ ++ idlen = 0; ++ switch(i2c_camera_client_type) ++ { ++ case I2C_CLIENT_MT9V111: ++ idlen = snprintf(id, DETECT_BUFLEN-1, "%s %s %lx", ++ "MICRON", "MT9V111", i2c_camera_chipid); ++ break; ++ case I2C_CLIENT_ADCM2700: ++ idlen = snprintf(id, DETECT_BUFLEN-1, "%s %s %lx", ++ "AGILENT", "ADCM2700", i2c_camera_chipid); ++ break; ++ default: ++ break; ++ } ++ id[DETECT_BUFLEN-1] = 0; ++ idlen = strlen(id)+1; ++ if(buflen < idlen) ++ { ++ kfree(id); ++ return -ENOMEM; ++ } ++ if(copy_to_user(param->data, id, idlen)) ++ { ++ kfree(id); ++ return -EFAULT; ++ } ++ kfree(id); ++ return 0; ++} ++ ++static int cam_ioctl_register_rw (unsigned int cmd, void * arg) ++{ ++ int ret = -ENOTSUPP; ++ struct camera_i2c_register reg; ++ if(copy_from_user(®, arg, sizeof(reg))) ++ { ++ return -EFAULT; ++ } ++ switch(cmd) ++ { ++ case CAMERA_I2C_WRITEW: ++ ret=i2c_camera_writew(reg.addr, reg.value.w); ++ break; ++ case CAMERA_I2C_WRITEB: ++ ret=i2c_camera_writeb(reg.addr, reg.value.b); ++ break; ++ case CAMERA_I2C_READW: ++ if((ret=i2c_camera_readw(reg.addr, &(reg.value.w)))>=0) ++ { ++ if(copy_to_user(arg, ®, sizeof(reg))) ++ ret = -EFAULT; ++ } ++ break; ++ case CAMERA_I2C_READB: ++ if((ret=i2c_camera_readb(reg.addr, &(reg.value.b)))>=0) ++ { ++ if(copy_to_user(arg, ®, sizeof(reg))) ++ ret = -EFAULT; ++ } ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int cam_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int ret = -ENOTSUPP; ++ switch (cmd) ++ { ++ case CAMERA_I2C_WRITEW: ++ case CAMERA_I2C_WRITEB: ++ case CAMERA_I2C_READW: ++ case CAMERA_I2C_READB: ++ ret = cam_ioctl_register_rw(cmd, (void *)arg); ++ break; ++ case CAMERA_I2C_DETECTID: ++ ret = cam_ioctl_detectid((void *)arg); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static struct file_operations cam_fops = { ++ ioctl: cam_ioctl, ++ open: cam_open, ++ release: cam_close, ++}; ++ ++static struct miscdevice cam_misc_device = { ++ CAM_MINOR, ++ CAM_NAME, ++ &cam_fops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++static int e680_camera_init_module(void) ++{ ++ int res; ++ ++ res = i2c_add_driver(&driver); ++ if( res < 0 ) ++ { ++ printk("error in add i2c driver\n"); ++ return res; ++ } ++ if (misc_register (&cam_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register cam driver\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void e680_camera_cleanup_module(void) ++{ ++ i2c_del_driver(&driver); ++ misc_deregister(&cam_misc_device); ++} ++/*-----------------------------------------------------------*/ ++static int ChgBlockAddr(unsigned char block) ++{ ++ static unsigned char old_blk = 0xFF; ++ int res; ++ char tmp[2]={BLOCK_SWITCH_CMD, block}; ++ ++ if(block == old_blk) ++ { ++ return 0; ++ } ++ ++ res = e680_camera_write(tmp, 2); ++ if(res < 0) ++ { ++ dbg_print("error code = %d", res); ++ return -1; ++ } ++ old_blk = block; ++ ++ return 0; ++} ++ ++int adcm2700_read(unsigned short addr, unsigned short *pvalue) ++{ ++ unsigned char blockaddr = BLOCK(addr); ++ unsigned char offset = OFFSET_R(addr); ++ int ret; ++ ++ if((ret = ChgBlockAddr(blockaddr)) != 0) ++ { ++ dbg_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -1; ++ } ++ if((ret = e680_camera_write(&offset, 1)) < 0) ++ { ++ dbg_print("i2c write error code =%d", ret); ++ return -1; ++ } ++ ++ ret = e680_camera_read((char *)pvalue, 2); ++ if(ret < 0) ++ { ++ dbg_print("i2c read error oce = %d", ret); ++ return -1; ++ } ++ ++ return *pvalue; ++} ++int adcm2700_write_byte(unsigned short addr, unsigned char value) ++{ ++ unsigned char blockaddr = BLOCK(addr); ++ unsigned char offset = OFFSET(addr);; ++ char tmp[3]={offset, value}; ++ int ret; ++ ++ if((ret = ChgBlockAddr(blockaddr)) != 0) ++ { ++ dbg_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -1; ++ } ++ ret = e680_camera_write(tmp, 2); ++ if(ret < 0) ++ { ++ dbg_print("i2c write error code = %d", ret); ++ return -1; ++ } ++ return 0; ++ ++} ++int adcm2700_read_byte(unsigned short addr, unsigned char * pvalue) ++{ ++ unsigned char blockaddr = BLOCK(addr); ++ unsigned char offset = OFFSET_R(addr);; ++ int ret; ++ ++ if((ret = ChgBlockAddr(blockaddr)) != 0) ++ { ++ dbg_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -1; ++ } ++ if((ret = e680_camera_write(&offset, 1)) < 0) ++ { ++ dbg_print("i2c write error code =%d", ret); ++ return -1; ++ } ++ ++ ret = e680_camera_read((char *)pvalue, 1); ++ if(ret < 0) ++ { ++ dbg_print("i2c read error oce = %d", ret); ++ return -1; ++ } ++ return 0; ++ ++} ++int adcm2700_write(unsigned short addr, unsigned short value) ++{ ++ unsigned char blockaddr = BLOCK(addr); ++ unsigned char offset = OFFSET(addr);; ++ char tmp[3]={offset, (char)(value&0xFF), (char)(value>>8)}; ++ int ret; ++ ++ if((ret = ChgBlockAddr(blockaddr)) != 0) ++ { ++ dbg_print("Change block address failed. block = 0x%2x", blockaddr); ++ return -1; ++ } ++ ret = e680_camera_write(tmp, 3); ++ if(ret < 0) ++ { ++ dbg_print("i2c write error code = %d", ret); ++ return -1; ++ } ++ return 0; ++} ++ ++int i2c_adcm2700_cleanup(void) ++{ ++ i2c_camera_client_type = I2C_CLIENT_NONE; ++ return 0; ++} ++int i2c_adcm2700_init(void) ++{ ++ unsigned short chipid; ++ unsigned short adcm_chipids[] = {ADCM2700_CHIP_ID, ADCM2700_CHIP_ID_NEW, 0x62}; ++ int i; ++ e680_camera_client->addr = 0x53; ++ ++ if(adcm2700_read(0, &chipid) < 0) ++ { ++ return -1; ++ } ++ ++ dbg_print("CHIP ID IS %x", chipid); ++ ++ for(i = 0; i < sizeof(adcm_chipids)/sizeof(adcm_chipids[0]); i++) ++ { ++ if(chipid == adcm_chipids[i]) ++ break; ++ } ++ ++ if(i >= sizeof(adcm_chipids)/sizeof(adcm_chipids[0])) ++ { ++ return -1; ++ } ++ ++ i2c_camera_client_type = I2C_CLIENT_ADCM2700; ++ i2c_camera_chipid = chipid; ++ ++ return 0; ++} ++//======================================================================= ++static int mt9v111_addr_select(unsigned char addrSpace) ++{ ++ int ret; ++ static u8 curSpace = 0; ++ char buf[3] = {REG_ADDRSELECT, 0, addrSpace}; ++ ++ if(curSpace != addrSpace) ++ { ++ if((ret = e680_camera_write(buf, 3)) < 0) ++ { ++ dbg_print("i2c write error code = %d", ret); ++ return ret; ++ } ++ curSpace = addrSpace; ++ } ++ return 0; ++} ++ ++int mt9v111_read(unsigned char addrSpace, unsigned short addr) ++{ ++ unsigned short value; ++ unsigned char reg_addr = (unsigned char)addr; ++ ++ if(addr != REG_ADDRSELECT) ++ { ++ if(mt9v111_addr_select(addrSpace) != 0) ++ { ++ dbg_print("Address space select failed. addrSpace = 0x%2x", addrSpace); ++ return -1; ++ } ++ } ++ if(e680_camera_write(®_addr, 1) < 0) ++ { ++ return -1; ++ } ++ ++ if(e680_camera_read((char *)&value, 2) < 0) ++ { ++ return -1; ++ } ++ ++ value = (value << 8 | value >> 8); ++ return value; ++} ++ ++int mt9v111_write(unsigned char addrSpace, unsigned short addr, unsigned short value) ++{ ++ int ret; ++ char buf[3] = {(char)addr, (char)(value>>8), (char)value}; ++ ++ if(addr != REG_ADDRSELECT) ++ { ++ if(mt9v111_addr_select(addrSpace) != 0) ++ { ++ dbg_print("Address space select failed. addrSpace = 0x%2x", addrSpace); ++ return -1; ++ } ++ } ++ ++ if((ret = e680_camera_write(buf, 3)) < 0) ++ { ++ dbg_print("write error code = %d", ret); ++ } ++ ++ return ret; ++} ++int i2c_mt9v111_cleanup(void) ++{ ++ i2c_camera_client_type = I2C_CLIENT_NONE; ++ return 0; ++} ++int i2c_mt9v111_init(void) ++{ ++ int chipid; ++ e680_camera_client->addr = 0x5C; ++ ++ if((chipid = mt9v111_read(0x04, 0x36)) < 0) ++ { ++ return -1; ++ } ++ ++ if((chipid & 0xFF00) != 0x8200) ++ { ++ return -1; ++ } ++ ++ i2c_camera_client_type = I2C_CLIENT_MT9V111; ++ i2c_camera_chipid = chipid; ++ ++ return 0; ++ ++} ++ ++static int i2c_camera_readw(unsigned short addr, unsigned short *pvalue) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++ case I2C_CLIENT_MT9V111: ++ ret = mt9v111_read((addr>>8), (addr&0xFF)); ++ if(ret > 0) ++ { ++ *pvalue = (u16)ret; ++ } ++ break; ++ case I2C_CLIENT_ADCM2700: ++ ret = adcm2700_read(addr, pvalue); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int i2c_camera_readb(unsigned short addr, unsigned char *pvalue) ++{ ++ int ret = -ENOTSUPP; ++ unsigned short value; ++ switch(i2c_camera_client_type) ++ { ++ case I2C_CLIENT_ADCM2700: ++ ret = adcm2700_read(addr, &value); ++ *pvalue = (value>>8); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int i2c_camera_writew(unsigned short addr, unsigned short value) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++ case I2C_CLIENT_MT9V111: ++ ret = mt9v111_write((addr>>8), (addr&0xFF), value); ++ break; ++ case I2C_CLIENT_ADCM2700: ++ ret = adcm2700_write(addr, value); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static int i2c_camera_writeb(unsigned short addr, unsigned char value) ++{ ++ int ret = -ENOTSUPP; ++ switch(i2c_camera_client_type) ++ { ++ case I2C_CLIENT_ADCM2700: ++ ret = adcm2700_write_byte(addr, value); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++ ++EXPORT_SYMBOL(i2c_adcm2700_init); ++EXPORT_SYMBOL(adcm2700_write); ++EXPORT_SYMBOL(adcm2700_write_byte); ++EXPORT_SYMBOL(adcm2700_read_byte); ++EXPORT_SYMBOL(adcm2700_read); ++EXPORT_SYMBOL(i2c_adcm2700_cleanup); ++ ++EXPORT_SYMBOL(i2c_mt9v111_init); ++EXPORT_SYMBOL(mt9v111_write); ++EXPORT_SYMBOL(mt9v111_read); ++EXPORT_SYMBOL(i2c_mt9v111_cleanup); ++ ++module_init(e680_camera_init_module); ++module_exit(e680_camera_cleanup_module); ++MODULE_AUTHOR("Jay Jia"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/i2c-adcm2700.h linux-2.6.16/drivers/i2c/chips/i2c-adcm2700.h +--- linux-2.6.16.orig/drivers/i2c/chips/i2c-adcm2700.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/i2c-adcm2700.h 2006-06-03 11:14:56.412313280 +0200 +@@ -0,0 +1,65 @@ ++ ++/*================================================================================ ++ ++ Header Name: i2c-adcm2700.h ++ ++General Description: Camera module adcm2700 I2C interface head file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef __I2C_ADCM2700_H__ ++#define __I2C_ADCM2700_H__ ++ ++#define DEBUG ++ ++/* Calculating the Module Block Number */ ++#define BLOCK(a) ((u8)(((a) >> 7) & 0x7F)) /* register's module block address. */ ++#define OFFSET(a) ((u8)(((a) << 1) & 0xFF)) /* register's offset to this block. */ ++#define OFFSET_R(a) (OFFSET(a)|1) /* register's offset ot this block to read*/ ++ ++#define BLOCK_SWITCH_CMD 0xFE ++#define ADCM2700_I2C_ADDR 0x53 ++#define I2C_DRIVERID_ADCM2700 I2C_DRIVERID_EXP1 ++#define ADCM2700_CHIP_ID 0x0060 ++#define ADCM2700_CHIP_ID_NEW 0x0061 ++#define REV_ID 0x0 /* Register definitions in ADCM2700's chip. */ ++ ++ ++struct adcm2700_data { ++ /* ++ * Because the i2c bus is slow, it is often useful to cache the read ++ * information of a chip for some time (for example, 1 or 2 seconds). ++ * It depends of course on the device whether this is really worthwhile ++ * or even sensible. ++ */ ++ struct semaphore update_lock; /* When we are reading lots of information, ++ another process should not update the ++ below information */ ++ ++ char valid; /* != 0 if the following fields are valid. */ ++ int blockaddr; /* current using block address. */ ++ unsigned long last_updated; /* In jiffies */ ++}; ++ ++#ifdef DEBUG ++#define dbg_print(fmt, args...) printk(KERN_INFO "I2C-ADCM2700 in fun:%s "fmt"\n", __FUNCTION__, ##args) ++#else ++#define dbg_print(fmt, args...) ; ++#endif ++ ++#endif /* __I2C_ADCM2700_H__ */ ++ +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/i2c-ov9640.c linux-2.6.16/drivers/i2c/chips/i2c-ov9640.c +--- linux-2.6.16.orig/drivers/i2c/chips/i2c-ov9640.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/i2c-ov9640.c 2006-06-03 11:14:56.421311912 +0200 +@@ -0,0 +1,303 @@ ++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <asm/hardware.h>
++#include <asm/types.h>
++#include <linux/delay.h>
++
++#include "i2c-ov9640.h"
++
++#define DEBUG 1
++#define DPRINTK(fmt,args...) do { if (DEBUG) printk("in function %s "fmt,__FUNCTION__,##args);} while(0)
++extern int i2c_adapter_id(struct i2c_adapter *adap);
++
++int i2c_ov9640_cleanup(void);
++void i2c_ov9640_inc_use (struct i2c_client *client);
++void i2c_ov9640_dec_use (struct i2c_client *client);
++int i2c_ov9640_attach_adapter(struct i2c_adapter *adapter);
++int i2c_ov9640_detect_client(struct i2c_adapter *, int, unsigned short, int);
++int i2c_ov9640_detach_client(struct i2c_client *client);
++
++struct i2c_driver ov9640_driver =
++{
++ name: "ov9640 driver", /* name */
++ id: I2C_DRIVERID_OV9640, /* id */
++ flags: I2C_DF_NOTIFY, /* flags */
++ attach_adapter: &i2c_ov9640_attach_adapter, /* attach_adapter */
++ detach_client: &i2c_ov9640_detach_client, /* detach_client */
++ command: NULL,
++ inc_use: &i2c_ov9640_inc_use,
++ dec_use: &i2c_ov9640_dec_use
++};
++
++extern struct i2c_adapter *i2cdev_adaps[];
++/* Unique ID allocation */
++static int ov9640_id = 0;
++struct i2c_client *g_client = NULL;
++static unsigned short normal_i2c[] = {OV9640_SLAVE_ADDR ,I2C_CLIENT_END };
++static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
++I2C_CLIENT_INSMOD;
++
++/*
++ * This call returns a unique low identifier for each registered adapter,
++ * or -1 if the adapter was not registered.
++ */
++void i2c_ov9640_inc_use (struct i2c_client *client)
++{
++ MOD_INC_USE_COUNT;
++#ifdef MODULE
++#endif
++}
++
++void i2c_ov9640_dec_use (struct i2c_client *client)
++{
++ MOD_DEC_USE_COUNT;
++#ifdef MODULE
++#endif
++}
++
++char ov9640_read(u8 addr, u8 *pvalue)
++{
++ int res=0;
++ char buf=0;
++ struct i2c_msg msgs[2] = {
++ { 0, I2C_M_WR, 1, &addr },
++ { 0, I2C_M_RD, 1, &buf }};
++
++ if( g_client == NULL )
++ return -1;
++ i2c_ov9640_inc_use(g_client);
++ msgs[0].addr=msgs[1].addr=g_client->addr;
++ res=i2c_transfer(g_client->adapter,&msgs[0],1);
++ if (res<=0)
++ goto out;
++ res=i2c_transfer(g_client->adapter,&msgs[1],1);
++ if (res<=0)
++ goto out;
++ *pvalue = buf;
++ i2c_ov9640_dec_use(g_client);
++out:
++ DPRINTK(KERN_INFO "In funtion %s addr:%x,value=%x\n", __FUNCTION__, addr,*pvalue);
++ if (res<=0) DPRINTK("res = %d \n",res);
++ return res;
++}
++
++int ov9640_write(u8 addr, u8 value)
++{
++ int res=0;
++ if( g_client == NULL )
++ return -1;
++ /*
++ char buf=0;
++ struct i2c_msg msgs[2] = {
++ { 0, I2C_M_WR, 1, &addr },
++ { 0, I2C_M_WR, 1, &value }};
++ msgs[0].addr=msgs[1].addr=g_client->addr;
++ res=i2c_transfer(g_client->adapter,&msgs[0],1);
++ if (res<=0) return res;
++ res=i2c_transfer(g_client->adapter,&msgs[1],1);
++ if (res<=0) return res;
++
++
++ res=i2c_smbus_write_byte_data(g_client, addr, value );
++ */
++ char buf[2]={addr,value};
++ i2c_ov9640_inc_use(g_client);
++ res = i2c_master_send(g_client, buf, 2);
++ i2c_ov9640_dec_use(g_client);
++ if (res >0) res =0;
++ else res =-1;
++ DPRINTK(KERN_INFO "In funtion %s addr:%x value:%xreturn %d \n", __FUNCTION__, addr,value,res);
++ return res;
++}
++
++
++int i2c_ov9640_read(struct i2c_client *client, u8 reg)
++{
++ unsigned char msgbuf=0;
++ DPRINTK("in function %s\n",__FUNCTION__);
++ i2c_master_recv(client,&msgbuf,1);
++ return msgbuf;
++ /*
++ */
++// return i2c_smbus_read_word_data(client,reg);
++// return i2c_smbus_read_byte_data(client,reg);
++}
++
++int i2c_ov9640_write(struct i2c_client *client, u8 reg, u16 value)
++{
++ return i2c_smbus_write_word_data(client,reg,value);
++}
++
++
++int i2c_ov9640_attach_adapter(struct i2c_adapter *adap)
++{
++ DPRINTK("In function %s.\n", __FUNCTION__);
++ return i2c_probe(adap,&addr_data,i2c_ov9640_detect_client);
++}
++
++
++int i2c_ov9640_detect_client(struct i2c_adapter *adapter, int address, unsigned short flags, int kind)
++{
++ struct i2c_client *new_client;
++ int err = 0;
++ struct ov9640_data *data;
++
++ /*check if */
++ if(g_client != NULL) {
++ err = -ENXIO;
++ goto ERROR0;
++ }
++
++
++ DPRINTK(KERN_INFO "In funtion %s. address=0X%X\n", __FUNCTION__, address);
++ /* Let's see whether this adapter can support what we need.
++ Please substitute the things you need here! */
++ if ( !i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA) ) {
++ DPRINTK(KERN_INFO "Word op is not permited.\n");
++ goto ERROR0;
++ }
++
++ /* OK. For now, we presume we have a valid client. We now create the
++ client structure, even though we cannot fill it completely yet.
++ But it allows us to access several i2c functions safely */
++
++ /* Note that we reserve some space for ov9640_data too. If you don't
++ need it, remove it. We do it here to help to lessen memory
++ fragmentation. */
++
++ new_client=kmalloc(sizeof(struct i2c_client)+sizeof(struct ov9640_data),
++ GFP_KERNEL );
++
++ if ( !new_client ) {
++ err = -ENOMEM;
++ goto ERROR0;
++ }
++
++ data = (struct ov9640_data *) (new_client + 1);
++
++ new_client->addr = address;
++ new_client->data = data;
++ new_client->adapter = adapter;
++ new_client->driver = &ov9640_driver;
++ new_client->flags = 0;
++
++ g_client = new_client;
++
++ /* Now, we do the remaining detection. If no `force' parameter is used. */
++
++ /* First, the generic detection (if any), that is skipped if any force
++ parameter was used. */
++
++ if (kind <= 0) {
++ char res = -1;
++ mdelay(2000);
++ ov9640_read(REV,&res);
++ /* The below is of course bogus */
++ DPRINTK("I2C: Probe ov9640 chip..addr=0x%x, REV=%d, res=0x%x\n", address, REV, res);
++ /*ov9640 chip id is 0x9648
++ if(res != OV9640_CHIP_ID) {
++ DPRINTK(KERN_WARNING "Failed.product id =%d \n",res);
++ goto ERROR1;
++ }
++ else {
++ DPRINTK("OV9640 chip id is 0X%04X\n", OV9640_CHIP_ID);
++ if ( ov9640_id == 0 )
++ DPRINTK(" detected.\n");
++ }*/
++ }
++
++ strcpy(new_client->name, "ov9640");
++ /* Automatically unique */
++ new_client->id = ov9640_id++;
++
++ /* Only if you use this field */
++ data->valid = 0;
++
++ /* Only if you use this field */
++ init_MUTEX(&data->update_lock);
++
++ /* Tell the i2c layer a new client has arrived */
++ if ((err = i2c_attach_client(new_client)))
++ goto ERROR3;
++
++ /* This function can write default values to the client registers, if
++ needed. */
++ /* ov9640_init_client(new_client); */
++ return 0;
++
++ /* OK, this is not exactly good programming practice, usually. But it is
++ very code-efficient in this case. */
++
++ERROR3:
++ERROR1:
++ kfree(new_client);
++ g_client = NULL;
++ERROR0:
++ return err;
++}
++
++int i2c_ov9640_detach_client(struct i2c_client *client)
++{
++ int err;
++
++ /* Try to detach the client from i2c space */
++ if ((err = i2c_detach_client(client))) {
++ DPRINTK("ov9640.o: Client deregistration failed, client not detached.\n");
++ return err;
++ }
++
++ kfree(client); /* Frees client data too, if allocated at the same time */
++ g_client = NULL;
++ return 0;
++}
++
++/* Keep track of how far we got in the initialization process. If several
++ things have to initialized, and we fail halfway, only those things
++ have to be cleaned up! */
++static int ov9640_initialized = 0;
++
++int i2c_ov9640_init(void)
++{
++ int res;
++
++ if (ov9640_initialized)
++ return 0;
++ DPRINTK("I2C: driver for device ov9640.\n");
++ if ( (res = i2c_add_driver(&ov9640_driver)) ) {
++ DPRINTK("ov9640: Driver registration failed, module not inserted.\n");
++ i2c_ov9640_cleanup();
++ return res;
++ }
++ ov9640_initialized ++;
++ if(g_client != NULL)
++ DPRINTK("I2C: driver for device %s registed!.\n", g_client->name);
++ else
++ DPRINTK("I2C: driver for device unregisted!.\n");
++ return 0;
++}
++
++int i2c_ov9640_cleanup(void)
++{
++ int res;
++
++ if (ov9640_initialized == 1) {
++ if ((res = i2c_del_driver(&ov9640_driver))) {
++ DPRINTK("ov9640: Driver registration failed, module not removed.\n");
++ return res;
++ }
++ ov9640_initialized --;
++ }
++ return 0;
++}
++
++EXPORT_SYMBOL(i2c_ov9640_init);
++EXPORT_SYMBOL(ov9640_write);
++EXPORT_SYMBOL(ov9640_read);
++EXPORT_SYMBOL(i2c_ov9640_cleanup);
++//module_init(i2c_ov9640_init);
++//module_exit(i2c_ov9640_cleanup);
++MODULE_LICENSE("GPL");
++
+diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/i2c-ov9640.h linux-2.6.16/drivers/i2c/chips/i2c-ov9640.h +--- linux-2.6.16.orig/drivers/i2c/chips/i2c-ov9640.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/i2c-ov9640.h 2006-06-03 11:14:56.421311912 +0200 +@@ -0,0 +1,42 @@ ++#ifndef __I2C_OV9640_H__
++#define __I2C_OV9640_H__
++
++#define DEBUG
++
++/* Calculating the Module Block Number */
++#define BLOCK(a) (u8)((a) >> 7) /* register's module block address. */
++#define OFFSET(a) (u8)((a) & 0x7F ) /* register's offset to this block. */
++
++/* Update the block address.*/
++#define BLOCK_SWITCH_CMD 0xFE
++
++#define OV9640_SLAVE_ADDR (0x60>>1) /* 60 for write , 61 for read */
++// #define SENSOR_SLAVE_ADDR 0x0055 /* tbd: */
++
++
++#define I2C_DRIVERID_OV9640 I2C_DRIVERID_EXP2
++
++/*ov9640 chip id*/
++#define OV9640_CHIP_ID 0x9648
++
++/* Register definitions in OV9640's chip. */
++#define PID 0xA
++#define REV 0xA
++
++struct ov9640_data {
++ /*
++ * Because the i2c bus is slow, it is often useful to cache the read
++ * information of a chip for some time (for example, 1 or 2 seconds).
++ * It depends of course on the device whether this is really worthwhile
++ * or even sensible.
++ */
++ struct semaphore update_lock; /* When we are reading lots of information,
++ another process should not update the
++ below information */
++
++ char valid; /* != 0 if the following fields are valid. */
++ int blockaddr; /* current using block address. */
++ unsigned long last_updated; /* In jiffies */
++};
++#endif
++
+diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/Kconfig linux-2.6.16/drivers/i2c/chips/Kconfig +--- linux-2.6.16.orig/drivers/i2c/chips/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/Kconfig 2006-06-03 11:14:56.398315408 +0200 +@@ -135,4 +135,25 @@ + This driver can also be built as a module. If so, the module + will be called x1205. + ++config I2C_ADCM2700 ++ tristate "ADCM2700 support" ++ depends on I2C_PXA ++ ++config I2C_A780_CAMERA ++ tristate "A780 camera support" ++ depends on I2C_PXA ++ ++config I2C_OV9640 ++ depends on I2C_A780_CAMERA ++ bool "OV9640 support" ++config I2C_OV9650 ++ depends on I2C_A780_CAMERA ++ bool "OV9650 support" ++config I2C_MT9M111 ++ depends on I2C_A780_CAMERA ++ bool "MT9M111 support" ++config I2C_ADCM3800 ++ depends on I2C_A780_CAMERA ++ bool "ADCM3800 support" ++ + endmenu +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/m41t00.c linux-2.6.16/drivers/i2c/chips/m41t00.c +--- linux-2.6.16.orig/drivers/i2c/chips/m41t00.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/m41t00.c 2006-06-03 11:14:55.273486408 +0200 +@@ -129,13 +129,13 @@ + if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0) + || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f) + < 0) +- || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x7f) ++ || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x3f) + < 0) +- || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x7f) ++ || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x3f) + < 0) +- || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x7f) ++ || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x1f) + < 0) +- || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0x7f) ++ || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0xff) + < 0)) + + dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n"); +diff -Nurd linux-2.6.16.orig/drivers/i2c/chips/Makefile linux-2.6.16/drivers/i2c/chips/Makefile +--- linux-2.6.16.orig/drivers/i2c/chips/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/Makefile 2006-06-03 11:14:56.409313736 +0200 +@@ -15,6 +15,10 @@ + obj-$(CONFIG_TPS65010) += tps65010.o + obj-$(CONFIG_RTC_X1205_I2C) += x1205.o + ++obj-$(CONFIG_I2C_ADCM2700) += e680_camera.o ++obj-$(CONFIG_I2C_A780_CAMERA) += a780_camera.o ++obj-$(CONFIG_PXA_EZX_E680) += boomer.o ++ + ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) + EXTRA_CFLAGS += -DDEBUG + endif +diff -Nurd linux-2.6.16.orig/drivers/ide/pci/alim15x3.c linux-2.6.16/drivers/ide/pci/alim15x3.c +--- linux-2.6.16.orig/drivers/ide/pci/alim15x3.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/ide/pci/alim15x3.c 2006-06-03 11:14:55.274486256 +0200 +@@ -731,6 +731,8 @@ + + if(m5229_revision <= 0x20) + tmpbyte = (tmpbyte & (~0x02)) | 0x01; ++ else if (m5229_revision == 0xc7) ++ tmpbyte |= 0x03; + else + tmpbyte |= 0x01; + +diff -Nurd linux-2.6.16.orig/drivers/ieee1394/sbp2.c linux-2.6.16/drivers/ieee1394/sbp2.c +--- linux-2.6.16.orig/drivers/ieee1394/sbp2.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/ieee1394/sbp2.c 2006-06-03 11:14:55.275486104 +0200 +@@ -495,22 +495,17 @@ + /* + * This function finds the sbp2_command for a given outstanding SCpnt. + * Only looks at the inuse list. ++ * Must be called with scsi_id->sbp2_command_orb_lock held. + */ +-static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt) ++static struct sbp2_command_info *sbp2util_find_command_for_SCpnt( ++ struct scsi_id_instance_data *scsi_id, void *SCpnt) + { + struct sbp2_command_info *command; +- unsigned long flags; + +- spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); +- if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { +- list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) { +- if (command->Current_SCpnt == SCpnt) { +- spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); ++ if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) ++ list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) ++ if (command->Current_SCpnt == SCpnt) + return command; +- } +- } +- } +- spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); + return NULL; + } + +@@ -579,17 +574,15 @@ + + /* + * This function moves a command to the completed orb list. ++ * Must be called with scsi_id->sbp2_command_orb_lock held. + */ +-static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, +- struct sbp2_command_info *command) ++static void sbp2util_mark_command_completed( ++ struct scsi_id_instance_data *scsi_id, ++ struct sbp2_command_info *command) + { +- unsigned long flags; +- +- spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); + list_del(&command->list); + sbp2util_free_command_dma(command); + list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); +- spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); + } + + /* +@@ -2177,7 +2170,9 @@ + * Matched status with command, now grab scsi command pointers and check status + */ + SCpnt = command->Current_SCpnt; ++ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); + sbp2util_mark_command_completed(scsi_id, command); ++ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); + + if (SCpnt) { + +@@ -2513,6 +2508,7 @@ + (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; + struct sbp2scsi_host_info *hi = scsi_id->hi; + struct sbp2_command_info *command; ++ unsigned long flags; + + SBP2_ERR("aborting sbp2 command"); + scsi_print_command(SCpnt); +@@ -2523,6 +2519,7 @@ + * Right now, just return any matching command structures + * to the free pool. + */ ++ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); + command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); + if (command) { + SBP2_DEBUG("Found command to abort"); +@@ -2540,6 +2537,7 @@ + command->Current_done(command->Current_SCpnt); + } + } ++ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); + + /* + * Initiate a fetch agent reset. +diff -Nurd linux-2.6.16.orig/drivers/input/keyboard/Kconfig linux-2.6.16/drivers/input/keyboard/Kconfig +--- linux-2.6.16.orig/drivers/input/keyboard/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/input/keyboard/Kconfig 2006-06-03 11:14:56.974227856 +0200 +@@ -183,4 +183,11 @@ + This driver implements support for HIL-keyboards attached + to your machine, so normally you should say Y here. + ++config KEYBOARD_PXA ++ tristate "Intel PXA keyboard support" ++ depends on ARCH_PXA ++ help ++ This add support for a driver of the Intel PXA2xx keyboard ++ controller. ++ + endif +diff -Nurd linux-2.6.16.orig/drivers/input/keyboard/Makefile linux-2.6.16/drivers/input/keyboard/Makefile +--- linux-2.6.16.orig/drivers/input/keyboard/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/input/keyboard/Makefile 2006-06-03 11:14:56.974227856 +0200 +@@ -15,4 +15,5 @@ + obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o + obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o + obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o ++obj-$(CONFIG_KEYBOARD_PXA) += pxakbd.o + +diff -Nurd linux-2.6.16.orig/drivers/input/keyboard/pxakbd.c linux-2.6.16/drivers/input/keyboard/pxakbd.c +--- linux-2.6.16.orig/drivers/input/keyboard/pxakbd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/input/keyboard/pxakbd.c 2006-06-03 11:14:56.978227248 +0200 +@@ -0,0 +1,411 @@ ++/* ++ * Driver for Motorola EZX phone "keyboard" ++ * ++ * (C) 2006 by Harald Welte <laforge@openezx.org> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/input.h> ++#include <linux/spinlock.h> ++#include <linux/platform_device.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++ ++#include <asm/arch/kbd.h> ++#include <asm/arch/irqs.h> ++#include <asm/arch/pxa-regs.h> ++ ++#if 0 ++#define DEBUGP(x, args ...) printk(x, ## args) ++#else ++#define DEBUGP(x, args ...) ++#endif ++ ++/* per-keyboard private data structure */ ++struct pxakbd { ++ struct input_dev *input; ++ struct timer_list timer; ++ spinlock_t lock; ++ ++ struct resource *res; ++ unsigned int irq; ++ ++ struct pxakbd_platform_data *pd; ++}; ++ ++static int pxakbd_scan_direct(struct pxakbd *pxakbd) ++{ ++ u_int32_t kpdk; ++ unsigned int i; ++ int num_pressed = 0; ++ ++ kpdk = KPDK & 0x0000000f; ++ ++ for (i = 0; i < pxakbd->pd->direct.num; i++) { ++ int pressed = 0; ++ ++ if (kpdk & (1 << i)) { ++ pressed = 1; ++ num_pressed++; ++ DEBUGP("pxakbd: pressed: direct %u\n", i); ++ } ++ ++ input_report_key(pxakbd->input, pxakbd->pd->direct.keycode[i], ++ pressed); ++ } ++ ++ return num_pressed; ++} ++ ++/* read the full 8x8 matrix from the PXA27x keypad controller */ ++static void __read_matrix(u_int8_t *matrix) ++{ ++ u_int32_t tmp; ++ ++ tmp = KPASMKP0; ++ matrix[0] = tmp & 0x000000ff; ++ matrix[1] = (tmp & 0x00ff0000) >> 16; ++ ++ tmp = KPASMKP1; ++ matrix[2] = tmp & 0x000000ff; ++ matrix[3] = (tmp & 0x00ff0000) >> 16; ++ ++ tmp = KPASMKP2; ++ matrix[4] = tmp & 0x000000ff; ++ matrix[5] = (tmp & 0x00ff0000) >> 16; ++ ++ tmp = KPASMKP3; ++ matrix[6] = tmp & 0x000000ff; ++ matrix[7] = (tmp & 0x00ff0000) >> 16; ++} ++ ++/* compare current matrix with last, generate 'diff' events */ ++static int __cmp_matrix_gen_events(struct pxakbd *pxakbd, u_int8_t *matrix) ++{ ++ unsigned int i; ++ int num_pressed = 0; ++ ++ /* iterate over the matrix */ ++ for (i = 0; i < pxakbd->pd->matrix.rows; i++) { ++ unsigned int j; ++ for (j = 0; j < pxakbd->pd->matrix.cols; j++) { ++ u_int32_t scancode = ++ (i * pxakbd->pd->matrix.cols) + j; ++ int pressed = matrix[i] & (1 << j); ++ ++ if (pressed) { ++ DEBUGP("pxakbd: pressed: %u/%u\n", i, j); ++ num_pressed++; ++ } ++ ++ input_report_key(pxakbd->input, ++ pxakbd->pd->matrix.keycode[scancode], pressed); ++ } ++ } ++ ++ return num_pressed; ++} ++ ++/* scan the matrix keypad */ ++static int pxakbd_scan_matrix(struct pxakbd *pxakbd) ++{ ++ int num_pressed; ++ u_int32_t kpas; ++ u_int8_t matrix[8]; ++ ++ kpas = KPAS; ++ ++ if ((kpas & KPAS_MUKP) == KPAS_MUKP_NONE) { ++ /* no keys pressed */ ++ memset(matrix, 0, sizeof(matrix)); ++ } else if ((kpas & KPAS_MUKP) == KPAS_MUKP_ONE) { ++ /* one key pressed */ ++ u_int8_t row = (kpas & KPAS_RP) >> 4; ++ u_int8_t col = kpas & KPAS_CP; ++ ++ if (row == 0x0f || col == 0x0f) { ++ printk(KERN_WARNING "pxakbd: col or row invalid!\n"); ++ return -1; ++ } ++ ++ /* clear the matrix and set the single pressed key */ ++ memset(matrix, 0, sizeof(matrix)); ++ matrix[row] |= (1 << col); ++ } else { ++ /* multiple keys pressed */ ++ __read_matrix(matrix); ++ } ++ ++ num_pressed = __cmp_matrix_gen_events(pxakbd, matrix); ++ ++ return num_pressed; ++} ++ ++static void pxakbd_timer_callback(unsigned long data) ++{ ++ unsigned long flags; ++ struct pxakbd *pxakbd = (struct pxakbd *) data; ++ unsigned int num_pressed; ++ ++ spin_lock_irqsave(&pxakbd->lock, flags); ++ ++ num_pressed = pxakbd_scan_direct(pxakbd); ++ num_pressed += pxakbd_scan_matrix(pxakbd); ++ ++ spin_unlock_irqrestore(&pxakbd->lock, flags); ++ ++ /* propagate events up the input stack */ ++ input_sync(pxakbd->input); ++} ++ ++static irqreturn_t pxakbd_interrupt(int irq, void *dummy, struct pt_regs *regs) ++{ ++ struct pxakbd *pxakbd = dummy; ++ u_int32_t kpc; ++ int handled = 0; ++ int num_pressed = 0; ++ ++ /* read and clear interrupt */ ++ kpc = KPC; ++ ++ if (kpc & KPC_DI) { ++ num_pressed += pxakbd_scan_direct(pxakbd); ++ handled = 1; ++ } ++ ++ if (kpc & KPC_MI) { ++ while (KPAS & KPAS_SO) { ++ /* wait for scan to complete beforereading scan regs */ ++ cpu_relax(); ++ } ++ num_pressed += pxakbd_scan_matrix(pxakbd); ++ handled = 1; ++ } ++ ++ /* If any keys are currently pressed, we need to start the timer to detect ++ * key release. */ ++ if (num_pressed) ++ mod_timer(&pxakbd->timer, jiffies + pxakbd->pd->scan_interval); ++ ++ /* propagate events up the input stack */ ++ input_sync(pxakbd->input); ++ ++ return IRQ_RETVAL(handled); ++} ++ ++static int __init pxakbd_probe(struct platform_device *pdev) ++{ ++ struct pxakbd *pxakbd; ++ struct input_dev *input_dev; ++ struct resource *r; ++ int i; ++ int ret = -ENOMEM; ++ ++ pxakbd = kzalloc(sizeof(*pxakbd), GFP_KERNEL); ++ if (!pxakbd) ++ goto out; ++ ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ goto out_pxa; ++ ++ pxakbd->irq = platform_get_irq(pdev, 0); ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r || pxakbd->irq == NO_IRQ) { ++ printk(KERN_ERR "pxakbd: invalid resources\n"); ++ ret = -EBUSY; ++ goto out_idev; ++ } ++ ++ pxakbd->input = input_dev; ++ init_timer(&pxakbd->timer); ++ pxakbd->timer.function = pxakbd_timer_callback; ++ pxakbd->timer.data = (unsigned long) pxakbd; ++ pxakbd->pd = pdev->dev.platform_data; ++ pxakbd->res = r; ++ ++ input_dev->name = "PXA Keyboard"; ++ input_dev->phys = "pxakbd/input0"; ++ input_dev->id.bustype = BUS_HOST; ++ input_dev->id.vendor = 0x0001; ++ input_dev->id.product = 0x0001; ++ input_dev->id.version = 0x0001; ++ input_dev->cdev.dev = &pdev->dev; ++ input_dev->private = pxakbd; ++ ++ input_dev->evbit[0] = BIT(EV_KEY)|BIT(EV_REP); ++ input_dev->keycode = pxakbd->pd->matrix.keycode; ++ input_dev->keycodesize = sizeof(unsigned char); ++ input_dev->keycodemax = pxakbd->pd->matrix.rows ++ *pxakbd->pd->matrix.cols; ++ ++ for (i = 0; i < input_dev->keycodemax; i++) ++ set_bit(pxakbd->pd->matrix.keycode[i], input_dev->keybit); ++ clear_bit(0, input_dev->keybit); ++ ++#if 0 ++ input_dev2->evbit[0] = ; ++ input_dev2->keycode = pxakbd->pd->direct.keycode; ++ input_dev2->keycodesize = sizeof(unsigned char); ++ input_dev2->keycodemax = pxakbd->pd->direct.num; ++ ++ for (i = 0; i < input_dev2->keycodemax; i++) ++ set_bit(ezxkbd->keycode[i], input_dev2->keybit); ++#endif ++ ++ if (request_irq(pxakbd->irq, pxakbd_interrupt, 0, "pxakbd", pxakbd)) { ++ printk(KERN_ERR "pxakbd: can't request irq %d\n", pxakbd->irq); ++ ret = -EBUSY; ++ goto out_idev; ++ } ++ ++ r = request_mem_region(r->start, 0x4c, "pxakbd"); ++ if (!r) { ++ printk(KERN_ERR "pxakbd: can't request memregion\n"); ++ ret = -EBUSY; ++ goto out_irq; ++ } ++ ++ /* set up gpio */ ++ pxakbd->pd->init(); ++ ++ /* set keypad control register */ ++ KPC = (KPC_ASACT | /* automatic scan on activity */ ++ KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ ++ ((pxakbd->pd->matrix.cols-1)<<23) | /* columns */ ++ ((pxakbd->pd->matrix.rows-1)<<26) | /* rows */ ++ KPC_MS_ALL); /* scan all columns */ ++ ++ pxa_set_cken(CKEN19_KEYPAD, 1); ++ ++#if 0 ++ /* * we want the phone to be able to tell the status of the screen ++ * lock switch at power-up time */ ++ kpdk = KPDK; /* read direct key register */ ++ ++ /* * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off */ ++ kpdk &= ~KPDK_DKP; ++ ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++#elif defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#elif defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); ++#if defined(CONFIG_E680_P4A) ++/*93,97,100,101,102*/ ++ PKWR = 0xe4400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++/*93,96,97,98,100,101,102*/ ++ PKWR = 0xee400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++/*93,97,98,100,101,102*/ ++ PKWR = 0xec400; ++/*103 104 105 106 107*/ ++ PGSR3 |= 0xf80; ++#endif ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++#ifdef CONFIG_PM ++ keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); ++ PGSR3 |= 0x8; ++#endif ++#endif ++ ++#endif ++ ++ KPC |= (KPC_DIE | KPC_MIE); /* enable matrix and direct keyboard */ ++ ++ KPKDI = 0x40; /* matrix key debounce interval: 0x40 */ ++ ++ platform_set_drvdata(pdev, pxakbd); ++ ++ return input_register_device(pxakbd->input); ++ ++out_drvdata: ++ platform_set_drvdata(pdev, NULL); ++out_mem: ++ release_resource(r); ++out_irq: ++ free_irq(pxakbd->irq, pxakbd); ++out_idev: ++ input_free_device(input_dev); ++out_pxa: ++ kfree(pxakbd); ++out: ++ return ret; ++} ++ ++static int pxakbd_remove(struct platform_device *pdev) ++{ ++ struct pxakbd *pxakbd = platform_get_drvdata(pdev); ++ ++ platform_set_drvdata(pdev, NULL); ++ release_resource(pxakbd->res); ++ free_irq(pxakbd->irq, pxakbd); ++ input_unregister_device(pxakbd->input); ++ kfree(pxakbd); ++ ++ return 0; ++} ++ ++static struct platform_driver pxakbd_driver = { ++ .probe = &pxakbd_probe, ++ .remove = &pxakbd_remove, ++ .driver = { ++ .name = "pxa-keyboard", ++ }, ++}; ++ ++static int __devinit pxakbd_init(void) ++{ ++ return platform_driver_register(&pxakbd_driver); ++} ++ ++static void __exit pxakbd_exit(void) ++{ ++ platform_driver_unregister(&pxakbd_driver); ++} ++ ++module_init(pxakbd_init); ++module_exit(pxakbd_exit); ++ ++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); ++MODULE_DESCRIPTION("Driver for Intel PXA27x keypad controller"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/input/touchscreen/Kconfig linux-2.6.16/drivers/input/touchscreen/Kconfig +--- linux-2.6.16.orig/drivers/input/touchscreen/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/input/touchscreen/Kconfig 2006-06-03 11:14:57.188195328 +0200 +@@ -108,4 +108,16 @@ + To compile this driver as a module, choose M here: the + module will be called hp680_ts_input. + ++config TOUCHSCREEN_PCAP ++ tristate "Motorola PCAP touchscreen" ++ depends on PXA_EZX_PCAP ++ help ++ Say Y here if you have a Motorola EZX (E680, A780) telephone ++ and want to support the built-in touchscreen. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called hp680_ts_input. ++ + endif +diff -Nurd linux-2.6.16.orig/drivers/input/touchscreen/Makefile linux-2.6.16/drivers/input/touchscreen/Makefile +--- linux-2.6.16.orig/drivers/input/touchscreen/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/input/touchscreen/Makefile 2006-06-03 11:14:57.189195176 +0200 +@@ -12,3 +12,4 @@ + obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o + obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o + obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o ++obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o +diff -Nurd linux-2.6.16.orig/drivers/input/touchscreen/pcap_ts.c linux-2.6.16/drivers/input/touchscreen/pcap_ts.c +--- linux-2.6.16.orig/drivers/input/touchscreen/pcap_ts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/input/touchscreen/pcap_ts.c 2006-06-03 11:14:57.190195024 +0200 +@@ -0,0 +1,364 @@ ++/* ++ * pcap_ts.c - Touchscreen driver for Motorola PCAP2 based touchscreen as found ++ * in the EZX phone platform. ++ * ++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org> ++ * ++ * Based on information found in the original Motorola 2.4.x ezx-ts.c driver. ++ * ++ * 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. ++ * ++ * TODO: ++ * split this in a hardirq handler and a tasklet/bh ++ * suspend/resume support ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/string.h> ++#include <linux/pm.h> ++#include <linux/timer.h> ++#include <linux/config.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/input.h> ++ ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++ ++#include "../../misc/ezx/ssp_pcap.h" ++ ++#if 1 ++#define DEBUGP(x, args ...) printk(KERN_DEBUG "%s: " x, __FUNCTION__, ## args) ++#else ++#define DEBUGP(x, args ...) ++#endif ++ ++#define PRESSURE 1 ++#define COORDINATE 2 ++ ++struct pcap_ts { ++ int irq_xy; ++ int irq_touch; ++ struct input_dev *input; ++ struct timer_list timer; ++ ++ u_int16_t x, y; ++ u_int16_t pressure, pressure_last; ++ ++ u_int8_t read_state; ++}; ++ ++#define X_AXIS_MIN 0 ++#define X_AXIS_MAX 1023 ++ ++#define Y_AXIS_MAX X_AXIS_MAX ++#define Y_AXIS_MIN X_AXIS_MIN ++ ++#define PRESSURE_MAX X_AXIS_MAX ++#define PRESSURE_MIN X_AXIS_MIN ++ ++static int pcap_ts_mode(u_int32_t mode) ++{ ++ int ret; ++ ++ u_int32_t tmp; ++ ++ ret = ezx_pcap_read(SSP_PCAP_ADJ_ADC1_REGISTER, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ tmp &= ~SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK; ++ tmp |= mode; ++ ret = ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++ ++ DEBUGP("set ts mode "); ++ if (mode == PCAP_TS_POSITION_XY_MEASUREMENT) ++ DEBUGP("COORD\n"); ++ else if (mode == PCAP_TS_PRESSURE_MEASUREMENT) ++ DEBUGP("PRESS\n"); ++ else if (mode == PCAP_TS_STANDBY_MODE) ++ DEBUGP("STANDBY\n"); ++ else ++ printk("UNKNOWN\n"); ++ ++ return ret; ++} ++ ++/* issue a XY read command to the ADC of PCAP2. Well get an ADCDONE2 interrupt ++ * once the result of the conversion is available */ ++static int pcap_ts_start_xy_read(struct pcap_ts *pcap_ts) ++{ ++ int ret; ++ u_int32_t tmp; ++ DEBUGP("start xy read in mode %s\n", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS"); ++ ++ ret = ezx_pcap_read(SSP_PCAP_ADJ_ADC1_REGISTER, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ tmp &= SSP_PCAP_ADC_START_VALUE_SET_MASK; ++ tmp |= SSP_PCAP_ADC_START_VALUE; ++ ++ ret = ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++ if (ret < 0) ++ return ret; ++ ++ ret = ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ADC2_ASC, 1); ++ ++ return ret; ++} ++ ++/* read the XY result from the ADC of PCAP2 */ ++static int pcap_ts_get_xy_value(struct pcap_ts *pcap_ts) ++{ ++ int ret; ++ u_int32_t tmp; ++ ++ DEBUGP("get xy value in mode %s\n", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS"); ++ ++ ret = ezx_pcap_read(SSP_PCAP_ADJ_ADC2_REGISTER, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ if (tmp & 0x00400000) ++ return -EIO; ++ ++ if (pcap_ts->read_state == COORDINATE) { ++ pcap_ts->x = (tmp & SSP_PCAP_ADD1_VALUE_MASK); ++ pcap_ts->y = (tmp & SSP_PCAP_ADD2_VALUE_MASK) ++ >>SSP_PCAP_ADD2_VALUE_SHIFT; ++ } else { ++ pcap_ts->pressure_last = pcap_ts->pressure; ++ pcap_ts->pressure = (tmp & SSP_PCAP_ADD2_VALUE_MASK) ++ >>SSP_PCAP_ADD2_VALUE_SHIFT; ++ } ++ ++ return 0; ++} ++ ++/* PCAP2 interrupts us when ADC conversion result is available */ ++static irqreturn_t pcap_ts_irq_xy(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct pcap_ts *pcap_ts = dev_id; ++ ++ if (pcap_ts_get_xy_value(pcap_ts) < 0) { ++ printk("pcap_ts: error reading XY value\n"); ++ return IRQ_HANDLED; ++ } ++ ++ DEBUGP("%s X=%4d, Y=%4d Z=%4d\n", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS", ++ pcap_ts->x, pcap_ts->y, pcap_ts->pressure); ++ ++ if (pcap_ts->read_state == PRESSURE) { ++ input_report_abs(pcap_ts->input, ABS_PRESSURE, ++ pcap_ts->pressure); ++ if ((pcap_ts->pressure >= PRESSURE_MAX || ++ pcap_ts->pressure <= PRESSURE_MIN ) && ++ pcap_ts->pressure == pcap_ts->pressure_last) { ++ /* pen has been released */ ++ input_report_key(pcap_ts->input, BTN_TOUCH, 0); ++ input_sync(pcap_ts->input); ++ ++ pcap_ts->x = pcap_ts->y = 0; ++ ++ /* ask PCAP2 to interrupt us if touch event happens ++ * again */ ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_mode(PCAP_TS_STANDBY_MODE); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ ++ /* no need for timer, we'll get interrupted with ++ * next touch down event */ ++ del_timer(&pcap_ts->timer); ++ } else { ++ /* pen has been touched down */ ++ input_report_key(pcap_ts->input, BTN_TOUCH, 1); ++ /* don't input_sync(), we don't know position yet */ ++ ++ /* switch state machine into coordinate read mode */ ++ pcap_ts->read_state = COORDINATE; ++ pcap_ts_mode(PCAP_TS_POSITION_XY_MEASUREMENT); ++ pcap_ts_start_xy_read(pcap_ts); ++ ++ mod_timer(&pcap_ts->timer, jiffies + HZ/20); ++ } ++ } else { ++ /* we are in coordinate mode */ ++ if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX || ++ pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) { ++ DEBUGP("invalid x/y coordinate position: PEN_UP?\n"); ++#if 0 ++ input_report_key(pcap_ts->input, BTN_TOUCH, 0); ++ pcap_ts->x = pcap_ts->y = 0; ++#endif ++ } else { ++ input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); ++ input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); ++ } ++ input_sync(pcap_ts->input); ++ ++ /* switch back to pressure read mode */ ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_mode(PCAP_TS_STANDBY_MODE); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* PCAP2 interrupts us if the pen touches down */ ++static irqreturn_t pcap_ts_irq_touch(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct pcap_ts *pcap_ts = dev_id; ++ DEBUGP("entered\n"); ++ ++ /* mask Touchscreen interrupt bit, prevents further touch events ++ * from being reported to us until we're finished with reading ++ * both pressure and x/y from ADC */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 1); ++ pcap_ts_mode(PCAP_TS_PRESSURE_MEASUREMENT); ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_start_xy_read(pcap_ts); ++ ++ return IRQ_HANDLED; ++} ++ ++static void pcap_ts_timer_fn(unsigned long data) ++{ ++ struct pcap_ts *pcap_ts = (struct pcap_ts *) data; ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 1); ++ pcap_ts_mode(PCAP_TS_PRESSURE_MEASUREMENT); ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_start_xy_read(pcap_ts); ++} ++ ++static int __init ezxts_probe(struct platform_device *pdev) ++{ ++ struct pcap_ts *pcap_ts; ++ struct input_dev *input_dev; ++ int err = -ENOMEM; ++ ++ pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL); ++ input_dev = input_allocate_device(); ++ if (!pcap_ts || !input_dev) ++ goto fail; ++ ++ pcap_ts->irq_xy = platform_get_irq(pdev, 0); ++ if (pcap_ts->irq_xy < 0) { ++ err = pcap_ts->irq_xy; ++ goto fail; ++ } ++ ++ pcap_ts->irq_touch = platform_get_irq(pdev, 1); ++ if (pcap_ts->irq_touch < 0) { ++ err = pcap_ts->irq_touch; ++ goto fail; ++ } ++ ++ ssp_pcap_open(SSP_PCAP_TS_OPEN); ++ ++ err = request_irq(pcap_ts->irq_xy, pcap_ts_irq_xy, SA_INTERRUPT, ++ "PCAP Touchscreen XY", pcap_ts); ++ if (err < 0) { ++ printk(KERN_ERR "pcap_ts: can't grab xy irq %d: %d\n", ++ pcap_ts->irq_xy, err); ++ goto fail; ++ } ++ ++ err = request_irq(pcap_ts->irq_touch, pcap_ts_irq_touch, SA_INTERRUPT, ++ "PCAP Touchscreen Touch", pcap_ts); ++ if (err < 0) { ++ printk(KERN_ERR "pcap_ts: can't grab touch irq %d: %d\n", ++ pcap_ts->irq_touch, err); ++ goto fail_xy; ++ } ++ ++ pcap_ts->input = input_dev; ++ pcap_ts->read_state = PRESSURE; ++ init_timer(&pcap_ts->timer); ++ pcap_ts->timer.data = (unsigned long) pcap_ts; ++ pcap_ts->timer.function = &pcap_ts_timer_fn; ++ ++ platform_set_drvdata(pdev, pcap_ts); ++ ++ /* enable pressure interrupt */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ ++ input_dev->name = "EZX PCAP2 Touchscreen"; ++ input_dev->phys = "ezxts/input0"; ++ input_dev->id.bustype = BUS_HOST; ++ input_dev->id.vendor = 0x0001; ++ input_dev->id.product = 0x0002; ++ input_dev->id.version = 0x0100; ++ input_dev->cdev.dev = &pdev->dev; ++ input_dev->private = pcap_ts; ++ ++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); ++ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); ++ input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, ++ PRESSURE_MAX, 0, 0); ++ ++ input_register_device(pcap_ts->input); ++ ++ return 0; ++ ++fail_xy: ++ free_irq(pcap_ts->irq_xy, pcap_ts); ++fail: ++ input_free_device(input_dev); ++ kfree(pcap_ts); ++ ++ return err; ++} ++ ++static int ezxts_remove(struct platform_device *pdev) ++{ ++ struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); ++ ++ del_timer_sync(&pcap_ts->timer); ++ ++ free_irq(pcap_ts->irq_touch, pcap_ts); ++ free_irq(pcap_ts->irq_xy, pcap_ts); ++ ++ input_unregister_device(pcap_ts->input); ++ kfree(pcap_ts); ++ ++ return 0; ++} ++ ++static struct platform_driver ezxts_driver = { ++ .probe = ezxts_probe, ++ .remove = ezxts_remove, ++ //.suspend = ezxts_suspend, ++ //.resume = ezxts_resume, ++ .driver = { ++ .name = "pcap-ts", ++ }, ++}; ++ ++static int __devinit ezxts_init(void) ++{ ++ return platform_driver_register(&ezxts_driver); ++} ++ ++static void __exit ezxts_exit(void) ++{ ++ platform_driver_unregister(&ezxts_driver); ++} ++ ++module_init(ezxts_init); ++module_exit(ezxts_exit); ++ ++MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver"); ++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/macintosh/therm_adt746x.c linux-2.6.16/drivers/macintosh/therm_adt746x.c +--- linux-2.6.16.orig/drivers/macintosh/therm_adt746x.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/macintosh/therm_adt746x.c 2006-06-03 11:14:55.276485952 +0200 +@@ -627,8 +627,8 @@ + if(therm_type == ADT7460) + device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); + +-#ifndef CONFIG_I2C_KEYWEST +- request_module("i2c-keywest"); ++#ifndef CONFIG_I2C_POWERMAC ++ request_module("i2c-powermac"); + #endif + + return i2c_add_driver(&thermostat_driver); +diff -Nurd linux-2.6.16.orig/drivers/Makefile linux-2.6.16/drivers/Makefile +--- linux-2.6.16.orig/drivers/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/Makefile 2006-06-03 11:14:55.891392472 +0200 +@@ -67,6 +67,7 @@ + obj-$(CONFIG_MCA) += mca/ + obj-$(CONFIG_EISA) += eisa/ + obj-$(CONFIG_CPU_FREQ) += cpufreq/ ++obj-$(CONFIG_DPM) += dpm/ + obj-$(CONFIG_MMC) += mmc/ + obj-$(CONFIG_INFINIBAND) += infiniband/ + obj-$(CONFIG_SGI_SN) += sn/ +diff -Nurd linux-2.6.16.orig/drivers/md/dm.c linux-2.6.16/drivers/md/dm.c +--- linux-2.6.16.orig/drivers/md/dm.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/md/dm.c 2006-06-03 11:14:55.278485648 +0200 +@@ -533,30 +533,35 @@ + + } else { + /* +- * Create two copy bios to deal with io that has +- * been split across a target. ++ * Handle a bvec that must be split between two or more targets. + */ + struct bio_vec *bv = bio->bi_io_vec + ci->idx; ++ sector_t remaining = to_sector(bv->bv_len); ++ unsigned int offset = 0; + +- clone = split_bvec(bio, ci->sector, ci->idx, +- bv->bv_offset, max); +- __map_bio(ti, clone, tio); ++ do { ++ if (offset) { ++ ti = dm_table_find_target(ci->map, ci->sector); ++ max = max_io_len(ci->md, ci->sector, ti); + +- ci->sector += max; +- ci->sector_count -= max; +- ti = dm_table_find_target(ci->map, ci->sector); ++ tio = alloc_tio(ci->md); ++ tio->io = ci->io; ++ tio->ti = ti; ++ memset(&tio->info, 0, sizeof(tio->info)); ++ } + +- len = to_sector(bv->bv_len) - max; +- clone = split_bvec(bio, ci->sector, ci->idx, +- bv->bv_offset + to_bytes(max), len); +- tio = alloc_tio(ci->md); +- tio->io = ci->io; +- tio->ti = ti; +- memset(&tio->info, 0, sizeof(tio->info)); +- __map_bio(ti, clone, tio); ++ len = min(remaining, max); ++ ++ clone = split_bvec(bio, ci->sector, ci->idx, ++ bv->bv_offset + offset, len); ++ ++ __map_bio(ti, clone, tio); ++ ++ ci->sector += len; ++ ci->sector_count -= len; ++ offset += to_bytes(len); ++ } while (remaining -= len); + +- ci->sector += len; +- ci->sector_count -= len; + ci->idx++; + } + } +@@ -1093,6 +1098,7 @@ + { + struct dm_table *map = NULL; + DECLARE_WAITQUEUE(wait, current); ++ struct bio *def; + int r = -EINVAL; + + down(&md->suspend_lock); +@@ -1152,9 +1158,11 @@ + /* were we interrupted ? */ + r = -EINTR; + if (atomic_read(&md->pending)) { ++ clear_bit(DMF_BLOCK_IO, &md->flags); ++ def = bio_list_get(&md->deferred); ++ __flush_deferred_io(md, def); + up_write(&md->io_lock); + unlock_fs(md); +- clear_bit(DMF_BLOCK_IO, &md->flags); + goto out; + } + up_write(&md->io_lock); +diff -Nurd linux-2.6.16.orig/drivers/md/dm-snap.c linux-2.6.16/drivers/md/dm-snap.c +--- linux-2.6.16.orig/drivers/md/dm-snap.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/md/dm-snap.c 2006-06-03 11:14:55.277485800 +0200 +@@ -542,8 +542,12 @@ + { + struct dm_snapshot *s = (struct dm_snapshot *) ti->private; + ++ /* Prevent further origin writes from using this snapshot. */ ++ /* After this returns there can be no new kcopyd jobs. */ + unregister_snapshot(s); + ++ kcopyd_client_destroy(s->kcopyd_client); ++ + exit_exception_table(&s->pending, pending_cache); + exit_exception_table(&s->complete, exception_cache); + +@@ -552,7 +556,7 @@ + + dm_put_device(ti, s->origin); + dm_put_device(ti, s->cow); +- kcopyd_client_destroy(s->kcopyd_client); ++ + kfree(s); + } + +diff -Nurd linux-2.6.16.orig/drivers/md/kcopyd.c linux-2.6.16/drivers/md/kcopyd.c +--- linux-2.6.16.orig/drivers/md/kcopyd.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/md/kcopyd.c 2006-06-03 11:14:55.278485648 +0200 +@@ -44,6 +44,9 @@ + struct page_list *pages; + unsigned int nr_pages; + unsigned int nr_free_pages; ++ ++ wait_queue_head_t destroyq; ++ atomic_t nr_jobs; + }; + + static struct page_list *alloc_pl(void) +@@ -293,10 +296,15 @@ + int read_err = job->read_err; + unsigned int write_err = job->write_err; + kcopyd_notify_fn fn = job->fn; ++ struct kcopyd_client *kc = job->kc; + +- kcopyd_put_pages(job->kc, job->pages); ++ kcopyd_put_pages(kc, job->pages); + mempool_free(job, _job_pool); + fn(read_err, write_err, context); ++ ++ if (atomic_dec_and_test(&kc->nr_jobs)) ++ wake_up(&kc->destroyq); ++ + return 0; + } + +@@ -431,6 +439,7 @@ + */ + static void dispatch_job(struct kcopyd_job *job) + { ++ atomic_inc(&job->kc->nr_jobs); + push(&_pages_jobs, job); + wake(); + } +@@ -670,6 +679,9 @@ + return r; + } + ++ init_waitqueue_head(&kc->destroyq); ++ atomic_set(&kc->nr_jobs, 0); ++ + client_add(kc); + *result = kc; + return 0; +@@ -677,6 +689,9 @@ + + void kcopyd_client_destroy(struct kcopyd_client *kc) + { ++ /* Wait for completion of all jobs submitted by this client. */ ++ wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); ++ + dm_io_put(kc->nr_pages); + client_free_pages(kc); + client_del(kc); +diff -Nurd linux-2.6.16.orig/drivers/media/dvb/dvb-usb/cxusb.c linux-2.6.16/drivers/media/dvb/dvb-usb/cxusb.c +--- linux-2.6.16.orig/drivers/media/dvb/dvb-usb/cxusb.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/media/dvb/dvb-usb/cxusb.c 2006-06-03 11:14:55.288484128 +0200 +@@ -149,6 +149,15 @@ + return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); + } + ++static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) ++{ ++ u8 b = 0; ++ if (onoff) ++ return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); ++ else ++ return 0; ++} ++ + static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) + { + u8 buf[2] = { 0x03, 0x00 }; +@@ -505,7 +514,7 @@ + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, +- .power_ctrl = cxusb_power_ctrl, ++ .power_ctrl = cxusb_bluebird_power_ctrl, + .frontend_attach = cxusb_lgdt3303_frontend_attach, + .tuner_attach = cxusb_lgh064f_tuner_attach, + +@@ -545,7 +554,7 @@ + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, +- .power_ctrl = cxusb_power_ctrl, ++ .power_ctrl = cxusb_bluebird_power_ctrl, + .frontend_attach = cxusb_dee1601_frontend_attach, + .tuner_attach = cxusb_dee1601_tuner_attach, + +@@ -594,7 +603,7 @@ + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, +- .power_ctrl = cxusb_power_ctrl, ++ .power_ctrl = cxusb_bluebird_power_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_lgz201_tuner_attach, + +@@ -634,7 +643,7 @@ + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, +- .power_ctrl = cxusb_power_ctrl, ++ .power_ctrl = cxusb_bluebird_power_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_dtt7579_tuner_attach, + +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm2700.c linux-2.6.16/drivers/media/video/adcm2700.c +--- linux-2.6.16.orig/drivers/media/video/adcm2700.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm2700.c 2006-06-03 11:14:56.423311608 +0200 +@@ -0,0 +1,644 @@ ++ ++/*================================================================================ ++ ++ Header Name: adcm2700.c ++ ++General Description: Camera module adcm2700 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++ Update algorithm for DMA transfer ++ Update strategy for memory management ++ Fix still picture capture failed sometime ++ New Agilent sensor chip ID support ++ Make output height in an even multiple of 8 ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++ ++#include <asm/pgtable.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++ ++#include <asm/arch/pxa-regs.h> ++ ++#include "camera.h" ++#include "adcm2700.h" ++#include "adcm2700_hw.h" ++ ++ ++/*********************************************************************** ++ * ++ * ADCM2700 and MT9v111 common functions ++ * ++ ***********************************************************************/ ++#define MAX_WIDTH 640 ++#define MAX_HEIGHT 480 ++#define MIN_WIDTH 64 ++#define MIN_HEIGHT 64 ++#define WIDTH_DEFT 240 ++#define HEIGHT_DEFT 320 ++#define FRAMERATE_DEFT 15 ++#define MCLK_DEFT 6 /* Default Master clock*/ ++#define BUF_SIZE_DEFT ((PAGE_ALIGN(MAX_WIDTH * MAX_HEIGHT) + (PAGE_ALIGN(MAX_WIDTH*MAX_HEIGHT/2)*2))) ++ ++extern int i2c_adcm2700_init(void); ++extern int i2c_mt9v111_init(void); ++ ++////////////////////////////////////////////////////////////////////////////////////// ++//adcm2700 functions ++// ++int camera_func_adcm2700_init(p_camera_context_t); ++int camera_func_adcm2700_deinit(p_camera_context_t); ++int camera_func_adcm2700_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++int camera_func_adcm2700_set_capture_format(p_camera_context_t); ++int camera_func_adcm2700_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_adcm2700_stop_capture(p_camera_context_t); ++ ++int camera_func_adcm2700_pm_management(p_camera_context_t, int); ++ ++////////////////////////////////////////////////////////////////////////////////////// ++//mt9v111 functions ++// ++int camera_func_mt9v111_init(p_camera_context_t); ++int camera_func_mt9v111_deinit(p_camera_context_t); ++int camera_func_mt9v111_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++int camera_func_mt9v111_set_capture_format(p_camera_context_t); ++int camera_func_mt9v111_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_mt9v111_stop_capture(p_camera_context_t); ++ ++int camera_func_mt9v111_pm_management(p_camera_context_t, int); ++ ++int camera_func_init(p_camera_context_t cam_ctx); ++ ++ ++camera_function_t e680_camera_func = ++{ ++ init: camera_func_init, ++}; ++ ++int camera_func_init(p_camera_context_t cam_ctx) ++{ ++ int ret = 0; ++ // init context status ++ cam_ctx->dma_channels[0] = 0xFF; ++ cam_ctx->dma_channels[1] = 0xFF; ++ cam_ctx->dma_channels[2] = 0xFF; ++ ++ cam_ctx->capture_width = WIDTH_DEFT; ++ cam_ctx->capture_height = HEIGHT_DEFT; ++ ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ ++ cam_ctx->frame_rate = cam_ctx->fps = FRAMERATE_DEFT; ++ ++ cam_ctx->mini_fps = FRAMERATE_DEFT-5; ++ ++ cam_ctx->mclk = MCLK_DEFT; ++ cam_ctx->flicker_freq = 50; ++ ++ cam_ctx->buf_size = BUF_SIZE_DEFT; ++ cam_ctx->dma_descriptors_size = (cam_ctx->buf_size/PAGE_SIZE + 10); ++ cam_ctx->vc.maxwidth = MAX_WIDTH; ++ cam_ctx->vc.maxheight = MAX_HEIGHT; ++ cam_ctx->vc.minwidth = MIN_WIDTH; ++ cam_ctx->vc.minheight = MIN_HEIGHT; ++ ++ camera_gpio_init(); ++ ci_init(); ++ ++ // Configure CI according to hardware ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ ++ // enable pixel clock(sensor will provide pclock) ++ ci_set_clock(cam_ctx->clk_reg_base, 1, 1, cam_ctx->mclk); ++ ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(0, 0, 0); ++ ++ // fifo control ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); // quality ++ ++ // Turn on M_CLK using xx MHz and wait for 150 ms. ++ ci_enable(1); ++ ++ mdelay(150); ++ ++ if(i2c_adcm2700_init() == 0) ++ { ++ cam_ctx->sensor_type = CAMERA_TYPE_ADCM_2700; ++ e680_camera_func.deinit = camera_func_adcm2700_deinit; ++ e680_camera_func.command = camera_func_adcm2700_docommand; ++ e680_camera_func.set_capture_format = camera_func_adcm2700_set_capture_format; ++ e680_camera_func.start_capture = camera_func_adcm2700_start_capture; ++ e680_camera_func.stop_capture = camera_func_adcm2700_stop_capture; ++ e680_camera_func.pm_management = camera_func_adcm2700_pm_management; ++ ++ if((ret = camera_func_adcm2700_init(cam_ctx)) < 0) ++ { ++ dbg_print("adcm2700 init error! capture format!"); ++ return -1; ++ } ++ ddbg_print("Agilent ADCM2700 camera module detected!"); ++ } ++ else if(i2c_mt9v111_init() == 0) ++ { ++ cam_ctx->sensor_type = CAMERA_TYPE_MT9V111; ++ ++ e680_camera_func.deinit = camera_func_mt9v111_deinit; ++ e680_camera_func.command = camera_func_mt9v111_docommand; ++ e680_camera_func.set_capture_format = camera_func_mt9v111_set_capture_format; ++ e680_camera_func.start_capture = camera_func_mt9v111_start_capture; ++ e680_camera_func.stop_capture = camera_func_mt9v111_stop_capture; ++ e680_camera_func.pm_management = camera_func_mt9v111_pm_management; ++ if((ret = camera_func_mt9v111_init(cam_ctx)) < 0) ++ { ++ dbg_print("mt9v111 init error! capture format!"); ++ return -1; ++ } ++ ddbg_print("Micro MT9V111 camera module detected!"); ++ } ++ else ++ { ++ dbg_print("no camera sensor detected!!!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * ++ * ADCM2700 Functions ++ * ++ ***********************************************************************/ ++int camera_func_adcm2700_init( p_camera_context_t camera_context ) ++{ ++ u16 sensor_rev, cm_rev; ++ int i; ++ adcm2700_power_on(camera_context->mclk); ++ //read out version ++ //adcm2700_version_revision(&cm_rev, &sensor_rev); ++ return 0; ++} ++ ++int camera_func_adcm2700_deinit( p_camera_context_t camera_context ) ++{ ++ /* power off the external module */ ++ camera_func_adcm2700_stop_capture(camera_context); ++ /* disable CI */ ++ ci_disable(1); ++ ++ i2c_adcm2700_cleanup(); ++ camera_gpio_deinit(); ++ return 0; ++} ++ ++int camera_func_adcm2700_set_capture_format(p_camera_context_t camera_context) ++{ ++ u16 adcm_format; ++ adcm_window_size size; ++ ++ //set sensor format ++ switch(camera_context->capture_input_format) ++ { ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ adcm_format = O_FORMAT_422_B_YCbYCr; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ adcm_format = O_FORMAT_565_RGB; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB888_PACKED: ++ case CAMERA_IMAGE_FORMAT_RGB888_PLANAR: ++ adcm_format = O_FORMAT_888RGB; ++ break; ++ default: ++ adcm_format = O_FORMAT_422_B_YCbYCr; ++ break; ++ } ++ size.width = camera_context->capture_width; ++ size.height = camera_context->capture_height; ++ //adcm2700_output_size(&size); ++ //adcm2700_viewfinder_cfg_output(adcm_format); ++ return 0; ++} ++ ++int camera_func_adcm2700_start_capture(p_camera_context_t cam_ctx, unsigned int frames) ++{ ++ int cisr; ++ int wait_count; ++ int error_count = 0; ++ static int error_times = 0; ++ ++start: ++ ++ // frames=0 means video mode capture ++ if(frames == 0) ++ { ++ // ddbg_print("video capture!"); ++ wait_count = 1; ++ adcm2700_restore_property(cam_ctx, frames); ++ adcm2700_viewfinder_on(); ++ ci_disable(1); ++ ci_enable(1); ++ ++ } ++ else ++ { ++ // ddbg_print("still capture"); ++ ++ wait_count = 1; ++ adcm2700_restore_property(cam_ctx, frames); ++ adcm2700_snapshot_trigger(); ++ ci_disable(1); ++ ci_enable(1); ++ ++ } ++ ++ dbg_print("wait for EOF %d time", wait_count); ++ unsigned int start_time = 0xFFFFF * 20 * wait_count; ++ unsigned int flags; ++ ++ // local_irq_save(flags); ++ CISR |= CI_CISR_EOF; ++ CISR |= CI_CISR_SOF; ++ cisr=CISR; ++ while(wait_count) ++ { ++ if(cisr & CI_CISR_EOF) ++ { ++ //wait_count -- ; ++ CISR |= CI_CISR_EOF; ++ } ++ ++ if(cisr & CI_CISR_SOF) ++ { ++ wait_count -- ; ++ CISR |= CI_CISR_SOF; ++ } ++ ++ cisr=CISR; ++ if(!(--start_time)) ++ { ++ goto wait_EOF_error; ++ } ++ ++ } ++ ci_disable(1); ++ ci_enable(1); ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ mdelay(1); ++ start_dma_transfer(cam_ctx, cam_ctx->block_header); ++// local_irq_restore(flags); ++ dbg_print("wait ok..%d", start_time); ++ return 0; ++ ++wait_EOF_error: ++ // local_irq_restore(flags); ++ error_times++; ++ if(error_count++ >= 3) ++ { ++ return -1; ++ } ++ dbg_print("wait EOF error! error_count = %d", error_count); ++ dbg_print("wait EOF error! error_times = %d", error_times); ++ dbg_print("Reset CIF and camera..."); ++ ci_disable(1); ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ // enable pixel clock(sensor will provide pclock) ++ ci_set_clock(cam_ctx->clk_reg_base, 1, 1, cam_ctx->mclk); ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(0, 0, 0); ++ // fifo control ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); // quality ++ // Turn on M_CLK using xx MHz and wait for 150 ms. ++ ci_enable(1); ++ mdelay(10); ++ adcm2700_power_on(cam_ctx->mclk); ++ goto start; ++} ++ ++int camera_func_adcm2700_stop_capture(p_camera_context_t cam_ctx) ++{ ++ adcm2700_viewfinder_off(); ++ stop_dma_transfer(cam_ctx); ++ return 0; ++} ++ ++int camera_func_adcm2700_pm_management(p_camera_context_t cam_ctx, int suspend) ++{ ++ static int resume_dma = 0; ++ if(suspend) ++ { ++ if(cam_ctx != NULL ) ++ { ++ if(cam_ctx->dma_started) ++ { ++ ddbg_print("camera running, suspended"); ++ stop_dma_transfer(cam_ctx); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ pxa_set_cken(CKEN24_CAMERA, 0); ++ } ++ else ++ { ++ pxa_set_cken(CKEN24_CAMERA, 1); ++ enable_irq(IRQ_CAMERA); ++ ++ if(cam_ctx != NULL) ++ { ++ ddbg_print("camera running, resumed"); ++ camera_init(cam_ctx); ++ if(resume_dma == 1) ++ { ++ camera_start_video_capture(cam_ctx, 0); ++ resume_dma = 0; ++ } ++ } ++ } ++ return 0; ++} ++ ++/*set picture brightness*/ ++static int pxa_cam_WCAM_VIDIOCSBRIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ ddbg_print("WCAM_VIDIOCSBRIGHT"); ++ int ret = 0; ++ if(cam_ctx->capture_bright != (int)param) ++ { ++ cam_ctx->capture_bright = (int)param; ++ ret = adcm2700_set_bright(cam_ctx->capture_bright); ++ } ++ return ret; ++} ++ ++/*set picture style*/ ++static int pxa_cam_WCAM_VIDIOCSSTYLE(p_camera_context_t cam_ctx, void * param) ++{ ++ ddbg_print("WCAM_VIDIOCSSTYLE"); ++ int ret = 0; ++ if(cam_ctx->capture_style != (V4l_PIC_STYLE)param) ++ { ++ cam_ctx->capture_style = (V4l_PIC_STYLE)param; ++ if(cam_ctx->dma_started == 1) ++ { ++ camera_func_adcm2700_stop_capture(cam_ctx); ++ ret = camera_func_adcm2700_start_capture(cam_ctx, 0); ++ } ++ ++ } ++ ++ return ret; ++} ++ ++ ++/*set picture light*/ ++static int pxa_cam_WCAM_VIDIOCSLIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ dbg_print("WCAM_VIDIOCSLIGHT"); ++ int ret = 0; ++ if(cam_ctx->capture_light != (V4l_PIC_WB)param) ++ { ++ cam_ctx->capture_light = (V4l_PIC_WB)param; ++ if(cam_ctx->dma_started == 1) ++ { ++ camera_func_adcm2700_stop_capture(cam_ctx); ++ ret = camera_func_adcm2700_start_capture(cam_ctx, 0); ++ } ++ ++ } ++ return ret; ++} ++ ++ ++//set output size ++static int pxa_cam_WCAM_VIDIOCSOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ //ddbg_print("WCAM_VIDIOCSOSIZE"); ++ ++ adcm_window_size size; ++ CI_MP_TIMING timing; ++ int ret = 0; ++ ++ if(copy_from_user(&size, param, sizeof(adcm_window_size))) ++ { ++ return -EFAULT; ++ } ++ if(cam_ctx->dma_started == 1) ++ { ++ return -EFAULT; ++ } ++ //make it in an even of multiple of 8 ++ size.width = (size.width +7)/8 * 8; ++ size.height = (size.height+7)/8 * 8; ++ dbg_print("w=%d h=%d", size.width, size.height); ++ if(cam_ctx->capture_width != size.width || cam_ctx->capture_height != size.height) ++ { ++ cam_ctx->capture_width = size.width; ++ cam_ctx->capture_height = size.height; ++ ret = adcm2700_output_size(&size); ++ ++ timing.BFW = timing.BLW = 0; ++ ++ ci_configure_mp(cam_ctx->capture_width-1, cam_ctx->capture_height-1, &timing); ++ camera_ring_buf_init(cam_ctx); ++ } ++ ++ return ret; ++} ++ ++/*Set sensor size*/ ++static int pxa_cam_WCAM_VIDIOCSSSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ //ddbg_print("WCAM_VIDIOCSSSIZE"); ++ adcm_window_size size; ++ int ret = 0; ++ ++ if(copy_from_user(&size, param, sizeof(adcm_window_size))) ++ { ++ return -EFAULT; ++ } ++ if(cam_ctx->dma_started == 1) ++ { ++ return -EFAULT; ++ } ++ //make it in an even of multiple of 8 ++ size.width = (size.width +7)/8 * 8; ++ size.height = (size.height+7)/8 * 8; ++ ++ if(cam_ctx->sensor_width != size.width || cam_ctx->sensor_height != size.height) ++ { ++ cam_ctx->sensor_width = size.width; ++ cam_ctx->sensor_height = size.height; ++ ret = adcm2700_input_size(&size); ++ dbg_print("w = %d h = %d", size.width, size.height); ++ } ++ return ret; ++} ++ ++static int pxa_cam_WCAM_VIDIOCSFPS(p_camera_context_t cam_ctx, void * param) ++{ ++ //ddbg_print("WCAM_VIDIOCSFPS"); ++ ++ struct {int fps, minfps;} cam_fps; ++ int ret = 0; ++ ++ if(copy_from_user(&cam_fps, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ if(cam_fps.fps < 12) ++ { ++ cam_fps.fps = 12; ++ } ++ ++ if(cam_ctx->fps != cam_fps.fps || cam_ctx->mini_fps != cam_fps.minfps) ++ { ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ if(cam_ctx->dma_started == 1) ++ { ++ camera_func_adcm2700_stop_capture(cam_ctx); ++ ret = camera_func_adcm2700_start_capture(cam_ctx, 0); ++ } ++ } ++ return ret; ++} ++ ++static int pxa_camera_WCAM_VIDIOCGCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ int reg_value, offset; ++ //ddbg_print("WCAM_VIDIOCGCAMREG"); ++ if(copy_from_user(&offset, param, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ reg_value = (int)adcm2700_reg_read((u16)offset); ++ ++ if(copy_to_user(param, ®_value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++/*set flicker frequency*/ ++static int pxa_cam_WCAM_VIDIOCSFLICKER(p_camera_context_t cam_ctx, void * param) ++{ ++ dbg_print("WCAM_VIDIOCSFLICKER"); ++ cam_ctx->flicker_freq = (int)param; ++ ++ return adcm2700_set_flicker(cam_ctx->flicker_freq); ++} ++ ++ ++static int pxa_camera_WCAM_VIDIOCSCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ struct reg_set_s{int val1, val2} reg_s; ++ //ddbg_print("WCAM_VIDIOCSCAMREG"); ++ ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ adcm2700_write((u16)reg_s.val1, (u16)reg_s.val2); ++ return 0; ++} ++ ++int camera_func_adcm2700_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param) ++{ ++ switch(cmd) ++ { ++ /*read adcm2700 registers*/ ++ case WCAM_VIDIOCGCAMREG: ++ return pxa_camera_WCAM_VIDIOCGCAMREG(cam_ctx, param); ++ ++ /*write adcm2700 registers*/ ++ case WCAM_VIDIOCSCAMREG: ++ return pxa_camera_WCAM_VIDIOCSCAMREG(cam_ctx, param); ++ ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return pxa_cam_WCAM_VIDIOCSSSIZE(cam_ctx, param); ++ ++ /*set output size*/ ++ case WCAM_VIDIOCSOSIZE: ++ return pxa_cam_WCAM_VIDIOCSOSIZE(cam_ctx, param); ++ ++ ++ /*set video mode fps*/ ++ case WCAM_VIDIOCSFPS: ++ return pxa_cam_WCAM_VIDIOCSFPS(cam_ctx, param); ++ ++ /*set picture style*/ ++ case WCAM_VIDIOCSSTYLE: ++ return pxa_cam_WCAM_VIDIOCSSTYLE(cam_ctx, param); ++ ++ /*set picture light*/ ++ case WCAM_VIDIOCSLIGHT: ++ return pxa_cam_WCAM_VIDIOCSLIGHT(cam_ctx, param); ++ ++ /*set picture brightness*/ ++ case WCAM_VIDIOCSBRIGHT: ++ return pxa_cam_WCAM_VIDIOCSBRIGHT(cam_ctx, param); ++ ++ /*set flicker frequency*/ ++ case WCAM_VIDIOCSFLICKER: ++ return pxa_cam_WCAM_VIDIOCSFLICKER(cam_ctx, param); ++ ++ default: ++ { ++ dbg_print("Error cmd=0x%x", cmd); ++ return -1; ++ } ++ } ++ return 0; ++ ++ } ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm2700.h linux-2.6.16/drivers/media/video/adcm2700.h +--- linux-2.6.16.orig/drivers/media/video/adcm2700.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm2700.h 2006-06-03 11:14:56.424311456 +0200 +@@ -0,0 +1,42 @@ ++ ++/*================================================================================ ++ ++ Header Name: adcm2700.h ++ ++General Description: Camera module adcm2700 interface head file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef _ADCM2700_H_ ++#define _ADCM2700_H_ ++ ++#include "camera.h" ++ ++////////////////////////////////////////////////////////////////////////////////////// ++// ++// Prototypes ++// ++////////////////////////////////////////////////////////////////////////////////////// ++ ++int camera_func_adcm2700_init(p_camera_context_t); ++int camera_func_adcm2700_deinit(p_camera_context_t); ++int camera_func_adcm2700_set_capture_format(p_camera_context_t); ++int camera_func_adcm2700_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_adcm2700_stop_capture(p_camera_context_t); ++ ++#endif /* _ADCM2700_H_ */ ++ ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm2700_hw.c linux-2.6.16/drivers/media/video/adcm2700_hw.c +--- linux-2.6.16.orig/drivers/media/video/adcm2700_hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm2700_hw.c 2006-06-03 11:14:56.425311304 +0200 +@@ -0,0 +1,936 @@ ++/*================================================================================ ++ ++ Header Name: adcm2700_hw.c ++ ++General Description: Camera module adcm2700 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++ ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++ ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++ Update algorithm for DMA transfer ++ Update strategy for memory management ++ Fix still picture capture failed sometime ++ New Agilent sensor chip ID support ++ Make output height in an even multiple of 8 ++ ++wangfei(w20239) 03/08/2004 LIBdd84578 Photo effects setting ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++ ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/wrapper.h> ++#include <linux/delay.h> ++#include <linux/i2c.h> ++ ++#define MAX_FPS 20 ++ ++#include "adcm2700_hw.h" ++#include "camera.h" ++ ++ ++extern int adcm2700_read(u16 addr, u16 *pvalue); ++extern int adcm2700_write(u16 addr, u16 value); ++extern int adcm2700_read_byte(unsigned short addr, unsigned char * value); ++ ++ ++ ++#define wait_sreg_update() { int retry = adcm2700__TIMEOUT<<2; \ ++ dbg_print("wait for sensor update simple registers"); \ ++ adcm2700_write(SREG_CONTROL, 0x05); \ ++ while(--retry) \ ++ { \ ++ u16 v = adcm2700_reg_read(SREG_CONTROL); \ ++ mdelay(1); \ ++ if(v == 0xFF) break; \ ++ if(!(v & 0x04)) break; \ ++ } \ ++ dbg_print("retry = %d", retry); \ ++ } ++ ++void adcm2700_wait(u32 ms) ++{ ++ if(ms > 10) ++ { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(ms/10); ++ } ++} ++ ++/**************************************************************************** ++* * ++* I2C Management * ++* * ++*****************************************************************************/ ++u16 adcm2700_reg_read(u16 reg_addr) ++{ ++ u16 value; ++ int ret = adcm2700_read(reg_addr, &value); ++ if(ret < 0) ++ { ++ return 0xFF; ++ } ++ return value; ++} ++ ++void adcm2700_reg_write(u16 reg_addr, u16 reg_value) ++{ ++ ++ /*experts registers or SREG_CONTROL write directly*/ ++ if(reg_addr > 0x26 || reg_addr == SREG_CONTROL) ++ { ++ adcm2700_write(reg_addr, reg_value); ++ return; ++ } ++ ++ /* write sample control register step: ++ 1 Stop the camera ¨C write 0x0000 to the CONTROL register. ++ 2 Change the relevant register. ++ 3 Set the CONFIG bit in the CONTROL register, write 0x0004. ++ 4 Wait for the CONFIG bit in CONTROL to clear. */ ++ adcm2700_write(SREG_CONTROL, 0); ++ adcm2700_write(reg_addr, reg_value); ++ wait_sreg_update(); ++ adcm2700_write(SREG_CONTROL, 0x01); ++ ++} ++ ++/*restore capture property*/ ++int adcm2700_restore_property(p_camera_context_t cam_ctx, int frames) ++{ ++ u16 awb_gain_grn1, awb_gain_grn2, awb_gain_red, awb_gain_blue; ++ u8 ae_gain1, ae_gain2, ae_gain3, ae_gain4; ++ u8 r813, r814, r815, r80e; ++ u16 r80, r84, rp; ++ u16 clk_div, sen_clk_div; ++ u32 texp; ++ ++ dbg_print("sensor width %d", cam_ctx->sensor_width); ++ dbg_print("sensor height %d", cam_ctx->sensor_height); ++ dbg_print("capture_width %d", cam_ctx->capture_width); ++ dbg_print("capture_height %d", cam_ctx->capture_height); ++ ddbg_print("fps %d mini fps %d", cam_ctx->fps, cam_ctx->mini_fps); ++ ddbg_print("light %d", cam_ctx->capture_light); ++ ddbg_print("capture_bright %d", cam_ctx->capture_bright); ++ ddbg_print("capture_style %d", cam_ctx->capture_style); ++ ++ ++ awb_gain_grn1 = adcm2700_reg_read(EREG_APS_COEF_GRN1); ++ awb_gain_grn2 = adcm2700_reg_read(EREG_APS_COEF_GRN2); ++ awb_gain_red = adcm2700_reg_read(EREG_APS_COEF_RED); ++ awb_gain_blue = adcm2700_reg_read(EREG_APS_COEF_BLUE); ++ ++ adcm2700_read_byte(0x080F, &ae_gain1); ++ adcm2700_read_byte(0x0810, &ae_gain2); ++ adcm2700_read_byte(0x0811, &ae_gain3); ++ adcm2700_read_byte(0x0812, &ae_gain4); ++ ++ adcm2700_read_byte(0x813, &r813); ++ adcm2700_read_byte(0x814, &r814); ++ adcm2700_read_byte(0x815, &r815); ++ adcm2700_read_byte(0x80e, &r80e); ++ dbg_print("r813= %x, r814=%x r815 = %x", r813, r814, r815); ++ ++ adcm2700_read(0x80, &r80); ++ adcm2700_read(0x84, &r84); ++ adcm2700_read(0x114, &rp); ++ ++ clk_div = r80+1; ++ sen_clk_div = (r84 == 0) ? 1 : (r84<<1); ++ texp = ((((u32)r814)<<8) + r813) * rp + 4 * r815; ++ texp *= clk_div * sen_clk_div * r80e; ++ dbg_print("before rp = 0x%x r80 = 0x%x r84 = 0x%x", rp, r80, r84); ++ dbg_print("before clk_div = 0x%x sen_clk_div = 0x%x r80e = 0x%x", clk_div, sen_clk_div, r80e); ++ //update simple registers ++ adcm2700_write(SREG_CONTROL, 0); ++ //sensor width and sensor height ++ adcm2700_write(SREG_SIZE, 0x707); ++ adcm2700_write(SREG_SENSOR_WID_V, (u16)(cam_ctx->sensor_width)); ++ adcm2700_write(SREG_SENSOR_HGT_V, (u16)(cam_ctx->sensor_height)); ++ ++ //output width and output height ++ adcm2700_write(SREG_OUTPUT_WID_V, (u16)(cam_ctx->capture_width)); ++ adcm2700_write(SREG_OUTPUT_HGT_V, (u16)(cam_ctx->capture_height)); ++ ++ //default fps ++ adcm2700_write(SREG_FRAME_RATE, cam_ctx->fps*10); ++ wait_sreg_update(); ++ adcm2700_set_light(cam_ctx->capture_light); ++ adcm2700_write(EREG_AE_ETIME_MAX, 100000/(cam_ctx->mini_fps)); ++ ++ //still mode and not night mode ++ if(frames == 1) ++ { ++ adcm2700_write(EREG_AF_CTRL1, 0x10); ++ adcm2700_read_byte(0x80e, &r80e); ++ adcm2700_read(0x80, &r80); ++ adcm2700_read(0x84, &r84); ++ adcm2700_read(0x114, &rp); ++ clk_div = r80+1; ++ sen_clk_div = (r84 == 0) ? 1 : (r84<<1); ++ texp /= (clk_div * sen_clk_div * r80e); ++ u16 ttexp = (texp/rp); ++ r815 = (u8)((texp - ttexp * rp)>>2); ++ r813 = (u8)(ttexp & 0xFF); ++ r814 = (u8)(ttexp >> 8); ++ dbg_print("after r813= %x, r814=%x r815 = %x", r813, r814, r815); ++ adcm2700_write_byte(0x813, r813); ++ adcm2700_write_byte(0x814, r814); ++ adcm2700_write_byte(0x815, r815); ++ dbg_print("after rp = 0x%x r80 = 0x%x r84 = 0x%x", rp, r80, r84); ++ dbg_print("after clk_div = 0x%x sen_clk_div = 0x%x r80e = 0x%x", clk_div, sen_clk_div, r80e); ++ ++ ++ adcm2700_write_byte(0x080F, ae_gain1); ++ adcm2700_write_byte(0x0810, ae_gain2); ++ adcm2700_write_byte(0x0811, ae_gain3); ++ adcm2700_write_byte(0x0812, ae_gain4); ++ ++ adcm2700_write(EREG_APS_COEF_GRN1, awb_gain_grn1); ++ adcm2700_write(EREG_APS_COEF_GRN2, awb_gain_grn2); ++ adcm2700_write(EREG_APS_COEF_RED, awb_gain_red); ++ adcm2700_write(EREG_APS_COEF_BLUE, awb_gain_blue); ++ ++ } ++ else ++ { ++ ++ } ++ ++ ++ //expert registers ++ adcm2700_set_bright(cam_ctx->capture_bright); ++ ++ if(cam_ctx->capture_style == V4l_STYLE_NORMAL && frames == 1) ++ { ++ adcm2700_set_gamma(3); ++ } ++ else ++ { ++ adcm2700_set_style(cam_ctx->capture_style); ++ } ++ ++ adcm2700_write(SREG_CONTROL, 0x01); ++ return ADCM_ERR_NONE; ++ ++} ++ ++ ++/////////////////////////////////////////////////////////////// ++// ++// Programming Guide Chapter 1: Basic Programming ++// ++/////////////////////////////////////////////////////////////// ++ ++void adcm2700_color_init(void); ++ ++int adcm2700_power_on( u8 clk ) ++{ ++ /*Follow these steps to correctly power on the ADCM-2700: ++ 1 Turn on VCC voltage (2.8 volts) and wait 20 milliseconds. ++ 2 Turn on MCLK (13 MHz is the default value) and wait 150 milliseconds. ++ 3 Read register 0x0004; if the return value equals 0x0001, power-up is complete. */ ++ int retry = adcm2700__TIMEOUT<<2; ++ while(--retry) ++ { ++ if(adcm2700_reg_read(SREG_STATUS) == 0x0001) ++ { ++ dbg_print("adcm2700 Power-up complete!!"); ++ break; ++ } ++ adcm2700_wait(2); ++ } ++ ++ ++ ++ /* Program the mafster clock */ ++ adcm2700_master_clock(clk); ++ ++ /* Configure anti-vignetting */ ++ adcm2700_color_init(); ++ ++ return ADCM_ERR_NONE; ++} ++ ++ ++int adcm2700_power_off() ++{ ++ /*stop camera*/ ++ adcm2700_write(SREG_CONTROL, 0); ++ return ADCM_ERR_NONE; ++} ++ ++ ++///////////////////////////////////////////////////////////////////////////////////// ++// ++// Programming Guide Chapter 2: Configuration Methods ++// ++///////////////////////////////////////////////////////////////////////////////////// ++ ++ ++int adcm2700_version_revision(u16 * cm_revision, u16 *sensor_revision) ++{ ++ //Camera module version is 0x060 ++ *cm_revision = adcm2700_reg_read(SREG_ID); ++ dbg_print("adcm2700 SREG_ID is 0x%x", *cm_revision); ++ ++ //Image sensor version is 0x60 ++ *sensor_revision = adcm2700_reg_read(EREG_IDENT); ++ dbg_print("adcm2700 EREG_IDENT is 0x%x", *sensor_revision); ++ return ADCM_ERR_NONE; ++} ++ ++int adcm2700_viewfinder_on() ++{ ++ //adcm2700_write(SREG_CONTROL, 0x01); ++ ddbg_print("camera video mode start!"); ++ return ADCM_ERR_NONE; ++} ++ ++ ++ ++int adcm2700_viewfinder_off() ++{ ++ //adcm2700_write(SREG_CONTROL, 0); ++ ddbg_print("camera video mode stop!"); ++ // adcm2700_store_af_regs(); ++ return ADCM_ERR_NONE; ++} ++ ++ ++int adcm2700_snapshot_trigger() ++{ ++ /* ++ u16 status = adcm2700_reg_read(EREG_AF_STATUS); ++ int retry = adcm2700__TIMEOUT<<1; ++ while(--retry) ++ { ++ if(status & 0x08) ++ break; ++ status = adcm2700_reg_read(EREG_AF_STATUS); ++ } ++ dbg_print("retry = %d", retry); ++ ++ */ ++ return ADCM_ERR_NONE; ++} ++ ++int adcm2700_master_clock(u8 clk) ++{ ++ ++ //0x2712 2X ++ //0x1D09 3X //default ++ //0x2709 4X ++ //0xFC53 ++ u16 div = 0x1D09; ++ ++ clk *= (((div>>8) + 1)/((div&0xFF) + 1)); ++ ++ ++ //adcm2700_reg_write(EREG_SEN_CLK_DIV, 1); ++ ++ /*enable pll*/ ++ adcm2700_write(SREG_CONTROL, 0); ++ ++ adcm2700_write(SREG_CLK_FREQ, (u16)clk * 1000); ++ adcm2700_write(EREG_PLL_DIV_L, div); ++ adcm2700_write(EREG_PLL_DIV_S, div); ++ adcm2700_write(EREG_PLL_CTRL, 0x0025); //0x002D ++ ++ wait_sreg_update(); ++ //adcm2700_reg_write(EREG_I_CLK_DIV, 0); ++ adcm2700_write(SREG_CONTROL, 1); ++ ++ return ADCM_ERR_NONE; ++} ++ ++ ++int adcm2700_input_size(adcm_window_size * window) ++{ ++ ++ /* write sample control register step: ++ 1 Stop the camera ¨C write 0x0000 to the CONTROL register. ++ 2 Change the relevant register. ++ 3 Set the CONFIG bit in the CONTROL register, write 0x0004. ++ 4 Wait for the CONFIG bit in CONTROL to clear. */ ++ /* ++ adcm2700_write(SREG_CONTROL, 0); ++ ++ adcm2700_write(SREG_SIZE, 0x707); ++ adcm2700_write(SREG_SENSOR_WID_V, window->width); ++ adcm2700_write(SREG_SENSOR_HGT_V, window->height); ++ ++ //adcm2700_write(SREG_SENSOR_WID_S, window->width); ++ //adcm2700_write(SREG_SENSOR_HGT_S, window->height); ++ ++ wait_sreg_update(); ++ */ ++ return ADCM_ERR_NONE; ++ } ++int adcm2700_output_size(adcm_window_size * window) ++{ ++ ++ /* write sample control register step: ++ 1 Stop the camera ¨C write 0x0000 to the CONTROL register. ++ 2 Change the relevant register. ++ 3 Set the CONFIG bit in the CONTROL register, write 0x0004. ++ 4 Wait for the CONFIG bit in CONTROL to clear. */ ++/* ++ adcm2700_write(SREG_CONTROL, 0); ++ ++ adcm2700_write(SREG_SIZE, 0x707); ++ adcm2700_write(SREG_OUTPUT_WID_V, window->width); ++ adcm2700_write(SREG_OUTPUT_HGT_V, window->height); ++// adcm2700_write(SREG_OUTPUT_WID_S, window->width); ++// adcm2700_write(SREG_OUTPUT_HGT_S, window->height); ++ ++ wait_sreg_update(); ++ */ ++ return ADCM_ERR_NONE; ++} ++ ++ ++int adcm2700_set_fps(u16 fps, u16 minfps) ++{ ++ if(fps > MAX_FPS || minfps > fps) ++ { ++ return ADCM_ERR_PARAMETER; ++ } ++ ++ adcm2700_reg_write(SREG_FRAME_RATE, fps*10); ++ adcm2700_reg_write(EREG_AE_ETIME_MAX, 100000/(minfps)); ++ ++ return ADCM_ERR_NONE; ++} ++ ++ ++int adcm2700_stillframe_cfg_output(u16 format) ++{ ++ ++ u16 oldcfg = adcm2700_reg_read(SREG_OUTPUT_FORMAT); ++ ++ oldcfg = (oldcfg & 0xF0FF) | ((format & 0x000F) << 8); ++ adcm2700_reg_write( SREG_OUTPUT_FORMAT, oldcfg); ++ ++ return ADCM_ERR_NONE; ++} ++ ++int adcm2700_viewfinder_cfg_output(u16 format) ++{ ++ ++ u16 oldcfg = adcm2700_reg_read( SREG_OUTPUT_FORMAT); ++ ++ oldcfg = (oldcfg & 0xFFF0) | (format & 0x000F); ++ adcm2700_reg_write( SREG_OUTPUT_FORMAT, oldcfg ); ++ return ADCM_ERR_NONE; ++} ++ ++ ++ ++void adcm2700_dump_register(u16 startRegAddr, u16 endRegAddr, u16* buffer) ++{ ++ u16 addr; ++ ++ for(addr = startRegAddr; addr <= endRegAddr; addr+=2) ++ { ++ adcm2700_read(addr, buffer++); ++ } ++} ++ ++int adcm2700_set_gamma(int table) ++{ ++ const u16 regs[] = ++ { ++ 0x1400, 0x1402, 0x1404, 0x1406, 0x1408, 0x140a, 0x140c, 0x140e, 0x1410, 0x1412, 0x1414, ++ 0x1416, 0x1418, 0x141a, 0x141c, 0x141e, 0x1420, 0x1422, 0x1424, 0x1426, 0x1428, 0x142a, ++ 0x142c, 0x142e, 0x1430, 0x1432, 0x1434, 0x1436, 0x1438, 0x143a, 0x143c, 0x143e, 0x1440 ++ }; ++ ++ ++ const u16 regsv[] = ++ { ++ EREG_TM_COEF_00_V, EREG_TM_COEF_01_V, EREG_TM_COEF_02_V, EREG_TM_COEF_03_V, ++ EREG_TM_COEF_04_V, EREG_TM_COEF_05_V, EREG_TM_COEF_06_V, EREG_TM_COEF_07_V, ++ EREG_TM_COEF_08_V, EREG_TM_COEF_09_V, EREG_TM_COEF_10_V, EREG_TM_COEF_11_V, ++ EREG_TM_COEF_12_V, EREG_TM_COEF_13_V, EREG_TM_COEF_14_V, EREG_TM_COEF_15_V, ++ EREG_TM_COEF_16_V, EREG_TM_COEF_17_V, EREG_TM_COEF_18_V, EREG_TM_COEF_19_V, ++ EREG_TM_COEF_20_V, EREG_TM_COEF_21_V, EREG_TM_COEF_22_V, EREG_TM_COEF_23_V, ++ EREG_TM_COEF_24_V, EREG_TM_COEF_25_V, EREG_TM_COEF_26_V, EREG_TM_COEF_27_V, ++ EREG_TM_COEF_28_V, EREG_TM_COEF_29_V, EREG_TM_COEF_30_V, EREG_TM_COEF_31_V, ++ EREG_TM_COEF_32_V ++ }; ++ const u16 regss[] = ++ { ++ EREG_TM_COEF_00_S, EREG_TM_COEF_01_S, EREG_TM_COEF_02_S, EREG_TM_COEF_03_S, ++ EREG_TM_COEF_04_S, EREG_TM_COEF_05_S, EREG_TM_COEF_06_S, EREG_TM_COEF_07_S, ++ EREG_TM_COEF_08_S, EREG_TM_COEF_09_S, EREG_TM_COEF_10_S, EREG_TM_COEF_11_S, ++ EREG_TM_COEF_12_S, EREG_TM_COEF_13_S, EREG_TM_COEF_14_S, EREG_TM_COEF_15_S, ++ EREG_TM_COEF_16_S, EREG_TM_COEF_17_S, EREG_TM_COEF_18_S, EREG_TM_COEF_19_S, ++ EREG_TM_COEF_20_S, EREG_TM_COEF_21_S, EREG_TM_COEF_22_S, EREG_TM_COEF_23_S, ++ EREG_TM_COEF_24_S, EREG_TM_COEF_25_S, EREG_TM_COEF_26_S, EREG_TM_COEF_27_S, ++ EREG_TM_COEF_28_S, EREG_TM_COEF_29_S, EREG_TM_COEF_30_S, EREG_TM_COEF_31_S, ++ EREG_TM_COEF_32_S ++ }; ++ ++ const u16 value[][33] = ++ { ++ //default ++ 0x0000, 0x003c, 0x0052, 0x0063, 0x0070, 0x007c, 0x0087, 0x0091, 0x0094, 0x00ab, 0x00b9, ++ 0x00c7, 0x00d3, 0x00ea, 0x00fe, 0x0111, 0x0122, 0x0141, 0x015d, 0x0176, 0x018d, 0x01b8, ++ 0x01de, 0x0201, 0x0221, 0x025b, 0x028f, 0x02bf, 0x02eb, 0x033b, 0x0382, 0x03c3, 0x0400, ++ /* ++ 0x0000, 0x004C, 0x0065, 0x0078, 0x0087, 0x0094, 0x00A0, 0x00ab, 0x00b5, 0x00c6, 0x00d6, ++ 0x00e4, 0x00f1, 0x0109, 0x011E, 0x0131, 0x0142, 0x0161, 0x017D, 0x0197, 0x01AE, 0x01d8, ++ 0x01fd, 0x021F, 0x023E, 0x0276, 0x02a8, 0x02d5, 0x02ff, 0x0349, 0x038C, 0x03C8, 0x0400, ++ */ ++ ++ ++ //solarize ++ 0x0400, 0x03e9, 0x03a9, 0x0344, 0x02c3, 0x0232, 0x019c, 0x010e, 0x0095, 0x003c, 0x0009, ++ 0x0002, 0x0026, 0x0074, 0x00e3, 0x016b, 0x01ff, 0x0294, 0x031c, 0x038b, 0x03d9, 0x03fd, ++ 0x03f6, 0x03c3, 0x036a, 0x02f1, 0x0263, 0x01cd, 0x013c, 0x00bb, 0x0056, 0x0016, 0x0000, ++ ++ //neg.art ++ 0x03ff, 0x03e8, 0x03cd, 0x03b9, 0x03a9, 0x039b, 0x038e, 0x0383, 0x0379, 0x0366, 0x0356, ++ 0x0347, 0x0339, 0x0320, 0x030a, 0x02f6, 0x02e4, 0x02c2, 0x02a5, 0x028a, 0x0272, 0x0245, ++ 0x021e, 0x01fa, 0x01da, 0x019e, 0x016a, 0x013a, 0x010e, 0x00c0, 0x007a, 0x003a, 0x0000, ++ ++ ++ /* ++ //2.6 ++ 0x0000, 0x005C, 0x0079, 0x008d, 0x009e, 0x00ac, 0x00b9, 0x00c4, 0x00ce, 0x00e1, 0x00f1, ++ 0x0100, 0x010e, 0x0126, 0x013b, 0x014e, 0x0160, 0x0180, 0x019c, 0x01b5, 0x01cc, 0x01f5, ++ 0x0219, 0x023a, 0x0258, 0x028e, 0x02be, 0x02e9, 0x0310, 0x0356, 0x0394, 0x03cc, 0x0400, ++ ++ //2.4 ++ 0x0000, 0x004C, 0x0065, 0x0078, 0x0087, 0x0094, 0x00A0, 0x00ab, 0x00b5, 0x00c6, 0x00d6, ++ 0x00e4, 0x00f1, 0x0109, 0x011E, 0x0131, 0x0142, 0x0161, 0x017D, 0x0197, 0x01AE, 0x01d8, ++ 0x01fd, 0x021F, 0x023E, 0x0276, 0x02a8, 0x02d5, 0x02ff, 0x0349, 0x038C, 0x03C8, 0x0400, ++ ++ //2.3 ++ 0x0000, 0x0043, 0x005b, 0x006d, 0x007c, 0x0088, 0x0094, 0x009e, 0x00a7, 0x00b8, 0x00c8, ++ 0x00d6, 0x00e2, 0x00fa, 0x010e, 0x0121, 0x0132, 0x0151, 0x016d, 0x0187, 0x019e, 0x01c8, ++ 0x01ee, 0x0210, 0x0230, 0x0269, 0x029c, 0x02ca, 0x02f5, 0x0342, 0x0387, 0x03c6, 0x0400, ++ */ ++ //2.2 ++ 0x0000, 0x003c, 0x0052, 0x0063, 0x0070, 0x007c, 0x0087, 0x0091, 0x0094, 0x00ab, 0x00b9, ++ 0x00c7, 0x00d3, 0x00ea, 0x00fe, 0x0111, 0x0122, 0x0141, 0x015d, 0x0176, 0x018d, 0x01b8, ++ 0x01de, 0x0201, 0x0221, 0x025b, 0x028f, 0x02bf, 0x02eb, 0x033b, 0x0382, 0x03c3, 0x0400, ++ ++ //2.1 ++ 0x0000, 0x0034, 0x0049, 0x0058, 0x0065, 0x0070, 0x007b, 0x0084, 0x008d, 0x009d, 0x00ab, ++ 0x00b8, 0x00c4, 0x00da, 0x00ee, 0x0100, 0x0111, 0x0130, 0x014b, 0x0164, 0x017c, 0x01a7, ++ 0x01cd, 0x01f0, 0x0211, 0x024c, 0x0281, 0x02b2, 0x02e0, 0x0332, 0x037c, 0x03c0, 0x0400, ++ ++ //2.0 ++ 0x0000, 0x002d, 0x0040, 0x004e, 0x005a, 0x0065, 0x006e, 0x0077, 0x0080, 0x008f, 0x009c, ++ 0x00a9, 0x00b5, 0x00ca, 0x00dd, 0x00ef, 0x0100, 0x011e, 0x0139, 0x0152, 0x016a, 0x0194, ++ 0x01bb, 0x01de, 0x0200, 0x023c, 0x0273, 0x02a5, 0x02d4, 0x0329, 0x0376, 0x03bd, 0x0400, ++ ++ //1.9 ++ 0x0000, 0x0026, 0x0037, 0x0044, 0x004f, 0x0059, 0x0062, 0x006a, 0x0072, 0x0081, 0x008e, ++ 0x009a, 0x00a5, 0x00b9, 0x00cc, 0x00dd, 0x00ed, 0x010b, 0x0126, 0x013f, 0x0156, 0x0181, ++ 0x01a8, 0x01cc, 0x01ed, 0x022b, 0x0263, 0x0296, 0x02c6, 0x031f, 0x0370, 0x03ba, 0x0400, ++ ++ //1.8 ap30 ++ 0x0000, 0x0020, 0x002f, 0x003a, 0x0045, 0x004e, 0x0056, 0x005e, 0x0065, 0x0073, 0x007f, ++ 0x008a, 0x0095, 0x00a9, 0x00bb, 0x00cb, 0x00db, 0x00f8, 0x0112, 0x012b, 0x0142, 0x016d, ++ 0x0194, 0x01b8, 0x01da, 0x0218, 0x0251, 0x0286, 0x02b8, 0x0314, 0x0368, 0x03b6, 0x0400, ++ //default ++ ++ 0x0000, 0x0017, 0x0032, 0x0046, 0x0056, 0x0064, 0x0071, 0x007c, 0x0086, 0x0099, 0x00a9, ++ 0x00b8, 0x00c6, 0x00df, 0x00f5, 0x0109, 0x011b, 0x013d, 0x015a, 0x0175, 0x018d, 0x01ba, ++ 0x01e1, 0x0205, 0x0225, 0x0261, 0x0295, 0x02c5, 0x02f1, 0x033f, 0x0385, 0x03c5, 0x0400 ++ ++ }; ++ ++ int i, ret; ++ /* ++ for(i = 0; i < 33; i++) ++ { ++ ret = adcm2700_write(regss[i], value[table][i]); ++ if(ret < 0) ++ { ++ dbg_print("adcm2700 write error!"); ++ return -1; ++ } ++ } ++ */ ++ ++ for(i = 0; i < 33; i++) ++ { ++ ret = adcm2700_write(regsv[i], value[table][i]); ++ if(ret < 0) ++ { ++ dbg_print("adcm2700 write error!"); ++ return -1; ++ } ++ } ++ ++ for(i = 0; i < 33; i++) ++ { ++ ret = adcm2700_write(regs[i], value[table][i]); ++ if(ret < 0) ++ { ++ dbg_print("adcm2700 write error!"); ++ return -1; ++ } ++ } ++ return ADCM_ERR_NONE; ++} ++/*set picture style(normal/black white/sepia/solarize/neg.art)*/ ++int adcm2700_set_style(V4l_PIC_STYLE style) ++{ ++ const u16 regs1[] = {EREG_CC_COEF_00, EREG_CC_COEF_01, EREG_CC_COEF_02, ++ EREG_CC_COEF_10, EREG_CC_COEF_11, EREG_CC_COEF_12, ++ EREG_CC_COEF_20, EREG_CC_COEF_21, EREG_CC_COEF_22}; ++ ++ // 0 - normal 1 - black white 2 - sepia ++ const u16 value1[][9] = ++ { ++ //{0x02f9, 0x0f03, 0x0f02, 0x0f4f, 0x025c, 0x0f54, 0x0fe0, 0x0e4a, 0x02d5}, //normal settings ++ ++ {0x01f0, 0x0f88, 0x0f88, ++ 0x0f88, 0x01f0, 0x0f88, ++ 0x0f88, 0x0f88, 0x01f0}, ++ ++ {0x003b, 0x00c8, 0x0fcf, 0x003b, 0x00c8, 0x0fcf, 0x003b, 0x00c8, 0x0fcf}, //black white ++ {0x005c, 0x0131, 0x0fb6, 0x0030, 0x00a2, 0x0fd9, 0x001a, 0x0058, 0x0feb}, //sepia ++ }; ++ ++ ++ u16 * reg_value; ++ u16 reg_count; ++ int i; ++ ++ switch(style) ++ { ++ case V4l_STYLE_BLACK_WHITE: ++ adcm2700_set_gamma(0); ++ reg_value = value1[1]; ++ reg_count = 9; ++ break; ++ case V4l_STYLE_SEPIA: ++ adcm2700_set_gamma(0); ++ reg_value = value1[2]; ++ reg_count = 9; ++ break; ++ case V4l_STYLE_SOLARIZE: ++ adcm2700_set_gamma(1); ++ return ADCM_ERR_NONE; ++ case V4l_STYLE_NEG_ART: ++ adcm2700_set_gamma(2); ++ return ADCM_ERR_NONE; ++ default: ++ adcm2700_set_gamma(0); ++ // adcm2700_reg_write(SREG_ILLUM, illum); ++ return ADCM_ERR_NONE; ++ } ++ ++ for(i = 0; i < reg_count; i++) ++ { ++ adcm2700_write(regs1[i], reg_value[i]); ++ } ++ return ADCM_ERR_NONE; ++} ++ ++/*set picture light(auto/direct sun/incandescent/fluorescent)*/ ++u16 adcm2700_get_light_v(V4l_PIC_WB light) ++{ /* ++ const u16 regs1[] = {EREG_CC_COEF_00, EREG_CC_COEF_01, EREG_CC_COEF_02, ++ EREG_CC_COEF_10, EREG_CC_COEF_11, EREG_CC_COEF_12, ++ EREG_CC_COEF_20, EREG_CC_COEF_21, EREG_CC_COEF_22}; ++ ++ const u16 value1[][9] = ++ { ++ {0x02f9, 0x0f03, 0x0f02, 0x0f4f, 0x025c, 0x0f54, 0x0fe0, 0x0e4a, 0x02d5}, //default ++ {0x0235, 0x0f8f, 0x0f3b, 0x0f63, 0x01f0, 0x0fad, 0x000d, 0x0eb2, 0x0241}, //day ++ {0x0235, 0x0f46, 0x0f85, 0x0f64, 0x01fc, 0x0f9f, 0x0008, 0x0e8d, 0x026b}, //fluorescent ++ {0x023a, 0x0f34, 0x0f92, 0x0f5a, 0x0218, 0x0f8e, 0x0ffa, 0x0deb, 0x031b}, //tungsten ++ }; ++ int i, index; ++ switch(light) ++ { ++ case V4l_WB_DIRECT_SUN: ++ index = 1; ++ break; ++ case V4l_WB_INCANDESCENT: ++ index = 3; ++ break; ++ case V4l_WB_FLUORESCENT: ++ index = 2; ++ break; ++ default: ++ index = 0; ++ break; ++ } ++ for(i = 0; i< 9; i++) ++ { ++ adcm2700_write(regs1[i], value1[index][i]); ++ } ++ ++ */ ++ ++ u16 value = adcm2700_reg_read(SREG_ILLUM); ++ value &= ~0x0007; ++ switch(light) ++ { ++ case V4l_WB_DIRECT_SUN: ++ value |= 0x0002; ++ break; ++ case V4l_WB_INCANDESCENT: ++ value |= 0x0006; ++ break; ++ case V4l_WB_FLUORESCENT: ++ value |= 0x0004; ++ break; ++ default: ++ break; ++ } ++ return value; ++} ++/* Sunny - 5500K daylight */ ++const u16 agilent_sunny_color[] = ++{0x0214, 0x0F6E, 0x0F7C, ++ 0x0F58, 0x022D, 0x0F79, ++ 0x0FF4, 0x0EB3, 0x0257}; ++ ++/* Cloudy - 7500K daylight */ ++const u16 agilent_cloudy_color[] = ++{0x021B, 0x0F8D, 0x0F56, ++ 0x0F5C, 0x0226, 0x0F7D, ++ 0x0FF5, 0x0EE7, 0x0223}; ++ ++/* Indoor - home tungsten */ ++const u16 agilent_home_tungsten_color[] = ++{0x0243, 0x0EDD, 0x0FDF, ++ 0x0F3B, 0x0273, 0x0F50, ++ 0x0FA4, 0x0D9F, 0x03BB}; ++ ++/* Indoor - office cool white fluorescent */ ++const u16 agilent_office_cool_white_fluorescent_color[] = ++{0x01CF, 0x0F6E, 0x0FC1, ++ 0x0F72, 0x020D, 0x0F7F, ++ 0x0FEF, 0x0E5A, 0x02B6}; ++ ++/* Night tungsten */ ++const u16 agilent_night_tungsten_color[] = ++{0x0243, 0x0EDD, 0x0FDF, ++ 0x0F3B, 0x0273, 0x0F50, ++ 0x0FA4, 0x0D9F, 0x03BB}; ++ ++/* Automatic (generic default setting) 6500K daylight */ ++const u16 agilent_automatic_color[] = ++{0x02F4, 0x0F27, 0x0F30, ++ 0x0F0C, 0x02F2, 0x0F4E, ++ 0x0FE8, 0x0E2E, 0x0335}; ++ ++int adcm2700_set_light(V4l_PIC_WB light) ++{ ++ // u16 value = adcm2700_get_light_v(light); ++ // adcm2700_reg_write(SREG_ILLUM, value); ++ ++ const u16 regs1[] = {EREG_CC_COEF_00, EREG_CC_COEF_01, EREG_CC_COEF_02, ++ EREG_CC_COEF_10, EREG_CC_COEF_11, EREG_CC_COEF_12, ++ EREG_CC_COEF_20, EREG_CC_COEF_21, EREG_CC_COEF_22}; ++ const u16 agilent_default[] = {0x02f9, 0x0f03, 0x0f02, 0x0f4f, 0x025c, 0x0f54, 0x0fe0, 0x0e4a, 0x02d5}; ++ /* ++ const u16 value1[][9] = ++ { ++ {0x02f9, 0x0f03, 0x0f02, 0x0f4f, 0x025c, 0x0f54, 0x0fe0, 0x0e4a, 0x02d5}, //default ++ {0x0235, 0x0f8f, 0x0f3b, 0x0f63, 0x01f0, 0x0fad, 0x000d, 0x0eb2, 0x0241}, //day ++ {0x0235, 0x0f46, 0x0f85, 0x0f64, 0x01fc, 0x0f9f, 0x0008, 0x0e8d, 0x026b}, //fluorescent ++ {0x023a, 0x0f34, 0x0f92, 0x0f5a, 0x0218, 0x0f8e, 0x0ffa, 0x0deb, 0x031b}, //tungsten ++ }; ++ */ ++ int i; ++ const u16 * values = NULL; ++ u16 v = adcm2700_reg_read(EREG_AF_CTRL1); ++ switch(light) ++ { ++ case V4l_WB_DIRECT_SUN: ++ values = agilent_sunny_color; ++ adcm2700_write(EREG_AF_CTRL1, v&(~0x0002)); ++ break; ++ case V4l_WB_INCANDESCENT: ++ values = agilent_night_tungsten_color; ++ adcm2700_write(EREG_AF_CTRL1, v&(~0x0002)); ++ break; ++ case V4l_WB_FLUORESCENT: ++ values = agilent_office_cool_white_fluorescent_color; ++ adcm2700_write(EREG_AF_CTRL1, v&(~0x0002)); ++ break; ++ default: ++ values = agilent_automatic_color; ++ adcm2700_write(EREG_AF_CTRL1, v|0x0002); ++ break; ++ } ++ if(values != agilent_automatic_color) ++ { ++ for(i = 0; i < 9; i++) ++ { ++ adcm2700_write(regs1[i], values[i]); ++ } ++ } ++ return 0; ++} ++ ++/*set picture brightness*/ ++int adcm2700_set_bright(int bright) ++{ ++ const u16 target[] = ++ { ++ 0x0010, // -2.0 EV ++ 0x0015, // -1.5 EV ++ 0x0020, // -1.0 EV ++ 0x0030, // -0.5 EV ++ 0x0040, // 0.0 EV ++ 0x0060, // +0.5 EV ++ 0x0080, // +1.0 EV ++ 0x00C0, // +1.5 EV ++ 0x00FF // +2.0 EV ++ }; ++ ++ if(bright < -4 || bright > 4) ++ { ++ return ADCM_ERR_PARAMETER; ++ } ++ adcm2700_write(EREG_AE_TARGET, target[bright+4]); ++ return ADCM_ERR_NONE; ++} ++ ++#define ADCM2700_PROC_CTRL_V_REG 0x0112 ++#define ADCM2700_PROC_CTRL_S_REG 0x0132 ++ ++#define ADCM2700_AV_CENTER_COL_REG 0x106e ++#define ADCM2700_AV_CENTER_ROW_REG 0x1070 ++#define ADCM2700_AV_OVAL_FACT_REG 0x1094 ++ ++ ++#define ADCM2700_PROC_CTRL_V_REG 0x0112 ++#define ADCM2700_PROC_CTRL_S_REG 0x0132 ++ ++#define ADCM2700_AV_LEFT_TOP_REG 0x106a ++#define ADCM2700_AV_RIGHT_BOT_REG 0x106c ++#define ADCM2700_AV_CENTER_COL_REG 0x106e ++#define ADCM2700_AV_CENTER_ROW_REG 0x1070 ++#define ADCM2700_AV_OVAL_FACT_REG 0x1094 ++ ++#define ADCM2700_AV_RED_RAM_REG 0x1800 ++#define ADCM2700_AV_GREEN_RAM_REG 0x1840 ++#define ADCM2700_AV_BLUE_RAM_REG 0x1880 ++ ++unsigned short AV_BLUE_2700[32] = ++{ ++ 0x47, 0x49, 0x4b, 0x4d, 0x50, 0x52, 0x55, 0x58, ++ 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6d, 0x71, ++ 0x75, 0x79, 0x7d, 0x82, 0x87, 0x8d, 0x93, 0x9a, ++ 0xa1, 0xa9, 0xb2, 0xbd, 0xc8, 0xd6, 0xe5, 0xf7 ++}; ++ ++unsigned short AV_GREEN_2700[32] = ++{ ++ 0x44, 0x48, 0x4b, 0x4f, 0x52, 0x56, 0x5a, 0x5e, ++ 0x63, 0x67, 0x6c, 0x70, 0x75, 0x7b, 0x80, 0x86, ++ 0x8c, 0x92, 0x98, 0x9f, 0xa6, 0xae, 0xb5, 0xbd, ++ 0xc6, 0xcf, 0xd8, 0xe2, 0xed, 0xf8, 0x103, 0x10f ++}; ++ ++unsigned short AV_RED_2700[32] = ++{ ++ 0x43, 0x47, 0x4b, 0x50, 0x54, 0x59, 0x5e, 0x63, ++ 0x69, 0x6f, 0x75, 0x7b, 0x82, 0x89, 0x90, 0x97, ++ 0x9e, 0xa6, 0xae, 0xb6, 0xbe, 0xc6, 0xce, 0xd6, ++ 0xde, 0xe6, 0xee, 0xf6, 0xfe, 0x103, 0x104, 0x103 ++}; ++ ++ ++void adcm2700_color_init(void) ++{ ++ u16 regdata; ++ int count; ++ ++ adcm2700_reg_write(ADCM2700_AV_CENTER_COL_REG, 0x0146); ++ adcm2700_reg_write(ADCM2700_AV_CENTER_ROW_REG, 0x00fc); ++ adcm2700_reg_write(ADCM2700_AV_OVAL_FACT_REG, 0x10e); ++ ++ for(count = 0; count < 32; count++) ++ { ++ adcm2700_reg_write(ADCM2700_AV_RED_RAM_REG+count*2, AV_RED_2700[count]); ++ } ++ ++ for(count = 0; count < 32; count++) ++ { ++ adcm2700_reg_write(ADCM2700_AV_GREEN_RAM_REG+count*2, AV_GREEN_2700[count]); ++ } ++ ++ for(count = 0; count < 32; count++) ++ { ++ adcm2700_reg_write(ADCM2700_AV_BLUE_RAM_REG+count*2, AV_BLUE_2700[count]); ++ } ++ ++ ++ /* video mode sharpening enable*/ ++ regdata = adcm2700_reg_read(ADCM2700_PROC_CTRL_V_REG); ++ adcm2700_reg_write(ADCM2700_PROC_CTRL_V_REG, regdata|0x4800); ++ ++ /* still mode sharpening enable*/ ++ regdata = adcm2700_reg_read(ADCM2700_PROC_CTRL_S_REG); ++ adcm2700_reg_write(ADCM2700_PROC_CTRL_S_REG, regdata|0x4800); ++ ++ ++ /* disable automatic dark*/ ++ regdata = 0x64; ++ adcm2700_reg_write(0x081C, regdata); ++} ++ ++int adcm2700_set_flicker(int flicker) ++{ ++ ++ u16 old = adcm2700_reg_read(EREG_AF_CTRL2); ++ u16 old1 = adcm2700_reg_read(SREG_ILLUM); ++ old1 &= ~(0x18); ++ dbg_print("set flicker to %d", flicker); ++ if(flicker == 50) ++ { ++ adcm2700_reg_write(SREG_ILLUM, old1|0x08); ++ adcm2700_write(EREG_AF_CTRL2, old&(~0x02)); ++ //1000 = 100000/50/2 ++ adcm2700_write(EREG_AE_ETIME_DFLT, 1000); ++ } ++ else if(flicker == 60) ++ { ++ adcm2700_reg_write(SREG_ILLUM, old1|0x10); ++ adcm2700_write(EREG_AF_CTRL2, old|0x02); ++ // 833 = 100000/60/2 ++ adcm2700_write(EREG_AE_ETIME_DFLT, 833); ++ } ++ else ++ { ++ return ADCM_ERR_PARAMETER; ++ } ++ return 0; ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm2700_hw.h linux-2.6.16/drivers/media/video/adcm2700_hw.h +--- linux-2.6.16.orig/drivers/media/video/adcm2700_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm2700_hw.h 2006-06-03 11:14:56.427311000 +0200 +@@ -0,0 +1,533 @@ ++/*================================================================================ ++ ++ Header Name: adcm2700_hw.h ++ ++General Description: Camera module adcm2700 interface header file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++wangfei(w20239) 03/08/2004 LIBdd84578 Photo effects setting ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef _PXA_ADCM_2700_HW_H__ ++#define _PXA_ADCM_2700_HW_H__ ++ ++#include "camera.h" ++/*********************************************************************** ++ * ++ * Constants & Structures ++ * ++ ***********************************************************************/ ++ ++/* ADCM_WINDOWSIZE */ ++typedef struct { ++ u16 width; ++ u16 height; ++} adcm_window_size; ++ ++ ++// Revision constants ++#define PIPE_REV 0x60 ++#define PIPE_REV_NEW 0x61 ++#define SENSOR_REV 0x60 ++ ++// Calculating the Module Block Number ++#define BLOCK(a) (u8)((a) >> 7) // register's module block address. ++#define OFFSET(a) (u8)((a) & 0x7F ) // register's offset to this block. ++ ++// Return codes ++#define ADCM_ERR_NONE 0x00 ++#define ADCM_ERR_TIMEOUT -1 ++#define ADCM_ERR_PARAMETER -2 ++ ++// Auto Exposure Frequency ++#define AEF_50HZ 0x20 ++#define AEF_60HZ 0x40 ++ ++// Non JEPG Output Format ++#define O_FORMAT_888RGB 0 //0b0000 // 888 RGB (1 pixel in 3 bytes ) ++#define O_FORMAT_666_A_RGB 1 //0b0001 // 666 A RGB (tight pack, 4 pixels in 9 bytes) ++#define O_FORMAT_666_B_RGB 2 //0b0010 // 666 B RGB (loose pack, 1 pixel in 3 bytes,left or right justified) ++#define O_FORMAT_565_RGB 3 //0b0011 // 565 RGB (1 pixel in 2 bytes) ++#define O_FORMAT_444_A_RGB 4 //0b0100 // 444 A RGB (tight pack, 2 pixels per 3 bytes, RG BR GB) ++#define O_FORMAT_444_B_RGB 5 //0b0101 // 444 B RGB (loose pack, 1 pixel per 2 bytes,RG B0 or 0R GB) ++#define O_FORMAT_444_C_RGV 6 //0b0110 // 444 C RGB (sparse pack, 1 pixel per three bytes,R0 G0 B0 or 0R 0G 0B) ++#define O_FORMAT_332_RGB 7 //0b0111 // 332 RGB (1 pixel in 1 byte) ++#define O_FORMAT_422_A_YCbYCr 8 //0b1000 // 4:2:2 A YCbYCr (Y1 Cb12 Y2 CRL2 order) ++#define O_FORMAT_422_B_YCbYCr 9 //0b1001 // 4:2:2 B YCbYCr (Cb12 Y1 CRL2 Y2 order) ++#define O_FORMAT_422_C_YCbYCr 10 //0b1010 // 4:2:2 C YCbYCr (Y1 CRL2 Y2 Cb12 order) ++#define O_FORMAT_422_D_YCbYCr 11 //0b1011 // 4:2:2 D YCbYCr (CRL2 Y1 Cb12 Y2 order) ++#define O_FORMAT_444_YCbYCr 12 //0b1100 // 4:4:4 YCbCr (1 pixels per 3 bytes) ++#define O_FORMAT_400_B_YCbYCr 13 //0b1101 // 4:0:0 YCbCr (Greyscale, 1 pixel per 1 byte) ++#define O_FORMAT_RAWBPA 14 //0b1110 // RAWBPA (with AWB and BPA) ++#define O_FORMAT_RAW 15 //0b1111 // RAW (without AWB and BPA) ++ ++// Camera Mode ++#define VIEWFINDER_MODE 0x10 ++#define STILLFRAME_MODE 0x20 ++ ++// Others ++#define adcm2700__TIMEOUT 100 // ms to timeout. ++#define BLOCK_SWITCH_CMD ((u8)0xFE) // Block Switch Code: 0x7F, CMD = Code << 1 ++#define VOLTS_28 0x28 ++ ++ ++/************************************************************************************* ++ * ++ * Simple Control Registers Address ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define SREG_ID 0x0000 //Chip ID 0x0060 139 ++#define SREG_CONTROL 0x0002 //Camera control 0x0001 140 ++#define SREG_STATUS 0x0004 //Camera status 0x0004 142 ++#define SREG_CLK_FREQ 0x0006 //Input clock frequency 0x32c8 144 ++#define SREG_SIZE 0x0008 //Image size and orientation 0x0605 145 ++#define SREG_OUTPUT_FORMAT 0x000a //Output format 0x0909 147 ++#define SREG_EXPOSURE 0x000c //Exposure 0x03e8 149 ++#define SREG_EXP_ADJ 0x000e //Exposure adjustment 0x0000 150 ++#define SREG_ILLUM 0x0010 //Illumination 0x0000 151 ++#define SREG_FRAME_RATE 0x0012 //Requested frame rate 0x0096 152 ++#define SREG_A_FRAME_RATE 0x0016 //Actual frame rate 0x0096 154 ++#define SREG_SENSOR_WID_V 0x0018 //Sensor window width, video mode 0x0000 155 ++#define SREG_SENSOR_HGT_V 0x001a //Sensor window height, video mode 0x0000 156 ++#define SREG_OUTPUT_WID_V 0x001c //Output window width, video mode 0x0000 157 ++#define SREG_OUTPUT_HGT_V 0x001e //Output window height, video mode 0x0000 158 ++#define SREG_SENSOR_WID_S 0x0020 //Sensor window width, still mode 0x0000 159 ++#define SREG_SENSOR_HGT_S 0x0022 //Sensor window height, still mode 0x0000 160 ++#define SREG_OUTPUT_WID_S 0x0024 //Output window width, still mode 0x0000 161 ++#define SREG_OUTPUT_HGT_S 0x0026 //Output window height, still mode 0x0000 162 ++ ++/************************************************************************************* ++ * ++ * Expert Hardware Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define EREG_I_CLK_DIV 0x0080 //Initial clock divider 0x0001 166 ++#define EREG_CTL_CLK_DIV 0x0082 //Clock dividers for control ++ //and serial interfaces 0x4000 167 ++#define EREG_SEN_CLK_DIV 0x0084 //Sensor clock dividers 0x0000 168 ++#define EREG_IP_CLK_DIV 0x0086 //Clock dividers for image pipeline 0x0000 169 ++#define EREG_TST_MODE 0x0088 //Latched test mode 0x0000 170 ++#define EREG_SER_ADDR 0x008a //Serial interface device address 0x0053 171 ++#define EREG_SER_PARM 0x008c //Serial Interface parameters 0x0000 172 ++#define EREG_OUT_CTRL 0x008e //Output control 0x0000 173 ++#define EREG_PLL_CTRL 0x0090 //PLL control 0x0024 174 ++#define EREG_PLL_DIV_L 0x0092 //PLL divisors, large values 0x1d09 175 ++#define EREG_PLL_DIV_S 0x0094 //PLL divisors, small values 0x0200 176 ++ ++/************************************************************************************* ++ * ++ * Expert Control Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define EREG_SZR_IN_WID_V 0x0100 //Sizer input width, video mode 0x0280 184 ++#define EREG_SZR_IN_HGT_V 0x0102 //Sizer input height, video mode 0x01e0 185 ++#define EREG_SZR_OUT_WID_V 0x0104 //Sizer output width, video mode 0x0140 186 ++#define EREG_SZR_OUT_HGT_V 0x0106 //Sizer output height, video mode 0x00f0 187 ++#define EREG_CPP_V 0x0108 //Clocks per pixel, video mode 0x0002 188 ++#define EREG_HBLANK_V 0x010a //Horizontal blanking period, video mode 0x0000 189 ++#define EREG_VBLANK_V 0x010c //Vertical blanking period, video mode 0x0000 190 ++#define EREG_MIN_MAX_F_V 0x010e //Frame convergence rates, video mode 0x0000 191 ++#define EREG_OUTPUT_CTRL_V 0x0110 //Output control, video mode 0x9019 192 ++#define EREG_PROC_CTRL_V 0x0112 //Processing control, video mode 0x0280 194 ++#define EREG_RPT_V 0x0114 //Row processing time, video mode 0x0546 196 ++#define EREG_HYSNC_PER_V 0x0116 //HSYNC period, video mode 0x0a8b 197 ++#define EREG_CLK_DIV_V 0x0118 //Clock divisors, video mode 0x0000 198 ++#define EREG_PARALLEL_CTRL_V 0x011a //Parallel output control, video mode 0x0003 199 ++#define EREG_SEN_CTRL_V 0x011c //Sensor control, video mode 0x0000 200 ++ ++#define EREG_SZR_IN_WID_S 0x0120 //Sizer input width, still mode 0x0280 202 ++#define EREG_SZR_IN_HGT_S 0x0122 //Sizer input height, still mode 0x01e0 203 ++#define EREG_SZR_OUT_WID_S 0x0124 //Sizer output width, still mode 0x0280 204 ++#define EREG_SZR_OUT_HGT_S 0x0126 //Sizer output height, still mode 0x01e0 205 ++#define EREG_CPP_S 0x0128 //Clocks per pixel, still mode 0x0002 206 ++#define EREG_HBLANK_S 0x012a //Horizontal blanking period, still mode 0x0000 207 ++#define EREG_VBLANK_S 0x012c //Vertical blanking period, still mode 0x0000 208 ++#define EREG_MIN_MAX_F_S 0x012e //Frame convergence rates, still mode 0x0002 209 ++#define EREG_OUTPUT_CTRL_S 0x0130 //Output control, still mode 0x8019 210 ++#define EREG_PROC_CTRL_S 0x0132 //Processing control, still mode 0x0280 212 ++#define EREG_RPT_S 0x0134 //Row processing time, still mode 0x0546 214 ++#define EREG_HYSNC_PER_S 0x0136 //HSYNC period, still mode 0x0545 215 ++#define EREG_CLK_DIV_S 0x0138 //Clock divisors, still mode 0x0000 216 ++#define EREG_PARALLEL_CTRL_S 0x013a //Parallel output control, still mode 0x0000 217 ++#define EREG_SEN_CTRL_S 0x013c //Sensor control, still mode 0x0000 218 ++ ++#define EREG_AF_CTRL1 0x0140 //Auto functions control 1 0x0013 220 ++#define EREG_AF_CTRL2 0x0142 //Auto functions control 2 0x0001 221 ++#define EREG_AF_STATUS 0x0144 //Auto functions status 0x0000 222 ++#define EREG_SOF_CODES 0x0146 //Start of frame codes 0xfeff 223 ++#define EREG_EOF_CODES 0x0148 //End of frame codes 0x0100 224 ++#define EREG_ABL_TARGET 0x014a //Auto black level target 0x0005 225 ++#define EREG_ABL_MAX_BIN 0x014c //Auto black level maximum bin 0x0003 226 ++#define EREG_ABL_MAX_BLACK 0x014e //Auto black level maximum black 0x0010 227 ++#define EREG_AE_GAIN_MIN 0x0150 //Auto exposure gain minimum 0x01c0 228 ++#define EREG_AE_GAIN_MIN_P 0x0152 //Auto exposure gain minimum, preferred 0x0200 229 ++#define EREG_AE_GAIN_MAX 0x0154 //Auto exposure gain maximum 0x0500 230 ++#define EREG_AE_GAIN_DFLT 0x0156 //Auto exposure gain default 0x0200 231 ++#define EREG_AE_ETIME_MIN 0x0158 //Auto exposure time minimum 0x0005 232 ++#define EREG_AE_ETIME_MAX 0x015a //Auto exposure time maximum 0x4e20 233 ++#define EREG_AE_ETIME_DFLT 0x015c //Auto exposure time default 0x03e8 234 ++#define EREG_AE_TARGET 0x015e //Auto exposure target 0x0040 235 ++#define EREG_AE_TOL_ACQ 0x0160 //Auto exposure tolerance acquire 0x0118 236 ++#define EREG_AE_TOL_MON 0x0162 //Auto exposure tolerance monitor 0x0118 237 ++#define EREG_AE_MARGIN 0x0164 //Auto exposure margin 0x0120 238 ++#define EREG_AE_DOE_FACTOR 0x0166 //AE deliberate overexposure factor 0x014e 239 ++#define EREG_AE_DOE_MARGIN 0x0168 //AE deliberate overexposure margin 0x0140 240 ++ ++#define EREG_AWB_RED_MIN 0x0170 //AWB minimum red/green ratio 0x00c0 242 ++#define EREG_AWB_RED_MAX 0x0172 //AWB maximum red/green ratio 0x01a6 243 ++#define EREG_AWB_RED_DFLT 0x0174 //AWB default red/green ratio 0x0134 244 ++#define EREG_AWB_BLUE_MIN 0x0176 //AWB minimum blue/green ratio 0x00c0 245 ++#define EREG_AWB_BLUE_MAX 0x0178 //AWB maximum blue/green ratio 0x02a4 246 ++#define EREG_AWB_BLUE_DFLT 0x017a //AWB default blue/green ratio 0x01e4 247 ++#define EREG_AWB_TOL_ACQ 0x017c //Auto white balance tolerance acquire 0x0110 248 ++#define EREG_AWB_TOL_MON 0x017e //Auto white balance tolerance monitor 0x0120 249 ++#define EREG_FIRMWARE_REV 0x0180 //Current firmware revision 0x0152 250 ++#define EREG_FLICK_CFG_1 0x0182 //Flicker configuration 1 0x2aeb 251 ++#define EREG_FLICK_CFG_2 0x0184 //Flicker configuration 2 0x0005 252 ++ ++#define EREG_MAX_SCLK 0x018a //Maximum sensor clock 0x1964 254 ++ ++#define EREG_CSC_00_V 0x0190 //Color conversion coefficient 00, video 0x0026 256 ++#define EREG_CSC_01_V 0x0192 //Color conversion coefficient 01, video 0x004b 256 ++#define EREG_CSC_02_V 0x0194 //Color conversion coefficient 02, video 0x000f 256 ++#define EREG_CSC_10_V 0x0196 //Color conversion coefficient 10, video 0x01ed 256 ++#define EREG_CSC_11_V 0x0198 //Color conversion coefficient 11, video 0x01db 256 ++#define EREG_CSC_12_V 0x019a //Color conversion coefficient 12, video 0x0038 256 ++#define EREG_CSC_20_V 0x019c //Color conversion coefficient 20, video 0x004f 256 ++#define EREG_CSC_21_V 0x019e //Color conversion coefficient 21, video 0x01be 256 ++#define EREG_CSC_22_V 0x01a0 //Color conversion coefficient 22, video 0x01f3 256 ++ ++#define EREG_CSC_OS0_V 0x01a2 //Color space conversion offset 0, video 0x0000 257 ++#define EREG_CSC_OS1_V 0x01a4 //Color space conversion offset 1, video 0x0080 257 ++#define EREG_CSC_OS2_V 0x01a6 //Color space conversion offset 2, video 0x0080 257 ++ ++#define EREG_CSC_00_S 0x01a8 //Color conversion coefficient 00, still 0x0026 258 ++#define EREG_CSC_01_S 0x01aa //Color conversion coefficient 01, still 0x004b 258 ++#define EREG_CSC_02_S 0x01ac //Color conversion coefficient 02, still 0x000f 258 ++#define EREG_CSC_10_S 0x01ae //Color conversion coefficient 10, still 0x01ed 258 ++#define EREG_CSC_11_S 0x01b0 //Color conversion coefficient 11, still 0x01db 258 ++#define EREG_CSC_12_S 0x01b2 //Color conversion coefficient 12, still 0x0038 258 ++#define EREG_CSC_20_S 0x01b4 //Color conversion coefficient 20, still 0x004f 258 ++#define EREG_CSC_21_S 0x01b6 //Color conversion coefficient 21, still 0x01be 258 ++#define EREG_CSC_22_S 0x01b8 //Color conversion coefficient 22, still 0x01f3 258 ++ ++#define EREG_CSC_OS0_S 0x01ba //Color space conversion offset 0, still 0x0000 259 ++#define EREG_CSC_OS1_S 0x01bc //Color space conversion offset 1, still 0x0080 259 ++#define EREG_CSC_OS2_S 0x01be //Color space conversion offset 2, still 0x0080 259 ++ ++ ++#define EREG_TM_COEF_00_V 0x01c0 //Tonemap coefficient 00, video 0x0000 261 ++#define EREG_TM_COEF_01_V 0x01c2 //Tonemap coefficient 01, video 0x0017 261 ++#define EREG_TM_COEF_02_V 0x01c4 //Tonemap coefficient 02, video 0x0032 261 ++#define EREG_TM_COEF_03_V 0x01c6 //Tonemap coefficient 03, video 0x0046 261 ++#define EREG_TM_COEF_04_V 0x01c8 //Tonemap coefficient 04, video 0x0056 261 ++#define EREG_TM_COEF_05_V 0x01ca //Tonemap coefficient 05, video 0x0064 261 ++#define EREG_TM_COEF_06_V 0x01cc //Tonemap coefficient 06, video 0x0071 261 ++#define EREG_TM_COEF_07_V 0x01ce //Tonemap coefficient 07, video 0x007c 261 ++#define EREG_TM_COEF_08_V 0x01d0 //Tonemap coefficient 08, video 0x0086 261 ++#define EREG_TM_COEF_09_V 0x01d2 //Tonemap coefficient 09, video 0x0099 261 ++#define EREG_TM_COEF_10_V 0x01d4 //Tonemap coefficient 10, video 0x00a9 261 ++#define EREG_TM_COEF_11_V 0x01d6 //Tonemap coefficient 11, video 0x00b8 261 ++#define EREG_TM_COEF_12_V 0x01d8 //Tonemap coefficient 12, video 0x00c6 261 ++#define EREG_TM_COEF_13_V 0x01da //Tonemap coefficient 13, video 0x00df 261 ++#define EREG_TM_COEF_14_V 0x01dc //Tonemap coefficient 14, video 0x00f5 261 ++#define EREG_TM_COEF_15_V 0x01de //Tonemap coefficient 15, video 0x0109 261 ++#define EREG_TM_COEF_16_V 0x01e0 //Tonemap coefficient 16, video 0x011b 261 ++#define EREG_TM_COEF_17_V 0x01e2 //Tonemap coefficient 17, video 0x013d 261 ++#define EREG_TM_COEF_18_V 0x01e4 //Tonemap coefficient 18, video 0x015a 261 ++#define EREG_TM_COEF_19_V 0x01e6 //Tonemap coefficient 19, video 0x0175 261 ++#define EREG_TM_COEF_20_V 0x01e8 //Tonemap coefficient 20, video 0x018d 261 ++#define EREG_TM_COEF_21_V 0x01ea //Tonemap coefficient 21, video 0x01ba 261 ++#define EREG_TM_COEF_22_V 0x01ec //Tonemap coefficient 22, video 0x01e1 261 ++#define EREG_TM_COEF_23_V 0x01ee //Tonemap coefficient 23, video 0x0205 261 ++#define EREG_TM_COEF_24_V 0x01f0 //Tonemap coefficient 24, video 0x0225 261 ++#define EREG_TM_COEF_25_V 0x01f2 //Tonemap coefficient 25, video 0x0261 261 ++#define EREG_TM_COEF_26_V 0x01f4 //Tonemap coefficient 26, video 0x0295 261 ++#define EREG_TM_COEF_27_V 0x01f6 //Tonemap coefficient 27, video 0x02c5 261 ++#define EREG_TM_COEF_28_V 0x01f8 //Tonemap coefficient 28, video 0x02f1 261 ++#define EREG_TM_COEF_29_V 0x01fa //Tonemap coefficient 29, video 0x033f 261 ++#define EREG_TM_COEF_30_V 0x01fc //Tonemap coefficient 30, video 0x0385 261 ++#define EREG_TM_COEF_31_V 0x01fe //Tonemap coefficient 31, video 0x03c5 261 ++#define EREG_TM_COEF_32_V 0x0200 //Tonemap coefficient 32, video 0x0400 261 ++ ++#define EREG_TM_COEF_00_S 0x0202 //Tonemap coefficient 00, still 0x0000 262 ++#define EREG_TM_COEF_01_S 0x0204 //Tonemap coefficient 01, still 0x0017 262 ++#define EREG_TM_COEF_02_S 0x0206 //Tonemap coefficient 02, still 0x0032 262 ++#define EREG_TM_COEF_03_S 0x0208 //Tonemap coefficient 03, still 0x0046 262 ++#define EREG_TM_COEF_04_S 0x020a //Tonemap coefficient 04, still 0x0056 262 ++#define EREG_TM_COEF_05_S 0x020c //Tonemap coefficient 05, still 0x0064 262 ++#define EREG_TM_COEF_06_S 0x020e //Tonemap coefficient 06, still 0x0071 262 ++#define EREG_TM_COEF_07_S 0x0210 //Tonemap coefficient 07, still 0x007c 262 ++#define EREG_TM_COEF_08_S 0x0212 //Tonemap coefficient 08, still 0x0086 262 ++#define EREG_TM_COEF_09_S 0x0214 //Tonemap coefficient 09, still 0x0099 262 ++#define EREG_TM_COEF_10_S 0x0216 //Tonemap coefficient 10, still 0x00a9 262 ++#define EREG_TM_COEF_11_S 0x0218 //Tonemap coefficient 11, still 0x00b8 262 ++#define EREG_TM_COEF_12_S 0x021a //Tonemap coefficient 12, still 0x00c6 262 ++#define EREG_TM_COEF_13_S 0x021c //Tonemap coefficient 13, still 0x00df 262 ++#define EREG_TM_COEF_14_S 0x021e //Tonemap coefficient 14, still 0x00f5 262 ++#define EREG_TM_COEF_15_S 0x0220 //Tonemap coefficient 15, still 0x0109 262 ++#define EREG_TM_COEF_16_S 0x0222 //Tonemap coefficient 16, still 0x011b 262 ++#define EREG_TM_COEF_17_S 0x0224 //Tonemap coefficient 17, still 0x013d 262 ++#define EREG_TM_COEF_18_S 0x0226 //Tonemap coefficient 18, still 0x015a 262 ++#define EREG_TM_COEF_19_S 0x0228 //Tonemap coefficient 19, still 0x0175 262 ++#define EREG_TM_COEF_20_S 0x022a //Tonemap coefficient 20, still 0x018d 262 ++#define EREG_TM_COEF_21_S 0x022c //Tonemap coefficient 21, still 0x01ba 262 ++#define EREG_TM_COEF_22_S 0x022e //Tonemap coefficient 22, still 0x01e1 262 ++#define EREG_TM_COEF_23_S 0x0230 //Tonemap coefficient 23, still 0x0205 262 ++#define EREG_TM_COEF_24_S 0x0232 //Tonemap coefficient 24, still 0x0225 262 ++#define EREG_TM_COEF_25_S 0x0234 //Tonemap coefficient 25, still 0x0261 262 ++#define EREG_TM_COEF_26_S 0x0236 //Tonemap coefficient 26, still 0x0295 262 ++#define EREG_TM_COEF_27_S 0x0238 //Tonemap coefficient 27, still 0x02c5 262 ++#define EREG_TM_COEF_28_S 0x023a //Tonemap coefficient 28, still 0x02f1 262 ++#define EREG_TM_COEF_29_S 0x023c //Tonemap coefficient 29, still 0x033f 262 ++#define EREG_TM_COEF_30_S 0x023e //Tonemap coefficient 30, still 0x0385 262 ++#define EREG_TM_COEF_31_S 0x0240 //Tonemap coefficient 31, still 0x03c5 262 ++#define EREG_TM_COEF_32_S 0x0242 //Tonemap coefficient 32, still 0x0400 262 ++ ++#define EREG_NACC_EGP_1 0x0250 //NACC EGP 1 0x05dc 265 ++#define EREG_NACC_SAT_1 0x0252 //NACC saturation 1 0x0000 265 ++#define EREG_NACC_EGP_2 0x0254 //NACC EGP 2 0x0465 265 ++#define EREG_NACC_SAT_2 0x0256 //NACC saturation 2 0x0040 265 ++#define EREG_NACC_EGP_3 0x0258 //NACC EGP 3 0x02ee 265 ++#define EREG_NACC_SAT_3 0x025a //NACC saturation 3 0x0080 265 ++#define EREG_NACC_EGP_4 0x025c //NACC EGP 4 0x0177 265 ++#define EREG_NACC_SAT_4 0x025e //NACC saturation 4 0x00c0 265 ++#define EREG_NACC_EGP_5 0x0260 //NACC EGP 5 0x0000 265 ++#define EREG_NACC_SAT_5 0x0262 //NACC saturation 5 0x0100 265 ++#define EREG_NACC_EGP_6 0x0264 //NACC EGP 6 0x0000 265 ++#define EREG_NACC_SAT_6 0x0266 //NACC saturation 6 0x0000 265 ++#define EREG_NACC_EGP_7 0x0268 //NACC EGP 7 0x0000 265 ++#define EREG_NACC_SAT_7 0x026a //NACC saturation 7 0x0000 265 ++#define EREG_NACC_EGP_8 0x026c //NACC EGP 8 0x0000 265 ++#define EREG_NACC_SAT_8 0x026e //NACC saturation 8 0x0000 265 ++#define EREG_NACC_BC_00 0x0270 //NACC NACC bright coefficients 00 0x0235 266 ++#define EREG_NACC_BC_01 0x0272 //NACC NACC bright coefficients 01 0xff46 266 ++#define EREG_NACC_BC_02 0x0274 //NACC bright coefficients 02 0xff85 266 ++#define EREG_NACC_BC_10 0x0276 //NACC bright coefficients 10 0xff64 266 ++#define EREG_NACC_BC_11 0x0278 //NACC bright coefficients 11 0x01fc 266 ++#define EREG_NACC_BC_12 0x027a //NACC bright coefficients 12 0xff9f 266 ++#define EREG_NACC_BC_20 0x027c //NACC bright coefficients 20 0x0008 266 ++#define EREG_NACC_BC_21 0x027e //NACC bright coefficients 21 0xfe8d 266 ++#define EREG_NACC_BC_22 0x0280 //NACC bright coefficients 22 0x026b 266 ++#define EREG_NACC_DC_00 0x0282 //NACC dark coefficients 00 0x0048 266 ++#define EREG_NACC_DC_01 0x0284 //NACC dark coefficients 01 0x010b 266 ++#define EREG_NACC_DC_02 0x0286 //NACC dark coefficients 02 0xffaa 266 ++#define EREG_NACC_DC_10 0x0288 //NACC dark coefficients 10 0x0048 266 ++#define EREG_NACC_DC_11 0x028a //NACC dark coefficients 11 0x010b 266 ++#define EREG_NACC_DC_12 0x028c //NACC dark coefficients 12 0xffaa 266 ++#define EREG_NACC_DC_20 0x028e //NACC dark coefficients 20 0x0048 266 ++#define EREG_NACC_DC_21 0x0290 //NACC dark coefficients 21 0x010b 266 ++#define EREG_NACC_DC_22 0x0292 //NACC dark coefficients 22 0xffaa 266 ++ ++/************************************************************************************* ++ * ++ * Expert Sensor Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define EREG_IDENT 0x0800 //Image sensor identification 0x60 272 ++#define EREG_IS_STATUS 0x0801 //Image sensor status 0x00 273 ++#define EREG_ICTRL 0x0805 //Interface control 0x00 275 ++ ++#define EREG_ADC_CTRL 0x0809 //ADC control 0x01 277 ++#define EREG_FWROW 0x080a //Window first row address 0x01 278 ++#define EREG_FWCOL 0x080b //Window first column address 0x01 279 ++#define EREG_LWROW 0x080c //Window last row address 0x7a 280 ++#define EREG_LWCOL 0x080d //Window last column address 0xa2 281 ++#define EREG_CLK_PIXEL 0x080e //Clocks per pixel 0x02 282 ++#define EREG_EREC_PGA 0x080f //Even row, even column(green 1)PGA gain 0x00 283 ++#define EREG_EROC_PGA 0x0810 //Even row, odd column (red) PGA gain 0x00 284 ++#define EREG_OREC_PGA 0x0811 //Odd row, even column (blue) PGA gain 0x00 285 ++#define EREG_OROC_PGA 0x0812 //Odd row, odd column (green 2) PGA gain 0x00 286 ++#define EREG_ROWEXP_L 0x0813 //Row exposure low 0x54 287 ++#define EREG_ROWEXP_H 0x0814 //Row exposure high 0x00 288 ++#define EREG_SROWEXP 0x0815 //Sub row exposure 0x31 289 ++#define EREG_ERROR 0x0816 //Error control 0x00 290 ++ ++#define EREG_HBLANK 0x0819 //Horizontal blank 0x00 292 ++#define EREG_VBLANK 0x081a //Vertical blank 0x00 293 ++#define EREG_CONFIG_1 0x081b //Image sensor configuration 1 0x0e 294 ++#define EREG_CONTROL_1 0x081c //Image sensor control 1 0x24 295 ++ ++#define EREG_CONFIG_2 0x0827 //Image sensor configuration 2 0x00 298 ++#define EREG_GRR_CTRL 0x0828 //Ground reset reference control 0x00 299 ++ ++#define EREG_BIAS_TRM 0x0837 //Bias trim 0x00 301 ++#define EREG_SMP_GR_E2 0x08d7 //Sample ground reference edge 2 0x00 303 ++#define EREG_SMP_GR_E1 0x08d8 //Sample ground reference edge 1 0x10 304 ++#define EREG_SMP_GR_E0 0x08d9 //Sample ground reference edge 0 0x0a 305 ++ ++#define EREG_EXP_GR_E1 0x08dc //Exposure, ground reference edge 1 0x10 307 ++#define EREG_EXP_GR_E0 0x08dd //Exposure, ground reference edge 0 0x06 308 ++#define EREG_GR_POL 0x08df //Ground reference polarity 0xd3 310 ++ ++#define EREG_SMP_RST_E2 0x08eb //Sample, reset edge 2 0x04 312 ++#define EREG_SMP_RST_E1 0x08ec //Sample, reset edge 1 0x10 313 ++#define EREG_SMP_RST_E0 0x08ed //Sample, reset edge 0 0x07 314 ++ ++#define EREG_EXP_RST_E1 0x08f0 //Exposure, reset edge 1 0x10 316 ++#define EREG_EXP_RST_E0 0x08f1 //Exposure, reset edge 1 0x03 317 ++#define EREG_RESET_POL 0x08f3 //Reset polarity enable 0xd3 319 ++ ++#define EREG_SMP_PRST_E2 0x08f5 //Sample, preset edge 2 0x00 321 ++#define EREG_SMP_PRST_E1 0x08f6 //Sample, preset edge 1 0x02 322 ++#define EREG_SMP_PRST_E0 0x08f7 //Sample, preset edge 0 0x0a 323 ++ ++#define EREG_EXP_PRST_E1 0x08fa //Exposure, preset edge 1 0x02 325 ++#define EREG_EXP_PRST_E0 0x08fb //Exposure, preset edge 1 0x06 326 ++#define EREG_PRESET_POL 0x08fd //Preset polarity enable 0xd3 328 ++ ++/************************************************************************************* ++ * ++ * Expert Image Pipeline Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++ ++#define EREG_CMD_1 0x1002 //Main command 1 0x0000 335 ++#define EREG_CMD_2 0x1004 //Main command 2 (write 1¡¯s only) 0x0002 336 ++#define EREG_OUTPUT_CTRL 0x1008 //Output control, working 0x9019 338 ++#define EREG_PARALLEL_CTRL 0x100a //Parallel output control working copy 0x0000 340 ++#define EREG_SOF_CODE_W 0x100c //Start of frame code working copy 0x00ff 341 ++#define EREG_PEOF_CODES 0x100e //End of frame codes working copy 0x0100 342 ++#define EREG_CCIR_TIMING 0x1010 //CCIR interface timing 0x0000 343 ++#define EREG_R_Y_MAX_MIN 0x1012 //Luminance, Y (or red) maximum/minimum 0xff00 344 ++#define EREG_G_CB_MAX_MIN 0x1014 //Chrominance,Cb(or green)maximum/minimum 0xff00 345 ++#define EREG_B_CR_MAX_MIN 0x1016 //Chrominance,Cr(or blue)maximum/minimum 0xff00 346 ++#define EREG_PROCESS_CTRL 0x1018 //Processing control working copy 0x0280 347 ++#define EREG_BPA_SF_GTHRESH 0x101a //BPA scale factor,green filter threshold 0x0220 349 ++#define EREG_BPA_OUTL_PED 0x101c //BPA outlier, pedestal 0x4008 350 ++#define EREG_BPA_BADPIX_CNT 0x101e //BPA bad pixel count (read only) 0x0000 351 ++#define EREG_SZR_IN_W 0x1020 //Sizer input width 0x0280 352 ++#define EREG_SZR_IN_H 0x1022 //Sizer input height 0x01e0 353 ++#define EREG_SZR_OUT_W 0x1024 //Sizer output width 0x0140 354 ++#define EREG_SZR_OUT_H 0x1026 //Sizer output height 0x00f0 355 ++ ++ ++#define EREG_CC_COEF_00 0x1028 //Color correction coefficient 00 0x02f9 358 ++#define EREG_CC_COEF_01 0x102a //Color correction coefficient 01 0x0f03 358 ++#define EREG_CC_COEF_02 0x102c //Color correction coefficient 02 0x0f02 358 ++#define EREG_CC_COEF_10 0x102e //Color correction coefficient 10 0x0f4f 358 ++#define EREG_CC_COEF_11 0x1030 //Color correction coefficient 11 0x025c 358 ++#define EREG_CC_COEF_12 0x1032 //Color correction coefficient 12 0x0f54 358 ++#define EREG_CC_COEF_20 0x1034 //Color correction coefficient 20 0x0fe0 358 ++#define EREG_CC_COEF_21 0x1036 //Color correction coefficient 21 0x0e4a 358 ++#define EREG_CC_COEF_22 0x1038 //Color correction coefficient 22 0x02d5 358 ++ ++#define EREG_CC_PRE_OS_0 0x103a //Color correction pre-offset 0 0x01f8 360 ++#define EREG_CC_PRE_OS_1 0x103c //Color correction pre-offset 1 0x01f8 360 ++#define EREG_CC_PRE_OS_2 0x103e //Color correction pre-offset 2 0x01f8 360 ++#define EREG_CC_POST_OS_0 0x1040 //Color correction post-offset 0 0x0000 360 ++#define EREG_CC_POST_OS_1 0x1042 //Color correction post-offset 1 0x0000 360 ++#define EREG_CC_POST_OS_2 0x1044 //Color correction post-offset 2 0x0000 360 ++ ++#define EREG_CSC_COEF_00 0x1046 //Color space conversion coefficient 00 0x0026 363 ++#define EREG_CSC_COEF_01 0x1048 //Color space conversion coefficient 01 0x004b 363 ++#define EREG_CSC_COEF_02 0x104a //Color space conversion coefficient 02 0x000f 363 ++#define EREG_CSC_COEF_10 0x104c //Color space conversion coefficient 10 0x01ed 363 ++#define EREG_CSC_COEF_11 0x104e //Color space conversion coefficient 11 0x01db 363 ++#define EREG_CSC_COEF_12 0x1050 //Color space conversion coefficient 12 0x0038 363 ++#define EREG_CSC_COEF_20 0x1052 //Color space conversion coefficient 20 0x004f 363 ++#define EREG_CSC_COEF_21 0x1054 //Color space conversion coefficient 21 0x01be 363 ++#define EREG_CSC_COEF_22 0x1056 //Color space conversion coefficient 22 0x01f3 363 ++#define EREG_CSC_OS_0 0x1058 //Color space conversion offset 0 0x0000 364 ++#define EREG_CSC_OS_1 0x105a //Color space conversion offset 1 0x0080 364 ++#define EREG_CSC_OS_2 0x105c //Color space conversion offset 2 0x0080 364 ++#define EREG_DATA_GEN 0x105e //Test data generator 0x0000 365 ++#define EREG_HSYNC_PER 0x1060 //Horizontal synchronization period 0x0a8b 366 ++#define EREG_APS_COEF_GRN1 0x1062 //Green 1 AWB gain 0x0080 368 ++#define EREG_APS_COEF_RED 0x1064 //Red AWB gain 0x0080 368 ++ ++ ++#define EREG_APS_COEF_BLUE 0x1066 //Blue AWB gain 0x0080 368 ++#define EREG_APS_COEF_GRN2 0x1068 //Green 2 AWB gain 0x0080 368 ++#define EREG_AV_LEFT_TOP 0x106a //Anti-v,sensor first row and column 0x0101 369 ++#define EREG_AV_RIGHT_BOT 0x106c //Anti-v, sensor last row and column 0xa27a 370 ++#define EREG_AV_CENTER_COL 0x106e //Anti-v, sensor center column 0x0148 371 ++#define EREG_AV_CENTER_ROW 0x1070 //Anti-v, sensor center row 0x00f8 372 ++#define EREG_STAT_CAP_CTRL 0x1072 //Image statistics capture control 0x0021 373 ++#define EREG_STAT_MODE_CTRL 0x1074 //Image statistics mode control 0x0000 374 ++#define EREG_GREEN_1_SUM 0x1076 //Green 1 pixel sum 0x0000 375 ++#define EREG_RED_SUM 0x1078 //Red pixel sum 0x0000 375 ++#define EREG_BLUE_SUM 0x107a //Blue pixel sum 0x0000 375 ++#define EREG_GREEN_2_SUM 0x107c //Green 2 pixel sum 0x0000 375 ++#define EREG_I_WIDTH 0x107e //Current image width 0x0000 376 ++#define EREG_I_HEIGHT 0x1080 //Current image height 0x0000 377 ++#define EREG_STATUS_FLAGS 0x1082 //Status flags (read only) 0x0000 378 ++#define EREG_CLK_GATE_DIS 0x1084 //Clock gate disable 0x0000 379 ++#define EREG_CCIR_TIMING2 0x1086 //CCIR interface timing 2 0x0000 381 ++#define EREG_CCIR_TIMING3 0x1088 //CCIR interface timing 3 0x0010 382 ++#define EREG_G1G2_DIAG_THRESH 0x108a //Green 1/green 2 diagonal threshold 0x0040 383 ++#define EREG_BPA_D2_THRESH 0x108c //BPA second derivative threshold 0x0100 384 ++#define EREG_SERIAL_CTRL 0x108e //Serial control 0x0000 385 ++#define EREG_INTP_CTRL_1 0x1090 //Interpolation control 1(demosaic) 0x0188 387 ++#define EREG_INTP_CTRL_2 0x1092 //Interpolation control 2(demosaic) 0x00c8 388 ++#define EREG_AV_OVAL_FACT 0x1094 //Anti-vignetting oval factor 0x0100 389 ++#define EREG_AV_OS_GREEN1 0x1096 //Anti-vignetting green 1 offset 0x0000 391 ++#define EREG_AV_OS_RED 0x1098 //Anti-vignetting red offset 0x0000 391 ++#define EREG_AV_OS_BLUE 0x109a //Anti-vignetting blue offset 0x0000 391 ++#define EREG_AV_OS_GREEN2 0x109c //Anti-vignetting green 2 offset 0x0000 391 ++ ++ ++ ++/*********************************************************************** ++ * ++ * Function Prototype ++ * ++ ***********************************************************************/ ++ ++u16 adcm2700_reg_read(u16 reg_addr); ++void adcm2700_reg_write(u16 reg_addr, u16 reg_value); ++ ++ ++// Configuration Procedures ++int adcm2700_power_on(u8); ++int adcm2700_power_off(void ); ++int adcm2700_change_viewfinder_mode(adcm_window_size * input_win, adcm_window_size *vf_output_win, adcm_window_size *sf_output_win ); ++int adcm2700_firmware_upgrade( void ); ++int adcm2700_version_revision(u16 * cm_revision, u16 *sensor_revision); ++int adcm2700_viewfinder_on( void ); ++int adcm2700_viewfinder_off( void ); ++int adcm2700_master_clock(u8 clk); ++int adcm2700_viewfinder_input_size(adcm_window_size * win ); ++int adcm2700_stillframe_input_size(adcm_window_size * win ); ++int adcm2700_viewfinder_output_size(adcm_window_size * win); ++int adcm2700_stillframe_output_size(adcm_window_size * win); ++int adcm2700_stillframe_cfg_output(u16 format); ++int adcm2700_viewfinder_cfg_output(u16 format); ++int adcm2700_gamma_correction(void); ++int adcm2700_get_output_frame_rate(u16 * fps); ++int adcm2700_detect_camera_mode(u16 *mode); ++ ++int adcm2700_set_fps(u16 fps, u16 minfps); ++ ++int adcm2700_input_size(adcm_window_size * win); ++int adcm2700_output_size(adcm_window_size * win); ++int adcm2700_get_input_size(adcm_window_size * win); ++/*set picture style(normal/black white/sepia/solarize/neg.art)*/ ++int adcm2700_set_style(V4l_PIC_STYLE style); ++/*set picture light(direct sun/incandescent/fluorescent)*/ ++int adcm2700_set_light(V4l_PIC_WB light); ++/*set picture brightness*/ ++int adcm2700_set_bright(int bright); ++ ++int adcm2700_restore_property(p_camera_context_t cam_ctx, int frames); ++ ++#endif /* _PXA_ADCM_2700_HW_H__ */ ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm3800.c linux-2.6.16/drivers/media/video/adcm3800.c +--- linux-2.6.16.orig/drivers/media/video/adcm3800.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm3800.c 2006-06-03 11:14:56.428310848 +0200 +@@ -0,0 +1,619 @@ ++ ++/*================================================================================ ++ ++ Header Name: adcm3800.c ++ ++General Description: Camera module adcm3800 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++ Update algorithm for DMA transfer ++ Update strategy for memory management ++ Fix still picture capture failed sometime ++ New Agilent sensor chip ID support ++ Make output height in an even multiple of 8 ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/irq.h> ++#include <asm/hardware.h> ++ ++#include <asm/arch/pxa-regs.h> ++ ++#include "camera.h" ++#include "adcm3800.h" ++#include "adcm3800_hw.h" ++ ++ ++/*********************************************************************** ++ * ++ * ADCM3800 common functions ++ * ++ ***********************************************************************/ ++#define MAX_WIDTH 1280 ++#define MAX_HEIGHT 1024 ++#define MIN_WIDTH 64 ++#define MIN_HEIGHT 56 ++#define WIDTH_DEFT 320 ++#define HEIGHT_DEFT 240 ++#define S_WIDTH_DEFT 1280 ++#define S_HEIGHT_DEFT 960 ++#define FRAMERATE_DEFT 15 ++#define MCLK_DEFT 48 /* Default Master clock*/ ++#define BUF_SIZE_DEFT ((PAGE_ALIGN(MAX_WIDTH * MAX_HEIGHT) + (PAGE_ALIGN(MAX_WIDTH*MAX_HEIGHT/2)*2))) ++ ++extern int i2c_adcm3800_init(void); ++extern int i2c_adcm3800_cleanup(void); ++ ++////////////////////////////////////////////////////////////////////////////////////// ++//adcm3800 functions ++// ++static int camera_func_adcm3800_init(p_camera_context_t); ++static int camera_func_adcm3800_deinit(p_camera_context_t); ++static int camera_func_adcm3800_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++static int camera_func_adcm3800_set_capture_format(p_camera_context_t); ++static int camera_func_adcm3800_start_capture(p_camera_context_t, unsigned int frames); ++static int camera_func_adcm3800_stop_capture(p_camera_context_t); ++ ++static int camera_func_adcm3800_pm_management(p_camera_context_t, int); ++ ++static int adcm3800_sensor_init(p_camera_context_t cam_ctx); ++ ++ ++camera_function_t camera_adcm3800_func = ++{ ++ init: camera_func_adcm3800_init, ++ deinit: camera_func_adcm3800_deinit, ++ command: camera_func_adcm3800_docommand, ++ set_capture_format: camera_func_adcm3800_set_capture_format, ++ start_capture: camera_func_adcm3800_start_capture, ++ stop_capture: camera_func_adcm3800_stop_capture, ++ pm_management: camera_func_adcm3800_pm_management ++}; ++ ++static int camera_func_adcm3800_init(p_camera_context_t cam_ctx) ++{ ++ int ret = 0; ++ // init context status ++ cam_ctx->dma_channels[0] = 0xFF; ++ cam_ctx->dma_channels[1] = 0xFF; ++ cam_ctx->dma_channels[2] = 0xFF; ++ ++ cam_ctx->capture_width = WIDTH_DEFT; ++ cam_ctx->capture_height = HEIGHT_DEFT; ++ cam_ctx->sensor_width = S_WIDTH_DEFT; ++ cam_ctx->sensor_height = S_HEIGHT_DEFT; ++ ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ ++ cam_ctx->frame_rate = cam_ctx->fps = FRAMERATE_DEFT; ++ ++ cam_ctx->mini_fps = FRAMERATE_DEFT-5; ++ ++ cam_ctx->mclk = MCLK_DEFT; ++ cam_ctx->flicker_freq = 50; ++ ++ cam_ctx->buf_size = BUF_SIZE_DEFT; ++ cam_ctx->dma_descriptors_size = (cam_ctx->buf_size/PAGE_SIZE + 10); ++ cam_ctx->vc.maxwidth = MAX_WIDTH; ++ cam_ctx->vc.maxheight = MAX_HEIGHT; ++ cam_ctx->vc.minwidth = MIN_WIDTH; ++ cam_ctx->vc.minheight = MIN_HEIGHT; ++ ++ camera_gpio_init(); ++ ci_init(); ++ ++ // Configure CI according to hardware ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ ++ // enable pixel clock(sensor will provide pclock) ++ ci_set_clock(cam_ctx->clk_reg_base, 1, 1, cam_ctx->mclk); ++ ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(0, 0, 0); ++ ++ // fifo control ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); // quality ++ ++ // Turn on M_CLK using xx MHz and wait for 150 ms. ++ ci_enable(1); ++ ++ mdelay(10); // TODO: reduce it ++ ++ if(i2c_adcm3800_init() == 0) ++ { ++ cam_ctx->sensor_type = CAMERA_TYPE_ADCM3800; ++ ++ //mdelay(100); ++ ++ if((ret = adcm3800_sensor_init(cam_ctx)) < 0) ++ { ++ dbg_print("adcm3800 hardware init error!"); ++ return -1; ++ } ++ ddbg_print("Agilent ADCM3800 camera module detected!"); ++ } ++ else ++ return -1; ++ ++ return 0; ++} ++ ++/*********************************************************************** ++ * ++ * ADCM3800 Functions ++ * ++ ***********************************************************************/ ++static int adcm3800_sensor_init( p_camera_context_t camera_context ) ++{ ++ //u32 adcm_mclk = camera_context->mclk * 195000 / 192; // SYS_CLK is 195Mhz ++ u32 adcm_mclk = camera_context->mclk * 1000; ++ adcm3800_power_on(adcm_mclk); ++ return 0; ++} ++ ++static int camera_func_adcm3800_deinit( p_camera_context_t camera_context ) ++{ ++ dbg_print("adcm3800 off!"); ++ ++ /* power off the external module */ ++ camera_func_adcm3800_stop_capture(camera_context); ++ ++ adcm3800_power_off(); ++ i2c_adcm3800_cleanup(); ++ ++ /* disable CI */ ++ ci_disable(1); ++ ++ camera_gpio_deinit(); ++ return 0; ++} ++ ++static int camera_func_adcm3800_set_capture_format(p_camera_context_t camera_context) ++{ ++ u16 adcm_format; ++ window_size size; ++ ++ //set sensor format ++ switch(camera_context->capture_input_format) ++ { ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ adcm_format = O_FORMAT_422_B_YCbYCr; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ adcm_format = O_FORMAT_565_RGB; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB888_PACKED: ++ case CAMERA_IMAGE_FORMAT_RGB888_PLANAR: ++ adcm_format = O_FORMAT_888RGB; ++ break; ++ default: ++ adcm_format = O_FORMAT_422_B_YCbYCr; ++ break; ++ } ++ adcm3800_set_output_format(adcm_format); ++ ++ size.width = camera_context->capture_width; ++ size.height = camera_context->capture_height; ++ adcm3800_set_output_size(size.width, size.height); ++ ++ return 0; ++} ++ ++static int camera_func_adcm3800_start_capture(p_camera_context_t cam_ctx, unsigned int frames) ++{ ++ int ret; ++ int cisr; ++ int wait_count; ++ static int error_times = 0; ++ unsigned int start_time; ++ ++ // frames=0 means video mode capture ++ if(frames == 0) ++ { ++ // ddbg_print("video capture!"); ++ wait_count = 1; ++ } ++ else ++ { ++ // ddbg_print("still capture"); ++ wait_count = 1; ++ } ++ ret = adcm3800_reconfigure(cam_ctx, frames); ++ if(ret<0) ++ return ret; ++ adcm3800_viewfinder_on(); ++ ++ ci_disable(1); ++ ci_enable(1); ++ ++ dbg_print("wait for SOF %d time", wait_count); ++ start_time = 0xFFFFF * 20 * wait_count; ++ ++ CISR |= CI_CISR_SOF; ++ CISR |= CI_CISR_EOF; ++ cisr=CISR; ++ while(wait_count) ++ { ++ if(cisr & CI_CISR_EOF) ++ { ++ dbg_print("get EOF %d:%d", wait_count, start_time); ++ CISR |= CI_CISR_EOF; ++ } ++ if(cisr & CI_CISR_SOF) ++ { ++ dbg_print("get SOF %d:%d", wait_count, start_time); ++ wait_count -- ; ++ CISR |= CI_CISR_SOF; ++ } ++ cisr=CISR; ++ if(!(--start_time)) ++ { ++ goto wait_SOF_error; ++ } ++ ++ } ++ //mdelay(1); ++ ci_disable(1); ++ ci_enable(1); ++ ci_reset_fifo(); ++ //ci_clear_int_status(0xFFFFFFFF); ++ start_dma_transfer(cam_ctx, cam_ctx->block_header); ++ dbg_print("wait ok..%d", start_time); ++ return 0; ++ ++wait_SOF_error: ++ error_times++; ++ dbg_print("wait SOF error! error_times = %d", error_times); ++ return -EIO; ++} ++ ++static int camera_func_adcm3800_stop_capture(p_camera_context_t cam_ctx) ++{ ++ adcm3800_viewfinder_off(); ++ stop_dma_transfer(cam_ctx); ++ return 0; ++} ++ ++static int camera_func_adcm3800_pm_management(p_camera_context_t cam_ctx, int suspend) ++{ ++ static int resume_dma = 0; ++ if(suspend) ++ { ++ if(cam_ctx != NULL ) ++ { ++ if(cam_ctx->dma_started) ++ { ++ ddbg_print("camera running, suspended"); ++ stop_dma_transfer(cam_ctx); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ pxa_set_cken(CKEN24_CAMERA, 0); ++ } ++ else ++ { ++ pxa_set_cken(CKEN24_CAMERA, 1); ++ enable_irq(IRQ_CAMERA); ++ ++ if(cam_ctx != NULL) ++ { ++ ddbg_print("camera running, resumed"); ++ camera_init(cam_ctx); ++ if(resume_dma == 1) ++ { ++ camera_start_video_capture(cam_ctx, 0); ++ resume_dma = 0; ++ } ++ } ++ } ++ return 0; ++} ++ ++/*set picture brightness*/ ++static int pxa_cam_WCAM_VIDIOCSBRIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ int ret = 0; ++ int bright; ++ bright = (int)param; ++ ddbg_print("WCAM_VIDIOCSBRIGHT %d", bright); ++ ++ cam_ctx->capture_bright = bright; ++ ret = adcm3800_set_bright(bright); ++ ++ if(cam_ctx->dma_started == 1 && ret>0) ++ { ++ camera_func_adcm3800_stop_capture(cam_ctx); ++ ret = camera_func_adcm3800_start_capture(cam_ctx, 0); ++ return ret; ++ } ++ return 0; ++} ++ ++/*set picture style*/ ++static int pxa_cam_WCAM_VIDIOCSSTYLE(p_camera_context_t cam_ctx, void * param) ++{ ++ int ret = 0; ++ V4l_PIC_STYLE style; ++ style = (V4l_PIC_STYLE)param; ++ ddbg_print("WCAM_VIDIOCSSTYLE %d", style); ++ ++ cam_ctx->capture_style = style; ++ ret = adcm3800_set_style(style); ++ if(cam_ctx->dma_started == 1 && ret>0) ++ { ++ camera_func_adcm3800_stop_capture(cam_ctx); ++ ret = camera_func_adcm3800_start_capture(cam_ctx, 0); ++ return ret; ++ } ++ return 0; ++} ++ ++ ++/*set picture light*/ ++static int pxa_cam_WCAM_VIDIOCSLIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ int ret = 0; ++ V4l_PIC_WB light; ++ light = (V4l_PIC_WB)param; ++ dbg_print("WCAM_VIDIOCSLIGHT %d", light); ++ ++ cam_ctx->capture_light = light; ++ ret = adcm3800_set_light(light); ++ if(cam_ctx->dma_started == 1) ++ { ++ camera_func_adcm3800_stop_capture(cam_ctx); ++ ret = camera_func_adcm3800_start_capture(cam_ctx, 0); ++ return ret; ++ } ++ return 0; ++} ++ ++ ++//set output size ++static int pxa_cam_WCAM_VIDIOCSOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ //ddbg_print("WCAM_VIDIOCSOSIZE"); ++ ++ window_size size; ++ ++ if(copy_from_user(&size, param, sizeof(window_size))) ++ { ++ return -EFAULT; ++ } ++ if(cam_ctx->dma_started == 1) ++ { ++ return -EFAULT; ++ } ++ ++ //make it in an even of multiple of 8 ++ size.width = (size.width +7)/8 * 8; ++ size.height = (size.height+7)/8 * 8; ++ ++ dbg_print("w=%d h=%d", size.width, size.height); ++ ++ if(cam_ctx->capture_width != size.width || cam_ctx->capture_height != size.height) ++ { ++ dbg_print("error: the camera output size should match CSWIN size"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/*Set sensor size*/ ++static int pxa_cam_WCAM_VIDIOCSSSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ //ddbg_print("WCAM_VIDIOCSSSIZE"); ++ window_size size; ++ int ret; ++ ++ if(copy_from_user(&size, param, sizeof(window_size))) ++ { ++ return -EFAULT; ++ } ++ if(cam_ctx->dma_started == 1) ++ { ++ return -EFAULT; ++ } ++ ++ //make it in an even of multiple of 8 ++ size.width = (size.width +7)/8 * 8; ++ size.height = (size.height+7)/8 * 8; ++ ++ cam_ctx->sensor_width = size.width; ++ cam_ctx->sensor_height = size.height; ++ dbg_print("w = %d h = %d", size.width, size.height); ++ ++ ret = adcm3800_set_sensor_size(size.width, size.height); ++ if(ret<0) ++ return ret; ++ ++ return 0; ++} ++ ++static int pxa_cam_WCAM_VIDIOCSFPS(p_camera_context_t cam_ctx, void * param) ++{ ++ //ddbg_print("WCAM_VIDIOCSFPS"); ++ ++ struct {int fps, minfps;} cam_fps; ++ int ret = 0; ++ ++ if(copy_from_user(&cam_fps, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ if(cam_fps.fps < 5) ++ { ++ cam_fps.fps = 5; ++ } ++ ++ ddbg_print("WCAM_VIDIOCSFPS %d:%d", cam_ctx->fps, cam_fps.fps); ++ if(cam_ctx->fps != cam_fps.fps || cam_ctx->mini_fps != cam_fps.minfps) ++ { ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ ++ ret = adcm3800_set_fps(cam_ctx->fps * 10); ++ if(ret<0) ++ return ret; ++ ++ if(cam_ctx->dma_started == 1 && ret>1) ++ { ++ camera_func_adcm3800_stop_capture(cam_ctx); ++ ret = camera_func_adcm3800_start_capture(cam_ctx, 0); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static int pxa_cam_WCAM_VIDIOCSNIGHTMODE(p_camera_context_t cam_ctx, void * param) ++{ ++ int ret; ++ struct { ++ V4l_NM mode; ++ int maxtime; ++ } expo_mode; ++ if (copy_from_user(&expo_mode, param, sizeof(expo_mode))) { ++ return -EFAULT; ++ } ++ ddbg_print("WCAM_VIDIOCSNIGHTMODE %d:%d", expo_mode.mode, expo_mode.maxtime); ++ ++ ret = adcm3800_set_exposure_mode(expo_mode.mode, expo_mode.maxtime); ++ if(cam_ctx->dma_started == 1 && ret>0) ++ { ++ camera_func_adcm3800_stop_capture(cam_ctx); ++ ret = camera_func_adcm3800_start_capture(cam_ctx, 0); ++ return ret; ++ } ++ return 0; ++} ++ ++/*set flicker frequency*/ ++static int pxa_cam_WCAM_VIDIOCSFLICKER(p_camera_context_t cam_ctx, void * param) ++{ ++ int ret; ++ dbg_print("WCAM_VIDIOCSFLICKER"); ++ cam_ctx->flicker_freq = (int)param; ++ ++ if(cam_ctx->dma_started == 1) ++ return -EPERM; ++ ++ ret = adcm3800_set_flicker(cam_ctx->flicker_freq); ++ if(ret<0) ++ return ret; ++ ++ return 0; ++} ++ ++static int pxa_camera_WCAM_VIDIOCGCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ int ret, offset; ++ u16 value; ++ //ddbg_print("WCAM_VIDIOCGCAMREG"); ++ if(copy_from_user(&offset, param, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ret = i2c_adcm3800_read((u16)offset, &value); ++ if(ret<0) ++ return ret; ++ ++ if(copy_to_user(param, &value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int pxa_camera_WCAM_VIDIOCSCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ struct reg_set_s{int val1, val2;} reg_s; ++ //ddbg_print("WCAM_VIDIOCSCAMREG"); ++ ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ i2c_adcm3800_write((u16)reg_s.val1, (u16)reg_s.val2); ++ return 0; ++} ++ ++static int camera_func_adcm3800_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param) ++{ ++ switch(cmd) ++ { ++ /*read adcm3800 registers*/ ++ case WCAM_VIDIOCGCAMREG: ++ return pxa_camera_WCAM_VIDIOCGCAMREG(cam_ctx, param); ++ ++ /*write adcm3800 registers*/ ++ case WCAM_VIDIOCSCAMREG: ++ return pxa_camera_WCAM_VIDIOCSCAMREG(cam_ctx, param); ++ ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return pxa_cam_WCAM_VIDIOCSSSIZE(cam_ctx, param); ++ ++ /*set output size*/ ++ case WCAM_VIDIOCSOSIZE: ++ return pxa_cam_WCAM_VIDIOCSOSIZE(cam_ctx, param); ++ ++ ++ /*set video mode fps*/ ++ case WCAM_VIDIOCSFPS: ++ return pxa_cam_WCAM_VIDIOCSFPS(cam_ctx, param); ++ ++ case WCAM_VIDIOCSNIGHTMODE: ++ return pxa_cam_WCAM_VIDIOCSNIGHTMODE(cam_ctx, param); ++ ++ /*set picture style*/ ++ case WCAM_VIDIOCSSTYLE: ++ return pxa_cam_WCAM_VIDIOCSSTYLE(cam_ctx, param); ++ ++ /*set picture light*/ ++ case WCAM_VIDIOCSLIGHT: ++ return pxa_cam_WCAM_VIDIOCSLIGHT(cam_ctx, param); ++ ++ /*set picture brightness*/ ++ case WCAM_VIDIOCSBRIGHT: ++ return pxa_cam_WCAM_VIDIOCSBRIGHT(cam_ctx, param); ++ ++ /*set flicker frequency*/ ++ case WCAM_VIDIOCSFLICKER: ++ return pxa_cam_WCAM_VIDIOCSFLICKER(cam_ctx, param); ++ ++ default: ++ { ++ dbg_print("Error cmd=0x%x", cmd); ++ return -1; ++ } ++ } ++ return 0; ++ ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm3800.h linux-2.6.16/drivers/media/video/adcm3800.h +--- linux-2.6.16.orig/drivers/media/video/adcm3800.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm3800.h 2006-06-03 11:14:56.428310848 +0200 +@@ -0,0 +1,41 @@ ++ ++/*================================================================================ ++ ++ Header Name: adcm3800.h ++ ++General Description: Camera module adcm3800 interface head file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef _ADCM3800_H_ ++#define _ADCM3800_H_ ++ ++#include "camera.h" ++ ++////////////////////////////////////////////////////////////////////////////////////// ++// ++// Prototypes ++// ++////////////////////////////////////////////////////////////////////////////////////// ++ ++/* WINDOW SIZE */ ++typedef struct { ++ u16 width; ++ u16 height; ++} window_size; ++ ++#endif /* _ADCM3800_H_ */ ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm3800_hw.c linux-2.6.16/drivers/media/video/adcm3800_hw.c +--- linux-2.6.16.orig/drivers/media/video/adcm3800_hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm3800_hw.c 2006-06-03 11:14:56.431310392 +0200 +@@ -0,0 +1,1828 @@ ++/*================================================================================ ++ ++ Header Name: adcm3800_hw.c ++ ++General Description: Camera module adcm3800 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++ ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++ ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++ Update algorithm for DMA transfer ++ Update strategy for memory management ++ Fix still picture capture failed sometime ++ New Agilent sensor chip ID support ++ Make output height in an even multiple of 8 ++ ++wangfei(w20239) 03/08/2004 LIBdd84578 Photo effects setting ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <linux/delay.h> ++ ++#include "camera.h" ++#include "adcm3800_hw.h" ++ ++#define MAX_FPS 300 // 30 fps ++ ++static adcm3800_context_t adcm3800_context; ++ ++#define adcm3800_read(addr, pvalue) \ ++ i2c_adcm3800_read(addr, pvalue); \ ++ ddbg_print("i2c read: a(0x%04x) v(0x%04x)", addr, *(pvalue)); ++ ++#define adcm3800_write(addr, value) \ ++ i2c_adcm3800_write(addr, value); \ ++ ddbg_print("i2c write: a(0x%04x) v(0x%04x)", addr, value); ++ ++#define adcm3800_read_byte(addr, pvalue) \ ++ i2c_adcm3800_read_byte(addr, pvalue); \ ++ ddbg_print("i2c read b: a(0x%04x) v(0x%02x)", addr, *(pvalue)); ++ ++#define adcm3800_write_byte(addr, value) \ ++ i2c_adcm3800_write_byte(addr, value); \ ++ ddbg_print("i2c write b: a(0x%04x) v(0x%02x)", addr, value); ++ ++static int adcm3800_reg_read(u16 reg_addr) ++{ ++ u16 value; ++ int ret = adcm3800_read(reg_addr, &value); ++ if(ret < 0) ++ { ++ return ret; ++ } ++ return value; ++} ++ ++// These routine writes to consectutive 16 bit registers ++// with addresses that increment by 2. ++static int adcm3800_write_regs (u16 regAddr, u16 *regData, u16 nRegs) ++{ ++ int i, ret; ++ for(i = 0; i < nRegs; i++) ++ { ++ ret = adcm3800_write(regAddr+i*2, regData[i]); ++ if(ret < 0) ++ { ++ dbg_print("adcm3800 write error %d:%04x!", i, regAddr+i*2); ++ return -1; ++ } ++ } ++ return i; ++} ++ ++static int adcm3800_writeb_regs (u16 regAddr, u8 *regData, u16 nRegs) ++{ ++ int i, ret; ++ for(i = 0; i < nRegs; i++) ++ { ++ ret = adcm3800_write_byte(regAddr+i, regData[i]); ++ if(ret < 0) ++ { ++ dbg_print("adcm3800 write error %d:%04x!", i, regAddr+i*2); ++ return -1; ++ } ++ } ++ return i; ++} ++ ++void adcm3800_dump_awb_regs(void) ++{ ++#ifdef DEBUG ++ int i; ++ unsigned short value; ++ unsigned char valueb; ++ ++ // read some PI/AWB registers ++ adcm3800_read(0x003e, &value); // current CC matrix for PI ++ dbg_print("003e: %04x (PI index)", value); ++ adcm3800_read(0x1064, &value); // current red gains ++ dbg_print("1064: %04x (red gain)", value); ++ adcm3800_read(0x1066, &value); // current blue gains ++ dbg_print("1066: %04x (blue gain)", value); ++ ++ // read only current registers ++ adcm3800_read(0x0244, &value); // C_GAIN, current gain ++ dbg_print("0244: %04x (current gain)", value); ++ adcm3800_read(0x0246, &value); // C_ETIME, current exposure time ++ dbg_print("0246: %04x (current exposure time)", value); ++ adcm3800_read(0x024a, &value); // C_RG_RATIO, current red/green ratio ++ dbg_print("024a: %04x (current red/green ratio)", value); ++ adcm3800_read(0x024c, &value); // C_BG_RATIO, current blue/green ratio ++ dbg_print("024c: %04x (current blue/green ratio)", value); ++#endif ++} ++ ++static int adcm3800_print_status(void) ++{ ++ adcm3800_dump_awb_regs(); ++ ++#if DEBUG > 1 ++ int i; ++ unsigned short value; ++ unsigned char valueb; ++ ++ adcm3800_read(0x0002, &value); ++ ddbg_print("control: %04x", value); ++ adcm3800_read(0x0004, &value); ++ ddbg_print("status: %04x", value); ++ adcm3800_read(0x000c, &value); ++ ddbg_print("exposure time: %d ms", value/100); ++ adcm3800_read(0x0016, &value); ++ ddbg_print("frame rate: %d/10 fps", value); ++ ++ // read only current registers ++ adcm3800_read(0x0248, &value); // C_BNF_TIME, current flicker time ++ ++ // PLL & clock registers ++ adcm3800_read(0x100a, &value); ++ adcm3800_read(0x3000, &value); ++ adcm3800_read(0x3004, &value); ++ adcm3800_read(0x3006, &value); ++ ++ adcm3800_read(0x114, &value); ++ ++ // Auto function registers ++ adcm3800_read(EREG_AE_TARGET, &value); ++ adcm3800_read(0x017c, &value); ++ adcm3800_read(0x017e, &value); ++ ++ adcm3800_read(EREG_AF_CTRL1, &value); ++ adcm3800_read(EREG_AF_CTRL2, &value); ++ adcm3800_read(EREG_APS_COEF_GRN1, &value); ++ adcm3800_read(EREG_APS_COEF_GRN2, &value); ++ adcm3800_read(EREG_APS_COEF_RED, &value); ++ adcm3800_read(EREG_APS_COEF_BLUE, &value); ++ ++ // statistics registers ++ //adcm3800_read(0x1076, &value); ++ //adcm3800_read(0x1074, &value); ++ ++ // Sensor exposure registers ++ adcm3800_read_byte(0x080F, &valueb); ++ adcm3800_read_byte(0x0810, &valueb); ++ adcm3800_read_byte(0x0811, &valueb); ++ adcm3800_read_byte(0x0812, &valueb); ++ ++ adcm3800_read_byte(0x0813, &valueb); ++ adcm3800_read_byte(0x0814, &valueb); ++ adcm3800_read_byte(0x0815, &valueb); ++ adcm3800_read_byte(0x080e, &valueb); ++ ++ // read CC_COEF ++ for(i=0; i<9; i++) ++ { adcm3800_read(0x1028+i*2, &value); } ++ // read NACC Bright CC ++ for(i=0; i<9; i++) ++ { adcm3800_read(0x0270+i*2, &value); } ++ // read gamma ++ for(i=0; i<33; i++) ++ { adcm3800_read(0x1400+i*2, &value); } ++ // read CSC ++ for(i=0; i<10; i++) ++ { adcm3800_read(0x0190+i*2, &value); } ++ for(i=0; i<10; i++) ++ { adcm3800_read(0x1046+i*2, &value); } ++#endif ++ return 0; ++} ++ ++static void adcm3800_wait(u32 ms) ++{ ++ if(ms > 10) ++ { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(ms/10); ++ } ++} ++ ++static int wait_sreg_update(void) ++{ ++ dbg_print("wait for sensor update simple registers"); ++ adcm3800_write(SREG_CONTROL, 0x04); ++ adcm3800_wait(10); ++ int retry = adcm3800__TIMEOUT*4; ++ while(--retry) ++ { ++ u16 v; ++ int ret; ++ ret = adcm3800_read(SREG_CONTROL, &v); ++ if(ret<0) ++ return ret; ++ ++ if(!(v & 0x04)) ++ { ++ dbg_print("retry = %d", retry); ++ return 0; ++ } ++ adcm3800_wait(2); ++ } ++ dbg_print("error:timeout to SCL, retry = %d", retry); ++ return -EIO; ++} ++ ++static int adcm3800_firmware_upgrade(void); ++static int adcm3800_init_regs(void); ++ ++static void adcm3800_init_context(void) ++{ ++ memset(&adcm3800_context, 0, sizeof(adcm3800_context)); ++ ++ adcm3800_context.SCL_restart = 1; // force restart at first time ++ adcm3800_context.format = O_FORMAT_NONE; ++ adcm3800_context.max_expotime = 100000; // 100ms ++} ++ ++/////////////////////////////////////////////////////////////// ++// ++// Programming Guide Chapter 1: Basic Programming ++// ++/////////////////////////////////////////////////////////////// ++ ++int adcm3800_master_clock(u32 clk) ++{ ++#if 1 ++ int i; ++ unsigned short value; ++ unsigned int clock; ++ //0x5017 3.375X // 24M*3.375 = 81M ++ //0x502f 1.6875X // 48M*1.6875 = 81M ++ //0x4f2f // 48.75*80/48 = 81.25M ++ //u16 div = 0x4f2f; // 48.75*80/48 = 81.25M ++ u16 div = 0x502f; // 48.75*81/48 = 82.265625M ++ ++ clock = clk*((div>>8) + 1) / ((div&0xFF) + 1); ++ ++ adcm3800_read(EREG_PLL_CTRL, &value); ++ dbg_print("1 clk %d, clock %d, PLL CTRL : %04x", clk, clock, value); ++ /*enable pll*/ ++ adcm3800_write(0x300a, clock/4000-1); ++ adcm3800_write(EREG_PLL_DIV_L, div); ++ adcm3800_write(EREG_PLL_DIV_S, div); ++ adcm3800_write(EREG_PLL_CTRL, 0x0015); //0x002D ++ adcm3800_write(0x3040, 0x0100); ++ ++ adcm3800_write(0x010c, 0x0006); ++ adcm3800_write(SREG_CLK_FREQ, (u16)(clock / 10)); ++ ++ for(i=0; i<1000; i++) ++ { ++ adcm3800_read(EREG_PLL_CTRL, &value); ++ dbg_print("2 PLL CTRL : %04x", value); ++ if(value&0x80) ++ break; ++ mdelay(2); ++ } ++ dbg_print("3 wait %d ms : ", i*2); ++ ++#else ++ adcm3800_write(SREG_CLK_FREQ, (u16)(clk / 10)); ++#endif ++ ++ return 0; ++} ++ ++int adcm3800_power_on( u32 clk ) ++{ ++ adcm3800_init_context(); ++ ++ //read out version ++ //u16 sensor_rev, cm_rev; ++ //adcm3800_version_revision(&cm_rev, &sensor_rev); ++ ++ /*Follow these steps to correctly power on the ADCM-2700: ++ 1 Turn on VCC voltage (2.8 volts) and wait 20 milliseconds. ++ 2 Turn on MCLK (13 MHz is the default value) and wait 150 milliseconds. ++ 3 Read register 0x0004; if the return value equals 0x0001, power-up is complete. */ ++ int retry = adcm3800__TIMEOUT/2; ++ int timeout = 0; ++ while(--retry) ++ { ++ int ret; ++ u16 value; ++ ret = adcm3800_read(SREG_STATUS, &value); ++ if(value == 0x0001) ++ { ++ dbg_print("adcm3800 Power-up complete!! time %dms", timeout); ++ break; ++ } ++ adcm3800_wait(2); ++ timeout += 2; ++ } ++ if(retry==0) ++ { ++ dbg_print("error: timeout! Power-up failed!"); ++ return -EIO; ++ } ++ ++ // turn off camera ++ adcm3800_write(SREG_CONTROL, 0x0); ++ ++ // Load the firmware upgrade ++ adcm3800_firmware_upgrade(); ++ ++ // initialize registers ++ adcm3800_init_regs(); ++ ++ /* Program the mafster clock */ ++ adcm3800_master_clock(clk); ++ ++ return 0; ++} ++ ++ ++int adcm3800_power_off() ++{ ++ /*stop camera*/ ++ adcm3800_write(SREG_CONTROL, 0); ++ return 0; ++} ++ ++ ++///////////////////////////////////////////////////////////////////////////////////// ++// ++// Programming Guide Chapter 2: Configuration Methods ++// ++///////////////////////////////////////////////////////////////////////////////////// ++ ++ ++static int adcm3800_version_revision(u16 * cm_revision, u16 *sensor_revision) ++{ ++ u8 bvalue; ++ ++ //Camera module version is 0x060 ++ adcm3800_read(SREG_ID, cm_revision); ++ dbg_print("adcm3800 SREG_ID is 0x%x", *cm_revision); ++ ++ //Image sensor version is 0x60 ++ adcm3800_read_byte(EREG_IDENT, &bvalue); ++ *sensor_revision = bvalue; ++ dbg_print("adcm3800 EREG_IDENT is 0x%x", *sensor_revision); ++ ++ return 0; ++} ++ ++int adcm3800_viewfinder_on() ++{ ++ ddbg_print("camera video mode start!"); ++ adcm3800_print_status(); ++ return 0; ++} ++ ++int adcm3800_viewfinder_off() ++{ ++ adcm3800_print_status(); ++ ++ ddbg_print("camera video mode stop!"); ++ return 0; ++} ++ ++static int adcm3800_register_sensor_size(u16 width, u16 height) ++{ ++ adcm3800_write(SREG_SENSOR_WID_V, width); ++ adcm3800_write(SREG_SENSOR_HGT_V, height); ++ return 0; ++} ++ ++int adcm3800_set_sensor_size(u16 width, u16 height) ++{ ++ if( width!=adcm3800_context.sensor_w || ++ height!=adcm3800_context.sensor_h ) ++ { ++ adcm3800_context.sensor_w = width; ++ adcm3800_context.sensor_h = height; ++ adcm3800_context.SCL_partial = 1; ++ return 1; ++ } ++ return 0; ++} ++ ++static int adcm3800_register_output_size(u16 width, u16 height) ++{ ++ adcm3800_write(SREG_OUTPUT_WID_V, width); ++ adcm3800_write(SREG_OUTPUT_HGT_V, height); ++ ++ return 0; ++} ++ ++int adcm3800_set_output_size(u16 width, u16 height) ++{ ++ if( width!=adcm3800_context.output_w || ++ height!=adcm3800_context.output_h ) ++ { ++ adcm3800_context.output_w = width; ++ adcm3800_context.output_h = height; ++ adcm3800_context.SCL_partial = 1; ++ return 1; ++ } ++ return 0; ++} ++ ++ ++static int adcm3800_register_output_format(u16 format) ++{ ++ u16 newcfg; ++ u16 oldcfg; ++ adcm3800_read(SREG_OUTPUT_FORMAT, &oldcfg); ++ ++ newcfg = (oldcfg & 0xFFF0) | (format & 0x000F); ++ if(newcfg!=oldcfg) ++ { ++ adcm3800_write( SREG_OUTPUT_FORMAT, newcfg ); ++ } ++ ++ return 0; ++} ++ ++int adcm3800_set_output_format(u16 format) ++{ ++ if( format!=adcm3800_context.format ) ++ { ++ adcm3800_context.format = format; ++ adcm3800_context.SCL_partial = 1; // TODO: not confirmed ++ return 1; ++ } ++ return 0; ++} ++ ++static int adcm3800_register_fps(p_adcm3800_context_t adcm_ctx) ++{ ++ if( (adcm_ctx->fps>70) && (adcm_ctx->output_w > 640 || adcm_ctx->output_h > 480) ) ++ { ++ //if capture size > VGA, the frame rate shall be low ++ // this is limit of CIF PCLK < 24.25Mhz ++ adcm3800_write(SREG_FRAME_RATE, 75); // 7.5 fps ++ } ++ else ++ { ++ //normal fps ++ adcm3800_write(SREG_FRAME_RATE, adcm_ctx->fps); ++ } ++ return 0; ++} ++ ++int adcm3800_set_fps(u16 fps) ++{ ++ if(fps > MAX_FPS) ++ { ++ return -EINVAL; ++ } ++ ++ if( fps!=adcm3800_context.fps ) ++ { ++ adcm3800_context.fps = fps; ++ adcm3800_context.SCL_partial = 1; // TODO: not confirmed ++ return 1; ++ } ++ return 0; ++} ++ ++static int adcm3800_register_gamma(int table) ++{ ++ dbg_print("set gamma table %d", table); ++ ++ const u16 value[][33] = ++ { ++ //0 default sRGB ++ { ++ 0x0000, 0x0017, 0x0032, 0x0046, 0x0056, 0x0064, 0x0071, 0x007c, 0x0086, 0x0099, 0x00a9, ++ 0x00b8, 0x00c6, 0x00df, 0x00f5, 0x0109, 0x011b, 0x013d, 0x015a, 0x0175, 0x018d, 0x01ba, ++ 0x01e1, 0x0205, 0x0225, 0x0261, 0x0295, 0x02c5, 0x02f1, 0x033f, 0x0385, 0x03c5, 0x0400}, ++ ++ //1 2.6 ++ { ++ 0x0000, 0x005c, 0x0079, 0x008d, 0x009e, 0x00ac, 0x00b9, 0x00c4, 0x00ce, 0x00e1, 0x00f1, ++ 0x0100, 0x010e, 0x0126, 0x013b, 0x014e, 0x0160, 0x0180, 0x019c, 0x01b5, 0x01cc, 0x01f5, ++ 0x0219, 0x023a, 0x0258, 0x028e, 0x02be, 0x02e9, 0x0310, 0x0356, 0x0394, 0x03cc, 0x0400}, ++ ++ //2 2.5 ++ { ++ 0x0000, 0x0054, 0x006f, 0x0083, 0x0093, 0x00a0, 0x00ac, 0x00b7, 0x00c2, 0x00d4, 0x00e4, ++ 0x00f2, 0x00ff, 0x0117, 0x012d, 0x0140, 0x0151, 0x0171, 0x018d, 0x01a6, 0x01bd, 0x01e7, ++ 0x020c, 0x022d, 0x024c, 0x0283, 0x02b3, 0x02df, 0x0308, 0x0350, 0x0390, 0x03ca, 0x0400}, ++ ++ //3 2.4 ++ { ++ 0x0000, 0x004C, 0x0065, 0x0078, 0x0087, 0x0094, 0x00A0, 0x00ab, 0x00b5, 0x00c6, 0x00d6, ++ 0x00e4, 0x00f1, 0x0109, 0x011E, 0x0131, 0x0142, 0x0161, 0x017D, 0x0197, 0x01AE, 0x01d8, ++ 0x01fd, 0x021F, 0x023E, 0x0276, 0x02a8, 0x02d5, 0x02ff, 0x0349, 0x038C, 0x03C8, 0x0400}, ++ ++ //4 2.3 ++ { ++ 0x0000, 0x0043, 0x005b, 0x006d, 0x007c, 0x0088, 0x0094, 0x009e, 0x00a7, 0x00b8, 0x00c8, ++ 0x00d6, 0x00e2, 0x00fa, 0x010e, 0x0121, 0x0132, 0x0151, 0x016d, 0x0187, 0x019e, 0x01c8, ++ 0x01ee, 0x0210, 0x0230, 0x0269, 0x029c, 0x02ca, 0x02f5, 0x0342, 0x0387, 0x03c6, 0x0400}, ++ ++ //5 2.2 ++ { ++ 0x0000, 0x003c, 0x0052, 0x0063, 0x0070, 0x007c, 0x0087, 0x0091, 0x0094, 0x00ab, 0x00b9, ++ 0x00c7, 0x00d3, 0x00ea, 0x00fe, 0x0111, 0x0122, 0x0141, 0x015d, 0x0176, 0x018d, 0x01b8, ++ 0x01de, 0x0201, 0x0221, 0x025b, 0x028f, 0x02bf, 0x02eb, 0x033b, 0x0382, 0x03c3, 0x0400}, ++ ++ //6 2.1 ++ { ++ 0x0000, 0x0034, 0x0049, 0x0058, 0x0065, 0x0070, 0x007b, 0x0084, 0x008d, 0x009d, 0x00ab, ++ 0x00b8, 0x00c4, 0x00da, 0x00ee, 0x0100, 0x0111, 0x0130, 0x014b, 0x0164, 0x017c, 0x01a7, ++ 0x01cd, 0x01f0, 0x0211, 0x024c, 0x0281, 0x02b2, 0x02e0, 0x0332, 0x037c, 0x03c0, 0x0400}, ++ ++ //7 2.0 ++ { ++ 0x0000, 0x002d, 0x0040, 0x004e, 0x005a, 0x0065, 0x006e, 0x0077, 0x0080, 0x008f, 0x009c, ++ 0x00a9, 0x00b5, 0x00ca, 0x00dd, 0x00ef, 0x0100, 0x011e, 0x0139, 0x0152, 0x016a, 0x0194, ++ 0x01bb, 0x01de, 0x0200, 0x023c, 0x0273, 0x02a5, 0x02d4, 0x0329, 0x0376, 0x03bd, 0x0400}, ++ ++ //8 1.9 ++ { ++ 0x0000, 0x0026, 0x0037, 0x0044, 0x004f, 0x0059, 0x0062, 0x006a, 0x0072, 0x0081, 0x008e, ++ 0x009a, 0x00a5, 0x00b9, 0x00cc, 0x00dd, 0x00ed, 0x010b, 0x0126, 0x013f, 0x0156, 0x0181, ++ 0x01a8, 0x01cc, 0x01ed, 0x022b, 0x0263, 0x0296, 0x02c6, 0x031f, 0x0370, 0x03ba, 0x0400}, ++ ++ //9 1.8 ++ { ++ 0x0000, 0x0020, 0x002f, 0x003a, 0x0045, 0x004e, 0x0056, 0x005e, 0x0065, 0x0073, 0x007f, ++ 0x008a, 0x0095, 0x00a9, 0x00bb, 0x00cb, 0x00db, 0x00f8, 0x0112, 0x012b, 0x0142, 0x016d, ++ 0x0194, 0x01b8, 0x01da, 0x0218, 0x0251, 0x0286, 0x02b8, 0x0314, 0x0368, 0x03b6, 0x0400}, ++ ++ //10 1.6 ++ { ++ 0x0000, 0x0014, 0x0020, 0x0029, 0x0031, 0x0038, 0x003f, 0x0046, 0x004c, 0x0057, 0x0062, ++ 0x006b, 0x0075, 0x0086, 0x0097, 0x00a6, 0x00b5, 0x00d0, 0x00e9, 0x0100, 0x0117, 0x0140, ++ 0x0167, 0x018c, 0x01ae, 0x01ee, 0x022a, 0x0262, 0x0297, 0x02fb, 0x0357, 0x03ae, 0x0400} ++ ++ }; ++ ++ int i, ret; ++ /* ++ for(i = 0; i < 33; i++) ++ { ++ adcm3800_write(0x1400+i*2, value[table][i]); ++ } ++ */ ++ ++ for(i = 0; i < 33; i++) ++ { ++ ret = adcm3800_write(EREG_TM_COEF_00_V+i*2, value[table][i]); ++ } ++ ++ return 0; ++} ++ ++static int adcm3800_register_gamma_solarize(void) ++{ ++ const u16 value[33] = ++ { ++ //solarize ++ 0x0400, 0x03e9, 0x03a9, 0x0344, 0x02c3, 0x0232, 0x019c, 0x010e, 0x0095, 0x003c, 0x0009, ++ 0x0002, 0x0026, 0x0074, 0x00e3, 0x016b, 0x01ff, 0x0294, 0x031c, 0x038b, 0x03d9, 0x03fd, ++ 0x03f6, 0x03c3, 0x036a, 0x02f1, 0x0263, 0x01cd, 0x013c, 0x00bb, 0x0056, 0x0016, 0x0000 ++ }; ++ ++ int i, ret; ++ /* ++ for(i = 0; i < 33; i++) ++ { ++ adcm3800_write(0x1400+i*2, value[i]); ++ } ++ */ ++ ++ for(i = 0; i < 33; i++) ++ { ++ ret = adcm3800_write(EREG_TM_COEF_00_V+i*2, value[i]); ++ } ++ ++ return 0; ++} ++ ++/***************** Image Styles ************************/ ++/* No special effect */ ++static const u16 agilent_adcm3800_normal_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01ED, 0x01DB, 0x0038, ++ 0x004F, 0x01BE, 0x01F3, ++ 0x0000}; ++ ++/* Antique effect */ ++static const u16 agilent_adcm3800_antique_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01F8, 0x01F8, 0x01F8, ++ 0x0008, 0x0008, 0x0008, ++ 0x0000}; ++ ++/* Black and White effect */ ++static const u16 agilent_adcm3800_black_and_white_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, ++ 0x0000}; ++ ++/* Color Negative effect */ ++static const u16 agilent_adcm3800_color_negative_effect[] = ++{0x01da, 0x01bf, 0x01f1, ++ 0x0013, 0x0025, 0x01c8, ++ 0x01b1, 0x0042, 0x000d, ++ 0x00ff}; ++ ++#if 0 ++/* saturation 50% effect */ ++static const u16 agilent_adcm3800_saturation_50_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01e4, 0x01c9, 0x0054, ++ 0x0076, 0x019d, 0x01ed, ++ 0x0000}; ++ ++/* saturation 100% effect */ ++static const u16 agilent_adcm3800_saturation_100_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01da, 0x01b6, 0x0070, ++ 0x009d, 0x017c, 0x01e6, ++ 0x0000}; ++ ++/* Reddish effect */ ++static const u16 agilent_adcm3800_red_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01e4, 0x01db, 0x0038, ++ 0x0076, 0x01be, 0x01f3, ++ 0x0000}; ++ ++/* Greenish effect */ ++static const u16 agilent_adcm3800_green_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01ed, 0x01c9, 0x0038, ++ 0x004f, 0x019d, 0x01F3, ++ 0x0000}; ++ ++/* Bluish effect */ ++static const u16 agilent_adcm3800_blue_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01ed, 0x01db, 0x0054, ++ 0x004f, 0x01be, 0x01ed, ++ 0x0000}; ++ ++/* Cyan effect */ ++static const u16 agilent_adcm3800_cyan_effect[] = ++{0x0026, 0x004B, 0x000F, ++ 0x01f7, 0x01db, 0x0038, ++ 0x0027, 0x01be, 0x01f3, ++ 0x0000}; ++#endif ++ ++/* End additional matrices */ ++/*******************************************************/ ++ ++ ++/*set picture style(normal/black white/sepia/solarize/neg.art)*/ ++static int adcm3800_register_style(V4l_PIC_STYLE style) ++{ ++ u16 * reg_value; ++ u16 reg_count = 10; ++ reg_value = (u16 *)agilent_adcm3800_normal_effect; ++ switch(style) ++ { ++ case V4l_STYLE_BLACK_WHITE: ++ reg_value = (u16 *)agilent_adcm3800_black_and_white_effect; ++ break; ++ case V4l_STYLE_SEPIA: ++ reg_value = (u16 *)agilent_adcm3800_antique_effect; ++ break; ++ case V4l_STYLE_SOLARIZE: ++ break; ++ case V4l_STYLE_NEG_ART: ++ reg_value = (u16 *)agilent_adcm3800_color_negative_effect; ++ break; ++ default: ++ break; ++ } ++ ++ int i; ++ for(i = 0; i < reg_count; i++) ++ { ++ adcm3800_write(EREG_CSC_00_V+i*2, reg_value[i]); ++ } ++ return 0; ++} ++ ++/*set picture style(normal/black white/sepia/solarize/neg.art)*/ ++int adcm3800_set_style(V4l_PIC_STYLE style) ++{ ++ if( style!=adcm3800_context.style ) ++ { ++ adcm3800_context.style = style; ++ adcm3800_context.SCL_restart = 1; ++ return 1; ++ } ++ return 0; ++} ++ ++/******* Agilent Color Matrices ***************************/ ++ ++/* ++White Balance gains are located in registers 0x1064 (Red Gain) and 0x1066 (Blue Gains) ++ ++Color Correction Coeffecients are located in registers 0x1028-0x1038 ++ ++* To force write White Balance coeffecients, make sure AWB is off (bit 1 in 0x140) ++ ++* To force write Color Correction coeffiecients, make sure NACC is off (bit 3 in 0x140) ++ ++ ++The following are the register writes for various iluminants: ++ ++************************************************* ++Illuminant D50 ++************************************************* ++w 1064 12B ++w 1066 143 ++w 1028 23E EDF FE3 F3E 2A8 F1A FBC E23 321 ++------------------------ ++************************************************* ++Illuminant D55 ++************************************************* ++w 1064 134 ++w 1066 13B ++w 1028 233 EF7 FD7 F3F 29B F26 FC1 E40 2FF ++------------------------ ++************************************************* ++Illuminant D65 ++************************************************* ++w 1064 141 ++w 1066 12D ++w 1028 223 F17 FC6 F41 289 F36 FC6 E6A 2D0 ++------------------------ ++************************************************* ++Illuminant D75 ++************************************************* ++w 1064 14B ++w 1066 123 ++w 1028 21A F2C FBA F42 27D F40 FC7 E86 2B3 ++------------------------ ++************************************************* ++Illuminant D90 ++************************************************* ++w 1064 155 ++w 1066 118 ++w 1028 212 F40 FAF F44 272 F4A FC7 EA2 298 ++------------------------ ++************************************************* ++Illuminant FluorTriphosphor_4000K ++************************************************* ++w 1064 111 ++w 1066 16A ++w 1028 251 E44 06B F63 281 F1B FB7 E12 338 ++------------------------ ++************************************************* ++Illuminant Fluor_PhilipsUltraLume ++************************************************* ++w 1064 F3 ++w 1066 190 ++w 1028 212 DCA 125 F81 23D F42 F8E D81 3F1 ++------------------------ ++************************************************* ++Illuminant blackbody2600 ++************************************************* ++w 1064 E4 ++w 1066 176 ++w 1028 240 DDC 0E4 F49 2BC EFC F44 D57 465 ++------------------------ ++************************************************* ++Illuminant blackbody3200 ++************************************************* ++w 1064 FA ++w 1066 166 ++w 1028 217 E74 075 F50 27D F33 F8C DEA 38A ++------------------------ ++************************************************* ++Illuminant blackbody3500 ++************************************************* ++w 1064 104 ++w 1066 15E ++w 1028 20A EA2 055 F53 26C F41 F9E E19 349 ++------------------------ ++************************************************* ++Illuminant blackbody3800 ++************************************************* ++w 1064 10E ++w 1066 157 ++w 1028 1FF EC5 03D F55 25F F4C FAB E3D 318 ++------------------------ ++************************************************* ++Illuminant blackbody4200 ++************************************************* ++w 1064 118 ++w 1066 14E ++w 1028 1F4 EE7 025 F57 252 F56 FB7 E63 2E7 ++------------------------ ++************************************************* ++Illuminant blackbody4600 ++************************************************* ++w 1064 121 ++w 1066 146 ++w 1028 1EB F02 013 F59 249 F5E FBE E80 2C2 ++------------------------ ++************************************************* ++Illuminant boothCool_4070K ++************************************************* ++w 1064 126 ++w 1066 16C ++w 1028 201 ED8 027 F6D 274 F1F FAE E0F 343 ++------------------------ ++************************************************* ++Illuminant boothHorizon ++************************************************* ++w 1064 D5 ++w 1066 17D ++w 1028 264 D43 159 F47 313 EA6 EF5 CD9 531 ++------------------------ ++************************************************* ++Illuminant boothInca ++************************************************* ++w 1064 ED ++w 1066 170 ++w 1028 22C E29 0AB F4C 29A F1A F69 DA0 3F7 ++------------------------ ++************************************************* ++Illuminant fluorescent_3335K ++************************************************* ++w 1064 109 ++w 1066 186 ++w 1028 1DB E6A 0BB F83 229 F54 FA2 DE4 37A ++------------------------ ++************************************************* ++Illuminant halogen_2250K ++************************************************* ++w 1064 D5 ++w 1066 184 ++w 1028 213 D7F 16E F5C 2C2 EE2 F01 D43 4BC ++------------------------ ++*/ ++ ++/* Sunlight ++************************************************* ++Illuminant D65 ++************************************************* ++w 1064 141 ++w 1066 12D ++w 1028 223 F17 FC6 F41 289 F36 FC6 E6A 2D0 ++*/ ++static const u16 agilent_adcm3800_sunny_color_gain[] = ++{0x0141, 0x012D}; ++static const u16 agilent_adcm3800_sunny_color[] = ++{0x0223, 0x0F17, 0x0FC6, ++ 0x0F41, 0x0289, 0x0F36, ++ 0x0FC6, 0x0E6A, 0x02D0}; ++ ++/* Cloudy ++************************************************* ++Illuminant D75 ++************************************************* ++w 1064 14B ++w 1066 123 ++w 1028 21A F2C FBA F42 27D F40 FC7 E86 2B3 ++*/ ++static const u16 agilent_adcm3800_cloudy_color_gain[] = ++{0x014B, 0x0123}; ++static const u16 agilent_adcm3800_cloudy_color[] = ++{0x021A, 0x0F2C, 0x0FBA, ++ 0x0F42, 0x027D, 0x0F40, ++ 0x0FC7, 0x0E86, 0x02B3}; ++ ++ ++/* Indoor - home tungsten ++************************************************* ++Illuminant blackbody3200 ++************************************************* ++w 1064 FA ++w 1066 166 ++w 1028 217 E74 075 F50 27D F33 F8C DEA 38A ++*/ ++static const u16 agilent_adcm3800_home_tungsten_color_gain[] = ++{0x0FA, 0x0166}; ++static const u16 agilent_adcm3800_home_tungsten_color[] = ++{0x0217, 0x0E74, 0x0075, ++ 0x0F50, 0x027D, 0x0F33, ++ 0x0F8C, 0x0DEA, 0x038A}; ++ ++ ++/* Indoor - office cool white fluorescent ++************************************************* ++Illuminant fluorescent_3335K ++************************************************* ++w 1064 109 ++w 1066 186 ++w 1028 1DB E6A 0BB F83 229 F54 FA2 DE4 37A ++ * */ ++static const u16 agilent_adcm3800_office_fluorescent_color_gain[] = ++{0x0109, 0x0186}; ++static const u16 agilent_adcm3800_office_fluorescent_color[] = ++{0x01DB, 0x0E6A, 0x00BB, ++ 0x0F83, 0x0229, 0x0F54, ++ 0x0FA2, 0x0DE4, 0x037A}; ++ ++/* Night tungsten ++static const u16 agilent_adcm3800_night_tungsten_color[] = ++{0x034f, 0x0cdd, 0x00d3, ++ 0x0f47, 0x033c, 0x0e73, ++ 0x0f31, 0x0b2a, 0x06a3}; ++*/ ++ ++/* Automatic (generic default setting) 5500K sun-light ++************************************************* ++Illuminant D55 ++************************************************* ++w 1064 134 ++w 1066 13B ++w 1028 233 EF7 FD7 F3F 29B F26 FC1 E40 2FF ++*/ ++static const u16 agilent_adcm3800_automatic_color_gain[] = ++{0x0134, 0x013B}; ++static const u16 agilent_adcm3800_automatic_color[] = ++{0x0233, 0x0EF7, 0x0FD7, ++ 0x0F3F, 0x029B, 0x0F26, ++ 0x0FC1, 0x0E40, 0x02FF}; ++/*******************************************************/ ++ ++ ++static int adcm3800_register_light(V4l_PIC_WB light) ++{ ++ int i; ++ int awb = 0; ++ u16* color_cc; ++ u16* color_gain; ++ switch(light) ++ { ++ case V4l_WB_DIRECT_SUN: ++ awb = 0; ++ color_cc = (u16 *)agilent_adcm3800_sunny_color; ++ color_gain = (u16 *)agilent_adcm3800_sunny_color_gain; ++ break; ++ case V4l_WB_INCANDESCENT: ++ awb = 0; ++ color_cc = (u16 *)agilent_adcm3800_home_tungsten_color; ++ color_gain = (u16 *)agilent_adcm3800_home_tungsten_color_gain; ++ break; ++ case V4l_WB_FLUORESCENT: ++ awb = 1; ++ color_cc = (u16 *)agilent_adcm3800_office_fluorescent_color; ++ color_gain = (u16 *)agilent_adcm3800_office_fluorescent_color_gain; ++ break; ++ default: ++ awb = 1; ++ color_cc = (u16 *)agilent_adcm3800_automatic_color; ++ color_gain = (u16 *)agilent_adcm3800_automatic_color_gain; ++ break; ++ } ++ ++ u16 value_r140; ++ adcm3800_read(EREG_AF_CTRL1, &value_r140); ++ // disable AWB NACC ++ adcm3800_write(EREG_AF_CTRL1, value_r140&(~0x02)&(~0x08)); ++ ++ for(i = 0; i< 9; i++) ++ { ++ adcm3800_write(EREG_CC_COEF_00+i*2, color_cc[i]); ++ } ++#if 1 ++ for(i = 0; i< 9; i++) ++ { ++ u16 value; ++ adcm3800_read(0x0270+i*2, &value); ++ adcm3800_write(0x0270+i*2, (value&0xf000)|color_cc[i]); ++ } ++#endif ++ ++ for(i = 0; i< 2; i++) ++ { ++ adcm3800_write(0x1064+i*2, color_gain[i]); ++ } ++ ++ // tighter awb tolerances ??? ++ // w 17c 108 110 ++ //adcm3800_write(EREG_AWB_TOL_ACQ, 0x0108); ++ //adcm3800_write(EREG_AWB_TOL_MON, 0x0110); ++ ++ if(awb) { ++ adcm3800_write(EREG_AF_CTRL1, value_r140|0x02); // enable AWB ++ } ++ else { ++ adcm3800_write(EREG_AF_CTRL1, value_r140&(~0x02)); // disable AWB ++ } ++ return 0; ++} ++ ++int adcm3800_set_light(V4l_PIC_WB light) ++{ ++ if( light!=adcm3800_context.light ) ++ { ++ adcm3800_context.light = light; ++ adcm3800_context.SCL_restart = 1; ++ return 1; ++ } ++ return 0; ++} ++ ++/*set exposure compensation */ ++static int adcm3800_register_exp_comp(int bright) ++{ ++ const u16 exp_adj[] = ++ { ++ 0x0108, // -2.0 EV ++ 0x0106, // -1.5 EV ++ 0x0104, // -1.0 EV ++ 0x0102, // -0.5 EV ++ 0x0000, // 0.0 EV ++ 0x0002, // +0.5 EV ++ 0x0004, // +1.0 EV ++ 0x0006, // +1.5 EV ++ 0x0008 // +2.0 EV ++ }; ++ ++ if(bright < -4 || bright > 4) ++ { ++ return -EINVAL; ++ } ++ ++ int value = exp_adj[bright+4]; ++ value |= 0x0200; // set center zone exposure ++ adcm3800_write(SREG_EXP_ADJ, value); ++ return 0; ++} ++ ++/*set picture brightness*/ ++static int adcm3800_register_bright(int bright) ++{ ++ const u16 target[] = ++ { ++ 16, //0x0010, // -2.0 EV ++ 23, //0x0017, // -1.5 EV ++ 32, //0x0020, // -1.0 EV ++ 45, //0x002d, // -0.5 EV ++ 64, //0x0040, // 0.0 EV ++ 90, //0x005a, // +0.5 EV ++ 128, //0x0080, // +1.0 EV ++ 181, //0x00b5, // +1.5 EV ++ 240 //0x00f0 // +2.0 EV ++ }; ++ ++ if(bright < -4 || bright > 4) ++ { ++ return -EINVAL; ++ } ++ adcm3800_write(EREG_AE_TARGET, target[bright+4]); ++ return 0; ++} ++ ++/*set picture brightness*/ ++int adcm3800_set_bright(int bright) ++{ ++ adcm3800_context.bright = bright; ++ adcm3800_register_bright(bright); ++ return 0; ++} ++ ++static int adcm3800_register_exposure_mode(V4l_NM mode, int maxexpotime) ++{ ++ adcm3800_write(EREG_AE_ETIME_MAX, maxexpotime/10); ++ return 0; ++} ++ ++/*set exposure mode: normal/night */ ++int adcm3800_set_exposure_mode(V4l_NM mode, int maxexpotime) ++{ ++ if(maxexpotime<10 && maxexpotime>500000) // 500ms > time > 10us ++ return -EINVAL; ++ ++ if(adcm3800_context.max_expotime != maxexpotime) ++ { ++ adcm3800_context.max_expotime = maxexpotime; ++ adcm3800_context.SCL_restart = 1; ++ return 1; ++ } ++ return 0; ++} ++ ++int adcm3800_set_flicker(int flicker) ++{ ++ adcm3800_context.flicker_freq = flicker; ++ u16 old; ++ u16 old1; ++ adcm3800_read(EREG_AF_CTRL2, &old); ++ adcm3800_read(SREG_ILLUM, &old1); ++ old1 &= ~(0x18); ++ dbg_print("set flicker to %d", flicker); ++ if(flicker == 50) ++ { ++ adcm3800_write(SREG_ILLUM, old1|0x08); ++ adcm3800_write(EREG_AF_CTRL2, old&(~0x02)); ++ //1000 = 100000/50/2 ++ adcm3800_write(EREG_AE_ETIME_DFLT, 1000); ++ } ++ else if(flicker == 60) ++ { ++ adcm3800_write(SREG_ILLUM, old1|0x10); ++ adcm3800_write(EREG_AF_CTRL2, old|0x02); ++ // 833 = 100000/60/2 ++ adcm3800_write(EREG_AE_ETIME_DFLT, 833); ++ } ++ else ++ { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++// SCL restart ++static int adcm3800_SCL_restart(p_camera_context_t cam_ctx, int frames) ++{ ++ int ret; ++ ++ /*stop camera*/ ++ adcm3800_write(SREG_CONTROL, 0); ++ ++ //update simple registers ++ adcm3800_register_fps(&adcm3800_context); ++ ++ adcm3800_register_output_format(adcm3800_context.format); ++ ++ adcm3800_write(SREG_SIZE, 0x0f0f); // perfer image quality, disallow subsampling ++ //sensor width and sensor height ++ adcm3800_register_sensor_size(adcm3800_context.sensor_w, adcm3800_context.sensor_h); ++ //output width and output height ++ adcm3800_register_output_size(adcm3800_context.output_w, adcm3800_context.output_h); ++ ++ if(adcm3800_context.style == V4l_STYLE_SOLARIZE ) { ++ adcm3800_register_gamma_solarize(); ++ } ++ else if(frames == 1) { ++ adcm3800_register_gamma(0); // gamma sRGB, still mode ++ } ++ else { ++ adcm3800_register_gamma(5); // gamma 2.0, video mode ++ } ++ ++ //adcm3800_print_status(); ++ ++ // SCL ++ ret = wait_sreg_update(); ++ if(ret<0) ++ return ret; ++ ++ //adcm3800_print_status(); ++ ++ // set AE_GAIN to improve pink at center issue ++ // w 150 240 280 500 280 ++#if 1 ++ adcm3800_write(EREG_AE_GAIN_MIN, 0x0240); ++ adcm3800_write(EREG_AE_GAIN_MIN_P, 0x0280); ++ adcm3800_write(EREG_AE_GAIN_MAX, 0x0500); ++ adcm3800_write(EREG_AE_GAIN_DFLT, 0x0280); ++#endif ++ ++ adcm3800_register_style(adcm3800_context.style); ++ ++ // re-initialize auto functions ++ u16 v_ctrl2; ++ adcm3800_read(EREG_AF_CTRL2, &v_ctrl2); ++ adcm3800_write(EREG_AF_CTRL2, v_ctrl2|0x0040); ++ ++ //adcm3800_print_status(); ++ ++ // set max exposure time ++ adcm3800_register_exposure_mode(adcm3800_context.expo_mode, ++ adcm3800_context.max_expotime); ++ ++ // set brightness ++ adcm3800_register_bright(adcm3800_context.bright); ++ ++ // set white balance ++ adcm3800_register_light(adcm3800_context.light); ++ ++ // start video mode ++ adcm3800_write(SREG_CONTROL, 0x01); ++ ++ //adcm3800_print_status(); ++ ++ adcm3800_write(EREG_AF_CTRL2, v_ctrl2); ++ ++ return 0; ++} ++ ++// SCL partial ++int adcm3800_SCL_partial(p_camera_context_t cam_ctx, int frames) ++{ ++ //update simple registers ++ adcm3800_register_fps(&adcm3800_context); ++ ++ adcm3800_write(SREG_SIZE, 0x0f0f); // perfer image quality, disallow subsampling ++ //sensor width and sensor height ++ adcm3800_register_sensor_size(adcm3800_context.sensor_w, adcm3800_context.sensor_h); ++ ++ //output width and output height ++ adcm3800_register_output_size(adcm3800_context.output_w, adcm3800_context.output_h); ++ ++ if(adcm3800_context.style == V4l_STYLE_SOLARIZE ) { ++ adcm3800_register_gamma_solarize(); ++ } ++ else if(frames == 1) { ++ adcm3800_register_gamma(0); // gamma sRGB, still mode ++ } ++ else { ++ adcm3800_register_gamma(5); // gamma 2.0, video mode ++ } ++ ++ // partial simple control ++ // still mode ++ ++ //adcm3800_print_status(); ++ ++ // partial config ++ adcm3800_write(SREG_CONTROL, 0x21); ++ ++ //adcm3800_print_status(); ++ ++ return 0; ++} ++ ++int adcm3800_reconfigure(p_camera_context_t cam_ctx, int frames) ++{ ++ dbg_print("sensor width %d", cam_ctx->sensor_width); ++ dbg_print("sensor height %d", cam_ctx->sensor_height); ++ dbg_print("capture_width %d", cam_ctx->capture_width); ++ dbg_print("capture_height %d", cam_ctx->capture_height); ++ ddbg_print("fps %d", cam_ctx->fps); ++ ddbg_print("light %d", cam_ctx->capture_light); ++ ddbg_print("capture_bright %d", cam_ctx->capture_bright); ++ ddbg_print("capture_style %d", cam_ctx->capture_style); ++ ++ int ret = 0; ++ if(adcm3800_context.SCL_restart != 0) ++ { ++ ret = adcm3800_SCL_restart(cam_ctx, frames); ++ adcm3800_context.SCL_restart = 0; ++ } ++ else if(adcm3800_context.SCL_partial != 0) ++ { ++ ret = adcm3800_SCL_partial(cam_ctx, frames); ++ adcm3800_context.SCL_partial = 0; ++ } ++ ++ return ret; ++} ++ ++// ++// This is an example of how to implement a firmware patch table. ++// The patch data contained here is the ADCM-3800 patch version 3. ++// ++// The first array is the starting register address of each contiguous block ++// of data to write. The second array is the number of words to write for ++// each block. These arrays are terminated with a zero entry. Some other ++// method could also be used to know how many patch blocks there are, ++// such as using the sizeof() operator, or a separate defined constant. ++// ++// The third array contains the patch data to be written, formatted according ++// to the length of each block. The length of the third array should equal ++// the sum of the entries in the second array. ++// ++ ++// patch code ver.7, 10/20/2004 ++static unsigned short patch3800addr[] = { ++ 0x0186, 0x484c, 0x488c, 0x4838, 0x4818, 0x4898, ++ 0x4980, 0x002c, 0x0034, 0x4820, 0x486C, ++ 0x4860, 0x4804, 0x4854, 0x487C, 0x4894, 0x482C, 0x4834, 0x4800, ++ 0x4868, 0x4C80, 0x0062, 0x006A, 0x0186, ++ 0}; ++static unsigned short patch3800len [] = { ++ 3, 2, 2, 2, 2, 2, ++ 352, 4, 4, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 1104, 4, 2, 2, ++ 0}; ++static unsigned short patch3800data[] = ++{ ++ // #Load patch ++ // 0x0186, 3 ++ 0x0000, 0x0000, 0x0000, ++ // 484C, 2 ++ 0x0002, 0x0012, ++ // 488C, 2 ++ 0x0002, 0x437e, ++ // 4838, 2 ++ 0x0002, 0x4385, ++ // 4818, 2 ++ 0x0002, 0x0564, ++ // 4898, 2 ++ 0x0002, 0x43a0, ++ ++ // #PI patch ++ // 0x4980, 352 ++ 0x0000, 0x00C0, 0x0000, 0x00EA, 0x0000, 0x0212, 0x0000, 0xFF40, ++ 0x0000, 0xFFAF, 0x0000, 0xFF44, 0x0000, 0x0272, 0x0000, 0xFF4A, ++ 0x0000, 0xFFC7, 0x0000, 0xFEA2, 0x0000, 0x0298, 0x0000, 0x00C6, ++ 0x0000, 0x00E1, 0x0000, 0x021A, 0x0000, 0xFF2C, 0x0000, 0xFFBA, ++ 0x0000, 0xFF42, 0x0000, 0x027D, 0x0000, 0xFF40, 0x0000, 0xFFC7, ++ 0x0000, 0xFE86, 0x0000, 0x02B3, 0x0000, 0x00CC, 0x0000, 0x00DA, ++ 0x0000, 0x0223, 0x0000, 0xFF17, 0x0000, 0xFFC6, 0x0000, 0xFF41, ++ 0x0000, 0x0289, 0x0000, 0xFF36, 0x0000, 0xFFC6, 0x0000, 0xFE6A, ++ 0x0000, 0x02D0, 0x0000, 0x00D5, 0x0000, 0x00D0, 0x0000, 0x0233, ++ 0x0000, 0xFEF7, 0x0000, 0xFFD7, 0x0000, 0xFF3F, 0x0000, 0x029B, ++ 0x0000, 0xFF26, 0x0000, 0xFFC1, 0x0000, 0xFE40, 0x0000, 0x02FF, ++ 0x0000, 0x00DB, 0x0000, 0x00CB, 0x0000, 0x023E, 0x0000, 0xFEDF, ++ 0x0000, 0xFFE3, 0x0000, 0xFF3E, 0x0000, 0x02A8, 0x0000, 0xFF1A, ++ 0x0000, 0xFFBC, 0x0000, 0xFE23, 0x0000, 0x0321, 0x0000, 0x00E3, ++ 0x0000, 0x00C9, 0x0000, 0x01EB, 0x0000, 0xFF02, 0x0000, 0x0013, ++ 0x0000, 0xFF59, 0x0000, 0x0249, 0x0000, 0xFF5E, 0x0000, 0xFFBE, ++ 0x0000, 0xFE80, 0x0000, 0x02C2, 0x0000, 0x00EA, 0x0000, 0x00C4, ++ 0x0000, 0x01F4, 0x0000, 0xFEE7, 0x0000, 0x0025, 0x0000, 0xFF57, ++ 0x0000, 0x0252, 0x0000, 0xFF56, 0x0000, 0xFFB7, 0x0000, 0xFE63, ++ 0x0000, 0x02E7, 0x0000, 0x00F3, 0x0000, 0x00BF, 0x0000, 0x01FF, ++ 0x0000, 0xFEC5, 0x0000, 0x003D, 0x0000, 0xFF55, 0x0000, 0x025F, ++ 0x0000, 0xFF4C, 0x0000, 0xFFAB, 0x0000, 0xFE3D, 0x0000, 0x0318, ++ 0x0000, 0x00DF, 0x0000, 0x00B4, 0x0000, 0x0201, 0x0000, 0xFED8, ++ 0x0000, 0x0027, 0x0000, 0xFF6D, 0x0000, 0x0274, 0x0000, 0xFF1F, ++ 0x0000, 0xFFAE, 0x0000, 0xFE0F, 0x0000, 0x0343, 0x0000, 0x00FC, ++ 0x0000, 0x00BB, 0x0000, 0x020A, 0x0000, 0xFEA2, 0x0000, 0x0055, ++ 0x0000, 0xFF53, 0x0000, 0x026C, 0x0000, 0xFF41, 0x0000, 0xFF9E, ++ 0x0000, 0xFE19, 0x0000, 0x0349, 0x0000, 0x0106, 0x0000, 0x00B7, ++ 0x0000, 0x0217, 0x0000, 0xFE74, 0x0000, 0x0075, 0x0000, 0xFF50, ++ 0x0000, 0x027D, 0x0000, 0xFF33, 0x0000, 0xFF8C, 0x0000, 0xFDEA, ++ 0x0000, 0x038A, 0x0000, 0x00F7, 0x0000, 0x00A8, 0x0000, 0x01DB, ++ 0x0000, 0xFE6A, 0x0000, 0x00BB, 0x0000, 0xFF83, 0x0000, 0x0229, ++ 0x0000, 0xFF54, 0x0000, 0xFFA2, 0x0000, 0xFDE4, 0x0000, 0x037A, ++ 0x0000, 0x0114, 0x0000, 0x00B2, 0x0000, 0x022C, 0x0000, 0xFE29, ++ 0x0000, 0x00AB, 0x0000, 0xFF4C, 0x0000, 0x029A, 0x0000, 0xFF1A, ++ 0x0000, 0xFF69, 0x0000, 0xFDA0, 0x0000, 0x03F7, 0x0000, 0x010E, ++ 0x0000, 0x00A4, 0x0000, 0x0212, 0x0000, 0xFDCA, 0x0000, 0x0125, ++ 0x0000, 0xFF81, 0x0000, 0x023D, 0x0000, 0xFF42, 0x0000, 0xFF8E, ++ 0x0000, 0xFD81, 0x0000, 0x03F1, 0x0000, 0x0120, 0x0000, 0x00AF, ++ 0x0000, 0x0240, 0x0000, 0xFDDC, 0x0000, 0x00E4, 0x0000, 0xFF49, ++ 0x0000, 0x02BC, 0x0000, 0xFEFC, 0x0000, 0xFF44, 0x0000, 0xFD57, ++ 0x0000, 0x0465, 0x0000, 0x0134, 0x0000, 0x00AC, 0x0000, 0x0264, ++ 0x0000, 0xFD43, 0x0000, 0x0159, 0x0000, 0xFF47, 0x0000, 0x0313, ++ 0x0000, 0xFEA6, 0x0000, 0xFEF5, 0x0000, 0xFCD9, 0x0000, 0x0531, ++ // 002c, 4 ++ 0x0080, 0x001A, 0x0034, 0x1388, ++ // 0034, 4 ++ 0x03E8, 0x0000, 0x07D0, 0x0001, ++ // 4820, 2, ++ 0x0002, 0x4320, ++ // 486C, 2 ++ 0x0002, 0x432F, ++ // 4860, 2 ++ 0x0002, 0x44C0, ++ // 4804, 2 ++ 0x0002, 0x44DF, ++ // 4854, 2 ++ 0x0002, 0x1D8B, ++ // 487C, 2 ++ 0x0002, 0x4510, ++ // 4894, 2 ++ 0x0002, 0x4516, ++ // 482C, 2 ++ 0x0002, 0x451E, ++ // 4834, 2 ++ 0x0002, 0x4522, ++ // 4800, 2 ++ 0x0002, 0x4536, ++ // 4868, 2 ++ 0x0002, 0x4538, ++ // 4C80, 1104 ++ 0x0003, 0x1DB3, 0x0000, 0x0632, 0x0009, 0x0006, 0x0000, 0x661F, ++ 0x0009, 0x0004, 0x0000, 0x6620, 0x0009, 0x0118, 0x0000, 0x6725, ++ 0x0009, 0x014e, 0x0000, 0x6726, 0x0009, 0x0118, 0x0000, 0x6532, ++ 0x0009, 0x014e, 0x0000, 0x6533, 0x0000, 0x01FF, 0x0000, 0x0958, ++ 0x0000, 0x0960, 0x0000, 0x0968, 0x0000, 0x0970, 0x0000, 0x0978, ++ 0x0000, 0x4F23, 0x0000, 0x4722, 0x0000, 0x024B, 0x0000, 0x01A3, ++ 0x0000, 0x091E, 0x000B, 0xFE26, 0x0009, 0x8480, 0x0000, 0x08CB, ++ 0x000B, 0xFE27, 0x0009, 0x001E, 0x0000, 0x08CB, 0x0009, 0xFE26, ++ // 4D00 ++ 0x0000, 0x6621, 0x0000, 0x7A22, 0x0009, 0xFE26, 0x0000, 0x6623, ++ 0x0003, 0x449B, 0x000B, 0xFE27, 0x0000, 0x085B, 0x000A, 0x0000, ++ 0x0000, 0x0153, 0x0006, 0x434B, 0x0002, 0x434E, 0x000B, 0xFE26, ++ 0x0009, 0xFFFF, 0x0000, 0x08CB, 0x0009, 0x0010, 0x0000, 0x662A, ++ 0x000B, 0xFE26, 0x0000, 0x0873, 0x0000, 0x5620, 0x000B, 0x0000, ++ 0x0000, 0x4A19, 0x0000, 0x0156, 0x0007, 0x435B, 0x000A, 0x0001, ++ 0x0000, 0x0155, 0x0004, 0x435B, 0x0002, 0x4363, 0x0000, 0x5219, ++ 0x0000, 0x042C, 0x0000, 0x4A19, 0x0000, 0x0054, 0x0000, 0x0166, ++ 0x0007, 0x4362, 0x0002, 0x4363, 0x0002, 0x4364, 0x0000, 0x0183, ++ 0x0000, 0x031B, 0x0005, 0x436A, 0x0009, 0x0205, 0x0000, 0x662A, ++ 0x000D, 0x0001, 0x0002, 0x43AE, 0x000B, 0x0000, 0x0000, 0x4A1A, ++ 0x0000, 0x0156, 0x0007, 0x4372, 0x000A, 0x0002, 0x0000, 0x0155, ++ 0x0004, 0x4372, 0x0002, 0x437A, 0x0000, 0x521A, 0x0000, 0x042C, ++ 0x0000, 0x4A1A, 0x0000, 0x0054, 0x0000, 0x0166, 0x0007, 0x4379, ++ 0x0002, 0x437A, 0x0002, 0x437B, 0x0000, 0x0183, 0x0000, 0x031B, ++ 0x0005, 0x4381, 0x0009, 0x0003, 0x0000, 0x662A, 0x000D, 0x0002, ++ // 4E00 ++ 0x0002, 0x43AE, 0x000B, 0x0000, 0x0000, 0x4A1B, 0x0000, 0x0156, ++ 0x0007, 0x4389, 0x000A, 0x0003, 0x0000, 0x0155, 0x0004, 0x4389, ++ 0x0002, 0x4391, 0x0000, 0x521B, 0x0000, 0x042C, 0x0000, 0x4A1B, ++ 0x0000, 0x0054, 0x0000, 0x0166, 0x0007, 0x4390, 0x0002, 0x4391, ++ 0x0002, 0x4392, 0x0000, 0x0183, 0x0000, 0x031B, 0x0005, 0x4396, ++ 0x000D, 0x0003, 0x0002, 0x43AE, 0x000B, 0x0000, 0x0000, 0x4A1C, ++ 0x0000, 0x0156, 0x0007, 0x439E, 0x000A, 0x0004, 0x0000, 0x0155, ++ 0x0004, 0x439E, 0x0002, 0x43A6, 0x0000, 0x521C, 0x0000, 0x042C, ++ 0x0000, 0x4A1C, 0x0000, 0x0054, 0x0000, 0x0166, 0x0007, 0x43A5, ++ 0x0002, 0x43A6, 0x0002, 0x43A7, 0x0000, 0x0183, 0x0000, 0x031B, ++ 0x0005, 0x43AD, 0x000D, 0x0004, 0x0009, 0x0010, 0x0000, 0x662A, ++ 0x0002, 0x43AE, 0x000D, 0x0005, 0x0000, 0x7620, 0x0000, 0x4F4D, ++ 0x0000, 0x474C, 0x0000, 0x028B, 0x0000, 0x4725, 0x0000, 0x028B, ++ 0x0000, 0x091F, 0x0000, 0x4F4E, 0x0000, 0x474C, 0x0000, 0x028B, ++ 0x0000, 0x4726, 0x0000, 0x028B, 0x0000, 0x6E25, 0x0000, 0x462A, ++ 0x0000, 0x0439, 0x0000, 0x6629, 0x0000, 0x4629, 0x000A, 0x000B, ++ // 4F00 ++ 0x0000, 0x0251, 0x0000, 0x01D3, 0x000A, 0x4260, 0x0000, 0x005A, ++ 0x0000, 0x6A2B, 0x0000, 0x4E2B, 0x0000, 0x0853, 0x0000, 0x6A21, ++ 0x0000, 0x7E22, 0x0000, 0x4E2B, 0x0000, 0x0183, 0x0000, 0x0853, ++ 0x0000, 0x6A23, 0x0000, 0x4625, 0x0000, 0x6624, 0x0003, 0x4485, ++ 0x0000, 0x6628, 0x0000, 0x5629, 0x0000, 0x0185, 0x0000, 0x4E2A, ++ 0x0000, 0x2CFF, 0x0000, 0x015D, 0x0007, 0x43D8, 0x0002, 0x43F0, ++ 0x0000, 0x462B, 0x000A, 0x000B, 0x0000, 0x0051, 0x0000, 0x662B, ++ 0x0000, 0x4E2B, 0x0000, 0x0853, 0x0000, 0x6A21, 0x0000, 0x7E22, ++ 0x0000, 0x4E2B, 0x0000, 0x0183, 0x0000, 0x0853, 0x0000, 0x6A23, ++ 0x0000, 0x4625, 0x0000, 0x6624, 0x0003, 0x4485, 0x0000, 0x090E, ++ 0x0000, 0x4A28, 0x0000, 0x0156, 0x0007, 0x43EC, 0x0002, 0x43EE, ++ 0x0000, 0x7A28, 0x0000, 0x7629, 0x0000, 0x0185, 0x0002, 0x43D3, ++ 0x0000, 0x461F, 0x000A, 0x000B, 0x0000, 0x0251, 0x0000, 0x01D3, ++ 0x000A, 0x4260, 0x0000, 0x005A, 0x0000, 0x6A2B, 0x0000, 0x4E2B, ++ 0x0000, 0x0853, 0x0000, 0x6A21, 0x0000, 0x7E22, 0x0000, 0x4E2B, ++ 0x0000, 0x0183, 0x0000, 0x0853, 0x0000, 0x6A23, 0x0000, 0x4625, ++ // 5000 ++ 0x0000, 0x6624, 0x0003, 0x4485, 0x0000, 0x090E, 0x0000, 0x4629, ++ 0x0000, 0x4A1F, 0x0000, 0x0151, 0x0004, 0x4409, 0x0000, 0x0602, ++ 0x0002, 0x4416, 0x0000, 0x4A28, 0x0000, 0x02B2, 0x0000, 0x0913, ++ 0x0000, 0x4A16, 0x0000, 0x0153, 0x0006, 0x4410, 0x0002, 0x4415, ++ 0x0000, 0x461F, 0x0000, 0x6629, 0x0000, 0x7A28, 0x0000, 0x0602, ++ 0x0002, 0x4416, 0x0000, 0x0622, 0x0000, 0x0652, 0x0005, 0x4422, ++ 0x0000, 0x4628, 0x0000, 0x4A17, 0x0000, 0x0151, 0x0007, 0x441D, ++ 0x0002, 0x4421, 0x0000, 0x0612, 0x0009, 0x0000, 0x0000, 0x661E, ++ 0x0000, 0x0622, 0x0002, 0x442B, 0x0000, 0x4628, 0x0000, 0x4A18, ++ 0x0000, 0x0151, 0x0006, 0x4427, 0x0002, 0x442B, 0x0000, 0x0632, ++ 0x0009, 0x0001, 0x0000, 0x661E, 0x0000, 0x0622, 0x000B, 0x0000, ++ 0x0000, 0x4629, 0x000A, 0x0005, 0x0000, 0x0151, 0x0007, 0x4435, ++ 0x0000, 0x4620, 0x000A, 0x0002, 0x0000, 0x0151, 0x0006, 0x4435, ++ 0x0000, 0x0183, 0x0000, 0x031B, 0x0005, 0x443B, 0x0000, 0x0632, ++ 0x0000, 0x0622, 0x0009, 0x0002, 0x0000, 0x6629, 0x0000, 0x0642, ++ 0x0005, 0x447B, 0x0000, 0x0605, 0x0000, 0x0606, 0x0000, 0x4629, ++ // 5100 ++ 0x000A, 0x000B, 0x0000, 0x0251, 0x0000, 0x01D3, 0x000A, 0x4260, ++ 0x0000, 0x0053, 0x000A, 0x000A, 0x0000, 0x0053, 0x0000, 0x6E2B, ++ 0x0000, 0x8EA0, 0x0005, 0x444D, 0x0009, 0xFF40, 0x0000, 0x662C, ++ 0x0002, 0x444F, 0x0009, 0xFD1C, 0x0000, 0x662C, 0x000D, 0x0001, ++ 0x000A, 0x000A, 0x0000, 0x0155, 0x0007, 0x4454, 0x0002, 0x4460, ++ 0x0000, 0x4E2C, 0x0000, 0x0193, 0x0000, 0x6E2C, 0x0000, 0x0183, ++ 0x0000, 0x522B, 0x0000, 0x0194, 0x0000, 0x722B, 0x0000, 0x0184, ++ 0x0000, 0x0864, 0x0000, 0x08E3, 0x0000, 0x0185, 0x0002, 0x4450, ++ 0x0000, 0x0652, 0x0005, 0x4472, 0x0000, 0x4E2B, 0x0000, 0x0193, ++ 0x0000, 0x6E2B, 0x0000, 0x0183, 0x0000, 0x085B, 0x000A, 0x0100, ++ 0x0000, 0x029A, 0x0000, 0x0913, 0x0000, 0x6F26, 0x0000, 0x4E2B, ++ 0x0000, 0x085B, 0x000A, 0x0100, 0x0000, 0x029A, 0x0000, 0x0913, ++ 0x0000, 0x6F25, 0x0002, 0x447A, 0x000A, 0x0100, 0x0000, 0x02BA, ++ 0x0000, 0x0913, 0x0000, 0x6F25, 0x000B, 0x0100, 0x0000, 0x4625, ++ 0x0000, 0x028B, 0x0000, 0x6F26, 0x0002, 0x447D, 0x0000, 0x0625, ++ 0x0000, 0x0626, 0x0000, 0x4629, 0x0000, 0x661F, 0x0000, 0x0838, ++ // 5200 ++ 0x0000, 0x0830, 0x0000, 0x0828, 0x0000, 0x0820, 0x0000, 0x0818, ++ 0x0000, 0x01FF, 0x0000, 0x0958, 0x0000, 0x4621, 0x0000, 0x4A22, ++ 0x0003, 0x4493, 0x0000, 0x090B, 0x0000, 0x4623, 0x0000, 0x4A24, ++ 0x0003, 0x4493, 0x0000, 0x0059, 0x0000, 0x01FB, 0x0005, 0x4491, ++ 0x0009, 0xFFFF, 0x0000, 0x0818, 0x0000, 0x01FF, 0x0000, 0x008A, ++ 0x0000, 0x0212, 0x0000, 0x01D1, 0x0000, 0x01C2, 0x0000, 0x0352, ++ 0x0005, 0x449A, 0x0009, 0xFFFF, 0x0000, 0x01FF, 0x0000, 0x0958, ++ 0x0000, 0x0960, 0x0000, 0x0978, 0x0000, 0x4A21, 0x0000, 0x080A, ++ 0x0000, 0x0852, 0x0000, 0x4E22, 0x000C, 0x0000, 0x000F, 0x0020, ++ 0x0000, 0x060A, 0x0000, 0x0404, 0x0000, 0x01FB, 0x0005, 0x44A9, ++ 0x0000, 0x062A, 0x0000, 0x05AF, 0x0005, 0x44AC, 0x0000, 0x0540, ++ 0x0000, 0x0402, 0x0000, 0x059F, 0x0005, 0x44B0, 0x0000, 0x0520, ++ 0x0000, 0x0401, 0x0000, 0x064A, 0x0004, 0x44B5, 0x0000, 0x015C, ++ 0x0007, 0x44B7, 0x0000, 0x00DC, 0x0000, 0x0510, 0x0000, 0x0197, ++ 0x0004, 0x44A4, 0x0000, 0x4E23, 0x0000, 0x088B, 0x0000, 0x08D3, ++ 0x0000, 0x0838, 0x0000, 0x0820, 0x0000, 0x0818, 0x0000, 0x01FF, ++ // 5300 ++ 0x0000, 0x060D, 0x0000, 0x513F, 0x000F, 0x0008, 0x0000, 0x00FC, ++ 0x0000, 0x5540, 0x0000, 0x00FD, 0x0000, 0x026C, 0x0000, 0x01A7, ++ 0x0000, 0x52A5, 0x0000, 0x0414, 0x0000, 0x0267, 0x0000, 0x01A7, ++ 0x0000, 0x7E50, 0x000F, 0x0000, 0x0000, 0x7E51, 0x0000, 0x7E53, ++ 0x0000, 0x7E55, 0x000B, 0x0000, 0x0002, 0x44D4, 0x0000, 0x0183, ++ 0x0000, 0x5EA6, 0x0000, 0x017B, 0x0006, 0x21A8, 0x000F, 0x4230, ++ 0x0000, 0x001F, 0x0000, 0x0877, 0x0000, 0x5253, 0x0000, 0x0074, ++ 0x0000, 0x7254, 0x000F, 0xFE31, 0x0002, 0x218D, 0x0000, 0x5E01, ++ 0x0000, 0x05F5, 0x0005, 0x004C, 0x0000, 0x04F5, 0x0000, 0x7E01, ++ 0x0003, 0x0213, 0x0000, 0x46AF, 0x0000, 0x0948, 0x0000, 0x4722, ++ 0x0000, 0x0948, 0x0000, 0x4723, 0x0000, 0x0948, 0x0000, 0x060A, ++ 0x0003, 0x05DC, 0x0000, 0x062A, 0x0003, 0x05DC, 0x0000, 0x060A, ++ 0x0003, 0x06EC, 0x0000, 0x675E, 0x0000, 0x062A, 0x0003, 0x06EC, ++ 0x0000, 0x675F, 0x0009, 0x44FA, 0x0000, 0x0948, 0x0009, 0xFFFB, ++ 0x0000, 0x0048, 0x0002, 0x0564, 0x0000, 0x0808, 0x0000, 0x6723, ++ 0x0000, 0x0808, 0x0000, 0x6722, 0x0000, 0x0808, 0x0000, 0x66AF, ++ // 5400 ++ 0x0003, 0x02BC, 0x0000, 0x7E67, 0x0000, 0x7A68, 0x0000, 0x7269, ++ 0x0003, 0x1C3B, 0x0000, 0x7E8A, 0x0003, 0x1C55, 0x0000, 0x7E8B, ++ 0x0000, 0x5EA4, 0x0000, 0x7D07, 0x0000, 0x5F23, 0x0003, 0x1CD1, ++ 0x0003, 0x01AF, 0x0003, 0x1B8A, 0x0003, 0x1B90, 0x0002, 0x004C, ++ 0x0000, 0x0640, 0x0004, 0x4514, 0x0000, 0x0641, 0x0005, 0x4515, ++ 0x0000, 0x0634, 0x0002, 0x225D, 0x0000, 0x0654, 0x0005, 0x451A, ++ 0x0000, 0x8EA2, 0x0004, 0x451C, 0x0000, 0x060D, 0x0000, 0x01FF, ++ 0x0000, 0x0614, 0x0002, 0x2163, 0x0003, 0x021E, 0x0000, 0x5E98, ++ 0x0000, 0x7D04, 0x0000, 0x01FF, 0x0000, 0x466E, 0x0000, 0x240F, ++ 0x000A, 0x0001, 0x0000, 0x014A, 0x0004, 0x010A, 0x0000, 0x4601, ++ 0x0000, 0x0591, 0x0004, 0x4531, 0x0000, 0x0590, 0x0004, 0x012C, ++ 0x0003, 0x0213, 0x0000, 0x4602, 0x0000, 0x0490, 0x0000, 0x6602, ++ 0x0002, 0x0017, 0x0000, 0xBAA1, 0x0004, 0x4535, 0x0000, 0x8EA2, ++ 0x0005, 0x012C, 0x0002, 0x0082, 0x0008, 0x4570, 0x0002, 0x001E, ++ 0x0000, 0x4723, 0x0000, 0x4AAD, 0x0000, 0x0151, 0x0007, 0x1E8F, ++ 0x0006, 0x4545, 0x0000, 0x4722, 0x0000, 0x4AAA, 0x0000, 0x0151, ++ // 5500 ++ 0x0007, 0x1E8F, 0x0009, 0x0100, 0x0000, 0x010C, 0x0007, 0x1E8F, ++ 0x0000, 0x01FF, 0x0000, 0x6B23, 0x0000, 0x0620, 0x0000, 0x01FF, ++ // 0062, 4 ++ 0x0200, 0x0600, 0x0C00, 0x1800, ++ // 006A, 2 ++ 0x2800, 0x3800, ++ // 0186, 2 ++ 0x2903, 0x8D20 ++}; ++ ++ ++static int adcm3800Patch(void) ++{ ++ int err; ++ int ipatch, idata; ++ for (ipatch = 0, idata = 0; patch3800addr[ipatch] != 0; ipatch++) ++ { ++ int addr = patch3800addr[ipatch]; ++ int len = patch3800len[ipatch]; ++ ddbg_print("write %d length to addr %x", len, addr); ++ err = adcm3800_write_regs (addr, &patch3800data[idata], len); ++ if (err < 0) ++ { ++ dbg_print("error: fail to upgrade patch code"); ++ return (err); ++ } ++ idata += len; ++ } ++ dbg_print("ok: write %d patch code", idata); ++ if(idata*2 != sizeof(patch3800data)) ++ { ++ dbg_print("error: patch len wrong! %d:%d", idata, sizeof(patch3800data)/2); ++ return -1; ++ } ++ return 0; ++} ++ ++ ++static int adcm3800_firmware_upgrade(void) ++{ ++ u8 valueb; ++ u16 valuew; ++ ++ //adcm3800_write(0x3040, 0x0100); ++ ++ int to = 200; ++ while(to>0) ++ { ++ adcm3800_read(0x0004, &valuew); ++ if(valuew==0x0000) ++ break; ++ mdelay(5); ++ to -= 1; ++ } ++ ++ dbg_print("start patch"); ++ adcm3800Patch(); ++ dbg_print("end patch"); ++ adcm3800_read_byte(0x084b, &valueb); ++ ++ return 0; ++} ++ ++static int adcm3800_init_regs(void) ++{ ++ u16 valuew; ++/* ++#Setting pixel ram and sensor registers ++#set block 14 ++w 0a04 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0005 0005 0805 0005 0007 0007 0007 0007 0107 0107 0187 0187 0187 0183 0183 0183 ++ ++#set block 15 ++w 0a80 0183 0183 0183 0183 0183 0183 0183 0183 ++w 0a90 0181 0001 0000 0000 0000 0000 0008 0008 ++w 0aa0 0008 0008 0079 0079 0079 0079 0079 0079 ++w 0ab0 0079 0079 0079 0079 0079 0079 0079 0079 ++ ++#set block 16 ++w 0b00 0079 0079 0079 0079 0079 0071 0035 0035 ++w 0b10 0035 0035 0037 0837 0037 0037 0137 0137 ++w 0b20 01b7 01b7 01b3 01b3 01b3 01b3 01b3 01b3 ++w 0b30 01b3 01b3 01b3 01b3 01b3 01b3 01b1 0071 ++ ++#set block 17 ++w 0b80 0071 0071 0071 0071 0071 0071 0061 0021 0020 0000 0000 0000 0000 0000 ++*/ ++ static u16 reg_0a04[] = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0005, 0x0005, 0x0805, 0x0005, 0x0007, 0x0007, 0x0007, 0x0007, 0x0107, 0x0107, 0x0187, 0x0187, 0x0187, 0x0183, 0x0183, 0x0183}; ++ adcm3800_write_regs (0x0a04, reg_0a04, 30); ++ ++ static u16 reg_0a80[] = { ++ 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, 0x0183, ++ 0x0181, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0008, ++ 0x0008, 0x0008, 0x0079, 0x0079, 0x0079, 0x0079, 0x0079, 0x0079, ++ 0x0079, 0x0079, 0x0079, 0x0079, 0x0079, 0x0079, 0x0079, 0x0079}; ++ adcm3800_write_regs (0x0a80, reg_0a80, 32); ++ ++ static u16 reg_0b00[] = { ++ 0x0079, 0x0079, 0x0079, 0x0079, 0x0079, 0x0071, 0x0035, 0x0035, ++ 0x0035, 0x0035, 0x0037, 0x0837, 0x0037, 0x0037, 0x0137, 0x0137, ++ 0x01b7, 0x01b7, 0x01b3, 0x01b3, 0x01b3, 0x01b3, 0x01b3, 0x01b3, ++ 0x01b3, 0x01b3, 0x01b3, 0x01b3, 0x01b3, 0x01b3, 0x01b1, 0x0071}; ++ adcm3800_write_regs (0x0b00, reg_0b00, 32); ++ ++ static u16 reg_0b80[] = { ++ 0x0071, 0x0071, 0x0071, 0x0071, 0x0071, 0x0071, 0x0061, 0x0021, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; ++ adcm3800_write_regs (0x0b80, reg_0b80, 14); ++ ++/* ++# Sensor settings ++w8 081e 00 ++w8 081f 00 ++w8 0820 00 ++w8 0821 00 ++w8 0822 00 ++w8 0823 00 ++w8 0824 00 ++w8 0825 00 ++w8 0828 02 ++w8 0845 b0 ++w8 0848 06 ++w8 0849 03 ++w8 084d 20 ++*/ ++ adcm3800_write_byte(0x081e, 0x00); ++ adcm3800_write_byte(0x081f, 0x00); ++ adcm3800_write_byte(0x0820, 0x00); ++ adcm3800_write_byte(0x0821, 0x00); ++ adcm3800_write_byte(0x0822, 0x00); ++ adcm3800_write_byte(0x0823, 0x00); ++ adcm3800_write_byte(0x0824, 0x00); ++ adcm3800_write_byte(0x0825, 0x00); ++ adcm3800_write_byte(0x0828, 0x02); ++ adcm3800_write_byte(0x0845, 0xb0); ++ adcm3800_write_byte(0x0848, 0x06); ++ adcm3800_write_byte(0x0849, 0x03); ++ adcm3800_write_byte(0x084D, 0x20); ++/* ++# Purple sky fix ++w8 84f F8 ++*/ ++ adcm3800_write_byte(0x084f, 0xF8); ++ ++/* ++#r 0112 1 # Return:8280 ++w 0112 c680 # PROC_CTRL_V ++#r 0132 1 # Return:0280 ++w 0132 4680 # PROC_CTRL_S ++w 014a 0015 # Auto Black Level Target ++#r 0008 1 # Return:0b84 ++// delete w 0008 0b04 # Image Size and Orientation, still: SXGA, Video: QQVGA ++*/ ++ // turn on AV ++ // sharpness ++ //adcm3800_write(0x0112, 0x4e80); // high sharpness ++ //adcm3800_write(0x0132, 0x4e80); ++ adcm3800_write(0x0112, 0x4a80); // medium sharpness ++ adcm3800_write(0x0132, 0x4a80); ++ //adcm3800_write(0x0112, 0x4680); // low sharpness ++ //adcm3800_write(0x0132, 0x4680); ++ //adcm3800_write(0x0112, 0x4280); // no sharpness ++ //adcm3800_write(0x0132, 0x4280); ++ adcm3800_write(0x014a, 0x0015); ++ ++/* ++# AWB setting ++w 0174 010d # AWB Default Red/Green Ratio ++w 017a 0185 # AWB Default Blue/Green Ratio ++w 017c 0108 # AWB Tolerance Acquire ++w 017e 0110 # AWB Tolerance Monitor ++*/ ++ // AWB ++ adcm3800_write(0x0174, 0x010d); ++ adcm3800_write(0x017a, 0x0185); ++ adcm3800_write(0x017c, 0x0108); ++ adcm3800_write(0x017e, 0x0110); ++ ++ // 0x00e0, 6 ++ static u16 reg_00e0[] = { ++ 0x003c, 0x00c8, 0x0200, 0x0130, 0x0180, 0x003c ++ }; ++ adcm3800_write_regs (0x00e0, reg_00e0, 6); ++ ++/* ++#set block 00, AWB setting ++w 0028 028f 0333 a3d7 001a 0021 c350 0bb8 01f4 0064 0001 0001 ++#set block 00 ++w 0062 0200 0600 0c00 1800 2800 3800 ++*/ ++#if 0 ++ static u16 reg_0028[] = { ++ 0x028f, 0x0333, 0xa3d7, 0x001a, 0x0021, 0xc350, 0x0bb8, 0x01f4, 0x0064, 0x0001, 0x0001}; ++ adcm3800_write_regs (0x0028, reg_0028, 11); ++ static u16 reg_0062[] = { ++ 0x0200, 0x0600, 0x0c00, 0x1800, 0x2800, 0x3800}; ++ adcm3800_write_regs (0x0062, reg_0062, 6); ++#endif ++ ++/* ++# 70% Vignetting Correction (7/27/04 - BB) ++w 10a6 248 1d0 248 1d0 260 160 0f6 0f6 0f2 ++ ++w 1800 0F1 102 111 120 12F 13F 14B 157 165 171 17E 18A 197 1A3 1AB 1B4 1BB 1C3 1C6 1CB 1CA 1C6 1C2 1BB 1B4 1AE 1A9 1A3 19E 198 193 18D ++w 1840 0E0 0EF 0FC 108 113 11F 12A 136 141 14D 158 161 16D 176 17E 186 18D 191 196 198 198 197 195 191 18A 183 17A 170 165 159 14C 13F ++w 1880 0F8 106 110 11A 124 12D 136 140 14B 154 15D 167 16F 178 180 188 18F 196 19C 1A0 1A4 1A6 1A8 1A7 1A6 1A4 1A0 19C 195 18E 186 17C ++*/ ++ static u16 reg_10a6[] = { ++ 0x0248, 0x01d0, 0x0248, 0x01d0, 0x0260, 0x0160, 0x00f6, 0x00f6, 0x00f2 ++ }; ++ adcm3800_write_regs (0x10a6, reg_10a6, 9); ++ // Red vignetting data ++ static u16 reg_1800[] = { ++ 0x00F1, 0x0102, 0x0111, 0x0120, 0x012F, 0x013F, 0x014B, 0x0157, ++ 0x0165, 0x0171, 0x017E, 0x018A, 0x0197, 0x01A3, 0x01AB, 0x01B4, ++ 0x01BB, 0x01C3, 0x01C6, 0x01CB, 0x01CA, 0x01C6, 0x01C2, 0x01BB, ++ 0x01B4, 0x01AE, 0x01A9, 0x01A3, 0x019E, 0x0198, 0x0193, 0x018D ++ }; ++ adcm3800_write_regs (0x1800, reg_1800, 32); ++ // Green vignetting data ++ static u16 reg_1840[] = { ++ 0x00E0, 0x00EF, 0x00FC, 0x0108, 0x0113, 0x011F, 0x012A, 0x0136, ++ 0x0141, 0x014D, 0x0158, 0x0161, 0x016D, 0x0176, 0x017E, 0x0186, ++ 0x018D, 0x0191, 0x0196, 0x0198, 0x0198, 0x0197, 0x0195, 0x0191, ++ 0x018A, 0x0183, 0x017A, 0x0170, 0x0165, 0x0159, 0x014C, 0x013F ++ }; ++ adcm3800_write_regs (0x1840, reg_1840, 32); ++ // Blue vignetting data ++ static u16 reg_1880[] = { ++ 0x00F8, 0x0106, 0x0110, 0x011A, 0x0124, 0x012D, 0x0136, 0x0140, ++ 0x014B, 0x0154, 0x015D, 0x0167, 0x016F, 0x0178, 0x0180, 0x0188, ++ 0x018F, 0x0196, 0x019C, 0x01A0, 0x01A4, 0x01A6, 0x01A8, 0x01A7, ++ 0x01A6, 0x01A4, 0x01A0, 0x019C, 0x0195, 0x018E, 0x0186, 0x017C ++ }; ++ adcm3800_write_regs (0x1880, reg_1880, 32); ++ ++ // BPA ++ // BPA 5 Line Threshold, default to 0x0020 ++ adcm3800_write(0x1094, 0x0010); ++ ++/* ++#G1/G2 Threshold ++w 101a 23f ++*/ ++ adcm3800_write(0x101a, 0x023f); ++/* ++#NACC Settings - Dark Table ++w 282 2B3 FE0B 41 FF69 2B1 FEE4 FF6D FC69 528 ++*/ ++ static u16 reg_0282[] = { ++ 0x2B3, 0xFE0B, 0x41, 0xFF69, 0x2B1, 0xFEE4, 0xFF6D, 0xFC69, 0x528 ++ }; ++ adcm3800_write_regs (0x0282, reg_0282, 9); ++/* ++#NACC Settings - NACC Table ++w 250 96 0 0 100 ++*/ ++ static u16 reg_0250[] = { ++ 0x0096, 0x0000, 0x0000, 0x0100, 0x0ea6, 0x0060, 0x09c4, 0x0080, ++ 0x04e2, 0x00a0, 0x0271, 0x00c0, 0x0000, 0x0100 ++ }; ++ adcm3800_write_regs (0x0250, reg_0250, 14); ++/* ++#PI control ++w 2e A4 EC ++*/ ++ adcm3800_write(0x002e, 0x00A4); ++ adcm3800_write(0x0030, 0x00EC); ++ ++/* ++#Sunlight oscillation ++#Set bit 4 of 0x142 ++# auto function control, select Xenon flash mode and enabled auto exposure deliberate overexposure ++w 142 1011 ++ ++#Turn NACC on ++w 140 1B ++*/ ++ //adcm3800_write(0x0142, 0x1011); ++ adcm3800_write(EREG_AF_CTRL2, 0x1011); ++ //adcm3800_write(0x0140, 0x001B); ++ adcm3800_write(EREG_AF_CTRL1, 0x001b); // enable AE AWB NACC ABL ++ ++ dbg_print("end"); ++ return 0; ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/adcm3800_hw.h linux-2.6.16/drivers/media/video/adcm3800_hw.h +--- linux-2.6.16.orig/drivers/media/video/adcm3800_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adcm3800_hw.h 2006-06-03 11:14:56.433310088 +0200 +@@ -0,0 +1,534 @@ ++/*================================================================================ ++ ++ Header Name: adcm3800_hw.h ++ ++General Description: Camera module adcm3800 interface header file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 12/15/2003 LIBdd35749 Created ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++wangfei(w20239) 03/08/2004 LIBdd84578 Photo effects setting ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef _PXA_ADCM3800_HW_H__ ++#define _PXA_ADCM3800_HW_H__ ++ ++#include "camera.h" ++ ++/*********************************************************************** ++ * ++ * Constants ++ * ++ ***********************************************************************/ ++ ++// Revision constants ++#define PIPE_REV 0x68 ++//#define PIPE_REV_NEW 0x68 ++#define SENSOR_REV 0x68 ++ ++// Others ++#define adcm3800__TIMEOUT 400 // times to timeout. ++ ++// Non JEPG Output Format ++#define O_FORMAT_888RGB 0 //0b0000 // 888 RGB (1 pixel in 3 bytes ) ++#define O_FORMAT_666_A_RGB 1 //0b0001 // 666 A RGB (tight pack, 4 pixels in 9 bytes) ++#define O_FORMAT_666_B_RGB 2 //0b0010 // 666 B RGB (loose pack, 1 pixel in 3 bytes,left or right justified) ++#define O_FORMAT_565_RGB 3 //0b0011 // 565 RGB (1 pixel in 2 bytes) ++#define O_FORMAT_444_A_RGB 4 //0b0100 // 444 A RGB (tight pack, 2 pixels per 3 bytes, RG BR GB) ++#define O_FORMAT_444_B_RGB 5 //0b0101 // 444 B RGB (loose pack, 1 pixel per 2 bytes,RG B0 or 0R GB) ++#define O_FORMAT_444_C_RGV 6 //0b0110 // 444 C RGB (sparse pack, 1 pixel per three bytes,R0 G0 B0 or 0R 0G 0B) ++#define O_FORMAT_332_RGB 7 //0b0111 // 332 RGB (1 pixel in 1 byte) ++#define O_FORMAT_422_A_YCbYCr 8 //0b1000 // 4:2:2 A YCbYCr (Y1 Cb12 Y2 CRL2 order) ++#define O_FORMAT_422_B_YCbYCr 9 //0b1001 // 4:2:2 B YCbYCr (Cb12 Y1 CRL2 Y2 order) ++#define O_FORMAT_422_C_YCbYCr 10 //0b1010 // 4:2:2 C YCbYCr (Y1 CRL2 Y2 Cb12 order) ++#define O_FORMAT_422_D_YCbYCr 11 //0b1011 // 4:2:2 D YCbYCr (CRL2 Y1 Cb12 Y2 order) ++#define O_FORMAT_444_YCbYCr 12 //0b1100 // 4:4:4 YCbCr (1 pixels per 3 bytes) ++#define O_FORMAT_400_B_YCbYCr 13 //0b1101 // 4:0:0 YCbCr (Greyscale, 1 pixel per 1 byte) ++#define O_FORMAT_RAWBPA 14 //0b1110 // RAWBPA (with AWB and BPA) ++#define O_FORMAT_RAW 15 //0b1111 // RAW (without AWB and BPA) ++ ++#define O_FORMAT_NONE 65535 // ++ ++/************************************************************************************* ++ * ++ * Simple Control Registers Address ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define SREG_ID 0x0000 //Chip ID 0x0060 139 ++#define SREG_CONTROL 0x0002 //Camera control 0x0001 140 ++#define SREG_STATUS 0x0004 //Camera status 0x0004 142 ++#define SREG_CLK_FREQ 0x0006 //Input clock frequency 0x32c8 144 ++#define SREG_SIZE 0x0008 //Image size and orientation 0x0605 145 ++#define SREG_OUTPUT_FORMAT 0x000a //Output format 0x0909 147 ++#define SREG_EXPOSURE 0x000c //Exposure 0x03e8 149 ++#define SREG_EXP_ADJ 0x000e //Exposure adjustment 0x0000 150 ++#define SREG_ILLUM 0x0010 //Illumination 0x0000 151 ++#define SREG_FRAME_RATE 0x0012 //Requested frame rate 0x0096 152 ++#define SREG_A_FRAME_RATE 0x0016 //Actual frame rate 0x0096 154 ++#define SREG_SENSOR_WID_V 0x0018 //Sensor window width, video mode 0x0000 155 ++#define SREG_SENSOR_HGT_V 0x001a //Sensor window height, video mode 0x0000 156 ++#define SREG_OUTPUT_WID_V 0x001c //Output window width, video mode 0x0000 157 ++#define SREG_OUTPUT_HGT_V 0x001e //Output window height, video mode 0x0000 158 ++#define SREG_SENSOR_WID_S 0x0020 //Sensor window width, still mode 0x0000 159 ++#define SREG_SENSOR_HGT_S 0x0022 //Sensor window height, still mode 0x0000 160 ++#define SREG_OUTPUT_WID_S 0x0024 //Output window width, still mode 0x0000 161 ++#define SREG_OUTPUT_HGT_S 0x0026 //Output window height, still mode 0x0000 162 ++ ++/************************************************************************************* ++ * ++ * Expert Hardware Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define EREG_I_CLK_DIV 0x3000 //Initial clock divider 0x0001 166 ++#define EREG_CTL_CLK_DIV 0x3002 //Clock dividers for control ++ //and serial interfaces 0x4000 167 ++#define EREG_SEN_CLK_DIV 0x3004 //Sensor clock dividers 0x0000 168 ++#define EREG_IP_CLK_DIV 0x3006 //Clock dividers for image pipeline 0x0000 169 ++#define EREG_TST_MODE 0x3008 //Latched test mode 0x0000 170 ++#define EREG_SER_ADDR 0x300a //Serial interface device address 0x0053 171 ++#define EREG_SER_PARM 0x300c //Serial Interface parameters 0x0000 172 ++#define EREG_OUT_CTRL 0x300e //Output control 0x0000 173 ++#define EREG_PLL_CTRL 0x3010 //PLL control 0x0014 470 ++#define EREG_PLL_DIV_L 0x3012 //PLL divisors, large values 0x500C 471 ++#define EREG_PLL_DIV_S 0x3014 //PLL divisors, small values 0x500C 472 ++ ++/************************************************************************************* ++ * ++ * Expert Control Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define EREG_SZR_IN_WID_V 0x0100 //Sizer input width, video mode 0x0280 184 ++#define EREG_SZR_IN_HGT_V 0x0102 //Sizer input height, video mode 0x01e0 185 ++#define EREG_SZR_OUT_WID_V 0x0104 //Sizer output width, video mode 0x0140 186 ++#define EREG_SZR_OUT_HGT_V 0x0106 //Sizer output height, video mode 0x00f0 187 ++#define EREG_CPP_V 0x0108 //Clocks per pixel, video mode 0x0002 188 ++#define EREG_HBLANK_V 0x010a //Horizontal blanking period, video mode 0x0000 189 ++#define EREG_VBLANK_V 0x010c //Vertical blanking period, video mode 0x0000 190 ++#define EREG_MIN_MAX_F_V 0x010e //Frame convergence rates, video mode 0x0000 191 ++#define EREG_OUTPUT_CTRL_V 0x0110 //Output control, video mode 0x9019 192 ++#define EREG_PROC_CTRL_V 0x0112 //Processing control, video mode 0x0280 194 ++#define EREG_RPT_V 0x0114 //Row processing time, video mode 0x0546 196 ++#define EREG_HYSNC_PER_V 0x0116 //HSYNC period, video mode 0x0a8b 197 ++#define EREG_CLK_DIV_V 0x0118 //Clock divisors, video mode 0x0000 198 ++#define EREG_PARALLEL_CTRL_V 0x011a //Parallel output control, video mode 0x0003 199 ++#define EREG_SEN_CTRL_V 0x011c //Sensor control, video mode 0x0000 200 ++ ++#define EREG_SZR_IN_WID_S 0x0120 //Sizer input width, still mode 0x0280 202 ++#define EREG_SZR_IN_HGT_S 0x0122 //Sizer input height, still mode 0x01e0 203 ++#define EREG_SZR_OUT_WID_S 0x0124 //Sizer output width, still mode 0x0280 204 ++#define EREG_SZR_OUT_HGT_S 0x0126 //Sizer output height, still mode 0x01e0 205 ++#define EREG_CPP_S 0x0128 //Clocks per pixel, still mode 0x0002 206 ++#define EREG_HBLANK_S 0x012a //Horizontal blanking period, still mode 0x0000 207 ++#define EREG_VBLANK_S 0x012c //Vertical blanking period, still mode 0x0000 208 ++#define EREG_MIN_MAX_F_S 0x012e //Frame convergence rates, still mode 0x0002 209 ++#define EREG_OUTPUT_CTRL_S 0x0130 //Output control, still mode 0x8019 210 ++#define EREG_PROC_CTRL_S 0x0132 //Processing control, still mode 0x0280 212 ++#define EREG_RPT_S 0x0134 //Row processing time, still mode 0x0546 214 ++#define EREG_HYSNC_PER_S 0x0136 //HSYNC period, still mode 0x0545 215 ++#define EREG_CLK_DIV_S 0x0138 //Clock divisors, still mode 0x0000 216 ++#define EREG_PARALLEL_CTRL_S 0x013a //Parallel output control, still mode 0x0000 217 ++#define EREG_SEN_CTRL_S 0x013c //Sensor control, still mode 0x0000 218 ++ ++#define EREG_AF_CTRL1 0x0140 //Auto functions control 1 0x0013 220 ++#define EREG_AF_CTRL2 0x0142 //Auto functions control 2 0x0001 221 ++#define EREG_AF_STATUS 0x0144 //Auto functions status 0x0000 222 ++#define EREG_SOF_CODES 0x0146 //Start of frame codes 0xfeff 223 ++#define EREG_EOF_CODES 0x0148 //End of frame codes 0x0100 224 ++#define EREG_ABL_TARGET 0x014a //Auto black level target 0x0005 225 ++#define EREG_ABL_MAX_BIN 0x014c //Auto black level maximum bin 0x0003 226 ++#define EREG_ABL_MAX_BLACK 0x014e //Auto black level maximum black 0x0010 227 ++#define EREG_AE_GAIN_MIN 0x0150 //Auto exposure gain minimum 0x01c0 228 ++#define EREG_AE_GAIN_MIN_P 0x0152 //Auto exposure gain minimum, preferred 0x0200 229 ++#define EREG_AE_GAIN_MAX 0x0154 //Auto exposure gain maximum 0x0500 230 ++#define EREG_AE_GAIN_DFLT 0x0156 //Auto exposure gain default 0x0200 231 ++#define EREG_AE_ETIME_MIN 0x0158 //Auto exposure time minimum 0x0005 232 ++#define EREG_AE_ETIME_MAX 0x015a //Auto exposure time maximum 0x4e20 233 ++#define EREG_AE_ETIME_DFLT 0x015c //Auto exposure time default 0x03e8 234 ++#define EREG_AE_TARGET 0x015e //Auto exposure target 0x0040 235 ++#define EREG_AE_TOL_ACQ 0x0160 //Auto exposure tolerance acquire 0x0118 236 ++#define EREG_AE_TOL_MON 0x0162 //Auto exposure tolerance monitor 0x0118 237 ++#define EREG_AE_MARGIN 0x0164 //Auto exposure margin 0x0120 238 ++#define EREG_AE_DOE_FACTOR 0x0166 //AE deliberate overexposure factor 0x014e 239 ++#define EREG_AE_DOE_MARGIN 0x0168 //AE deliberate overexposure margin 0x0140 240 ++ ++#define EREG_AWB_RED_MIN 0x0170 //AWB minimum red/green ratio 0x00c0 242 ++#define EREG_AWB_RED_MAX 0x0172 //AWB maximum red/green ratio 0x01a6 243 ++#define EREG_AWB_RED_DFLT 0x0174 //AWB default red/green ratio 0x0134 244 ++#define EREG_AWB_BLUE_MIN 0x0176 //AWB minimum blue/green ratio 0x00c0 245 ++#define EREG_AWB_BLUE_MAX 0x0178 //AWB maximum blue/green ratio 0x02a4 246 ++#define EREG_AWB_BLUE_DFLT 0x017a //AWB default blue/green ratio 0x01e4 247 ++#define EREG_AWB_TOL_ACQ 0x017c //Auto white balance tolerance acquire 0x0110 248 ++#define EREG_AWB_TOL_MON 0x017e //Auto white balance tolerance monitor 0x0120 249 ++#define EREG_FIRMWARE_REV 0x0180 //Current firmware revision 0x0152 250 ++#define EREG_FLICK_CFG_1 0x0182 //Flicker configuration 1 0x2aeb 251 ++#define EREG_FLICK_CFG_2 0x0184 //Flicker configuration 2 0x0005 252 ++ ++#define EREG_MAX_SCLK 0x018a //Maximum sensor clock 0x1964 254 ++ ++#define EREG_CSC_00_V 0x0190 //Color conversion coefficient 00, video 0x0026 256 ++#define EREG_CSC_01_V 0x0192 //Color conversion coefficient 01, video 0x004b 256 ++#define EREG_CSC_02_V 0x0194 //Color conversion coefficient 02, video 0x000f 256 ++#define EREG_CSC_10_V 0x0196 //Color conversion coefficient 10, video 0x01ed 256 ++#define EREG_CSC_11_V 0x0198 //Color conversion coefficient 11, video 0x01db 256 ++#define EREG_CSC_12_V 0x019a //Color conversion coefficient 12, video 0x0038 256 ++#define EREG_CSC_20_V 0x019c //Color conversion coefficient 20, video 0x004f 256 ++#define EREG_CSC_21_V 0x019e //Color conversion coefficient 21, video 0x01be 256 ++#define EREG_CSC_22_V 0x01a0 //Color conversion coefficient 22, video 0x01f3 256 ++ ++#define EREG_CSC_OS0_V 0x01a2 //Color space conversion offset 0, video 0x0000 257 ++#define EREG_CSC_OS1_V 0x01a4 //Color space conversion offset 1, video 0x0080 257 ++#define EREG_CSC_OS2_V 0x01a6 //Color space conversion offset 2, video 0x0080 257 ++ ++#define EREG_CSC_00_S 0x01a8 //Color conversion coefficient 00, still 0x0026 258 ++#define EREG_CSC_01_S 0x01aa //Color conversion coefficient 01, still 0x004b 258 ++#define EREG_CSC_02_S 0x01ac //Color conversion coefficient 02, still 0x000f 258 ++#define EREG_CSC_10_S 0x01ae //Color conversion coefficient 10, still 0x01ed 258 ++#define EREG_CSC_11_S 0x01b0 //Color conversion coefficient 11, still 0x01db 258 ++#define EREG_CSC_12_S 0x01b2 //Color conversion coefficient 12, still 0x0038 258 ++#define EREG_CSC_20_S 0x01b4 //Color conversion coefficient 20, still 0x004f 258 ++#define EREG_CSC_21_S 0x01b6 //Color conversion coefficient 21, still 0x01be 258 ++#define EREG_CSC_22_S 0x01b8 //Color conversion coefficient 22, still 0x01f3 258 ++ ++#define EREG_CSC_OS0_S 0x01ba //Color space conversion offset 0, still 0x0000 259 ++#define EREG_CSC_OS1_S 0x01bc //Color space conversion offset 1, still 0x0080 259 ++#define EREG_CSC_OS2_S 0x01be //Color space conversion offset 2, still 0x0080 259 ++ ++ ++#define EREG_TM_COEF_00_V 0x01c0 //Tonemap coefficient 00, video 0x0000 261 ++#define EREG_TM_COEF_01_V 0x01c2 //Tonemap coefficient 01, video 0x0017 261 ++#define EREG_TM_COEF_02_V 0x01c4 //Tonemap coefficient 02, video 0x0032 261 ++#define EREG_TM_COEF_03_V 0x01c6 //Tonemap coefficient 03, video 0x0046 261 ++#define EREG_TM_COEF_04_V 0x01c8 //Tonemap coefficient 04, video 0x0056 261 ++#define EREG_TM_COEF_05_V 0x01ca //Tonemap coefficient 05, video 0x0064 261 ++#define EREG_TM_COEF_06_V 0x01cc //Tonemap coefficient 06, video 0x0071 261 ++#define EREG_TM_COEF_07_V 0x01ce //Tonemap coefficient 07, video 0x007c 261 ++#define EREG_TM_COEF_08_V 0x01d0 //Tonemap coefficient 08, video 0x0086 261 ++#define EREG_TM_COEF_09_V 0x01d2 //Tonemap coefficient 09, video 0x0099 261 ++#define EREG_TM_COEF_10_V 0x01d4 //Tonemap coefficient 10, video 0x00a9 261 ++#define EREG_TM_COEF_11_V 0x01d6 //Tonemap coefficient 11, video 0x00b8 261 ++#define EREG_TM_COEF_12_V 0x01d8 //Tonemap coefficient 12, video 0x00c6 261 ++#define EREG_TM_COEF_13_V 0x01da //Tonemap coefficient 13, video 0x00df 261 ++#define EREG_TM_COEF_14_V 0x01dc //Tonemap coefficient 14, video 0x00f5 261 ++#define EREG_TM_COEF_15_V 0x01de //Tonemap coefficient 15, video 0x0109 261 ++#define EREG_TM_COEF_16_V 0x01e0 //Tonemap coefficient 16, video 0x011b 261 ++#define EREG_TM_COEF_17_V 0x01e2 //Tonemap coefficient 17, video 0x013d 261 ++#define EREG_TM_COEF_18_V 0x01e4 //Tonemap coefficient 18, video 0x015a 261 ++#define EREG_TM_COEF_19_V 0x01e6 //Tonemap coefficient 19, video 0x0175 261 ++#define EREG_TM_COEF_20_V 0x01e8 //Tonemap coefficient 20, video 0x018d 261 ++#define EREG_TM_COEF_21_V 0x01ea //Tonemap coefficient 21, video 0x01ba 261 ++#define EREG_TM_COEF_22_V 0x01ec //Tonemap coefficient 22, video 0x01e1 261 ++#define EREG_TM_COEF_23_V 0x01ee //Tonemap coefficient 23, video 0x0205 261 ++#define EREG_TM_COEF_24_V 0x01f0 //Tonemap coefficient 24, video 0x0225 261 ++#define EREG_TM_COEF_25_V 0x01f2 //Tonemap coefficient 25, video 0x0261 261 ++#define EREG_TM_COEF_26_V 0x01f4 //Tonemap coefficient 26, video 0x0295 261 ++#define EREG_TM_COEF_27_V 0x01f6 //Tonemap coefficient 27, video 0x02c5 261 ++#define EREG_TM_COEF_28_V 0x01f8 //Tonemap coefficient 28, video 0x02f1 261 ++#define EREG_TM_COEF_29_V 0x01fa //Tonemap coefficient 29, video 0x033f 261 ++#define EREG_TM_COEF_30_V 0x01fc //Tonemap coefficient 30, video 0x0385 261 ++#define EREG_TM_COEF_31_V 0x01fe //Tonemap coefficient 31, video 0x03c5 261 ++#define EREG_TM_COEF_32_V 0x0200 //Tonemap coefficient 32, video 0x0400 261 ++ ++#define EREG_TM_COEF_00_S 0x0202 //Tonemap coefficient 00, still 0x0000 262 ++#define EREG_TM_COEF_01_S 0x0204 //Tonemap coefficient 01, still 0x0017 262 ++#define EREG_TM_COEF_02_S 0x0206 //Tonemap coefficient 02, still 0x0032 262 ++#define EREG_TM_COEF_03_S 0x0208 //Tonemap coefficient 03, still 0x0046 262 ++#define EREG_TM_COEF_04_S 0x020a //Tonemap coefficient 04, still 0x0056 262 ++#define EREG_TM_COEF_05_S 0x020c //Tonemap coefficient 05, still 0x0064 262 ++#define EREG_TM_COEF_06_S 0x020e //Tonemap coefficient 06, still 0x0071 262 ++#define EREG_TM_COEF_07_S 0x0210 //Tonemap coefficient 07, still 0x007c 262 ++#define EREG_TM_COEF_08_S 0x0212 //Tonemap coefficient 08, still 0x0086 262 ++#define EREG_TM_COEF_09_S 0x0214 //Tonemap coefficient 09, still 0x0099 262 ++#define EREG_TM_COEF_10_S 0x0216 //Tonemap coefficient 10, still 0x00a9 262 ++#define EREG_TM_COEF_11_S 0x0218 //Tonemap coefficient 11, still 0x00b8 262 ++#define EREG_TM_COEF_12_S 0x021a //Tonemap coefficient 12, still 0x00c6 262 ++#define EREG_TM_COEF_13_S 0x021c //Tonemap coefficient 13, still 0x00df 262 ++#define EREG_TM_COEF_14_S 0x021e //Tonemap coefficient 14, still 0x00f5 262 ++#define EREG_TM_COEF_15_S 0x0220 //Tonemap coefficient 15, still 0x0109 262 ++#define EREG_TM_COEF_16_S 0x0222 //Tonemap coefficient 16, still 0x011b 262 ++#define EREG_TM_COEF_17_S 0x0224 //Tonemap coefficient 17, still 0x013d 262 ++#define EREG_TM_COEF_18_S 0x0226 //Tonemap coefficient 18, still 0x015a 262 ++#define EREG_TM_COEF_19_S 0x0228 //Tonemap coefficient 19, still 0x0175 262 ++#define EREG_TM_COEF_20_S 0x022a //Tonemap coefficient 20, still 0x018d 262 ++#define EREG_TM_COEF_21_S 0x022c //Tonemap coefficient 21, still 0x01ba 262 ++#define EREG_TM_COEF_22_S 0x022e //Tonemap coefficient 22, still 0x01e1 262 ++#define EREG_TM_COEF_23_S 0x0230 //Tonemap coefficient 23, still 0x0205 262 ++#define EREG_TM_COEF_24_S 0x0232 //Tonemap coefficient 24, still 0x0225 262 ++#define EREG_TM_COEF_25_S 0x0234 //Tonemap coefficient 25, still 0x0261 262 ++#define EREG_TM_COEF_26_S 0x0236 //Tonemap coefficient 26, still 0x0295 262 ++#define EREG_TM_COEF_27_S 0x0238 //Tonemap coefficient 27, still 0x02c5 262 ++#define EREG_TM_COEF_28_S 0x023a //Tonemap coefficient 28, still 0x02f1 262 ++#define EREG_TM_COEF_29_S 0x023c //Tonemap coefficient 29, still 0x033f 262 ++#define EREG_TM_COEF_30_S 0x023e //Tonemap coefficient 30, still 0x0385 262 ++#define EREG_TM_COEF_31_S 0x0240 //Tonemap coefficient 31, still 0x03c5 262 ++#define EREG_TM_COEF_32_S 0x0242 //Tonemap coefficient 32, still 0x0400 262 ++ ++#define EREG_NACC_EGP_1 0x0250 //NACC EGP 1 0x05dc 265 ++#define EREG_NACC_SAT_1 0x0252 //NACC saturation 1 0x0000 265 ++#define EREG_NACC_EGP_2 0x0254 //NACC EGP 2 0x0465 265 ++#define EREG_NACC_SAT_2 0x0256 //NACC saturation 2 0x0040 265 ++#define EREG_NACC_EGP_3 0x0258 //NACC EGP 3 0x02ee 265 ++#define EREG_NACC_SAT_3 0x025a //NACC saturation 3 0x0080 265 ++#define EREG_NACC_EGP_4 0x025c //NACC EGP 4 0x0177 265 ++#define EREG_NACC_SAT_4 0x025e //NACC saturation 4 0x00c0 265 ++#define EREG_NACC_EGP_5 0x0260 //NACC EGP 5 0x0000 265 ++#define EREG_NACC_SAT_5 0x0262 //NACC saturation 5 0x0100 265 ++#define EREG_NACC_EGP_6 0x0264 //NACC EGP 6 0x0000 265 ++#define EREG_NACC_SAT_6 0x0266 //NACC saturation 6 0x0000 265 ++#define EREG_NACC_EGP_7 0x0268 //NACC EGP 7 0x0000 265 ++#define EREG_NACC_SAT_7 0x026a //NACC saturation 7 0x0000 265 ++#define EREG_NACC_EGP_8 0x026c //NACC EGP 8 0x0000 265 ++#define EREG_NACC_SAT_8 0x026e //NACC saturation 8 0x0000 265 ++#define EREG_NACC_BC_00 0x0270 //NACC NACC bright coefficients 00 0x0235 266 ++#define EREG_NACC_BC_01 0x0272 //NACC NACC bright coefficients 01 0xff46 266 ++#define EREG_NACC_BC_02 0x0274 //NACC bright coefficients 02 0xff85 266 ++#define EREG_NACC_BC_10 0x0276 //NACC bright coefficients 10 0xff64 266 ++#define EREG_NACC_BC_11 0x0278 //NACC bright coefficients 11 0x01fc 266 ++#define EREG_NACC_BC_12 0x027a //NACC bright coefficients 12 0xff9f 266 ++#define EREG_NACC_BC_20 0x027c //NACC bright coefficients 20 0x0008 266 ++#define EREG_NACC_BC_21 0x027e //NACC bright coefficients 21 0xfe8d 266 ++#define EREG_NACC_BC_22 0x0280 //NACC bright coefficients 22 0x026b 266 ++#define EREG_NACC_DC_00 0x0282 //NACC dark coefficients 00 0x0048 266 ++#define EREG_NACC_DC_01 0x0284 //NACC dark coefficients 01 0x010b 266 ++#define EREG_NACC_DC_02 0x0286 //NACC dark coefficients 02 0xffaa 266 ++#define EREG_NACC_DC_10 0x0288 //NACC dark coefficients 10 0x0048 266 ++#define EREG_NACC_DC_11 0x028a //NACC dark coefficients 11 0x010b 266 ++#define EREG_NACC_DC_12 0x028c //NACC dark coefficients 12 0xffaa 266 ++#define EREG_NACC_DC_20 0x028e //NACC dark coefficients 20 0x0048 266 ++#define EREG_NACC_DC_21 0x0290 //NACC dark coefficients 21 0x010b 266 ++#define EREG_NACC_DC_22 0x0292 //NACC dark coefficients 22 0xffaa 266 ++ ++/************************************************************************************* ++ * ++ * Expert Sensor Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++#define EREG_IDENT 0x0800 //Image sensor identification 0x60 272 ++#define EREG_IS_STATUS 0x0801 //Image sensor status 0x00 273 ++#define EREG_ICTRL 0x0805 //Interface control 0x00 275 ++ ++#define EREG_ADC_CTRL 0x0809 //ADC control 0x01 277 ++#define EREG_FWROW 0x080a //Window first row address 0x01 278 ++#define EREG_FWCOL 0x080b //Window first column address 0x01 279 ++#define EREG_LWROW 0x080c //Window last row address 0x7a 280 ++#define EREG_LWCOL 0x080d //Window last column address 0xa2 281 ++#define EREG_CLK_PIXEL 0x080e //Clocks per pixel 0x02 282 ++#define EREG_EREC_PGA 0x080f //Even row, even column(green 1)PGA gain 0x00 283 ++#define EREG_EROC_PGA 0x0810 //Even row, odd column (red) PGA gain 0x00 284 ++#define EREG_OREC_PGA 0x0811 //Odd row, even column (blue) PGA gain 0x00 285 ++#define EREG_OROC_PGA 0x0812 //Odd row, odd column (green 2) PGA gain 0x00 286 ++#define EREG_ROWEXP_L 0x0813 //Row exposure low 0x54 287 ++#define EREG_ROWEXP_H 0x0814 //Row exposure high 0x00 288 ++#define EREG_SROWEXP 0x0815 //Sub row exposure 0x31 289 ++#define EREG_ERROR 0x0816 //Error control 0x00 290 ++ ++#define EREG_HBLANK 0x0819 //Horizontal blank 0x00 292 ++#define EREG_VBLANK 0x081a //Vertical blank 0x00 293 ++#define EREG_CONFIG_1 0x081b //Image sensor configuration 1 0x0e 294 ++#define EREG_CONTROL_1 0x081c //Image sensor control 1 0x24 295 ++ ++#define EREG_CONFIG_2 0x0827 //Image sensor configuration 2 0x00 298 ++#define EREG_GRR_CTRL 0x0828 //Ground reset reference control 0x00 299 ++ ++#define EREG_BIAS_TRM 0x0837 //Bias trim 0x00 301 ++#define EREG_SMP_GR_E2 0x08d7 //Sample ground reference edge 2 0x00 303 ++#define EREG_SMP_GR_E1 0x08d8 //Sample ground reference edge 1 0x10 304 ++#define EREG_SMP_GR_E0 0x08d9 //Sample ground reference edge 0 0x0a 305 ++ ++#define EREG_EXP_GR_E1 0x08dc //Exposure, ground reference edge 1 0x10 307 ++#define EREG_EXP_GR_E0 0x08dd //Exposure, ground reference edge 0 0x06 308 ++#define EREG_GR_POL 0x08df //Ground reference polarity 0xd3 310 ++ ++#define EREG_SMP_RST_E2 0x08eb //Sample, reset edge 2 0x04 312 ++#define EREG_SMP_RST_E1 0x08ec //Sample, reset edge 1 0x10 313 ++#define EREG_SMP_RST_E0 0x08ed //Sample, reset edge 0 0x07 314 ++ ++#define EREG_EXP_RST_E1 0x08f0 //Exposure, reset edge 1 0x10 316 ++#define EREG_EXP_RST_E0 0x08f1 //Exposure, reset edge 1 0x03 317 ++#define EREG_RESET_POL 0x08f3 //Reset polarity enable 0xd3 319 ++ ++#define EREG_SMP_PRST_E2 0x08f5 //Sample, preset edge 2 0x00 321 ++#define EREG_SMP_PRST_E1 0x08f6 //Sample, preset edge 1 0x02 322 ++#define EREG_SMP_PRST_E0 0x08f7 //Sample, preset edge 0 0x0a 323 ++ ++#define EREG_EXP_PRST_E1 0x08fa //Exposure, preset edge 1 0x02 325 ++#define EREG_EXP_PRST_E0 0x08fb //Exposure, preset edge 1 0x06 326 ++#define EREG_PRESET_POL 0x08fd //Preset polarity enable 0xd3 328 ++ ++/************************************************************************************* ++ * ++ * Expert Image Pipeline Registers ++ * ++ *************************************************************************************/ ++// name addr description default page ++ ++#define EREG_CMD_1 0x1002 //Main command 1 0x0000 335 ++#define EREG_CMD_2 0x1004 //Main command 2 (write 1¡¯s only) 0x0002 336 ++#define EREG_OUTPUT_CTRL 0x1008 //Output control, working 0x9019 338 ++#define EREG_PARALLEL_CTRL 0x100a //Parallel output control working copy 0x0000 340 ++#define EREG_SOF_CODE_W 0x100c //Start of frame code working copy 0x00ff 341 ++#define EREG_PEOF_CODES 0x100e //End of frame codes working copy 0x0100 342 ++#define EREG_CCIR_TIMING 0x1010 //CCIR interface timing 0x0000 343 ++#define EREG_R_Y_MAX_MIN 0x1012 //Luminance, Y (or red) maximum/minimum 0xff00 344 ++#define EREG_G_CB_MAX_MIN 0x1014 //Chrominance,Cb(or green)maximum/minimum 0xff00 345 ++#define EREG_B_CR_MAX_MIN 0x1016 //Chrominance,Cr(or blue)maximum/minimum 0xff00 346 ++#define EREG_PROCESS_CTRL 0x1018 //Processing control working copy 0x0280 347 ++#define EREG_BPA_SF_GTHRESH 0x101a //BPA scale factor,green filter threshold 0x0220 349 ++#define EREG_BPA_OUTL_PED 0x101c //BPA outlier, pedestal 0x4008 350 ++#define EREG_BPA_BADPIX_CNT 0x101e //BPA bad pixel count (read only) 0x0000 351 ++#define EREG_SZR_IN_W 0x1020 //Sizer input width 0x0280 352 ++#define EREG_SZR_IN_H 0x1022 //Sizer input height 0x01e0 353 ++#define EREG_SZR_OUT_W 0x1024 //Sizer output width 0x0140 354 ++#define EREG_SZR_OUT_H 0x1026 //Sizer output height 0x00f0 355 ++ ++ ++#define EREG_CC_COEF_00 0x1028 //Color correction coefficient 00 0x02f9 358 ++#define EREG_CC_COEF_01 0x102a //Color correction coefficient 01 0x0f03 358 ++#define EREG_CC_COEF_02 0x102c //Color correction coefficient 02 0x0f02 358 ++#define EREG_CC_COEF_10 0x102e //Color correction coefficient 10 0x0f4f 358 ++#define EREG_CC_COEF_11 0x1030 //Color correction coefficient 11 0x025c 358 ++#define EREG_CC_COEF_12 0x1032 //Color correction coefficient 12 0x0f54 358 ++#define EREG_CC_COEF_20 0x1034 //Color correction coefficient 20 0x0fe0 358 ++#define EREG_CC_COEF_21 0x1036 //Color correction coefficient 21 0x0e4a 358 ++#define EREG_CC_COEF_22 0x1038 //Color correction coefficient 22 0x02d5 358 ++ ++#define EREG_CC_PRE_OS_0 0x103a //Color correction pre-offset 0 0x01f8 360 ++#define EREG_CC_PRE_OS_1 0x103c //Color correction pre-offset 1 0x01f8 360 ++#define EREG_CC_PRE_OS_2 0x103e //Color correction pre-offset 2 0x01f8 360 ++#define EREG_CC_POST_OS_0 0x1040 //Color correction post-offset 0 0x0000 360 ++#define EREG_CC_POST_OS_1 0x1042 //Color correction post-offset 1 0x0000 360 ++#define EREG_CC_POST_OS_2 0x1044 //Color correction post-offset 2 0x0000 360 ++ ++#define EREG_CSC_COEF_00 0x1046 //Color space conversion coefficient 00 0x0026 363 ++#define EREG_CSC_COEF_01 0x1048 //Color space conversion coefficient 01 0x004b 363 ++#define EREG_CSC_COEF_02 0x104a //Color space conversion coefficient 02 0x000f 363 ++#define EREG_CSC_COEF_10 0x104c //Color space conversion coefficient 10 0x01ed 363 ++#define EREG_CSC_COEF_11 0x104e //Color space conversion coefficient 11 0x01db 363 ++#define EREG_CSC_COEF_12 0x1050 //Color space conversion coefficient 12 0x0038 363 ++#define EREG_CSC_COEF_20 0x1052 //Color space conversion coefficient 20 0x004f 363 ++#define EREG_CSC_COEF_21 0x1054 //Color space conversion coefficient 21 0x01be 363 ++#define EREG_CSC_COEF_22 0x1056 //Color space conversion coefficient 22 0x01f3 363 ++#define EREG_CSC_OS_0 0x1058 //Color space conversion offset 0 0x0000 364 ++#define EREG_CSC_OS_1 0x105a //Color space conversion offset 1 0x0080 364 ++#define EREG_CSC_OS_2 0x105c //Color space conversion offset 2 0x0080 364 ++#define EREG_DATA_GEN 0x105e //Test data generator 0x0000 365 ++#define EREG_HSYNC_PER 0x1060 //Horizontal synchronization period 0x0a8b 366 ++#define EREG_APS_COEF_GRN1 0x1062 //Green 1 AWB gain 0x0080 368 ++#define EREG_APS_COEF_RED 0x1064 //Red AWB gain 0x0080 368 ++ ++ ++#define EREG_APS_COEF_BLUE 0x1066 //Blue AWB gain 0x0080 368 ++#define EREG_APS_COEF_GRN2 0x1068 //Green 2 AWB gain 0x0080 368 ++#define EREG_AV_LEFT_TOP 0x106a //Anti-v,sensor first row and column 0x0101 369 ++#define EREG_AV_RIGHT_BOT 0x106c //Anti-v, sensor last row and column 0xa27a 370 ++#define EREG_AV_CENTER_COL 0x106e //Anti-v, sensor center column 0x0148 371 ++#define EREG_AV_CENTER_ROW 0x1070 //Anti-v, sensor center row 0x00f8 372 ++#define EREG_STAT_CAP_CTRL 0x1072 //Image statistics capture control 0x0021 373 ++#define EREG_STAT_MODE_CTRL 0x1074 //Image statistics mode control 0x0000 374 ++#define EREG_GREEN_1_SUM 0x1076 //Green 1 pixel sum 0x0000 375 ++#define EREG_RED_SUM 0x1078 //Red pixel sum 0x0000 375 ++#define EREG_BLUE_SUM 0x107a //Blue pixel sum 0x0000 375 ++#define EREG_GREEN_2_SUM 0x107c //Green 2 pixel sum 0x0000 375 ++#define EREG_I_WIDTH 0x107e //Current image width 0x0000 376 ++#define EREG_I_HEIGHT 0x1080 //Current image height 0x0000 377 ++#define EREG_STATUS_FLAGS 0x1082 //Status flags (read only) 0x0000 378 ++#define EREG_CLK_GATE_DIS 0x1084 //Clock gate disable 0x0000 379 ++#define EREG_CCIR_TIMING2 0x1086 //CCIR interface timing 2 0x0000 381 ++#define EREG_CCIR_TIMING3 0x1088 //CCIR interface timing 3 0x0010 382 ++#define EREG_G1G2_DIAG_THRESH 0x108a //Green 1/green 2 diagonal threshold 0x0040 383 ++#define EREG_BPA_D2_THRESH 0x108c //BPA second derivative threshold 0x0100 384 ++#define EREG_SERIAL_CTRL 0x108e //Serial control 0x0000 385 ++#define EREG_INTP_CTRL_1 0x1090 //Interpolation control 1(demosaic) 0x0188 387 ++#define EREG_INTP_CTRL_2 0x1092 //Interpolation control 2(demosaic) 0x00c8 388 ++#define EREG_AV_OVAL_FACT 0x1094 //Anti-vignetting oval factor 0x0100 389 ++#define EREG_AV_OS_GREEN1 0x1096 //Anti-vignetting green 1 offset 0x0000 391 ++#define EREG_AV_OS_RED 0x1098 //Anti-vignetting red offset 0x0000 391 ++#define EREG_AV_OS_BLUE 0x109a //Anti-vignetting blue offset 0x0000 391 ++#define EREG_AV_OS_GREEN2 0x109c //Anti-vignetting green 2 offset 0x0000 391 ++ ++ ++/*********************************************************************** ++ * ++ * typedefs & Structures ++ * ++ ***********************************************************************/ ++ ++struct adcm3800_context_s ++{ ++ int video_running; // =1 video is running ++ int SCL_partial; // =1 partial SCL updated ++ int SCL_restart; // =1 SCL & restart updated ++ ++ u32 chipid; ++ ++ u16 format; ++ u16 sensor_w; ++ u16 sensor_h; ++ u16 output_w; ++ u16 output_h; ++ ++ // frame rate control ++ unsigned int fps; ++ unsigned int mclk; ++ ++ int bright; ++ V4l_PIC_STYLE style; ++ V4l_PIC_WB light; ++ int flicker_freq; ++ ++ V4l_NM expo_mode; ++ int max_expotime; ++}; ++ ++typedef struct adcm3800_context_s adcm3800_context_t, *p_adcm3800_context_t; ++ ++ ++/*********************************************************************** ++ * ++ * Function Prototype ++ * ++ ***********************************************************************/ ++ ++// Configuration Procedures ++int adcm3800_power_on(u32 clk); ++int adcm3800_power_off(void ); ++int adcm3800_viewfinder_on( void ); ++int adcm3800_viewfinder_off( void ); ++int adcm3800_reconfigure(p_camera_context_t cam_ctx, int frames); ++ ++int adcm3800_set_output_format(u16 format); ++int adcm3800_set_output_size(u16 width, u16 height); ++int adcm3800_set_sensor_size(u16 width, u16 height); ++ ++int adcm3800_set_fps(u16 fps); ++ ++/*set picture style(normal/black white/sepia/solarize/neg.art)*/ ++int adcm3800_set_style(V4l_PIC_STYLE style); ++/*set picture light(direct sun/incandescent/fluorescent)*/ ++int adcm3800_set_light(V4l_PIC_WB light); ++/*set picture brightness*/ ++int adcm3800_set_bright(int bright); ++int adcm3800_set_flicker(int freq); ++int adcm3800_set_exposure_mode(V4l_NM mode, int maxexpotime); ++ ++extern int i2c_adcm3800_read(u16 addr, u16 *pvalue); ++extern int i2c_adcm3800_write(u16 addr, u16 value); ++extern int i2c_adcm3800_read_byte(u16 addr, u8 *pvalue); ++extern int i2c_adcm3800_write_byte(u16 addr, u8 value); ++ ++#endif /* _PXA_ADCM3800_HW_H__ */ ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/camera.h linux-2.6.16/drivers/media/video/camera.h +--- linux-2.6.16.orig/drivers/media/video/camera.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/camera.h 2006-06-03 11:14:56.434309936 +0200 +@@ -0,0 +1,663 @@ ++/*================================================================================ ++ ++ Module Name: camera.h ++ ++General Description: Camera module adcm2700 head file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Wangfei(w20239) 12/19/2003 LIBdd35749 Created ++wangfei(w20239) 02/26/2004 LIBdd81055 Update algorithm for DMA transfer ++ ++Portability: Indicate ifthis module is portable to other compilers or ++platforms. If not, indicate specific reasons why is it not portable. ++ ++================================================================================== ++ INCLUDE FILES ++================================================================================*/ ++#ifndef CAMERA_H_ ++#define CAMERA_H_ ++ ++#include <linux/pxa_camera.h> ++#include <linux/videodev.h> ++ ++#define DEBUG 1 ++ ++#ifdef CONFIG_CAMERA_ADCM2700 ++#endif ++ ++#ifdef CONFIG_CAMERA_OV9640 ++#endif ++ ++#ifdef CONFIG_CAMERA_MT9M111 ++#endif ++ ++/* ++Bpp definition ++*/ ++ ++#define YUV422_BPP 16 ++#define RGB565_BPP 16 ++#define RGB666_UNPACKED_BPP 32 ++#define RGB666_PACKED_BPP 24 ++ ++//--------------------------------------------------------------------------- ++// Register definitions ++//--------------------------------------------------------------------------- ++ ++enum CI_REGBITS_CICR0 { ++ CI_CICR0_FOM = 0x00000001, ++ CI_CICR0_EOFM = 0x00000002, ++ CI_CICR0_SOFM = 0x00000004, ++ CI_CICR0_CDM = 0x00000008, ++ CI_CICR0_QDM = 0x00000010, ++ CI_CICR0_PERRM = 0x00000020, ++ CI_CICR0_EOLM = 0x00000040, ++ CI_CICR0_FEM = 0x00000080, ++ CI_CICR0_RDAVM = 0x00000100, ++ CI_CICR0_TOM = 0x00000200, ++ CI_CICR0_RESERVED = 0x03FFFC00, ++ CI_CICR0_SIM_SHIFT = 24, ++ CI_CICR0_SIM_SMASK = 0x7, ++ CI_CICR0_DIS = 0x08000000, ++ CI_CICR0_ENB = 0x10000000, ++ CI_CICR0_SL_CAP_EN = 0x20000000, ++ CI_CICR0_PAR_EN = 0x40000000, ++ CI_CICR0_DMA_EN = 0x80000000, ++ CI_CICR0_INTERRUPT_MASK = 0x3FF ++}; ++ ++enum CI_REGBITS_CICR1 { ++ CI_CICR1_DW_SHIFT = 0, ++ CI_CICR1_DW_SMASK = 0x7, ++ CI_CICR1_COLOR_SP_SHIFT = 3, ++ CI_CICR1_COLOR_SP_SMASK = 0x3, ++ CI_CICR1_RAW_BPP_SHIFT = 5, ++ CI_CICR1_RAW_BPP_SMASK = 0x3, ++ CI_CICR1_RGB_BPP_SHIFT = 7, ++ CI_CICR1_RGB_BPP_SMASK = 0x7, ++ CI_CICR1_YCBCR_F = 0x00000400, ++ CI_CICR1_RBG_F = 0x00000800, ++ CI_CICR1_RGB_CONV_SHIFT = 12, ++ CI_CICR1_RGB_CONV_SMASK = 0x7, ++ CI_CICR1_PPL_SHIFT = 15, ++ CI_CICR1_PPL_SMASK = 0x7FF, ++ CI_CICR1_RESERVED = 0x1C000000, ++ CI_CICR1_RGBT_CONV_SHIFT= 29, ++ CI_CICR1_RGBT_CONV_SMASK= 0x3, ++ CI_CICR1_TBIT = 0x80000000 ++}; ++ ++enum CI_REGBITS_CICR2 { ++ CI_CICR2_FSW_SHIFT = 0, ++ CI_CICR2_FSW_SMASK = 0x3, ++ CI_CICR2_BFPW_SHIFT= 3, ++ CI_CICR2_BFPW_SMASK= 0x3F, ++ CI_CICR2_RESERVED = 0x00000200, ++ CI_CICR2_HSW_SHIFT = 10, ++ CI_CICR2_HSW_SMASK = 0x3F, ++ CI_CICR2_ELW_SHIFT = 16, ++ CI_CICR2_ELW_SMASK = 0xFF, ++ CI_CICR2_BLW_SHIFT = 24, ++ CI_CICR2_BLW_SMASK = 0xFF ++}; ++ ++enum CI_REGBITS_CICR3 { ++ CI_CICR3_LPF_SHIFT = 0, ++ CI_CICR3_LPF_SMASK = 0x7FF, ++ CI_CICR3_VSW_SHIFT = 11, ++ CI_CICR3_VSW_SMASK = 0x1F, ++ CI_CICR3_EFW_SHIFT = 16, ++ CI_CICR3_EFW_SMASK = 0xFF, ++ CI_CICR3_BFW_SHIFT = 24, ++ CI_CICR3_BFW_SMASK = 0xFF ++}; ++ ++enum CI_REGBITS_CICR4 { ++ CI_CICR4_DIV_SHIFT = 0, ++ CI_CICR4_DIV_SMASK = 0xFF, ++ CI_CICR4_FR_RATE_SHIFT = 8, ++ CI_CICR4_FR_RATE_SMASK = 0x7, ++ CI_CICR4_RESERVED1 = 0x0007F800, ++ CI_CICR4_MCLK_EN = 0x00080000, ++ CI_CICR4_VSP = 0x00100000, ++ CI_CICR4_HSP = 0x00200000, ++ CI_CICR4_PCP = 0x00400000, ++ CI_CICR4_PCLK_EN = 0x00800000, ++ CI_CICR4_RESERVED2 = 0xFF000000, ++ CI_CICR4_RESERVED = CI_CICR4_RESERVED1 | CI_CICR4_RESERVED2 ++}; ++ ++enum CI_REGBITS_CISR { ++ CI_CISR_IFO_0 = 0x00000001, ++ CI_CISR_IFO_1 = 0x00000002, ++ CI_CISR_IFO_2 = 0x00000004, ++ CI_CISR_EOF = 0x00000008, ++ CI_CISR_SOF = 0x00000010, ++ CI_CISR_CDD = 0x00000020, ++ CI_CISR_CQD = 0x00000040, ++ CI_CISR_PAR_ERR = 0x00000080, ++ CI_CISR_EOL = 0x00000100, ++ CI_CISR_FEMPTY_0 = 0x00000200, ++ CI_CISR_FEMPTY_1 = 0x00000400, ++ CI_CISR_FEMPTY_2 = 0x00000800, ++ CI_CISR_RDAV_0 = 0x00001000, ++ CI_CISR_RDAV_1 = 0x00002000, ++ CI_CISR_RDAV_2 = 0x00004000, ++ CI_CISR_FTO = 0x00008000, ++ CI_CISR_RESERVED = 0xFFFF0000 ++}; ++ ++enum CI_REGBITS_CIFR { ++ CI_CIFR_FEN0 = 0x00000001, ++ CI_CIFR_FEN1 = 0x00000002, ++ CI_CIFR_FEN2 = 0x00000004, ++ CI_CIFR_RESETF = 0x00000008, ++ CI_CIFR_THL_0_SHIFT= 4, ++ CI_CIFR_THL_0_SMASK= 0x3, ++ CI_CIFR_RESERVED1 = 0x000000C0, ++ CI_CIFR_FLVL0_SHIFT= 8, ++ CI_CIFR_FLVL0_SMASK= 0xFF, ++ CI_CIFR_FLVL1_SHIFT= 16, ++ CI_CIFR_FLVL1_SMASK= 0x7F, ++ CI_CIFR_FLVL2_SHIFT= 23, ++ CI_CIFR_FLVL2_SMASK= 0x7F, ++ CI_CIFR_RESERVED2 = 0xC0000000, ++ CI_CIFR_RESERVED = CI_CIFR_RESERVED1 | CI_CIFR_RESERVED2 ++}; ++ ++//--------------------------------------------------------------------------- ++// Parameter Type definitions ++//--------------------------------------------------------------------------- ++typedef enum { ++ CI_RAW8 = 0, //RAW ++ CI_RAW9, ++ CI_RAW10, ++ CI_YCBCR422, //YCBCR ++ CI_YCBCR422_PLANAR, //YCBCR Planaried ++ CI_RGB444, //RGB ++ CI_RGB555, ++ CI_RGB565, ++ CI_RGB666, ++ CI_RGB888, ++ CI_RGBT555_0, //RGB+Transparent bit 0 ++ CI_RGBT888_0, ++ CI_RGBT555_1, //RGB+Transparent bit 1 ++ CI_RGBT888_1, ++ CI_RGB666_PACKED, //RGB Packed ++ CI_RGB888_PACKED, ++ CI_INVALID_FORMAT = 0xFF ++} CI_IMAGE_FORMAT; ++ ++typedef enum { ++ CI_INTSTATUS_IFO_0 = 0x00000001, ++ CI_INTSTATUS_IFO_1 = 0x00000002, ++ CI_INTSTATUS_IFO_2 = 0x00000004, ++ CI_INTSTATUS_EOF = 0x00000008, ++ CI_INTSTATUS_SOF = 0x00000010, ++ CI_INTSTATUS_CDD = 0x00000020, ++ CI_INTSTATUS_CQD = 0x00000040, ++ CI_INTSTATUS_PAR_ERR = 0x00000080, ++ CI_INTSTATUS_EOL = 0x00000100, ++ CI_INTSTATUS_FEMPTY_0 = 0x00000200, ++ CI_INTSTATUS_FEMPTY_1 = 0x00000400, ++ CI_INTSTATUS_FEMPTY_2 = 0x00000800, ++ CI_INTSTATUS_RDAV_0 = 0x00001000, ++ CI_INTSTATUS_RDAV_1 = 0x00002000, ++ CI_INTSTATUS_RDAV_2 = 0x00004000, ++ CI_INTSTATUS_FTO = 0x00008000, ++ CI_INTSTATUS_ALL = 0x0000FFFF ++} CI_INTERRUPT_STATUS; ++ ++typedef enum { ++ CI_INT_IFO = 0x00000001, ++ CI_INT_EOF = 0x00000002, ++ CI_INT_SOF = 0x00000004, ++ CI_INT_CDD = 0x00000008, ++ CI_INT_CQD = 0x00000010, ++ CI_INT_PAR_ERR = 0x00000020, ++ CI_INT_EOL = 0x00000040, ++ CI_INT_FEMPTY = 0x00000080, ++ CI_INT_RDAV = 0x00000100, ++ CI_INT_FTO = 0x00000200, ++ CI_INT_ALL = 0x000003FF ++} CI_INTERRUPT_MASK; ++#define CI_INT_MAX 10 ++ ++typedef enum CI_MODE { ++ CI_MODE_MP, // Master-Parallel ++ CI_MODE_SP, // Slave-Parallel ++ CI_MODE_MS, // Master-Serial ++ CI_MODE_EP, // Embedded-Parallel ++ CI_MODE_ES // Embedded-Serial ++} CI_MODE; ++ ++ ++typedef enum { ++ CI_FR_ALL = 0, // Capture all incoming frames ++ CI_FR_1_2, // Capture 1 out of every 2 frames ++ CI_FR_1_3, // Capture 1 out of every 3 frames ++ CI_FR_1_4, ++ CI_FR_1_5, ++ CI_FR_1_6, ++ CI_FR_1_7, ++ CI_FR_1_8 ++} CI_FRAME_CAPTURE_RATE; ++ ++ ++typedef enum { ++ CI_FIFO_THL_32 = 0, ++ CI_FIFO_THL_64, ++ CI_FIFO_THL_96 ++} CI_FIFO_THRESHOLD; ++ ++typedef struct { ++ unsigned int BFW; ++ unsigned int BLW; ++} CI_MP_TIMING, CI_MS_TIMING; ++ ++typedef struct { ++ unsigned int BLW; ++ unsigned int ELW; ++ unsigned int HSW; ++ unsigned int BFPW; ++ unsigned int FSW; ++ unsigned int BFW; ++ unsigned int EFW; ++ unsigned int VSW; ++} CI_SP_TIMING; ++ ++typedef enum { ++ CI_DATA_WIDTH4 = 0x0, ++ CI_DATA_WIDTH5 = 0x1, ++ CI_DATA_WIDTH8 = 0x2, ++ CI_DATA_WIDTH9 = 0x3, ++ CI_DATA_WIDTH10= 0x4 ++} CI_DATA_WIDTH; ++ ++//------------------------------------------------------------------------------------------------------- ++// Configuration APIs ++//------------------------------------------------------------------------------------------------------- ++ ++void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate); ++CI_FRAME_CAPTURE_RATE ci_get_frame_rate(void); ++void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format); ++void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width); ++void ci_configure_mp(unsigned int PPL, unsigned int LPF, CI_MP_TIMING* timing); ++void ci_configure_sp(unsigned int PPL, unsigned int LPF, CI_SP_TIMING* timing); ++void ci_configure_ms(unsigned int PPL, unsigned int LPF, CI_MS_TIMING* timing); ++void ci_configure_ep(int parity_check); ++void ci_configure_es(int parity_check); ++void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz); ++void ci_set_polarity(int pclk_sample_falling, int hsync_active_low, int vsync_active_low); ++void ci_set_fifo( unsigned int timeout, CI_FIFO_THRESHOLD threshold, int fifo1_enable, ++ int fifo2_enable); ++void ci_set_int_mask( unsigned int mask); ++void ci_clear_int_status( unsigned int status); ++void ci_set_reg_value( unsigned int reg_offset, unsigned int value); ++int ci_get_reg_value(unsigned int reg_offset); ++ ++void ci_reset_fifo(void); ++unsigned int ci_get_int_mask(void); ++unsigned int ci_get_int_status(void); ++void ci_slave_capture_enable(void); ++void ci_slave_capture_disable(void); ++ ++//------------------------------------------------------------------------------------------------------- ++// Control APIs ++//------------------------------------------------------------------------------------------------------- ++int ci_init(void); ++void ci_deinit(void); ++void ci_enable( int dma_en); ++int ci_disable(int quick); ++ ++//debug ++void ci_dump(void); ++// IRQ ++irqreturn_t pxa_camera_irq(int irq, void *dev_id, struct pt_regs *regs); ++ ++#ifdef DEBUG ++ ++#define dbg_print(fmt, args...) printk(KERN_INFO "fun %s "fmt"\n", __FUNCTION__, ##args) ++ ++#if DEBUG > 1 ++#define ddbg_print(fmt, args...) printk(KERN_INFO "fun %s "fmt"\n", __FUNCTION__, ##args) ++#else ++#define ddbg_print(fmt, args...) ; ++#endif ++ ++#else ++ ++#define dbg_print(fmt, args...) ; ++#define ddbg_print(fmt, args...) ; ++ ++#endif ++ ++ ++#define VID_HARDWARE_PXA_CAMERA 50 /* subject to change */ ++ ++#define STATUS_FAILURE (0) ++#define STATUS_SUCCESS (1) ++#define STATUS_WRONG_PARAMETER -1 ++ ++#ifdef CONFIG_CAMERA_OV9640 ++#define CIBR0_PHY (0x50000000 + 0x28) ++#define CIBR1_PHY (0x50000000 + 0x30) ++#define CIBR2_PHY (0x50000000 + 0x38) ++#endif ++/* ++Macros ++*/ ++/*GPIO and CIF pin definitions*/ ++#define CIF_PD 50 ++#define CIF_RST 19 ++#define CIF_MCLK 23 ++#define CIF_PCLK 54 ++#define CIF_LV 85 ++#define CIF_FV 84 ++#define CIF_DD0 27 ++#define CIF_DD1 114 ++#define CIF_DD2 51 ++#define CIF_DD3 115 ++#define CIF_DD4 95 ++#define CIF_DD5 94 ++#define CIF_DD6 17 ++#define CIF_DD7 108 ++ ++#define CIF_PD_MD (CIF_PD | GPIO_OUT) ++#define CIF_RST_MD (CIF_RST | GPIO_OUT) ++#define CIF_MCLK_MD (CIF_MCLK | GPIO_ALT_FN_1_OUT) ++#define CIF_PCLK_MD (CIF_PCLK | GPIO_ALT_FN_3_IN) ++#define CIF_LV_MD (CIF_LV | GPIO_ALT_FN_3_IN) ++#define CIF_FV_MD (CIF_FV | GPIO_ALT_FN_3_IN) ++#define CIF_DD0_MD (CIF_DD0 | GPIO_ALT_FN_3_IN) ++#define CIF_DD1_MD (CIF_DD1 | GPIO_ALT_FN_1_IN) ++#define CIF_DD2_MD (CIF_DD2 | GPIO_ALT_FN_1_IN) ++#define CIF_DD3_MD (CIF_DD3 | GPIO_ALT_FN_2_IN) ++#define CIF_DD4_MD (CIF_DD4 | GPIO_ALT_FN_2_IN) ++#define CIF_DD5_MD (CIF_DD5 | GPIO_ALT_FN_2_IN) ++#define CIF_DD6_MD (CIF_DD6 | GPIO_ALT_FN_2_IN) ++#define CIF_DD7_MD (CIF_DD7 | GPIO_ALT_FN_1_IN) ++ ++/* ++Image format definition ++*/ ++#define CAMERA_IMAGE_FORMAT_MAX CAMERA_IMAGE_FORMAT_YCBCR444_PLANAR ++ ++// Interrupt mask ++#define CAMERA_INTMASK_FIFO_OVERRUN 0x0001 ++#define CAMERA_INTMASK_END_OF_FRAME 0x0002 ++#define CAMERA_INTMASK_START_OF_FRAME 0x0004 ++#define CAMERA_INTMASK_CI_DISABLE_DONE 0x0008 ++#define CAMERA_INTMASK_CI_QUICK_DISABLE 0x0010 ++#define CAMERA_INTMASK_PARITY_ERROR 0x0020 ++#define CAMERA_INTMASK_END_OF_LINE 0x0040 ++#define CAMERA_INTMASK_FIFO_EMPTY 0x0080 ++#define CAMERA_INTMASK_RCV_DATA_AVALIBLE 0x0100 ++#define CAMERA_INTMASK_TIME_OUT 0x0200 ++#define CAMERA_INTMASK_END_OF_DMA 0x0400 ++ ++// Interrupt status ++#define CAMERA_INTSTATUS_FIFO_OVERRUN_0 0x00000001 ++#define CAMERA_INTSTATUS_FIFO_OVERRUN_1 0x00000002 ++#define CAMERA_INTSTATUS_FIFO_OVERRUN_2 0x00000004 ++#define CAMERA_INTSTATUS_END_OF_FRAME 0x00000008 ++#define CAMERA_INTSTATUS_START_OF_FRAME 0x00000010 ++#define CAMERA_INTSTATUS_CI_DISABLE_DONE 0x00000020 ++#define CAMERA_INTSTATUS_CI_QUICK_DISABLE 0x00000040 ++#define CAMERA_INTSTATUS_PARITY_ERROR 0x00000080 ++#define CAMERA_INTSTATUS_END_OF_LINE 0x00000100 ++#define CAMERA_INTSTATUS_FIFO_EMPTY_0 0x00000200 ++#define CAMERA_INTSTATUS_FIFO_EMPTY_1 0x00000400 ++#define CAMERA_INTSTATUS_FIFO_EMPTY_2 0x00000800 ++#define CAMERA_INTSTATUS_RCV_DATA_AVALIBLE_0 0x00001000 ++#define CAMERA_INTSTATUS_RCV_DATA_AVALIBLE_1 0x00002000 ++#define CAMERA_INTSTATUS_RCV_DATA_AVALIBLE_2 0x00004000 ++#define CAMERA_INTSTATUS_TIME_OUT 0x00008000 ++#define CAMERA_INTSTATUS_END_OF_DMA 0x00010000 ++ ++// Capture status ++#define CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS 0x0001 ++#define CAMERA_STATUS_RING_BUFFER_FULL 0x0002 ++ ++ ++/* ++Structures ++*/ ++typedef struct camera_context_s camera_context_t, *p_camera_context_t; ++ ++typedef struct { ++ int (*init)(p_camera_context_t context); ++ int (*deinit)(p_camera_context_t); ++ int (*set_capture_format)(p_camera_context_t); ++ int (*start_capture)(p_camera_context_t, unsigned int frames); ++ int (*stop_capture)(p_camera_context_t); ++ int (*command)(p_camera_context_t, unsigned int cmd, void *param); ++ int (*pm_management)(p_camera_context_t, int suspend); ++} camera_function_t, *p_camera_function_t; ++// context ++ ++struct camera_context_s { ++ // syncronization stuff ++ atomic_t refcount; ++ ++ /* ++ * DRIVER FILLED PARAMTER ++ */ ++ ++ // sensor info ++ unsigned int sensor_type; ++ ++ // capture image info ++ unsigned int capture_width; ++ unsigned int capture_height; ++ unsigned int sensor_width; ++ unsigned int sensor_height; ++ ++ unsigned int capture_input_format; ++ unsigned int capture_output_format; ++ V4l_PIC_STYLE capture_style; ++ V4l_PIC_WB capture_light; ++ int capture_bright; ++ int capture_contrast; ++ int flicker_freq; ++ ++ ++ ++ struct video_capability vc; ++ ++ ++ // frame rate control ++ unsigned int frame_rate; ++ unsigned int fps; ++ unsigned int mini_fps; ++ ++ unsigned int mclk; ++ ++ // ring buffers ++ // note: must pass in 8 bytes aligned address ++ void *buffer_virtual; ++ void *buffer_physical; ++ unsigned int buf_size; ++ ++ // memory for dma descriptors, layout: ++ // dma descriptor chain 0, ++ // dma descriptor chain 1, ++ // ... ++ void *dma_descriptors_virtual; ++ void *dma_descriptors_physical; ++ unsigned int dma_descriptors_size; ++ ++ // os mapped register address ++ unsigned int clk_reg_base; ++ unsigned int ost_reg_base; ++ unsigned int gpio_reg_base; ++ unsigned int ci_reg_base; ++ unsigned int board_reg_base; ++ ++ // function dispatch table ++ p_camera_function_t camera_functions; ++ ++ /* ++ * FILLED PARAMTER ++ */ ++ int dma_channels[3]; ++ unsigned int capture_status; ++ ++ /* ++ * INTERNALLY USED: DON'T TOUCH! ++ */ ++ unsigned int block_number, block_size, block_number_max; ++ unsigned int block_header, block_tail; ++ unsigned int fifo0_descriptors_virtual, fifo0_descriptors_physical; ++ unsigned int fifo1_descriptors_virtual, fifo1_descriptors_physical; ++ unsigned int fifo2_descriptors_virtual, fifo2_descriptors_physical; ++ unsigned int fifo0_num_descriptors; ++ unsigned int fifo1_num_descriptors; ++ unsigned int fifo2_num_descriptors; ++ unsigned int fifo0_transfer_size; ++ unsigned int fifo1_transfer_size; ++ unsigned int fifo2_transfer_size; ++ ++ struct page **page_array; ++ ++ unsigned int pages_allocated; ++ unsigned int page_aligned_block_size; ++ unsigned int pages_per_block; ++ unsigned int pages_per_fifo0; ++ unsigned int pages_per_fifo1; ++ unsigned int pages_per_fifo2; ++ ++#ifdef CONFIG_DPM ++ struct pm_dev *pmdev; ++#endif ++ int dma_started; ++}; ++ ++ ++/* ++Prototypes ++*/ ++/*********************************************************************** ++ * ++ * Init/Deinit APIs ++ * ++ ***********************************************************************/ ++// Setup the sensor type, configure image capture format (RGB, yuv 444, yuv 422, yuv 420, packed | planar, MJPEG) regardless ++// of current operating mode (i.e. sets mode for both still capture and video capture) ++int camera_init( p_camera_context_t camera_context ); ++ ++// Power off sensor ++int camera_deinit( p_camera_context_t camera_context ); ++ ++ ++/*********************************************************************** ++ * ++ * Capture APIs ++ * ++ ***********************************************************************/ ++// Set the image format ++int camera_set_capture_format( p_camera_context_t camera_context ); ++ ++// take a picture and copy it into the ring buffer ++int camera_capture_still_image( p_camera_context_t camera_context, unsigned int block_id ); ++ ++// capture motion video and copy it the ring buffer ++int camera_start_video_capture( p_camera_context_t camera_context, unsigned int block_id ); ++ ++// disable motion video image capture ++void camera_stop_video_capture( p_camera_context_t camera_context ); ++ ++int camera_func_ov9640_command(p_camera_context_t camera_context, unsigned int cmd, void *param); ++ ++/*********************************************************************** ++ * ++ * Flow Control APIs ++ * ++ ***********************************************************************/ ++// continue capture image to next available buffer ++// Returns the continued buffer id, -1 means buffer full and no transfer started ++void camera_continue_transfer( p_camera_context_t camera_context ); ++ ++// Return 1: there is available buffer, 0: buffer is full ++int camera_next_buffer_available( p_camera_context_t camera_context ); ++ ++// Application supplies the FrameBufferID to the driver to tell it that the application has completed processing of the given frame buffer, and that buffer is now available for re-use. ++void camera_release_frame_buffer( p_camera_context_t camera_context, unsigned int frame_buffer_id ); ++ ++// Returns the FrameBufferID for the first filled frame ++// Note: -1 represents buffer empty ++int camera_get_first_frame_buffer_id( p_camera_context_t camera_context ); ++ ++/* ++Returns the FrameBufferID for the last filled frame, this would be used if we were polling for image completion data, ++or we wanted to make sure there were no frames waiting for us to process. ++Note: -1 represents buffer empty ++*/ ++int camera_get_last_frame_buffer_id( p_camera_context_t camera_context ); ++ ++ ++/*********************************************************************** ++ * ++ * Buffer Info APIs ++ * ++ ***********************************************************************/ ++// Return: the number of frame buffers allocated for use. ++unsigned int camera_get_num_frame_buffers( p_camera_context_t camera_context ); ++ ++/* ++FrameBufferID is a number between 0 and N-1, where N is the total number of frame buffers in use. ++Returns the address of the given frame buffer. ++The application will call this once for each frame buffer at application initialization only. ++*/ ++void* camera_get_frame_buffer_addr( p_camera_context_t camera_context, unsigned int frame_buffer_id ); ++ ++// Return the block id ++int camera_get_frame_buffer_id( p_camera_context_t camera_context, void* address ); ++ ++/*********************************************************************** ++ * ++ * Frame rate APIs ++ * ++ ***********************************************************************/ ++// Set desired frame rate ++void camera_set_capture_frame_rate( p_camera_context_t camera_context ); ++ ++// return current setting ++void camera_get_capture_frame_rate( p_camera_context_t camera_context ); ++ ++ ++/*********************************************************************** ++ * ++ * Interrupt APIs ++ * ++ ***********************************************************************/ ++// set interrupt mask ++void camera_set_int_mask( p_camera_context_t camera_context, unsigned int mask ); ++ ++// get interrupt mask ++unsigned int camera_get_int_mask( p_camera_context_t camera_context ); ++ ++// clear interrupt status ++void camera_clear_int_status( p_camera_context_t camera_context, unsigned int status ); ++ ++// gpio init ++void camera_gpio_init(void); ++void camera_gpio_deinit(void); ++ ++// ci functions ++void ci_reset(void); ++ ++// dma functions ++extern void start_dma_transfer(p_camera_context_t camera_context, unsigned block_id); ++extern void stop_dma_transfer(p_camera_context_t camera_context); ++extern int camera_ring_buf_init(p_camera_context_t camera_context); ++ ++#endif +diff -Nurd linux-2.6.16.orig/drivers/media/video/ci.h linux-2.6.16/drivers/media/video/ci.h +--- linux-2.6.16.orig/drivers/media/video/ci.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ci.h 2006-06-03 11:14:56.435309784 +0200 +@@ -0,0 +1,303 @@ ++/******************************************************************************
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++********************************************************************************/
++#ifndef __CI_H__
++#define __CI_H__
++
++//---------------------------------------------------------------------------
++// Register definitions
++//---------------------------------------------------------------------------
++
++extern unsigned long ci_regs_base ; /* for CI registers IOMEM mapping */
++
++#define CI_REG(x) (* (volatile u32*)(x) )
++#define CI_REG_SIZE 0x40 /* 0x5000_0000 --- 0x5000_0038 * 64K */
++#define CI_REGS_PHYS 0x50000000 /* Start phyical address of CI registers */
++//
++#define CICR0 CI_REG((u32)(ci_regs_base) + 0x00)
++#define CICR1 CI_REG((u32)(ci_regs_base) + 0x04)
++#define CICR2 CI_REG((u32)(ci_regs_base) + 0x08)
++#define CICR3 CI_REG((u32)(ci_regs_base) + 0x0c)
++#define CICR4 CI_REG((u32)(ci_regs_base) + 0x10)
++#define CISR CI_REG((u32)(ci_regs_base) + 0x14)
++#define CIFR CI_REG((u32)(ci_regs_base) + 0x18)
++#define CITOR CI_REG((u32)(ci_regs_base) + 0x1c)
++#define CIBR0 CI_REG((u32)(ci_regs_base) + 0x28)
++#define CIBR1 CI_REG((u32)(ci_regs_base) + 0x30)
++#define CIBR2 CI_REG((u32)(ci_regs_base) + 0x38)
++/*
++*/
++enum CI_REGBITS_CICR0 {
++ CI_CICR0_FOM = 0x00000001,
++ CI_CICR0_EOFM = 0x00000002,
++ CI_CICR0_SOFM = 0x00000004,
++ CI_CICR0_CDM = 0x00000008,
++ CI_CICR0_QDM = 0x00000010,
++ CI_CICR0_PERRM = 0x00000020,
++ CI_CICR0_EOLM = 0x00000040,
++ CI_CICR0_FEM = 0x00000080,
++ CI_CICR0_RDAVM = 0x00000100,
++ CI_CICR0_TOM = 0x00000200,
++ CI_CICR0_RESERVED = 0x03FFFC00,
++ CI_CICR0_SIM_SHIFT = 24,
++ CI_CICR0_SIM_SMASK = 0x7,
++ CI_CICR0_DIS = 0x08000000,
++ CI_CICR0_ENB = 0x10000000,
++ CI_CICR0_SL_CAP_EN = 0x20000000,
++ CI_CICR0_PAR_EN = 0x40000000,
++ CI_CICR0_DMA_EN = 0x80000000,
++ CI_CICR0_INTERRUPT_MASK = 0x3FF
++};
++
++enum CI_REGBITS_CICR1 {
++ CI_CICR1_DW_SHIFT = 0,
++ CI_CICR1_DW_SMASK = 0x7,
++ CI_CICR1_COLOR_SP_SHIFT = 3,
++ CI_CICR1_COLOR_SP_SMASK = 0x3,
++ CI_CICR1_RAW_BPP_SHIFT = 5,
++ CI_CICR1_RAW_BPP_SMASK = 0x3,
++ CI_CICR1_RGB_BPP_SHIFT = 7,
++ CI_CICR1_RGB_BPP_SMASK = 0x7,
++ CI_CICR1_YCBCR_F = 0x00000400,
++ CI_CICR1_RBG_F = 0x00000800,
++ CI_CICR1_RGB_CONV_SHIFT = 12,
++ CI_CICR1_RGB_CONV_SMASK = 0x7,
++ CI_CICR1_PPL_SHIFT = 15,
++ CI_CICR1_PPL_SMASK = 0x7FF,
++ CI_CICR1_RESERVED = 0x1C000000,
++ CI_CICR1_RGBT_CONV_SHIFT= 29,
++ CI_CICR1_RGBT_CONV_SMASK= 0x3,
++ CI_CICR1_TBIT = 0x80000000
++};
++
++enum CI_REGBITS_CICR2 {
++ CI_CICR2_FSW_SHIFT = 0,
++ CI_CICR2_FSW_SMASK = 0x3,
++ CI_CICR2_BFPW_SHIFT= 3,
++ CI_CICR2_BFPW_SMASK= 0x3F,
++ CI_CICR2_RESERVED = 0x00000200,
++ CI_CICR2_HSW_SHIFT = 10,
++ CI_CICR2_HSW_SMASK = 0x3F,
++ CI_CICR2_ELW_SHIFT = 16,
++ CI_CICR2_ELW_SMASK = 0xFF,
++ CI_CICR2_BLW_SHIFT = 24,
++ CI_CICR2_BLW_SMASK = 0xFF
++};
++
++enum CI_REGBITS_CICR3 {
++ CI_CICR3_LPF_SHIFT = 0,
++ CI_CICR3_LPF_SMASK = 0x7FF,
++ CI_CICR3_VSW_SHIFT = 11,
++ CI_CICR3_VSW_SMASK = 0x1F,
++ CI_CICR3_EFW_SHIFT = 16,
++ CI_CICR3_EFW_SMASK = 0xFF,
++ CI_CICR3_BFW_SHIFT = 24,
++ CI_CICR3_BFW_SMASK = 0xFF
++};
++
++enum CI_REGBITS_CICR4 {
++ CI_CICR4_DIV_SHIFT = 0,
++ CI_CICR4_DIV_SMASK = 0xFF,
++ CI_CICR4_FR_RATE_SHIFT = 8,
++ CI_CICR4_FR_RATE_SMASK = 0x7,
++ CI_CICR4_RESERVED1 = 0x0007F800,
++ CI_CICR4_MCLK_EN = 0x00080000,
++ CI_CICR4_VSP = 0x00100000,
++ CI_CICR4_HSP = 0x00200000,
++ CI_CICR4_PCP = 0x00400000,
++ CI_CICR4_PCLK_EN = 0x00800000,
++ CI_CICR4_RESERVED2 = 0xFF000000,
++ CI_CICR4_RESERVED = CI_CICR4_RESERVED1 | CI_CICR4_RESERVED2
++};
++
++enum CI_REGBITS_CISR {
++ CI_CISR_IFO_0 = 0x00000001,
++ CI_CISR_IFO_1 = 0x00000002,
++ CI_CISR_IFO_2 = 0x00000004,
++ CI_CISR_EOF = 0x00000008,
++ CI_CISR_SOF = 0x00000010,
++ CI_CISR_CDD = 0x00000020,
++ CI_CISR_CQD = 0x00000040,
++ CI_CISR_PAR_ERR = 0x00000080,
++ CI_CISR_EOL = 0x00000100,
++ CI_CISR_FEMPTY_0 = 0x00000200,
++ CI_CISR_FEMPTY_1 = 0x00000400,
++ CI_CISR_FEMPTY_2 = 0x00000800,
++ CI_CISR_RDAV_0 = 0x00001000,
++ CI_CISR_RDAV_1 = 0x00002000,
++ CI_CISR_RDAV_2 = 0x00004000,
++ CI_CISR_FTO = 0x00008000,
++ CI_CISR_RESERVED = 0xFFFF0000
++};
++
++enum CI_REGBITS_CIFR {
++ CI_CIFR_FEN0 = 0x00000001,
++ CI_CIFR_FEN1 = 0x00000002,
++ CI_CIFR_FEN2 = 0x00000004,
++ CI_CIFR_RESETF = 0x00000008,
++ CI_CIFR_THL_0_SHIFT= 4,
++ CI_CIFR_THL_0_SMASK= 0x3,
++ CI_CIFR_RESERVED1 = 0x000000C0,
++ CI_CIFR_FLVL0_SHIFT= 8,
++ CI_CIFR_FLVL0_SMASK= 0xFF,
++ CI_CIFR_FLVL1_SHIFT= 16,
++ CI_CIFR_FLVL1_SMASK= 0x7F,
++ CI_CIFR_FLVL2_SHIFT= 23,
++ CI_CIFR_FLVL2_SMASK= 0x7F,
++ CI_CIFR_RESERVED2 = 0xC0000000,
++ CI_CIFR_RESERVED = CI_CIFR_RESERVED1 | CI_CIFR_RESERVED2
++};
++
++//---------------------------------------------------------------------------
++// Parameter Type definitions
++//---------------------------------------------------------------------------
++typedef enum {
++ CI_RAW8 = 0, //RAW
++ CI_RAW9,
++ CI_RAW10,
++ CI_YCBCR422, //YCBCR
++ CI_YCBCR422_PLANAR, //YCBCR Planaried
++ CI_RGB444, //RGB
++ CI_RGB555,
++ CI_RGB565,
++ CI_RGB666,
++ CI_RGB888,
++ CI_RGBT555_0, //RGB+Transparent bit 0
++ CI_RGBT888_0,
++ CI_RGBT555_1, //RGB+Transparent bit 1
++ CI_RGBT888_1,
++ CI_RGB666_PACKED, //RGB Packed
++ CI_RGB888_PACKED,
++ CI_INVALID_FORMAT = 0xFF
++} CI_IMAGE_FORMAT;
++
++typedef enum {
++ CI_INTSTATUS_IFO_0 = 0x00000001,
++ CI_INTSTATUS_IFO_1 = 0x00000002,
++ CI_INTSTATUS_IFO_2 = 0x00000004,
++ CI_INTSTATUS_EOF = 0x00000008,
++ CI_INTSTATUS_SOF = 0x00000010,
++ CI_INTSTATUS_CDD = 0x00000020,
++ CI_INTSTATUS_CQD = 0x00000040,
++ CI_INTSTATUS_PAR_ERR = 0x00000080,
++ CI_INTSTATUS_EOL = 0x00000100,
++ CI_INTSTATUS_FEMPTY_0 = 0x00000200,
++ CI_INTSTATUS_FEMPTY_1 = 0x00000400,
++ CI_INTSTATUS_FEMPTY_2 = 0x00000800,
++ CI_INTSTATUS_RDAV_0 = 0x00001000,
++ CI_INTSTATUS_RDAV_1 = 0x00002000,
++ CI_INTSTATUS_RDAV_2 = 0x00004000,
++ CI_INTSTATUS_FTO = 0x00008000,
++ CI_INTSTATUS_ALL = 0x0000FFFF
++} CI_INTERRUPT_STATUS;
++
++typedef enum {
++ CI_INT_IFO = 0x00000001,
++ CI_INT_EOF = 0x00000002,
++ CI_INT_SOF = 0x00000004,
++ CI_INT_CDD = 0x00000008,
++ CI_INT_CQD = 0x00000010,
++ CI_INT_PAR_ERR = 0x00000020,
++ CI_INT_EOL = 0x00000040,
++ CI_INT_FEMPTY = 0x00000080,
++ CI_INT_RDAV = 0x00000100,
++ CI_INT_FTO = 0x00000200,
++ CI_INT_ALL = 0x000003FF
++} CI_INTERRUPT_MASK;
++#define CI_INT_MAX 10
++
++typedef enum CI_MODE {
++ CI_MODE_MP, // Master-Parallel
++ CI_MODE_SP, // Slave-Parallel
++ CI_MODE_MS, // Master-Serial
++ CI_MODE_EP, // Embedded-Parallel
++ CI_MODE_ES // Embedded-Serial
++} CI_MODE;
++
++
++typedef enum {
++ CI_FR_ALL = 0, // Capture all incoming frames
++ CI_FR_1_2, // Capture 1 out of every 2 frames
++ CI_FR_1_3, // Capture 1 out of every 3 frames
++ CI_FR_1_4,
++ CI_FR_1_5,
++ CI_FR_1_6,
++ CI_FR_1_7,
++ CI_FR_1_8
++} CI_FRAME_CAPTURE_RATE;
++
++
++typedef enum {
++ CI_FIFO_THL_32 = 0,
++ CI_FIFO_THL_64,
++ CI_FIFO_THL_96
++} CI_FIFO_THRESHOLD;
++
++typedef struct {
++ unsigned int BFW;
++ unsigned int BLW;
++} CI_MP_TIMING, CI_MS_TIMING;
++
++typedef struct {
++ unsigned int BLW;
++ unsigned int ELW;
++ unsigned int HSW;
++ unsigned int BFPW;
++ unsigned int FSW;
++ unsigned int BFW;
++ unsigned int EFW;
++ unsigned int VSW;
++} CI_SP_TIMING;
++
++typedef enum {
++ CI_DATA_WIDTH4 = 0x0,
++ CI_DATA_WIDTH5 = 0x1,
++ CI_DATA_WIDTH8 = 0x2,
++ CI_DATA_WIDTH9 = 0x3,
++ CI_DATA_WIDTH10= 0x4
++} CI_DATA_WIDTH;
++
++//-------------------------------------------------------------------------------------------------------
++// Configuration APIs
++//-------------------------------------------------------------------------------------------------------
++
++void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate);
++CI_FRAME_CAPTURE_RATE ci_get_frame_rate();
++void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format);
++void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width);
++void ci_configure_mp(unsigned int PPL, unsigned int LPF, CI_MP_TIMING* timing);
++void ci_configure_sp(unsigned int PPL, unsigned int LPF, CI_SP_TIMING* timing);
++void ci_configure_ms(unsigned int PPL, unsigned int LPF, CI_MS_TIMING* timing);
++void ci_configure_ep(int parity_check);
++void ci_configure_es(int parity_check);
++void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz);
++void ci_set_polarity(int pclk_sample_falling, int hsync_active_low, int vsync_active_low);
++void ci_set_fifo( unsigned int timeout, CI_FIFO_THRESHOLD threshold, int fifo1_enable,
++ int fifo2_enable);
++void ci_set_int_mask( unsigned int mask);
++void ci_clear_int_status( unsigned int status);
++void ci_set_reg_value( unsigned int reg_offset, unsigned int value);
++int ci_get_reg_value(unsigned int reg_offset);
++
++void ci_reset_fifo(void);
++unsigned int ci_get_int_mask(void);
++unsigned int ci_get_int_status(void);
++void ci_slave_capture_enable(void);
++void ci_slave_capture_disable(void);
++
++//-------------------------------------------------------------------------------------------------------
++// Control APIs
++//-------------------------------------------------------------------------------------------------------
++int ci_init(void);
++void ci_deinit(void);
++void ci_enable( int dma_en);
++int ci_disable(int quick);
++
++//debug
++void ci_dump(void);
++// IRQ
++void pxa_camera_irq(int irq, void *dev_id, struct pt_regs *regs);
++
++#endif
+diff -Nurd linux-2.6.16.orig/drivers/media/video/e680_camera.c linux-2.6.16/drivers/media/video/e680_camera.c +--- linux-2.6.16.orig/drivers/media/video/e680_camera.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/e680_camera.c 2006-06-03 11:14:56.435309784 +0200 +@@ -0,0 +1,144 @@ ++ ++ ++/*================================================================================ ++ ++ Header Name: e680_camera.c ++ ++General Description: Camera module interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 04/15/2004 Created ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++ ++#include <asm/pgtable.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++ ++#include "camera.h" ++#include "adcm2700.h" ++ ++#define MCLK_DEFT 13 /* Default Master clock*/ ++ ++extern int i2c_adcm2700_init(void); ++extern int i2c_mt9v111_init(void); ++////////////////////////////////////////////////////////////////////////////////////// ++//adcm2700 functions ++// ++int camera_func_adcm2700_init(p_camera_context_t); ++int camera_func_adcm2700_deinit(p_camera_context_t); ++int camera_func_adcm2700_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++int camera_func_adcm2700_set_capture_format(p_camera_context_t); ++int camera_func_adcm2700_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_adcm2700_stop_capture(p_camera_context_t); ++ ++int camera_func_adcm2700_pm_management(p_camera_context_t, int); ++ ++////////////////////////////////////////////////////////////////////////////////////// ++//mt9v111 functions ++// ++int camera_func_mt9v111_init(p_camera_context_t); ++int camera_func_mt9v111_deinit(p_camera_context_t); ++int camera_func_mt9v111_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++int camera_func_mt9v111_set_capture_format(p_camera_context_t); ++int camera_func_mt9v111_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_mt9v111_stop_capture(p_camera_context_t); ++ ++int camera_func_mt9v111_pm_management(p_camera_context_t, int); ++ ++ ++extern int camera_func_init(p_camera_context_t cam_ctx); ++ ++ ++camera_function_t camera_func = ++{ ++ init: camera_func_init, ++}; ++ ++int camera_func_init(p_camera_context_t cam_ctx) ++{ ++ // Configure CI according to hardware ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ ++ // enable pixel clock(sensor will provide pclock) and master clock = 26MHZ ++ ci_set_clock(cam_ctx->clk_reg_base, 1, 1, MCLK_DEFT); ++ ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(0, 0, 0); ++ ++ // fifo control ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); // quality ++ ++ // Turn on M_CLK using xx MHz and wait for 150 ms. ++ ci_enable(1); ++ mdelay(150); ++ ++ cam_ctx->mclk = MCLK_DEFT; ++ dbg_print("detect..."); ++ if(i2c_adcm2700_init() == 0) ++ { ++ dbg_print("Agilent ADCM2700 camera module detected!"); ++ cam_ctx->sensor_type = CAMERA_TYPE_ADCM_2700; ++ ++ camera_func.deinit = camera_func_adcm2700_deinit; ++ camera_func.command = camera_func_adcm2700_docommand; ++ camera_func.set_capture_format = camera_func_adcm2700_set_capture_format; ++ camera_func.start_capture = camera_func_adcm2700_start_capture; ++ camera_func.stop_capture = camera_func_adcm2700_stop_capture; ++ camera_func.pm_management = camera_func_adcm2700_pm_management; ++ ++ return camera_func_adcm2700_init(cam_ctx); ++ } ++ else if(i2c_mt9v111_init() == 0) ++ { ++ dbg_print("Micro MT9V111 camera module detected!"); ++ cam_ctx->sensor_type = CAMERA_TYPE_MT9V111; ++ ++ camera_func.deinit = camera_func_mt9v111_deinit; ++ camera_func.command = camera_func_mt9v111_docommand; ++ camera_func.set_capture_format = camera_func_mt9v111_set_capture_format; ++ camera_func.start_capture = camera_func_mt9v111_start_capture; ++ camera_func.stop_capture = camera_func_mt9v111_stop_capture; ++ camera_func.pm_management = camera_func_mt9v111_pm_management; ++ ++ return camera_func_mt9v111_init(cam_ctx); ++ } ++ return -1; ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/Kconfig linux-2.6.16/drivers/media/video/Kconfig +--- linux-2.6.16.orig/drivers/media/video/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/Kconfig 2006-06-03 11:14:56.422311760 +0200 +@@ -349,8 +349,40 @@ + config VIDEO_DECODER + tristate "Add support for additional video chipsets" + depends on VIDEO_DEV && I2C && EXPERIMENTAL ++ select FW_LOADER + ---help--- + Say Y here to compile drivers for SAA7115, SAA7127 and CX25840 + video decoders. + ++config PXA_CAMERA ++ depends on VIDEO_DEV ++ tristate "Camera Interface for PXA27x" ++ ++choice ++ prompt "PXA27x Camera Type" ++ depends on PXA_CAMERA ++ ++config CAMERA_ADCM2700 ++ select I2C_ADCM2700 ++ bool "ADCM2700" ++ ++config CAMERA_MT9M111 ++ select I2C_A780_CAMERA ++ bool "Mt9m111" ++ ++config CAMERA_OV9640 ++ select I2C_A780_CAMERA ++ bool "Omnivision 9640" ++ ++config CAMERA_OV9650 ++ select I2C_A780_CAMERA ++ bool "Omnivision 9650" ++ ++config CAMERA_ADCM3800 ++ select I2C_A780_CAMERA ++ bool "ADCM3900" ++ ++endchoice ++ ++ + endmenu +diff -Nurd linux-2.6.16.orig/drivers/media/video/Makefile linux-2.6.16/drivers/media/video/Makefile +--- linux-2.6.16.orig/drivers/media/video/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/Makefile 2006-06-03 11:14:56.422311760 +0200 +@@ -19,6 +19,14 @@ + tda7432.o tda9875.o ir-kbd-i2c.o + obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o + ++obj-$(CONFIG_PXA_CAMERA) += pxa_camera.o ++ ++obj-$(CONFIG_CAMERA_ADCM2700) += adcm2700.o adcm2700_hw.o ++obj-$(CONFIG_CAMERA_OV9640) += ov9640.o ov9640_hw.o ++obj-$(CONFIG_CAMERA_OV9650) += ov9650.o ov9650_hw.o ++obj-$(CONFIG_CAMERA_MT9M111) += mt9m111.o mt9m111_hw.o ++obj-$(CONFIG_CAMERA_ADCM3800) += adcm3800.o adcm3800_hw.o ++ + obj-$(CONFIG_VIDEO_ZR36120) += zoran.o + obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o + obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o +diff -Nurd linux-2.6.16.orig/drivers/media/video/mt9m111.c linux-2.6.16/drivers/media/video/mt9m111.c +--- linux-2.6.16.orig/drivers/media/video/mt9m111.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/mt9m111.c 2006-06-03 11:14:56.436309632 +0200 +@@ -0,0 +1,795 @@ ++ ++/*================================================================================ ++ ++ Header Name: mt9m111.c ++ ++General Description: Camera module mt9m111 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Ma Zhiqiang 06/29/2004 Change for auto-detect ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++ ++#include <asm/pgtable.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++ ++#include "camera.h" ++#include "mt9m111.h" ++#include "mt9m111_hw.h" ++ ++//#define LOG_TIME_STAMP //If defined, the time stamp log will be printed out ++//#define MT9M111_LOG //If defined, the mt9m111_mt9m111_dbg_print logs will be printed out ++//#define MT9M111_ECHO_CMD //If defined, the "echo {address, value} > cam" commands will be enabled. ++ ++#ifdef MT9M111_LOG ++#define mt9m111_dbg_print(fmt, args...) dbg_print(fmt, ##args) ++#else ++#define mt9m111_dbg_print(fmt, args...) ; ++#endif ++ ++#define MCLK_DEFT (24) /* Default Master clock*/ ++#define MSCWR1_CAMERA_ON (0x1 << 15) /* Camera Interface Power Control */ ++#define MSCWR1_CAMERA_SEL (0x1 << 14) /* Camera Interface Mux control */ ++ ++#define MAX_WIDTH 1280 ++#define MAX_HEIGHT 1024 ++ ++#define MIN_WIDTH 40 ++#define MIN_HEIGHT 30 ++ ++#define VIEW_FINDER_WIDTH_DEFT 320 ++#define VIEW_FINDER_HEIGHT_DEFT 240 ++ ++#define FRAMERATE_DEFT 15 ++#define BUF_SIZE_DEFT ((PAGE_ALIGN(MAX_WIDTH * MAX_HEIGHT) + (PAGE_ALIGN(MAX_WIDTH*MAX_HEIGHT/2)*2))) ++ ++extern int mt9m111_read(u16 addr, u16 *pvalue); ++extern int mt9m111_write(u16 addr, u16 value); ++extern int i2c_mt9m111_cleanup(void); ++extern int i2c_mt9m111_init(void); ++ ++extern void stop_dma_transfer(p_camera_context_t camera_context); ++extern int camera_ring_buf_init(p_camera_context_t camera_context); ++extern void camera_gpio_init(void); ++extern void camera_gpio_deinit(void); ++extern void start_dma_transfer(p_camera_context_t camera_context, unsigned block_id); ++ ++/*********************************************************************** ++ * ++ * MT9M111 Functions ++ * ++ ***********************************************************************/ ++int camera_func_mt9m111_init(p_camera_context_t); ++int camera_func_mt9m111_deinit(p_camera_context_t); ++int camera_func_mt9m111_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++int camera_func_mt9m111_set_capture_format(p_camera_context_t); ++int camera_func_mt9m111_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_mt9m111_stop_capture(p_camera_context_t); ++int camera_func_mt9m111_pm_management(p_camera_context_t, int); ++ ++ ++camera_function_t mt9m111_func = ++{ ++ init: camera_func_mt9m111_init, ++ deinit: camera_func_mt9m111_deinit, ++ command: camera_func_mt9m111_docommand, ++ set_capture_format: camera_func_mt9m111_set_capture_format, ++ start_capture: camera_func_mt9m111_start_capture, ++ stop_capture: camera_func_mt9m111_stop_capture, ++ pm_management: camera_func_mt9m111_pm_management ++}; ++ ++int camera_func_mt9m111_init( p_camera_context_t cam_ctx ) ++{ ++ u16 device_id = 0 ; ++ ++ // init context status ++ cam_ctx->dma_channels[0] = 0xFF; ++ cam_ctx->dma_channels[1] = 0xFF; ++ cam_ctx->dma_channels[2] = 0xFF; ++ ++ cam_ctx->capture_width = VIEW_FINDER_WIDTH_DEFT; ++ cam_ctx->capture_height = VIEW_FINDER_HEIGHT_DEFT; ++ ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ ++ cam_ctx->frame_rate = cam_ctx->fps = FRAMERATE_DEFT; ++ ++ cam_ctx->mini_fps = FRAMERATE_DEFT; ++ ++ cam_ctx->mclk = MCLK_DEFT; ++ ++ cam_ctx->buf_size = BUF_SIZE_DEFT; ++ cam_ctx->dma_descriptors_size = (cam_ctx->buf_size/PAGE_SIZE + 10); ++ strcpy (cam_ctx->vc.name, "Micron MT9M111"); ++ cam_ctx->vc.maxwidth = MAX_WIDTH; ++ cam_ctx->vc.maxheight = MAX_HEIGHT; ++ cam_ctx->vc.minwidth = MIN_WIDTH; ++ cam_ctx->vc.minheight = MIN_HEIGHT; ++ ++ camera_gpio_init(); ++ ci_init(); ++ ++ // Configure CI according to MT9M111's hardware ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ ++ // enable pixel clock(sensor will provide pclock) ++ ci_set_clock(cam_ctx->clk_reg_base, 1, 1, cam_ctx->mclk); ++ ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(1, 0, 0); ++ ++ // fifo control ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); // quality ++ ++ // Turn on M_CLK and wait for 150 ms. ++ ci_enable(1); ++ //mdelay(150); ++ ++ i2c_mt9m111_init(); ++ ++ // read out device id ++ mt9m111_get_device_id(&device_id); ++ if(device_id != 0x1419 && device_id != 0x1429 && device_id != 0x143A) ++ { ++ //ci_disable(1); ++ //camera_gpio_deinit(); ++ return -1; ++ } ++ else ++ { ++ mt9m111_dbg_print("Micron MT9M111 camera module detected!"); ++ } ++ ++ ++ /* To resolve the vertical line in view finder issue (LIBff11930) ++ * The solution is: ++ * AP Kernel camera driver: set TCMM_EN to low when camera is running and TCMM_EN to high when camera stops. ++ * BP Software: if TCMM_EN is low, BP do not shut off 26M clock ,but BP can sleep itself.*/ ++ ++ set_GPIO_mode(99|GPIO_OUT);//It's GPIO99 for the "TCMM_EN" ++ GPCR(99) = GPIO_bit(99); ++ ++ cam_ctx->sensor_type = CAMERA_TYPE_MT9M111; ++ ++ mt9m111_default_settings(); ++ ++ mt9m111_dbg_print("mt9m111 init success!"); ++ ++#ifdef MT9M111_ECHO_CMD ++ /*for test commmand throught terminal*/ ++ struct proc_dir_entry *pw; ++ static ssize_t test_command_write(struct file *file, const char *buf, size_t count, loff_t *pos); ++ ++ static struct file_operations test_command_funcs = ++ { ++ read:NULL, ++ write:test_command_write, ++ }; ++ ++ if ((pw = create_proc_entry ("cam", 0666, 0)) != NULL) ++ { ++ pw->proc_fops = &test_command_funcs; ++ } ++#endif ++ return 0; ++} ++ ++static void mt9m111_gpio_deinit(void) ++{ ++ GPSR(CIF_PD) = GPIO_bit(CIF_PD); ++} ++ ++int camera_func_mt9m111_deinit( p_camera_context_t camera_context ) ++{ ++ mt9m111_write(0x1B3, 0); ++ mdelay(5); ++ ++ i2c_mt9m111_cleanup(); ++ ++ /* disable CI */ ++ ci_disable(1); ++ ++ mt9m111_gpio_deinit(); ++ ++#ifdef MT9M111_ECHO_CMD ++ /*for test commmand throught terminal*/ ++ remove_proc_entry ("cam", NULL); ++#endif ++ ++ /* To resolve the vertical line in view finder issue (LIBff11930) ++ * The solution is: ++ * AP Kernel camera driver: set TCMM_EN to low when camera is running and TCMM_EN to high when camera stops. ++ * BP Software: if TCMM_EN is low, BP do not shut off 26M clock ,but BP can sleep itself.*/ ++ ++ set_GPIO_mode(99|GPIO_OUT);//It's GPIO99 for the "TCMM_EN" ++ GPSR(99) = GPIO_bit(99); ++ ++ return 0; ++} ++ ++int camera_func_mt9m111_set_capture_format( p_camera_context_t camera_context ) ++{ ++ micron_window_size wsize; ++ u16 micron_format; ++ mt9m111_dbg_print(""); ++ ++ // set sensor input/output window ++ wsize.width = camera_context->capture_width; ++ wsize.height = camera_context->capture_height; ++ mt9m111_output_size(&wsize); ++ ++ // set sensor format ++ switch(camera_context->capture_input_format) { ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ micron_format = O_FORMAT_422_YCbYCr; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ micron_format = O_FORMAT_565_RGB; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB555: ++ micron_format = O_FORMAT_555_RGB; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB444: ++ micron_format = O_FORMAT_444_RGB; ++ break; ++ default: ++ micron_format = O_FORMAT_422_YCbYCr; ++ break; ++ } ++ mt9m111_output_format(micron_format); ++ ++ return 0; ++} ++ ++int camera_func_mt9m111_start_capture( p_camera_context_t cam_ctx, unsigned int frames ) ++{ ++ int waitingFrame = 0; ++ ++#ifdef LOG_TIME_STAMP ++ struct timeval tv0,tv1,tv2,tv3,tv4; ++ do_gettimeofday(&tv0); ++#endif ++ ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ ++ // frames=0 means video mode capture ++ if (frames == 0) ++ { ++ mt9m111_dbg_print("video capture!"); ++ mt9m111_viewfinder_on(); ++ } ++ else ++ { ++ mt9m111_dbg_print("still capture"); ++ mt9m111_snapshot_trigger(); ++ } ++ ++#ifdef LOG_TIME_STAMP ++ do_gettimeofday(&tv1); ++#endif ++ ++ ci_disable(1); ++ ci_enable(1); ++ ++#ifdef LOG_TIME_STAMP ++ do_gettimeofday(&tv2); ++#endif ++ ++ if(frames == 1) //Wait 1 frames to begin capture photo ++ { ++ waitingFrame = 1; ++ } ++ else ++ { ++ waitingFrame = 1; ++ } ++ ++ while(waitingFrame--) ++ { ++ CISR |= (1<<4); ++ while(!(CISR&(1<<4))); //Wait a SOF then begin start DMA ++ } ++ ++#ifdef LOG_TIME_STAMP ++ do_gettimeofday(&tv3); ++#endif ++ ++ ci_disable(1); ++ ci_enable(1); ++ ci_reset_fifo(); ++ start_dma_transfer(cam_ctx, 0); ++ ++#ifdef LOG_TIME_STAMP ++ do_gettimeofday(&tv4); ++ ++ printk("mt9m111 capture: Begin time is sec: %d , msec: %d\n", tv0.tv_sec, tv0.tv_usec/1000); ++ printk("mt9m111 capture: End time is sec: %d , msec: %d\n", tv4.tv_sec, tv4.tv_usec/1000); ++ if(frames) ++ printk("mt9m111 capture: Total time(photo) is %d ms\n\n", (tv4.tv_sec-tv0.tv_sec)*1000+ (tv4.tv_usec-tv0.tv_usec)/1000); ++ else ++ printk("mt9m111 capture: Total time(preview) is %d ms\n\n", (tv4.tv_sec-tv0.tv_sec)*1000+ (tv4.tv_usec-tv0.tv_usec)/1000); ++ printk("mt9m111 capture: Write reg time is %d ms\n\n", (tv1.tv_sec-tv0.tv_sec)*1000+ (tv1.tv_usec-tv0.tv_usec)/1000); ++ printk("mt9m111 capture: Reset ci time is %d ms\n\n", (tv2.tv_sec-tv1.tv_sec)*1000+ (tv2.tv_usec-tv1.tv_usec)/1000); ++ printk("mt9m111 capture: Wait sof time is %d ms\n\n", (tv3.tv_sec-tv2.tv_sec)*1000+ (tv3.tv_usec-tv2.tv_usec)/1000); ++ printk("mt9m111 capture: Left time is %d ms\n\n", (tv4.tv_sec-tv3.tv_sec)*1000+ (tv4.tv_usec-tv3.tv_usec)/1000); ++#endif ++ return 0; ++} ++ ++int camera_func_mt9m111_stop_capture( p_camera_context_t camera_context ) ++{ ++ mt9m111_viewfinder_off(); ++ stop_dma_transfer(camera_context); ++ ++ /* disable CI */ ++ //ci_disable(1); ++ ++ return 0; ++} ++ ++static int camera_mt9m111_restore_settings(p_camera_context_t cam_ctx) ++{ ++ micron_window_size size; ++ ++ size.width = cam_ctx->sensor_width; ++ size.height = cam_ctx->sensor_height; ++ mt9m111_input_size(&size); ++ ++ size.width = cam_ctx->capture_width; ++ size.height = cam_ctx->capture_height; ++ mt9m111_output_size(&size); ++ ++ mt9m111_set_bright(cam_ctx->capture_bright); ++ ++ mt9m111_set_fps(cam_ctx->fps, cam_ctx->mini_fps); ++ mt9m111_set_light(cam_ctx->capture_light); ++ mt9m111_set_style(cam_ctx->capture_style); ++ //mt9m111_set_contrast(cam_ctx->capture_contrast); ++ mt9m111_set_autoexposure_zone(cam_ctx->mini_fps); ++ mt9m111_set_flicker(cam_ctx->flicker_freq); ++ ++ return 0; ++} ++ ++int camera_func_mt9m111_pm_management(p_camera_context_t cam_ctx, int suspend) ++{ ++ static int resume_dma = 0; ++ if(suspend) ++ { ++ if(cam_ctx != NULL ) ++ { ++ if(cam_ctx->dma_started) ++ { ++ mt9m111_dbg_print("camera running, suspended"); ++ stop_dma_transfer(cam_ctx); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ CKEN &= ~CKEN24_CAMERA; ++ } ++ else ++ { ++ CKEN |= CKEN24_CAMERA; ++ enable_irq(IRQ_CAMERA); ++ ++ if(cam_ctx != NULL) ++ { ++ mt9m111_dbg_print("camera running, resumed"); ++ camera_init(cam_ctx); ++ ++ camera_mt9m111_restore_settings(cam_ctx); ++ ++ if(resume_dma == 1) ++ { ++ camera_start_video_capture(cam_ctx, 0); ++ resume_dma = 0; ++ } ++ } ++ } ++ return 0; ++} ++ ++static int pxa_camera_WCAM_VIDIOCGCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ int reg_value, offset; ++ mt9m111_dbg_print("WCAM_VIDIOCGCAMREG"); ++ if(copy_from_user(&offset, param, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ reg_value = (int)mt9m111_reg_read((u16)offset); ++ ++ if(copy_to_user(param, ®_value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++static int pxa_camera_WCAM_VIDIOCSCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ struct reg_set_s{int val1; int val2;} reg_s; ++ mt9m111_dbg_print("WCAM_VIDIOCSCAMREG"); ++ ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ mt9m111_reg_write((u16)reg_s.val1, (u16)reg_s.val2); ++ return 0; ++} ++ ++static int pxa_cam_WCAM_VIDIOCSFPS(p_camera_context_t cam_ctx, void * param) ++{ ++ struct {int fps, minfps;} cam_fps; ++ mt9m111_dbg_print("WCAM_VIDIOCSFPS"); ++ if(copy_from_user(&cam_fps, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ mt9m111_set_fps(cam_fps.fps, cam_fps.minfps); ++ return 0; ++} ++ ++ ++/*Set sensor size*/ ++static int pxa_cam_WCAM_VIDIOCSSSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ micron_window_size size; ++ mt9m111_dbg_print("WCAM_VIDIOCSSSIZE"); ++ ++ if(copy_from_user(&size, param, sizeof(micron_window_size))) ++ { ++ return -EFAULT; ++ } ++ ++ size.width = (size.width+3)/4 * 4; ++ size.height = (size.height+3)/4 * 4; ++ cam_ctx->sensor_width = size.width; ++ cam_ctx->sensor_height = size.height; ++ mt9m111_input_size(&size); ++ return 0; ++} ++ ++//set output size ++static int pxa_cam_WCAM_VIDIOCSOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ micron_window_size size; ++ CI_MP_TIMING timing; ++ mt9m111_dbg_print("WCAM_VIDIOCSOSIZE"); ++ ++ if(copy_from_user(&size, param, sizeof(micron_window_size))) ++ { ++ return -EFAULT; ++ } ++ ++ //make it in an even number ++ size.width = (size.width+1)/2 * 2; ++ size.height = (size.height+1)/2 * 2; ++ mt9m111_output_size(&size); ++ ++ cam_ctx->capture_width = size.width; ++ cam_ctx->capture_height = size.height; ++ timing.BFW = timing.BLW = 0; ++ ++ ci_configure_mp(cam_ctx->capture_width-1, cam_ctx->capture_height-1, &timing); ++ camera_ring_buf_init(cam_ctx); ++ ++ return 0; ++} ++ ++/*set picture style*/ ++static int pxa_cam_WCAM_VIDIOCSSTYLE(p_camera_context_t cam_ctx, void * param) ++{ ++ mt9m111_dbg_print("WCAM_VIDIOCSSTYLE"); ++ cam_ctx->capture_style = (V4l_PIC_STYLE)param; ++ ++ return mt9m111_set_style(cam_ctx->capture_style); ++} ++ ++/*set picture light*/ ++static int pxa_cam_WCAM_VIDIOCSLIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ mt9m111_dbg_print("WCAM_VIDIOCSLIGHT"); ++ cam_ctx->capture_light = (V4l_PIC_WB)param; ++ ++ return mt9m111_set_light((V4l_PIC_WB)param); ++} ++ ++/*set picture brightness*/ ++static int pxa_cam_WCAM_VIDIOCSBRIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ mt9m111_dbg_print("WCAM_VIDIOCSBRIGHT"); ++ cam_ctx->capture_bright = (int)param; ++ ++ return mt9m111_set_bright((int)param); ++} ++ ++/*set picture contrast*/ ++/*static int pxa_cam_WCAM_VIDIOCSCONTRAST(p_camera_context_t cam_ctx, void * param) ++{ ++ mt9m111_dbg_print("WCAM_VIDIOCSCONTRAST"); ++ cam_ctx->capture_contrast = ((int)param-50)/12; ++ ++ return mt9m111_set_contrast(cam_ctx->capture_contrast); ++}*/ ++ ++/*set flicker frequency*/ ++static int pxa_cam_WCAM_VIDIOCSFLICKER(p_camera_context_t cam_ctx, void * param) ++{ ++ mt9m111_dbg_print("WCAM_VIDIOCSFLICKER"); ++ cam_ctx->flicker_freq = (int)param; ++ ++ return mt9m111_set_flicker(cam_ctx->flicker_freq); ++} ++ ++ ++/*set night mode*/ ++static int pxa_cam_WCAM_VIDIOCSNIGHTMODE(p_camera_context_t cam_ctx, void * param) ++{ ++ struct {u32 mode, maxexpotime; } cam_mode; ++ u32 maxexpotime; ++ ++ if (copy_from_user(&cam_mode, param, sizeof(cam_mode))) ++ { ++ return -EFAULT; ++ } ++ ++ maxexpotime = cam_mode.maxexpotime; ++ if(maxexpotime == 0) ++ { ++ return -EFAULT; ++ } ++ ++ switch (cam_mode.mode) ++ { ++ case V4l_NM_NIGHT: ++ case V4l_NM_ACTION: ++ case V4l_NM_AUTO: ++ cam_ctx->mini_fps = (1000000+maxexpotime/2)/maxexpotime; ++ mt9m111_set_autoexposure_zone(cam_ctx->mini_fps); ++ break; ++ default: ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int camera_func_mt9m111_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param) ++{ ++ switch(cmd) ++ { ++ /*read mt9m111 registers*/ ++ case WCAM_VIDIOCGCAMREG: ++ return pxa_camera_WCAM_VIDIOCGCAMREG(cam_ctx, param); ++ ++ /*write mt9m111 registers*/ ++ case WCAM_VIDIOCSCAMREG: ++ return pxa_camera_WCAM_VIDIOCSCAMREG(cam_ctx, param); ++ ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return pxa_cam_WCAM_VIDIOCSSSIZE(cam_ctx, param); ++ ++ /*set output size*/ ++ case WCAM_VIDIOCSOSIZE: ++ return pxa_cam_WCAM_VIDIOCSOSIZE(cam_ctx, param); ++ ++ /*set video mode fps*/ ++ case WCAM_VIDIOCSFPS: ++ return pxa_cam_WCAM_VIDIOCSFPS(cam_ctx, param); ++ ++ /*set picture style*/ ++ case WCAM_VIDIOCSSTYLE: ++ return pxa_cam_WCAM_VIDIOCSSTYLE(cam_ctx, param); ++ ++ /*set picture light*/ ++ case WCAM_VIDIOCSLIGHT: ++ return pxa_cam_WCAM_VIDIOCSLIGHT(cam_ctx, param); ++ ++ /*set picture brightness*/ ++ case WCAM_VIDIOCSBRIGHT: ++ return pxa_cam_WCAM_VIDIOCSBRIGHT(cam_ctx, param); ++ ++ /*set picture contrast*/ ++ //case WCAM_VIDIOCSCONTRAST: ++ // return pxa_cam_WCAM_VIDIOCSCONTRAST(cam_ctx, param); ++ ++ /*set flicker frequency*/ ++ case WCAM_VIDIOCSFLICKER: ++ return pxa_cam_WCAM_VIDIOCSFLICKER(cam_ctx, param); ++ ++ case WCAM_VIDIOCSNIGHTMODE: ++ return pxa_cam_WCAM_VIDIOCSNIGHTMODE(cam_ctx, param); ++ ++ default: ++ { ++ mt9m111_dbg_print("Error cmd=0x%x", cmd); ++ return -1; ++ } ++ } ++ return 0; ++ ++} ++ ++#ifdef MT9M111_ECHO_CMD ++/*********************************************************************** ++ * ++ * MT9M111 test command throught terminal ++ * ++ ***********************************************************************/ ++ ++#define MIN(a, b) ((a) < (b) ? (a) : (b)) ++#define MAX_WRITE_LEN 12 ++ ++extern int mt9m111_write(u16 addr, u16 value); ++ ++static ssize_t test_command_write (struct file *file, const char *buf, size_t count, loff_t * pos) ++{ ++ char feedback[2*MAX_WRITE_LEN + 1] ={0}; ++ char feedback1[2*MAX_WRITE_LEN + 1] = {0}; ++ size_t n = count; ++ size_t l; ++ char c; ++ int i,x,y,t; ++ ++ u16 reg, value; ++ ++ MOD_INC_USE_COUNT; ++ ++ if (n > 0) ++ { ++ l = MIN (n, MAX_WRITE_LEN); ++ if (copy_from_user (feedback, buf, l)) ++ { ++ count = -1; ++ } ++ else ++ { ++ if (l > 0 && feedback[l - 1] == '\n') ++ { ++ l -= 1; ++ } ++ feedback[l] = 0; ++ n -= l; ++ ++ while (n > 0) ++ { ++ if (copy_from_user (&c, buf + (count - n), 1)) ++ { ++ count = -1; ++ break; ++ } ++ n -= 1; ++ } ++ } ++ } ++ ++ i = x = y = 1; ++ ++ if (count > 0 && feedback[0] == '{') ++ { ++ while(feedback[i] != '}' && i<=MAX_WRITE_LEN*2) ++ { ++ c= feedback[i]; ++ i++; ++ if(c>='a' && c<='f') ++ { ++ c -= 0x20; ++ } ++ if(!((c>='0'&& c<='9')||(c>='A'&&c<='F')||c==',')) ++ { ++ continue; ++ } ++ feedback1[x++] = c; ++ } ++ ++ feedback1[x]='}'; ++ feedback1[0]='{'; ++ ++ for(i=1;i<=x;i++) ++ { ++ if(feedback1[i] == ',') ++ { ++ y=3; ++ for(t=i-1;t>=1;t--) ++ { ++ if(y==0) ++ break; ++ feedback[y--]=feedback1[t]; ++ } ++ if(y>=1) ++ { ++ for(t=y;t>=1;t--) ++ { ++ feedback[t] = '0'; ++ } ++ } ++ } ++ ++ if(feedback1[i] == '}') ++ { ++ y=8; ++ for(t=i-1;feedback1[t]!=','&&t>=1;t--) ++ { ++ if(y==4) ++ break; ++ feedback[y--]=feedback1[t]; ++ } ++ if(y>=5) ++ { ++ for(t=y;t>=5;t--) ++ { ++ feedback[t] = '0'; ++ } ++ } ++ } ++ } ++ ++ reg = 16 * 16 * (feedback[1]>='A'?feedback[1]-'A'+10:feedback[1]-0x30) + 16 * (feedback[2]>='A'?feedback[2]-'A'+10:feedback[2]-0x30) + (feedback[3]>='A'?feedback[3]-'A'+10:feedback[3]-0x30) ; ++ value = 16 * 16 * 16 * (feedback[5]>='A'?feedback[5]-'A'+10:feedback[5]-0x30) + 16 *16* (feedback[6]>='A'?feedback[6]-'A'+10:feedback[6]-0x30) + 16 * (feedback[7]>='A'?feedback[7]-'A'+10:feedback[7]-0x30) + (feedback[8]>='A'?feedback[8]-'A'+10:feedback[8]-0x30) ; ++ ++ if(reg == 0xFFF && value == 0xFFFF) ++ { ++ mt9m111_dump_register(0,0x2ff,NULL); ++ } ++ else if(reg == 0xFFF || reg == 0xFF) ++ { ++ mt9m111_reg_read(value); ++ } ++ else ++ { ++ mt9m111_write(reg, value); ++ } ++ } ++ ++ MOD_DEC_USE_COUNT; ++ ++ return (count); ++} ++#endif +diff -Nurd linux-2.6.16.orig/drivers/media/video/mt9m111.h linux-2.6.16/drivers/media/video/mt9m111.h +--- linux-2.6.16.orig/drivers/media/video/mt9m111.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/mt9m111.h 2006-06-03 11:14:56.437309480 +0200 +@@ -0,0 +1,44 @@ ++ ++/*================================================================================ ++ ++ Header Name: mt9m111.h ++ ++General Description: Camera module mt9m111 interface head file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Ma Zhiqiang 6/30/2004 Change for auto-detect ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef _MT9M111_H_ ++#define _MT9M111_H_ ++ ++#include "camera.h" ++ ++////////////////////////////////////////////////////////////////////////////////////// ++// ++// Prototypes ++// ++////////////////////////////////////////////////////////////////////////////////////// ++ ++int camera_func_mt9m111_init(p_camera_context_t); ++int camera_func_mt9m111_deinit(p_camera_context_t); ++int camera_func_mt9m111_set_capture_format(p_camera_context_t); ++int camera_func_mt9m111_start_capture(p_camera_context_t, unsigned int frames); ++int camera_func_mt9m111_stop_capture(p_camera_context_t); ++int camera_func_mt9m111_pm_management(p_camera_context_t cam_ctx, int suspend); ++int camera_func_mt9m111_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param); ++ ++#endif /* _MT9M111_H_ */ ++ ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/mt9m111_hw.c linux-2.6.16/drivers/media/video/mt9m111_hw.c +--- linux-2.6.16.orig/drivers/media/video/mt9m111_hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/mt9m111_hw.c 2006-06-03 11:14:56.438309328 +0200 +@@ -0,0 +1,994 @@ ++/*================================================================================ ++ ++ Header Name: mt9m111_hw.c ++ ++General Description: Camera module mt9m111 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Ma Zhiqiang 6/30/2004 Change for auto-detect ++Ma Zhiqiang 9/03/2004 Add the update from Peter ++ (worked out with Micron/Flextronix and LV CTO team) ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++ ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/wrapper.h> ++#include <linux/delay.h> ++#include <linux/i2c.h> ++ ++#include "mt9m111_hw.h" ++#include "camera.h" ++ ++//#define MT9M111_LOG ++ ++#ifdef MT9M111_LOG ++#define mt9m111_dbg_print(fmt, args...) dbg_print(fmt, ##args) ++#else ++#define mt9m111_dbg_print(fmt, args...) ; ++#endif ++ ++extern int mt9m111_read(u16 addr, u16 *pvalue); ++extern int mt9m111_write(u16 addr, u16 value); ++ ++static u16 outWidth = 320; ++static u16 outHeight = 240; ++static u16 sensorWidth = 1280; ++static u16 sensorHeight = 1024; ++ ++static u16 preferredFlickerMask = 0; ++static int inSkipMode = 1; ++static int didSnapPhoto = 0; ++static u16 minFPS = -1; ++static u16 maxFPS = -1; ++ ++static u8 isHalfSensorSize = 0; ++ ++// light tables ++ ++#if 0 ++// table generated by Micron's default calibration ++ ++// auto ++static u16 autoLight[] = ++{ 0x00AE, 0x2923, 0x04E4, 0x00B7, 0x009F, 0x0068, 0x00C5, 0x0088, ++ 0x0027, 0x007A, 0x0088, 0x00AF, 0x00C9, 0x0014, 0x0005, 0x0033, ++ 0x0031, 0x0004, 0x0052, 0x0057, 0x0091, 0x005B, 0x6345, 0x3E26, ++ 0x0002 }; ++ ++// direct sun ++static u16 directSun[] = ++{ 0x00AE, 0x2923, 0x0524, 0x00BF, 0x009B, 0x004A, 0x00AC, 0x008A, ++ 0x0051, 0x004F, 0x007E, 0x0082, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4458, 0x0000, ++ 0x0000 }; ++ ++// incandescent ++static u16 incandescentLight[] = ++{ 0x00A6, 0x2923, 0x04E4, 0x00A8, 0x0090, 0x007A, 0x00DC, 0x0083, ++ 0x0004, 0x00A7, 0x00CC, 0x00DB, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8232, 0x0000, ++ 0x0000 }; ++ ++// fluorescent ++static u16 tl84Light[] = ++{ 0x00A6, 0x2737, 0x04E4, 0x00AF, 0x006F, 0x003C, 0x008B, 0x0097, ++ 0x000F, 0x00D2, 0x00B5, 0x00DF, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8630, 0x0000, ++ 0x0000 }; ++ ++#endif ++ ++#if 1 ++// no lens cover ccmat -- Satish likes this one ++ ++/* ++static u16 autoLight[] = ++{ 0x00AE, 0x271B, 0x02A4, 0x00E9, 0x0082, 0x006D, 0x007A, 0x009C, ++ 0x0047, 0x0095, 0x0065, 0x006C, 0x00C9, 0x0010, 0x0007, 0x0027, ++ 0x001A, 0x0001, 0x004C, 0x0062, 0x0059, 0x0037, 0x6345, 0x3E26, ++ 0x0002 }; ++*/ ++// ++static u16 autoLight[] = ++{ 0x00AE, 0x2923, 0x04E4, 0x00C8, 0x00DF, 0x0080, 0x00C2, 0x0084, ++ 0x001F, 0x006B, 0x007F, 0x00AB, 0x00C9, 0x001F, 0x0002, 0x002F, ++ 0x0022, 0x000D, 0x005E, 0x002E, 0x007B, 0x0048, 0x604C, 0x3C28, ++ 0x0002 }; ++ ++static u16 incandescentLight[] = ++{ 0x00AE, 0x2723, 0x02A4, 0x00D8, 0x00EB, 0x0076, 0x0084, 0x0096, ++ 0x001E, 0x00C5, 0x008D, 0x0085, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8232, 0x0000, ++ 0x0000 }; ++ ++static u16 tl84Light[] = ++{ 0x00AE, 0x2723, 0x02A4, 0x00EB, 0x00D6, 0x002C, 0x00A8, 0x00B0, ++ 0x000E, 0x00F8, 0x0086, 0x008B, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8630, 0x0000, ++ 0x0000 }; ++ ++static u16 d65Light[] = ++{ 0x00AE, 0x291B, 0x0524, 0x00EF, 0x0082, 0x0054, 0x00D9, 0x009D, ++ 0x006E, 0x0064, 0x00E0, 0x00A1, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4458, 0x0000, ++ 0x0000 }; ++ ++#endif ++ ++#if 0 ++ ++// lens cover ccmat -- Satish doesn't like this one ++ ++static u16 autoLight[] = ++{ 0x00AE, 0x271A, 0x02A4, 0x007E, 0x0081, 0x003A, 0x0082, 0x00BB, ++ 0x00AD, 0x009B, 0x007D, 0x0079, 0x0099, 0x000C, 0x0025, 0x0011, ++ 0x0024, 0x0009, 0x001E, 0x007F, 0x0063, 0x003F, 0x6344, 0x3A28, ++ 0x0002 }; ++ ++static u16 incandescentLight[] = ++{ 0x00AE, 0x2723, 0x02A4, 0x00EF, 0x00DE, 0x0032, 0x0094, 0x00BF, ++ 0x009E, 0x00DA, 0x00AF, 0x0098, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8030, 0x0000, ++ 0x0000 }; ++ ++static u16 tl84Light[] = ++{ 0x00AE, 0x2723, 0x02A4, 0x00E9, 0x00EC, 0x0045, 0x0093, 0x0097, ++ 0x0001, 0x00DA, 0x0092, 0x008A, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8630, 0x0000, ++ 0x0000 }; ++ ++static u16 d65Light[] = ++{ 0x00AE, 0x291A, 0x04E4, 0x0082, 0x0092, 0x0042, 0x00DD, 0x00B4, ++ 0x00B9, 0x005A, 0x0096, 0x00B0, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4658, 0x0000, ++ 0x0000 }; ++ ++#endif ++ ++ ++/***************************************************************************** ++* ++*****************************************************************************/ ++static void mt9m111_reset(void) ++{ ++ minFPS = -1; ++ maxFPS = -1; ++ inSkipMode = 1; ++ didSnapPhoto = 0; ++ isHalfSensorSize = 0; ++} ++ ++/***************************************************************************** ++* * ++* I2C Management * ++* * ++*****************************************************************************/ ++u16 mt9m111_reg_read(u16 reg_addr) ++{ ++ u16 value=0; ++ mt9m111_read(reg_addr, &value); ++ return value; ++} ++ ++void mt9m111_reg_write(u16 reg_addr, u16 reg_value) ++{ ++ mt9m111_write(reg_addr, reg_value); ++} ++ ++///////////////////////////////////////////////////////////////////////////////////// ++// ++// Programming Guide : Configuration Methods ++// ++///////////////////////////////////////////////////////////////////////////////////// ++ ++int mt9m111_get_device_id(u16 *id) ++{ ++ /*Device ID is in register 0x0 */ ++ *id = mt9m111_reg_read(0x0); ++ mt9m111_dbg_print("mt9m111 device ID is 0x%x", *id); ++ ++ return MICRON_ERR_NONE; ++} ++ ++static int mt9m111_update_size(int context) ++{ ++ mt9m111_dbg_print("mt9m111_update_size, sensor=%dx%d, out=%dx%d", sensorWidth, sensorHeight, outWidth, outHeight); ++ ++ /* set the sensor size */ ++ if(context == 0) ++ { ++ //context A ++ mt9m111_write(0x1A6, sensorWidth); ++ mt9m111_write(0x1A9, sensorHeight); ++ } ++ else ++ { ++ //context B ++ mt9m111_write(0x1A0, sensorWidth); ++ mt9m111_write(0x1A3, sensorHeight); ++ } ++ /* set output size */ ++ if(outWidth > sensorWidth) ++ { ++ outWidth = sensorWidth; ++ } ++ if(outHeight > sensorHeight) ++ { ++ outHeight = sensorHeight; ++ } ++ ++ if(context == 0) ++ { ++ //context A ++ mt9m111_write(0x1A7, outWidth); ++ mt9m111_write(0x1AA, outHeight); ++ } ++ else ++ { ++ //context B ++ mt9m111_write(0x1A1, outWidth); ++ mt9m111_write(0x1A4, outHeight); ++ } ++ ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_viewfinder_on() ++{ ++ mt9m111_dbg_print("mt9m111_viewfinder_on, sensor=%dx%d, out=%dx%d", sensorWidth, sensorHeight, outWidth, outHeight); ++ ++ if((outWidth*2 > sensorWidth) || (outHeight*2 > sensorHeight)) ++ { ++ mt9m111_dbg_print("mt9m111_viewfinder_on: making sure skip mode is off"); ++ ++ // make sure skip mode is off ++ ++ if (inSkipMode || didSnapPhoto) ++ { ++ mt9m111_dbg_print("mt9m111_viewfinder_on: skip mode is on -- turning in off"); ++ // ++ // set to full power, turn off subsampling ++ // switch to context B for read mode, full frame, and max line delay ++ // ++ ++ mt9m111_write(0x2D2, 0x0041); // turn off subsampling and turn on full power mode ++ mt9m111_write(0x2CC, 0x4); // Context Ctl Program Select -- use default program ++ u16 v = mt9m111_reg_read(0x2CB); // read Context Ctl Program Advance ++ mt9m111_write(0x2CB, v|1); // advance program ++ ++ didSnapPhoto = 0; ++ inSkipMode = 0; ++ ++ // ++ // after program advance, we need to poll Global Context Ctl to wait for ++ // sensor read mode context has switched to context B ++ // ++ ++ int count = 0; ++ while ((mt9m111_reg_read(0x00C8) != 0x000B) && (++count < 20)) ++ { ++ mdelay(10); ++ } ++ } ++ ++ mt9m111_update_size(0); ++ } ++ else ++ { ++ mt9m111_update_size(0); ++ ++ // make sure skip mode is on ++ ++ mt9m111_dbg_print("mt9m111_viewfinder_on: making sure skip mode is on"); ++ ++ if (!inSkipMode || didSnapPhoto) ++ { ++ mt9m111_dbg_print("mt9m111_viewfinder_on: skip mode is off -- turning in on"); ++ ++ // ++ // set to low power, turn on subsampling ++ // switch to context A for read mode, full frame, and max line delay ++ ++ mt9m111_write(0x2D2, 0x0000); // turn off subsampling and turn on full power mode ++ mt9m111_write(0x2CC, 0x4); // Context Ctl Program Select -- use default program ++ u16 v = mt9m111_reg_read(0x2CB); // read Context Ctl Program Advance ++ mt9m111_write(0x2CB, v|1); // advance program ++ ++ inSkipMode = 1; ++ didSnapPhoto = 0; ++ } ++ } ++ ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_viewfinder_off() ++{ ++ mt9m111_dbg_print("mt9m111_viewfinder_off"); ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_snapshot_trigger() ++{ ++ mt9m111_dbg_print("mt9m111_snapshot_trigger"); ++ ++ mt9m111_update_size(1); ++ ++ mt9m111_write(0x2D2, 0x007F); // Context return to default => all in context B ++ mt9m111_write(0x2CC, 0x0004); // Program Select = default => run program to default ++ u16 v = mt9m111_reg_read(0x2CB); ++ mt9m111_write(0x2CB, v | 1); // Program Advance = RUN/GO ++ ++ didSnapPhoto = 1; ++ ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_snapshot_complete() ++{ ++ mt9m111_dbg_print("mt9m111_snapshot_complete"); ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_input_size(micron_window_size * window) ++{ ++ sensorWidth = window->width; ++ sensorHeight = window->height; ++ ++ mt9m111_dbg_print("mt9m111_input_size, sensor=%dx%d", sensorWidth, sensorHeight); ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_output_size(micron_window_size * window) ++{ ++ outWidth = window->width; ++ outHeight = window->height; ++ ++ mt9m111_dbg_print("mt9m111_output_size, out=%dx%d", outWidth, outHeight); ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_get_input_size( micron_window_size * window) ++{ ++ window->width = mt9m111_reg_read(0x1A6); ++ window->height = mt9m111_reg_read(0x1A9); ++ ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_set_fps(u16 newMaxFPS, u16 newMinFPS) ++{ ++ mt9m111_dbg_print("mt9m111_set_fps: newMaxFPS=%d, newMinFPS=%d", newMaxFPS, newMinFPS); ++ ++ // ++ // clamp newMaxFPS to a legal range ++ // ++ ++ const int MIN_FPS = 5; ++ const int MAX_FPS = 15; ++ ++ newMaxFPS = (newMaxFPS > MAX_FPS) ? MAX_FPS : newMaxFPS; ++ newMaxFPS = (newMaxFPS < MIN_FPS) ? MIN_FPS : newMaxFPS; ++ ++ mt9m111_dbg_print("mt9m111_set_fps: newMaxFPS=%d, newMinFPS=%d", newMaxFPS, newMinFPS); ++ ++ // ++ // if the maxFPS has changed, update the vblank ++ // ++ ++ if (newMaxFPS != maxFPS) ++ { ++ ++ // ++ // enforce max fps by setting the vertical blanking ++ // ++ // The table below assumes: ++ // MCLK = 24.375 MHz ++ // target line time = 127 micro seconds ++ // HBLANK in low power = ??? ++ // HBLANK in full power = ??? ++ // ++ // The following values came from Micron during a site visit on 9/1. ++ // ++ // If the input clock changes, these settings also need to change. ++ // ++ // The basic idea is that a flicker-detection friendly framerate close ++ // to the requested frame rate is chosen. ++ // ++ ++ const u16 vblanksLowPower[] = ++ { ++ 1021, /* 5.11 */ ++ 701, /* 6.45 */ ++ 556, /* 7.32 */ ++ 412, /* 8.45 */ ++ 309, /* 9.5 */ ++ 233, /* 10.45 */ ++ 162, /* 11.55 */ ++ 123, /* 12.25 */ ++ 90, /* 12.91 */ ++ 50, /* 13.81 */ ++ 18 /* 14.645 */ ++ }; ++ ++ const u16 vblanksFullPower[] = ++ { ++ 509, /* 5.11 */ ++ 189, /* 6.45 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44, /* 7.32 */ ++ 44 /* 7.32 */ ++ }; ++ ++ // ++ // use the following hblanks to achieve a line rate of 127us ++ // ++ ++ const u16 readModeLowPower = 0x040C; ++ const u16 readModeFullPower = 0x0300; ++ const u16 hblankLowPower = 126; ++ const u16 hblankFullPower = 260; ++ const u16 aeLineSizeLowPower = 1548; ++ const u16 aeLineSizeFullPower = 1548; ++ const u16 aeShutterDelayLimitLowPower = 1548; ++ const u16 aeShutterDelayLimitFullPower = 1548; ++ const u16 aeFlickerFullFrameTime60HzLowPower = 262; ++ const u16 aeFlickerFullFrameTime60HzFullPower = 262; ++ const u16 aeFlickerFullFrameTime50HzLowPower = 314; ++ const u16 aeFlickerFullFrameTime50HzFullPower = 314; ++ const u16 flickerSearchRange50HZ = 0x1712; ++ const u16 flickerSearchRange60HZ = 0x120D; ++ // const u16 flickerParameter = 0x1E1C; // 7/8 trials ++ const u16 flickerParameter = 0x0D1C; // 3/4 trials ++ ++ mt9m111_write(0x005, hblankFullPower); ++ mt9m111_write(0x006, vblanksFullPower[newMaxFPS-5]); ++ mt9m111_write(0x007, hblankLowPower); ++ mt9m111_write(0x008, vblanksLowPower[newMaxFPS-5]); ++ mt9m111_write(0x020, readModeFullPower); ++ mt9m111_write(0x021, readModeLowPower); ++ mt9m111_write(0x239, aeLineSizeLowPower); ++ mt9m111_write(0x23A, aeLineSizeFullPower); ++ mt9m111_write(0x23B, aeShutterDelayLimitLowPower); ++ mt9m111_write(0x23C, aeShutterDelayLimitFullPower); ++ mt9m111_write(0x257, aeFlickerFullFrameTime60HzLowPower); ++ mt9m111_write(0x258, aeFlickerFullFrameTime50HzLowPower); ++ mt9m111_write(0x259, aeFlickerFullFrameTime60HzFullPower); ++ mt9m111_write(0x25A, aeFlickerFullFrameTime50HzFullPower); ++ mt9m111_write(0x25C, flickerSearchRange60HZ); ++ mt9m111_write(0x25D, flickerSearchRange50HZ); ++ mt9m111_write(0x264, flickerParameter); ++ ++ maxFPS = newMaxFPS; ++ } ++ ++ return MICRON_ERR_NONE; ++ ++} ++ ++int mt9m111_set_autoexposure_zone(u16 newMinFPS) ++{ ++ const int MIN_FPS = 5; ++ const int MAX_FPS = 15; ++ ++ // ++ // This driver only implements two minimum framerates: 5fps and 15fps. ++ // ++ // The mt9m111 can support every min fps between 5fps and 15fps, but the AE settings ++ // will become very complex. ++ // ++ ++ if (newMinFPS > 5) ++ { ++ newMinFPS = MAX_FPS; ++ } ++ else ++ { ++ newMinFPS = MIN_FPS; ++ } ++ ++ // ++ // if the minFPS has changed, update the AE limit ++ // ++ ++ if (newMinFPS != minFPS) ++ { ++ // ++ // enforce min fps by setting max exposure time ++ // ++ ++ if (newMinFPS == 5) ++ { ++ // set min fps to 5 fps -> AE Zone 24 ++ u16 limitAE = ((120/5) << 5) & 0x03E0; ++ mt9m111_write(0x237, limitAE); ++ ++ // ++ // work-around for AE strangeness ++ // symptom: start in dark, preview gets darker, darker, very dark, black, then is OK. ++ // ++ ++ if (mt9m111_reg_read(0x23F) == 8) ++ { ++ u16 v; ++ v = mt9m111_reg_read(0x22E); // read target luma register ++ ++ // by setting target luma to 0, trick AE into zone <= 8 ++ mt9m111_write(0x22E, 0x0000); // set target luma to 0 ++ ++ // ++ // wait until AE zone is in bounds (or time exceeds 1500ms) ++ // ++ // 1500ms is a long time! ++ // ++ ++ int count=0; ++ while ((mt9m111_reg_read(0x23F) == 8) && (++count < 30)) ++ { ++ mdelay(50); ++ } ++ ++ mt9m111_write(0x22E, v); // rewrite target luma register ++ } ++ } ++ else ++ { ++ // set min fps to 15 fps -> AE Zone 8 ++ u16 limitAE = ((120/15) << 5) & 0x03E0; ++ mt9m111_write(0x237, limitAE); ++ mt9m111_dbg_print("AE zone limit is %0x\n", limitAE); ++ ++ // ++ // work-around for AE strangeness ++ // symptom: start in dark, preview gets darker, darker, very dark, black, then is OK. ++ // ++ ++ if (mt9m111_reg_read(0x23F) > 8) ++ { ++ u16 v; ++ v = mt9m111_reg_read(0x22E); // read target luma register ++ ++ // by setting target luma to 0, trick AE into zone <= 8 ++ mt9m111_write(0x22E, 0x0000); // set target luma to 0 ++ ++ // ++ // wait until AE zone is in bounds (or time exceeds 1500ms) ++ // ++ // 1500ms is a long time! ++ // ++ ++ int count=0; ++ while ((mt9m111_reg_read(0x23F) > 8) && (++count < 30)) ++ { ++ mdelay(50); ++ } ++ ++ mt9m111_write(0x22E, v); // rewrite target luma register ++ } ++ } ++ ++ minFPS = newMinFPS; ++ } ++ ++ return MICRON_ERR_NONE; ++ ++} ++ ++int mt9m111_output_format(u16 format) ++{ ++ u16 value; ++ ++ if(format == O_FORMAT_422_YCbYCr) ++ { ++ mt9m111_write(0x13A, 0); ++ } ++ else ++ { ++ value = (1<<8)|((format-1)<<6); ++ mt9m111_write(0x13A, value); ++ } ++ return MICRON_ERR_NONE; ++} ++ ++void mt9m111_dump_register(u16 startRegAddr, u16 endRegAddr, u16* buffer) ++{ ++ u16 addr,value; ++ ++ for(addr = startRegAddr; addr <= endRegAddr; addr++) ++ { ++ unsigned long flags; ++ local_irq_save(flags); ++ ++ mt9m111_read(addr, &value); ++ ++ local_irq_restore(flags); ++ ++ mt9m111_dbg_print("mt9m111 register: 0x%04x = %04x",addr,value); ++ ++ if(buffer) ++ { ++ *buffer = value; ++ buffer++; ++ } ++ } ++} ++ ++// ++// TODO: make this an IOCTL that is called by the application some time after set_flicker() is ++// called ++// ++ ++int mt9m111_set_flicker_2(void) ++{ ++ mt9m111_dbg_print("mt9m111_set_flicker_2: %04x", preferredFlickerMask); ++ ++ int count=0; ++ ++ // ++ // read flicker_control_1 until it verifies that flicker is set to the preferred rate. ++ // ++ ++ while(((mt9m111_reg_read(0x25B) & 0x8000) != preferredFlickerMask) && (++count < 50)) ++ { ++ mdelay(20); ++ } ++ ++ mt9m111_write(0x25B, 0x0002); // back to auto mode ++ ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_set_flicker(int flicker) ++{ ++ mt9m111_dbg_print("mt9m111_set_flicker: %d", flicker); ++ ++ preferredFlickerMask = (flicker == 50) ? 0x0000 : 0x8000; ++ ++ if (flicker == 50) ++ { ++ mt9m111_write(0x25B, 0x0001); // manual mode 50Hz ++ } ++ else if (flicker == 60) ++ { ++ mt9m111_write(0x25B, 0x0003); // manual mode 60Hz ++ } ++ else ++ { ++ return MICRON_ERR_PARAMETER; ++ } ++ ++ mt9m111_set_flicker_2(); ++ ++ return MICRON_ERR_NONE; ++} ++ ++int mt9m111_set_contrast(int contrast) ++{ ++ mt9m111_dbg_print("mt9m111_set_contrast: %d (skipped)", contrast); ++ return MICRON_ERR_NONE; ++ ++#if 0 ++ // ++ // we don't support setting the contrast in the initial release of A780 ++ // ++ ++ const u16 gammaTable[] = ++ { ++ //0x3B2C,0x664D,0x9F87,0xC3B3,0xE0D2, //0.40 ++ //0x3224,0x664D,0x9F87,0xC3B3,0xE0D2, //0.45 ++ 0x2A1D,0x543B,0x9277,0xBDA9,0xE0CF, //0.50 ++ 0x2318,0x4C34,0x8C70,0xBAA4,0xE0CD, //0.55 ++ 0x1E14,0x462E,0x876A,0xB7A0,0xE0CC, //0.60 ++ 0x1910,0x3F28,0x8163,0xB39B,0xE0CA, //0.65 ++ 0x150D,0x3923,0x7B5D,0xB097,0xE0C9, //0.70 ++ 0x120A,0x341E,0x7657,0xAE93,0xE0C7, //0.75 ++ 0x0F08,0x2F1B,0x7152,0xAB8F,0xE0C6, //0.80 ++ 0x0D07,0x2A17,0x6D4D,0xA88B,0xE0C4, //0.85 ++ 0x0B05,0x2614,0x6848,0xA587,0xE0C2, //0.90 ++ //0x0804,0x2010,0x6040,0xA080,0xE0C0, //1.00 ++ //0x0502,0x1A0C,0x5838,0x9A79,0xE0BD, //1.10 ++ //0x0401,0x1509,0x5131,0x9572,0xE0BA, //1.20 ++ }; ++ ++ if(contrast < -4 || contrast > 4) ++ { ++ return MICRON_ERR_PARAMETER; ++ } ++ ++ u16 i, regA=0x153, regB=0x1DC; ++ ++ for(i=0; i<5; i++) ++ { ++ mt9m111_write(regA++, gammaTable[(contrast+4)*5+i]); ++ mt9m111_write(regB++, gammaTable[(contrast+4)*5+i]); ++ } ++ ++ return MICRON_ERR_NONE; ++#endif ++ ++} ++ ++/*set picture style(normal/black white/sepia/solarize/neg.art)*/ ++int mt9m111_set_style(V4l_PIC_STYLE style) ++{ ++ mt9m111_dbg_print("mt9m111_set_style: %d", style); ++ ++ switch(style) ++ { ++ case V4l_STYLE_BLACK_WHITE: ++ mt9m111_write(0x1E2,0x7001); ++ break; ++ case V4l_STYLE_SEPIA: ++ mt9m111_write(0x1E2,0x7002); ++ mt9m111_write(0x1E3,0xB023); ++ break; ++ case V4l_STYLE_SOLARIZE: ++ mt9m111_write(0x1E2,0x7004); ++ break; ++ case V4l_STYLE_NEG_ART: ++ mt9m111_write(0x1E2,0x7003); ++ break; ++ default: ++ mt9m111_write(0x1E2,0x7000); ++ break; ++ } ++ ++ return MICRON_ERR_NONE; ++} ++ ++ ++/*set picture light(auto/direct sun/incandescent/fluorescent)*/ ++int mt9m111_set_light(V4l_PIC_WB light) ++{ ++ u16 *m; ++ u16 v; ++ ++ switch(light) ++ { ++ case V4l_WB_DIRECT_SUN: ++ ++ mt9m111_dbg_print("mt9m111_set_light: %d (direct sun)", light); ++ m = d65Light; ++ break; ++ ++ case V4l_WB_INCANDESCENT: ++ ++ mt9m111_dbg_print("mt9m111_set_light: %d (incandescent)", light); ++ m = incandescentLight; ++ break; ++ ++ case V4l_WB_FLUORESCENT: ++ ++ mt9m111_dbg_print("mt9m111_set_light: %d (fluorescent)", light); ++ m = tl84Light; ++ break; ++ ++ default: ++ ++ mt9m111_dbg_print("mt9m111_set_light: %d (default)", light); ++ m = autoLight; ++ break; ++ ++ } ++ ++ mt9m111_write(0x202, m[0]); //BASE_MATRIX_SIGNS ++ mt9m111_write(0x203, m[1]); //BASE_MATRIX_SCALE_K1_K5 ++ mt9m111_write(0x204, m[2]); //BASE_MATRIX_SCALE_K6_K9 ++ ++ mt9m111_write(0x209, m[3]); //BASE_MATRIX_COEF_K1 ++ mt9m111_write(0x20A, m[4]); //BASE_MATRIX_COEF_K2 ++ mt9m111_write(0x20B, m[5]); //BASE_MATRIX_COEF_K3 ++ mt9m111_write(0x20C, m[6]); //BASE_MATRIX_COEF_K4 ++ mt9m111_write(0x20D, m[7]); //BASE_MATRIX_COEF_K5 ++ mt9m111_write(0x20E, m[8]); //BASE_MATRIX_COEF_K6 ++ mt9m111_write(0x20F, m[9]); //BASE_MATRIX_COEF_K7 ++ mt9m111_write(0x210, m[10]); //BASE_MATRIX_COEF_K8 ++ mt9m111_write(0x211, m[11]); //BASE_MATRIX_COEF_K9 ++ mt9m111_write(0x215, m[12]); //DELTA_COEF_SIGNS ++ mt9m111_write(0x216, m[13]); //DELTA_MATRIX_COEF_D1 ++ mt9m111_write(0x217, m[14]); //DELTA_MATRIX_COEF_D2 ++ mt9m111_write(0x218, m[15]); //DELTA_MATRIX_COEF_D3 ++ mt9m111_write(0x219, m[16]); //DELTA_MATRIX_COEF_D4 ++ mt9m111_write(0x21A, m[17]); //DELTA_MATRIX_COEF_D5 ++ mt9m111_write(0x21B, m[18]); //DELTA_MATRIX_COEF_D6 ++ mt9m111_write(0x21C, m[19]); //DELTA_MATRIX_COEF_D7 ++ mt9m111_write(0x21D, m[20]); //DELTA_MATRIX_COEF_D8 ++ mt9m111_write(0x21E, m[21]); //DELTA_MATRIX_COEF_D9 ++ ++ mt9m111_write(0x25E, m[22]); //RATIO_BASE_REG ++ mt9m111_write(0x25F, m[23]); //RATIO_DELTA_REG ++ mt9m111_write(0x260, m[24]); //SIGNS_DELTA_REG ++ ++ //Toggle Manual White Balance to force loading the new table ++ v = mt9m111_reg_read(0x106); ++ mt9m111_write(0x106, v|0x8000); // Operating Mode Control -- P.13 708E ++ mdelay(200); // TODO: correct amount of time? ++ mt9m111_write(0x106, v&~0x8000); ++ ++ return MICRON_ERR_NONE; ++} ++ ++ ++/*set picture brightness*/ ++int mt9m111_set_bright(int bright) ++{ ++ mt9m111_dbg_print("mt9m111_set_bright (gamma) %d", bright); ++ ++ const u16 target[] = ++ { ++ 37, // -2.0 EV ++ 44, // -1.5 EV ++ 52, // -1.0 EV ++ 62, // -0.5 EV ++ 74, // 0.0 EV ++ 88, // +0.5 EV ++ 105, // +1.0 EV ++ 124, // +1.5 EV ++ 148 // +2.0 EV ++ }; ++ ++ if(bright < -4 || bright > 4) ++ { ++ return MICRON_ERR_PARAMETER; ++ } ++ ++ /*set luma value of AE target*/ ++ mt9m111_write(0x22E, 0x0C00 + target[bright+4]); ++ return MICRON_ERR_NONE; ++} ++ ++ ++int mt9m111_default_settings() ++{ ++ mt9m111_dbg_print("mt9m111_default_settings"); ++ ++ mt9m111_reset(); ++ ++ // Soft Reset -- Reset both sensor AND SOC (and leave sensor digital logic enabled) ++ ++ mt9m111_write(0x00D, 0x29); // Reset sensor and SOC -- P.54 ++ // i2c will delay enough here for reset to finish (1us is enough) ++ mt9m111_write(0x00D, 0x08); // Release reset -- P.54 ++ ++ mt9m111_write(0x285, 0x0061); // AE Gain table ++ mt9m111_write(0x286, 0x0080); // AE Gain table ++ mt9m111_write(0x287, 0x0061); // AE Gain table ++ mt9m111_write(0x288, 0x0061); // AE Gain table ++ mt9m111_write(0x289, 0x03E2); // AE Gain table ++ mt9m111_write(0x238, 0x0840); // Shutter priority transition zone ++ ++ //Enable flicker detection ++ mt9m111_write(0x106, 0x708E); // Operating Mode Control -- P.13 0x0708C ++ ++ // Enable 2D defect correction in both contexts ++ mt9m111_write(0x14C, 0x0001); // Defect Buffer Context A -- P.13 0x0000 -- Enable 2D defect correct context A ++ mt9m111_write(0x14D, 0x0001); // Defect Buffer Context B -- P.13 0x0000 -- Enable 2D defect correct context B ++ ++ // Set centered origin ++ mt9m111_write(0x1a8, 0x4000); // Reducer YPan A -- P.14 0x0000 -- Cntxt A Y Crop centering ++ mt9m111_write(0x1a5, 0x4000); // Reducer XPan A -- P.14 0x0000 -- Cntxt A X Crop centering ++ mt9m111_write(0x1a2, 0x4000); // Reducer YPan B -- P.14 0x0000 -- Cntxt B Y Crop centering ++ mt9m111_write(0x19F, 0x4000); // Reducer XPan B -- P.14 0x0000 -- Cntxt B X Crop centering ++ ++ // Sensor is running in semi auto mode only ++ mt9m111_write(0x2CC, 0x0004); // Context Ctl Pgm Select -- P.19 0x0000 ++ ++ //mt9m111_write(0x034, 0xC039); // Reserved -- P.54 0xC019 in es3 -- turn on eclipse ++ ++ // Do not invert the pixel clock ++ mt9m111_write(0x13A, 0x0000); // Output Format Control 2A -- P.13 0x0000 ++ mt9m111_write(0x19B, 0x0000); // Output Format Control 2B -- P.14 0x0000 ++ ++ //Auto sharpening ++ mt9m111_write(0x105, 0x000B); // Aperature Correction (sharpening) gain -- 0x0003 ++ // 75% sharpening, auto-sharpening on ++ ++ //Enable classic interpolation at full res ++ mt9m111_write(0x1AF, 0x0018); // Reducer Zoom Control -- P.14 0x0010 ++ ++ //AWB settings for 12mm lens, no ulens shift ++ mt9m111_write(0x222, 0xb070); // Red Gain AWB Limits -- P.16 0x0D960 -- overconstrained currently? (sunburned->0x8870) ++ mt9m111_write(0x223, 0xb070); // Blue Gain AWB Limits -- P.16 0x0D960 -- overconstrained currently? ++ mt9m111_write(0x229, 0x847C); // Reserved -- P.16 0x8D73 -- Thresholds (tied into digital gains above) ++ ++ //mt9m111_set_light(V4l_WB_AUTO); //the app will call ioctl to set light ++ ++ // lens correction for Micron es3 + flex module 9/31 ++ ++ mt9m111_write(0x180, 0x0003); // LENS_ADJ_PARAM_0_5 ++ mt9m111_write(0x181, 0xC813); // LENS_ADJ_VERT_RED_0 ++ mt9m111_write(0x182, 0xEEE2); // LENS_ADJ_VERT_RED_1_2 ++ mt9m111_write(0x183, 0xFDF9); // LENS_ADJ_VERT_RED_3_4 ++ mt9m111_write(0x184, 0xE10C); // LENS_ADJ_VERT_GREEN_0 ++ mt9m111_write(0x185, 0xF0E9); // LENS_ADJ_VERT_GREEN_1_2 ++ mt9m111_write(0x186, 0xFFF8); // LENS_ADJ_VERT_GREEN_3_4 ++ mt9m111_write(0x187, 0xE60A); // LENS_ADJ_VERT_BLUE_0 ++ mt9m111_write(0x188, 0xF2EB); // LENS_ADJ_VERT_BLUE_1_2 ++ mt9m111_write(0x189, 0x01F9); // LENS_ADJ_VERT_BLUE_3_4 ++ mt9m111_write(0x18A, 0xAE25); // LENS_ADJ_HORIZ_RED_0 ++ mt9m111_write(0x18B, 0xDACE); // LENS_ADJ_HORIZ_RED_1_2 ++ mt9m111_write(0x18C, 0xF5EF); // LENS_ADJ_HORIZ_RED_3_4 ++ mt9m111_write(0x18D, 0x00FD); // LENS_ADJ_HORIZ_RED_5 ++ mt9m111_write(0x18E, 0xDE18); // LENS_ADJ_HORIZ_GREEN_0 ++ mt9m111_write(0x18F, 0xE5E2); // LENS_ADJ_HORIZ_GREEN_1_2 ++ mt9m111_write(0x190, 0xF7F2); // LENS_ADJ_HORIZ_GREEN_3_4 ++ mt9m111_write(0x191, 0x00FE); // LENS_ADJ_HORIZ_GREEN_5 ++ mt9m111_write(0x192, 0xCF17); // LENS_ADJ_HORIZ_BLUE_0 ++ mt9m111_write(0x193, 0xEAE4); // LENS_ADJ_HORIZ_BLUE_1_2 ++ mt9m111_write(0x194, 0xF8F4); // LENS_ADJ_HORIZ_BLUE_3_4 ++ mt9m111_write(0x195, 0x00FF); // LENS_ADJ_HORIZ_BLUE_5 ++ mt9m111_write(0x1B6, 0x1104); // LENS_ADJ_VERT_RED_5_6 ++ mt9m111_write(0x1B7, 0x3420); // LENS_ADJ_VERT_RED_7_8 ++ mt9m111_write(0x1B8, 0x0503); // LENS_ADJ_VERT_GREEN_5_6 ++ mt9m111_write(0x1B9, 0x1C0F); // LENS_ADJ_VERT_GREEN_7_8 ++ mt9m111_write(0x1BA, 0x0502); // LENS_ADJ_VERT_BLUE_5_6 ++ mt9m111_write(0x1BB, 0x1B0C); // LENS_ADJ_VERT_BLUE_7_8 ++ mt9m111_write(0x1BC, 0x0F03); // LENS_ADJ_HORIZ_RED_6_7 ++ mt9m111_write(0x1BD, 0x2E1C); // LENS_ADJ_HORIZ_RED_8_9 ++ mt9m111_write(0x1BE, 0x0050); // LENS_ADJ_HORIZ_RED_10 ++ mt9m111_write(0x1BF, 0x0A02); // LENS_ADJ_HORIZ_GREEN_6_7 ++ mt9m111_write(0x1C0, 0x1C13); // LENS_ADJ_HORIZ_GREEN_8_9 ++ mt9m111_write(0x1C1, 0x0023); // LENS_ADJ_HORIZ_GREEN_10 ++ mt9m111_write(0x1C2, 0x0801); // LENS_ADJ_HORIZ_BLUE_6_7 ++ mt9m111_write(0x1C3, 0x1B0F); // LENS_ADJ_HORIZ_BLUE_8_9 ++ mt9m111_write(0x1C4, 0x0027); // LENS_ADJ_HORIZ_BLUE_10 ++ ++ //turn on lens correction ++ mt9m111_write(0x106, 0x748E); // Operating Mode Control -- P.13 0x708E ++ ++ // set luma offset and clip for both contexts ++ mt9m111_write(0x134, 0x0000); // Luma offset (Brightness Offset) ++ mt9m111_write(0x135, 0xFF01); // Luma clip (Brightness Offset) ++ // TODO: why FF01, why not FF00? ++ ++ // load hard-coded 0.6 gamma table (Context A) ++ mt9m111_write(0x153, 0x2217); ++ mt9m111_write(0x154, 0x4F34); ++ mt9m111_write(0x155, 0x9978); ++ mt9m111_write(0x156, 0xD0B6); ++ mt9m111_write(0x157, 0xFEE8); ++ mt9m111_write(0x158, 0x0000); ++ ++ // load hard-coded 0.6 gamma table (Context B) ++ mt9m111_write(0x1DC, 0x2217); ++ mt9m111_write(0x1DD, 0x4F34); ++ mt9m111_write(0x1DE, 0x9978); ++ mt9m111_write(0x1DF, 0xD0B6); ++ mt9m111_write(0x1E0, 0xFEE8); ++ mt9m111_write(0x1E1, 0x0000); ++ ++ // add new setting from Kenta's email, Nov.2, 2004 ++ mt9m111_write(0x21F, 0x0090); ++ //mt9m111_write(0x222, 0xb070); // aleady write above ++ //mt9m111_write(0x223, 0xb070); // aleady write above ++ mt9m111_write(0x228, 0xef14); ++ ++ return MICRON_ERR_NONE; ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/mt9m111_hw.h linux-2.6.16/drivers/media/video/mt9m111_hw.h +--- linux-2.6.16.orig/drivers/media/video/mt9m111_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/mt9m111_hw.h 2006-06-03 11:14:56.439309176 +0200 +@@ -0,0 +1,89 @@ ++/*================================================================================ ++ ++ Header Name: mt9m111_hw.h ++ ++General Description: Camera module mt9m111 interface header file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Ma Zhiqiang 6/30/2004 Change for auto-detect ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++ ++#ifndef _PXA_MT9M111_HW_H__ ++#define _PXA_MT9M111_HW_H__ ++ ++#include "camera.h" ++/*********************************************************************** ++ * ++ * Constants & Structures ++ * ++ ***********************************************************************/ ++ ++/* MICRON_WINDOWSIZE */ ++typedef struct { ++ u16 width; ++ u16 height; ++} micron_window_size; ++ ++ ++// Return codes ++#define MICRON_ERR_NONE 0 ++#define MICRON_ERR_TIMEOUT -1 ++#define MICRON_ERR_PARAMETER -2 ++ ++ ++// Output Format ++#define O_FORMAT_422_YCbYCr 0 ++#define O_FORMAT_565_RGB 1 ++#define O_FORMAT_555_RGB 2 ++#define O_FORMAT_444_RGB 3 ++ ++ ++/*********************************************************************** ++ * ++ * Function Prototype ++ * ++ ***********************************************************************/ ++ ++u16 mt9m111_reg_read(u16 reg_addr); ++void mt9m111_reg_write(u16 reg_addr, u16 reg_value); ++ ++ ++// Configuration Procedures ++int mt9m111_get_device_id(u16 *id); ++ ++int mt9m111_viewfinder_on( void ); ++int mt9m111_viewfinder_off( void ); ++int mt9m111_snapshot_trigger( void ); ++int mt9m111_snapshot_complete( void ); ++ ++int mt9m111_set_fps(u16 fps, u16 minfps); ++int mt9m111_set_autoexposure_zone(u16 minfps); ++ ++int mt9m111_input_size(micron_window_size * win); ++int mt9m111_output_size(micron_window_size * win); ++int mt9m111_get_input_size(micron_window_size * win); ++int mt9m111_output_format(u16 format); ++ ++int mt9m111_set_contrast(int contrast); ++int mt9m111_set_style(V4l_PIC_STYLE style); ++int mt9m111_set_light(V4l_PIC_WB light); ++int mt9m111_set_bright(int bright); ++int mt9m111_set_flicker(int bright); ++ ++int mt9m111_default_settings( void ); ++ ++void mt9m111_dump_register(u16 startRegAddr, u16 endRegAddr, u16* buffer); ++ ++#endif /* _PXA_MT9M111_HW_H__ */ ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/mt9v111.c linux-2.6.16/drivers/media/video/mt9v111.c +--- linux-2.6.16.orig/drivers/media/video/mt9v111.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/mt9v111.c 2006-06-03 11:14:56.440309024 +0200 +@@ -0,0 +1,910 @@ ++ ++/*================================================================================ ++ ++ Header Name: mt9v111.c ++ ++General Description: Camera module mt9v111 interface source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++wangfei(w20239) 04/14/2003 Created ++ ++================================================================================== ++ INCLUDE FILES ++==================================================================================*/ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++ ++#include <asm/pgtable.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++ ++#include <asm/arch/pxa-regs.h> ++ ++#include "adcm2700.h" ++#include "adcm2700_hw.h" ++ ++#define ADDRSPACE_CORE 0x04 /* code to select core registers 0-170*/ ++#define ADDRSPACE_IFP 0x01 /* code to select IFP/SOC registers 0-255*/ ++#define MT9V111_SENSOR_WIDTH 640 ++#define MT9V111_SENSOR_HEIGHT 480 ++ ++extern int mt9v111_write(u8 addrSpace, u16 addr, u16 value); ++extern int mt9v111_read(u8 addrSpace, u16 addr); ++extern int i2c_mt9v111_cleanup(void); ++extern int camera_ring_buf_init(p_camera_context_t); ++extern void adcm2700_wait(u32); ++extern void start_dma_transfer(p_camera_context_t,unsigned); ++extern void stop_dma_transfer(p_camera_context_t); ++extern int camera_func_mt9v111_stop_capture(p_camera_context_t camera_context); ++ ++static int mt9v111_restore_property(p_camera_context_t); ++ ++static inline int mt9v111_read_core_reg(u16 addr) ++{ ++ return mt9v111_read(ADDRSPACE_CORE, addr); ++} ++ ++static inline int mt9v111_read_ifp_reg(u16 addr) ++{ ++ return mt9v111_read(ADDRSPACE_IFP, addr); ++} ++static inline int mt9v111_write_core_reg(u16 addr, u16 value) ++{ ++ return mt9v111_write(ADDRSPACE_CORE, addr, value); ++} ++static inline int mt9v111_write_ifp_reg(u16 addr, u16 value) ++{ ++ return mt9v111_write(ADDRSPACE_IFP, addr, value); ++} ++static int mt9v111_input_size(adcm_window_size * size) ++{ ++ u16 pan_ver,pan_hor; ++ pan_hor=(MT9V111_SENSOR_WIDTH - size->width)>>1; ++ pan_ver=(MT9V111_SENSOR_HEIGHT- size->height)>>1; ++ ++ mt9v111_write_ifp_reg(0xa5,0x8000|pan_hor); ++ mt9v111_write_ifp_reg(0xa8,0x8000|pan_ver); ++ mt9v111_write_ifp_reg(0xa6,0x8000|size->width); ++ mt9v111_write_ifp_reg(0xa9,size->height); ++ dbg_print("set sensor width : %d height : %d\n",size->width , size->height); ++ //dbg_print("horizontal pan :%d vertical pan %d \n",pan_hor,pan_ver); ++ return 0; ++} ++static int mt9v111_set_fps(int fps, int minfps) ++{ ++ //write to r55 (0x37) [9..5] to change minimum fps ++ u16 blank_v,r55,zone_low,zone_high; ++ dbg_print("set fps : %d min fps : %d\n",fps,minfps); ++ ++ //Set vertical blank to adjust frame rate ++ blank_v = (15-fps)*496/fps + 4; ++ mt9v111_write_core_reg(0x06,blank_v); ++ ++ //shut width ++ zone_low=0; ++ zone_high=fps*8/minfps; ++ r55 = zone_low|(zone_high<<5); ++ mt9v111_write_ifp_reg(0x37, r55); ++ ++ return 0; ++} ++static int mt9v111_set_bright(int bright) ++{ ++ const u16 target[]= ++ { ++ 25, ++ 35, ++ 50, ++ 75, ++ 100, ++ 120, ++ 140, ++ 160, ++ 180 ++ }; ++ if(bright > 4|| bright < -4) ++ { ++ return -EFAULT; ++ } ++ mt9v111_write_ifp_reg(0x2e,(16<<8)|target[bright+4]); ++ return 0; ++} ++static int mt9v111_output_size(adcm_window_size * size) ++{ ++ //0xA7 Horizontal size of output ++ //0xAA Vertical size of output ++ //refer to mt9v111-datasheet.pdf page 45 and page 46 ++ mt9v111_write_ifp_reg(0xA7, 0x8000|size->width); ++ mt9v111_write_ifp_reg(0xAA, size->height); ++ dbg_print("output size :%d * %d \n",size->width,size->height); ++ adcm2700_wait(50); ++ return 0; ++} ++static int mt9v111_set_blackwhite(int black_white) ++{ ++ u16 value = mt9v111_read_ifp_reg(0x08); ++ if(black_white) ++ { ++ value |= 1<<5; ++ } ++ else ++ { ++ value &= ~(1<<5); ++ } ++ ++ mt9v111_write_ifp_reg(0x08, value); ++ return 0; ++} ++//set color correction matrix ++static int mt9v111_set_ccm(int index) ++{ ++ int i; ++ u16 r6; ++ const u16 regs[]= ++ { ++ 72, //digital gain ++ 2, //sign ++ 3,4, //scale ++ 9,10,11,12,13,14,15,16,17, //magnitude ++ 21,22,23,24,25,26,27,28,29,30, //delta matrix ++ 94,95,96 ++ }; ++ const u16 value[][26]= ++ { ++ //default ++ { ++ ++ 0, ++ 0x6e, ++ 0x2923,0x0524, ++ 146,22,8,171,147,88,77,169,160, ++ 373,22,67,12,0,21,31,22,152,76, ++ 26684,12296,2 ++ /* ++ 0, ++ 110, ++ 10531,1316, ++ 125,108,58,129,141,112,95,128,138, ++ 145,6,231,221,15,65,208,72,59,43, ++ 26953,11283,2 ++ */ ++ }, ++ //direct sun ++ { ++ /* ++ 128, ++ 0xea, ++ 0x3922,0x4e4, ++ 0x8d,0x71,0xc5,0x9d,0xf8,0x53,0x0d,0xa7,0x90, ++ 0,0,0,0,0,0,0,0,0,0 ++ */ ++ 128, ++ 174, ++ 14627,1828, ++ 128,7,52,122,215,7,59,99,232, ++ 0,0,0,0,0,0,0,0,0,0, ++ 21331,0,0 ++ ++ }, ++ //incandescent ++ { ++ /* ++ 128, ++ 0xee, ++ 0x2922,0x4a4, ++ 0x8c,0xcc,0x6e,0xa6,0x86,0x72,0x06,0x85,0xc6, ++ 0,0,0,0,0,0,0,0,0,0 ++ */ ++ 128, ++ 110, ++ 10532,1316, ++ 245,244,168,137,174,216,131,158,160, ++ 0,0,0,0,0,0,0,0,0,0, ++ 32832,0,0 ++ }, ++ //fluorescent ++ { ++ /* ++ 0, ++ 0xea, ++ 0x3922,0x4e4, ++ 0x8d,0xba,0x7b,0x9c,0xfe,0x61,0x08,0xb9,0x9a, ++ 0,0,0,0,0,0,0,0,0,0 ++ */ ++ 128, ++ 166, ++ 10531,1316, ++ 197,160,77,230,132,3,122,91,131, ++ 0,0,0,0,0,0,0,0,0,0, ++ 32844,0,0 ++ ++ }, ++ //sepia ++ { ++ 128, ++ 36, ++ 10516,2276, ++ 9,142,17,24,134,43,10,147,17, ++ 0,0,0,0,0,0,0,0,0,0, ++ 20560,0,0 ++ }, ++ }; ++ ++ for(i=0; i<26; i++) ++ { ++ mt9v111_write_ifp_reg(regs[i],value[index][i]); ++ } ++ ++ r6=mt9v111_read_ifp_reg(0x06); ++ r6 |= 1<<15; ++ mt9v111_write_ifp_reg(0x06,r6); ++ r6 &= ~(1<<15); ++ mt9v111_write_ifp_reg(0x06,r6); ++ return 0; ++} ++static int mt9v111_set_gamma(int index) ++{ ++ const u16 regs[]= ++ { ++ 0x58,0x53,0x54,0x55,0x56,0x57, ++ }; ++ const u16 value[][11]= ++ { ++ //default ++ { ++ //0x0,0x09,0x0f,0x1b,0x2f,0x52,0x71,0x8f,0xab,0xc6,0xe0 ++ 0,10,18,31,54,94,130,164,196,226,255 ++ }, ++ //solarize ++ { ++ // 224,23,17,128,220,175,105,53,33,8,0 ++ 0,4,8,16,32,64,96,128,160,192,224 ++ }, ++ //neg art ++ { ++ // 224,204,194,178,174,118,89,64,41,20,0 ++ 0,4,8,16,32,64,96,128,160,192,224 ++ } ++ }; ++ int i; ++ dbg_print("mt9v111_set_gamma to index :%d \n",index); ++ mt9v111_write_ifp_reg(regs[0],value[index][0]); ++ for(i=0; i<5; i++) ++ { ++ mt9v111_write_ifp_reg(regs[i+1],value[index][2*i+1]|(value[index][2*i+2]<<8)); ++ } ++ return 0; ++} ++static int mt9v111_set_light(V4l_PIC_WB light) ++{ ++ int index; ++ switch(light) ++ { ++ case V4l_WB_DIRECT_SUN: ++ index = 1; ++ break; ++ case V4l_WB_INCANDESCENT: ++ index = 2; ++ break; ++ case V4l_WB_FLUORESCENT: ++ index = 3; ++ break; ++ case V4l_WB_AUTO: ++ index = 0; ++ break; ++ default: ++ dbg_print("incorrect light type!\n"); ++ return -EFAULT; ++ } ++ return mt9v111_set_ccm(index); ++} ++static int mt9v111_set_style(V4l_PIC_STYLE style) ++{ ++ if(style != V4l_STYLE_BLACK_WHITE) ++ { ++ mt9v111_set_blackwhite(0); ++ } ++ switch(style) ++ { ++ case V4l_STYLE_BLACK_WHITE: ++ mt9v111_set_gamma(0); ++ mt9v111_set_blackwhite(1); ++ break; ++ case V4l_STYLE_SEPIA: ++ mt9v111_set_gamma(0); ++ mt9v111_set_ccm(4); ++ break; ++ case V4l_STYLE_SOLARIZE: ++ mt9v111_set_gamma(1); ++ break; ++ case V4l_STYLE_NEG_ART: ++ mt9v111_set_gamma(2); ++ break; ++ default: ++ mt9v111_set_gamma(0); ++ break; ++ } ++ return 0; ++} ++ ++static inline int mt9v111_set_effects(p_camera_context_t cam_ctx) ++{ ++ mt9v111_set_light(cam_ctx->capture_light); ++ mt9v111_set_style(cam_ctx->capture_style); ++ return 0; ++} ++static int mt9v111_reset(void) ++{ ++ //stop and reset ++ mt9v111_write_core_reg(0x07, 0x0); ++ adcm2700_wait(20); ++ mt9v111_write_core_reg(0x0D, 0x1); ++ adcm2700_wait(5); ++ mt9v111_write_core_reg(0x0D, 0x0); ++ adcm2700_wait(5); ++ mt9v111_write_ifp_reg(0x07, 0x1); ++ adcm2700_wait(5); ++ mt9v111_write_ifp_reg(0x07, 0x0); ++ ++ return 0; ++} ++static int mt9v111_set_flicker(int flicker) ++{ ++/* ++ if (flicker == 50) ++ { ++ mt9v111_write(0x5b,0x01); ++ } ++ else if (flicker ==60) ++ { ++ mt9v111_write(0x5b,0x03); ++ } ++ else ++ { ++ return -EFAULT; ++ } ++*/ ++ return 0; ++} ++/*********************************************************************** ++ * ++ * MT9V111 Functions ++ * ++ ***********************************************************************/ ++int camera_func_mt9v111_init( p_camera_context_t cam_ctx ) ++{ ++ u16 addr; ++ u16 reg_value; ++ const u16 values2[] = ++ { ++ 0x0006, 0xCE12, 0x00F0, 0x370D, 0xE20C, 0xFDF5, ++ 0x280B, 0xDE0D, 0x00F4, 0x280A, 0xBD20, 0xF8E4, ++ 0x1E0A, 0x0050, 0xD812, 0xFCEC, 0x1407, 0x0028, ++ 0xD413, 0xFEEC, 0x1405, 0x0028 ++ }; ++ ++ ci_disable(1); ++ cam_ctx->mclk=12; ++ ci_set_clock(cam_ctx->clk_reg_base, 1, 1, cam_ctx->mclk); ++ ci_enable(1); ++ adcm2700_wait(10); ++ mt9v111_reset(); ++ /* lens shading */ ++ for(addr = 0x80; addr <= 0x95; addr++) ++ { ++ mt9v111_write_ifp_reg(addr, values2[addr-0x80]); ++ } ++ //accelerate AE speed ++ //mt9v111_write_ifp_reg(0x2f,0x80); ++ /* 100% sharpening */ ++ //mt9v111_write_ifp_reg(0x05,0x0c); ++//codes from jason ++ //lens shading enable ++ //* ++ reg_value = mt9v111_read_ifp_reg(0x08); ++ reg_value |= 0x0100; ++ mt9v111_write_ifp_reg(0x08,reg_value); ++ //*/ ++ mt9v111_write_core_reg(0x09,280); ++ mt9v111_write_core_reg(0x21,0xe401); ++ reg_value = mt9v111_read_core_reg(0x07); ++ reg_value &= ~(0x0010); ++ mt9v111_write_core_reg(0x07,reg_value); ++ mt9v111_write_core_reg(0x2f,0xe7b6); ++ mt9v111_write_ifp_reg(0x39,282); ++ mt9v111_write_ifp_reg(0x59,280); ++ mt9v111_write_ifp_reg(0x5a,336); ++ mt9v111_write_ifp_reg(0x5c,4624); ++ mt9v111_write_ifp_reg(0x5d,5652); ++ mt9v111_write_ifp_reg(0x25,0x4514); ++ //mt9v111_write_ifp_reg(0x25,0x6d14); ++ mt9v111_write_ifp_reg(0x34,0x0); ++ mt9v111_write_ifp_reg(0x35,0xff00); ++ mt9v111_write_ifp_reg(0x33,0x1411); ++ mt9v111_write_ifp_reg(0x3e,0x0fff); ++ mt9v111_write_ifp_reg(0x3b,0x042c); ++ mt9v111_write_ifp_reg(0x3d,0x01da); ++ mt9v111_write_ifp_reg(0x38,0x0878); ++ mt9v111_write_ifp_reg(0x40,0x1e10); ++ mt9v111_write_ifp_reg(0x41,0x1417); ++ mt9v111_write_ifp_reg(0x42,0x1213); ++ mt9v111_write_ifp_reg(0x43,0x1112); ++ mt9v111_write_ifp_reg(0x44,0x7110); ++ mt9v111_write_ifp_reg(0x45,0x7473); ++ ++ dbg_print("Mt9v111 init success!"); ++ return 0; ++} ++ ++int camera_func_mt9v111_deinit( p_camera_context_t camera_context ) ++{ ++ //stop camera run ++ camera_func_mt9v111_stop_capture(camera_context); ++ ci_disable(1); ++ i2c_mt9v111_cleanup(); ++ return 0; ++} ++ ++int camera_func_mt9v111_set_capture_format(p_camera_context_t camera_context) ++{ ++ adcm_window_size wsize; ++ u16 fmt_v1, fmt_v2; ++ u16 old1, old2; ++ ++ //set sensor input/output window ++ wsize.width = camera_context->capture_width; ++ wsize.height = camera_context->capture_height; ++ mt9v111_output_size(&wsize); ++ dbg_print("output size width=%d, height=%d", wsize.width, wsize.height); ++ /* ++ 0x08 output format contorl bit 12 ++ 1 RGB ++ 0 YCbCr ++ 0x3A output format control 2 bit 6-7 ++ 00 16-bit RGB565 ++ 01 15-bit RGB555 ++ 10 12-bit RGB444x ++ 11 12-bit RGB444 ++ refer to mt9v111-datasheet.pdf page 32 and page 39 ++ */ ++ old1 = mt9v111_read_ifp_reg(0x08); ++ old2 = mt9v111_read_ifp_reg(0x3A); ++ ++ // set sensor format ++ switch(camera_context->capture_input_format) ++ { ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ dbg_print("output format YCBCR422"); ++ fmt_v1 = 0; ++ fmt_v2 = 0; ++ break; ++ ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ dbg_print("output format RGB565"); ++ fmt_v1 = (1<<12); ++ fmt_v2 = 0; ++ break; ++ ++ case CAMERA_IMAGE_FORMAT_RGB444: ++ dbg_print("output format RGB444"); ++ fmt_v1 = (1<<12); ++ fmt_v2 = (0x03<<6); ++ break; ++ ++ case CAMERA_IMAGE_FORMAT_RGB555: ++ dbg_print("output format RGB555"); ++ fmt_v1 = (1<<12); ++ fmt_v2 = (0x01<<6); ++ break; ++ ++ default: ++ dbg_print("unsupported format!"); ++ return -EFAULT; ++ } ++ ++ old1 = (old1 & ~(1<<12)) | fmt_v1; ++ old2 = ((old2 & ~(3<<6)) & (~0x03)) | fmt_v2; // | (2<<3)/*out test ramp*/; ++ mt9v111_write_ifp_reg(0x08, old1); ++ mt9v111_write_ifp_reg(0x3A, old2); ++ return 0; ++} ++ ++int camera_func_mt9v111_start_capture(p_camera_context_t cam_ctx, unsigned int frames) ++{ ++ int cisr; ++ int wait_count = 1; ++ unsigned int start_time; ++ unsigned int flags; ++ int error_count = 0; ++ //mt9v111_restore_property(cam_ctx); ++restart: ++ start_time = 0x1000000; ++ if(frames == 1) ++ { ++ wait_count = 2; ++ } ++ //mt9v111_write_core_reg(0x07, 0x0002); ++ dbg_print("wait for EOF %d time", wait_count); ++ ci_disable(1); ++ ci_enable(1); ++ ++ start_time *= wait_count; ++ CISR|=CI_CISR_EOF; ++ cisr=CISR; ++ //local_irq_save(flags); ++ //mdelay(200); ++ while(wait_count) ++ { ++ if(cisr & CI_CISR_EOF) ++ { ++ wait_count -- ; ++ CISR|=CI_CISR_EOF; ++ } ++ cisr=CISR; ++ if(!(--start_time)) ++ { ++ goto start_error; ++ } ++ } ++ // ci_clear_int_status(0xFFFFFFFF); ++ mdelay(1); ++ ci_reset_fifo(); ++ ci_disable(1); ++ ci_enable(1); ++ start_dma_transfer(cam_ctx, 0); ++ //local_irq_restore(flags); ++ return 0; ++ ++start_error: ++ dbg_print("start error \n"); ++ if(error_count++ > 3) ++ { ++ return -1; ++ } ++ ci_disable(1); ++ ci_enable(1); ++ adcm2700_wait(10); ++ mt9v111_reset(); ++ mt9v111_restore_property(cam_ctx); ++ goto restart; ++ ++} ++ ++int camera_func_mt9v111_stop_capture( p_camera_context_t camera_context ) ++{ ++ /* ++ u16 old = mt9v111_read_core_reg(0x07); ++ old &= ~0x02; ++ mt9v111_write_core_reg(0x07, old); ++ */ ++ // stop_dma_transfer(camera_context); ++ return 0; ++} ++/*set output size*/ ++static int pxa_cam_WCAM_VIDIOCSOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ adcm_window_size size; ++ CI_MP_TIMING timing; ++ int ret = 0; ++ unsigned int value; ++ memset(&timing, 0, sizeof(timing)); ++ dbg_print("WCAM_VIDIOCSOSIZE"); ++ if(copy_from_user(&size, param, sizeof(adcm_window_size))) ++ { ++ return -EFAULT; ++ } ++ size.height = (size.height+7)/8 * 8; ++ size.width = (size.width +7)/8 * 8; ++ if(size.height != cam_ctx->capture_height || size.width != cam_ctx->capture_width) ++ { ++ cam_ctx->capture_width = size.width; ++ cam_ctx->capture_height = size.height; ++ ret = mt9v111_output_size(&size); ++ timing.BFW = 0; ++ timing.BLW = 0; ++ ci_disable(1); ++ ci_configure_mp(cam_ctx->capture_width-1, cam_ctx->capture_height-1, &timing); ++ camera_ring_buf_init(cam_ctx); ++ ci_enable(1); ++ //mdelay(150); ++ } ++ return ret; ++} ++ ++/*read mt9v111 registers*/ ++static int pxa_camera_WCAM_VIDIOCGCAMREG(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print(""); ++ int data, reg_value; ++ if(copy_from_user(&data, param, sizeof(data))) ++ { ++ return -EFAULT; ++ } ++ u16 space = (u16)(data>>16); ++ u16 addr = (u16)data; ++ ++ if(space == ADDRSPACE_CORE) ++ { ++ reg_value = mt9v111_read_core_reg(addr); ++ } ++ else if(space == ADDRSPACE_IFP) ++ { ++ reg_value = mt9v111_read_ifp_reg(addr); ++ } ++ else ++ { ++ return -EFAULT; ++ } ++ ++ if(copy_to_user(param, ®_value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/*write mt9v111 registers*/ ++static int pxa_camera_WCAM_VIDIOCSCAMREG(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print(""); ++ ++ struct reg_set_s {int val1, val2;}reg_value; ++ ++ if(copy_from_user(®_value, param, sizeof(reg_value))) ++ { ++ return -EFAULT; ++ } ++ ++ u16 space = (u16)(reg_value.val1 >> 16); ++ u16 addr = (u16)(reg_value.val1); ++ ++ if(space == ADDRSPACE_CORE) ++ { ++ mt9v111_write_core_reg(addr, (u16)(reg_value.val2)); ++ } ++ else if(space == ADDRSPACE_IFP) ++ { ++ mt9v111_write_ifp_reg(addr, (u16)(reg_value.val2)); ++ } ++ else ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*set sensor size*/ ++static int pxa_cam_WCAM_VIDIOCSSSIZE(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print(""); ++ adcm_window_size size; ++ int ret = 0; ++ if(copy_from_user(&size, param, sizeof(adcm_window_size))) ++ { ++ return -EFAULT; ++ } ++ size.width = ((size.width+7)/8) * 8; ++ size.height = ((size.height+7)/8) *8; ++ if(size.width != cam_ctx->sensor_width || size.height != cam_ctx->sensor_height) ++ { ++ cam_ctx->sensor_width = size.width; ++ cam_ctx->sensor_height = size.height; ++ ++ if(size.width > MT9V111_SENSOR_WIDTH || size.height > MT9V111_SENSOR_HEIGHT) ++ { ++ dbg_print("error input size width %d height %d",size.width, size.height); ++ return -EFAULT; ++ } ++ ++ ret = mt9v111_input_size(&size); ++ } ++ return ret; ++} ++ ++/*set fps*/ ++static int pxa_cam_WCAM_VIDIOCSFPS(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print("WCAM_VIDIOCSFPS"); ++ struct {int fps, minfps;} cam_fps; ++ int ret = 0; ++ ++ if(copy_from_user(&cam_fps, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ ++ if(cam_fps.minfps < 5) ++ { ++ cam_fps.minfps = 5; ++ } ++ if(cam_fps.fps >15) ++ { ++ cam_fps.fps = 15; ++ } ++ ++ if(cam_fps.fps != cam_ctx->fps || cam_fps.minfps != cam_ctx->mini_fps) ++ { ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ ret = mt9v111_set_fps(cam_ctx->fps, cam_ctx->mini_fps); ++ } ++ ++ return ret; ++} ++/*set image style*/ ++static int pxa_cam_WCAM_VIDIOCSSTYLE(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print("WCAM_VIDIOCSSTYLE"); ++ int ret=0; ++ if(cam_ctx->capture_style != (V4l_PIC_STYLE)param) ++ { ++ cam_ctx->capture_style = (V4l_PIC_STYLE)param; ++ ret = mt9v111_set_effects(cam_ctx); ++ } ++ return ret; ++} ++/*set video light*/ ++static int pxa_cam_WCAM_VIDIOCSLIGHT(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print("WACM_VIDIOCSLIGHT"); ++ int ret=0; ++ if(cam_ctx->capture_light!= (V4l_PIC_WB)param) ++ { ++ cam_ctx->capture_light=(V4l_PIC_WB)param; ++ ret = mt9v111_set_effects(cam_ctx); ++ } ++ return ret; ++} ++/*set picture brightness*/ ++static int pxa_cam_WCAM_VIDIOCSBRIGHT(p_camera_context_t cam_ctx, void *param) ++{ ++ dbg_print("WCAM_VIDIOCSBRIGHT"); ++ int ret =0; ++ if( cam_ctx->capture_bright != (int)param) ++ { ++ cam_ctx->capture_bright = (int)param; ++ ret=mt9v111_set_bright(cam_ctx->capture_bright); ++ } ++ return ret; ++} ++static int pxa_cam_WCAM_VIDIOCSFLICKER(p_camera_context_t cam_ctx, void * param) ++{ ++ dbg_print("WCAM_VIDIOCSFLICKER"); ++ cam_ctx->flicker_freq = (int)param; ++ return mt9v111_set_flicker(cam_ctx->flicker_freq); ++} ++static int mt9v111_restore_property(p_camera_context_t cam_ctx) ++{ ++ adcm_window_size size; ++ ++ size.width = cam_ctx->sensor_width; ++ size.height= cam_ctx->sensor_height; ++ mt9v111_input_size(&size); ++ ++ camera_func_mt9v111_set_capture_format(cam_ctx); ++ ++ mt9v111_set_fps(cam_ctx->fps,cam_ctx->mini_fps); ++ ++ mt9v111_set_bright(cam_ctx->capture_bright); ++ ++ mt9v111_set_effects(cam_ctx); ++ ++ return 0; ++} ++int camera_func_mt9v111_pm_management(p_camera_context_t cam_ctx, int suspend) ++{ ++ static int resume_dma = 0; ++ if(suspend) ++ { ++ if(cam_ctx != NULL ) ++ { ++ if(cam_ctx->dma_started) ++ { ++ dbg_print("camera running, suspended"); ++ stop_dma_transfer(cam_ctx); ++ resume_dma = 1; ++ } ++ } ++ disable_irq(IRQ_CAMERA); ++ pxa_set_cken(CKEN24_CAMERA, 0); ++ } ++ else ++ { ++ pxa_set_cken(CKEN24_CAMERA, 1); ++ if(cam_ctx != NULL) ++ { ++ dbg_print("camera running, resumed"); ++ camera_init(cam_ctx); ++ mt9v111_restore_property(cam_ctx); ++ if(resume_dma == 1) ++ { ++ camera_start_video_capture(cam_ctx, 0); ++ resume_dma = 0; ++ } ++ } ++ enable_irq(IRQ_CAMERA); ++ } ++ return 0; ++} ++ ++int camera_func_mt9v111_docommand(p_camera_context_t cam_ctx, unsigned int cmd, void *param) ++{ ++ switch(cmd) ++ { ++ /*read mt9v111 registers*/ ++ case WCAM_VIDIOCGCAMREG: ++ return pxa_camera_WCAM_VIDIOCGCAMREG(cam_ctx, param); ++ ++ /*write mt9v111 registers*/ ++ case WCAM_VIDIOCSCAMREG: ++ return pxa_camera_WCAM_VIDIOCSCAMREG(cam_ctx, param); ++ ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return pxa_cam_WCAM_VIDIOCSSSIZE(cam_ctx, param); ++ ++ /*set output size*/ ++ case WCAM_VIDIOCSOSIZE: ++ return pxa_cam_WCAM_VIDIOCSOSIZE(cam_ctx, param); ++ ++ /*set video mode fps*/ ++ case WCAM_VIDIOCSFPS: ++ return pxa_cam_WCAM_VIDIOCSFPS(cam_ctx, param); ++ ++ /*set picture style*/ ++ case WCAM_VIDIOCSSTYLE: ++ return pxa_cam_WCAM_VIDIOCSSTYLE(cam_ctx, param); ++ ++ /*set picture light*/ ++ case WCAM_VIDIOCSLIGHT: ++ return pxa_cam_WCAM_VIDIOCSLIGHT(cam_ctx, param); ++ ++ /*set picture brightness*/ ++ case WCAM_VIDIOCSBRIGHT: ++ return pxa_cam_WCAM_VIDIOCSBRIGHT(cam_ctx, param); ++ /*set flicker frequency*/ ++ case WCAM_VIDIOCSFLICKER: ++ return pxa_cam_WCAM_VIDIOCSFLICKER(cam_ctx, param); ++ default: ++ { ++ dbg_print("Error cmd=0x%x", cmd); ++ return -EFAULT; ++ } ++ } ++ return 0; ++ ++} +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9640.c linux-2.6.16/drivers/media/video/ov9640.c +--- linux-2.6.16.orig/drivers/media/video/ov9640.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9640.c 2006-06-03 11:14:56.441308872 +0200 +@@ -0,0 +1,608 @@ ++/* ++ ov9640 - Omnivision 9640 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++ ++#include <asm/pgtable.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++#include "camera.h" ++#include "ov9640.h" ++#include "ov9640_hw.h" ++ ++ ++#define MAX_WIDTH 1280 ++#define MAX_HEIGHT 960 ++#define MIN_WIDTH 88 ++#define MIN_HEIGHT 72 ++ ++#define MAX_BPP 16 ++#define WIDTH_DEFT 320 ++#define HEIGHT_DEFT 240 ++#define FRAMERATE_DEFT 0xf ++ ++/* ++ * It is required to have at least 3 frames in buffer ++ * in current implementation ++ */ ++#define FRAMES_IN_BUFFER 3 ++#define MIN_FRAMES_IN_BUFFER 3 ++#define MAX_FRAME_SIZE (MAX_WIDTH * MAX_HEIGHT * (MAX_BPP >> 3)) ++#define BUF_SIZE_DEFT (MAX_FRAME_SIZE ) ++#define SINGLE_DESC_TRANS_MAX PAGE_SIZE ++#define MAX_DESC_NUM ((MAX_FRAME_SIZE / SINGLE_DESC_TRANS_MAX + 1) *\ ++ MIN_FRAMES_IN_BUFFER) ++ ++#define MAX_BLOCK_NUM 20 ++extern ov9640 g_ov; ++ ++camera_function_t ov9640_func = { ++ .init = camera_func_ov9640_init, ++ .deinit = camera_func_ov9640_deinit, ++ .set_capture_format = camera_func_ov9640_set_capture_format, ++ .start_capture = camera_func_ov9640_start_capture, ++ .stop_capture = camera_func_ov9640_stop_capture, ++ .command = camera_func_ov9640_command, ++ .pm_management = camera_func_ov9640_pm, ++}; ++ ++/*********************************************************************** ++ * ++ * OV9640 Functions ++ * ++ ***********************************************************************/ ++static void ov9640_gpio_init() ++{ ++ ++ set_GPIO_mode(27 | GPIO_ALT_FN_3_IN); /* CIF_DD[0] */ ++ set_GPIO_mode(114 | GPIO_ALT_FN_1_IN); /* CIF_DD[1] */ ++ set_GPIO_mode(51 | GPIO_ALT_FN_1_IN); /* CIF_DD[2] */ ++ set_GPIO_mode(115 | GPIO_ALT_FN_2_IN); /* CIF_DD[3] */ ++ set_GPIO_mode(95 | GPIO_ALT_FN_2_IN); /* CIF_DD[4] */ ++ set_GPIO_mode(94 | GPIO_ALT_FN_2_IN); /* CIF_DD[5] */ ++ set_GPIO_mode(17 | GPIO_ALT_FN_2_IN); /* CIF_DD[6] */ ++ set_GPIO_mode(108 | GPIO_ALT_FN_1_IN); /* CIF_DD[7] */ ++ set_GPIO_mode(23 | GPIO_ALT_FN_1_OUT); /* CIF_MCLK */ ++ set_GPIO_mode(54 | GPIO_ALT_FN_3_IN); /* CIF_PCLK */ ++ set_GPIO_mode(85 | GPIO_ALT_FN_3_IN); /* CIF_LV */ ++ set_GPIO_mode(84 | GPIO_ALT_FN_3_IN); /* CIF_FV */ ++ set_GPIO_mode(50 | GPIO_OUT); /*CIF_PD */ ++ set_GPIO_mode(19 | GPIO_IN); /*CIF_RST */ ++ ++ ++ return; ++ ++} ++ ++void ov9640_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz) ++{ ++ unsigned int ciclk = 0, value, div, cccr_l, K; ++ ++ // determine the LCLK frequency programmed into the CCCR. ++ cccr_l = (CCCR & 0x0000001F); ++ ++ if (cccr_l < 8) // L = [2 - 7] ++ ciclk = (13 * cccr_l) * 100; ++ else if (cccr_l < 17) // L = [8 - 16] ++ ciclk = ((13 * cccr_l) * 100) >> 1; ++ else if (cccr_l < 32) // L = [17 - 31] ++ ciclk = ((13 * cccr_l) * 100) >> 2; ++ DPRINTK(KERN_WARNING "the mclk_khz = %d \n", mclk_khz); ++ ++ // want a divisor that gives us a clock rate as close to, but not more than the given mclk. ++ div = (ciclk + mclk_khz) / (2 * mclk_khz) - 1; ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK << CI_CICR4_DIV_SHIFT); ++ value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0; ++ value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0; ++ value |= div << CI_CICR4_DIV_SHIFT; ++ CICR4 = value; ++ return; ++} ++ ++int camera_func_ov9640_init(p_camera_context_t cam_ctx) ++{ ++ u8 cm_rev, cm_pid; ++ u32 timeout; ++ int status; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ memset(pov, 0, sizeof(ov9640)); ++ ++ pov->pre_size = OV_SIZE_NONE; ++ pov->win.width = cam_ctx->capture_width; ++ pov->win.height = cam_ctx->capture_height; ++ // init context status ++ cam_ctx->dma_channels[0] = 0xFF; ++ cam_ctx->dma_channels[1] = 0xFF; ++ cam_ctx->dma_channels[2] = 0xFF; ++ ++ cam_ctx->capture_width = WIDTH_DEFT; ++ cam_ctx->capture_height = HEIGHT_DEFT; ++ ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ ++ cam_ctx->frame_rate = cam_ctx->fps = FRAMERATE_DEFT; ++ ++ cam_ctx->mini_fps = FRAMERATE_DEFT - 2; ++ ++ cam_ctx->buf_size = BUF_SIZE_DEFT; ++ cam_ctx->dma_descriptors_size = MAX_DESC_NUM; ++ DPRINTK(KERN_WARNING "dma_descriptors_size =%d,cam_ctx->buf_size=%d\n", cam_ctx->dma_descriptors_size, ++ cam_ctx->buf_size); ++ cam_ctx->vc.maxwidth = 1280; ++ cam_ctx->vc.maxheight = 960; ++ cam_ctx->vc.minwidth = MIN_WIDTH; ++ cam_ctx->vc.minheight = MIN_HEIGHT; ++ //DPRINTK( KERN_WARNING" before ov9640_gpio_init\n"); ++ ov9640_gpio_init(); ++ ci_init(); ++ // Configure CI according to OV9640's hardware ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ // enable pixel clock(sensor will provide pclock) and master clock = 26MHZ ++ //ci_set_clock(cam_ctx->clk_reg_base, 1, 1, 26); ++ ov9640_set_clock(cam_ctx->clk_reg_base, 1, 1, 2400); ++ pov->mclock = 24; ++ ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(0, 0, 0); ++ ++ // fifo control ++ // CISetFIFO(cam_ctx->ci_reg_base, 4000, XLLP_CI_FIFO_THL_32, XLLP_TRUE, XLLP_TRUE); ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); ++ ++ // OV9640 Power on sequence ++ // Take out of Power down mode, PWRDWN=1, NORMAL=0 ++ // Assert Reset ++ // Delay ++ // Remove reset ++ // Delay ++ ov9640_power_down(0); ++ ov9640_reset(); ++ mdelay(1); ++ ++ // init I2C. ++ status = i2c_init(); ++ if (status) ++ return status; ++ ++ // 2 Turn on M_CLK using xx MHz and wait for 150 ms. ?? ++ ci_enable(1); ++ mdelay(20); ++ ++ // read out version ++ //timeout = 50; ++ timeout = 5; ++ do { ++ cm_pid = cm_rev = 0; ++ status = ov9640_version_revision(&cm_pid, &cm_rev); ++ ++ // Check to make sure we are working with an OV9640 ++ if (cm_pid == PID_OV && cm_rev == PID_9640) { ++ int ver = (PID_OV << 8) | (PID_9640); ++ pov->version = ver; ++ } ++ else if (cm_pid == PID_OV_v3 || cm_rev == PID_9640_v3) { ++ int ver = (PID_OV_v3 << 8) | (PID_9640_v3); ++ pov->version = ver; ++ } ++ else { ++ ov9640_power_down(1); ++ ov9640_power_down(0); ++ ov9640_reset(); ++ mdelay(1); ++ } ++ printk("in fun camera_func_ov9640_init version=%x\n", pov->version); ++ if (--timeout == 0) ++ return -1; ++ } ++ while (cm_pid != PID_OV); ++ ++ cam_ctx->sensor_type = CAMERA_TYPE_OMNIVISION_9640; ++ // turn sensor output off ++ ov9640_viewfinder_off(); ++ ++ return 0; ++} ++ ++int camera_func_ov9640_deinit(p_camera_context_t cam_ctx) ++{ ++ //init the prev_xx value. ++ ov9640_set_format(OV_SIZE_NONE, OV_FORMAT_NONE); ++ mdelay(20); ++ // power off the external module ++ ov9640_power_down(1); ++ ++ return 0; ++} ++ ++int camera_func_ov9640_sleep(p_camera_context_t cam_ctx) ++{ ++ camera_func_ov9640_deinit(cam_ctx); ++} ++ ++int camera_func_ov9640_wake(p_camera_context_t cam_ctx) ++{ ++ camera_func_ov9640_init(cam_ctx); ++} ++ ++static get_ov_format(p_camera_context_t cam_ctx, u32 * size_format, u32 * color_format) ++{ ++ u32 ovSizeFormat, ovFormat; ++ ++ // Set the current mode ++ switch (cam_ctx->capture_input_format) { ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ ovFormat = OV_FORMAT_YUV_422; ++ printk("in get_ov_format ovFormat = OV_FORMAT_YUV_422\n"); ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ ovFormat = OV_FORMAT_RGB_565; ++ break; ++ default: ++ printk(KERN_INFO "The Format doesn't support by OV9640 Sensor \n"); ++ return -1; ++ } ++ if (cam_ctx->capture_width == 88 && cam_ctx->capture_height == 72) ++ ovSizeFormat = OV_SIZE_QQCIF; ++ else if (cam_ctx->capture_width == 160 && cam_ctx->capture_height == 120) ++ ovSizeFormat = OV_SIZE_QQVGA; ++ else if (cam_ctx->capture_width == 176 && cam_ctx->capture_height == 144) ++ ovSizeFormat = OV_SIZE_QCIF; ++ else if (cam_ctx->capture_width == 320 && cam_ctx->capture_height == 240) ++ ovSizeFormat = OV_SIZE_QVGA; ++ else if (cam_ctx->capture_width == 352 && cam_ctx->capture_height == 288) ++ ovSizeFormat = OV_SIZE_CIF; ++ else if (cam_ctx->capture_width == 640 && cam_ctx->capture_height == 480) ++ ovSizeFormat = OV_SIZE_VGA; ++ else if (cam_ctx->capture_width == 1280 && cam_ctx->capture_height == 960) ++ ovSizeFormat = OV_SIZE_SXGA; ++ else { ++ return -1; ++ } ++ if (ovSizeFormat == OV_SIZE_QVGA) ++ printk("ovSizeFormat =OV_SIZE_QVGA \n"); ++ *size_format = ovSizeFormat; ++ *color_format = ovFormat; ++ return 0; ++} ++ ++int camera_func_ov9640_set_capture_format(p_camera_context_t cam_ctx) ++{ ++ CI_MP_TIMING timing; ++ int status = -1; ++ u32 ovSizeFormat, ovFormat; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ ++ status = get_ov_format(cam_ctx, &ovSizeFormat, &ovFormat); ++ if (status) ++ return -1; ++ ++ status = ov9640_set_format(ovSizeFormat, ovFormat); ++ if (status) ++ return -1; ++ ++ // set capture width/height and timing ++ //timing.BFW = pov->win.x; ++ //timing.BLW = pov->win.y; ++ timing.BFW = 0; ++ timing.BLW = 0; ++ //ci_configure_mp(pov->win.width - 1, pov->win.height - 1, &timing); ++ ++ return status; ++} ++ ++#define COPY_BUFFERS(pdes, p_page, size) \ ++do { \ ++ unsigned int len; \ ++ unsigned int remain_size = size; \ ++ while (remain_size > 0) { \ ++ if (remain_size > PAGE_SIZE) \ ++ len = PAGE_SIZE; \ ++ else \ ++ len = remain_size; \ ++ if (memcpy(page_address(*pdes), page_address(*p_page), len)) \ ++ return -EFAULT; \ ++ remain_size -= len; \ ++ pdes ++;\ ++ p_page++; \ ++ } \ ++} while (0); ++ ++int camera_func_ov9640_start_capture(p_camera_context_t cam_ctx, unsigned int frames) ++{ ++ int status = -1; ++ u32 ovSizeFormat, ovFormat; ++ ov9640 *pov; ++ u8 value; ++ ++ pov = &g_ov; ++ ++ ci_disable(1); ++ mdelay(1); ++ ci_enable(1); ++ // clear ci fifo ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ ++ camera_set_int_mask(cam_ctx, 0x3ff | 0x0400); ++ // turn auto function on only doing continues capture ++ if (frames == 0) { ++// CISR |= (1 << 3); ++// while (!(CISR & (1 << 3))); //Wait a EOF then begin start DMA ++ ov9640_auto_function_on(); ++ // start dma ++ start_dma_transfer(cam_ctx, 0); ++ } ++ else { ++ status = get_ov_format(cam_ctx, &ovSizeFormat, &ovFormat); ++ if (status) ++ return -1; ++ if (pov->pre_size == OV_SIZE_NONE) ++ return -1; ++ printk("in function %s, cam_ctx->block_tail == 0\n", __FUNCTION__); ++ if (pov->pre_size == ovSizeFormat) { ++ if (cam_ctx->block_tail == 0) { ++ } ++ else { ++ struct page **p_page; ++ struct page **pdes; ++ ++ printk("in function %s, cam_ctx->block_tail != 0\n", __FUNCTION__); ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ pdes = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ COPY_BUFFERS(pdes, p_page, cam_ctx->fifo0_transfer_size); ++ COPY_BUFFERS(pdes, p_page, cam_ctx->fifo1_transfer_size); ++ COPY_BUFFERS(pdes, p_page, cam_ctx->fifo2_transfer_size); ++ } ++ set_still_image_ready(1); ++ return 0; ++ } ++ else { ++ ov9640_auto_function_off(); ++ cam_ctx->block_tail = cam_ctx->block_header = 0; ++ ov9640_prepare_capture(cam_ctx, ovSizeFormat, ovFormat); ++ } ++ // turn viewfinder on ++ ov9640_viewfinder_on(); ++ } ++ // turn viewfinder on ++ ov9640_viewfinder_on(); ++ ov9640_read(0xc, &value); ++ ov9640_set_start(); ++ return 0; ++} ++ ++int Ov9640AutoFunctionOn() ++{ ++ u8 regValue; ++ ++ printk("in function %s \n", __FUNCTION__); ++ ov9640_read(0x13, ®Value); ++ if ((regValue & 0x7) == 7) ++ return 1; ++ return 0; ++} ++ ++int camera_func_ov9640_stop_capture(p_camera_context_t cam_ctx) ++{ ++ if (ov9640_output_stoped()) ++ return 0; ++ printk("in camera_func_ov9640_stop_capture\n"); ++ //if (Ov9640AutoFunctionOn()) ++ ov9640_save_gains(); ++ // turn auto function off ++ //ov9640_auto_function_off(); ++ ++ // turn viewfinder off ++ ov9640_viewfinder_off(); ++ stop_dma_transfer(cam_ctx); ++ ov9640_set_stop(cam_ctx); ++ return 0; ++} ++ ++int camera_func_ov9640_command(p_camera_context_t cam_ctx, unsigned int cmd, void *param) ++{ ++ int ret = 0; ++ ++ printk("in function %s, param =%d, \n", __FUNCTION__, param); ++ switch (cmd) { ++ /* get capture size */ ++ case VIDIOCGWIN: ++ { ++ struct video_window vw; ++ vw.width = cam_ctx->capture_width; ++ vw.height = cam_ctx->capture_height; ++ ov9640_get_window(&vw); ++ if (copy_to_user(param, &vw, sizeof(struct video_window))) ++ ret = -EFAULT; ++ break; ++ } ++ ++ /* set capture size. */ ++ case VIDIOCSWIN: ++ { ++ struct video_window vw; ++ if (copy_from_user(&vw, param, sizeof(vw))) { ++ ret = -EFAULT; ++ break; ++ } ++ printk("in %s, vw-x =%d, vw-y=%d,vw.width=%d,vw.height=%d\n", ++ __FUNCTION__, vw.x, vw.y, vw.width, vw.height); ++ if (vw.width > 1280 || vw.height > 960 || vw.width < MIN_WIDTH || vw.height < MIN_HEIGHT) { ++ ret = -EFAULT; ++ break; ++ } ++ /* ++ */ ++ ov9640_set_window(&vw); ++ cam_ctx->capture_width = vw.width; ++ cam_ctx->capture_height = vw.height; ++ camera_set_capture_format(cam_ctx); ++ break; ++ } ++ /*set picture style */ ++ case WCAM_VIDIOCSSTYLE: ++ { ++ V4l_PIC_STYLE capture_style; ++ capture_style = (V4l_PIC_STYLE) param; ++ cam_ctx->capture_style = (V4l_PIC_STYLE) param; ++ //ret = ov9640_set_special_effect(capture_style); ++ printk("in camera_func_ov9640_command ret=%d\n", ret); ++ if (cam_ctx->capture_style != V4l_STYLE_BLACK_WHITE && cam_ctx->capture_style != V4l_STYLE_SEPIA) { ++ } ++ } ++ break; ++ /*set picture light */ ++ case WCAM_VIDIOCSLIGHT: ++ cam_ctx->capture_light = (int) param; ++ ret = ov9640_set_white_balance(param); ++ break; ++ /*set picture brightness */ ++ case WCAM_VIDIOCSBRIGHT: ++ cam_ctx->capture_bright = (int) param; ++ //ret = ov9640_set_expose_compensation((int) param); ++ ret = ov9640_set_brightness((int) param); ++ break; ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return ov9640_set_sensor_size(cam_ctx, param); ++ ++ /*get sensor size */ ++ case WCAM_VIDIOCGSSIZE: ++ return ov9640_get_sensor_size(cam_ctx, param); ++ ++ /*set output size */ ++ case WCAM_VIDIOCSOSIZE: ++ return ov9640_set_output_size(cam_ctx, param); ++ ++ /*get output size */ ++ case WCAM_VIDIOCGOSIZE: ++ return ov9640_get_output_size(cam_ctx, param); ++#if 0 ++#endif ++ /*set video mode fps */ ++ case WCAM_VIDIOCSFPS: ++ { ++ struct { ++ int fps, minfps; ++ } cam_fps; ++ DPRINTK("WCAM_VIDIOCSFPS"); ++ if (copy_from_user(&cam_fps, param, sizeof(int) * 2)) { ++ return -EFAULT; ++ } ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ return ov9640_set_fps(cam_fps.fps, cam_fps.minfps); ++ } ++ return -1; ++ case WCAM_VIDIOCSNIGHTMODE: ++ { ++ struct { ++ int mode, maxexpottime; ++ } cam_mode; ++ int mode; ++ if (copy_from_user(&cam_mode, param, sizeof(cam_mode))) { ++ return -EFAULT; ++ } ++ mode = cam_mode.mode; ++ if (mode == V4l_NM_NIGHT) ++ ov9640_set_night_mode(); ++ if (mode == V4l_NM_ACTION) ++ ov9640_set_action_mode(); ++ if (mode == V4l_NM_AUTO) ++ ov9640_set_auto_mode(); ++ } ++ break; ++ case WCAM_VIDIOCSCONTRAST: ++ { ++ DPRINTK("WCAM_VIDIOCSCONTRAST parameter=%d",param); ++ ret = ov9640_set_contrast((int)param/50); ++ break; ++ } ++ case WCAM_VIDIOCSFLICKER: ++ { ++ ret = ov9640_set_light_environment(param); ++ break; ++ } ++ default: ++ printk("in %s default case -----------------cmd =%d param=%d\n", __FUNCTION__, cmd, param); ++ ret = -1; ++ } ++ return ret; ++} ++int camera_func_ov9640_pm(p_camera_context_t cam_ctx, int suspend) ++{ ++ static int resume_dma = 0; ++ if (suspend) { ++ if (cam_ctx != NULL) { ++ if (cam_ctx->dma_started) { ++ dbg_print("camera running, suspended"); ++ stop_dma_transfer(cam_ctx); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ CKEN &= ~CKEN24_CAMERA; ++ } ++ else { ++ CKEN |= CKEN24_CAMERA; ++ enable_irq(IRQ_CAMERA); ++ ++ if (cam_ctx != NULL) { ++ dbg_print("camera running, resumed"); ++ camera_init(cam_ctx); ++ //ov9640_restore_property(cam_ctx, 0); ++ ++ ++ if (resume_dma == 1) { ++ camera_start_video_capture(cam_ctx, 0); ++ resume_dma = 0; ++ } ++ } ++ } ++ return 0; ++} +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9640.h linux-2.6.16/drivers/media/video/ov9640.h +--- linux-2.6.16.orig/drivers/media/video/ov9640.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9640.h 2006-06-03 11:14:56.442308720 +0200 +@@ -0,0 +1,67 @@ ++/* ++ ov9640 - Omnivision 9640 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++#ifndef _OV_9640_H_ ++#define _OV_9640_H_ ++ ++#include <linux/videodev.h> ++#include "camera.h" ++typedef struct { ++ u32 version; ++ u32 stoped; ++ u32 mclock; ++ u32 pre_size; ++ u32 exp_value; ++ u32 exp_time; ++ u32 adjusted_exp_value; ++ u32 adjusted_exp_time; ++ u8 pclock; ++ u8 gain; ++ u8 blue_gain; ++ u8 red_gain; ++ u8 y_average; ++ u32 sensor_width; ++ u32 sensor_height; ++ u32 sub_win; ++ u32 night_mode; ++ struct video_window win; ++}ov9640; ++ ++////////////////////////////////////////////////////////////////////////////////////// ++// ++// Prototypes ++// ++////////////////////////////////////////////////////////////////////////////////////// ++ ++int camera_func_ov9640_init( p_camera_context_t ); ++ ++int camera_func_ov9640_deinit( p_camera_context_t ); ++ ++int camera_func_ov9640_sleep( p_camera_context_t camera_context ); ++ ++int camera_func_ov9640_wake( p_camera_context_t camera_context ); ++ ++int camera_func_ov9640_set_capture_format( p_camera_context_t ); ++ ++int camera_func_ov9640_start_capture( p_camera_context_t, unsigned int frames ); ++ ++int camera_func_ov9640_stop_capture( p_camera_context_t ); ++ ++int camera_func_ov9640_pm(p_camera_context_t cam_ctx, int suspend); ++#endif +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9640_hw.c linux-2.6.16/drivers/media/video/ov9640_hw.c +--- linux-2.6.16.orig/drivers/media/video/ov9640_hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9640_hw.c 2006-06-03 11:14:56.446308112 +0200 +@@ -0,0 +1,3034 @@ ++/* ++ ov9640_hw - Omnivision 9640 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#include <linux/types.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/wrapper.h> ++#include <linux/delay.h> ++#include <linux/videodev.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++ ++#include <linux/i2c.h> ++#include "camera.h" ++#include "ov9640.h" ++#include "ov9640_hw.h" ++ ++ov9640 g_ov; ++/*********************************************************************** ++* Attention: This is platform related! ++***********************************************************************/ ++static const u32 OV9640_PWRDWN_GPIO[2] = { 1, 50 }; ++//static const u32 OV9640_RESET_GPIO[2] = { 1, xxx }; ++volatile int ov9640_step = 0; ++ ++/*********************************************************************** ++* Register Settings ++***********************************************************************/ ++static u8 gDelta[] = { ++ OV9640_COM7, //0x12 ++ OV9640_COM1, //0x04 ++// OV9640_CLKRC, //0x11 ++ OV9640_COM4, //0x0d ++ OV9640_COM3, //0x0c ++ OV9640_REGEND // End of list delimiter. ++}; ++const static u8 gYUV_QQVGA[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x10, ++ OV9640_COM1, 0x24, ++ OV9640_CLKRC, 0x01, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x5, //0x04 ++ OV9640_COM4, 0xC0, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x8, ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_QQCIF[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x08, ++ OV9640_COM1, 0x24, ++ OV9640_CLKRC, 0x01, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x5, //0x04 ++ OV9640_COM4, 0xC0, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x8, ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_QVGA1[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x10, ++ OV9640_COM1, 0x00, ++ OV9640_CLKRC, 0x01, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x5, //0x04 ++ OV9640_COM4, 0xC0, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x8, ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ /* ++ OV9640_MTX1 , 0x3c, ++ OV9640_MTX2 , 0x32, ++ OV9640_MTX3 , 0x09, ++ OV9640_MTX4 , 0x13, ++ OV9640_MTX5 , 0x39, ++ OV9640_MTX6 , 0x4c, ++ */ ++ ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_VGA[] = { ++ 0x15, 0x20, ++ 0x12, 0x40, ++ 0x04, 0x00, ++ 0x11, 0x83, ++ //0x01 , 0x80, ++ //0x02 , 0x80, ++ 0x0C, 0x05, ++ 0x0D, 0xC0, ++ 0x0E, 0x01, ++ 0x0F, 0x4F, ++ 0x13, 0x82, //0x80 ++ 0x14, 0x4A, ++ 0x1B, 0x01, ++ 0x24, 0x78, ++ 0x25, 0x70, ++ 0x27, 0x90, ++ 0x33, 0x08, ++ 0x36, 0xC9, ++ 0x3A, 0x08, ++ 0x3B, 0x00, ++ 0x3C, 0x46, ++ 0x3D, 0x90, ++ 0x3E, 0x02, ++ 0x3F, 0xF2, ++ 0x41, 0x02, ++ 0x42, 0xC8, ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x5C, ++ 0x46, 0x70, ++ 0x47, 0x46, ++ 0x48, 0x4D, ++ 0x4F, 0x3C, ++ 0x50, 0x32, ++ 0x51, 0x09, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4C, ++ 0x59, 0x1F, ++ 0x5A, 0x55, ++ 0x5B, 0x43, ++ 0x5C, 0x7C, ++ 0x5D, 0x54, ++ 0x5E, 0x0A, ++ 0x5F, 0x01, ++ 0x60, 0x94, ++ 0x61, 0xCE, ++ 0x6B, 0x3A, ++ 0x6C, 0x40, ++ 0x6D, 0x30, ++ 0x6E, 0x4B, ++ 0x6F, 0x60, ++ 0x70, 0x70, ++ 0x71, 0x70, ++ 0x72, 0x70, ++ 0x73, 0x70, ++ 0x74, 0x60, ++ 0x75, 0x60, ++ 0x76, 0x50, ++ 0x77, 0x48, ++ 0x78, 0x3A, ++ 0x79, 0x2E, ++ 0x7A, 0x28, ++ 0x7B, 0x22, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x10, ++ 0x7F, 0x28, ++ 0x80, 0x36, ++ 0x81, 0x44, ++ 0x82, 0x52, ++ 0x83, 0x60, ++ 0x84, 0x6C, ++ 0x85, 0x78, ++ 0x86, 0x8C, ++ 0x87, 0x9E, ++ 0x88, 0xBB, ++ 0x89, 0xD2, ++ 0x8A, 0xE6, ++ 0x13, 0xaF, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++const static u8 gYUV_QVGA[] = { ++ 0x15, 0x20, ++ 0x12, 0x10, ++ 0x04, 0x00, ++ 0x11, 0x81, ++ 0x01, 0x80, ++ 0x02, 0x24, ++ 0x0C, 0x05, ++ 0x0D, 0xC0, ++ 0x0E, 0x01, ++ 0x0F, 0x4F, ++ 0x13, 0x80, //0x82 ++ 0x14, 0x8A, ++ 0x1B, 0x01, ++ 0x24, 0x90, ++ 0x25, 0x80, ++ 0x2A, 0x00, ++ 0x2b, 0x00, ++ 0x27, 0x90, ++ 0x33, 0x08, ++ 0x36, 0xC9, ++ 0x3A, 0x08, ++ 0x3B, 0x00, ++ 0x3C, 0x46, ++ 0x3D, 0x90, ++ 0x3E, 0x02, ++ 0x3F, 0xa4, ++ 0x41, 0x02, ++ 0x42, 0xC8, ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x5C, ++ 0x46, 0x70, ++ 0x47, 0x46, ++ 0x48, 0x4D, ++ 0x4F, 0x3C, ++ 0x50, 0x32, ++ 0x51, 0x09, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4C, ++ 0x59, 0x1F, ++ 0x5A, 0x55, ++ 0x5B, 0x43, ++ 0x5C, 0x7C, ++ 0x5D, 0x54, ++ 0x5E, 0x0A, ++ 0x5F, 0x01, ++ 0x60, 0x94, ++ 0x61, 0xCE, ++ 0x6B, 0x3A, ++ 0x6C, 0x50, ++ 0x6D, 0x60, ++ 0x6E, 0x58, ++ 0x6F, 0x58, ++ 0x70, 0x58, ++ 0x71, 0x50, ++ 0x72, 0x50, ++ 0x73, 0x50, ++ 0x74, 0x50, ++ 0x75, 0x50, ++ 0x76, 0x4c, ++ 0x77, 0x4c, ++ 0x78, 0x45, ++ 0x79, 0x3c, ++ 0x7A, 0x2c, ++ 0x7B, 0x24, ++ 0x7C, 0x05, ++ 0x7D, 0x0b, ++ 0x7E, 0x16, ++ 0x7F, 0x2c, ++ 0x80, 0x37, ++ 0x81, 0x41, ++ 0x82, 0x4b, ++ 0x83, 0x55, ++ 0x84, 0x5f, ++ 0x85, 0x69, ++ 0x86, 0x7C, ++ 0x87, 0x8f, ++ 0x88, 0xB1, ++ 0x89, 0xcf, ++ 0x8A, 0xE5, ++ 0x13, 0xad, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++const static u8 gYUV_CIF[] = { ++ 0x15, 0x20, ++ 0x12, 0x20, ++ 0x04, 0x00, ++ 0x11, 0x87, ++ //0x01 , 0x80, ++ //0x02 , 0x80, ++ 0x0C, 0x05, ++ 0x0D, 0xC0, ++ 0x0E, 0x01, ++ 0x0F, 0x4F, ++ 0x13, 0x80, ++ 0x14, 0x4A, ++ 0x1B, 0x01, ++ 0x24, 0x78, ++ 0x25, 0x70, ++ 0x27, 0x90, ++ 0x33, 0x08, ++ 0x36, 0xC9, ++ 0x3A, 0x08, ++ 0x3B, 0x00, ++ 0x3C, 0x46, ++ 0x3D, 0x90, ++ 0x3E, 0x02, ++ 0x3F, 0xF2, ++ 0x41, 0x02, ++ 0x42, 0xC8, ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x5C, ++ 0x46, 0x70, ++ 0x47, 0x46, ++ 0x48, 0x4D, ++ 0x4F, 0x3C, ++ 0x50, 0x32, ++ 0x51, 0x09, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4C, ++ 0x59, 0x1F, ++ 0x5A, 0x55, ++ 0x5B, 0x43, ++ 0x5C, 0x7C, ++ 0x5D, 0x54, ++ 0x5E, 0x0A, ++ 0x5F, 0x01, ++ 0x60, 0x94, ++ 0x61, 0xCE, ++ 0x6B, 0x3A, ++ 0x6C, 0x40, ++ 0x6D, 0x30, ++ 0x6E, 0x4B, ++ 0x6F, 0x60, ++ 0x70, 0x70, ++ 0x71, 0x70, ++ 0x72, 0x70, ++ 0x73, 0x70, ++ 0x74, 0x60, ++ 0x75, 0x60, ++ 0x76, 0x50, ++ 0x77, 0x48, ++ 0x78, 0x3A, ++ 0x79, 0x2E, ++ 0x7A, 0x28, ++ 0x7B, 0x22, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x10, ++ 0x7F, 0x28, ++ 0x80, 0x36, ++ 0x81, 0x44, ++ 0x82, 0x52, ++ 0x83, 0x60, ++ 0x84, 0x6C, ++ 0x85, 0x78, ++ 0x86, 0x8C, ++ 0x87, 0x9E, ++ 0x88, 0xBB, ++ 0x89, 0xD2, ++ 0x8A, 0xE6, ++ 0x13, 0xaF, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++#if 0 ++#endif ++const static u8 gYUV_QCIF[] = { ++ 0x15, 0x20, ++ 0x12, 0x08, ++ 0x04, 0x00, ++ 0x11, 0x87, ++ //0x01 , 0x80, ++ //0x02 , 0x80, ++ 0x0C, 0x05, ++ 0x0D, 0xC0, ++ 0x0E, 0x01, ++ 0x0F, 0x4F, ++ 0x13, 0x80, ++ 0x14, 0x4A, ++ 0x1B, 0x01, ++ 0x24, 0x78, ++ 0x25, 0x70, ++ 0x27, 0x90, ++ 0x33, 0x08, ++ 0x36, 0xC9, ++ 0x3A, 0x08, ++ 0x3B, 0x00, ++ 0x3C, 0x46, ++ 0x3D, 0x90, ++ 0x3E, 0x02, ++ 0x3F, 0xF2, ++ 0x41, 0x02, ++ 0x42, 0xC8, ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x5C, ++ 0x46, 0x70, ++ 0x47, 0x46, ++ 0x48, 0x4D, ++ 0x4F, 0x3C, ++ 0x50, 0x32, ++ 0x51, 0x09, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4C, ++ 0x59, 0x1F, ++ 0x5A, 0x55, ++ 0x5B, 0x43, ++ 0x5C, 0x7C, ++ 0x5D, 0x54, ++ 0x5E, 0x0A, ++ 0x5F, 0x01, ++ 0x60, 0x94, ++ 0x61, 0xCE, ++ 0x6B, 0x3A, ++ 0x6C, 0x40, ++ 0x6D, 0x30, ++ 0x6E, 0x4B, ++ 0x6F, 0x60, ++ 0x70, 0x70, ++ 0x71, 0x70, ++ 0x72, 0x70, ++ 0x73, 0x70, ++ 0x74, 0x60, ++ 0x75, 0x60, ++ 0x76, 0x50, ++ 0x77, 0x48, ++ 0x78, 0x3A, ++ 0x79, 0x2E, ++ 0x7A, 0x28, ++ 0x7B, 0x22, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x10, ++ 0x7F, 0x28, ++ 0x80, 0x36, ++ 0x81, 0x44, ++ 0x82, 0x52, ++ 0x83, 0x60, ++ 0x84, 0x6C, ++ 0x85, 0x78, ++ 0x86, 0x8C, ++ 0x87, 0x9E, ++ 0x88, 0xBB, ++ 0x89, 0xD2, ++ 0x8A, 0xE6, ++ 0x13, 0xaF, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++const static u8 gYUV_QCIF1[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x08, ++ OV9640_COM1, 0x00, ++ OV9640_CLKRC, 0x01, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x5, //0x04 ++ OV9640_COM4, 0xC0, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x8, ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++ ++const static u8 gYUV_VGA1[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x40, ++ OV9640_COM1, 0x00, ++ OV9640_CLKRC, 0x00, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x5, //0x04 ++ OV9640_COM4, 0x40, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x8, ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_CIF1[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x20, ++ OV9640_COM1, 0x00, ++ OV9640_CLKRC, 0x00, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x5, //0x04 ++ OV9640_COM4, 0x40, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x8, ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_SXGA[] = { ++ OV9640_COM10, 0x20, ++ OV9640_COM7, 0x00, ++ OV9640_COM1, 0x00, ++ OV9640_CLKRC, 0x80, ++ ++ // From OmniVision ++ OV9640_COM8, 0x8D, ++ OV9640_BLUE, 0x80, ++ OV9640_RED, 0x80, ++ OV9640_COM3, 0x1, //0x04 ++ OV9640_COM4, 0x40, ++ OV9640_COM6, 0x4E, //0x4F ++ OV9640_COM9, 0x4A, //0x0A ++ OV9640_PSHFT, 0x1, ++ OV9640_AEW, 0x78, ++ OV9640_AEB, 0x70, ++ OV9640_BBIAS, 0x90, ++ OV9640_CHLF, 0x8, ++ OV9640_VIDO, 0xC9, ++ OV9640_TSLB, 0x0, //0x8 ++ OV9640_COM11, 0x8, ++ OV9640_COM12, 0x46, ++ OV9640_COM13, 0x90, ++ OV9640_COM14, 0x2, ++ OV9640_EDGE, 0xA4, ++ OV9640_COM16, 0x2, ++ OV9640_COM17, 0xC8, ++ OV9640_AWBTH1, 0xF0, ++ OV9640_AWBTH2, 0x10, ++ OV9640_AWBTH3, 0x5C, ++ OV9640_AWBTH4, 0x70, ++ OV9640_AWBTH5, 0x46, ++ OV9640_AWBTH6, 0x4D, ++ OV9640_MTX1, 0x63, ++ OV9640_MTX2, 0x4E, ++ OV9640_MTX3, 0x15, ++ OV9640_MTX4, 0x1D, ++ OV9640_MTX5, 0xBE, ++ OV9640_MTX6, 0xDC, ++ OV9640_MTXS, 0xF, ++ OV9640_AWBC1, 0x1F, ++ OV9640_AWBC2, 0x55, ++ OV9640_AWBC3, 0x43, ++ OV9640_AWBC4, 0x7C, ++ OV9640_AWBC5, 0x54, ++ OV9640_AWBC6, 0xA, ++ OV9640_AWBC7, 0x5, ++ OV9640_AWBC8, 0x14, ++ OV9640_AWBC9, 0xCE, ++ OV9640_DBLV, 0x3A, ++ OV9640_GST0, 0x2, ++ OV9640_GSP0, 0x40, ++ OV9640_GSP1, 0x30, ++ OV9640_GSP2, 0x4B, ++ OV9640_GSP3, 0x60, ++ OV9640_GSP4, 0x70, ++ OV9640_GSP5, 0x70, ++ OV9640_GSP6, 0x70, ++ OV9640_GSP7, 0x70, ++ OV9640_GSP8, 0x60, ++ OV9640_GSP9, 0x60, ++ OV9640_GSP10, 0x50, ++ OV9640_GSP11, 0x48, ++ OV9640_GSP12, 0x3A, ++ OV9640_GSP13, 0x2E, ++ OV9640_GSP14, 0x28, ++ OV9640_GSP15, 0x22, ++ OV9640_GST0, 0x4, ++ OV9640_GST1, 0x7, ++ OV9640_GST2, 0x10, ++ OV9640_GST3, 0x28, ++ OV9640_GST4, 0x36, ++ OV9640_GST5, 0x44, ++ OV9640_GST6, 0x52, ++ OV9640_GST7, 0x60, ++ OV9640_GST8, 0x6C, ++ OV9640_GST9, 0x78, ++ OV9640_GST10, 0x8C, ++ OV9640_GST11, 0x9E, ++ OV9640_GST12, 0xBB, ++ OV9640_GST13, 0xD2, ++ OV9640_GST14, 0xE6, ++ OV9640_COM8, 0x8F, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++ ++const static u8 gRGB_QQVGA[] = { ++ OV9640_COM7, 0x80, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_QVGA[] = { ++ OV9640_COM7, 0x80, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_QCIF[] = { ++ OV9640_COM7, 0x80, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++ ++const static u8 gRGB_VGA[] = { ++ OV9640_COM7, 0x80, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_CIF[] = { ++ OV9640_COM7, 0x80, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_SXGA[] = { ++ OV9640_COM7, 0x80, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++const static u8 gYUV_QVGA_v3[] = { ++ 0x11, 0x83, ++ 0x12, 0x10, ++// 0x13, 0xA8, ++ 0x01, 0x80, ++ 0x02, 0x80, ++ 0x04, 0x00, ++ 0x0C, 0x05, ++ 0x0D, 0xC0, ++ 0x0E, 0x81, ++ 0x0F, 0x4F, ++ 0x14, 0x8A, ++ 0x16, 0x02, ++ 0x1B, 0x01, ++ 0x24, 0x70, ++ 0x25, 0x68, ++ 0x26, 0xD1, ++ 0x27, 0x88, ++ 0x2A, 0x00, ++ 0x2B, 0x00, ++ 0x2c, 0x88, ++ 0x33, 0x02, ++ 0x37, 0x05, ++ 0x38, 0x13, ++ 0x39, 0xF0, ++ 0x3A, 0x0C, ++ 0x3B, 0x01, ++ 0x3C, 0x46, ++ 0x3D, 0x90, ++ 0x3E, 0x02, ++ 0x3F, 0xa4, ++ 0x41, 0x02, ++ 0x42, 0xC8, ++ ++ /* ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x5C, ++ 0x46, 0x70, ++ 0x47, 0x46, ++ 0x48, 0x4d, ++ ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x6C, ++ 0x46, 0x6c, ++ 0x47, 0x44, ++ 0x48, 0x44, ++ */ ++ ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x20, ++ 0x46, 0x20, ++ 0x47, 0x20, ++ 0x48, 0x20, ++ ++ 0x49, 0x03, ++ 0x4f, 0x3c, ++ 0x50, 0x32, ++ 0x51, 0x09, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4c, ++ ++ /* ++ 0x59, 0x1f, ++ 0x5A, 0x55, ++ 0x5B, 0x43, ++ 0x5C, 0x7c, ++ 0x5D, 0x54, ++ 0x5E, 0x0a, ++ 0x5F, 0x01, ++ 0x60, 0x94, ++ 0x61, 0xCE, ++ ++ 0x59, 0x49, ++ 0x5A, 0x94, ++ 0x5B, 0x46, ++ 0x5C, 0x84, ++ 0x5D, 0x5c, ++ 0x5E, 0x08, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x61, 0xCE, ++ */ ++ 0x59, 0x27, ++ 0x5A, 0x72, ++ 0x5B, 0x56, ++ 0x5C, 0x7a, ++ 0x5D, 0x5d, ++ 0x5E, 0x17, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x61, 0xCE, ++ 0x62, 0x78, ++ 0x63, 0x00, ++ 0x64, 0x04, ++ 0x65, 0x50, ++ 0x66, 0x01, ++ 0x69, 0x00, ++ 0x6A, 0x3d, //for QVGA 3e-->3d, ++ 0x6B, 0x3F, ++ /* ++ 0x6C, 0x50, ++ 0x6D, 0x60, ++ 0x6E, 0x58, ++ 0x6F, 0x58, ++ 0x70, 0x58, ++ 0x71, 0x50, ++ 0x72, 0x50, ++ 0x73, 0x50, ++ 0x74, 0x50, ++ 0x75, 0x50, ++ 0x76, 0x4c, ++ 0x77, 0x4c, ++ 0x78, 0x45, ++ 0x79, 0x3c, ++ 0x7A, 0x2c, ++ 0x7B, 0x24, ++ 0x7C, 0x05, ++ 0x7D, 0x0b, ++ 0x7E, 0x16, ++ 0x7F, 0x2c, ++ 0x80, 0x37, ++ 0x81, 0x41, ++ 0x82, 0x4b, ++ 0x83, 0x55, ++ 0x84, 0x5f, ++ 0x85, 0x69, ++ 0x86, 0x7C, ++ 0x87, 0x8f, ++ 0x88, 0xB1, ++ 0x89, 0xcf, ++ 0x8A, 0xE5, ++ */ ++ 0x6C, 0x40, ++ 0x6D, 0x30, ++ 0x6E, 0x4B, ++ 0x6F, 0x60, ++ 0x70, 0x70, ++ 0x71, 0x70, ++ 0x72, 0x70, ++ 0x73, 0x70, ++ 0x74, 0x60, ++ 0x75, 0x60, ++ 0x76, 0x50, ++ 0x77, 0x48, ++ 0x78, 0x3A, ++ 0x79, 0x2E, ++ 0x7A, 0x28, ++ 0x7B, 0x22, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x10, ++ 0x7F, 0x28, ++ 0x80, 0x36, ++ 0x81, 0x44, ++ 0x82, 0x52, ++ 0x83, 0x60, ++ 0x84, 0x6C, ++ 0x85, 0x78, ++ 0x86, 0x8C, ++ 0x87, 0x9E, ++ 0x88, 0xBB, ++ 0x89, 0xD2, ++ 0x8A, 0xE6, ++ /* ++ */ ++ 0x13, 0xAF, ++ OV9640_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gSensorSlaveAddr = 0x30; ++ ++int i2c_init(void) ++{ ++ return i2c_ov9640_init(); ++} ++ ++int i2c_deinit(void) ++{ ++ return i2c_ov9640_cleanup(); ++} ++ ++/*********************************************************************** ++* Private/helper api ++***********************************************************************/ ++static int prv_get_reg_value(u8 * regP, u8 regAddr, u8 * regValueP) ++{ ++ unsigned int index = 0; ++ u8 curReg = 0; ++ while (curReg < OV9640_REGEND) { ++ curReg = regP[index << 1]; ++ if (curReg == regAddr) { ++ *regValueP = regP[(index << 1) + 1]; ++ return 0; ++ } ++ index++; ++ } ++ ++ return -1; ++ ++} ++ ++static int prv_set_reg_value(u8 * regP, u8 regAddr, u8 regValue) ++{ ++ unsigned int index = 0; ++ u8 curReg = 0; ++ ++ while (curReg < OV9640_REGEND) { ++ curReg = regP[index << 1]; ++ if (curReg == regAddr) { ++ regP[(index << 1) + 1] = regValue; ++ return 0; ++ } ++ index++; ++ } ++ ++ return -1; ++ ++} ++ ++/*********************************************************************** ++* Sensor read/write ++***********************************************************************/ ++static int prv_read_sensor_reg(const u8 subAddress, u8 * bufP) ++{ ++ return ov9640_read(subAddress, bufP); ++} ++ ++static int prv_write_sensor_reg(const u8 subAddress, u8 * bufP) ++{ ++ return ov9640_write(subAddress, *bufP); ++} ++ ++static int prv_RMW_sensor_reg(const u8 subAddress, u8 * bufP, u8 andMask, u8 orMask) ++{ ++ int status; ++ status = prv_read_sensor_reg(subAddress, bufP); ++ if (!status) { ++ *bufP &= andMask; ++ *bufP |= orMask; ++ status = prv_write_sensor_reg(subAddress, bufP); ++ } ++ return status; ++} ++ ++int ov9640_read_sensor_reg(const u8 subAddress, u8 * bufP) ++{ ++ return prv_read_sensor_reg(subAddress, bufP); ++} ++ ++int ov9640_write_sensor_reg(const u8 subAddress, u8 * bufP) ++{ ++ return prv_write_sensor_reg(subAddress, bufP); ++} ++ ++int ov9640_set_regs(u8 * regP) ++{ ++ u32 curReg = 0; ++ int status = 0; ++ ++ // The list is a register number followed by the value. ++ while (regP[curReg << 1] < OV9640_REGEND) { ++ status = prv_write_sensor_reg(regP[curReg << 1], ®P[(curReg << 1) + 1]); ++ if (curReg == 0) ++ ov9640_wait(1); ++ ++ curReg++; ++ } ++ return status; ++} ++ ++int ov9640_read_all_regs(u8 * bufP, u32 numRegs) ++{ ++ u32 curReg; ++ ++ for (curReg = 0; curReg < numRegs; curReg++, bufP++) ++ prv_read_sensor_reg(curReg, bufP); ++ ++ return 0; ++} ++ ++/*********************************************************************** ++* Power & Reset ++***********************************************************************/ ++void ov9640_power_down(int powerDown) ++{ ++ // OV9640 PWRDWN, 0 = NORMAL, 1=POWER DOWN ++ //GPDR1 |= GPIO_bit(50); ++ //OV9640 reset CIF_RST, 0 = NORMAL, 1=RESET ++ //GPDR0 |= GPIO_bit(19); ++ if (powerDown == 1) { ++ mdelay(200); ++ ov9640_soft_reset(); ++ ov9640_write(0x39, 0xf4); ++ ov9640_write(0x1e, 0x80); ++ ov9640_write(0x6b, 0x3f); ++ ov9640_write(0x36, 0x49); ++ ov9640_write(0x12, 0x05); ++ mdelay(800); ++ GPSR1 = GPIO_bit(50); ++ } ++ else { ++ ov9640_write(0x39, 0xf0); ++ ov9640_write(0x1e, 0x00); ++ ov9640_write(0x6b, 0x3f); ++ ov9640_write(0x36, 0x49); ++ ov9640_write(0x12, 0x10); ++ GPCR1 = GPIO_bit(50); ++ //GPSR0 = GPIO_bit(19); ++ mdelay(20); ++ //GPCR0 = GPIO_bit(19); ++ } ++ mdelay(100); ++} ++ ++void ov9640_soft_reset(void) ++{ ++ u8 regValue; ++ regValue = 0x80; ++ prv_write_sensor_reg(OV9640_COM7, ®Value); ++ mdelay(10); ++ return; ++} ++ ++void ov9640_reset(void) ++{ ++ // do nothing on Zoar ++ return 0; ++} ++ ++void ov9640_wait(int ms) ++{ ++ mdelay(ms); ++} ++ ++int ov9640_output_stoped() ++{ ++ ov9640 *pov; ++ pov = &g_ov; ++ return pov->stoped; ++} ++ ++void ov9640_set_start() ++{ ++ ov9640 *pov; ++ pov = &g_ov; ++ ++ pov->stoped = 0; ++} ++ ++void ov9640_set_stop(p_camera_context_t cam_ctx) ++{ ++ ov9640 *pov; ++ pov = &g_ov; ++ ++ pov->stoped = 1; ++} ++ ++/*********************************************************************** ++* Settings ++***********************************************************************/ ++int ov9640_version_revision(u8 * pCmRevision, u8 * pSensorRevision) ++{ ++ prv_read_sensor_reg(OV9640_PID, pCmRevision); ++ prv_read_sensor_reg(OV9640_VER, pSensorRevision); ++ return 0; ++} ++ ++void ov9640_set_HSYNC(void) ++{ ++ u8 val; ++ ++ // Makes HREF become HSYNC ++ prv_read_sensor_reg(OV9640_COM10, &val); ++ val |= 0x40; ++ prv_write_sensor_reg(OV9640_COM10, &val); ++} ++ ++void ov9640_auto_function_on(void) ++{ ++ u8 val; ++ DPRINTK("in function %s\n", __FUNCTION__); ++ prv_read_sensor_reg(OV9640_COM8, &val); ++ val |= 0x07; ++ prv_write_sensor_reg(OV9640_COM8, &val); ++} ++ ++void ov9640_auto_function_off(void) ++{ ++ u8 val; ++ DPRINTK("in function %s\n", __FUNCTION__); ++ prv_read_sensor_reg(OV9640_COM8, &val); ++ val &= ~0x07; ++ prv_write_sensor_reg(OV9640_COM8, &val); ++} ++ ++ ++/*********************************************************************** ++* Viewfinder, still ++***********************************************************************/ ++int ov9640_viewfinder_on(void) ++{ ++ u8 com3; ++ ++ prv_read_sensor_reg(OV9640_COM3, &com3); ++ com3 &= ~0x01; ++ prv_write_sensor_reg(OV9640_COM3, &com3); ++ ++ return OV_ERR_NONE; ++} ++ ++ ++int ov9640_viewfinder_off(void) ++{ ++ u8 com3; ++ ++ prv_read_sensor_reg(OV9640_COM3, &com3); ++ com3 |= 0x01; ++ prv_write_sensor_reg(OV9640_COM3, &com3); ++ ++ mdelay(200); ++ return OV_ERR_NONE; ++} ++ ++ ++int ov9640_halt_video_output(void) ++{ ++ u8 com3; ++ ++ // Set the camera to only output 1 frame. ++ prv_read_sensor_reg(OV9640_COM3, &com3); ++ com3 |= 1; ++ prv_write_sensor_reg(OV9640_COM3, &com3); ++ ++ return OV_ERR_NONE; ++} ++ ++int ov9640_resume_to_full_output_mode(void) ++{ ++ u8 mode; ++ ++ // Output still frames continuously ++ // Turn off single capture mode COM3. ++ prv_RMW_sensor_reg(OV9640_COM3, (&mode), ((u8) ~ 1), 0); ++ return OV_ERR_NONE; ++} ++ ++int ov9640_get_single_image(void) ++{ ++ u8 mode; ++ ++ prv_RMW_sensor_reg(OV9640_COM3, &mode, (u8) ~ 1, 1); ++ return OV_ERR_NONE; ++} ++static u8 *ov9640_get_regs_list(u32 captureSizeFormat, u32 colorFormat) ++{ ++ char *formatNameP; ++ u8 *defaultDataP = NULL; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ ++ ++ // Get the default setting. ++ if (colorFormat == OV_FORMAT_YUV_422) { ++ switch (captureSizeFormat) { ++ case OV_SIZE_QQVGA: ++ defaultDataP = gYUV_QQVGA; ++ formatNameP = "QQVGA.422"; ++ break; ++ case OV_SIZE_QQCIF: ++ defaultDataP = gYUV_QQCIF; ++ formatNameP = "QQCIF.422"; ++ break; ++ case OV_SIZE_QVGA: ++ defaultDataP = gYUV_QVGA; ++ formatNameP = "QVGA.422"; ++ //version 3 support: ++ if (pov->version == ((PID_OV_v3 << 8) | (PID_9640_v3))) { ++ DPRINTK("ver 3 sensor!\n"); ++ defaultDataP = gYUV_QVGA_v3; ++ } ++ break; ++ case OV_SIZE_QCIF: ++ defaultDataP = gYUV_QCIF; ++ formatNameP = "QCIF.422"; ++ break; ++ case OV_SIZE_VGA: ++ defaultDataP = gYUV_VGA; ++ formatNameP = "VGA.422"; ++ break; ++ case OV_SIZE_CIF: ++ defaultDataP = gYUV_CIF; ++ formatNameP = "CIF.422"; ++ break; ++ case OV_SIZE_SXGA: ++ defaultDataP = gYUV_SXGA; ++ formatNameP = "SXGA.422"; ++ break; ++ default: ++ return NULL; ++ } ++ } ++ ++ if (colorFormat == OV_FORMAT_RGB_565) { ++ switch (captureSizeFormat) { ++ case OV_SIZE_QQVGA: ++ defaultDataP = gRGB_QQVGA; ++ formatNameP = "QQVGA.RGB"; ++ break; ++ case OV_SIZE_QCIF: ++ defaultDataP = gRGB_QCIF; ++ formatNameP = "QCIF.RGB"; ++ break; ++ ++ case OV_SIZE_QVGA: ++ defaultDataP = gRGB_QVGA; ++ formatNameP = "QVGA.RGB"; ++ break; ++ case OV_SIZE_VGA: ++ defaultDataP = gRGB_VGA; ++ formatNameP = "VGA.RGB"; ++ break; ++ case OV_SIZE_CIF: ++ defaultDataP = gRGB_CIF; ++ formatNameP = "CIF.RGB"; ++ break; ++ case OV_SIZE_SXGA: ++ defaultDataP = gRGB_SXGA; ++ formatNameP = "SXGA.RGB"; ++ break; ++ default: ++ return NULL; ++ } ++ } ++ return defaultDataP; ++} ++ ++/*********************************************************************** ++* Format ++***********************************************************************/ ++int ov9640_set_format(u32 captureSizeFormat, u32 colorFormat) ++{ ++ int status = OV_ERR_PARAMETER; ++ u8 *regsP, regValue; ++ unsigned int index = 0; ++ u8 curReg = 0; ++ static u32 prev_colorFormat = OV_FORMAT_NONE, prev_size = OV_SIZE_NONE; ++ ++ if (prev_colorFormat == colorFormat && captureSizeFormat == prev_size) ++ return 0; ++ if ((captureSizeFormat == OV_SIZE_NONE) && (colorFormat == OV_FORMAT_NONE)) ++ goto no_set; ++ ++ if ((prev_colorFormat == OV_FORMAT_NONE) && (prev_size == OV_SIZE_NONE)) { ++ regsP = (u8 *) ov9640_get_regs_list(captureSizeFormat, colorFormat); ++ // Get the pointer to the basic setting. The pointer must be freed after exiting. ++ ++ if (regsP == NULL) ++ return OV_ERR_PARAMETER; ++ ov9640_soft_reset(); ++ // Blast the entire parameter tree into the part. ++ status = ov9640_set_regs(regsP); ++ } ++ else { ++ status = ov9640_switch_format(captureSizeFormat, colorFormat); ++ } ++ no_set: ++ prev_colorFormat = colorFormat; ++ prev_size = captureSizeFormat; ++ return status; ++} ++ ++void ov9640_save_gains() ++{ ++ u8 gain, aech, aecl, laec, blue, red; ++ ov9640 *pov; ++ u8 regValue; ++ u32 current_size; ++ ++ pov = &g_ov; ++ ++ // Get current size ++ prv_read_sensor_reg(OV9640_COM7, ®Value); ++ switch (regValue) { ++ case 0x00: ++ current_size = OV_SIZE_SXGA; ++ break; ++ case 0x08: ++ prv_read_sensor_reg(OV9640_COM1, ®Value); ++ if (regValue & 0x20) ++ current_size = OV_SIZE_QQCIF; ++ else ++ current_size = OV_SIZE_QCIF; ++ break; ++ case 0x10: ++ prv_read_sensor_reg(OV9640_COM1, ®Value); ++ if (regValue & 0x20) ++ current_size = OV_SIZE_QQVGA; ++ else ++ current_size = OV_SIZE_QVGA; ++ break; ++ case 0x20: ++ current_size = OV_SIZE_CIF; ++ break; ++ case 0x40: ++ current_size = OV_SIZE_VGA; ++ break; ++ default: ++ current_size = OV_SIZE_SXGA; ++ break; ++ } ++ pov->pre_size = current_size; ++ ++ // Get the awb, gain, exposure values ++ prv_read_sensor_reg(OV9640_BLUE, &blue); ++ prv_read_sensor_reg(OV9640_RED, &red); ++ prv_read_sensor_reg(OV9640_GAIN, &gain); ++ gain &= 0x3F; ++ prv_read_sensor_reg(OV9640_AECH, &aech); ++ prv_read_sensor_reg(OV9640_COM1, &aecl); ++ aecl &= 0x3; ++ prv_read_sensor_reg(OV9640_LAEC, &laec); ++ ++ pov->gain = gain; ++ pov->blue_gain = blue; ++ pov->red_gain = red; ++ pov->exp_value = (aech << 2) | aecl; ++ pov->exp_time = laec; ++ ++} ++ ++void ov9640_adjust_gains(u32 prev_size, u32 cur_size) ++{ ++ u8 expMultiple = 1; ++ u8 gain; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ if (prev_size == OV_SIZE_QVGA) { ++ if (cur_size == OV_SIZE_VGA) { ++ if (pov->gain & 0x20) { ++ /* hight gain capture 7.5 fps */ ++ pov->pclock = 0x83; ++ pov->gain = pov->gain & ~0x20; ++ pov->adjusted_exp_value = pov->exp_value * 2; ++ } ++ else { ++ /* capture 15 fps */ ++ pov->pclock = 0x81; ++ pov->adjusted_exp_value = pov->exp_value * 2; ++ } ++ if (pov->night_mode == 1) { ++ //night mode ++ //pov->pclock = 0x87; ++ } ++ else if (pov->night_mode == 2) { //action mode ++ pov->pclock = 0x80; ++ } ++ } ++ else if (cur_size == OV_SIZE_SXGA) { ++ if (pov->gain & 0x20) { ++ /* 8x gain capture 7.5 fps to 4x gain */ ++ pov->pclock = 0x80; ++ pov->gain = pov->gain & ~0x20; ++ pov->adjusted_exp_value = pov->exp_value * 4; ++ } ++ else if (pov->gain & 0x10) { ++ /* 4x gain capture 7.5 fps to 2x gain */ ++ pov->pclock = 0x80; ++ pov->gain = pov->gain & ~0x10; ++ pov->adjusted_exp_value = pov->exp_value * 4; ++ } ++ else { ++ pov->pclock = 0x80; ++ pov->adjusted_exp_value = pov->exp_value * 2; ++ } ++ if (pov->night_mode == 1) { ++ //night mode ++ //pov->pclock = 0x81; ++ } ++ else if (pov->night_mode == 2) { //action mode ++ pov->pclock = 0x80; ++ } ++ } ++ else if (cur_size == OV_SIZE_QVGA) { ++ if (pov->gain & 0x20) { ++ /* hight gain capture 7.5 fps */ ++ pov->pclock = 0x87; ++ pov->gain = pov->gain & ~0x20; ++ pov->adjusted_exp_value = pov->exp_value; ++ } ++ else { ++ /* capture 15 fps */ ++ pov->pclock = 0x83; ++ pov->adjusted_exp_value = pov->exp_value; ++ } ++ if (pov->night_mode == 1) { ++ //night mode ++ //pov->pclock = 0x89; ++ } ++ else if (pov->night_mode == 2) { //action mode ++ pov->pclock = 0x81; ++ } ++ } ++ pov->red_gain=pov->red_gain*9 /10; ++ pov->blue_gain=pov->blue_gain *21 /20; ++ } ++} ++ ++static void ov9640_upload_gains() ++{ ++ ov9640 *pov; ++ u32 expValue; ++ u8 gain, aech, aecl, laec, blue, red; ++ u8 regValue; ++ ++ pov = &g_ov; ++ ++ gain = pov->gain; ++ blue = pov->blue_gain; ++ red = pov->red_gain; ++ expValue = pov->adjusted_exp_value; ++ // Set awb ++ prv_write_sensor_reg(OV9640_BLUE, &blue); ++ prv_write_sensor_reg(OV9640_RED, &red); ++ ++ // Set gain ++ prv_write_sensor_reg(OV9640_GAIN, &gain); ++ // Set exposure ++ prv_read_sensor_reg(OV9640_COM1, ®Value); ++ regValue = (regValue & 0xFC) | (expValue & 0x03); ++ prv_write_sensor_reg(OV9640_COM1, ®Value); ++ expValue >>= 2; ++ if (expValue > 0xFF) ++ regValue = 0xFF; ++ else ++ regValue = expValue; ++ prv_write_sensor_reg(OV9640_AECH, ®Value); ++ prv_write_sensor_reg(OV9640_CLKRC, &pov->pclock); ++} ++ ++int ov9640_switch_format(u32 captureSizeFormat, u32 colorFormat) ++{ ++ int status; ++ u32 index, curReg; ++ u8 *regsP; ++ u8 regValue; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ ++ regsP = (u8 *) ov9640_get_regs_list(captureSizeFormat, colorFormat); ++ // Get the pointer to the basic setting. The pointer must be freed after exiting. ++ ++ if (regsP == NULL) ++ return OV_ERR_PARAMETER; ++ // Apply the delta registers. ++ index = curReg = 0; ++ while ((curReg = gDelta[index]) < OV9640_REGEND) { ++ status = prv_get_reg_value(regsP, curReg, ®Value); ++ if (status == 0) { ++ prv_write_sensor_reg(curReg, ®Value); ++ } ++ else ++ break; ++ index++; ++ } ++ mdelay(50); ++ if (pov->night_mode == 1) { ++ //night mode ++ ov9640_set_night_mode(); ++ } ++ else if (pov->night_mode == 2) { //action mode ++ ov9640_set_action_mode(); ++ } ++ else ++ ov9640_set_auto_mode(); ++ ++ return status; ++} ++ ++int ++ov9640_set_dma_pages(pxa_dma_desc ** pdes, ++ pxa_dma_desc ** des_physical, int num, struct page *array[], int total_size, int dsadr, int flags) ++{ ++ int remain_size, des_transfer_size; ++ int j, target_page_num = num; ++ pxa_dma_desc *cur_des_virtual = *pdes; ++ pxa_dma_desc *cur_des_physical = *des_physical; ++ ++ // in each iteration, generate one dma chain for one frame ++ remain_size = total_size; ++ ++ for (j = 0; j < num; j++) { ++ // set descriptor ++ if (remain_size > PAGE_SIZE) ++ des_transfer_size = PAGE_SIZE; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = dsadr; // FIFO0 physical address ++ cur_des_virtual->dtadr = page_to_bus(array[j]); ++ cur_des_virtual->dcmd = des_transfer_size | flags; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ *pdes = cur_des_virtual; ++ *des_physical = cur_des_physical; ++} ++ ++int ++ov9640_set_dma_page1(pxa_dma_desc ** pdes, ++ pxa_dma_desc ** des_physical, int num, struct page *page1, int total_size, int dsadr, int flags) ++{ ++ int remain_size, des_transfer_size; ++ int j, target_page_num = num; ++ pxa_dma_desc *cur_des_virtual = *pdes; ++ pxa_dma_desc *cur_des_physical = *des_physical; ++ int dump_page; ++ ++ // in each iteration, generate one dma chain for one frame ++ remain_size = total_size; ++ dump_page = page_to_bus(page1); ++ DPRINTK("dump_page=%x", dump_page); ++ ++ for (j = 0; j < num; j++) { ++ // set descriptor ++ if (remain_size > PAGE_SIZE) ++ des_transfer_size = PAGE_SIZE; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = dsadr; // FIFO0 physical address ++ cur_des_virtual->dtadr = dump_page; ++ cur_des_virtual->dcmd = des_transfer_size | flags; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ *pdes = cur_des_virtual; ++ *des_physical = cur_des_physical; ++} ++ ++int ov9640_update_still_dma_chain(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size; ++ unsigned int i, j; ++ ++ int target_page_num; ++ ++ DPRINTK("ov9640_update_still_dma_chain\n"); ++ // clear descriptor pointers ++ cam_ctx->fifo0_descriptors_virtual = cam_ctx->fifo0_descriptors_physical = 0; ++ cam_ctx->fifo1_descriptors_virtual = cam_ctx->fifo1_descriptors_physical = 0; ++ cam_ctx->fifo2_descriptors_virtual = cam_ctx->fifo2_descriptors_physical = 0; ++ ++ // calculate how many descriptors are needed per frame ++ cam_ctx->fifo0_num_descriptors = cam_ctx->pages_per_fifo0; ++ ++ cam_ctx->fifo1_num_descriptors = cam_ctx->pages_per_fifo1; ++ ++ cam_ctx->fifo2_num_descriptors = cam_ctx->pages_per_fifo2; ++ ++ // check if enough memory to generate descriptors ++ DPRINTK("in %s, cam_ctx->block_number =%d\n", __FUNCTION__, cam_ctx->block_number); ++ if ((cam_ctx->fifo0_num_descriptors + cam_ctx->fifo1_num_descriptors + ++ cam_ctx->fifo2_num_descriptors) * cam_ctx->block_number > cam_ctx->dma_descriptors_size) ++ return -1; ++ ++ // generate fifo0 dma chains ++ cam_ctx->fifo0_descriptors_virtual = (unsigned) cam_ctx->dma_descriptors_virtual; ++ cam_ctx->fifo0_descriptors_physical = (unsigned) cam_ctx->dma_descriptors_physical; ++ cur_des_virtual = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_physical; ++ ++ DPRINTK("pages_allocated=%d,fifo0_descriptors_virtual=%x\n", cam_ctx->pages_allocated, cur_des_virtual); ++ ++ for (i = 0; i < 2; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo0_transfer_size; ++ ov9640_set_dma_page1(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo0_num_descriptors, ++ cam_ctx->page_array[cam_ctx-> ++ pages_allocated - ++ 1], remain_size, CIBR0_PHY, DCMD_FLOWSRC | DCMD_BURST32); ++ ++ } ++ DPRINTK("after ov9640_set_dma_page1=%d\n", cam_ctx->pages_allocated); ++ for (i = 0; i < 1; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo0_transfer_size; ++ ++ // assume the blocks are stored consecutively ++ target_page_num = cam_ctx->pages_per_block * i; ++ DPRINTK("target_page_num=%d\n", target_page_num); ++ ov9640_set_dma_pages(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo0_num_descriptors, ++ &cam_ctx->page_array[target_page_num], ++ remain_size, CIBR0_PHY, DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo0_descriptors_physical); ++ last_des_virtual->ddadr |= 0x1; ++ last_des_virtual->dcmd |= DCMD_ENDIRQEN; ++ ++ // generate fifo1 dma chains ++ if (cam_ctx->fifo1_transfer_size) { ++ // record fifo1 descriptors' start address ++ cam_ctx->fifo1_descriptors_virtual = (unsigned) cur_des_virtual; ++ cam_ctx->fifo1_descriptors_physical = (unsigned) cur_des_physical; ++ ++ for (i = 0; i < 2; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo1_transfer_size; ++ ov9640_set_dma_page1(&cur_des_virtual, ++ &cur_des_physical, ++ cam_ctx-> ++ fifo1_num_descriptors, ++ cam_ctx->page_array[cam_ctx-> ++ pages_allocated ++ - 2], ++ remain_size, CIBR1_PHY, DCMD_FLOWSRC | DCMD_BURST32); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ for (i = 0; i < 1; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo1_transfer_size; ++ ++ target_page_num = cam_ctx->pages_per_block * i + cam_ctx->pages_per_fifo0; ++ ov9640_set_dma_pages(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo1_num_descriptors, ++ &cam_ctx->page_array[target_page_num], ++ remain_size, CIBR1_PHY, DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo1_descriptors_physical); ++ last_des_virtual->ddadr |= 0x1; ++ } ++ // generate fifo2 dma chains ++ if (cam_ctx->fifo2_transfer_size) { ++ // record fifo1 descriptors' start address ++ cam_ctx->fifo2_descriptors_virtual = (unsigned) cur_des_virtual; ++ cam_ctx->fifo2_descriptors_physical = (unsigned) cur_des_physical; ++ ++ for (i = 0; i < 2; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo2_transfer_size; ++ ov9640_set_dma_page1(&cur_des_virtual, ++ &cur_des_physical, ++ cam_ctx-> ++ fifo2_num_descriptors, ++ cam_ctx->page_array[cam_ctx-> ++ pages_allocated ++ - 3], ++ remain_size, CIBR2_PHY, DCMD_FLOWSRC | DCMD_BURST32); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ DPRINTK("last target_page_num=%d\n", target_page_num + cam_ctx->fifo2_num_descriptors); ++ for (i = 0; i < 1; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo2_transfer_size; ++ target_page_num = ++ cam_ctx->pages_per_block * i + cam_ctx->pages_per_fifo0 + cam_ctx->pages_per_fifo1; ++ ov9640_set_dma_pages(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo2_num_descriptors, ++ &cam_ctx->page_array[target_page_num], ++ remain_size, CIBR2_PHY, DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ DPRINTK("last target_page_num=%d\n", target_page_num + cam_ctx->fifo2_num_descriptors); ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo2_descriptors_physical); ++ last_des_virtual->ddadr |= 0x1; ++ } ++ return 0; ++} ++ ++int ov9640_prepare_capture(p_camera_context_t cam_ctx, u32 captureSizeFormat, u32 colorFormat) ++{ ++ static int first = 1; ++ int status; ++ //u32 expMultiple, expValue; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ ++ stop_dma_transfer(cam_ctx); ++ ov9640_switch_format(captureSizeFormat, colorFormat); ++ ov9640_adjust_gains(pov->pre_size, captureSizeFormat); ++ ov9640_upload_gains(); ++ if (captureSizeFormat == OV_SIZE_VGA) { ++ //ov9640_update_still_dma_chain(cam_ctx); ++ ov9640_stop_third_des(cam_ctx); ++ /* ++ */ ++ } ++ else if (captureSizeFormat == OV_SIZE_SXGA) { ++ camera_set_int_mask(cam_ctx, 0x3fd | 0x0400); ++ ov9640_update_still_dma_chain(cam_ctx); ++ //ov9640_halt_video_output(); ++ //ci_clear_int_status(0xFFFFFFFF); ++ //DPRINTK("before camera_sleep \n"); ++ //camera_sleep(); ++ } ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ start_dma_transfer(cam_ctx, 1); ++ DPRINTK("after ov9640_prepare_capture \n"); ++} ++ ++int ov9640_set_special_effect(int style) ++{ ++ int ret = 0; ++ u32 index, curReg; ++ u8 *regsP; ++ u8 regValue; ++ ++ DPRINTK("in function %s parameter=%d\n", __FUNCTION__, style); ++ curReg = 0x3a; ++ ov9640_read(0x3a, ®Value); ++ regValue = regValue & 0xf; ++ switch (style) { ++ case V4l_STYLE_NORMAL: ++ DPRINTK("V4l_STYLE_NORMAL\n"); ++ regValue &= 0x7f; ++ //ov9640_write(0x3a, 0x08); ++ ov9640_write(0x3a, regValue); ++ ov9640_write(0x67, 0x80); ++ ov9640_write(0x68, 0x80); ++ break; ++ case V4l_STYLE_BLACK_WHITE: ++ DPRINTK("V4l_STYLE_BLACK_WHITE\n"); ++ regValue |= 0x10; ++ //ov9640_write(0x3a, 0x18); ++ ov9640_write(0x3a, regValue); ++ ov9640_write(0x67, 0x80); ++ ov9640_write(0x68, 0x80); ++ break; ++ case V4l_STYLE_SEPIA: ++ DPRINTK("V4l_STYLE_SEPIA\n"); ++ regValue |= 0x10; ++ //ov9640_write(0x3a, 0x18); ++ ov9640_write(0x3a, regValue); ++ ov9640_write(0x67, 0xa0); ++ ov9640_write(0x68, 0x40); ++ break; ++ //case V4l_STYLE_BULISH: ++ DPRINTK("V4l_STYLE_BULISH\n"); ++ ov9640_write(0x3a, 0x18); ++ ov9640_write(0x67, 0x80); ++ ov9640_write(0x68, 0xc0); ++ break; ++ default: ++ DPRINTK("case default ????????????????????\n"); ++ //ret=OV_ERR_PARAMETER; ++ } ++ return ret; ++ ++} ++ ++int ov9640_set_brightness(int bright) ++{ ++ int ret = 0; ++ const u8 BN[] = { ++ //BN-3 ++ 0x0f, 0x4f, ++ 0x27, 0xe8, ++ 0x28, 0xe0, ++ 0x29, 0xe0, ++ 0x2c, 0xe0, ++ //BN-2 ++ 0x0f, 0x4f, ++ 0x27, 0xc8, ++ 0x28, 0xc0, ++ 0x29, 0xc0, ++ 0x2c, 0xc0, ++ //BN-1 ++ 0x0f, 0x4f, ++ 0x27, 0xa8, ++ 0x28, 0xa0, ++ 0x29, 0xa0, ++ 0x2c, 0xa0, ++ //BN-0 ++ 0x0f, 0x4f, ++ 0x27, 0x88, ++ 0x28, 0x80, ++ 0x29, 0x80, ++ 0x2c, 0x88, ++ //BN+1 ++ 0x0f, 0x4f, ++ 0x27, 0x28, ++ 0x28, 0x20, ++ 0x29, 0x20, ++ 0x2c, 0x20, ++ //BN+2 ++ 0x0f, 0x4f, ++ 0x27, 0x48, ++ 0x28, 0x40, ++ 0x29, 0x40, ++ 0x2c, 0x40, ++ //BN+3 ++ 0x0f, 0x4f, ++ 0x27, 0x68, ++ 0x28, 0x60, ++ 0x29, 0x60, ++ 0x2c, 0x60, ++ }; ++ u8 *regs; ++ int n = 5; ++ int i; ++ ++ DPRINTK("in function %s bright =%d \n", __FUNCTION__, bright); ++ if (bright < -3) ++ bright = -3; ++ if (bright > 3) ++ bright = 3; ++ //bright = -4 .. 4 ++ regs = &BN[(bright + 3) * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ret |= ov9640_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++ ++} ++int ov9640_set_expose_compensation(int bright) ++{ ++ int ret = 0; ++ const u8 EV[] = { ++ //EV-3 ++ 0x24, 0x1c, ++ 0x25, 0x14, ++ //EV-3 ++ 0x24, 0x28, ++ 0x25, 0x20, ++ //EV-2 ++ 0x24, 0x38, ++ 0x25, 0x30, ++ //EV-1 ++ 0x24, 0x50, ++ 0x25, 0x48, ++ //EV-0 ++ 0x24, 0x70, ++ 0x25, 0x68, ++ //EV+1 ++ 0x24, 0x90, ++ 0x25, 0x88, ++ //EV+2 ++ 0x24, 0xb4, ++ 0x25, 0xac, ++ //EV+3 ++ 0x24, 0xc8, ++ 0x25, 0xc0, ++ //EV+4 ++ 0x24, 0xe0, ++ 0x25, 0xd8, ++ }; ++ u8 *regs; ++ int n = 2; ++ int i; ++ ++ DPRINTK("in function %s bright =%d \n", __FUNCTION__, bright); ++ if (bright < -4) ++ bright = -4; ++ if (bright > 4) ++ bright = 4; ++ //bright = -4 .. 4 ++ regs = &EV[(bright + 4) * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ret |= ov9640_write(regs[i], regs[i + 1]); ++// if ( ret) ++// return OV_ERR_PARAMETER; ++ return OV_ERR_NONE; ++ ++} ++ ++int ov9640_set_white_balance(V4l_PIC_WB light) ++{ ++ int ret = 0; ++ const u8 WB_v3[] = { ++ //V4l_WB_DIRECT_SUN ++ 0x13, 0xad, ++ 0x01, 0x80, ++ 0x02, 0x80, ++ 0x45, 0x20, ++ 0x46, 0x20, ++ 0x47, 0x58, ++ 0x48, 0x58, ++ 0x5C, 0x7a, ++ 0x5D, 0x5d, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x13, 0xaf, ++ 0x14, 0x4a, ++ //V4l_WB_INCANDESCENT home mode ++ 0x13, 0xad, ++ 0x01, 0x80, ++ 0x02, 0x80, ++ 0x45, 0x64, ++ 0x46, 0x64, ++ 0x47, 0x20, ++ 0x48, 0x20, ++ 0x5C, 0x7a, ++ 0x5D, 0x48, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x13, 0xaf, ++ 0x14, 0x8a, ++ //V4l_WB_FLUORESCENT office mode ++ 0x13, 0xad, ++ 0x01, 0x80, ++ 0x02, 0x80, ++ 0x45, 0x64, ++ 0x46, 0x64, ++ 0x47, 0x58, ++ 0x48, 0x58, ++ 0x5C, 0x7a, ++ 0x5D, 0x5d, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x13, 0xaf, ++ 0x14, 0x8a, ++ // auto ++ 0x13, 0xaf, ++ 0x01, 0x80, ++ 0x02, 0x80, ++/* ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x6C, ++ 0x46, 0x6c, ++ 0x47, 0x44, ++ 0x48, 0x44, ++ 0x59, 0x49, ++ 0x5A, 0x94, ++ 0x5B, 0x46, ++ 0x5C, 0x84, ++ 0x5D, 0x5c, ++ 0x5E, 0x08, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x61, 0xCE, ++ */ ++ 0x43, 0xF0, ++ 0x44, 0x10, ++ 0x45, 0x20, ++ 0x46, 0x20, ++ 0x47, 0x20, ++ 0x48, 0x20, ++ 0x59, 0x27, ++ 0x5A, 0x72, ++ 0x5B, 0x56, ++ 0x5C, 0x7a, ++ 0x5D, 0x5d, ++ 0x5E, 0x17, ++ 0x5F, 0x00, ++ 0x60, 0x14, ++ 0x61, 0xCE, ++ ++ 0x14, 0x8a, ++ }; ++ u8 *regs; ++ int n = 13; ++ int i = 0; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ ++ DPRINTK("in function %s ,parameter=%d\n", __FUNCTION__, light); ++ switch (light) { ++ case V4l_WB_DIRECT_SUN: ++ //ov9640_set_color_saturation(3); ++ DPRINTK("V4l_WB_DIRECT_SUN\n"); ++ i = 0 * n * 2; ++ //ov9640_set_night_mode(); ++ break; ++ case V4l_WB_INCANDESCENT: ++ //ov9640_set_color_saturation(2); ++ DPRINTK("V4l_WB_INCANDESCENT\n"); ++ i = 1 * n * 2; ++ //ov9640_set_action_mode(); ++ break; ++ case V4l_WB_FLUORESCENT: ++ //ov9640_set_color_saturation(2); ++ DPRINTK("V4l_WB_FLUORESCENT\n"); ++ i = 2 * n * 2; ++ break; ++ default: ++ /* auto */ ++ //ov9640_set_color_saturation(2); ++ DPRINTK("case default ????????????????????\n"); ++ i = 3 * n * 2; ++ n = 19; ++ //ov9640_set_auto_mode(); ++ break; ++ } ++ regs = &WB_v3[i]; ++ if (pov->version == ((PID_OV_v3 << 8) | (PID_9640_v3))) { ++ DPRINTK("ver 3 sensor!\n"); ++ regs = &WB_v3[i]; ++ } ++ ++ for (i = 0; i < n * 2; i += 2) ++ ret |= ov9640_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++} ++ ++int ov9640_set_night_mode() ++{ ++ const u8 NM_v3[] = { ++ //auto ++ 0x11, 0x89, ++ //night mode ++ //action mode ++ }; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ pov->night_mode = 1; ++ //ov9640_write(0x11, 0x89); ++ ov9640_write(0x3b, 0xe1); ++ ++} ++ ++int ov9640_set_action_mode() ++{ ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ pov->night_mode = 2; ++ ov9640_write(0x11, 0x81); ++ ov9640_write(0x3b, 0x01); ++ ov9640_write(0x2d, 0x0); ++ ov9640_write(0x2e, 0x0); ++ ++ ++} ++ ++int ov9640_set_auto_mode() ++{ ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ pov->night_mode = 0; ++ ov9640_write(0x11, 0x83); ++ ov9640_write(0x3b, 0x01); ++ ov9640_write(0x2d, 0x0); ++ ov9640_write(0x2e, 0x0); ++} ++ ++int ov9640_set_light_environment(V4l_PIC_WB light) ++{ ++ int ret = 0; ++ const u8 LE_v3[] = { ++ //OutDoor ++ 0x3b, 0x00, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 60Hz(Default) ++ 0x3b, 0x01, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 50Hz ++ 0x3b, 0x01, ++ 0x2a, 0x10, ++ 0x2b, 0x40, ++ 0x6a, 0x3d, ++ }; ++ const u8 LE_v2[] = { ++ //OutDoor ++ 0x13, 0x8d, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 60Hz(Default) ++ 0x13, 0x8d, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 50Hz ++ 0x13, 0x8d, ++ 0x2a, 0x10, ++ 0x2b, 0x14, ++ 0x6a, 0x3d, ++ }; ++ u8 *regs; ++ int n = 4; ++ int i = 0; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ DPRINTK("in function %s ,parameter=%d\n", __FUNCTION__, light); ++ switch (light) { ++ case 0: ++ i = 0 * n * 2; ++ break; ++ case 60: ++ i = 1 * n * 2; ++ break; ++ case 50: ++ i = 2 * n * 2; ++ break; ++ default: ++ i = 0; ++ break; ++ } ++ ++ regs = &LE_v2[i]; ++ if (pov->version == ((PID_OV_v3 << 8) | (PID_9640_v3))) { ++ DPRINTK("ver 3 sensor!\n"); ++ regs = &LE_v3[i]; ++ } ++ ++ ++ for (i = 0; i < n * 2; i += 2) ++ ret |= ov9640_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++} ++ ++int ov9640_set_color_saturation(int saturation) ++{ ++ const u8 CS[] = { ++ //Saturation: 0.25 ++ 0x4f, 0x14, ++ 0x50, 0x10, ++ 0x51, 0x3, ++ 0x52, 0x6, ++ 0x53, 0x13, ++ 0x54, 0x19, ++ //Saturation 0.5 ++ 0x4f, 0x28, ++ 0x50, 0x22, ++ 0x51, 0x6, ++ 0x52, 0xc, ++ 0x53, 0x26, ++ 0x54, 0x33, ++ //Saturation 0.75 (Default) ++ 0x4f, 0x3c, ++ 0x50, 0x32, ++ 0x51, 0x9, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4c, ++ //Saturation 1.0 ++ 0x4f, 0x50, ++ 0x50, 0x43, ++ 0x51, 0xd, ++ 0x52, 0x19, ++ 0x53, 0x4d, ++ 0x54, 0x66, ++ //Saturation 1.25 ++ 0x4f, 0x64, ++ 0x50, 0x53, ++ 0x51, 0x10, ++ 0x52, 0x1f, ++ 0x53, 0x5f, ++ 0x54, 0x7f, ++ }; ++ u8 *regs; ++ int n = 6; ++ int i; ++ ++ DPRINTK("in function %s ,parameter=%d\n", __FUNCTION__, saturation); ++ if (saturation < 0) ++ saturation = 0; ++ if (saturation > 4) ++ saturation = 4; ++ ++ regs = &CS[saturation * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ov9640_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++ ++} ++ ++int ov9640_set_contrast(int contrast) ++{ ++ const u8 CO[] = { ++ //Low contrast ++ 0x6C, 0x20, ++ 0x6D, 0x50, ++ 0x6E, 0xc0, ++ 0x6F, 0xa8, ++ 0x70, 0x88, ++ 0x71, 0x80, ++ 0x72, 0x78, ++ 0x73, 0x70, ++ 0x74, 0x68, ++ 0x75, 0x58, ++ 0x76, 0x40, ++ 0x77, 0x30, ++ 0x78, 0x28, ++ 0x79, 0x20, ++ 0x7A, 0x1e, ++ 0x7B, 0x18, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x1f, ++ 0x7F, 0x49, ++ 0x80, 0x5a, ++ 0x81, 0x6a, ++ 0x82, 0x79, ++ 0x83, 0x87, ++ 0x84, 0x94, ++ 0x85, 0x9f, ++ 0x86, 0xaf, ++ 0x87, 0xbb, ++ 0x88, 0xcf, ++ 0x89, 0xdf, ++ 0x8A, 0xee, ++ //Middle contrast (default) ++ 0x6C, 0x40, ++ 0x6D, 0x30, ++ 0x6E, 0x4B, ++ 0x6F, 0x60, ++ 0x70, 0x70, ++ 0x71, 0x70, ++ 0x72, 0x70, ++ 0x73, 0x70, ++ 0x74, 0x60, ++ 0x75, 0x60, ++ 0x76, 0x50, ++ 0x77, 0x48, ++ 0x78, 0x3A, ++ 0x79, 0x2E, ++ 0x7A, 0x28, ++ 0x7B, 0x22, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x10, ++ 0x7F, 0x28, ++ 0x80, 0x36, ++ 0x81, 0x44, ++ 0x82, 0x52, ++ 0x83, 0x60, ++ 0x84, 0x6C, ++ 0x85, 0x78, ++ 0x86, 0x8C, ++ 0x87, 0x9E, ++ 0x88, 0xBB, ++ 0x89, 0xD2, ++ 0x8A, 0xE6, ++ //High contrast ++ 0x6c, 0x50, ++ 0x6d, 0x60, ++ 0x6e, 0x58, ++ 0x6f, 0x58, ++ 0x70, 0x58, ++ 0x71, 0x50, ++ 0x72, 0x50, ++ 0x73, 0x50, ++ 0x74, 0x50, ++ 0x75, 0x50, ++ 0x76, 0x4c, ++ 0x77, 0x4c, ++ 0x78, 0x45, ++ 0x79, 0x3c, ++ 0x7a, 0x2c, ++ 0x7b, 0x24, ++ 0x7c, 0x05, ++ 0x7d, 0x0b, ++ 0x7e, 0x16, ++ 0x7f, 0x2c, ++ 0x80, 0x37, ++ 0x81, 0x41, ++ 0x82, 0x4b, ++ 0x83, 0x55, ++ 0x84, 0x5f, ++ 0x85, 0x69, ++ 0x86, 0x7c, ++ 0x87, 0x8f, ++ 0x88, 0xb1, ++ 0x89, 0xcf, ++ 0x8a, 0xe5, ++ }; ++ ++ u8 *regs; ++ int n = 31; ++ int i; ++ ++ DPRINTK("in function %s parameter=%d \n", __FUNCTION__, contrast); ++ if (contrast < 0) ++ contrast = 0; ++ if (contrast > 2) ++ contrast = 2; ++ ++ regs = &CO[contrast * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ov9640_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++ ++} ++ ++int ov9640_set_back_light(int b_light) ++{ ++ const u8 BL[] = { ++ 0x3B, 0, ++ 0x3B, 8, ++ 0x3B, 0x10, ++ 0x3B, 0x18, ++ }; ++ u8 *regs; ++ int n = 1; ++ int i; ++ ++ DPRINTK("in function %s parameter=%d\n", __FUNCTION__, b_light); ++ if (b_light < 0) ++ b_light = 0; ++ if (b_light > 3) ++ b_light = 3; ++ ++ regs = &BL[b_light * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ov9640_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++} ++ ++int ov9640_stop_third_des(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *pdesc, *ptmp; ++ unsigned int phy_addr; ++ int i; ++ ++ // stop the dma transfer on one frame captured ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo0_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo0_num_descriptors * 2; ++ for (i = 0; i < cam_ctx->fifo0_num_descriptors; i++) ++ (ptmp + i)->dtadr = (pdesc + i)->dtadr; ++ ++ pdesc += cam_ctx->fifo0_num_descriptors - 1; ++ pdesc->dcmd = (pdesc->dcmd & DCMD_LENGTH) | DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR; ++ pdesc += cam_ctx->fifo0_num_descriptors; ++ pdesc->dcmd = (pdesc->dcmd & DCMD_LENGTH) | DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR; ++ pdesc += cam_ctx->fifo0_num_descriptors; ++ pdesc->ddadr |= 0x1; ++ ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo1_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo1_num_descriptors * 2; ++ for (i = 0; i < cam_ctx->fifo1_num_descriptors; i++) ++ (ptmp + i)->dtadr = (pdesc + i)->dtadr; ++ pdesc += cam_ctx->fifo1_num_descriptors * 3 - 1; ++ pdesc->ddadr |= 0x1; ++ ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo2_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo2_num_descriptors * 2; ++ for (i = 0; i < cam_ctx->fifo2_num_descriptors; i++) ++ (ptmp + i)->dtadr = (pdesc + i)->dtadr; ++ pdesc += cam_ctx->fifo2_num_descriptors * 3 - 1; ++ pdesc->ddadr |= 0x1; ++} ++ ++int ov9640_stop_third_des1(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *pdesc, *ptmp; ++ unsigned int phy_addr; ++ int i; ++ ++ // stop the dma transfer on one frame captured ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo0_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo0_num_descriptors * 2; ++ /* ++ for (i=0;i<cam_ctx->fifo0_num_descriptors;i++) ++ (ptmp+i)->dtadr = (pdesc+i)->dtadr; ++ */ ++ pdesc += cam_ctx->fifo0_num_descriptors - 1; ++ pdesc->dcmd = DCMD_FLOWSRC | DCMD_BURST32; ++ pdesc += cam_ctx->fifo0_num_descriptors; ++ pdesc->dcmd = DCMD_FLOWSRC | DCMD_BURST32; ++ pdesc += cam_ctx->fifo0_num_descriptors; ++ pdesc->ddadr |= 0x1; ++ ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo1_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo1_num_descriptors * 2; ++ /* ++ for (i=0;i<cam_ctx->fifo1_num_descriptors;i++) ++ (ptmp+i)->dtadr = (pdesc+i)->dtadr; ++ */ ++ pdesc += cam_ctx->fifo1_num_descriptors * 3 - 1; ++ pdesc->ddadr |= 0x1; ++ ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo2_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo2_num_descriptors * 2; ++ /* ++ for (i=0;i<cam_ctx->fifo2_num_descriptors;i++) ++ (ptmp+i)->dtadr = (pdesc+i)->dtadr; ++ */ ++ pdesc += cam_ctx->fifo2_num_descriptors * 3 - 1; ++ pdesc->ddadr |= 0x1; ++} ++ ++int find_window(struct video_window *vw, int *sub_win) ++{ ++ int ret = OV_SIZE_NONE; ++ ++ *sub_win = 1; ++ if (vw->width > 1280 || vw->height > 960 || vw->width < 88 || vw->height < 72) { ++ ret = OV_SIZE_NONE; ++ } ++ else if (vw->width == 1280 && vw->height == 960) { ++ *sub_win = 0; ++ ret = OV_SIZE_SXGA; ++ } ++ else if (vw->width >= 640 && vw->height >= 480) { ++ if (vw->width == 640 && vw->height == 480) ++ *sub_win = 0; ++ ret = OV_SIZE_VGA; ++ } ++ else if (vw->width >= 352 && vw->height >= 288) { ++ if (vw->width == 352 && vw->height == 288) ++ *sub_win = 0; ++ ret = OV_SIZE_CIF; ++ } ++ else if (vw->width >= 320 && vw->height >= 240) { ++ if (vw->width == 320 && vw->height == 240) ++ *sub_win = 0; ++ ret = OV_SIZE_QVGA; ++ } ++ else if (vw->width >= 176 && vw->height >= 144) { ++ if (vw->width == 176 && vw->height == 144) ++ *sub_win = 0; ++ ret = OV_SIZE_QCIF; ++ } ++ else if (vw->width >= 160 && vw->height >= 120) { ++ if (vw->width == 160 && vw->height == 120) ++ *sub_win = 0; ++ ret = OV_SIZE_QQVGA; ++ } ++ else if (vw->width >= 88 && vw->height >= 72) { ++ if (vw->width == 88 && vw->height == 72) ++ *sub_win = 0; ++ ret = OV_SIZE_QQCIF; ++ } ++ DPRINTK("in %s,ret = %d, subwin=%d\n", __FUNCTION__, ret, *sub_win); ++ return ret; ++} ++ ++int ov9640_set_window(struct video_window *vw) ++{ ++ int ret = 0; ++ int x_start, x_end; ++ int y_start, y_end; ++ struct video_window window; ++ int width; ++ int height; ++ int sub_win; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ vw->width = (vw->width + 7) & (~0x7); ++ vw->height = (vw->height + 7) & (~0x7); ++ vw->x = vw->y = 0; ++ x_end = window.width = (vw->width + vw->x); ++ y_end = window.height = (vw->height + vw->y); ++ DPRINTK("in %s, vw-x =%d, vw-y=%d,vw->width=%d,vw->height=%d\n", ++ __FUNCTION__, vw->x, vw->y, vw->width, vw->height); ++ ret = find_window(&window, &sub_win); ++ if (ret <= OV_SIZE_NONE) ++ return -1; ++ ++ ret = ov9640_set_format(ret, OV_FORMAT_YUV_422); ++ if (ret < 0) ++ return -1; ++ ++ /* ++ if ((sub_win == 1) || (vw->x != 0) || (vw->y != 0) || (pov->sub_win != sub_win)) { ++ u8 href = 0; ++ u8 vref = 0; ++ ov9640_read(0x32, &href); ++ href = href & 0xc0 | (vw->width & 0x7) << 3 | (vw->x & 0x7); ++ ov9640_write(0x17, vw->x >> 3); ++ ov9640_write(0x18, x_end >> 3); ++ ov9640_write(0x19, vw->y >> 2); ++ ov9640_write(0x20, y_end >> 2); ++ ov9640_read(0x3, &vref); ++ vref = vref & 0xf0 | (vw->height & 0x3) << 2 | (vw->y & 0x3); ++ pov->sub_win = sub_win; ++ } ++ */ ++ pov->win = *vw; ++ return ret; ++} ++ ++int ov9640_get_window(struct video_window *vw) ++{ ++ ov9640 *pov; ++ pov = &g_ov; ++ *vw = pov->win; ++ return 0; ++} ++ ++struct win_size { ++ int width; ++ int height; ++}; ++int ov9640_set_sensor_size(void *w_size) ++{ ++ struct win_size size; ++ ov9640 *pov; ++ pov = &g_ov; ++ if (copy_from_user(&size, w_size, sizeof(struct win_size))) { ++ return -EFAULT; ++ } ++//make it in an even of multiple of 8 ++ size.height = (size.height + 7) / 8 * 8; ++ pov->sensor_width = size.width; ++ pov->sensor_height = size.height; ++ return 0; ++} ++ ++int ov9640_get_sensor_size(void *w_size) ++{ ++} ++int ov9640_set_output_size(void *w_size) ++{ ++ struct win_size size; ++ ov9640 *pov; ++ pov = &g_ov; ++ if (copy_from_user(&size, w_size, sizeof(struct win_size))) { ++ return -EFAULT; ++ } ++//make it in an even of multiple of 8 ++ size.height = (size.height + 7) / 8 * 8; ++ pov->sensor_width = size.width; ++ pov->sensor_height = size.height; ++ return 0; ++} ++ ++int ov9640_get_output_size(void *w_size) ++{ ++} ++int test_divider(int res, int fps) ++{ ++ int max_hz = 48 * 1000000; ++ int div = 1; ++ int i; ++ int ov_fps[5] = { 3, 7, 15, 30, 60 }; ++ u32 value = 320 * 240; ++ /* ++ switch (prevSize) { ++ case OV_SIZE_QQCIF: ++ value = 88 * 72; ++ break; ++ case OV_SIZE_QQVGA: ++ value = 176 * 144; ++ break; ++ case OV_SIZE_QCIF: ++ value = 160 * 120; ++ break; ++ case OV_SIZE_QVGA: ++ value = 320 * 240; ++ break; ++ case OV_SIZE_CIF: ++ value = 352 * 288; ++ break; ++ case OV_SIZE_VGA: ++ value = 640 * 480; ++ break; ++ case OV_SIZE_SXGA: ++ value = 1280 * 960; ++ break; ++ } ++ ++ while (max_hz / res / div > fps) ++ div++; ++ if (div > 64) ++ div = 64; ++ return (div - 1); ++ ++ for (i =0;i<5;i++) ++ if ( fps < ov_fps[i] ) ++ continue; ++ */ ++ if (fps == 0) ++ return 0; ++ if (fps > 60) ++ fps = 60; ++ return (div = 60 / fps - 1); ++} ++ ++int ov9640_set_fps(int fps, int min_fps) ++{ ++ u32 res = 0; ++ u8 value; ++ if (fps < 0) { ++ DPRINTK("in %s fps = %d divider value =%d\n", __FUNCTION__, fps, res); ++ fps = 15; ++ } ++ res = test_divider(0, fps); ++ ov9640_read(OV9640_CLKRC, &value); ++ value = (value & 0xc0) | res; ++ ov9640_write(OV9640_CLKRC, value); ++ DPRINTK("in %s fps = %d divider value =%d\n", __FUNCTION__, fps, res); ++ /* ++ ov9640_set_night_mode(); ++ ov9640_set_action_mode(); ++ ov9640_set_auto_mode(); ++ */ ++ return 0; ++} ++ ++#ifndef MIN ++#define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++#endif ++#ifndef MAX ++#define MAX(a, b) (((a) > (b)) ? (a) : (b)) ++#endif ++ ++void write_balance() ++{ ++ u8 yav, uav, vav; ++ static int bg = 0x80; ++ static int rg = 0x24; ++ int awb_mode; ++ ov9640 *pov; ++ ++ pov = &g_ov; ++ ++ if (pov->version == ((PID_OV_v3 << 8) | (PID_9640_v3))) { ++ DPRINTK("ver 3 sensor!\n"); ++ return; ++ } ++ ++ ++ prv_read_sensor_reg(0x5, &vav); ++ prv_read_sensor_reg(0x6, &yav); ++ prv_read_sensor_reg(0x8, &uav); ++ DPRINTK("in %s, v =%x ,y =%x,u =%x\n)", __FUNCTION__, vav, yav, uav); ++ if (yav >= 0x20 && yav <= 0xc0) { ++ if (vav < 50) ++ rg = MIN(255, rg + 40); ++ else if (vav < 80) ++ rg = MIN(255, rg + 20); ++ else if (vav < 100) ++ rg = MIN(255, rg + 5); ++ else if (vav < 120) ++ rg = MIN(255, rg + 1); ++ else if (vav > 206) ++ rg = MAX(0, rg - 40); ++ else if (vav > 180) ++ rg = MAX(0, rg - 20); ++ else if (vav > 156) ++ rg = MAX(0, rg - 5); ++ else if (vav > 136) ++ rg = MAX(0, rg - 1); ++ ++ if (uav < 50) ++ bg = MIN(255, bg + 40); ++ else if (uav < 80) ++ bg = MIN(255, bg + 20); ++ else if (uav < 100) ++ bg = MIN(255, bg + 5); ++ else if (uav < 120) ++ bg = MIN(255, bg + 1); ++ else if (uav > 206) ++ bg = MAX(0, bg - 40); ++ else if (uav > 180) ++ bg = MAX(0, bg - 20); ++ else if (uav > 156) ++ bg = MAX(0, bg - 5); ++ else if (uav > 136) ++ bg = MAX(0, bg - 1); ++ } ++ ov9640_write(0x01, bg); ++ ov9640_write(0x2, rg); ++} +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9640_hw.h linux-2.6.16/drivers/media/video/ov9640_hw.h +--- linux-2.6.16.orig/drivers/media/video/ov9640_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9640_hw.h 2006-06-03 11:14:56.446308112 +0200 +@@ -0,0 +1,259 @@ ++/* ++ ov9640_hw - Omnivision 9640 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#ifndef _OV_9640_HW_H_ ++#define _OV_9640_HW_H_ ++ ++/*********************************************************************** ++ * ++ * Constants & Structures ++ * ++ ***********************************************************************/ ++// Revision constants ++#define PID_OV 0x96 ++#define PID_9640 0x48 ++ ++#define PID_OV_v3 0x96 ++#define PID_9640_v3 0x49 ++ ++// Return codes ++#define OV_ERR_NONE 0x00 ++#define OV_ERR_TIMEOUT -1 ++#define OV_ERR_PARAMETER -2 ++#define OV_COMM_ERR -3 ++ ++#define CIBR0_PHY (0x50000000 + 0x28) ++#define CIBR1_PHY (0x50000000 + 0x30) ++#define CIBR2_PHY (0x50000000 + 0x38) ++#define DEBUG 1 ++#define DPRINTK(fmt,args...) do { if (DEBUG) printk("in function %s "fmt,__FUNCTION__,##args);} while(0) ++ ++// Output Size & Format ++/* ++#define OV_SIZE_NONE 0 ++#define OV_SIZE_QQVGA 0x01 ++#define OV_SIZE_QVGA ( OV_SIZE_QQVGA << 1 ) ++#define OV_SIZE_VGA ( OV_SIZE_QQVGA << 2 ) ++#define OV_SIZE_SXGA ( OV_SIZE_QQVGA << 3 ) ++#define OV_SIZE_QQCIF 0x10 ++#define OV_SIZE_QCIF ( OV_SIZE_QQCIF << 1 ) ++#define OV_SIZE_CIF ( OV_SIZE_QQCIF << 2 ) ++#define OV_FORMAT_NONE 0 ++#define OV_FORMAT_YUV_422 1 ++#define OV_FORMAT_RGB_565 2 ++*/ ++enum OV_SIZE { ++ OV_SIZE_NONE=0 , ++ OV_SIZE_QQVGA , ++ OV_SIZE_QVGA , ++ OV_SIZE_VGA , ++ OV_SIZE_SXGA , ++ OV_SIZE_QQCIF , ++ OV_SIZE_QCIF , ++ OV_SIZE_CIF ++}; ++enum OV_FORMAT { ++ OV_FORMAT_NONE=0 , ++ OV_FORMAT_YUV_422, ++ OV_FORMAT_RGB_565, ++}; ++ ++// Camera Mode ++#define VIEWFINDER_MODE 0x10 ++#define STILLFRAME_MODE 0x20 ++ ++// Others ++#define OV9640_TIMEOUT 1000 // ms to timeout. ++ ++// OV9640 Register Definitions ++#define OV9640_GAIN 0x0000 ++#define OV9640_BLUE 0x0001 ++#define OV9640_RED 0x0002 ++#define OV9640_VREF 0x0003 ++#define OV9640_COM1 0x0004 ++#define OV9640_BAVE 0x0005 // U/B Average Level ++#define OV9640_GEAVE 0x0006 // Y/Ge Average Level ++#define OV9640_GOAVE 0x0007 // Y/Go Average Level ++#define OV9640_RAVE 0x0008 // V/R Average level ++#define OV9640_COM2 0x0009 // Common control 2 ++#define OV9640_PID 0x000A // Product ID ++#define OV9640_VER 0x000B // Version ++#define OV9640_COM3 0x000C ++#define OV9640_COM4 0x000D ++#define OV9640_COM5 0x000E ++#define OV9640_COM6 0x000F ++#define OV9640_AECH 0x0010 ++#define OV9640_CLKRC 0x0011 ++#define OV9640_COM7 0x0012 ++#define OV9640_COM8 0x0013 ++#define OV9640_COM9 0x0014 ++#define OV9640_COM10 0x0015 ++#define OV9640_WS 0x0016 ++#define OV9640_HSTART 0x0017 ++#define OV9640_HSTOP 0x0018 ++#define OV9640_VSTRT 0x0019 ++#define OV9640_VSTOP 0x001A ++#define OV9640_PSHFT 0x001B ++#define OV9640_MIDH 0x001C ++#define OV9640_MIDL 0x001D ++#define OV9640_DLY 0x001E ++#define OV9640_LAEC 0x001F ++#define OV9640_BOS 0x0020 ++#define OV9640_GBOS 0x0021 ++#define OV9640_GROS 0x0022 ++#define OV9640_ROS 0x0023 ++#define OV9640_AEW 0x0024 ++#define OV9640_AEB 0x0025 ++#define OV9640_VPT 0x0026 ++#define OV9640_BBIAS 0x0027 ++#define OV9640_GbBIAS 0x0028 ++#define OV9640_GrBIAS 0x0029 ++#define OV9640_EXHCH 0x002A ++#define OV9640_EXHCL 0x002B ++#define OV9640_RBIAS 0x002C ++#define OV9640_ADVFL 0x002D ++#define OV9640_ADVFH 0x002E ++#define OV9640_YAVE 0x002F ++#define OV9640_HSYST 0x0030 ++#define OV9640_HSYEN 0x0031 ++#define OV9640_HREF 0x0032 ++#define OV9640_CHLF 0x0033 ++#define OV9640_ARBLM 0x0034 ++#define OV9640_VRHL 0x0035 ++#define OV9640_VIDO 0x0036 ++#define OV9640_ADC 0x0037 ++#define OV9640_ACOM 0x0038 ++#define OV9640_OFON 0x0039 ++#define OV9640_TSLB 0x003A ++#define OV9640_COM11 0x003B ++#define OV9640_COM12 0x003C ++#define OV9640_COM13 0x003D ++#define OV9640_COM14 0x003E ++#define OV9640_EDGE 0x003F ++#define OV9640_COM15 0x0040 ++#define OV9640_COM16 0x0041 ++#define OV9640_COM17 0x0042 ++#define OV9640_AWBTH1 0x0043 ++#define OV9640_AWBTH2 0x0044 ++#define OV9640_AWBTH3 0x0045 ++#define OV9640_AWBTH4 0x0046 ++#define OV9640_AWBTH5 0x0047 ++#define OV9640_AWBTH6 0x0048 ++#define OV9640_MTX1 0x004F ++#define OV9640_MTX2 0x0050 ++#define OV9640_MTX3 0x0051 ++#define OV9640_MTX4 0x0052 ++#define OV9640_MTX5 0x0053 ++#define OV9640_MTX6 0x0054 ++#define OV9640_MTX7 0x0055 ++#define OV9640_MTX8 0x0056 ++#define OV9640_MTX9 0x0057 ++#define OV9640_MTXS 0x0058 ++#define OV9640_AWBC1 0x0059 ++#define OV9640_AWBC2 0x005A ++#define OV9640_AWBC3 0x005B ++#define OV9640_AWBC4 0x005C ++#define OV9640_AWBC5 0x005D ++#define OV9640_AWBC6 0x005E ++#define OV9640_AWBC7 0x005F ++#define OV9640_AWBC8 0x0060 ++#define OV9640_AWBC9 0x0061 ++#define OV9640_LCC1 0x0062 ++#define OV9640_LCC2 0x0063 ++#define OV9640_LCC3 0x0064 ++#define OV9640_LCC4 0x0065 ++#define OV9640_LCC5 0x0066 ++#define OV9640_MANU 0x0067 ++#define OV9640_MANV 0x0068 ++#define OV9640_HV 0x0069 ++#define OV9640_MBD 0x006A ++#define OV9640_DBLV 0x006B ++#define OV9640_GSP0 0x006C ++#define OV9640_GSP1 0x006D ++#define OV9640_GSP2 0x006E ++#define OV9640_GSP3 0x006F ++#define OV9640_GSP4 0x0070 ++#define OV9640_GSP5 0x0071 ++#define OV9640_GSP6 0x0072 ++#define OV9640_GSP7 0x0073 ++#define OV9640_GSP8 0x0074 ++#define OV9640_GSP9 0x0075 ++#define OV9640_GSP10 0x0076 ++#define OV9640_GSP11 0x0077 ++#define OV9640_GSP12 0x0078 ++#define OV9640_GSP13 0x0079 ++#define OV9640_GSP14 0x007A ++#define OV9640_GSP15 0x007B ++#define OV9640_GST0 0x007C ++#define OV9640_GST1 0x007D ++#define OV9640_GST2 0x007E ++#define OV9640_GST3 0x007F ++#define OV9640_GST4 0x0080 ++#define OV9640_GST5 0x0081 ++#define OV9640_GST6 0x0082 ++#define OV9640_GST7 0x0083 ++#define OV9640_GST8 0x0084 ++#define OV9640_GST9 0x0085 ++#define OV9640_GST10 0x0086 ++#define OV9640_GST11 0x0087 ++#define OV9640_GST12 0x0088 ++#define OV9640_GST13 0x0089 ++#define OV9640_GST14 0x008A ++ ++// End of OV9640 register ++#define OV9640_REGEND ( OV9640_GST14 + 1 ) ++ ++ ++ ++/*********************************************************************** ++ * ++ * Function Prototype ++ * ++ ***********************************************************************/ ++int ov9640_set_regs( u8 *regP ); ++int ov9640_read_all_regs( u8 *bufP, u32 numRegs ); ++ ++void ov9640_power_down( int powerDown ); ++void ov9640_reset( void ); ++void ov9640_wait( int ms ); ++ ++int ov9640_version_revision(u8 * pCmRevision, u8 *pSensorRevision); ++void ov9640_set_HSYNC(void); ++void ov9640_auto_fucntion_on(void); ++void ov9640_auto_fucntion_off(void); ++ ++int ov9640_viewfinder_on(void); ++int ov9640_viewfinder_off(void); ++int ov9640_halt_video_output(void); ++int ov9640_resume_to_full_output_mode(void); ++int ov9640_get_single_image(void); ++ ++int ov9640_set_format( u32 captureSizeFormat, u32 colorFormat ); ++ ++int i2c_init(void); ++int i2c_deinit(void); ++ ++extern int i2c_ov9640_init(void); ++extern int i2c_ov9640_cleanup(void); ++extern int ov9640_read(u8 addr, u8 *pvalue); ++extern int ov9640_write(u8 addr, u8 value); ++ ++ ++#endif +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9650.c linux-2.6.16/drivers/media/video/ov9650.c +--- linux-2.6.16.orig/drivers/media/video/ov9650.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9650.c 2006-06-03 11:14:56.447307960 +0200 +@@ -0,0 +1,576 @@ ++/* ++ ov9650 - Omnivision 9650 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++ ++#include <linux/types.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/ctype.h> ++ ++#include <asm/irq.h> ++#include <asm/hardware.h> ++ ++#include "camera.h" ++#include "ov9650.h" ++#include "ov9650_hw.h" ++ ++ ++#define MAX_WIDTH 1280 ++#define MAX_HEIGHT 1024 ++#define MIN_WIDTH 88 ++#define MIN_HEIGHT 72 ++ ++#define MAX_BPP 16 ++#define WIDTH_DEFT 320 ++#define HEIGHT_DEFT 240 ++#define FRAMERATE_DEFT 0xf ++ ++/* ++ * It is required to have at least 3 frames in buffer ++ * in current implementation ++ */ ++#define FRAMES_IN_BUFFER 3 ++#define MIN_FRAMES_IN_BUFFER 3 ++#define MAX_FRAME_SIZE (MAX_WIDTH * MAX_HEIGHT * (MAX_BPP >> 3)) ++#define BUF_SIZE_DEFT (MAX_FRAME_SIZE ) ++#define SINGLE_DESC_TRANS_MAX PAGE_SIZE ++#define MAX_DESC_NUM ((MAX_FRAME_SIZE / SINGLE_DESC_TRANS_MAX + 1) *\ ++ MIN_FRAMES_IN_BUFFER) ++ ++#define MAX_BLOCK_NUM 20 ++extern ov9650 g_ov9650; ++extern void set_still_image_ready(int); ++ ++camera_function_t camera_ov9650_func = { ++ .init = camera_func_ov9650_init, ++ .deinit = camera_func_ov9650_deinit, ++ .set_capture_format = camera_func_ov9650_set_capture_format, ++ .start_capture = camera_func_ov9650_start_capture, ++ .stop_capture = camera_func_ov9650_stop_capture, ++ .command = camera_func_ov9650_command, ++ .pm_management = camera_func_ov9650_pm, ++}; ++ ++/*********************************************************************** ++ * ++ * OV9650 Functions ++ * ++ ***********************************************************************/ ++static void ov9650_gpio_init(void) ++{ ++ ++ set_GPIO_mode(27 | GPIO_ALT_FN_3_IN); /* CIF_DD[0] */ ++ set_GPIO_mode(114 | GPIO_ALT_FN_1_IN); /* CIF_DD[1] */ ++ set_GPIO_mode(51 | GPIO_ALT_FN_1_IN); /* CIF_DD[2] */ ++ set_GPIO_mode(115 | GPIO_ALT_FN_2_IN); /* CIF_DD[3] */ ++ set_GPIO_mode(95 | GPIO_ALT_FN_2_IN); /* CIF_DD[4] */ ++ set_GPIO_mode(94 | GPIO_ALT_FN_2_IN); /* CIF_DD[5] */ ++ set_GPIO_mode(17 | GPIO_ALT_FN_2_IN); /* CIF_DD[6] */ ++ set_GPIO_mode(108 | GPIO_ALT_FN_1_IN); /* CIF_DD[7] */ ++ set_GPIO_mode(23 | GPIO_ALT_FN_1_OUT); /* CIF_MCLK */ ++ set_GPIO_mode(54 | GPIO_ALT_FN_3_IN); /* CIF_PCLK */ ++ set_GPIO_mode(85 | GPIO_ALT_FN_3_IN); /* CIF_LV */ ++ set_GPIO_mode(84 | GPIO_ALT_FN_3_IN); /* CIF_FV */ ++ set_GPIO_mode(50 | GPIO_OUT); /*CIF_PD */ ++ set_GPIO_mode(19 | GPIO_OUT); /*CIF_RST */ ++ ++ ++ return; ++ ++} ++ ++void ov9650_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz) ++{ ++ unsigned int ciclk = 0, value, div, cccr_l; ++ ++ // determine the LCLK frequency programmed into the CCCR. ++ cccr_l = (CCCR & 0x0000001F); ++ ++ if (cccr_l < 8) // L = [2 - 7] ++ ciclk = (13 * cccr_l) * 100; ++ else if (cccr_l < 17) // L = [8 - 16] ++ ciclk = ((13 * cccr_l) * 100) >> 1; ++ else if (cccr_l < 32) // L = [17 - 31] ++ ciclk = ((13 * cccr_l) * 100) >> 2; ++ DPRINTK(KERN_WARNING "the mclk_khz = %d \n", mclk_khz); ++ ++ // want a divisor that gives us a clock rate as close to, but not more than the given mclk. ++ div = (ciclk + mclk_khz) / (2 * mclk_khz) - 1; ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK << CI_CICR4_DIV_SHIFT); ++ value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0; ++ value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0; ++ value |= div << CI_CICR4_DIV_SHIFT; ++ CICR4 = value; ++ return; ++} ++ ++int camera_func_ov9650_init(p_camera_context_t cam_ctx) ++{ ++ u8 cm_rev, cm_pid; ++ int status; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ memset(pov, 0, sizeof(ov9650)); ++ ++ pov->pre_size = OV_SIZE_NONE; ++ pov->win.width = cam_ctx->capture_width; ++ pov->win.height = cam_ctx->capture_height; ++ // init context status ++ cam_ctx->dma_channels[0] = 0xFF; ++ cam_ctx->dma_channels[1] = 0xFF; ++ cam_ctx->dma_channels[2] = 0xFF; ++ ++ cam_ctx->capture_width = WIDTH_DEFT; ++ cam_ctx->capture_height = HEIGHT_DEFT; ++ ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ ++ cam_ctx->frame_rate = cam_ctx->fps = FRAMERATE_DEFT; ++ ++ cam_ctx->mini_fps = FRAMERATE_DEFT - 2; ++ ++ cam_ctx->buf_size = BUF_SIZE_DEFT; ++ cam_ctx->dma_descriptors_size = MAX_DESC_NUM; ++ DPRINTK(KERN_WARNING "dma_descriptors_size =%d,cam_ctx->buf_size=%d\n", cam_ctx->dma_descriptors_size, ++ cam_ctx->buf_size); ++ cam_ctx->vc.maxwidth = MAX_WIDTH; ++ cam_ctx->vc.maxheight = MAX_HEIGHT; ++ cam_ctx->vc.minwidth = MIN_WIDTH; ++ cam_ctx->vc.minheight = MIN_HEIGHT; ++ //DPRINTK( KERN_WARNING" before ov9650_gpio_init\n"); ++ ov9650_gpio_init(); ++ ci_init(); ++ wmb(); ++ // Configure CI according to OV9650's hardware ++ // master parallel with 8 data pins ++ ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8); ++ // enable pixel clock(sensor will provide pclock) and master clock = 26MHZ ++ //ci_set_clock(cam_ctx->clk_reg_base, 1, 1, 24); ++ ov9650_set_clock(cam_ctx->clk_reg_base, 1, 1, 2400); ++ pov->mclock = 24; ++ ++ // data sample on rising and h,vsync active high ++ ci_set_polarity(0, 0, 0); ++ ++ // fifo control ++ // CISetFIFO(cam_ctx->ci_reg_base, 4000, XLLP_CI_FIFO_THL_32, XLLP_TRUE, XLLP_TRUE); ++ ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); ++ ++ // OV9650 Power on sequence ++ // Take out of Power down mode, PWRDWN=1, NORMAL=0 ++ // Assert Reset ++ // Delay ++ // Remove reset ++ // Delay ++ ov9650_power_down(0); ++ mdelay(1); ++ ++ // init I2C. ++ status = i2c_ov9650_init(); ++ if (status) ++ return status; ++ ++ // 2 Turn on M_CLK using xx MHz and wait for 150 ms. ?? ++ ci_enable(1); ++ mdelay(1); ++ ++ // read out version ++ { ++ cm_pid = cm_rev = 0; ++ status = ov9650_version_revision(&cm_pid, &cm_rev); ++ ++ // Check to make sure we are working with an OV9650 ++ if (cm_pid == PID_OV) { ++ int ver = (PID_OV << 8) | cm_rev; ++ pov->version = ver; ++ } ++ else { ++ return -1; ++ } ++ printk("in fun camera_func_ov9650_init version=%x\n", pov->version); ++ } ++ ++ cam_ctx->sensor_type = CAMERA_TYPE_OV9650; ++ ++ ov9650_soft_reset(); ++ ++ // turn sensor output off ++ ov9650_viewfinder_off(); ++ ++ return 0; ++} ++ ++int camera_func_ov9650_deinit(p_camera_context_t cam_ctx) ++{ ++ //init the prev_xx value. ++ ov9650_set_format(OV_SIZE_NONE, OV_FORMAT_NONE); ++ // power off the external module ++ ov9650_power_down(1); ++ ++ return 0; ++} ++ ++static int get_ov_format(p_camera_context_t cam_ctx, u32 * size_format, u32 * color_format) ++{ ++ u32 ovSizeFormat, ovFormat; ++ ++ // Set the current mode ++ switch (cam_ctx->capture_input_format) { ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ ovFormat = OV_FORMAT_YUV_422; ++ printk("in get_ov_format ovFormat = OV_FORMAT_YUV_422\n"); ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ ovFormat = OV_FORMAT_RGB_565; ++ break; ++ default: ++ printk(KERN_INFO "The Format doesn't support by OV9650 Sensor \n"); ++ return -1; ++ } ++ if (cam_ctx->capture_width == 88 && cam_ctx->capture_height == 72) ++ ovSizeFormat = OV_SIZE_QQCIF; ++ else if (cam_ctx->capture_width == 160 && cam_ctx->capture_height == 120) ++ ovSizeFormat = OV_SIZE_QQVGA; ++ else if (cam_ctx->capture_width == 176 && cam_ctx->capture_height == 144) ++ ovSizeFormat = OV_SIZE_QCIF; ++ else if (cam_ctx->capture_width == 320 && cam_ctx->capture_height == 240) ++ ovSizeFormat = OV_SIZE_QVGA; ++ else if (cam_ctx->capture_width == 352 && cam_ctx->capture_height == 288) ++ ovSizeFormat = OV_SIZE_CIF; ++ else if (cam_ctx->capture_width == 640 && cam_ctx->capture_height == 480) ++ ovSizeFormat = OV_SIZE_VGA; ++ else if (cam_ctx->capture_width == 1280 && cam_ctx->capture_height == 960) ++ ovSizeFormat = OV_SIZE_SXGA; ++ else if (cam_ctx->capture_width == 1280 && cam_ctx->capture_height == 1024) ++ ovSizeFormat = OV_SIZE_SXGA; ++ else { ++ return -1; ++ } ++ if (ovSizeFormat == OV_SIZE_QVGA) ++ printk("ovSizeFormat =OV_SIZE_QVGA \n"); ++ *size_format = ovSizeFormat; ++ *color_format = ovFormat; ++ return 0; ++} ++ ++int camera_func_ov9650_set_capture_format(p_camera_context_t cam_ctx) ++{ ++ CI_MP_TIMING timing; ++ int status = -1; ++ u32 ovSizeFormat, ovFormat; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ ++ status = get_ov_format(cam_ctx, &ovSizeFormat, &ovFormat); ++ if (status) ++ return -1; ++ ++ status = ov9650_set_format(ovSizeFormat, ovFormat); ++ if (status) ++ return -1; ++ ++ // set capture width/height and timing ++ //timing.BFW = pov->win.x; ++ //timing.BLW = pov->win.y; ++ timing.BFW = 0; ++ timing.BLW = 0; ++ //ci_configure_mp(pov->win.width - 1, pov->win.height - 1, &timing); ++ ++ return status; ++} ++ ++#define COPY_BUFFERS(pdes, p_page, size) \ ++do { \ ++ unsigned int len; \ ++ unsigned int remain_size = size; \ ++ while (remain_size > 0) { \ ++ if (remain_size > PAGE_SIZE) \ ++ len = PAGE_SIZE; \ ++ else \ ++ len = remain_size; \ ++ if (memcpy(page_address(*pdes), page_address(*p_page), len)) \ ++ return -EFAULT; \ ++ remain_size -= len; \ ++ pdes ++;\ ++ p_page++; \ ++ } \ ++} while (0); ++ ++int camera_func_ov9650_start_capture(p_camera_context_t cam_ctx, unsigned int frames) ++{ ++ int status = -1; ++ u32 ovSizeFormat, ovFormat; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ ++ ci_disable(1); ++ mdelay(1); ++ ci_enable(1); ++ // clear ci fifo ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ ++ camera_set_int_mask(cam_ctx, 0x3ff | 0x0400); ++ // turn auto function on only doing continues capture ++ if (frames == 0) { ++// CISR |= (1 << 3); ++// while (!(CISR & (1 << 3))); //Wait a EOF then begin start DMA ++ ov9650_auto_function_on(); ++ // start dma ++ start_dma_transfer(cam_ctx, 0); ++ } ++ else { ++ status = get_ov_format(cam_ctx, &ovSizeFormat, &ovFormat); ++ if (status) ++ return -1; ++ if (pov->pre_size == OV_SIZE_NONE) ++ return -1; ++ printk("in function %s, cam_ctx->block_tail == 0\n", __FUNCTION__); ++ if (pov->pre_size == ovSizeFormat) { ++ if (cam_ctx->block_tail == 0) { ++ } ++ else { ++ struct page **p_page; ++ struct page **pdes; ++ ++ printk("in function %s, cam_ctx->block_tail != 0\n", __FUNCTION__); ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ pdes = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ COPY_BUFFERS(pdes, p_page, cam_ctx->fifo0_transfer_size); ++ COPY_BUFFERS(pdes, p_page, cam_ctx->fifo1_transfer_size); ++ COPY_BUFFERS(pdes, p_page, cam_ctx->fifo2_transfer_size); ++ } ++ set_still_image_ready(1); ++ return 0; ++ } ++ else { ++ ov9650_auto_function_off(); ++ cam_ctx->block_tail = cam_ctx->block_header = 0; ++ ov9650_prepare_capture(cam_ctx, ovSizeFormat, ovFormat); ++ } ++ // turn viewfinder on ++ ov9650_viewfinder_on(); ++ } ++ // turn viewfinder on ++ ov9650_viewfinder_on(); ++ ov9650_set_start(); ++ return 0; ++} ++ ++int Ov9650AutoFunctionOn(void) ++{ ++ u8 regValue = 0; ++ ++ printk("in function %s \n", __FUNCTION__); ++ //ov9650_read(0x13, ®Value); ++ if ((regValue & 0x7) == 7) ++ return 1; ++ return 0; ++} ++ ++int camera_func_ov9650_stop_capture(p_camera_context_t cam_ctx) ++{ ++ if (ov9650_output_stoped()) ++ return 0; ++ printk("in camera_func_ov9650_stop_capture\n"); ++ //if (Ov9650AutoFunctionOn()) ++ // turn auto function off ++ ov9650_auto_function_off(); ++ ov9650_save_gains(); ++ ++ // turn viewfinder off ++ ov9650_viewfinder_off(); ++ stop_dma_transfer(cam_ctx); ++ ov9650_set_stop(cam_ctx); ++ return 0; ++} ++ ++int camera_func_ov9650_command(p_camera_context_t cam_ctx, unsigned int cmd, void *param) ++{ ++ int ret = 0; ++ ++ printk("in function %s, param =%p, \n", __FUNCTION__, param); ++ switch (cmd) { ++ /* get capture size */ ++ case VIDIOCGWIN: ++ { ++ struct video_window vw; ++ vw.width = cam_ctx->capture_width; ++ vw.height = cam_ctx->capture_height; ++ ov9650_get_window(&vw); ++ if (copy_to_user(param, &vw, sizeof(struct video_window))) ++ ret = -EFAULT; ++ break; ++ } ++ ++ /* set capture size. */ ++ case VIDIOCSWIN: ++ { ++ struct video_window vw; ++ if (copy_from_user(&vw, param, sizeof(vw))) { ++ ret = -EFAULT; ++ break; ++ } ++ printk("in %s, vw-x =%d, vw-y=%d,vw.width=%d,vw.height=%d\n", ++ __FUNCTION__, vw.x, vw.y, vw.width, vw.height); ++ if (vw.width > 1280 || vw.height > 1024 || vw.width < MIN_WIDTH || vw.height < MIN_HEIGHT) { ++ ret = -EFAULT; ++ break; ++ } ++ /* ++ */ ++ ov9650_set_window(&vw); ++ cam_ctx->capture_width = vw.width; ++ cam_ctx->capture_height = vw.height; ++ camera_set_capture_format(cam_ctx); ++ break; ++ } ++ /*set picture style */ ++ case WCAM_VIDIOCSSTYLE: ++ { ++ V4l_PIC_STYLE capture_style; ++ capture_style = (V4l_PIC_STYLE) param; ++ cam_ctx->capture_style = (V4l_PIC_STYLE) param; ++ ret = ov9650_set_special_effect(capture_style); ++ printk("in camera_func_ov9650_command ret=%d\n", ret); ++ if (cam_ctx->capture_style != V4l_STYLE_BLACK_WHITE && cam_ctx->capture_style != V4l_STYLE_SEPIA) { ++ } ++ } ++ break; ++ /*set picture light */ ++ case WCAM_VIDIOCSLIGHT: ++ cam_ctx->capture_light = (int) param; ++ ret = ov9650_set_white_balance((int)param); ++ break; ++ /*set picture brightness */ ++ case WCAM_VIDIOCSBRIGHT: ++ cam_ctx->capture_bright = (int) param; ++ ret = ov9650_set_brightness((int) param); ++ break; ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return ov9650_set_sensor_size(param); ++ ++ /*get sensor size */ ++ case WCAM_VIDIOCGSSIZE: ++ return ov9650_get_sensor_size(param); ++ ++ /*set output size */ ++ case WCAM_VIDIOCSOSIZE: ++ return ov9650_set_output_size(param); ++ ++ /*get output size */ ++ case WCAM_VIDIOCGOSIZE: ++ return ov9650_get_output_size(param); ++#if 0 ++#endif ++ /*set video mode fps */ ++ case WCAM_VIDIOCSFPS: ++ { ++ struct { ++ int fps, minfps; ++ } cam_fps; ++ DPRINTK("WCAM_VIDIOCSFPS"); ++ if (copy_from_user(&cam_fps, param, sizeof(int) * 2)) { ++ return -EFAULT; ++ } ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ return ov9650_set_fps(cam_fps.fps, cam_fps.minfps); ++ } ++ return -1; ++ case WCAM_VIDIOCSNIGHTMODE: ++ { ++ struct { ++ int mode, maxexpottime; ++ } cam_mode; ++ int mode; ++ if (copy_from_user(&cam_mode, param, sizeof(cam_mode))) { ++ return -EFAULT; ++ } ++ mode = cam_mode.mode; ++ if (mode == V4l_NM_NIGHT) ++ ov9650_set_night_mode(); ++ if (mode == V4l_NM_ACTION) ++ ov9650_set_action_mode(); ++ if (mode == V4l_NM_AUTO) ++ ov9650_set_auto_mode(); ++ } ++ break; ++ case WCAM_VIDIOCSCONTRAST: ++ { ++ ret = ov9650_set_contrast((int)param/50); ++ break; ++ } ++ case WCAM_VIDIOCSFLICKER: ++ { ++ ret = ov9650_set_flicker((int)param); ++ break; ++ } ++ default: ++ printk("in %s default case -----------------cmd =%d param=%p\n", __FUNCTION__, cmd, param); ++ ret = -1; ++ } ++ return ret; ++} ++int camera_func_ov9650_pm(p_camera_context_t cam_ctx, int suspend) ++{ ++ static int resume_dma = 0; ++ if (suspend) { ++ if (cam_ctx != NULL) { ++ if (cam_ctx->dma_started) { ++ dbg_print("camera running, suspended"); ++ stop_dma_transfer(cam_ctx); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ CKEN &= ~CKEN24_CAMERA; ++ } ++ else { ++ CKEN |= CKEN24_CAMERA; ++ enable_irq(IRQ_CAMERA); ++ ++ if (cam_ctx != NULL) { ++ dbg_print("camera running, resumed"); ++ camera_init(cam_ctx); ++ //ov9650_restore_property(cam_ctx, 0); ++ ++ ++ if (resume_dma == 1) { ++ camera_start_video_capture(cam_ctx, 0); ++ resume_dma = 0; ++ } ++ } ++ } ++ return 0; ++} +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9650.h linux-2.6.16/drivers/media/video/ov9650.h +--- linux-2.6.16.orig/drivers/media/video/ov9650.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9650.h 2006-06-03 11:14:56.448307808 +0200 +@@ -0,0 +1,71 @@ ++/* ++ ov9650 - Omnivision 9650 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++#ifndef _OV_9650_H_ ++#define _OV_9650_H_ ++ ++#include <linux/videodev.h> ++#include "camera.h" ++typedef struct { ++ u32 version; ++ u32 stoped; ++ u32 mclock; ++ u32 pre_size; ++ u32 exp_value; ++ u32 exp_time; ++ u32 adjusted_exp_value; ++ u32 adjusted_exp_time; ++ u8 pclock; ++ u32 gain; ++ u32 gaina; ++ u8 blue_gain; ++ u8 red_gain; ++ u8 y_average; ++ u32 sensor_width; ++ u32 sensor_height; ++ u32 sub_win; ++ u32 night_mode; ++ struct video_window win; ++}ov9650; ++ ++////////////////////////////////////////////////////////////////////////////////////// ++// ++// Prototypes ++// ++////////////////////////////////////////////////////////////////////////////////////// ++ ++int camera_func_ov9650_init( p_camera_context_t ); ++ ++int camera_func_ov9650_deinit( p_camera_context_t ); ++ ++int camera_func_ov9650_sleep( p_camera_context_t camera_context ); ++ ++int camera_func_ov9650_wake( p_camera_context_t camera_context ); ++ ++int camera_func_ov9650_set_capture_format( p_camera_context_t ); ++ ++int camera_func_ov9650_start_capture( p_camera_context_t, unsigned int frames ); ++ ++int camera_func_ov9650_stop_capture( p_camera_context_t ); ++ ++int camera_func_ov9650_pm(p_camera_context_t cam_ctx, int suspend); ++ ++int camera_func_ov9650_command(p_camera_context_t camera_context, unsigned int cmd, void *param); ++ ++#endif // _OV_9650_H_ +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9650_hw.c linux-2.6.16/drivers/media/video/ov9650_hw.c +--- linux-2.6.16.orig/drivers/media/video/ov9650_hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9650_hw.c 2006-06-03 11:14:56.450307504 +0200 +@@ -0,0 +1,1773 @@ ++/* ++ ov9650_hw - Omnivision 9650 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#include <linux/types.h> ++#include <linux/delay.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++ ++#include "camera.h" ++#include "ov9650.h" ++#include "ov9650_hw.h" ++ ++ov9650 g_ov9650; ++/*********************************************************************** ++* Attention: This is platform related! ++***********************************************************************/ ++static const u32 OV9650_PWRDWN_GPIO[2] = { 1, 50 }; ++//static const u32 OV9650_RESET_GPIO[2] = { 1, xxx }; ++volatile int ov9650_step = 0; ++ ++/*********************************************************************** ++* Register Settings ++***********************************************************************/ ++ ++static u8 gInit_9650[] = { ++ /* ++ //0x12, 0x80, //0x12 ++ 0x11, 0x87, //0x11 ++ 0x39, 0x40, //0x39 ++ 0x13, 0x80, //0x13 ++ 0x01, 0x80, //0x01 ++ 0x02, 0x80, //0x ++ 0x00, 0x00, //0x ++ 0x0c, 0x05, //0x stop frame ++ 0x0d, 0x80, //0x ++ 0x12, 0x10, //0x ++ 0x10, 0xf0, //0x ++ 0xa1, 0x00, //0x ++ 0x3a, 0x0c, //0x ??? ++ 0x8c, 0x23, //0x ++ 0x3d, 0x92, //0x ++ 0x18, 0xc6, //0x ++ 0x17, 0x26, //0x ++ 0x1b, 0x01, //0x ++ 0x16, 0x02, //0x ++ 0x33, 0x10, //0x ++ 0x34, 0x38, //0x ++ 0xa8, 0x81, //0x ++ 0x41, 0x10, //0x ++ 0x96, 0x04, //0x ++*/ ++ //0x12, 0x80, //0x12 ++ 0x11, 0x83, //0x11 ++ 0x39, 0x40, //0x39 ++ 0x0e, 0x01, //0x ++ 0x38, 0x12, //0x ++ 0x13, 0xc7, //0x13 ++ 0x14, 0x2a, //Gain Control ++ 0x1e, 0x04, //0x01 ++ ++ 0x01, 0x80, //0x ++ 0x02, 0x80, //0x ++ 0x00, 0x00, //0x ++ 0x10, 0xf0, //0x ++ ++ 0x12, 0x10, //0x ++ 0x0c, 0x05, //0x stop frame ++ 0x0d, 0x80, //0x ++ //0x3a, 0x0d, //enable Digital BLC, Rev0 0x0c ++ ++ //0x1b, 0x00, //0x ++ 0x16, 0x06, //0x ++ 0x33, 0x10, //0x ++ 0x34, 0xbf, //0x ++ 0xa8, 0x81, //0x ++ 0x41, 0x10, //0x ++ 0x96, 0x04, //0x ++ 0x3d, 0x19, //0x ++ 0x1b, 0x01, //0x ++ ++ 0x18, 0xc6, ++ 0x17, 0x26, ++ 0x32, 0xa4, ++ 0x03, 0x36, ++ //0x1a, 0x1e, ++ //0x19, 0x00, ++ 0x8e, 0x00, ++ ++ 0x3c, 0x60, ++ 0x8f, 0xcf, ++ 0x8b, 0x06, ++ 0x35, 0x91, ++ 0x94, 0x99, ++ 0x95, 0x99, ++ 0x40, 0xc1, ++ 0x29, 0x2f, ++ //0x0f, 0x42, //Rev0 0x4a ++ 0x27, 0x90, ++ 0x28, 0x8c, ++ 0x2c, 0x08, ++ 0xa5, 0x80, ++ ++ 0x41, 0x00, ++ 0x13, 0xc5, ++ 0x26, 0xe2, ++ ++ 0x3d, 0x92, ++ 0x69, 0x80, ++ 0x43, 0xf0, ++ 0x44, 0x10, ++ 0x45, 0x67, ++ 0x46, 0x96, ++ 0x47, 0x4e, ++ 0x48, 0x9a, ++ 0x59, 0x36, ++ 0x5a, 0x73, ++ 0x5b, 0x55, ++ 0x5c, 0xa8, ++ 0x5d, 0x84, ++ 0x5e, 0x0f, ++ 0x5f, 0xf0, ++ 0x60, 0x0c, ++ 0x61, 0x20, ++ ++ 0xa5, 0xd9, ++ 0xa4, 0x74, ++ 0x8d, 0x02, ++ ++ 0x13, 0xc7, ++ ++ 0x4f, 0x32, ++ 0x50, 0x27, ++ 0x51, 0x0b, ++ 0x52, 0x0d, ++ 0x53, 0x48, ++ 0x54, 0x55, ++ 0x41, 0x32, ++ ++ 0x8c, 0x23, ++ 0x3d, 0x92, ++ 0x3e, 0x02, ++ 0xa9, 0x97, ++ ++ 0x8f, 0xcf, ++ 0x90, 0x00, ++ 0x91, 0x00, ++ 0x9f, 0x00, ++ 0xa0, 0x00, ++ 0xff,0, // End of list delimiter. ++ ++ 0xff,0 // End of list delimiter. ++}; ++ ++const static u8 gYUV_QQVGA[] = { ++ OV9650_COM10, 0x20, ++ OV9650_COM7, 0x10, ++ OV9650_COM1, 0x24, ++ OV9650_CLKRC, 0x01, ++ ++ // From OmniVision ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_QQCIF[] = { ++ OV9650_COM10, 0x20, ++ OV9650_COM7, 0x08, ++ OV9650_COM1, 0x24, ++ OV9650_CLKRC, 0x01, ++ ++ // From OmniVision ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_VGA[] = { ++ 0x0d, 0x80, ++ 0x11, 0x81, ++ 0x12, 0x40, ++ 0x18, 0xc6, ++ 0x17, 0x26, ++ 0x32, 0xad, ++ 0x03, 0x00, ++ 0x1a, 0x3d, ++ 0x19, 0x01, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++const static u8 gYUV_QVGA[] = { ++ //0x0c, 0x05, ++ 0x0d, 0x80, ++ 0x11, 0x83, ++ 0x12, 0x10, ++ 0x18, 0xc6, ++ 0x17, 0x26, ++ 0x32, 0xa4, ++ 0x03, 0x36, ++ 0x1a, 0x1e, ++ 0x19, 0x00, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++const static u8 gYUV_CIF[] = { ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_QCIF[] = { ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gYUV_SXGA[] = { ++ // From OmniVision ++ 0x0d, 0x40, ++ 0x11, 0x80, ++ 0x12, 0x00, ++ 0x18, 0xbd, ++ 0x17, 0x1d, ++ 0x32, 0xad, ++ 0x03, 0x12, ++ 0x1a, 0x81, ++ 0x19, 0x01, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++ ++const static u8 gRGB_QQVGA[] = { ++ OV9650_COM7, 0x80, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_QVGA[] = { ++ OV9650_COM7, 0x80, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_QCIF[] = { ++ OV9650_COM7, 0x80, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++ ++const static u8 gRGB_VGA[] = { ++ OV9650_COM7, 0x80, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_CIF[] = { ++ OV9650_COM7, 0x80, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++const static u8 gRGB_SXGA[] = { ++ OV9650_COM7, 0x80, ++ OV9650_REGEND, 0x00 // End of list delimiter. ++}; ++ ++/*********************************************************************** ++* Private/helper api ++***********************************************************************/ ++static void ov9650_wait(int ms) ++{ ++ mdelay(ms); ++} ++ ++/*********************************************************************** ++* Sensor read/write ++***********************************************************************/ ++// TODO: temp ++static int ov9650_read(u8 addr, u8 *pvalue) ++{ ++ return i2c_ov9650_read(addr, pvalue); ++} ++ ++static int ov9650_write(u8 addr, u8 value) ++{ ++ return i2c_ov9650_write(addr, value); ++} ++// end TODO ++ ++static int prv_read_sensor_reg(const u8 subAddress, u8 * bufP) ++{ ++ return ov9650_read(subAddress, bufP); ++} ++ ++static int prv_write_sensor_reg(const u8 subAddress, u8 * bufP) ++{ ++ return ov9650_write(subAddress, *bufP); ++} ++ ++static int ov9650_set_regs(u8 * regP) ++{ ++ u32 curReg = 0; ++ int status = 0; ++ ++ // The list is a register number followed by the value. ++ while (regP[curReg << 1] < OV9650_REGEND) { ++ status = prv_write_sensor_reg(regP[curReg << 1], ®P[(curReg << 1) + 1]); ++ if (curReg == 0) ++ ov9650_wait(1); ++ ++ curReg++; ++ } ++ return status; ++} ++ ++static void ov9650_print_all_regs(void) ++{ ++#if 0 ++ // read all register after power up ++ ov9650 *pov; ++ pov = &g_ov9650; ++ int i, maxreg; ++ maxreg = OV9650_LASTREG; ++ ++ dbg_print("start read all default register (0x%x)", maxreg); ++ for(i=0; i<=maxreg; i++) ++ { ++ char value; ++ ov9650_read(i, &value); ++ //dbg_print("reg addr(0x%x) value(0x%x)", i, value); ++ } ++ dbg_print("end read all default register"); ++#endif ++} ++ ++/*********************************************************************** ++* Power & Reset ++***********************************************************************/ ++void ov9650_power_down(int powerDown) ++{ ++ // OV9650 PWRDWN, 0 = NORMAL, 1=POWER DOWN ++ GPDR1 |= GPIO_bit(50); ++ //OV9650 reset CIF_RST, 0 = NORMAL, 1=RESET ++ GPDR0 |= GPIO_bit(19); ++ if (powerDown == 1) { ++ GPSR1 = GPIO_bit(50); ++ } ++ else { ++ GPCR1 = GPIO_bit(50); ++ GPSR0 = GPIO_bit(19); ++ mdelay(20); ++ GPCR0 = GPIO_bit(19); ++ } ++ mdelay(100); ++} ++ ++void ov9650_soft_reset(void) ++{ ++ ov9650 *pov = &g_ov9650; ++ u8 regValue; ++ regValue = 0x80; ++ prv_write_sensor_reg(OV9650_COM7, ®Value); ++ mdelay(10); ++ ++ ov9650_print_all_regs(); ++ ++ ov9650_set_regs(gInit_9650); ++ ++ //0x3a, 0x0d, //enable Digital BLC, Rev0 0x0c ++ //0x0f, 0x42, //Rev0 0x4a ++ if ( (pov->version&0xff) == PID_9650_0 ) ++ { ++ ov9650_write(0x3a, 0x0c); ++ ov9650_write(0x0f, 0x4a); ++ } ++ else ++ { ++ ov9650_write(0x3a, 0x0d); ++ ov9650_write(0x0f, 0x42); ++ } ++ ++ dbg_print("end initial register"); ++ return; ++} ++ ++int ov9650_output_stoped() ++{ ++ ov9650 *pov; ++ pov = &g_ov9650; ++ return pov->stoped; ++} ++ ++void ov9650_set_start() ++{ ++ ov9650 *pov; ++ pov = &g_ov9650; ++ ++ pov->stoped = 0; ++} ++ ++void ov9650_set_stop(p_camera_context_t cam_ctx) ++{ ++ ov9650 *pov; ++ pov = &g_ov9650; ++ ++ pov->stoped = 1; ++} ++ ++/*********************************************************************** ++* Settings ++***********************************************************************/ ++int ov9650_version_revision(u8 * pCmRevision, u8 * pSensorRevision) ++{ ++ prv_read_sensor_reg(OV9650_PID, pCmRevision); ++ prv_read_sensor_reg(OV9650_VER, pSensorRevision); ++ return 0; ++} ++ ++void ov9650_auto_function_on(void) ++{ ++ u8 val; ++ DPRINTK("in function %s\n", __FUNCTION__); ++ prv_read_sensor_reg(OV9650_COM8, &val); ++ val |= 0x07; ++ prv_write_sensor_reg(OV9650_COM8, &val); ++} ++ ++void ov9650_auto_function_off(void) ++{ ++ u8 val; ++ DPRINTK("in function %s\n", __FUNCTION__); ++ prv_read_sensor_reg(OV9650_COM8, &val); ++ val &= ~0x07; ++ prv_write_sensor_reg(OV9650_COM8, &val); ++} ++ ++ ++/*********************************************************************** ++* Viewfinder, still ++***********************************************************************/ ++int ov9650_viewfinder_on(void) ++{ ++ u8 com3; ++ ++ ov9650_print_all_regs(); ++ ++ prv_read_sensor_reg(OV9650_COM3, &com3); ++ com3 &= ~0x01; ++ prv_write_sensor_reg(OV9650_COM3, &com3); ++ ++ return OV_ERR_NONE; ++} ++ ++ ++int ov9650_viewfinder_off(void) ++{ ++ u8 com3; ++ ++ prv_read_sensor_reg(OV9650_COM3, &com3); ++ com3 |= 0x01; ++ prv_write_sensor_reg(OV9650_COM3, &com3); ++ ++ ov9650_print_all_regs(); ++ ++ mdelay(200); ++ return OV_ERR_NONE; ++} ++ ++ ++static u8 *ov9650_get_regs_list(u32 captureSizeFormat, u32 colorFormat) ++{ ++ char *formatNameP=NULL; ++ u8 *defaultDataP=NULL; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ ++ // Get the default setting. ++ if (colorFormat == OV_FORMAT_YUV_422) { ++ switch (captureSizeFormat) { ++ case OV_SIZE_QQVGA: ++ defaultDataP = (u8 *)gYUV_QQVGA; ++ formatNameP = "QQVGA.422"; ++ break; ++ case OV_SIZE_QQCIF: ++ defaultDataP = (u8 *)gYUV_QQCIF; ++ formatNameP = "QQCIF.422"; ++ break; ++ case OV_SIZE_QVGA: ++ defaultDataP = (u8 *)gYUV_QVGA; ++ formatNameP = "QVGA.422"; ++ break; ++ case OV_SIZE_QCIF: ++ defaultDataP = (u8 *)gYUV_QCIF; ++ formatNameP = "QCIF.422"; ++ break; ++ case OV_SIZE_VGA: ++ defaultDataP = (u8 *)gYUV_VGA; ++ formatNameP = "VGA.422"; ++ break; ++ case OV_SIZE_CIF: ++ defaultDataP = (u8 *)gYUV_CIF; ++ formatNameP = "CIF.422"; ++ break; ++ case OV_SIZE_SXGA: ++ defaultDataP = (u8 *)gYUV_SXGA; ++ formatNameP = "SXGA.422"; ++ break; ++ default: ++ return NULL; ++ } ++ } ++ ++ if (colorFormat == OV_FORMAT_RGB_565) { ++ switch (captureSizeFormat) { ++ case OV_SIZE_QQVGA: ++ defaultDataP = (u8 *)gRGB_QQVGA; ++ formatNameP = "QQVGA.RGB"; ++ break; ++ case OV_SIZE_QCIF: ++ defaultDataP = (u8 *)gRGB_QCIF; ++ formatNameP = "QCIF.RGB"; ++ break; ++ ++ case OV_SIZE_QVGA: ++ defaultDataP = (u8 *)gRGB_QVGA; ++ formatNameP = "QVGA.RGB"; ++ break; ++ case OV_SIZE_VGA: ++ defaultDataP = (u8 *)gRGB_VGA; ++ formatNameP = "VGA.RGB"; ++ break; ++ case OV_SIZE_CIF: ++ defaultDataP = (u8 *)gRGB_CIF; ++ formatNameP = "CIF.RGB"; ++ break; ++ case OV_SIZE_SXGA: ++ defaultDataP = (u8 *)gRGB_SXGA; ++ formatNameP = "SXGA.RGB"; ++ break; ++ default: ++ return NULL; ++ } ++ } ++ dbg_print("%s", formatNameP); ++ return defaultDataP; ++} ++ ++/*********************************************************************** ++* Format ++***********************************************************************/ ++static int ov9650_switch_format(u32 captureSizeFormat, u32 colorFormat) ++{ ++ int status; ++ u8 *regsP; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ ++ regsP = (u8 *) ov9650_get_regs_list(captureSizeFormat, colorFormat); ++ // Get the pointer to the basic setting. The pointer must be freed after exiting. ++ ++ if (regsP == NULL) ++ return OV_ERR_PARAMETER; ++ ++ status = ov9650_set_regs(regsP); ++ mdelay(50); ++ if (pov->night_mode == 1) { ++ //night mode ++ ov9650_set_night_mode(); ++ } ++ else if (pov->night_mode == 2) { //action mode ++ ov9650_set_action_mode(); ++ } ++ else ++ ov9650_set_auto_mode(); ++ ++ return status; ++} ++ ++int ov9650_set_format(u32 captureSizeFormat, u32 colorFormat) ++{ ++ int status = OV_ERR_PARAMETER; ++ u8 *regsP; ++ static u32 prev_colorFormat = OV_FORMAT_NONE, prev_size = OV_SIZE_NONE; ++ ++ if (prev_colorFormat == colorFormat && captureSizeFormat == prev_size) ++ return 0; ++ if ((captureSizeFormat == OV_SIZE_NONE) && (colorFormat == OV_FORMAT_NONE)) ++ goto no_set; ++ ++ if ((prev_colorFormat == OV_FORMAT_NONE) && (prev_size == OV_SIZE_NONE)) { ++ regsP = (u8 *) ov9650_get_regs_list(captureSizeFormat, colorFormat); ++ // Get the pointer to the basic setting. The pointer must be freed after exiting. ++ ++ if (regsP == NULL) ++ return OV_ERR_PARAMETER; ++ //ov9650_soft_reset(); ++ // Blast the entire parameter tree into the part. ++ status = ov9650_set_regs(regsP); ++ } ++ else { ++ status = ov9650_switch_format(captureSizeFormat, colorFormat); ++ } ++no_set: ++ prev_colorFormat = colorFormat; ++ prev_size = captureSizeFormat; ++ return status; ++} ++ ++void ov9650_save_gains(void) ++{ ++ u8 gainh, gainl, aech, aechm, aecl, laec, blue, red; ++ u32 gain, gaina, exp_value; ++ ov9650 *pov; ++ u8 regValue; ++ static u32 prevSize; ++ ++ pov = &g_ov9650; ++ ++ // Get current size ++ prv_read_sensor_reg(OV9650_COM7, ®Value); ++ switch (regValue) { ++ case 0x00: ++ prevSize = OV_SIZE_SXGA; ++ break; ++ case 0x08: ++ prv_read_sensor_reg(OV9650_COM1, ®Value); ++ if (regValue & 0x20) ++ prevSize = OV_SIZE_QQCIF; ++ else ++ prevSize = OV_SIZE_QCIF; ++ break; ++ case 0x10: ++ prv_read_sensor_reg(OV9650_COM1, ®Value); ++ if (regValue & 0x20) ++ prevSize = OV_SIZE_QQVGA; ++ else ++ prevSize = OV_SIZE_QVGA; ++ break; ++ case 0x20: ++ prevSize = OV_SIZE_CIF; ++ break; ++ case 0x40: ++ prevSize = OV_SIZE_VGA; ++ break; ++ default: ++ prevSize = OV_SIZE_SXGA; ++ break; ++ } ++ pov->pre_size = prevSize; ++ ++ // Get the awb, gain, exposure values ++ prv_read_sensor_reg(OV9650_BLUE, &blue); ++ prv_read_sensor_reg(OV9650_RED, &red); ++ prv_read_sensor_reg(OV9650_GAIN, &gainl); ++ prv_read_sensor_reg(OV9650_VREF, &gainh); ++ gain = gainl + ((gainh>>6)&0x03); ++ prv_read_sensor_reg(OV9650_AECHM, &aechm); ++ prv_read_sensor_reg(OV9650_AECH, &aech); ++ prv_read_sensor_reg(OV9650_COM1, &aecl); ++ exp_value = (((aechm&0x3f)<<10) + (aech << 2)) | (aecl&0x03); ++ prv_read_sensor_reg(OV9650_LAEC, &laec); ++ ++ pov->gain = gain; ++ pov->blue_gain = blue; ++ pov->red_gain = red; ++ pov->exp_value = exp_value; ++ pov->exp_time = laec; ++ ++ //TODO: ++ gaina = (gainl & 0x0f) + 16; ++ if(gainl&0x20) ++ gaina *= 2; ++ if(gainl&0x10) ++ gaina *= 2; ++ pov->gaina = gaina; ++ ++ DPRINTK("gain=%x gaina=%x blue=%x red=%x, expv=%x expt=%x\n", ++ gain, gaina, blue, red, exp_value, laec); ++} ++ ++static void ov9650_adjust_gains(u32 prev_size, u32 cur_size) ++{ ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ if (prev_size == OV_SIZE_QVGA) { ++ if (cur_size == OV_SIZE_VGA) { ++ { ++ /* capture 15 fps */ ++ pov->pclock = 0x81; ++ pov->adjusted_exp_value = pov->exp_value * 2; ++ } ++ if (pov->night_mode == 1) { ++ //night mode ++ //pov->pclock = 0x87; ++ } ++ else if (pov->night_mode == 2) { //action mode ++ pov->pclock = 0x80; ++ } ++ } ++ else if (cur_size == OV_SIZE_SXGA) { ++ int adjexp = 0; ++ adjexp = pov->exp_value * 2; ++#if 0 ++ if (pov->gain & 0x80) { ++ /* 8x gain capture 7.5 fps to 4x gain */ ++ if(adjexp<500) ++ { ++ //pov->pclock = 0x80; ++ adjexp = adjexp * 2; ++ pov->gain = pov->gain & ~0x80; ++ } ++ } ++ if (pov->gain & 0x40) { ++ /* 4x gain capture 7.5 fps to 2x gain */ ++ if(adjexp<500) ++ { ++ //pov->pclock = 0x80; ++ adjexp = adjexp * 2; ++ pov->gain = pov->gain & ~0x40; ++ } ++ } ++ if (pov->gain & 0x20) { ++ if(adjexp<500) ++ { ++ //pov->pclock = 0x80; ++ adjexp = adjexp * 2; ++ pov->gain = pov->gain & ~0x20; ++ } ++ } ++ if (pov->gain & 0x10) { ++ if(adjexp<500) ++ { ++ //pov->pclock = 0x80; ++ adjexp = adjexp * 2; ++ pov->gain = pov->gain & ~0x10; ++ } ++ } ++#endif ++ if (pov->night_mode == 1) { ++ //night mode ++ //pov->pclock = 0x81; ++ } ++ else if (pov->night_mode == 2) { //action mode ++ pov->pclock = 0x80; ++ } ++ pov->adjusted_exp_value = adjexp; ++ } ++ else if (cur_size == OV_SIZE_QVGA) { ++ if (pov->gain & 0x20) { ++ /* hight gain capture 7.5 fps */ ++ pov->pclock = 0x87; ++ pov->gain = pov->gain & ~0x20; ++ pov->adjusted_exp_value = pov->exp_value; ++ } ++ else { ++ /* capture 15 fps */ ++ pov->pclock = 0x83; ++ pov->adjusted_exp_value = pov->exp_value; ++ } ++ if (pov->night_mode == 1) { ++ //night mode ++ //pov->pclock = 0x89; ++ } ++ else if (pov->night_mode == 2) { //action mode ++ pov->pclock = 0x81; ++ } ++ } ++ } ++} ++ ++static void ov9650_upload_gains(void) ++{ ++ ov9650 *pov; ++ u32 expValue, gain, gaina; ++ u8 gainh, gainl, aechm, aech, aecl, laec, blue, red; ++ u8 regValue; ++ ++ pov = &g_ov9650; ++ ++ gain = pov->gain; ++ gaina = pov->gaina; ++ blue = pov->blue_gain; ++ red = pov->red_gain; ++ expValue = pov->adjusted_exp_value; ++ laec = pov->exp_time; ++ // Set awb ++ prv_write_sensor_reg(OV9650_BLUE, &blue); ++ prv_write_sensor_reg(OV9650_RED, &red); ++ ++ // Set gain ++ gaina = (gaina*5)/7; ++ gain = 0; ++ if(gaina>62) ++ { ++ gain |= 0x20; ++ gaina /= 2; ++ } ++ if(gaina>31) ++ { ++ gain |= 0x10; ++ gaina /= 2; ++ } ++ if( gaina>16 ) ++ gaina -= 16; ++ else ++ gaina = 0; ++ gain = gain | gaina; ++ ++ gainl = gain & 0xff; ++ gainh = (gain&0x0300)>>2; ++ prv_write_sensor_reg(OV9650_GAIN, &gainl); ++ prv_read_sensor_reg(OV9650_VREF, ®Value); ++ regValue = (regValue & 0x3f) | gainh; ++ prv_write_sensor_reg(OV9650_VREF, ®Value); ++ // Set exposure ++ aechm = (expValue>>10)&0x3f; ++ aech = (expValue>>2)&0xff; ++ aecl = expValue&0x03; ++ prv_read_sensor_reg(OV9650_AECHM, ®Value); ++ regValue = (regValue & 0xc0) | aechm; ++ prv_write_sensor_reg(OV9650_AECHM, ®Value); ++ prv_write_sensor_reg(OV9650_AECH, &aech); ++ prv_read_sensor_reg(OV9650_COM1, ®Value); ++ regValue = (regValue & 0xfc) | aecl; ++ prv_write_sensor_reg(OV9650_COM1, ®Value); ++ ++ //prv_write_sensor_reg(OV9650_CLKRC, &pov->pclock); ++ DPRINTK("gain=%x gaina=%x blue=%x red=%x, expv=%x, pclock=%x\n", ++ gain, gaina, blue, red, expValue, pov->pclock); ++} ++ ++static int ++ov9650_set_dma_pages(pxa_dma_desc ** pdes, ++ pxa_dma_desc ** des_physical, int num, struct page *array[], int total_size, int dsadr, int flags) ++{ ++ int remain_size, des_transfer_size; ++ int j, target_page_num = num; ++ pxa_dma_desc *cur_des_virtual = *pdes; ++ pxa_dma_desc *cur_des_physical = *des_physical; ++ ++ // in each iteration, generate one dma chain for one frame ++ remain_size = total_size; ++ ++ for (j = 0; j < num; j++) { ++ // set descriptor ++ if (remain_size > PAGE_SIZE) ++ des_transfer_size = PAGE_SIZE; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = dsadr; // FIFO0 physical address ++ cur_des_virtual->dtadr = page_to_bus(array[j]); ++ cur_des_virtual->dcmd = des_transfer_size | flags; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ *pdes = cur_des_virtual; ++ *des_physical = cur_des_physical; ++ return 0; ++} ++ ++static int ++ov9650_set_dma_page1(pxa_dma_desc ** pdes, ++ pxa_dma_desc ** des_physical, int num, struct page *page1, int total_size, int dsadr, int flags) ++{ ++ int remain_size, des_transfer_size; ++ int j, target_page_num = num; ++ pxa_dma_desc *cur_des_virtual = *pdes; ++ pxa_dma_desc *cur_des_physical = *des_physical; ++ int dump_page; ++ ++ // in each iteration, generate one dma chain for one frame ++ remain_size = total_size; ++ dump_page = page_to_bus(page1); ++ DPRINTK("dump_page=%x", dump_page); ++ ++ for (j = 0; j < num; j++) { ++ // set descriptor ++ if (remain_size > PAGE_SIZE) ++ des_transfer_size = PAGE_SIZE; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = dsadr; // FIFO0 physical address ++ cur_des_virtual->dtadr = dump_page; ++ cur_des_virtual->dcmd = des_transfer_size | flags; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ *pdes = cur_des_virtual; ++ *des_physical = cur_des_physical; ++ return 0; ++} ++ ++static int ov9650_update_still_dma_chain(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int remain_size; ++ unsigned int i; ++ ++ int target_page_num; ++ ++ DPRINTK("ov9650_update_still_dma_chain\n"); ++ // clear descriptor pointers ++ cam_ctx->fifo0_descriptors_virtual = cam_ctx->fifo0_descriptors_physical = 0; ++ cam_ctx->fifo1_descriptors_virtual = cam_ctx->fifo1_descriptors_physical = 0; ++ cam_ctx->fifo2_descriptors_virtual = cam_ctx->fifo2_descriptors_physical = 0; ++ ++ // calculate how many descriptors are needed per frame ++ cam_ctx->fifo0_num_descriptors = cam_ctx->pages_per_fifo0; ++ ++ cam_ctx->fifo1_num_descriptors = cam_ctx->pages_per_fifo1; ++ ++ cam_ctx->fifo2_num_descriptors = cam_ctx->pages_per_fifo2; ++ ++ // check if enough memory to generate descriptors ++ DPRINTK("in %s, cam_ctx->block_number =%d\n", __FUNCTION__, cam_ctx->block_number); ++ if ((cam_ctx->fifo0_num_descriptors + cam_ctx->fifo1_num_descriptors + ++ cam_ctx->fifo2_num_descriptors) * cam_ctx->block_number > cam_ctx->dma_descriptors_size) ++ return -1; ++ ++ // generate fifo0 dma chains ++ cam_ctx->fifo0_descriptors_virtual = (unsigned) cam_ctx->dma_descriptors_virtual; ++ cam_ctx->fifo0_descriptors_physical = (unsigned) cam_ctx->dma_descriptors_physical; ++ cur_des_virtual = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_physical; ++ ++ DPRINTK("pages_allocated=%d,fifo0_descriptors_virtual=%p\n", cam_ctx->pages_allocated, cur_des_virtual); ++ ++ for (i = 0; i < 2; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo0_transfer_size; ++ ov9650_set_dma_page1(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo0_num_descriptors, ++ cam_ctx->page_array[cam_ctx-> ++ pages_allocated - ++ 1], remain_size, CIBR0_PHY, DCMD_FLOWSRC | DCMD_BURST32); ++ ++ } ++ DPRINTK("after ov9650_set_dma_page1=%d\n", cam_ctx->pages_allocated); ++ for (i = 0; i < 1; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo0_transfer_size; ++ ++ // assume the blocks are stored consecutively ++ target_page_num = cam_ctx->pages_per_block * i; ++ DPRINTK("target_page_num=%d\n", target_page_num); ++ ov9650_set_dma_pages(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo0_num_descriptors, ++ &cam_ctx->page_array[target_page_num], ++ remain_size, CIBR0_PHY, DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo0_descriptors_physical); ++ last_des_virtual->ddadr |= 0x1; ++ last_des_virtual->dcmd |= DCMD_ENDIRQEN; ++ ++ // generate fifo1 dma chains ++ if (cam_ctx->fifo1_transfer_size) { ++ // record fifo1 descriptors' start address ++ cam_ctx->fifo1_descriptors_virtual = (unsigned) cur_des_virtual; ++ cam_ctx->fifo1_descriptors_physical = (unsigned) cur_des_physical; ++ ++ for (i = 0; i < 2; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo1_transfer_size; ++ ov9650_set_dma_page1(&cur_des_virtual, ++ &cur_des_physical, ++ cam_ctx-> ++ fifo1_num_descriptors, ++ cam_ctx->page_array[cam_ctx-> ++ pages_allocated ++ - 2], ++ remain_size, CIBR1_PHY, DCMD_FLOWSRC | DCMD_BURST32); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ for (i = 0; i < 1; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo1_transfer_size; ++ ++ target_page_num = cam_ctx->pages_per_block * i + cam_ctx->pages_per_fifo0; ++ ov9650_set_dma_pages(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo1_num_descriptors, ++ &cam_ctx->page_array[target_page_num], ++ remain_size, CIBR1_PHY, DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo1_descriptors_physical); ++ last_des_virtual->ddadr |= 0x1; ++ } ++ // generate fifo2 dma chains ++ if (cam_ctx->fifo2_transfer_size) { ++ // record fifo1 descriptors' start address ++ cam_ctx->fifo2_descriptors_virtual = (unsigned) cur_des_virtual; ++ cam_ctx->fifo2_descriptors_physical = (unsigned) cur_des_physical; ++ ++ for (i = 0; i < 2; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo2_transfer_size; ++ ov9650_set_dma_page1(&cur_des_virtual, ++ &cur_des_physical, ++ cam_ctx-> ++ fifo2_num_descriptors, ++ cam_ctx->page_array[cam_ctx-> ++ pages_allocated ++ - 3], ++ remain_size, CIBR2_PHY, DCMD_FLOWSRC | DCMD_BURST32); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ DPRINTK("last target_page_num=%d\n", target_page_num + cam_ctx->fifo2_num_descriptors); ++ for (i = 0; i < 1; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo2_transfer_size; ++ target_page_num = ++ cam_ctx->pages_per_block * i + cam_ctx->pages_per_fifo0 + cam_ctx->pages_per_fifo1; ++ ov9650_set_dma_pages(&cur_des_virtual, &cur_des_physical, ++ cam_ctx->fifo2_num_descriptors, ++ &cam_ctx->page_array[target_page_num], ++ remain_size, CIBR2_PHY, DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR); ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ DPRINTK("last target_page_num=%d\n", target_page_num + cam_ctx->fifo2_num_descriptors); ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo2_descriptors_physical); ++ last_des_virtual->ddadr |= 0x1; ++ } ++ return 0; ++} ++ ++static int ov9650_stop_third_des(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *pdesc, *ptmp; ++ int i; ++ ++ // stop the dma transfer on one frame captured ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo0_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo0_num_descriptors * 2; ++ for (i = 0; i < cam_ctx->fifo0_num_descriptors; i++) ++ (ptmp + i)->dtadr = (pdesc + i)->dtadr; ++ ++ pdesc += cam_ctx->fifo0_num_descriptors - 1; ++ pdesc->dcmd = (pdesc->dcmd & DCMD_LENGTH) | DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR; ++ pdesc += cam_ctx->fifo0_num_descriptors; ++ pdesc->dcmd = (pdesc->dcmd & DCMD_LENGTH) | DCMD_FLOWSRC | DCMD_BURST32 | DCMD_INCTRGADDR; ++ pdesc += cam_ctx->fifo0_num_descriptors; ++ pdesc->ddadr |= 0x1; ++ ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo1_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo1_num_descriptors * 2; ++ for (i = 0; i < cam_ctx->fifo1_num_descriptors; i++) ++ (ptmp + i)->dtadr = (pdesc + i)->dtadr; ++ pdesc += cam_ctx->fifo1_num_descriptors * 3 - 1; ++ pdesc->ddadr |= 0x1; ++ ++ pdesc = (pxa_dma_desc *) (cam_ctx->fifo2_descriptors_virtual); ++ ptmp = pdesc + cam_ctx->fifo2_num_descriptors * 2; ++ for (i = 0; i < cam_ctx->fifo2_num_descriptors; i++) ++ (ptmp + i)->dtadr = (pdesc + i)->dtadr; ++ pdesc += cam_ctx->fifo2_num_descriptors * 3 - 1; ++ pdesc->ddadr |= 0x1; ++ return 0; ++} ++ ++int ov9650_prepare_capture(p_camera_context_t cam_ctx, u32 captureSizeFormat, u32 colorFormat) ++{ ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ ++ stop_dma_transfer(cam_ctx); ++ ov9650_switch_format(captureSizeFormat, colorFormat); ++ ov9650_adjust_gains(pov->pre_size, captureSizeFormat); ++ ov9650_upload_gains(); ++ if (captureSizeFormat == OV_SIZE_VGA) { ++ //ov9650_update_still_dma_chain(cam_ctx); ++ ov9650_stop_third_des(cam_ctx); ++ /* ++ */ ++ } ++ else if (captureSizeFormat == OV_SIZE_SXGA) { ++ camera_set_int_mask(cam_ctx, 0x3fd | 0x0400); ++ ov9650_update_still_dma_chain(cam_ctx); ++ //ci_clear_int_status(0xFFFFFFFF); ++ //DPRINTK("before camera_sleep \n"); ++ //camera_sleep(); ++ } ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ start_dma_transfer(cam_ctx, 1); ++ DPRINTK("after ov9650_prepare_capture \n"); ++ return 0; ++} ++ ++int ov9650_set_special_effect(int style) ++{ ++#if 0 ++ int ret = 0; ++ u32 index, curReg; ++ u8 *regsP; ++ u8 regValue; ++ ++ DPRINTK("in function %s parameter=%d\n", __FUNCTION__, style); ++ curReg = 0x3a; ++ ov9650_read(0x3a, ®Value); ++ regValue = regValue & 0xf; ++ switch (style) { ++ case V4l_STYLE_NORMAL: ++ DPRINTK("V4l_STYLE_NORMAL\n"); ++ regValue &= 0x7f; ++ //ov9650_write(0x3a, 0x08); ++ ov9650_write(0x3a, regValue); ++ ov9650_write(0x67, 0x80); ++ ov9650_write(0x68, 0x80); ++ break; ++ case V4l_STYLE_BLACK_WHITE: ++ DPRINTK("V4l_STYLE_BLACK_WHITE\n"); ++ regValue |= 0x10; ++ //ov9650_write(0x3a, 0x18); ++ ov9650_write(0x3a, regValue); ++ ov9650_write(0x67, 0x80); ++ ov9650_write(0x68, 0x80); ++ break; ++ case V4l_STYLE_SEPIA: ++ DPRINTK("V4l_STYLE_SEPIA\n"); ++ regValue |= 0x10; ++ //ov9650_write(0x3a, 0x18); ++ ov9650_write(0x3a, regValue); ++ ov9650_write(0x67, 0xa0); ++ ov9650_write(0x68, 0x40); ++ break; ++ //case V4l_STYLE_BULISH: ++ DPRINTK("V4l_STYLE_BULISH\n"); ++ ov9650_write(0x3a, 0x18); ++ ov9650_write(0x67, 0x80); ++ ov9650_write(0x68, 0xc0); ++ break; ++ default: ++ DPRINTK("case default ????????????????????\n"); ++ //ret=OV_ERR_PARAMETER; ++ } ++ return ret; ++#else ++ return 0; ++#endif ++} ++ ++int ov9650_set_brightness(int bright) ++{ ++#if 0 ++ int ret = 0; ++ const u8 BN[] = { ++ //BN-3 ++ 0x0f, 0x4f, ++ 0x27, 0xe8, ++ 0x28, 0xe0, ++ 0x29, 0xe0, ++ 0x2c, 0xe0, ++ //BN-2 ++ 0x0f, 0x4f, ++ 0x27, 0xc8, ++ 0x28, 0xc0, ++ 0x29, 0xc0, ++ 0x2c, 0xc0, ++ //BN-1 ++ 0x0f, 0x4f, ++ 0x27, 0xa8, ++ 0x28, 0xa0, ++ 0x29, 0xa0, ++ 0x2c, 0xa0, ++ //BN-0 ++ 0x0f, 0x4f, ++ 0x27, 0x88, ++ 0x28, 0x80, ++ 0x29, 0x80, ++ 0x2c, 0x80, ++ //BN+1 ++ 0x0f, 0x4f, ++ 0x27, 0x28, ++ 0x28, 0x20, ++ 0x29, 0x20, ++ 0x2c, 0x20, ++ //BN+2 ++ 0x0f, 0x4f, ++ 0x27, 0x48, ++ 0x28, 0x40, ++ 0x29, 0x40, ++ 0x2c, 0x40, ++ //BN+3 ++ 0x0f, 0x4f, ++ 0x27, 0x68, ++ 0x28, 0x60, ++ 0x29, 0x60, ++ 0x2c, 0x60, ++ }; ++ u8 *regs; ++ int n = 5; ++ int i; ++ ++ DPRINTK("in function %s bright =%d \n", __FUNCTION__, bright); ++ if (bright < -3) ++ bright = -3; ++ if (bright > 3) ++ bright = 3; ++ //bright = -4 .. 4 ++ regs = &BN[(bright + 3) * n * 2]; ++ //for (i = 0; i < n * 2; i += 2) ++ // ret |= ov9650_write(regs[i], regs[i + 1]); ++#endif ++ return OV_ERR_NONE; ++} ++ ++#if 0 ++static int ov9650_set_color_saturation(int saturation) ++{ ++ const u8 CS[] = { ++ //Saturation: 0.25 ++ 0x4f, 0x14, ++ 0x50, 0x10, ++ 0x51, 0x3, ++ 0x52, 0x6, ++ 0x53, 0x13, ++ 0x54, 0x19, ++ //Saturation 0.5 ++ 0x4f, 0x28, ++ 0x50, 0x22, ++ 0x51, 0x6, ++ 0x52, 0xc, ++ 0x53, 0x26, ++ 0x54, 0x33, ++ //Saturation 0.75 (Default) ++ 0x4f, 0x3c, ++ 0x50, 0x32, ++ 0x51, 0x9, ++ 0x52, 0x13, ++ 0x53, 0x39, ++ 0x54, 0x4c, ++ //Saturation 1.0 ++ 0x4f, 0x50, ++ 0x50, 0x43, ++ 0x51, 0xd, ++ 0x52, 0x19, ++ 0x53, 0x4d, ++ 0x54, 0x66, ++ //Saturation 1.25 ++ 0x4f, 0x64, ++ 0x50, 0x53, ++ 0x51, 0x10, ++ 0x52, 0x1f, ++ 0x53, 0x5f, ++ 0x54, 0x7f, ++ }; ++ u8 *regs; ++ int n = 6; ++ int i; ++ ++ DPRINTK("in function %s ,parameter=%d\n", __FUNCTION__, saturation); ++ if (saturation < 0) ++ saturation = 0; ++ if (saturation > 4) ++ saturation = 4; ++ ++ regs = &CS[saturation * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ov9650_write(regs[i], regs[i + 1]); ++ return OV_ERR_NONE; ++ ++} ++#endif ++ ++int ov9650_set_white_balance(V4l_PIC_WB light) ++{ ++#if 0 ++ int ret = 0; ++ u8 *regs; ++ int n = 13; ++ int i = 0; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ ++ DPRINTK("in function %s ,parameter=%d\n", __FUNCTION__, light); ++ switch (light) { ++ case V4l_WB_DIRECT_SUN: ++ //ov9650_set_color_saturation(3); ++ DPRINTK("V4l_WB_DIRECT_SUN\n"); ++ i = 0 * n * 2; ++ //ov9650_set_night_mode(); ++ break; ++ case V4l_WB_INCANDESCENT: ++ //ov9650_set_color_saturation(2); ++ DPRINTK("V4l_WB_INCANDESCENT\n"); ++ i = 1 * n * 2; ++ //ov9650_set_action_mode(); ++ break; ++ case V4l_WB_FLUORESCENT: ++ //ov9650_set_color_saturation(2); ++ DPRINTK("V4l_WB_FLUORESCENT\n"); ++ i = 2 * n * 2; ++ break; ++ default: ++ /* auto */ ++ //ov9650_set_color_saturation(2); ++ DPRINTK("case default ????????????????????\n"); ++ i = 3 * n * 2; ++ n = 19; ++ //ov9650_set_auto_mode(); ++ break; ++ } ++ //TODO: ++#endif ++ ++ return OV_ERR_NONE; ++} ++ ++int ov9650_set_night_mode() ++{ ++#if 0 ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ pov->night_mode = 1; ++ //ov9650_write(0x11, 0x89); ++ ov9650_write(0x3b, 0xe1); ++#endif ++ return 0; ++} ++ ++int ov9650_set_action_mode() ++{ ++#if 0 ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ pov->night_mode = 2; ++ ov9650_write(0x11, 0x81); ++ ov9650_write(0x3b, 0x01); ++ ov9650_write(0x2d, 0x0); ++ ov9650_write(0x2e, 0x0); ++#endif ++ return 0; ++} ++ ++int ov9650_set_auto_mode() ++{ ++#if 0 ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ pov->night_mode = 0; ++ ov9650_write(0x11, 0x83); ++ ov9650_write(0x3b, 0x01); ++ ov9650_write(0x2d, 0x0); ++ ov9650_write(0x2e, 0x0); ++#endif ++ return 0; ++} ++ ++int ov9650_set_flicker(int freq) ++{ ++#if 0 ++ int ret = 0; ++ const u8 LE_v3[] = { ++ //OutDoor ++ 0x3b, 0x00, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 60Hz(Default) ++ 0x3b, 0x01, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 50Hz ++ 0x3b, 0x01, ++ 0x2a, 0x10, ++ 0x2b, 0x40, ++ 0x6a, 0x3d, ++ }; ++ const u8 LE_v2[] = { ++ //OutDoor ++ 0x13, 0x8d, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 60Hz(Default) ++ 0x13, 0x8d, ++ 0x2a, 0, ++ 0x2b, 0, ++ 0x6a, 0x3d, ++ //Indoor 50Hz ++ 0x13, 0x8d, ++ 0x2a, 0x10, ++ 0x2b, 0x14, ++ 0x6a, 0x3d, ++ }; ++ u8 *regs; ++ int n = 4; ++ int i = 0; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ DPRINTK("in function %s ,parameter=%d\n", __FUNCTION__, freq); ++ switch (freq) { ++ case 0: ++ i = 0 * n * 2; ++ break; ++ case 60: ++ i = 1 * n * 2; ++ break; ++ case 50: ++ i = 2 * n * 2; ++ break; ++ default: ++ i = 0; ++ break; ++ } ++ ++ //regs = &LE_v2[i]; ++ regs = &LE_v3[i]; ++ ++ ++ for (i = 0; i < n * 2; i += 2) ++ ret |= ov9650_write(regs[i], regs[i + 1]); ++#endif ++ return OV_ERR_NONE; ++} ++ ++int ov9650_set_contrast(int contrast) ++{ ++#if 0 ++ const u8 CO[] = { ++ //Low contrast ++ 0x6C, 0x20, ++ 0x6D, 0x50, ++ 0x6E, 0xc0, ++ 0x6F, 0xa8, ++ 0x70, 0x88, ++ 0x71, 0x80, ++ 0x72, 0x78, ++ 0x73, 0x70, ++ 0x74, 0x68, ++ 0x75, 0x58, ++ 0x76, 0x40, ++ 0x77, 0x30, ++ 0x78, 0x28, ++ 0x79, 0x20, ++ 0x7A, 0x1e, ++ 0x7B, 0x18, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x1f, ++ 0x7F, 0x49, ++ 0x80, 0x5a, ++ 0x81, 0x6a, ++ 0x82, 0x79, ++ 0x83, 0x87, ++ 0x84, 0x94, ++ 0x85, 0x9f, ++ 0x86, 0xaf, ++ 0x87, 0xbb, ++ 0x88, 0xcf, ++ 0x89, 0xdf, ++ 0x8A, 0xee, ++ //Middle contrast (default) ++ 0x6C, 0x40, ++ 0x6D, 0x30, ++ 0x6E, 0x4B, ++ 0x6F, 0x60, ++ 0x70, 0x70, ++ 0x71, 0x70, ++ 0x72, 0x70, ++ 0x73, 0x70, ++ 0x74, 0x60, ++ 0x75, 0x60, ++ 0x76, 0x50, ++ 0x77, 0x48, ++ 0x78, 0x3A, ++ 0x79, 0x2E, ++ 0x7A, 0x28, ++ 0x7B, 0x22, ++ 0x7C, 0x04, ++ 0x7D, 0x07, ++ 0x7E, 0x10, ++ 0x7F, 0x28, ++ 0x80, 0x36, ++ 0x81, 0x44, ++ 0x82, 0x52, ++ 0x83, 0x60, ++ 0x84, 0x6C, ++ 0x85, 0x78, ++ 0x86, 0x8C, ++ 0x87, 0x9E, ++ 0x88, 0xBB, ++ 0x89, 0xD2, ++ 0x8A, 0xE6, ++ //High contrast ++ 0x6c, 0x50, ++ 0x6d, 0x60, ++ 0x6e, 0x58, ++ 0x6f, 0x58, ++ 0x70, 0x58, ++ 0x71, 0x50, ++ 0x72, 0x50, ++ 0x73, 0x50, ++ 0x74, 0x50, ++ 0x75, 0x50, ++ 0x76, 0x4c, ++ 0x77, 0x4c, ++ 0x78, 0x45, ++ 0x79, 0x3c, ++ 0x7a, 0x2c, ++ 0x7b, 0x24, ++ 0x7c, 0x05, ++ 0x7d, 0x0b, ++ 0x7e, 0x16, ++ 0x7f, 0x2c, ++ 0x80, 0x37, ++ 0x81, 0x41, ++ 0x82, 0x4b, ++ 0x83, 0x55, ++ 0x84, 0x5f, ++ 0x85, 0x69, ++ 0x86, 0x7c, ++ 0x87, 0x8f, ++ 0x88, 0xb1, ++ 0x89, 0xcf, ++ 0x8a, 0xe5, ++ }; ++ ++ u8 *regs; ++ int n = 31; ++ int i; ++ ++ DPRINTK("in function %s parameter=%d \n", __FUNCTION__, contrast); ++ if (contrast < 0) ++ contrast = 0; ++ if (contrast > 2) ++ contrast = 2; ++ ++ regs = &CO[contrast * n * 2]; ++ for (i = 0; i < n * 2; i += 2) ++ ov9650_write(regs[i], regs[i + 1]); ++#endif ++ return OV_ERR_NONE; ++ ++} ++ ++static int ov9650_find_window(struct video_window *vw, int *sub_win) ++{ ++ int ret = OV_SIZE_NONE; ++ ++ *sub_win = 1; ++ if (vw->width > 1280 || vw->height > 1024 || vw->width < 88|| vw->height < 72) { ++ ret = OV_SIZE_NONE; ++ } ++ else if (vw->width == 1280 && ((vw->height == 960)||(vw->height == 1024))) { ++ *sub_win = 0; ++ ret = OV_SIZE_SXGA; ++ } ++ else if (vw->width >= 640 && vw->height >= 480) { ++ if (vw->width == 640 && vw->height == 480) ++ *sub_win = 0; ++ ret = OV_SIZE_VGA; ++ } ++ else if (vw->width >= 352 && vw->height >= 288) { ++ if (vw->width == 352 && vw->height == 288) ++ *sub_win = 0; ++ ret = OV_SIZE_CIF; ++ } ++ else if (vw->width >= 320 && vw->height >= 240) { ++ if (vw->width == 320 && vw->height == 240) ++ *sub_win = 0; ++ ret = OV_SIZE_QVGA; ++ } ++ else if (vw->width >= 176 && vw->height >= 144) { ++ if (vw->width == 176 && vw->height == 144) ++ *sub_win = 0; ++ ret = OV_SIZE_QCIF; ++ } ++ else if (vw->width >= 160 && vw->height >= 120) { ++ if (vw->width == 160 && vw->height == 120) ++ *sub_win = 0; ++ ret = OV_SIZE_QQVGA; ++ } ++ else if (vw->width >= 88 && vw->height >= 72) { ++ if (vw->width == 88 && vw->height == 72) ++ *sub_win = 0; ++ ret = OV_SIZE_QQCIF; ++ } ++ DPRINTK("in %s,ret = %d, subwin=%d\n", __FUNCTION__, ret, *sub_win); ++ return ret; ++} ++ ++int ov9650_set_window(struct video_window *vw) ++{ ++ int ret = 0; ++ int x_end; ++ int y_end; ++ struct video_window window; ++ int sub_win; ++ ov9650 *pov; ++ ++ pov = &g_ov9650; ++ vw->width = (vw->width + 7) & (~0x7); ++ vw->height = (vw->height + 7) & (~0x7); ++ vw->x = vw->y = 0; ++ x_end = window.width = (vw->width + vw->x); ++ y_end = window.height = (vw->height + vw->y); ++ DPRINTK("in %s, vw-x =%d, vw-y=%d,vw->width=%d,vw->height=%d\n", ++ __FUNCTION__, vw->x, vw->y, vw->width, vw->height); ++ ret = ov9650_find_window(&window, &sub_win); ++ if (ret <= OV_SIZE_NONE) ++ return -1; ++ ++ ret = ov9650_set_format(ret, OV_FORMAT_YUV_422); ++ if (ret < 0) ++ return -1; ++ ++ pov->win = *vw; ++ return ret; ++} ++ ++int ov9650_get_window(struct video_window *vw) ++{ ++ ov9650 *pov; ++ pov = &g_ov9650; ++ *vw = pov->win; ++ return 0; ++} ++ ++struct win_size { ++ int width; ++ int height; ++}; ++int ov9650_set_sensor_size(void *w_size) ++{ ++ struct win_size size; ++ ov9650 *pov; ++ pov = &g_ov9650; ++ if (copy_from_user(&size, w_size, sizeof(struct win_size))) { ++ return -EFAULT; ++ } ++//make it in an even of multiple of 8 ++ size.height = (size.height + 7) / 8 * 8; ++ pov->sensor_width = size.width; ++ pov->sensor_height = size.height; ++ return 0; ++} ++ ++int ov9650_get_sensor_size(void *w_size) ++{ ++ return 0; ++} ++ ++int ov9650_set_output_size(void *w_size) ++{ ++ struct win_size size; ++ ov9650 *pov; ++ pov = &g_ov9650; ++ if (copy_from_user(&size, w_size, sizeof(struct win_size))) { ++ return -EFAULT; ++ } ++//make it in an even of multiple of 8 ++ size.height = (size.height + 7) / 8 * 8; ++ pov->sensor_width = size.width; ++ pov->sensor_height = size.height; ++ return 0; ++} ++ ++int ov9650_get_output_size(void *w_size) ++{ ++ return 0; ++} ++ ++#if 0 ++static int test_divider(int res, int fps) ++{ ++ int max_hz = 48 * 1000000; ++ int div = 1; ++ int i; ++ int ov_fps[5] = { 3, 7, 15, 30, 60 }; ++ u32 value = 320 * 240; ++ /* ++ switch (prevSize) { ++ case OV_SIZE_QQCIF: ++ value = 88 * 72; ++ break; ++ case OV_SIZE_QQVGA: ++ value = 176 * 144; ++ break; ++ case OV_SIZE_QCIF: ++ value = 160 * 120; ++ break; ++ case OV_SIZE_QVGA: ++ value = 320 * 240; ++ break; ++ case OV_SIZE_CIF: ++ value = 352 * 288; ++ break; ++ case OV_SIZE_VGA: ++ value = 640 * 480; ++ break; ++ case OV_SIZE_SXGA: ++ value = 1280 * 960; ++ break; ++ } ++ ++ while (max_hz / res / div > fps) ++ div++; ++ if (div > 64) ++ div = 64; ++ return (div - 1); ++ ++ for (i =0;i<5;i++) ++ if ( fps < ov_fps[i] ) ++ continue; ++ */ ++ if (fps == 0) ++ return 0; ++ if (fps > 60) ++ fps = 60; ++ return (div = 60 / fps - 1); ++} ++#endif ++ ++int ov9650_set_fps(int fps, int min_fps) ++{ ++#if 0 ++ u32 res = 0; ++ u8 value; ++ if (fps < 0) { ++ DPRINTK("in %s fps = %d divider value =%d\n", __FUNCTION__, fps, res); ++ fps = 15; ++ } ++ res = test_divider(0, fps); ++ ov9650_read(OV9650_CLKRC, &value); ++ value = (value & 0xc0) | res; ++ ov9650_write(OV9650_CLKRC, value); ++ DPRINTK("in %s fps = %d divider value =%d\n", __FUNCTION__, fps, res); ++ /* ++ ov9650_set_night_mode(); ++ ov9650_set_action_mode(); ++ ov9650_set_auto_mode(); ++ */ ++#endif ++ return 0; ++} ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/ov9650_hw.h linux-2.6.16/drivers/media/video/ov9650_hw.h +--- linux-2.6.16.orig/drivers/media/video/ov9650_hw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/ov9650_hw.h 2006-06-03 11:14:56.450307504 +0200 +@@ -0,0 +1,284 @@ ++/* ++ ov9650_hw - Omnivision 9650 CMOS sensor driver ++ ++ Copyright (C) 2003, Intel Corporation ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#ifndef _OV_9650_HW_H_ ++#define _OV_9650_HW_H_ ++ ++/*********************************************************************** ++ * ++ * Constants & Structures ++ * ++ ***********************************************************************/ ++// Revision constants ++#define PID_OV 0x96 ++#define PID_9650_0 0x51 ++#define PID_9650 0x52 ++ ++// Return codes ++#define OV_ERR_NONE 0x00 ++#define OV_ERR_TIMEOUT -1 ++#define OV_ERR_PARAMETER -2 ++#define OV_COMM_ERR -3 ++ ++#define CIBR0_PHY (0x50000000 + 0x28) ++#define CIBR1_PHY (0x50000000 + 0x30) ++#define CIBR2_PHY (0x50000000 + 0x38) ++#define DPRINTK(fmt,args...) do { if (DEBUG) printk("in function %s "fmt,__FUNCTION__,##args);} while(0) ++ ++// Output Size & Format ++/* ++#define OV_SIZE_NONE 0 ++#define OV_SIZE_QQVGA 0x01 ++#define OV_SIZE_QVGA ( OV_SIZE_QQVGA << 1 ) ++#define OV_SIZE_VGA ( OV_SIZE_QQVGA << 2 ) ++#define OV_SIZE_SXGA ( OV_SIZE_QQVGA << 3 ) ++#define OV_SIZE_QQCIF 0x10 ++#define OV_SIZE_QCIF ( OV_SIZE_QQCIF << 1 ) ++#define OV_SIZE_CIF ( OV_SIZE_QQCIF << 2 ) ++#define OV_FORMAT_NONE 0 ++#define OV_FORMAT_YUV_422 1 ++#define OV_FORMAT_RGB_565 2 ++*/ ++enum OV_SIZE { ++ OV_SIZE_NONE=0 , ++ OV_SIZE_QQVGA , ++ OV_SIZE_QVGA , ++ OV_SIZE_VGA , ++ OV_SIZE_SXGA , ++ OV_SIZE_QQCIF , ++ OV_SIZE_QCIF , ++ OV_SIZE_CIF ++}; ++enum OV_FORMAT { ++ OV_FORMAT_NONE=0 , ++ OV_FORMAT_YUV_422, ++ OV_FORMAT_RGB_565, ++}; ++ ++// Camera Mode ++#define VIEWFINDER_MODE 0x10 ++#define STILLFRAME_MODE 0x20 ++ ++// Others ++#define OV9650_TIMEOUT 1000 // ms to timeout. ++ ++// OV9650 Register Definitions ++#define OV9650_GAIN 0x0000 ++#define OV9650_BLUE 0x0001 ++#define OV9650_RED 0x0002 ++#define OV9650_VREF 0x0003 ++#define OV9650_COM1 0x0004 ++#define OV9650_BAVE 0x0005 // U/B Average Level ++#define OV9650_GEAVE 0x0006 // Y/Ge Average Level ++#define OV9650_GOAVE 0x0007 // Y/Go Average Level ++#define OV9650_RAVE 0x0008 // V/R Average level ++#define OV9650_COM2 0x0009 // Common control 2 ++#define OV9650_PID 0x000A // Product ID ++#define OV9650_VER 0x000B // Version ++#define OV9650_COM3 0x000C ++#define OV9650_COM4 0x000D ++#define OV9650_COM5 0x000E ++#define OV9650_COM6 0x000F ++#define OV9650_AECH 0x0010 ++#define OV9650_CLKRC 0x0011 ++#define OV9650_COM7 0x0012 ++#define OV9650_COM8 0x0013 ++#define OV9650_COM9 0x0014 ++#define OV9650_COM10 0x0015 ++#define OV9650_WS 0x0016 ++#define OV9650_HSTART 0x0017 ++#define OV9650_HSTOP 0x0018 ++#define OV9650_VSTRT 0x0019 ++#define OV9650_VSTOP 0x001A ++#define OV9650_PSHFT 0x001B ++#define OV9650_MIDH 0x001C ++#define OV9650_MIDL 0x001D ++#define OV9650_MVLP 0x001E ++#define OV9650_LAEC 0x001F ++#define OV9650_BOS 0x0020 ++#define OV9650_GBOS 0x0021 ++#define OV9650_GROS 0x0022 ++#define OV9650_ROS 0x0023 ++#define OV9650_AEW 0x0024 ++#define OV9650_AEB 0x0025 ++#define OV9650_VPT 0x0026 ++#define OV9650_BBIAS 0x0027 ++#define OV9650_GbBIAS 0x0028 ++//#define OV9650_GrBIAS 0x0029 ++#define OV9650_GrCOM 0x0029 ++#define OV9650_EXHCH 0x002A ++#define OV9650_EXHCL 0x002B ++#define OV9650_RBIAS 0x002C ++#define OV9650_ADVFL 0x002D ++#define OV9650_ADVFH 0x002E ++#define OV9650_YAVE 0x002F ++#define OV9650_HSYST 0x0030 ++#define OV9650_HSYEN 0x0031 ++#define OV9650_HREF 0x0032 ++#define OV9650_CHLF 0x0033 ++#define OV9650_ARBLM 0x0034 ++#define OV9650_VRHL 0x0035 ++#define OV9650_VIDO 0x0036 ++#define OV9650_ADC 0x0037 ++#define OV9650_ACOM 0x0038 ++#define OV9650_OFON 0x0039 ++#define OV9650_TSLB 0x003A ++#define OV9650_COM11 0x003B ++#define OV9650_COM12 0x003C ++#define OV9650_COM13 0x003D ++#define OV9650_COM14 0x003E ++#define OV9650_EDGE 0x003F ++#define OV9650_COM15 0x0040 ++#define OV9650_COM16 0x0041 ++#define OV9650_COM17 0x0042 ++#define OV9650_AWBTH1 0x0043 ++#define OV9650_AWBTH2 0x0044 ++#define OV9650_AWBTH3 0x0045 ++#define OV9650_AWBTH4 0x0046 ++#define OV9650_AWBTH5 0x0047 ++#define OV9650_AWBTH6 0x0048 ++#define OV9650_MTX1 0x004F ++#define OV9650_MTX2 0x0050 ++#define OV9650_MTX3 0x0051 ++#define OV9650_MTX4 0x0052 ++#define OV9650_MTX5 0x0053 ++#define OV9650_MTX6 0x0054 ++#define OV9650_MTX7 0x0055 ++#define OV9650_MTX8 0x0056 ++#define OV9650_MTX9 0x0057 ++#define OV9650_MTXS 0x0058 ++#define OV9650_AWBC1 0x0059 ++#define OV9650_AWBC2 0x005A ++#define OV9650_AWBC3 0x005B ++#define OV9650_AWBC4 0x005C ++#define OV9650_AWBC5 0x005D ++#define OV9650_AWBC6 0x005E ++#define OV9650_AWBC7 0x005F ++#define OV9650_AWBC8 0x0060 ++#define OV9650_AWBC9 0x0061 ++#define OV9650_LCC1 0x0062 ++#define OV9650_LCC2 0x0063 ++#define OV9650_LCC3 0x0064 ++#define OV9650_LCC4 0x0065 ++#define OV9650_LCC5 0x0066 ++#define OV9650_MANU 0x0067 ++#define OV9650_MANV 0x0068 ++#define OV9650_HV 0x0069 ++#define OV9650_MBD 0x006A ++#define OV9650_DBLV 0x006B ++#define OV9650_GSP0 0x006C ++#define OV9650_GSP1 0x006D ++#define OV9650_GSP2 0x006E ++#define OV9650_GSP3 0x006F ++#define OV9650_GSP4 0x0070 ++#define OV9650_GSP5 0x0071 ++#define OV9650_GSP6 0x0072 ++#define OV9650_GSP7 0x0073 ++#define OV9650_GSP8 0x0074 ++#define OV9650_GSP9 0x0075 ++#define OV9650_GSP10 0x0076 ++#define OV9650_GSP11 0x0077 ++#define OV9650_GSP12 0x0078 ++#define OV9650_GSP13 0x0079 ++#define OV9650_GSP14 0x007A ++#define OV9650_GSP15 0x007B ++#define OV9650_GST0 0x007C ++#define OV9650_GST1 0x007D ++#define OV9650_GST2 0x007E ++#define OV9650_GST3 0x007F ++#define OV9650_GST4 0x0080 ++#define OV9650_GST5 0x0081 ++#define OV9650_GST6 0x0082 ++#define OV9650_GST7 0x0083 ++#define OV9650_GST8 0x0084 ++#define OV9650_GST9 0x0085 ++#define OV9650_GST10 0x0086 ++#define OV9650_GST11 0x0087 ++#define OV9650_GST12 0x0088 ++#define OV9650_GST13 0x0089 ++#define OV9650_GST14 0x008A ++// OV9650 Register Definitions ++#define OV9650_COM21 0x008B ++#define OV9650_COM22 0x008C ++#define OV9650_COM23 0x008D ++#define OV9650_COM24 0x008E ++#define OV9650_DBLC1 0x008F ++#define OV9650_DBLCB 0x0090 ++#define OV9650_DBLCR 0x0091 ++#define OV9650_DMLNL 0x0092 ++#define OV9650_DMLNH 0x0093 ++ ++#define OV9650_AECHM 0x00A1 ++ ++// End of OV9650 register ++#define OV9650_LASTREG 0x00AA ++ ++// End flag of register ++#define OV9650_REGEND ( 0xff ) ++ ++ ++ ++/*********************************************************************** ++ * ++ * Function Prototype ++ * ++ ***********************************************************************/ ++ ++void ov9650_power_down( int powerDown ); ++void ov9650_soft_reset( void ); ++ ++int ov9650_version_revision(u8 * pCmRevision, u8 *pSensorRevision); ++void ov9650_auto_function_on(void); ++void ov9650_auto_function_off(void); ++ ++int ov9650_viewfinder_on(void); ++int ov9650_viewfinder_off(void); ++ ++int ov9650_set_format( u32 captureSizeFormat, u32 colorFormat ); ++int ov9650_prepare_capture(p_camera_context_t cam_ctx, u32 captureSizeFormat, u32 colorFormat); ++void ov9650_set_start(void); ++int ov9650_output_stoped(void); ++void ov9650_set_stop(p_camera_context_t cam_ctx); ++void ov9650_save_gains(void); ++int ov9650_set_window(struct video_window *vw); ++int ov9650_get_window(struct video_window *vw); ++int ov9650_set_sensor_size(void *w_size); ++int ov9650_get_sensor_size(void *w_size); ++int ov9650_set_output_size(void *w_size); ++int ov9650_get_output_size(void *w_size); ++int ov9650_set_special_effect(int style); ++int ov9650_set_white_balance(V4l_PIC_WB light); ++int ov9650_set_flicker(int freq); ++int ov9650_set_brightness(int); ++int ov9650_set_fps(int fps, int min_fps); ++int ov9650_set_night_mode(void); ++int ov9650_set_auto_mode(void); ++int ov9650_set_action_mode(void); ++int ov9650_set_contrast(int); ++ ++extern int i2c_ov9650_deinit(void); ++ ++extern int i2c_ov9650_init(void); ++extern int i2c_ov9650_cleanup(void); ++extern int i2c_ov9650_read(u8 addr, u8 *pvalue); ++extern int i2c_ov9650_write(u8 addr, u8 value); ++ ++ ++#endif +diff -Nurd linux-2.6.16.orig/drivers/media/video/pxa_camera.c linux-2.6.16/drivers/media/video/pxa_camera.c +--- linux-2.6.16.orig/drivers/media/video/pxa_camera.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/pxa_camera.c 2006-06-03 11:14:56.607283640 +0200 +@@ -0,0 +1,2860 @@ ++/*================================================================================ ++ ++ Module Name: pxa-camera.c ++ ++General Description: Camera module e680 camera source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Wangfei(w20239) 12/19/2003 LIBdd35749 Created ++ ++WangWenxin(w20158) 1/1/2004 LIBdd35749 Modified ++ ++wangfei(w20239) 02/05/2004 LIBdd74309 Set frame rate in video mode ++ ++wangfei(w20239) 02/26/2004 LIBdd81055 New chip id support ++ Update algorithm for DMA transfer ++ Update strategy for memory management ++ Fix still picture capture failed sometime ++ New Agilent sensor chip ID support ++ Make output height in an even multiple of 8 ++ Dynamic power management feature ++ ++wangfei(w20239) 03/08/2004 LIBdd84578 Photo effects setting ++ Fix segmentation fault in rmmod ++ Adjust default image buffer size ++ ++wangfei(w20239) 04/26/2004 LIBdd97716 Power Management added ++ Photo effects setting bug fix ++ ++wangfei(w20239) 05/28/2004 LIBee13628 add two new interface. ++ 1 get ready frames ++ 2 set frame buffer count ++ ++ 06/10/2004 add mt9v111 support ++ ++Portability: Indicate ifthis module is portable to other compilers or ++platforms. If not, indicate specific reasons why is it not portable. ++ ++================================================================================== ++ INCLUDE FILES ++================================================================================*/ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++ ++#include <linux/types.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/arch/irqs.h> ++#include <asm/irq.h> ++ ++#include <asm/arch/pxa-regs.h> ++ ++#include "camera.h" ++//#include "adcm2700_hw.h" ++ ++#define CIBR0_PHY (0x50000000 + 0x28) ++#define CIBR1_PHY (0x50000000 + 0x30) ++#define CIBR2_PHY (0x50000000 + 0x38) ++/* ++ * It is required to have at least 3 frames in buffer ++ * in current implementation ++ */ ++#define FRAMES_IN_BUFFER 3 ++#define SINGLE_DESC_TRANS_MAX PAGE_SIZE ++ ++ ++#define DRCMR68 __REG(0x40001110) /* Request to Channel Map Register for Camera FIFO 0 Request */ ++#define DRCMR69 __REG(0x40001114) /* Request to Channel Map Register for Camera FIFO 1 Request */ ++#define DRCMR70 __REG(0x40001118) /* Request to Channel Map Register for Camera FIFO 2 Request */ ++ ++static camera_context_t *g_camera_context; ++#ifdef CONFIG_ARCH_EZX_E680 ++extern camera_function_t e680_camera_func; ++#endif ++#ifdef CONFIG_ARCH_EZX_A780 ++ #ifdef CONFIG_CAMERA_MT9M111 ++ extern camera_function_t mt9m111_func; ++ #endif ++ #ifdef CONFIG_CAMERA_OV9640 ++ extern camera_function_t ov9640_func; ++ #endif ++ #ifdef CONFIG_CAMERA_OV9650 ++ extern camera_function_t camera_ov9650_func; ++ #endif ++ #ifdef CONFIG_CAMERA_ADCM3800 ++ extern camera_function_t camera_adcm3800_func; ++ #endif ++#endif ++wait_queue_head_t camera_wait_q; ++ ++/* /dev/videoX registration number */ ++static int minor = 0; ++static int ci_dma_y = -1; ++static int ci_dma_cb = -1; ++static int ci_dma_cr = -1; ++static int task_waiting = 0; ++static int still_image_mode = 0; ++static int still_image_rdy = 0; ++static int first_video_frame = 0; ++static int detected_sensor_type = 0; ++// map of camera image format (camera.h) ==> capture interface format (ci.h) ++static const CI_IMAGE_FORMAT FORMAT_MAPPINGS[] = ++{ ++ CI_RAW8, //RAW ++ CI_RAW9, ++ CI_RAW10, ++ ++ CI_RGB444, //RGB ++ CI_RGB555, ++ CI_RGB565, ++ CI_RGB666_PACKED, //RGB Packed ++ CI_RGB666, ++ CI_RGB888_PACKED, ++ CI_RGB888, ++ CI_RGBT555_0, //RGB+Transparent bit 0 ++ CI_RGBT888_0, ++ CI_RGBT555_1, //RGB+Transparent bit 1 ++ CI_RGBT888_1, ++ ++ CI_INVALID_FORMAT, ++ CI_YCBCR422, //YCBCR ++ CI_YCBCR422_PLANAR, //YCBCR Planaried ++ CI_INVALID_FORMAT, ++ CI_INVALID_FORMAT ++}; ++ ++ ++void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs); ++void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs); ++void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs); ++void stop_dma_transfer(p_camera_context_t camera_context); ++int start_capture(p_camera_context_t camera_context, unsigned int block_id, unsigned int frames); ++int camera_init(p_camera_context_t camera_context); ++static int update_dma_chain(p_camera_context_t camera_context); ++ ++static int pxa_camera_open(struct inode *inode, struct file *file); ++static int pxa_camera_close(struct inode *inode, struct file *file); ++static ssize_t pxa_camera_read(struct file *file, char __user *data, ++ size_t count, loff_t *ppos); ++static ssize_t pxa_camera_write(struct file *file, const char __user *data, ++ size_t count, loff_t *ppos); ++static unsigned int pxa_camera_poll(struct file *file, poll_table *wait); ++static int pxa_camera_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++static int pxa_camera_mmap(struct file *file, struct vm_area_struct *vma); ++int pxa_camera_video_init(struct video_device *vdev); ++ ++void start_dma_transfer(p_camera_context_t camera_context, unsigned block_id); ++void pxa_dma_repeat(camera_context_t *cam_ctx); ++void pxa_dma_continue(camera_context_t *cam_ctx); ++ ++int pxa_camera_mem_deinit(void); ++int pxa_camera_mem_init(void); ++ ++static struct file_operations vd_fops = { ++ .owner = THIS_MODULE, ++ .open = pxa_camera_open, ++ .release = pxa_camera_close, ++ .read = pxa_camera_read, ++ .poll = pxa_camera_poll, ++ .ioctl = pxa_camera_ioctl, ++ .mmap = pxa_camera_mmap, ++ .llseek = no_llseek, ++ .write = pxa_camera_write, ++}; ++ ++static struct video_device vd = { ++ .owner = THIS_MODULE, ++ .name = "E680 camera", ++ .type = VID_TYPE_CAPTURE, ++ .hardware = VID_HARDWARE_PXA_CAMERA, /* FIXME */ ++ .fops = &vd_fops, ++ //FIXME .initialize = pxa_camera_video_init, ++ .minor = -1, ++}; ++ ++ ++/*********************************************************************** ++ * ++ * Declarations ++ * ++ ***********************************************************************/ ++ ++ ++#ifdef CONFIG_PM ++ static struct pm_dev *pm_dev; ++#endif ++ ++#ifdef CONFIG_PM ++static int camera_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ if(g_camera_context == NULL) ++ { ++ return 0; ++ } ++ ++ if(g_camera_context->camera_functions == NULL) ++ { ++ return 0; ++ } ++ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ g_camera_context->camera_functions->pm_management(g_camera_context, 1); ++ break; ++ ++ case PM_RESUME: ++ g_camera_context->camera_functions->pm_management(g_camera_context, 0); ++ break; ++ ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++/*********************************************************************** ++ * ++ * Private functions ++ * ++ ***********************************************************************/ ++ ++static int pxa_dma_buffer_init(p_camera_context_t camera_context) ++{ ++ struct page *page; ++ unsigned int pages; ++ unsigned int page_count; ++ ++ camera_context->pages_allocated = 0; ++ ++ pages = (PAGE_ALIGN(camera_context->buf_size) / PAGE_SIZE); ++ ++ camera_context->page_array = (struct page **) ++ kmalloc(pages * sizeof(struct page *), ++ GFP_KERNEL); ++ ++ if(camera_context->page_array == NULL) ++ { ++ return -ENOMEM; ++ } ++ memset(camera_context->page_array, 0, pages * sizeof(struct page *)); ++ ++ for(page_count = 0; page_count < pages; page_count++) ++ { ++ page = alloc_page(GFP_KERNEL); ++ if(page == NULL) ++ { ++ goto error; ++ } ++ camera_context->page_array[page_count] = page; ++ set_page_count(page, 1); ++ SetPageReserved(page); ++ } ++ camera_context->buffer_virtual = remap_page_array(camera_context->page_array, ++ pages, ++ GFP_KERNEL); ++ if(camera_context->buffer_virtual == NULL) ++ { ++ goto error; ++ } ++ ++ camera_context->pages_allocated = pages; ++ ++ return 0; ++ ++error: ++ for(page_count = 0; page_count < pages; page_count++) ++ { ++ if((page = camera_context->page_array[page_count]) != NULL) ++ { ++ ClearPageReserved(page); ++ set_page_count(page, 1); ++ put_page(page); ++ } ++ } ++ kfree(camera_context->page_array); ++ ++ return -ENOMEM; ++} ++ ++static void pxa_dma_buffer_free(p_camera_context_t camera_context) ++{ ++ struct page *page; ++ int page_count; ++ ++ if(camera_context->buffer_virtual == NULL) ++ return; ++ ++ vfree(camera_context->buffer_virtual); ++ ++ for(page_count = 0; page_count < camera_context->pages_allocated; page_count++) ++ { ++ if((page = camera_context->page_array[page_count]) != NULL) ++ { ++ ClearPageReserved(page); ++ set_page_count(page, 1); ++ put_page(page); ++ } ++ } ++ kfree(camera_context->page_array); ++} ++/* ++Generate dma descriptors ++Pre-condition: these variables must be set properly ++ block_number, fifox_transfer_size ++ dma_descriptors_virtual, dma_descriptors_physical, dma_descirptors_size ++Post-condition: these variables will be set ++ fifox_descriptors_virtual, fifox_descriptors_physical ++ fifox_num_descriptors ++*/ ++//#ifdef CONFIG_ARCH_EZX_E680 ++static int generate_fifo2_dma_chain(p_camera_context_t camera_context, pxa_dma_desc ** cur_vir, pxa_dma_desc ** cur_phy) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size, target_page_num; ++ unsigned int i,j; ++ ++ cur_des_virtual = (pxa_dma_desc *)camera_context->fifo2_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *)camera_context->fifo2_descriptors_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo2_transfer_size; ++ ++ target_page_num = camera_context->pages_per_block * i + ++ camera_context->pages_per_fifo0 + ++ camera_context->pages_per_fifo1; ++ ++ if (camera_context->pages_per_fifo1 > 1) ++ { ++ for(j=0; j<camera_context->fifo2_num_descriptors; j++) ++ { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX) ++ { ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ } ++ else ++ { ++ des_transfer_size = remain_size; ++ } ++ ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR2_PHY; // FIFO2 physical address ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ else ++ { ++ for(j=0; j<camera_context->fifo2_num_descriptors; j++) ++ { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX/2) ++ { ++ des_transfer_size = SINGLE_DESC_TRANS_MAX/2; ++ } ++ else ++ { ++ des_transfer_size = remain_size; ++ } ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR2_PHY; // FIFO2 physical address ++ if (!(j % 2)) ++ { ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]); ++ } ++ else ++ { ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]) + (PAGE_SIZE/2); ++ } ++ ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ ddbg_print(" CR: the ddadr = %8x, dtadr = %8x, dcmd = %8x, page = %8x \n", ++ cur_des_virtual->ddadr, ++ cur_des_virtual->dtadr, ++ cur_des_virtual->dcmd, ++ page_to_bus(camera_context->page_array[target_page_num]) ); ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ ++ if (j % 2) ++ { ++ target_page_num++; ++ } ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ } ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo2_descriptors_physical); ++ ++ *cur_vir = cur_des_virtual; ++ *cur_phy = cur_des_physical; ++ return 0; ++} ++static int generate_fifo1_dma_chain(p_camera_context_t camera_context, pxa_dma_desc ** cur_vir, pxa_dma_desc ** cur_phy) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size, target_page_num; ++ unsigned int i,j; ++ ++ cur_des_virtual = (pxa_dma_desc *)camera_context->fifo1_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *)camera_context->fifo1_descriptors_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo1_transfer_size; ++ ++ target_page_num = camera_context->pages_per_block * i + ++ camera_context->pages_per_fifo0; ++ ++ if (camera_context->pages_per_fifo1 > 1) ++ { ++ for(j=0; j<camera_context->fifo1_num_descriptors; j++) ++ { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR1_PHY; // FIFO1 physical address ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ else ++ { ++ for(j=0; j<camera_context->fifo1_num_descriptors; j++) ++ { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX/2) ++ { ++ des_transfer_size = SINGLE_DESC_TRANS_MAX/2; ++ } ++ else ++ { ++ des_transfer_size = remain_size; ++ } ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR1_PHY; // FIFO1 physical address ++ if(!(j % 2)) ++ { ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]); ++ } ++ else ++ { ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]) + (PAGE_SIZE/2); ++ } ++ ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ ddbg_print("CB: the ddadr = %8x, dtadr = %8x, dcmd = %8x, page = %8x \n", ++ cur_des_virtual->ddadr, ++ cur_des_virtual->dtadr, ++ cur_des_virtual->dcmd, ++ page_to_bus(camera_context->page_array[target_page_num])); ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ if (j % 2) ++ { ++ target_page_num++; ++ } ++ }//end of for j... ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ }// end of else ++ }//end of for i... ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo1_descriptors_physical); ++ *cur_vir = cur_des_virtual; ++ *cur_phy = cur_des_physical; ++ ++ return 0; ++} ++static int generate_fifo0_dma_chain(p_camera_context_t camera_context, pxa_dma_desc ** cur_vir, pxa_dma_desc ** cur_phy) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size, target_page_num; ++ unsigned int i,j; ++ ++ cur_des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo0_transfer_size; ++ ++ // assume the blocks are stored consecutively ++ target_page_num = camera_context->pages_per_block * i; ++ ++ if (camera_context->pages_per_fifo0 > 2) ++ { ++ for(j=0; j<camera_context->fifo0_num_descriptors; j++) ++ { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX) ++ { ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ } ++ else ++ { ++ des_transfer_size = remain_size; ++ } ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR0_PHY; // FIFO0 physical address ++ cur_des_virtual->dtadr = ++ page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ else ++ { ++ for(j=0; j<camera_context->fifo0_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX/2) ++ { ++ des_transfer_size = SINGLE_DESC_TRANS_MAX/2; ++ } ++ else ++ { ++ des_transfer_size = remain_size; ++ } ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR0_PHY; // FIFO0 physical address ++ if(!(j % 2)) ++ { ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ } ++ else ++ { ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]) + (PAGE_SIZE / 2); ++ } ++ ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ ddbg_print(" Y: the ddadr = %8x, dtadr = %8x, dcmd = %8x, page = %8x, page_num = %d \n", ++ cur_des_virtual->ddadr, ++ cur_des_virtual->dtadr, ++ cur_des_virtual->dcmd, ++ page_to_bus(camera_context->page_array[target_page_num]), ++ target_page_num); ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ if (j % 2) ++ { ++ target_page_num++; ++ } ++ }//end of for j.. ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ }// end of else ++ } ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo0_descriptors_physical); ++ *cur_vir = cur_des_virtual; ++ *cur_phy = cur_des_physical; ++ return 0; ++} ++ ++int update_dma_chain(p_camera_context_t camera_context) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical; ++ // clear descriptor pointers ++ camera_context->fifo0_descriptors_virtual = camera_context->fifo0_descriptors_physical = 0; ++ camera_context->fifo1_descriptors_virtual = camera_context->fifo1_descriptors_physical = 0; ++ camera_context->fifo2_descriptors_virtual = camera_context->fifo2_descriptors_physical = 0; ++ ++ // calculate how many descriptors are needed per frame ++ camera_context->fifo0_num_descriptors = ++ camera_context->pages_per_fifo0 > 2 ? camera_context->pages_per_fifo0 : (camera_context->fifo0_transfer_size / (PAGE_SIZE/2) + 1); ++ ++ camera_context->fifo1_num_descriptors = ++ camera_context->pages_per_fifo1 > 1 ? camera_context->pages_per_fifo1 : (camera_context->fifo1_transfer_size / (PAGE_SIZE/2) + 1); ++ ++ camera_context->fifo2_num_descriptors = ++ camera_context->pages_per_fifo2 > 1 ? camera_context->pages_per_fifo2 : (camera_context->fifo2_transfer_size / (PAGE_SIZE/2) + 1); ++ ++ // check if enough memory to generate descriptors ++ if((camera_context->fifo0_num_descriptors + camera_context->fifo1_num_descriptors + ++ camera_context->fifo2_num_descriptors) * camera_context->block_number ++ > camera_context->dma_descriptors_size) ++ { ++ return -1; ++ } ++ ++ // generate fifo0 dma chains ++ camera_context->fifo0_descriptors_virtual = (unsigned)camera_context->dma_descriptors_virtual; ++ camera_context->fifo0_descriptors_physical = (unsigned)camera_context->dma_descriptors_physical; ++ // generate fifo0 dma chains ++ generate_fifo0_dma_chain(camera_context, &cur_des_virtual, &cur_des_physical); ++ ++ // generate fifo1 dma chains ++ if(!camera_context->fifo1_transfer_size) ++ { ++ return 0; ++ } ++ // record fifo1 descriptors' start address ++ camera_context->fifo1_descriptors_virtual = (unsigned)cur_des_virtual; ++ camera_context->fifo1_descriptors_physical = (unsigned)cur_des_physical; ++ // generate fifo1 dma chains ++ generate_fifo1_dma_chain(camera_context, &cur_des_virtual, &cur_des_physical); ++ ++ if(!camera_context->fifo2_transfer_size) ++ { ++ return 0; ++ } ++ // record fifo1 descriptors' start address ++ camera_context->fifo2_descriptors_virtual = (unsigned)cur_des_virtual; ++ camera_context->fifo2_descriptors_physical = (unsigned)cur_des_physical; ++ // generate fifo2 dma chains ++ generate_fifo2_dma_chain(camera_context, &cur_des_virtual, &cur_des_physical); ++ ++ return 0; ++} ++//#else ++#if 0 ++int update_dma_chain(p_camera_context_t camera_context) ++{ ++ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size; ++ unsigned int i,j; ++ int target_page_num; ++ ++ dbg_print(""); ++ ++ // clear descriptor pointers ++ camera_context->fifo0_descriptors_virtual = camera_context->fifo0_descriptors_physical = 0; ++ camera_context->fifo1_descriptors_virtual = camera_context->fifo1_descriptors_physical = 0; ++ camera_context->fifo2_descriptors_virtual = camera_context->fifo2_descriptors_physical = 0; ++ ++ // calculate how many descriptors are needed per frame ++ camera_context->fifo0_num_descriptors = ++ camera_context->pages_per_fifo0; ++ ++ camera_context->fifo1_num_descriptors = ++ camera_context->pages_per_fifo1; ++ ++ camera_context->fifo2_num_descriptors = ++ camera_context->pages_per_fifo2; ++ ++ // check if enough memory to generate descriptors ++ if((camera_context->fifo0_num_descriptors + ++ camera_context->fifo1_num_descriptors + ++ camera_context->fifo2_num_descriptors) * camera_context->block_number ++ > camera_context->dma_descriptors_size) ++ { ++ return -1; ++ } ++ ++ dbg_print("1"); ++ // generate fifo0 dma chains ++ camera_context->fifo0_descriptors_virtual = (unsigned)camera_context->dma_descriptors_virtual; ++ camera_context->fifo0_descriptors_physical = (unsigned)camera_context->dma_descriptors_physical; ++ ++ cur_des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo0_transfer_size; ++ ++ // assume the blocks are stored consecutively ++ target_page_num = camera_context->pages_per_block * i; ++ ++ for(j=0; j<camera_context->fifo0_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR0_PHY; // FIFO0 physical address ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo0_descriptors_physical); ++ ++ // generate fifo1 dma chains ++ if(camera_context->fifo1_transfer_size) ++ { ++ // record fifo1 descriptors' start address ++ camera_context->fifo1_descriptors_virtual = (unsigned)cur_des_virtual; ++ camera_context->fifo1_descriptors_physical = (unsigned)cur_des_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo1_transfer_size; ++ ++ target_page_num = camera_context->pages_per_block * i + ++ camera_context->pages_per_fifo0; ++ ++ for(j=0; j<camera_context->fifo1_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR1_PHY; // FIFO1 physical address ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ // advance pointers ++ ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo1_descriptors_physical); ++ } ++ ++ // generate fifo2 dma chains ++ if(camera_context->fifo2_transfer_size) ++ { ++ // record fifo1 descriptors' start address ++ camera_context->fifo2_descriptors_virtual = (unsigned)cur_des_virtual; ++ camera_context->fifo2_descriptors_physical = (unsigned)cur_des_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo2_transfer_size; ++ ++ target_page_num = camera_context->pages_per_block * i + ++ camera_context->pages_per_fifo0 + ++ camera_context->pages_per_fifo1; ++ ++ for(j=0; j<camera_context->fifo2_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR2_PHY; // FIFO2 physical address ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo2_descriptors_physical); ++ } ++ ++ dbg_print(" success!"); ++ return 0; ++} ++#endif ++void start_dma_transfer(p_camera_context_t camera_context, unsigned block_id) ++{ ++ pxa_dma_desc *des_virtual, *des_physical; ++ /* ++ if(block_id >= camera_context->block_number) ++ { ++ return; ++ } ++ */ ++ // start channel 0 ++ des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual + ++ block_id * camera_context->fifo0_num_descriptors; ++ ++ des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical + ++ block_id * camera_context->fifo0_num_descriptors; ++ ++ DDADR(camera_context->dma_channels[0]) = des_physical; ++ DCSR(camera_context->dma_channels[0]) |= DCSR_RUN; ++ ++ // start channel 1 ++ if(camera_context->fifo1_descriptors_virtual) ++ { ++ des_virtual = (pxa_dma_desc *)camera_context->fifo1_descriptors_virtual + ++ block_id * camera_context->fifo1_num_descriptors; ++ ++ des_physical = (pxa_dma_desc *)camera_context->fifo1_descriptors_physical + ++ block_id * camera_context->fifo1_num_descriptors; ++ ++ DDADR(camera_context->dma_channels[1]) = des_physical; ++ DCSR(camera_context->dma_channels[1]) |= DCSR_RUN; ++ } ++ ++ // start channel 2 ++ if(camera_context->fifo2_descriptors_virtual) ++ { ++ des_virtual = (pxa_dma_desc *)camera_context->fifo2_descriptors_virtual + ++ block_id * camera_context->fifo2_num_descriptors; ++ ++ des_physical = (pxa_dma_desc *)camera_context->fifo2_descriptors_physical + ++ block_id * camera_context->fifo2_num_descriptors; ++ ++ DDADR(camera_context->dma_channels[2]) = des_physical; ++ DCSR(camera_context->dma_channels[2]) |= DCSR_RUN; ++ } ++ ++ camera_context->dma_started = 1; ++} ++ ++void set_still_image_ready(int rdy) ++{ ++ still_image_rdy = rdy; ++} ++void stop_dma_transfer(p_camera_context_t camera_context) ++{ ++ int ch0, ch1, ch2; ++ ++ ch0 = camera_context->dma_channels[0]; ++ ch1 = camera_context->dma_channels[1]; ++ ch2 = camera_context->dma_channels[2]; ++ ++ DCSR(ch0) &= ~DCSR_RUN; ++ DCSR(ch1) &= ~DCSR_RUN; ++ DCSR(ch2) &= ~DCSR_RUN; ++ camera_context->dma_started = 0; ++ ++ return; ++} ++ ++int start_capture(p_camera_context_t camera_context, unsigned int block_id, unsigned int frames) ++{ ++ int status; ++ status = camera_context->camera_functions->start_capture(camera_context, frames); ++ ++ return status; ++} ++ ++/*********************************************************************** ++ * ++ * Init/Deinit APIs ++ * ++ ***********************************************************************/ ++int camera_init(p_camera_context_t camera_context) ++{ ++ int ret=0; ++ dbg_print(""); ++ ++ /*init gpio pins*/ ++ //camera_gpio_init(); ++ ++ /*init cif*/ ++ // ci_init(); ++ ++ /*init sensor */ ++ if(detected_sensor_type == 0) { ++ /* test sensor type */ ++#ifdef CONFIG_ARCH_EZX_E680 ++ camera_context->camera_functions = &e680_camera_func; ++ if((ret = camera_context->camera_functions->init(camera_context)) ==0) ++ { ++ goto test_success; ++ } ++#endif ++#ifdef CONFIG_ARCH_EZX_A780 ++ ++ #ifdef CONFIG_CAMERA_MT9M111 ++ camera_context->camera_functions = &mt9m111_func; ++ if((ret = camera_context->camera_functions->init(camera_context)) ==0) ++ { ++ goto test_success; ++ } ++ #endif ++ ++ #ifdef CONFIG_CAMERA_ADCM3800 ++ dbg_print("detect ADCM3800..."); ++ camera_context->camera_functions = &camera_adcm3800_func; ++ if((ret = camera_context->camera_functions->init(camera_context)) ==0) ++ { ++ goto test_success; ++ } ++ #endif ++ ++ #ifdef CONFIG_CAMERA_OV9650 ++ dbg_print("detect OV9650..."); ++ camera_context->camera_functions = &camera_ov9650_func; ++ if((ret = camera_context->camera_functions->init(camera_context)) ==0) ++ { ++ goto test_success; ++ } ++ #endif ++ ++ #ifdef CONFIG_CAMERA_OV9640 ++ camera_context->camera_functions = &ov9640_func; ++ if((ret = camera_context->camera_functions->init(camera_context)) ==0) ++ { ++ goto test_success; ++ } ++ #endif ++ ++#endif ++ ++ camera_context->camera_functions = 0; ++ ++ dbg_print("camera function init error!!"); ++ goto camera_init_err; ++ } ++ else ++ { ++ switch (detected_sensor_type) { ++#ifdef CONFIG_ARCH_EZX_E680 ++ case CAMERA_TYPE_ADCM_2700: ++ camera_context->camera_functions = &e680_camera_func; ++ break; ++ case CAMERA_TYPE_MT9V111: ++ camera_context->camera_functions = &e680_camera_func; ++ break; ++#endif ++#ifdef CONFIG_ARCH_EZX_A780 ++ #ifdef CONFIG_CAMERA_OV9640 ++ case CAMERA_TYPE_OMNIVISION_9640: ++ camera_context->camera_functions = &ov9640_func; ++ break; ++ #endif ++ #ifdef CONFIG_CAMERA_MT9M111 ++ case CAMERA_TYPE_MT9M111: ++ camera_context->camera_functions = &mt9m111_func; ++ break; ++ #endif ++ #ifdef CONFIG_CAMERA_ADCM3800 ++ case CAMERA_TYPE_ADCM3800: ++ camera_context->camera_functions = &camera_adcm3800_func; ++ break; ++ #endif ++ #ifdef CONFIG_CAMERA_OV9650 ++ case CAMERA_TYPE_OV9650: ++ camera_context->camera_functions = &camera_ov9650_func; ++ break; ++ #endif ++#endif ++ } ++ camera_context->camera_functions->init(camera_context); ++ } ++test_success: ++ camera_context->dma_channels[0] = ci_dma_y; ++ camera_context->dma_channels[1] = ci_dma_cb; ++ camera_context->dma_channels[2] = ci_dma_cr; ++ DRCMR68 = ci_dma_y | DRCMR_MAPVLD; ++ DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; ++ DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; ++ ++ detected_sensor_type = camera_context->sensor_type; ++#ifdef DEBUG ++ ci_dump(); ++#endif ++ return 0; ++ ++camera_init_err: ++ camera_deinit(camera_context); ++ return -1; ++} ++ ++void camera_gpio_init() ++{ ++ ++ pxa_gpio_mode( CIF_PD_MD ); /*CIF_PD*/ ++ GPCR(CIF_PD) = GPIO_bit(CIF_PD); /*set to low*/ ++ pxa_gpio_mode( CIF_RST_MD ); /*CIF_RST*/ ++ GPSR(CIF_RST) = GPIO_bit(CIF_RST); /*set to high*/ ++ ++ pxa_gpio_mode( CIF_DD0_MD ); /* CIF_DD[0] */ ++ pxa_gpio_mode( CIF_DD1_MD ); /* CIF_DD[1] */ ++ pxa_gpio_mode( CIF_DD2_MD ); /* CIF_DD[2] */ ++ pxa_gpio_mode( CIF_DD3_MD ); /* CIF_DD[3] */ ++ pxa_gpio_mode( CIF_DD4_MD ); /* CIF_DD[4] */ ++ pxa_gpio_mode( CIF_DD5_MD ); /* CIF_DD[5] */ ++ pxa_gpio_mode( CIF_DD6_MD ); /* CIF_DD[6] */ ++ pxa_gpio_mode( CIF_DD7_MD ); /* CIF_DD[7] */ ++ pxa_gpio_mode( CIF_MCLK_MD ); /* CIF_MCLK */ ++ pxa_gpio_mode( CIF_PCLK_MD ); /* CIF_PCLK */ ++ pxa_gpio_mode( CIF_LV_MD ); /* CIF_LV */ ++ pxa_gpio_mode( CIF_FV_MD ); /* CIF_FV */ ++} ++ ++ ++void camera_gpio_deinit() ++{ ++ /* Turn off M_VCC CIF_PD*/ ++ GPSR(CIF_PD) = GPIO_bit(CIF_PD); /* Set PD to low */ ++ pxa_gpio_mode( CIF_MCLK | GPIO_IN); /*trun off MCLK*/ ++} ++ ++int camera_deinit( p_camera_context_t camera_context ) ++{ ++ // deinit sensor ++ if(camera_context->camera_functions) ++ camera_context->camera_functions->deinit(camera_context); ++ ++ // capture interface deinit ++ ci_deinit(); ++ //camera_gpio_deinit(); ++ return 0; ++} ++ ++int camera_ring_buf_init(p_camera_context_t camera_context) ++{ ++ unsigned frame_size; ++ dbg_print(""); ++ switch(camera_context->capture_output_format) ++ { ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 2; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 2; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 2; ++ camera_context->fifo0_transfer_size = frame_size / 2; ++ camera_context->fifo1_transfer_size = frame_size / 4; ++ camera_context->fifo2_transfer_size = frame_size / 4; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB666_PLANAR: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 4; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB666_PACKED: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 3; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ default: ++ return STATUS_WRONG_PARAMETER; ++ break; ++ } ++ ++ camera_context->block_size = frame_size; ++ ++ camera_context->pages_per_fifo0 = ++ (PAGE_ALIGN(camera_context->fifo0_transfer_size) / PAGE_SIZE); ++ camera_context->pages_per_fifo1 = ++ (PAGE_ALIGN(camera_context->fifo1_transfer_size) / PAGE_SIZE); ++ camera_context->pages_per_fifo2 = ++ (PAGE_ALIGN(camera_context->fifo2_transfer_size) / PAGE_SIZE); ++ ++ camera_context->pages_per_block = ++ camera_context->pages_per_fifo0 + ++ camera_context->pages_per_fifo1 + ++ camera_context->pages_per_fifo2; ++ ++ camera_context->page_aligned_block_size = ++ camera_context->pages_per_block * PAGE_SIZE; ++ ++ camera_context->block_number_max = ++ camera_context->pages_allocated / ++ camera_context->pages_per_block; ++ ++ ++ //restrict max block number ++ if(camera_context->block_number_max > FRAMES_IN_BUFFER) ++ { ++ camera_context->block_number = FRAMES_IN_BUFFER; ++ } ++ else ++ { ++ camera_context->block_number = camera_context->block_number_max; ++ } ++ camera_context->block_header = camera_context->block_tail = 0; ++ // generate dma descriptor chain ++ return update_dma_chain(camera_context); ++ ++} ++/*********************************************************************** ++ * ++ * Capture APIs ++ * ++ ***********************************************************************/ ++// Set the image format ++int camera_set_capture_format(p_camera_context_t camera_context) ++{ ++ ++ int status=-1; ++ CI_IMAGE_FORMAT ci_input_format, ci_output_format; ++ CI_MP_TIMING timing; ++ ++ if(camera_context->capture_input_format > CAMERA_IMAGE_FORMAT_MAX || ++ camera_context->capture_output_format > CAMERA_IMAGE_FORMAT_MAX ) ++ { ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ ci_input_format = FORMAT_MAPPINGS[camera_context->capture_input_format]; ++ ci_output_format = FORMAT_MAPPINGS[camera_context->capture_output_format]; ++ ++ if(ci_input_format == CI_INVALID_FORMAT || ci_output_format == CI_INVALID_FORMAT) ++ { ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ ci_set_image_format(ci_input_format, ci_output_format); ++ ++ ++ timing.BFW = 0; ++ timing.BLW = 0; ++ ++ ci_configure_mp(camera_context->capture_width-1, camera_context->capture_height-1, &timing); ++ ++ if(camera_context == NULL || camera_context->camera_functions == NULL || ++ camera_context->camera_functions->set_capture_format == NULL) ++ { ++ dbg_print("camera_context point NULL!!!"); ++ return -1; ++ } ++ status = camera_ring_buf_init(camera_context); ++ // set sensor setting ++ if(camera_context->camera_functions->set_capture_format(camera_context)) ++ { ++ return -1; ++ } ++ ++ // ring buffer init ++ return status; ++ ++} ++ ++// take a picture and copy it into the ring buffer ++int camera_capture_still_image(p_camera_context_t camera_context, unsigned int block_id) ++{ ++ // init buffer status & capture ++ camera_set_int_mask(camera_context, 0x3ff | 0x0400); ++ still_image_mode = 1; ++ first_video_frame = 0; ++ task_waiting = 0; ++ camera_context->block_header = camera_context->block_tail = block_id; ++ camera_context->capture_status = 0; ++ still_image_rdy = 0; ++ return start_capture(camera_context, block_id, 1); ++ ++} ++ ++// capture motion video and copy it to the ring buffer ++int camera_start_video_capture( p_camera_context_t camera_context, unsigned int block_id ) ++{ ++ //init buffer status & capture ++ camera_set_int_mask(camera_context, 0x3ff | 0x0400); ++ still_image_mode = 0; ++ first_video_frame = 1; ++ camera_context->block_header = camera_context->block_tail = block_id; ++ camera_context->capture_status = CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS; ++ return start_capture(camera_context, block_id, 0); ++} ++ ++// disable motion video image capture ++void camera_stop_video_capture( p_camera_context_t camera_context ) ++{ ++ ++ //stop capture ++ camera_context->camera_functions->stop_capture(camera_context); ++ ++ //stop dma ++ stop_dma_transfer(camera_context); ++ ++ //update the flag ++ if(!(camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ { ++ camera_context->capture_status &= ~CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS; ++ } ++} ++ ++ ++/*********************************************************************** ++ * ++ * Flow Control APIs ++ * ++ ***********************************************************************/ ++// continue capture image to next available buffer ++void camera_continue_transfer( p_camera_context_t camera_context ) ++{ ++ // don't think we need this either. JR ++ // continue transfer on next block ++ start_dma_transfer( camera_context, camera_context->block_tail ); ++} ++ ++// Return 1: there is available buffer, 0: buffer is full ++int camera_next_buffer_available( p_camera_context_t camera_context ) ++{ ++ camera_context->block_header = (camera_context->block_header + 1) % camera_context->block_number; ++ if(((camera_context->block_header + 1) % camera_context->block_number) != camera_context->block_tail) ++ { ++ return 1; ++ } ++ ++ camera_context->capture_status |= CAMERA_STATUS_RING_BUFFER_FULL; ++ return 0; ++} ++ ++// Application supplies the FrameBufferID to the driver to tell it that the application has completed processing of ++// the given frame buffer, and that buffer is now available for re-use. ++void camera_release_frame_buffer(p_camera_context_t camera_context, unsigned int frame_buffer_id) ++{ ++ ++ camera_context->block_tail = (camera_context->block_tail + 1) % camera_context->block_number; ++ ++ // restart video capture only ifvideo capture is in progress and space is available for image capture ++ if((camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL ) && ++ (camera_context->capture_status & CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS)) ++ { ++ if(((camera_context->block_header + 2) % camera_context->block_number) != camera_context->block_tail) ++ { ++ camera_context->capture_status &= ~CAMERA_STATUS_RING_BUFFER_FULL; ++ start_capture(camera_context, camera_context->block_tail, 0); ++ } ++ } ++} ++ ++// Returns the FrameBufferID for the first filled frame ++// Note: -1 represents buffer empty ++int camera_get_first_frame_buffer_id(p_camera_context_t camera_context) ++{ ++ // not sure ifthis routine makes any sense.. JR ++ ++ // check whether buffer is empty ++ if((camera_context->block_header == camera_context->block_tail) && ++ !(camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ { ++ return -1; ++ } ++ ++ // return the block header ++ return camera_context->block_header; ++} ++ ++// Returns the FrameBufferID for the last filled frame, this would be used ifwe were polling for image completion data, ++// or we wanted to make sure there were no frames waiting for us to process. ++// Note: -1 represents buffer empty ++int camera_get_last_frame_buffer_id(p_camera_context_t camera_context) ++{ ++ ++ // check whether buffer is empty ++ if((camera_context->block_header == camera_context->block_tail) && ++ !(camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ { ++ return -1; ++ } ++ ++ // return the block before the block_tail ++ return (camera_context->block_tail + camera_context->block_number - 1) % camera_context->block_number; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Buffer Info APIs ++ * ++ ***********************************************************************/ ++// Return: the number of frame buffers allocated for use. ++unsigned int camera_get_num_frame_buffers(p_camera_context_t camera_context) ++{ ++ return camera_context->block_number; ++} ++ ++// FrameBufferID is a number between 0 and N-1, where N is the total number of frame buffers in use. Returns the address of ++// the given frame buffer. The application will call this once for each frame buffer at application initialization only. ++void * camera_get_frame_buffer_addr(p_camera_context_t camera_context, unsigned int frame_buffer_id) ++{ ++ return (void*)((unsigned)camera_context->buffer_virtual + ++ camera_context->page_aligned_block_size * frame_buffer_id); ++} ++ ++// Return the block id ++int camera_get_frame_buffer_id(p_camera_context_t camera_context, void* address) ++{ ++ if(((unsigned)address >= (unsigned)camera_context->buffer_virtual) && ++ ((unsigned)address <= (unsigned)camera_context->buffer_virtual + camera_context->buf_size)) ++ { ++ return ((unsigned)address - ++ (unsigned)camera_context->buffer_virtual) / ++ camera_context->page_aligned_block_size; ++ } ++ ++ return -1; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Frame rate APIs ++ * ++ ***********************************************************************/ ++// Set desired frame rate ++void camera_set_capture_frame_rate(p_camera_context_t camera_context) ++{ ++ ci_set_frame_rate(camera_context->fps); ++} ++ ++// return current setting ++void camera_get_capture_frame_rate(p_camera_context_t camera_context) ++{ ++ camera_context->fps = ci_get_frame_rate(); ++} ++ ++ ++/*********************************************************************** ++ * ++ * Interrupt APIs ++ * ++ ***********************************************************************/ ++// set interrupt mask ++void camera_set_int_mask(p_camera_context_t cam_ctx, unsigned int mask) ++{ ++ pxa_dma_desc * end_des_virtual; ++ int dma_interrupt_on, i; ++ ++ // set CI interrupt ++ ci_set_int_mask( mask & CI_CICR0_INTERRUPT_MASK ); ++ ++ // set dma end interrupt ++ if( mask & CAMERA_INTMASK_END_OF_DMA ) ++ dma_interrupt_on = 1; ++ else ++ dma_interrupt_on = 0; ++ ++ // set fifo0 dma chains' flag ++ end_des_virtual = (pxa_dma_desc*)cam_ctx->fifo0_descriptors_virtual + cam_ctx->fifo0_num_descriptors - 1; ++ ++ for(i=0; i<cam_ctx->block_number; i++) ++ { ++ if(dma_interrupt_on) ++ end_des_virtual->dcmd |= DCMD_ENDIRQEN; ++ else ++ end_des_virtual->dcmd &= ~DCMD_ENDIRQEN; ++ ++ end_des_virtual += cam_ctx->fifo0_num_descriptors; ++ } ++} ++ ++// get interrupt mask ++unsigned int camera_get_int_mask(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *end_des_virtual; ++ unsigned int ret; ++ ++ // get CI mask ++ ret = ci_get_int_mask(); ++ ++ // get dma end mask ++ end_des_virtual = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + cam_ctx->fifo0_num_descriptors - 1; ++ ++ if(end_des_virtual->dcmd & DCMD_ENDIRQEN) ++ { ++ ret |= CAMERA_INTMASK_END_OF_DMA; ++ } ++ return ret; ++} ++ ++// clear interrupt status ++void camera_clear_int_status( p_camera_context_t camera_context, unsigned int status ) ++{ ++ ci_clear_int_status( (status & 0xFFFF) ); ++} ++ ++static void camera_free_dma_irq() ++{ ++ if(ci_dma_y>=0) ++ { ++ pxa_free_dma(ci_dma_y); ++ ci_dma_y = 0; ++ } ++ if(ci_dma_cb>=0) ++ { ++ pxa_free_dma(ci_dma_cb); ++ ci_dma_cb = 0; ++ } ++ if(ci_dma_cr>=0) ++ { ++ pxa_free_dma(ci_dma_cr); ++ ci_dma_cr = 0; ++ } ++ DRCMR68 = 0; ++ DRCMR69 = 0; ++ DRCMR70 = 0; ++} ++/*********************************************************************************** ++* Application interface * ++***********************************************************************************/ ++//static int pxa_camera_open(struct video_device *dev, int flags) ++static int pxa_camera_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ camera_context_t *cam_ctx; ++ dbg_print("start..."); ++ /* ++ According to Peter's suggestion, move the code of request camera IRQ and DMQ channel to here ++ */ ++ /* 1. mapping CI registers, so that we can access the CI */ ++ ++ ci_dma_y = pxa_request_dma("CI_Y",DMA_PRIO_HIGH, pxa_ci_dma_irq_y, &vd); ++ if(ci_dma_y < 0) ++ { ++ camera_free_dma_irq(); ++ dbg_print( "PXA_CAMERA: Cann't request DMA for Y\n"); ++ return -EIO; ++ } ++ dbg_print( "PXA_CAMERA: Request DMA for Y successfully [%d]\n",ci_dma_y); ++ ++ ci_dma_cb = pxa_request_dma("CI_Cb",DMA_PRIO_HIGH, pxa_ci_dma_irq_cb, &vd); ++ if(ci_dma_cb < 0) ++ { ++ camera_free_dma_irq(); ++ dbg_print( "PXA_CAMERA: Cann't request DMA for Cb\n"); ++ return -EIO; ++ } ++ dbg_print( "PXA_CAMERA: Request DMA for Cb successfully [%d]\n",ci_dma_cb); ++ ++ ci_dma_cr = pxa_request_dma("CI_Cr",DMA_PRIO_HIGH, pxa_ci_dma_irq_cr, &vd); ++ if(ci_dma_cr < 0) ++ { ++ camera_free_dma_irq(); ++ dbg_print( "PXA_CAMERA: Cann't request DMA for Cr\n"); ++ return -EIO; ++ } ++ ++ dbg_print( "PXA_CAMERA: Request DMA for Cr successfully [%d]\n",ci_dma_cr); ++ ++ DRCMR68 = ci_dma_y | DRCMR_MAPVLD; ++ DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; ++ DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; ++ ++ ++ init_waitqueue_head(&camera_wait_q); ++ ++ /*alloc memory for camera context*/ ++ if(pxa_camera_mem_init()) ++ { ++ camera_free_dma_irq(); ++ dbg_print("memory allocate failed!"); ++ return -1; ++ } ++ ++ cam_ctx = g_camera_context; ++ ++ /* ++ camera_init call init function for E680 ++ */ ++ if(camera_init(cam_ctx)) ++ { ++ dbg_print("camera_init faile!"); ++ camera_free_dma_irq(); ++ pxa_camera_mem_deinit(); ++ return -1; ++ } ++ ++ /* ++ allocate memory for dma descriptors ++ init function of each sensor should set proper value for cam_ctx->buf_size ++ */ ++ cam_ctx->dma_started = 0; ++ cam_ctx->dma_descriptors_virtual = consistent_alloc(GFP_KERNEL, ++ (cam_ctx->dma_descriptors_size) * sizeof(pxa_dma_desc), ++ (void *)&(cam_ctx->dma_descriptors_physical)); ++ if(cam_ctx->dma_descriptors_virtual == NULL) ++ { ++ dbg_print("consistent alloc memory for dma_descriptors_virtual fail!"); ++ camera_free_dma_irq(); ++ pxa_camera_mem_deinit(); ++ return -1; ++ } ++ ++ ++ /* ++ alloc memory for picture buffer ++ init function of each sensor should set proper value for cam_ctx->buf_size ++ */ ++ if(pxa_dma_buffer_init(cam_ctx) != 0) ++ { ++ dbg_print("alloc memory for buffer_virtual %d bytes fail!", g_camera_context->buf_size); ++ camera_free_dma_irq(); ++ pxa_camera_mem_deinit(); ++ return -1; ++ } ++ ++ /* ++ set default size and capture format ++ init function of each sensor should set proper value ++ for capture_width, capture_height, etc. of camera context ++ */ ++ if(camera_set_capture_format(cam_ctx) != 0) ++ { ++ dbg_print("camera function init error! capture format!"); ++ camera_free_dma_irq(); ++ pxa_camera_mem_deinit(); ++ return -1; ++ } ++ dbg_print("PXA_CAMERA: pxa_camera_open success!"); ++ return 0; ++} ++ ++//static void pxa_camera_close(struct video_device *dev) ++static int pxa_camera_close(struct inode *inode, struct file *file) ++{ ++ camera_deinit(g_camera_context); ++ pxa_camera_mem_deinit(); ++ camera_free_dma_irq(); ++ dbg_print("PXA_CAMERA: pxa_camera_close\n"); ++} ++ ++#define PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, size) \ ++do { \ ++ unsigned int len; \ ++ unsigned int remain_size = size; \ ++ while (remain_size > 0) { \ ++ if(remain_size > PAGE_SIZE) \ ++ len = PAGE_SIZE; \ ++ else \ ++ len = remain_size; \ ++ if(copy_to_user(buf, page_address(*p_page), len)) \ ++ return -EFAULT; \ ++ remain_size -= len; \ ++ buf += len; \ ++ p_page++; \ ++ } \ ++} while (0); ++ ++static ssize_t pxa_camera_write(struct file *file, const char __user *data, ++ size_t count, loff_t *ppos) ++{ ++ return -EINVAL; ++} ++ ++static ssize_t pxa_camera_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ ++ struct page **p_page; ++ ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ if(still_image_mode == 1 && still_image_rdy == 1) ++ { ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo0_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo1_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo2_transfer_size); ++ ++ still_image_rdy = 0; ++ return cam_ctx->block_size; ++ } ++ ++ if(still_image_mode == 0) ++ { ++ if(first_video_frame == 1) ++ cam_ctx->block_tail = cam_ctx->block_header; ++ else ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ } ++ ++ first_video_frame = 0; ++ ++ if(cam_ctx->block_header == cam_ctx->block_tail) ++ { ++ task_waiting = 1; ++ interruptible_sleep_on (&camera_wait_q); ++ } ++ ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo0_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo1_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo2_transfer_size); ++ ++ return cam_ctx->block_size; ++} ++ ++struct reg_set_s ++{ ++ int val1; ++ int val2; ++}; ++ ++/*ioctl sub functions*/ ++static int pxa_camera_VIDIOCGCAP(p_camera_context_t cam_ctx, void * param) ++{ ++ dbg_print("VIDIOCGCAP"); ++ /* ++ add a vc member to camera context ++ */ ++ if(copy_to_user(param, &(cam_ctx->vc), sizeof(struct video_capability))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_VIDIOCGWIN(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_window vw; ++ dbg_print("VIDIOCGWIN"); ++ vw.width = cam_ctx->capture_width; ++ vw.height = cam_ctx->capture_height; ++ if(copy_to_user(param, &vw, sizeof(struct video_window))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_VIDIOCSWIN(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_window vw; ++ dbg_print("VIDIOCSWIN"); ++ if(copy_from_user(&vw, param, sizeof(vw))) ++ { ++ dbg_print("VIDIOCSWIN get parameter error!"); ++ return -EFAULT; ++ } ++ ++ if(vw.width > cam_ctx->vc.maxwidth || ++ vw.height > cam_ctx->vc.maxheight || ++ vw.width < cam_ctx->vc.minwidth || ++ vw.height < cam_ctx->vc.minheight) ++ { ++ dbg_print("VIDIOCSWIN error parameter!"); ++ dbg_print("vw.width:%d, MAX_WIDTH:%d, MIN_WIDTH:%d", vw.width, cam_ctx->vc.maxwidth, cam_ctx->vc.minwidth); ++ dbg_print("vw.height:%d, MAX_HEIGHT:%d, MIN_HEIGHT:%d", vw.width, cam_ctx->vc.maxheight, cam_ctx->vc.minheight); ++ return -EFAULT; ++ } ++ ++ //make it in an even multiple of 8 ++ ++ cam_ctx->capture_width = (vw.width+7)/8; ++ cam_ctx->capture_width *= 8; ++ ++ cam_ctx->capture_height = (vw.height+7)/8; ++ cam_ctx->capture_height *= 8; ++ ++ return camera_set_capture_format(cam_ctx); ++} ++static int pxa_camera_VIDIOCSPICT(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_picture vp; ++ dbg_print("VIDIOCSPICT"); ++ if(copy_from_user(&vp, param, sizeof(vp))) ++ { ++ return -EFAULT; ++ } ++ cam_ctx->capture_output_format = vp.palette; ++ ++ return camera_set_capture_format(cam_ctx); ++ ++} ++ ++static int pxa_camera_VIDIOCGPICT(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_picture vp; ++ dbg_print("VIDIOCGPICT"); ++ vp.palette = cam_ctx->capture_output_format; ++ if(copy_to_user(param, &vp, sizeof(struct video_picture))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_VIDIOCCAPTURE(p_camera_context_t cam_ctx, void * param) ++{ ++ int capture_flag = (int)param; ++ dbg_print("VIDIOCCAPTURE"); ++ if(capture_flag > 0) ++ { ++ dbg_print("Still Image capture!"); ++ camera_capture_still_image(cam_ctx, 0); ++ } ++ else if(capture_flag == 0) ++ { ++ dbg_print("Video Image capture!"); ++ camera_start_video_capture(cam_ctx, 0); ++ } ++ else if(capture_flag == -1) ++ { ++ dbg_print("Capture stop!"); ++ camera_set_int_mask(cam_ctx, 0x3ff); ++ camera_stop_video_capture(cam_ctx); ++ } ++ else ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_VIDIOCGMBUF(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_mbuf vm; ++ int i; ++ ++ dbg_print("VIDIOCGMBUF"); ++ ++ memset(&vm, 0, sizeof(vm)); ++ vm.size = cam_ctx->buf_size; ++ vm.frames = cam_ctx->block_number; ++ for(i = 0; i < vm.frames; i++) ++ { ++ vm.offsets[i] = cam_ctx->page_aligned_block_size * i; ++ } ++ if(copy_to_user((void *)param, (void *)&vm, sizeof(vm))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_WCAM_VIDIOCSINFOR(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ struct reg_set_s reg_s; ++ int ret; ++ dbg_print("WCAM_VIDIOCSINFOR"); ++ ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ ++ cam_ctx->capture_input_format = reg_s.val1; ++ cam_ctx->capture_output_format = reg_s.val2; ++ ret=camera_set_capture_format(cam_ctx); ++ return ret; ++} ++static int pxa_camera_WCAM_VIDIOCGINFOR(p_camera_context_t cam_ctx, void * param) ++{ ++ struct reg_set_s reg_s; ++ dbg_print("WCAM_VIDIOCGINFOR"); ++ reg_s.val1 = cam_ctx->capture_input_format; ++ reg_s.val2 = cam_ctx->capture_output_format; ++ if(copy_to_user(param, ®_s, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_WCAM_VIDIOCGCIREG(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ int reg_value, offset; ++ dbg_print("WCAM_VIDIOCGCIREG"); ++ if(copy_from_user(&offset, param, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ reg_value = ci_get_reg_value (offset); ++ if(copy_to_user(param, ®_value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_WCAM_VIDIOCSCIREG(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ struct reg_set_s reg_s; ++ dbg_print("WCAM_VIDIOCSCIREG"); ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ ci_set_reg_value (reg_s.val1, reg_s.val2); ++ return 0; ++ ++} ++ ++/*get sensor size */ ++static int pxa_cam_WCAM_VIDIOCGSSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ struct adcm_window_size{u16 width, height;} size; ++ dbg_print("WCAM_VIDIOCGSSIZE"); ++ size.width = cam_ctx->sensor_width; ++ size.height = cam_ctx->sensor_height; ++ ++ if(copy_to_user(param, &size, sizeof(struct adcm_window_size))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/*get output size*/ ++static int pxa_cam_WCAM_VIDIOCGOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ struct adcm_window_size{u16 width, height;}size; ++ dbg_print("WCAM_VIDIOCGOSIZE"); ++ size.width = cam_ctx->capture_width; ++ size.height = cam_ctx->capture_height; ++ if(copy_to_user(param, &size, sizeof(struct adcm_window_size))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++ ++ ++/*set frame buffer count*/ ++static int pxa_cam_WCAM_VIDIOCSBUFCOUNT(p_camera_context_t cam_ctx, void * param) ++{ ++ int count; ++ dbg_print(""); ++ if (copy_from_user(&count, param, sizeof(int))) ++ return -EFAULT; ++ ++ if(cam_ctx->block_number_max == 0) { ++ dbg_print("windows size or format not setting!!"); ++ return -EFAULT; ++ } ++ ++ if(count < FRAMES_IN_BUFFER) ++ { ++ count = FRAMES_IN_BUFFER; ++ } ++ ++ if(count > cam_ctx->block_number_max) ++ { ++ count = cam_ctx->block_number_max; ++ } ++ ++ ++ cam_ctx->block_number = count; ++ cam_ctx->block_header = cam_ctx->block_tail = 0; ++ //generate dma descriptor chain ++ update_dma_chain(cam_ctx); ++ ++ if(copy_to_user(param, &count, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*get cur avaliable frames*/ ++static int pxa_cam_WCAM_VIDIOCGCURFRMS(p_camera_context_t cam_ctx, void * param) ++{ ++ //dbg_print(""); ++ struct {int first, last;}pos; ++ ++ pos.first = cam_ctx->block_tail; ++ pos.last = cam_ctx->block_header; ++ ++ if(copy_to_user(param, &pos, sizeof(pos))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/*get sensor type*/ ++static int pxa_cam_WCAM_VIDIOCGSTYPE(p_camera_context_t cam_ctx, void * param) ++{ ++ dbg_print(""); ++ if(copy_to_user(param, &(cam_ctx->sensor_type), sizeof(cam_ctx->sensor_type))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ void *param = (void *) arg; ++ ++ switch (cmd) ++ { ++ /*get capture capability*/ ++ case VIDIOCGCAP: ++ return pxa_camera_VIDIOCGCAP(g_camera_context, param); ++ /* get capture size */ ++ case VIDIOCGWIN: ++ return pxa_camera_VIDIOCGWIN(g_camera_context, param); ++ ++ /* set capture size. */ ++ case VIDIOCSWIN: ++ return pxa_camera_VIDIOCSWIN(g_camera_context, param); ++ /*set capture output format*/ ++ case VIDIOCSPICT: ++ return pxa_camera_VIDIOCSPICT(g_camera_context, param); ++ ++ /*get capture output format*/ ++ case VIDIOCGPICT: ++ return pxa_camera_VIDIOCGPICT(g_camera_context, param); ++ ++ /*start capture */ ++ case VIDIOCCAPTURE: ++ return pxa_camera_VIDIOCCAPTURE(g_camera_context, param); ++ ++ /* mmap interface */ ++ case VIDIOCGMBUF: ++ return pxa_camera_VIDIOCGMBUF(g_camera_context, param); ++ ++ /* Application extended IOCTL. */ ++ /* Register access interface */ ++ case WCAM_VIDIOCSINFOR: ++ return pxa_camera_WCAM_VIDIOCSINFOR(g_camera_context, param); ++ ++ /*get capture format*/ ++ case WCAM_VIDIOCGINFOR: ++ return pxa_camera_WCAM_VIDIOCGINFOR(g_camera_context, param); ++ ++ /*get ci reg value*/ ++ case WCAM_VIDIOCGCIREG: ++ return pxa_camera_WCAM_VIDIOCGCIREG(g_camera_context, param); ++ ++ /*set ci reg*/ ++ case WCAM_VIDIOCSCIREG: ++ return pxa_camera_WCAM_VIDIOCSCIREG(g_camera_context, param); ++ ++ /*get sensor size */ ++ case WCAM_VIDIOCGSSIZE: ++ return pxa_cam_WCAM_VIDIOCGSSIZE(g_camera_context, param); ++ ++ /*get output size*/ ++ case WCAM_VIDIOCGOSIZE: ++ return pxa_cam_WCAM_VIDIOCGOSIZE(g_camera_context, param); ++ ++ /*set frame buffer count*/ ++ case WCAM_VIDIOCSBUFCOUNT: ++ return pxa_cam_WCAM_VIDIOCSBUFCOUNT(g_camera_context, param); ++ ++ /*get cur avaliable frames*/ ++ case WCAM_VIDIOCGCURFRMS: ++ return pxa_cam_WCAM_VIDIOCGCURFRMS(g_camera_context, param); ++ ++ /*get cur sensor type*/ ++ case WCAM_VIDIOCGSTYPE: ++ return pxa_cam_WCAM_VIDIOCGSTYPE(g_camera_context, param); ++ ++ default: ++ return g_camera_context->camera_functions->command(g_camera_context, cmd, param); ++ } ++ ++ return 0; ++} ++ ++//static int pxa_camera_mmap(struct video_device *dev, const char *adr, unsigned long size) ++static int pxa_camera_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long start = vma->vm_start; ++ unsigned long size = (vma->vm_end - vma->vm_start); ++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; ++ camera_context_t *cam_ctx = g_camera_context; ++ struct page **p_page = cam_ctx->page_array; ++ ++ size = PAGE_ALIGN(size); ++ if (remap_pfn_range(vma, start, page_to_phys(*p_page), size, ++ PAGE_SHARED)) { ++ return -EFAULT; ++ } ++ return 0; ++ } ++ ++static unsigned int pxa_camera_poll(struct file *file, poll_table *wait) ++{ ++ static int waited = 0; ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ poll_wait(file, &camera_wait_q, wait); ++ ++ if(still_image_mode == 1 && still_image_rdy == 1) ++ { ++ still_image_rdy = 0; ++ waited = 0; ++ return POLLIN | POLLRDNORM; ++ } ++ ++ if(first_video_frame == 1) ++ { ++ first_video_frame = 0; ++ } ++ else if(still_image_mode == 0 && waited != 1) ++ { ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ } ++ ++ if(cam_ctx->block_header == cam_ctx->block_tail) ++ { ++ task_waiting = 1; ++ waited = 1; ++ return 0; ++ } ++ waited = 0; ++ return POLLIN | POLLRDNORM; ++} ++ ++int pxa_camera_mem_deinit(void) ++{ ++ if(g_camera_context) ++ { ++ if(g_camera_context->dma_descriptors_virtual != NULL) ++ { ++ consistent_free(g_camera_context->dma_descriptors_virtual, ++ g_camera_context->dma_descriptors_size * sizeof(pxa_dma_desc), ++ (int)g_camera_context->dma_descriptors_physical); ++ ++ g_camera_context->dma_descriptors_virtual = NULL; ++ ++ } ++ if(g_camera_context->buffer_virtual != NULL) ++ { ++ pxa_dma_buffer_free(g_camera_context); ++ g_camera_context->buffer_virtual = NULL; ++ } ++ kfree(g_camera_context); ++ g_camera_context = NULL; ++ } ++ ++ return 0; ++} ++ ++int pxa_camera_mem_init(void) ++{ ++ g_camera_context = kmalloc(sizeof(struct camera_context_s), GFP_KERNEL); ++ ++ if(g_camera_context == NULL) ++ { ++ dbg_print( "PXA_CAMERA: Cann't allocate buffer for camera control structure \n"); ++ return -1; ++ } ++ ++ memset(g_camera_context, 0, sizeof(struct camera_context_s)); ++ ++ dbg_print("success!"); ++ return 0; ++} ++ ++int pxa_camera_video_init(struct video_device *vdev) ++{ ++ return 0; ++} ++ ++ ++static int __init pxa_camera_init(void) ++{ ++ camera_context_t cam_ctx; ++ ++ if (request_irq(IRQ_CAMERA, pxa_camera_irq, 0, "PXA Camera", &vd)) { ++ dbg_print("Camera interrupt register failed failed number \n"); ++ return -EIO; ++ } ++ dbg_print ("Camera interrupt register successful \n"); ++ ++ minor =0 ; ++ ++ if(video_register_device(&vd, VFL_TYPE_GRABBER, minor) < 0) ++ { ++ dbg_print("PXA_CAMERA: video_register_device failed\n"); ++ return -EIO; ++ } ++#ifdef CONFIG_ARCH_EZX_A780 ++ PGSR1 |= GPIO_bit(50); ++ PGSR0 |= GPIO_bit(19); ++#endif ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, camera_pm_callback); ++#endif ++ ++ dbg_print("PXA_CAMERA: video_register_device successfully. /dev/video%d \n",minor); ++ ++ return 0; ++} ++ ++static void __exit pxa_camera_exit(void) ++{ ++ free_irq(IRQ_CAMERA, &vd); ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ ++ video_unregister_device(&vd); ++ ++} ++ ++ ++//------------------------------------------------------------------------------------------------------- ++// Configuration APIs ++//------------------------------------------------------------------------------------------------------- ++void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate) ++{ ++ unsigned int value; ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_FR_RATE_SMASK << CI_CICR4_FR_RATE_SHIFT); ++ value |= (unsigned)frate << CI_CICR4_FR_RATE_SHIFT; ++ CICR4 = value; ++} ++ ++CI_FRAME_CAPTURE_RATE ci_get_frame_rate(void) ++{ ++ unsigned int value; ++ value = CICR4; ++ return (CI_FRAME_CAPTURE_RATE)((value >> CI_CICR4_FR_RATE_SHIFT) & CI_CICR4_FR_RATE_SMASK); ++} ++ ++void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format) ++{ ++ ++ unsigned int value, tbit, rgbt_conv, rgb_conv, rgb_f, ycbcr_f, rgb_bpp, raw_bpp, cspace; ++ // write cicr1: preserve ppl value and data width value ++ dbg_print("0"); ++ value = CICR1; ++ dbg_print("1"); ++ value &= ( (CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT) | ((CI_CICR1_DW_SMASK) << CI_CICR1_DW_SHIFT)); ++ tbit = rgbt_conv = rgb_conv = rgb_f = ycbcr_f = rgb_bpp = raw_bpp = cspace = 0; ++ switch(input_format) ++ { ++ case CI_RAW8: ++ cspace = 0; ++ raw_bpp = 0; ++ break; ++ case CI_RAW9: ++ cspace = 0; ++ raw_bpp = 1; ++ break; ++ case CI_RAW10: ++ cspace = 0; ++ raw_bpp = 2; ++ break; ++ case CI_YCBCR422: ++ case CI_YCBCR422_PLANAR: ++ cspace = 2; ++ if(output_format == CI_YCBCR422_PLANAR) ++ { ++ ycbcr_f = 1; ++ } ++ break; ++ case CI_RGB444: ++ cspace = 1; ++ rgb_bpp = 0; ++ break; ++ case CI_RGB555: ++ cspace = 1; ++ rgb_bpp = 1; ++ if(output_format == CI_RGBT555_0) ++ { ++ rgbt_conv = 2; ++ tbit = 0; ++ } ++ else if(output_format == CI_RGBT555_1) ++ { ++ rgbt_conv = 2; ++ tbit = 1; ++ } ++ break; ++ case CI_RGB565: ++ cspace = 1; ++ rgb_bpp = 2; ++ rgb_f = 1; ++ break; ++ case CI_RGB666: ++ cspace = 1; ++ rgb_bpp = 3; ++ if(output_format == CI_RGB666_PACKED) ++ { ++ rgb_f = 1; ++ } ++ break; ++ case CI_RGB888: ++ case CI_RGB888_PACKED: ++ cspace = 1; ++ rgb_bpp = 4; ++ switch(output_format) ++ { ++ case CI_RGB888_PACKED: ++ rgb_f = 1; ++ break; ++ case CI_RGBT888_0: ++ rgbt_conv = 1; ++ tbit = 0; ++ break; ++ case CI_RGBT888_1: ++ rgbt_conv = 1; ++ tbit = 1; ++ break; ++ case CI_RGB666: ++ rgb_conv = 1; ++ break; ++ // RGB666 PACKED - JamesL ++ case CI_RGB666_PACKED: ++ rgb_conv = 1; ++ rgb_f = 1; ++ break; ++ // end ++ case CI_RGB565: ++ dbg_print("format : 565"); ++ rgb_conv = 2; ++ break; ++ case CI_RGB555: ++ rgb_conv = 3; ++ break; ++ case CI_RGB444: ++ rgb_conv = 4; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ dbg_print("2"); ++ value |= (tbit==1) ? CI_CICR1_TBIT : 0; ++ value |= rgbt_conv << CI_CICR1_RGBT_CONV_SHIFT; ++ value |= rgb_conv << CI_CICR1_RGB_CONV_SHIFT; ++ value |= (rgb_f==1) ? CI_CICR1_RBG_F : 0; ++ value |= (ycbcr_f==1) ? CI_CICR1_YCBCR_F : 0; ++ value |= rgb_bpp << CI_CICR1_RGB_BPP_SHIFT; ++ value |= raw_bpp << CI_CICR1_RAW_BPP_SHIFT; ++ value |= cspace << CI_CICR1_COLOR_SP_SHIFT; ++ CICR1 = value; ++ ++} ++ ++void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width) ++{ ++ unsigned int value; ++ ++ // write mode field in cicr0 ++ value = CICR0; ++ value &= ~(CI_CICR0_SIM_SMASK << CI_CICR0_SIM_SHIFT); ++ value |= (unsigned int)mode << CI_CICR0_SIM_SHIFT; ++ CICR0 = value; ++ ++ // write data width cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_DW_SMASK << CI_CICR1_DW_SHIFT); ++ value |= ((unsigned)data_width) << CI_CICR1_DW_SHIFT; ++ CICR1 = value; ++ return; ++} ++ ++void ci_configure_mp(unsigned int ppl, unsigned int lpf, CI_MP_TIMING* timing) ++{ ++ unsigned int value; ++ // write ppl field in cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); ++ value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; ++ CICR1 = value; ++ ++ // write BLW, ELW in cicr2 ++ value = CICR2; ++ value &= ~(CI_CICR2_BLW_SMASK << CI_CICR2_BLW_SHIFT | CI_CICR2_ELW_SMASK << CI_CICR2_ELW_SHIFT ); ++ value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; ++ CICR2 = value; ++ ++ // write BFW, LPF in cicr3 ++ value = CICR3; ++ value &= ~(CI_CICR3_BFW_SMASK << CI_CICR3_BFW_SHIFT | CI_CICR3_LPF_SMASK << CI_CICR3_LPF_SHIFT ); ++ value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; ++ value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; ++ CICR3 = value; ++ ++} ++ ++void ci_configure_sp(unsigned int ppl, unsigned int lpf, CI_SP_TIMING* timing) ++{ ++ unsigned int value; ++ ++ // write ppl field in cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); ++ value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; ++ CICR1 = value; ++ ++ // write cicr2 ++ value = CICR2; ++ value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; ++ value |= (timing->ELW & CI_CICR2_ELW_SMASK) << CI_CICR2_ELW_SHIFT; ++ value |= (timing->HSW & CI_CICR2_HSW_SMASK) << CI_CICR2_HSW_SHIFT; ++ value |= (timing->BFPW & CI_CICR2_BFPW_SMASK) << CI_CICR2_BFPW_SHIFT; ++ value |= (timing->FSW & CI_CICR2_FSW_SMASK) << CI_CICR2_FSW_SHIFT; ++ CICR2 = value; ++ ++ // write cicr3 ++ value = CICR3; ++ value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; ++ value |= (timing->EFW & CI_CICR3_EFW_SMASK) << CI_CICR3_EFW_SHIFT; ++ value |= (timing->VSW & CI_CICR3_VSW_SMASK) << CI_CICR3_VSW_SHIFT; ++ value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; ++ CICR3 = value; ++ return; ++} ++ ++void ci_configure_ms(unsigned int ppl, unsigned int lpf, CI_MS_TIMING* timing) ++{ ++ // the operation is same as Master-Parallel ++ ci_configure_mp(ppl, lpf, (CI_MP_TIMING*)timing); ++} ++ ++void ci_configure_ep(int parity_check) ++{ ++ unsigned int value; ++ ++ // write parity_enable field in cicr0 ++ value = CICR0; ++ if(parity_check) ++ { ++ value |= CI_CICR0_PAR_EN; ++ } ++ else ++ { ++ value &= ~CI_CICR0_PAR_EN; ++ } ++ CICR0 = value; ++ return; ++} ++ ++void ci_configure_es(int parity_check) ++{ ++ // the operationi is same as Embedded-Parallel ++ ci_configure_ep(parity_check); ++} ++ ++void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz) ++{ ++ unsigned int ciclk, value, div, cccr_l, K; ++ ++ // determine the LCLK frequency programmed into the CCCR. ++ cccr_l = (CCCR & 0x0000001F); ++ ++ if(cccr_l < 8) ++ K = 1; ++ else if(cccr_l < 17) ++ K = 2; ++ else ++ K = 3; ++ ++ ciclk = (13 * cccr_l) / K; ++ ++ div = (ciclk + mclk_khz) / ( 2 * mclk_khz ) - 1; ++ dbg_print("cccr=%xciclk=%d,cccr_l=%d,K=%d,div=%d,mclk=%d\n",CCCR,ciclk,cccr_l,K,div,mclk_khz); ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK<<CI_CICR4_DIV_SHIFT); ++ value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0; ++ value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0; ++ value |= div << CI_CICR4_DIV_SHIFT; ++ CICR4 = value; ++ return; ++} ++ ++void ci_set_polarity(int pclk_sample_falling, int hsync_active_low, int vsync_active_low) ++{ ++ unsigned int value; ++ dbg_print(""); ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCP | CI_CICR4_HSP | CI_CICR4_VSP); ++ value |= (pclk_sample_falling)? CI_CICR4_PCP : 0; ++ value |= (hsync_active_low) ? CI_CICR4_HSP : 0; ++ value |= (vsync_active_low) ? CI_CICR4_VSP : 0; ++ CICR4 = value; ++ return; ++} ++ ++void ci_set_fifo(unsigned int timeout, CI_FIFO_THRESHOLD threshold, int fifo1_enable, ++ int fifo2_enable) ++{ ++ unsigned int value; ++ dbg_print(""); ++ // write citor ++ CITOR = timeout; ++ ++ // write cifr: always enable fifo 0! also reset input fifo ++ value = CIFR; ++ value &= ~(CI_CIFR_FEN0 | CI_CIFR_FEN1 | CI_CIFR_FEN2 | CI_CIFR_RESETF | ++ CI_CIFR_THL_0_SMASK<<CI_CIFR_THL_0_SHIFT); ++ value |= (unsigned int)threshold << CI_CIFR_THL_0_SHIFT; ++ value |= (fifo1_enable) ? CI_CIFR_FEN1 : 0; ++ value |= (fifo2_enable) ? CI_CIFR_FEN2 : 0; ++ value |= CI_CIFR_RESETF | CI_CIFR_FEN0; ++ CIFR = value; ++} ++ ++void ci_reset_fifo() ++{ ++ unsigned int value; ++ value = CIFR; ++ value |= CI_CIFR_RESETF; ++ CIFR = value; ++} ++ ++void ci_set_int_mask(unsigned int mask) ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value &= ~CI_CICR0_INTERRUPT_MASK; ++ value |= (mask & CI_CICR0_INTERRUPT_MASK); ++ dbg_print("-----------value=0x%x\n",value); ++ CICR0 = value; ++ return; ++} ++ ++unsigned int ci_get_int_mask() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ return (value & CI_CICR0_INTERRUPT_MASK); ++} ++ ++void ci_clear_int_status(unsigned int status) ++{ ++ // write 1 to clear ++ CISR = status; ++} ++ ++unsigned int ci_get_int_status() ++{ ++ int value; ++ ++ value = CISR; ++ ++ return value; ++} ++ ++void ci_set_reg_value(unsigned int reg_offset, unsigned int value) ++{ ++ switch(reg_offset) ++ { ++ case 0: ++ CICR0 = value; ++ break; ++ case 1: ++ CICR1 = value; ++ break; ++ case 2: ++ CICR2 = value; ++ break; ++ case 3: ++ CICR3 = value; ++ break; ++ case 4: ++ CICR4 = value; ++ break; ++ case 5: ++ CISR = value; ++ break; ++ case 6: ++ CIFR = value; ++ break; ++ case 7: ++ CITOR = value; ++ break; ++ } ++} ++ ++int ci_get_reg_value(unsigned int reg_offset) ++{ ++ ++ unsigned values[] = {CICR0, CICR1, CICR2, CICR3, CICR4, CISR, CIFR, CITOR}; ++ ++ if(reg_offset >=0 && reg_offset <= 7) ++ return values[reg_offset]; ++ else ++ return CISR; ++} ++ ++//------------------------------------------------------------------------------------------------------- ++// Control APIs ++//------------------------------------------------------------------------------------------------------- ++int ci_init() ++{ ++ ++ // clear all CI registers disable all interrupts ++ CICR0 = 0x3FF; ++ CICR1 = 0; ++ CICR2 = 0; ++ CICR3 = 0; ++ CICR4 = 0; ++ CISR = ~0; ++ CIFR = 0; ++ CITOR = 0; ++ ++ // enable CI clock ++ CKEN |= CKEN24_CAMERA; ++ return 0; ++} ++ ++void ci_deinit() ++{ ++ // disable CI clock ++ CICR4 = 0; ++ mdelay(1); ++ CKEN &= ~CKEN24_CAMERA; ++} ++void ci_reset() ++{ ++ ci_disable(1); ++ ci_enable(1); ++ mdelay(30); ++} ++void ci_enable(int dma_en) ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value |= CI_CICR0_ENB; ++ if(dma_en) { ++ value |= CI_CICR0_DMA_EN; ++ } ++ CICR0 = value; ++ return; ++} ++ ++int ci_disable(int quick) ++{ ++ volatile unsigned int value, mask; ++ int retry; ++ ++ // write control bit in cicr0 ++ value = CICR0; ++ if(quick) ++ { ++ value &= ~CI_CICR0_ENB; ++ mask = CI_CISR_CQD; ++ } ++ else ++ { ++ value |= CI_CICR0_DIS; ++ mask = CI_CISR_CDD; ++ } ++ CICR0 = value; ++ ++ // wait shutdown complete ++ retry = 50; ++ while ( retry-- > 0 ) ++ { ++ value = CISR; ++ if( value & mask ) ++ { ++ CISR = mask; ++ return 0; ++ } ++ mdelay(10); ++ } ++ return -1; ++} ++ ++void ci_slave_capture_enable() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value |= CI_CICR0_SL_CAP_EN; ++ CICR0 = value; ++ return; ++} ++ ++void ci_slave_capture_disable() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value &= ~CI_CICR0_SL_CAP_EN; ++ CICR0 = value; ++ return; ++} ++ ++void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs) ++{ ++ ++ static int dma_repeated = 0; ++ camera_context_t *cam_ctx = g_camera_context; ++ int dcsr; ++ ++ dcsr = DCSR(channel); ++ DCSR(channel) = dcsr & ~DCSR_STOPIRQEN; ++ ++ if(still_image_mode == 1) ++ { ++ if(task_waiting == 1) ++ { ++ wake_up_interruptible (&camera_wait_q); ++ task_waiting = 0; ++ } ++ still_image_rdy = 1; ++ stop_dma_transfer(cam_ctx); ++ } ++ else if(dma_repeated == 0 && ++ (cam_ctx->block_tail == ((cam_ctx->block_header + 2) % cam_ctx->block_number))) ++ { ++ dma_repeated = 1; ++ pxa_dma_repeat(cam_ctx); ++ //dbg_print ("DMA repeated."); ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ } ++ else if(dma_repeated == 1 && ++ (cam_ctx->block_tail != ((cam_ctx->block_header + 1) % cam_ctx->block_number)) && ++ (cam_ctx->block_tail != ((cam_ctx->block_header + 2) % cam_ctx->block_number))) ++ { ++ pxa_dma_continue(cam_ctx); ++ //dbg_print ("DMA continue."); ++ dma_repeated = 0; ++ } ++ else if(dma_repeated == 0) ++ { ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ } ++ ++ if(task_waiting == 1 && !(cam_ctx->block_header == cam_ctx->block_tail)) ++ { ++ wake_up_interruptible (&camera_wait_q); ++ task_waiting = 0; ++ } ++ ++} ++ ++void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs) ++{ ++ return; ++} ++ ++void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs) ++{ ++ return; ++} ++ ++ ++static irqreturn_t pxa_camera_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned int cisr; ++ ++ disable_irq(IRQ_CAMERA); ++ cisr = CISR; ++ ++ if (cisr & CI_CISR_SOF) ++ CISR |= CI_CISR_SOF; ++ ++ if (cisr & CI_CISR_EOF) ++ CISR |= CI_CISR_EOF; ++ ++ enable_irq(IRQ_CAMERA); ++ ++ return IRQ_HANDLED; ++} ++ ++void pxa_dma_repeat(camera_context_t *cam_ctx) ++{ ++ pxa_dma_desc *cnt_head, *cnt_tail; ++ int cnt_block; ++ ++ cnt_block = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ ++ // FIFO0 ++ (pxa_dma_desc *)cnt_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + ++ cnt_block * cam_ctx->fifo0_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ ++ // FIFO1 ++ if(cam_ctx->fifo1_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + ++ cnt_block * cam_ctx->fifo1_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ ++ // FIFO2 ++ if(cam_ctx->fifo2_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + ++ cnt_block * cam_ctx->fifo2_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ } ++ ++void pxa_dma_continue(camera_context_t *cam_ctx) ++{ ++ pxa_dma_desc *cnt_head, *cnt_tail; ++ pxa_dma_desc *next_head; ++ int cnt_block, next_block; ++ ++ cnt_block = cam_ctx->block_header; ++ next_block = (cnt_block + 1) % cam_ctx->block_number; ++ ++ // FIFO0 ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + ++ cnt_block * cam_ctx->fifo0_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; ++ ++ next_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + ++ next_block * cam_ctx->fifo0_num_descriptors; ++ ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ ++ // FIFO1 ++ if(cam_ctx->fifo1_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + ++ cnt_block * cam_ctx->fifo1_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; ++ ++ next_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + ++ next_block * cam_ctx->fifo1_num_descriptors; ++ ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ ++ // FIFO2 ++ if(cam_ctx->fifo2_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + ++ cnt_block * cam_ctx->fifo2_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; ++ ++ next_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + ++ next_block * cam_ctx->fifo2_num_descriptors; ++ ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ return; ++ ++} ++ ++void ci_dump(void) ++{ ++ dbg_print ("CICR0 = 0x%8lx ", CICR0); ++ dbg_print ("CICR1 = 0x%8lx ", CICR1); ++ dbg_print ("CICR2 = 0x%8lx ", CICR2); ++ dbg_print ("CICR3 = 0x%8lx ", CICR3); ++ dbg_print ("CICR4 = 0x%8lx ", CICR4); ++ dbg_print ("CISR = 0x%8lx ", CISR); ++ dbg_print ("CITOR = 0x%8lx ", CITOR); ++ dbg_print ("CIFR = 0x%8lx ", CIFR); ++} ++ ++ ++module_init(pxa_camera_init); ++module_exit(pxa_camera_exit); ++ ++MODULE_DESCRIPTION("Bulverde Camera Interface driver"); ++MODULE_LICENSE("GPL"); ++ +diff -Nurd linux-2.6.16.orig/drivers/media/video/pxa_camera_micron.c linux-2.6.16/drivers/media/video/pxa_camera_micron.c +--- linux-2.6.16.orig/drivers/media/video/pxa_camera_micron.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/pxa_camera_micron.c 2006-06-03 11:14:56.611283032 +0200 +@@ -0,0 +1,2905 @@ ++/*================================================================================ ++ ++ Module Name: pxa-camera.c ++ ++General Description: Camera module mt9m111 source file ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++ ++Portability: Indicate ifthis module is portable to other compilers or ++platforms. If not, indicate specific reasons why is it not portable. ++ ++================================================================================== ++ INCLUDE FILES ++================================================================================*/ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++ ++#include <linux/types.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/arch/irqs.h> ++#include <asm/irq.h> ++ ++ ++#define DEBUG ++#include "camera.h" ++#include "mt9m111.h" ++#include "mt9m111_hw.h" ++ ++#define CIBR0_PHY (0x50000000 + 0x28) ++#define CIBR1_PHY (0x50000000 + 0x30) ++#define CIBR2_PHY (0x50000000 + 0x38) ++ ++#define MAX_WIDTH 1280 ++#define MAX_HEIGHT 1024 ++ ++#define MIN_WIDTH 88 ++#define MIN_HEIGHT 72 ++#define WIDTH_DEFT 320 ++#define HEIGHT_DEFT 240 ++#define FRAMERATE_DEFT 15 ++ ++/* ++ * It is required to have at least 3 frames in buffer ++ * in current implementation ++ */ ++#define FRAMES_IN_BUFFER 3 ++#define BUF_SIZE_DEFT ((PAGE_ALIGN(MAX_WIDTH * MAX_HEIGHT) + (PAGE_ALIGN(MAX_WIDTH*MAX_HEIGHT/2)*2))) ++#define SINGLE_DESC_TRANS_MAX PAGE_SIZE ++#define MAX_DESC_NUM (BUF_SIZE_DEFT/PAGE_SIZE +10) ++ ++#define DRCMR68 __REG(0x40001110) /* Request to Channel Map Register for Camera FIFO 0 Request */ ++#define DRCMR69 __REG(0x40001114) /* Request to Channel Map Register for Camera FIFO 1 Request */ ++#define DRCMR70 __REG(0x40001118) /* Request to Channel Map Register for Camera FIFO 2 Request */ ++ ++static camera_context_t *g_camera_context; ++ ++#ifdef CONFIG_CAMERA_MT9M111 ++static camera_function_t mt9m111_func; ++#endif ++#ifdef CONFIG_CAMERA_OV9640 ++extern camera_function_t ov9640_func; ++#endif ++ ++static int irq_n =0; ++static int camera_irq_n =0; ++wait_queue_head_t camera_wait_q; ++ ++static int waitingFrame = 0; ++ ++/* /dev/videoX registration number */ ++static int minor = 0; ++static int ci_dma_y = -1; ++static int ci_dma_cb = -1; ++static int ci_dma_cr = -1; ++static int task_waiting = 0; ++static int still_image_mode = 0; ++static int still_image_rdy = 0; ++static int first_video_frame = 0; ++ ++void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs); ++void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs); ++void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs); ++ ++static unsigned long ci_regs_base = 0; /* for CI registers IOMEM mapping */ ++ ++#define CI_REG(x) (* (volatile u32*)(x) ) ++#define CI_REG_SIZE 0x40 /* 0x5000_0000 --- 0x5000_0038 * 64K */ ++#define CI_REGS_PHYS 0x50000000 /* Start phyical address of CI registers */ ++ ++/* ++#define CICR0 CI_REG((u32)(ci_regs_base) + 0x00) ++#define CICR1 CI_REG((u32)(ci_regs_base) + 0x04) ++#define CICR2 CI_REG((u32)(ci_regs_base) + 0x08) ++#define CICR3 CI_REG((u32)(ci_regs_base) + 0x0c) ++#define CICR4 CI_REG((u32)(ci_regs_base) + 0x10) ++#define CISR CI_REG((u32)(ci_regs_base) + 0x14) ++#define CIFR CI_REG((u32)(ci_regs_base) + 0x18) ++#define CITOR CI_REG((u32)(ci_regs_base) + 0x1c) ++#define CIBR0 CI_REG((u32)(ci_regs_base) + 0x28) ++#define CIBR1 CI_REG((u32)(ci_regs_base) + 0x30) ++#define CIBR2 CI_REG((u32)(ci_regs_base) + 0x38) ++*/ ++ ++/*********************************************************************** ++ * ++ * Declarations ++ * ++ ***********************************************************************/ ++ ++// map of camera image format (camera.h) ==> capture interface format (ci.h) ++static const CI_IMAGE_FORMAT FORMAT_MAPPINGS[] = { ++ CI_RAW8, //RAW ++ CI_RAW9, ++ CI_RAW10, ++ ++ CI_RGB444, //RGB ++ CI_RGB555, ++ CI_RGB565, ++ CI_RGB666_PACKED, //RGB Packed ++ CI_RGB666, ++ CI_RGB888_PACKED, ++ CI_RGB888, ++ CI_RGBT555_0, //RGB+Transparent bit 0 ++ CI_RGBT888_0, ++ CI_RGBT555_1, //RGB+Transparent bit 1 ++ CI_RGBT888_1, ++ ++ CI_INVALID_FORMAT, ++ CI_YCBCR422, //YCBCR ++ CI_YCBCR422_PLANAR, //YCBCR Planaried ++ CI_INVALID_FORMAT, ++ CI_INVALID_FORMAT ++}; ++ ++static int update_dma_chain(p_camera_context_t camera_context); ++static void start_dma_transfer(p_camera_context_t camera_context, unsigned block_id); ++void stop_dma_transfer(p_camera_context_t camera_context); ++static int start_capture(p_camera_context_t camera_context, unsigned int block_id, unsigned int frames); ++int camera_init(p_camera_context_t camera_context); ++ ++#ifdef CONFIG_PM ++ static struct pm_dev *pm_dev; ++ static int resume_dma = 0; ++#endif ++ ++#ifdef CONFIG_PM ++ ++static int pxa_camera_pm_suspend() ++{ ++ if(g_camera_context != NULL ) ++ { ++ if(g_camera_context->dma_started) ++ { ++ dbg_print("camera running, suspended"); ++ stop_dma_transfer(g_camera_context); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ CKEN &= ~CKEN24_CAMERA; ++ return 0; ++} ++ ++static int pxa_camera_pm_resume() ++{ ++ CKEN |= CKEN24_CAMERA; ++ enable_irq(IRQ_CAMERA); ++ ++ if(g_camera_context != NULL) ++ { ++ dbg_print("camera running, resumed"); ++ micron_window_size size; ++ camera_init(g_camera_context); ++ ++ size.width = g_camera_context->sensor_width; ++ size.height = g_camera_context->sensor_height; ++ mt9m111_input_size(&size); ++ ++ size.width = g_camera_context->capture_width; ++ size.height = g_camera_context->capture_height; ++ mt9m111_output_size(&size); ++ ++ mt9m111_set_bright(g_camera_context->capture_bright); ++ ++ mt9m111_set_fps(g_camera_context->fps, g_camera_context->mini_fps); ++ mt9m111_set_light(g_camera_context->capture_light); ++ mt9m111_set_style(g_camera_context->capture_style); ++ ++ if(resume_dma == 1) ++ { ++ camera_start_video_capture(g_camera_context, 0); ++ resume_dma = 0; ++ } ++ ++ } ++ ++ return 0; ++} ++static int camera_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ pxa_camera_pm_suspend(); ++ break; ++ ++ case PM_RESUME: ++ pxa_camera_pm_resume(); ++ break; ++ ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++/*********************************************************************** ++ * ++ * Private functions ++ * ++ ***********************************************************************/ ++ ++static int pxa_dma_buffer_init(p_camera_context_t camera_context) ++{ ++ struct page *page; ++ unsigned int pages; ++ unsigned int page_count; ++ ++ camera_context->pages_allocated = 0; ++ ++ pages = (PAGE_ALIGN(camera_context->buf_size) / PAGE_SIZE); ++ ++ camera_context->page_array = (struct page **) ++ kmalloc(pages * sizeof(struct page *), ++ GFP_KERNEL); ++ ++ if(camera_context->page_array == NULL) ++ { ++ return -ENOMEM; ++ } ++ memset(camera_context->page_array, 0, pages * sizeof(struct page *)); ++ ++ for(page_count = 0; page_count < pages; page_count++) ++ { ++ page = alloc_page(GFP_KERNEL); ++ if(page == NULL) ++ { ++ goto error; ++ } ++ camera_context->page_array[page_count] = page; ++ set_page_count(page, 1); ++ SetPageReserved(page); ++ } ++ camera_context->buffer_virtual = remap_page_array(camera_context->page_array, ++ pages, ++ GFP_KERNEL); ++ ++ if(camera_context->buffer_virtual == NULL) ++ { ++ goto error; ++ } ++ ++ camera_context->pages_allocated = pages; ++ ++ return 0; ++ ++error: ++ for(page_count = 0; page_count < pages; page_count++) ++ { ++ if((page = camera_context->page_array[page_count]) != NULL) ++ { ++ ClearPageReserved(page); ++ set_page_count(page, 1); ++ put_page(page); ++ } ++ } ++ kfree(camera_context->page_array); ++ ++ return -ENOMEM; ++} ++ ++static void pxa_dma_buffer_free(p_camera_context_t camera_context) ++{ ++ struct page *page; ++ int page_count; ++ ++ if(camera_context->buffer_virtual == NULL) ++ return; ++ ++ vfree(camera_context->buffer_virtual); ++ ++ for(page_count = 0; page_count < camera_context->pages_allocated; page_count++) ++ { ++ if((page = camera_context->page_array[page_count]) != NULL) ++ { ++ ClearPageReserved(page); ++ set_page_count(page, 1); ++ put_page(page); ++ } ++ } ++ kfree(camera_context->page_array); ++} ++/* ++Generate dma descriptors ++Pre-condition: these variables must be set properly ++ block_number, fifox_transfer_size ++ dma_descriptors_virtual, dma_descriptors_physical, dma_descirptors_size ++Post-condition: these variables will be set ++ fifox_descriptors_virtual, fifox_descriptors_physical ++ fifox_num_descriptors ++*/ ++int update_dma_chain(p_camera_context_t camera_context) ++{ ++ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size; ++ unsigned int i,j; ++ int target_page_num; ++ ++ dbg_print(""); ++ ++ // clear descriptor pointers ++ camera_context->fifo0_descriptors_virtual = camera_context->fifo0_descriptors_physical = 0; ++ camera_context->fifo1_descriptors_virtual = camera_context->fifo1_descriptors_physical = 0; ++ camera_context->fifo2_descriptors_virtual = camera_context->fifo2_descriptors_physical = 0; ++ ++ // calculate how many descriptors are needed per frame ++ camera_context->fifo0_num_descriptors = ++ camera_context->pages_per_fifo0; ++ ++ camera_context->fifo1_num_descriptors = ++ camera_context->pages_per_fifo1; ++ ++ camera_context->fifo2_num_descriptors = ++ camera_context->pages_per_fifo2; ++ ++ // check if enough memory to generate descriptors ++ if((camera_context->fifo0_num_descriptors + ++ camera_context->fifo1_num_descriptors + ++ camera_context->fifo2_num_descriptors) * camera_context->block_number ++ > camera_context->dma_descriptors_size) ++ { ++ return -1; ++ } ++ ++ dbg_print("1"); ++ // generate fifo0 dma chains ++ camera_context->fifo0_descriptors_virtual = (unsigned)camera_context->dma_descriptors_virtual; ++ camera_context->fifo0_descriptors_physical = (unsigned)camera_context->dma_descriptors_physical; ++ ++ cur_des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo0_transfer_size; ++ ++ // assume the blocks are stored consecutively ++ target_page_num = camera_context->pages_per_block * i; ++ ++ for(j=0; j<camera_context->fifo0_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR0_PHY; // FIFO0 physical address ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo0_descriptors_physical); ++ ++ // generate fifo1 dma chains ++ if(camera_context->fifo1_transfer_size) ++ { ++ // record fifo1 descriptors' start address ++ camera_context->fifo1_descriptors_virtual = (unsigned)cur_des_virtual; ++ camera_context->fifo1_descriptors_physical = (unsigned)cur_des_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo1_transfer_size; ++ ++ target_page_num = camera_context->pages_per_block * i + ++ camera_context->pages_per_fifo0; ++ ++ for(j=0; j<camera_context->fifo1_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR1_PHY; // FIFO1 physical address ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo1_descriptors_physical); ++ } ++ ++ // generate fifo2 dma chains ++ if(camera_context->fifo2_transfer_size) ++ { ++ // record fifo1 descriptors' start address ++ camera_context->fifo2_descriptors_virtual = (unsigned)cur_des_virtual; ++ camera_context->fifo2_descriptors_physical = (unsigned)cur_des_physical; ++ ++ for(i=0; i<camera_context->block_number; i++) ++ { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = camera_context->fifo2_transfer_size; ++ ++ target_page_num = camera_context->pages_per_block * i + ++ camera_context->pages_per_fifo0 + ++ camera_context->pages_per_fifo1; ++ ++ for(j=0; j<camera_context->fifo2_num_descriptors; j++) ++ { ++ // set descriptor ++ if(remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR2_PHY; // FIFO2 physical address ++ cur_des_virtual->dtadr = page_to_bus(camera_context->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ } ++ last_des_virtual->ddadr = ((unsigned)camera_context->fifo2_descriptors_physical); ++ } ++ ++ dbg_print(" success!"); ++ return 0; ++} ++ ++void start_dma_transfer(p_camera_context_t camera_context, unsigned block_id) ++{ ++ pxa_dma_desc *des_virtual, *des_physical; ++ ++ if(block_id >= camera_context->block_number) ++ { ++ return; ++ } ++ ++ // start channel 0 ++ des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual + ++ block_id * camera_context->fifo0_num_descriptors; ++ ++ des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical + ++ block_id * camera_context->fifo0_num_descriptors; ++ ++ DDADR(camera_context->dma_channels[0]) = des_physical; ++ DCSR(camera_context->dma_channels[0]) |= DCSR_RUN; ++ ++ // start channel 1 ++ if(camera_context->fifo1_descriptors_virtual) ++ { ++ des_virtual = (pxa_dma_desc *)camera_context->fifo1_descriptors_virtual + ++ block_id * camera_context->fifo1_num_descriptors; ++ ++ des_physical = (pxa_dma_desc *)camera_context->fifo1_descriptors_physical + ++ block_id * camera_context->fifo1_num_descriptors; ++ ++ DDADR(camera_context->dma_channels[1]) = des_physical; ++ DCSR(camera_context->dma_channels[1]) |= DCSR_RUN; ++ } ++ ++ // start channel 2 ++ if(camera_context->fifo2_descriptors_virtual) ++ { ++ des_virtual = (pxa_dma_desc *)camera_context->fifo2_descriptors_virtual + ++ block_id * camera_context->fifo2_num_descriptors; ++ ++ des_physical = (pxa_dma_desc *)camera_context->fifo2_descriptors_physical + ++ block_id * camera_context->fifo2_num_descriptors; ++ ++ DDADR(camera_context->dma_channels[2]) = des_physical; ++ DCSR(camera_context->dma_channels[2]) |= DCSR_RUN; ++ } ++ ++ camera_context->dma_started = 1; ++} ++ ++void stop_dma_transfer(p_camera_context_t camera_context) ++{ ++ int ch0, ch1, ch2; ++ ++ ch0 = camera_context->dma_channels[0]; ++ ch1 = camera_context->dma_channels[1]; ++ ch2 = camera_context->dma_channels[2]; ++ ++ DCSR(ch0) &= ~DCSR_RUN; ++ DCSR(ch1) &= ~DCSR_RUN; ++ DCSR(ch2) &= ~DCSR_RUN; ++ camera_context->dma_started = 0; ++ ++ return; ++} ++ ++int start_capture(p_camera_context_t camera_context, unsigned int block_id, unsigned int frames) ++{ ++ int status; ++ //clear ci fifo ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ ++ //start dma ++// start_dma_transfer(camera_context, block_id); ++ ++ ++ // start capture ++ status = camera_context->camera_functions->start_capture(camera_context, frames); ++ ++ ci_enable(1); ++ ++ if(frames == 1) //Wait 2 frames to begin capture photo ++ { ++ waitingFrame = 2; ++ } ++ else ++ { ++ waitingFrame = 1; ++ } ++ while(waitingFrame--) ++ { ++ CISR|=(1<<3); ++ while(!(CISR&(1<<3))); //Wait a EOF then begin start DMA ++ } ++ ci_reset_fifo(); ++ start_dma_transfer(camera_context, block_id); ++ return status; ++} ++ ++/*********************************************************************** ++ * ++ * Init/Deinit APIs ++ * ++ ***********************************************************************/ ++int camera_init(p_camera_context_t camera_context) ++{ ++ int ret=0; ++ int i; ++ dbg_print("0"); ++#ifdef DEBUG ++ // parameter check ++ if(camera_context->buffer_virtual == NULL || ++ camera_context->buf_size == 0) ++ { ++ dbg_print("camera_context->buffer wrong!"); ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ if(camera_context->dma_descriptors_virtual == NULL || ++ camera_context->dma_descriptors_physical == NULL || ++ camera_context->dma_descriptors_size == 0) ++ { ++ dbg_print("camera_context->dma_descriptors wrong!"); ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ if(camera_context->sensor_type > CAMERA_TYPE_MAX) ++ { ++ dbg_print("camera_context->sensor type wrong!"); ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ if(camera_context->capture_input_format > CAMERA_IMAGE_FORMAT_MAX || ++ camera_context->capture_output_format > CAMERA_IMAGE_FORMAT_MAX) ++ { ++ dbg_print("camera_context->capture format wrong!"); ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ // check the function dispatch table according to the sensor type ++ if(!camera_context->camera_functions ) ++ { ++ dbg_print("camera_context->camera_functions wrong!"); ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ if( !camera_context->camera_functions->init || ++ !camera_context->camera_functions->deinit || ++ !camera_context->camera_functions->set_capture_format || ++ !camera_context->camera_functions->start_capture || ++ !camera_context->camera_functions->stop_capture ) ++ { ++ return STATUS_WRONG_PARAMETER; ++ } ++#endif ++ dbg_print(""); ++ // init context status ++ for(i=0; i<3; i++) ++ { ++ camera_context->dma_channels[i] = 0xFF; ++ } ++ ++ (int)camera_context->fifo0_descriptors_virtual = NULL; ++ (int)camera_context->fifo1_descriptors_virtual = NULL; ++ (int)camera_context->fifo2_descriptors_virtual = NULL; ++ (int)camera_context->fifo0_descriptors_physical = NULL; ++ (int)camera_context->fifo1_descriptors_physical = NULL; ++ (int)camera_context->fifo2_descriptors_physical = NULL; ++ ++ camera_context->fifo0_num_descriptors = 0; ++ camera_context->fifo1_num_descriptors = 0; ++ camera_context->fifo2_num_descriptors = 0; ++ ++ camera_context->fifo0_transfer_size = 0; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ ++ camera_context->block_number = 0; ++ camera_context->block_size = 0; ++ camera_context->block_header = 0; ++ camera_context->block_tail = 0; ++ ++ // Enable hardware ++ camera_gpio_init(); ++ ++ // capture interface init ++ ci_init(); ++ ++ ++ // sensor init ++ if(camera_context->camera_functions->init(camera_context)) ++ { ++ dbg_print("camera function init error!!"); ++ goto camera_init_err; ++ } ++ ++ camera_context->dma_channels[0] = ci_dma_y; ++ camera_context->dma_channels[1] = ci_dma_cb; ++ camera_context->dma_channels[2] = ci_dma_cr; ++ DRCMR68 = ci_dma_y | DRCMR_MAPVLD; ++ DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; ++ DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; ++ ret = camera_set_capture_format(camera_context); ++ if(ret) ++ { ++ dbg_print("camera function init error!!"); ++ goto camera_init_err; ++ } ++ ++#ifdef DEBUG ++ ci_dump(); ++#endif ++ ++ ci_disable(1); ++ return 0; ++ ++camera_init_err: ++ camera_deinit(camera_context); ++ return -1; ++} ++ ++void camera_gpio_init() ++{ ++#ifdef CONFIG_CAMERA_OV9640 ++ set_GPIO_mode( 50 | GPIO_OUT ); /*CIF_PD*/ ++ set_GPIO_mode( 19 | GPIO_OUT ); /*CIF_RST*/ ++ set_GPIO_mode( 27 | GPIO_ALT_FN_3_IN); /* CIF_DD[0] */ ++ set_GPIO_mode( 114 | GPIO_ALT_FN_1_IN); /* CIF_DD[1] */ ++ set_GPIO_mode( 51 | GPIO_ALT_FN_1_IN); /* CIF_DD[2] */ ++ set_GPIO_mode( 115| GPIO_ALT_FN_2_IN); /* CIF_DD[3] */ ++ set_GPIO_mode( 95 | GPIO_ALT_FN_2_IN); /* CIF_DD[4] */ ++ set_GPIO_mode( 94 | GPIO_ALT_FN_2_IN); /* CIF_DD[5] */ ++ set_GPIO_mode( 17 | GPIO_ALT_FN_2_IN); /* CIF_DD[6] */ ++ set_GPIO_mode( 108 | GPIO_ALT_FN_1_IN); /* CIF_DD[7] */ ++// set_GPIO_mode( 107 | GPIO_ALT_FN_1_IN); /* CIF_DD[8] */ ++// set_GPIO_mode( 106 | GPIO_ALT_FN_1_IN); /* CIF_DD[9] */ ++ set_GPIO_mode( 23 | GPIO_ALT_FN_1_OUT); /* CIF_MCLK */ ++ set_GPIO_mode( 54 | GPIO_ALT_FN_3_IN); /* CIF_PCLK */ ++ set_GPIO_mode( 85 | GPIO_ALT_FN_3_IN); /* CIF_LV */ ++ set_GPIO_mode( 84 | GPIO_ALT_FN_3_IN); /* CIF_FV */ ++ ++#endif ++ ++#ifdef CONFIG_CAMERA_MT9M111 ++ set_GPIO_mode( CIF_PD_MD ); /*CIF_PD*/ ++ GPCR(CIF_PD) = GPIO_bit(CIF_PD); /*set to low*/ ++ set_GPIO_mode( CIF_RST_MD ); /*CIF_RST*/ ++ GPSR(CIF_RST) = GPIO_bit(CIF_RST); /*set to high*/ ++ set_GPIO_mode( CIF_DD0_MD ); /* CIF_DD[0] */ ++ set_GPIO_mode( CIF_DD1_MD ); /* CIF_DD[1] */ ++ set_GPIO_mode( CIF_DD2_MD ); /* CIF_DD[2] */ ++ set_GPIO_mode( CIF_DD3_MD ); /* CIF_DD[3] */ ++ set_GPIO_mode( CIF_DD4_MD ); /* CIF_DD[4] */ ++ set_GPIO_mode( CIF_DD5_MD ); /* CIF_DD[5] */ ++ set_GPIO_mode( CIF_DD6_MD ); /* CIF_DD[6] */ ++ set_GPIO_mode( CIF_DD7_MD ); /* CIF_DD[7] */ ++ set_GPIO_mode( CIF_MCLK_MD ); /* CIF_MCLK */ ++ set_GPIO_mode( CIF_PCLK_MD ); /* CIF_PCLK */ ++ set_GPIO_mode( CIF_LV_MD ); /* CIF_LV */ ++ set_GPIO_mode( CIF_FV_MD ); /* CIF_FV */ ++#endif ++ ++ ++ return; ++} ++ ++ ++void camera_gpio_deinit() ++{ ++ ++ #ifdef CONFIG_CAMERA_MT9M111 ++ /* Turn off M_VCC CIF_PD*/ ++ GPSR(CIF_PD) = GPIO_bit(CIF_PD); /* Set PD to low */ ++ ++ set_GPIO_mode( CIF_MCLK | GPIO_IN); /*trun off MCLK*/ ++ #endif ++} ++ ++int camera_deinit( p_camera_context_t camera_context ) ++{ ++ ++ // free dma channel ++ /* ++ for(i=0; i<3; i++) ++ { ++ if(camera_context->dma_channels[i] != 0x00) ++ { ++ pxa_free_dma(camera_context->dma_channels[i]); ++ camera_context->dma_channels[i] = 0; ++ } ++ } ++ */ ++ ++ // deinit sensor ++ camera_context->camera_functions->deinit(camera_context); ++ ++ // capture interface deinit ++ ci_deinit(); ++ camera_gpio_deinit(); ++ return 0; ++} ++ ++int camera_ring_buf_init(p_camera_context_t camera_context) ++{ ++ dbg_print(""); ++ unsigned frame_size; ++ switch(camera_context->capture_output_format) ++ { ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 2; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 2; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 2; ++ camera_context->fifo0_transfer_size = frame_size / 2; ++ camera_context->fifo1_transfer_size = frame_size / 4; ++ camera_context->fifo2_transfer_size = frame_size / 4; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB666_PLANAR: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 4; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB666_PACKED: ++ frame_size = camera_context->capture_width * camera_context->capture_height * 3; ++ camera_context->fifo0_transfer_size = frame_size; ++ camera_context->fifo1_transfer_size = 0; ++ camera_context->fifo2_transfer_size = 0; ++ break; ++ default: ++ return STATUS_WRONG_PARAMETER; ++ break; ++ } ++ ++ camera_context->block_size = frame_size; ++ ++ camera_context->pages_per_fifo0 = ++ (PAGE_ALIGN(camera_context->fifo0_transfer_size) / PAGE_SIZE); ++ camera_context->pages_per_fifo1 = ++ (PAGE_ALIGN(camera_context->fifo1_transfer_size) / PAGE_SIZE); ++ camera_context->pages_per_fifo2 = ++ (PAGE_ALIGN(camera_context->fifo2_transfer_size) / PAGE_SIZE); ++ ++ camera_context->pages_per_block = ++ camera_context->pages_per_fifo0 + ++ camera_context->pages_per_fifo1 + ++ camera_context->pages_per_fifo2; ++ ++ camera_context->page_aligned_block_size = ++ camera_context->pages_per_block * PAGE_SIZE; ++ ++ camera_context->block_number_max = ++ camera_context->pages_allocated / ++ camera_context->pages_per_block; ++ ++ ++ //restrict max block number ++ if(camera_context->block_number_max > FRAMES_IN_BUFFER) ++ { ++ camera_context->block_number = FRAMES_IN_BUFFER; ++ } ++ else ++ { ++ camera_context->block_number = camera_context->block_number_max; ++ } ++ ++ camera_context->block_header = camera_context->block_tail = 0; ++ ++ // generate dma descriptor chain ++ return update_dma_chain(camera_context); ++ ++} ++/*********************************************************************** ++ * ++ * Capture APIs ++ * ++ ***********************************************************************/ ++// Set the image format ++int camera_set_capture_format(p_camera_context_t camera_context) ++{ ++ ++ CI_IMAGE_FORMAT ci_input_format, ci_output_format; ++ CI_MP_TIMING timing; ++ ++ if(camera_context->capture_input_format > CAMERA_IMAGE_FORMAT_MAX || ++ camera_context->capture_output_format > CAMERA_IMAGE_FORMAT_MAX ) ++ { ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ ci_input_format = FORMAT_MAPPINGS[camera_context->capture_input_format]; ++ ci_output_format = FORMAT_MAPPINGS[camera_context->capture_output_format]; ++ ++ if(ci_input_format == CI_INVALID_FORMAT || ci_output_format == CI_INVALID_FORMAT) ++ { ++ return STATUS_WRONG_PARAMETER; ++ } ++ ++ ci_set_image_format(ci_input_format, ci_output_format); ++ ++#ifdef CONFIG_CAMERA_MT9M111 ++ timing.BFW = 0; ++ timing.BLW = 0; ++#endif ++#ifdef CONFIG_CAMERA_OV9640 ++ timing.BFW = 0; ++ timing.BLW = 51*2; ++#endif ++ ++ ++ ci_configure_mp(camera_context->capture_width-1, camera_context->capture_height-1, &timing); ++ ++ if(camera_context == NULL || camera_context->camera_functions == NULL || ++ camera_context->camera_functions->set_capture_format == NULL) ++ { ++ dbg_print("camera_context point NULL!!!"); ++ return -1; ++ } ++ // set sensor setting ++ if(camera_context->camera_functions->set_capture_format(camera_context)) ++ { ++ return -1; ++ } ++ ++ // ring buffer init ++ return camera_ring_buf_init(camera_context); ++ ++} ++ ++// take a picture and copy it into the ring buffer ++int camera_capture_still_image(p_camera_context_t camera_context, unsigned int block_id) ++{ ++ // init buffer status & capture ++ camera_set_int_mask(camera_context, 0x3ff | 0x0400); ++ still_image_mode = 1; ++ first_video_frame = 0; ++ camera_context->block_header = camera_context->block_tail = block_id; ++ camera_context->capture_status = 0; ++ return start_capture(camera_context, block_id, 1); ++} ++ ++// capture motion video and copy it to the ring buffer ++int camera_start_video_capture( p_camera_context_t camera_context, unsigned int block_id ) ++{ ++ //init buffer status & capture ++ camera_set_int_mask(camera_context, 0x3ff | 0x0400); ++ still_image_mode = 0; ++ first_video_frame = 1; ++ camera_context->block_header = camera_context->block_tail = block_id; ++ camera_context->capture_status = CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS; ++ return start_capture(camera_context, block_id, 0); ++} ++ ++// disable motion video image capture ++void camera_stop_video_capture( p_camera_context_t camera_context ) ++{ ++ //stop capture ++ camera_context->camera_functions->stop_capture(camera_context); ++ ++ //stop dma ++ stop_dma_transfer(camera_context); ++ ++ //update the flag ++ if(!(camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ { ++ camera_context->capture_status &= ~CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS; ++ } ++ ++ ci_disable(1); ++} ++ ++ ++/*********************************************************************** ++ * ++ * Flow Control APIs ++ * ++ ***********************************************************************/ ++// continue capture image to next available buffer ++void camera_continue_transfer( p_camera_context_t camera_context ) ++{ ++ // don't think we need this either. JR ++ // continue transfer on next block ++ start_dma_transfer( camera_context, camera_context->block_tail ); ++} ++ ++// Return 1: there is available buffer, 0: buffer is full ++int camera_next_buffer_available( p_camera_context_t camera_context ) ++{ ++ camera_context->block_header = (camera_context->block_header + 1) % camera_context->block_number; ++ if(((camera_context->block_header + 1) % camera_context->block_number) != camera_context->block_tail) ++ { ++ return 1; ++ } ++ ++ camera_context->capture_status |= CAMERA_STATUS_RING_BUFFER_FULL; ++ return 0; ++} ++ ++// Application supplies the FrameBufferID to the driver to tell it that the application has completed processing of ++// the given frame buffer, and that buffer is now available for re-use. ++void camera_release_frame_buffer(p_camera_context_t camera_context, unsigned int frame_buffer_id) ++{ ++ ++ camera_context->block_tail = (camera_context->block_tail + 1) % camera_context->block_number; ++ ++ // restart video capture only ifvideo capture is in progress and space is available for image capture ++ if((camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL ) && ++ (camera_context->capture_status & CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS)) ++ { ++ if(((camera_context->block_header + 2) % camera_context->block_number) != camera_context->block_tail) ++ { ++ camera_context->capture_status &= ~CAMERA_STATUS_RING_BUFFER_FULL; ++ start_capture(camera_context, camera_context->block_tail, 0); ++ } ++ } ++} ++ ++// Returns the FrameBufferID for the first filled frame ++// Note: -1 represents buffer empty ++int camera_get_first_frame_buffer_id(p_camera_context_t camera_context) ++{ ++ // not sure ifthis routine makes any sense.. JR ++ ++ // check whether buffer is empty ++ if((camera_context->block_header == camera_context->block_tail) && ++ !(camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ { ++ return -1; ++ } ++ ++ // return the block header ++ return camera_context->block_header; ++} ++ ++// Returns the FrameBufferID for the last filled frame, this would be used ifwe were polling for image completion data, ++// or we wanted to make sure there were no frames waiting for us to process. ++// Note: -1 represents buffer empty ++int camera_get_last_frame_buffer_id(p_camera_context_t camera_context) ++{ ++ ++ // check whether buffer is empty ++ if((camera_context->block_header == camera_context->block_tail) && ++ !(camera_context->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ { ++ return -1; ++ } ++ ++ // return the block before the block_tail ++ return (camera_context->block_tail + camera_context->block_number - 1) % camera_context->block_number; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Buffer Info APIs ++ * ++ ***********************************************************************/ ++// Return: the number of frame buffers allocated for use. ++unsigned int camera_get_num_frame_buffers(p_camera_context_t camera_context) ++{ ++ return camera_context->block_number; ++} ++ ++// FrameBufferID is a number between 0 and N-1, where N is the total number of frame buffers in use. Returns the address of ++// the given frame buffer. The application will call this once for each frame buffer at application initialization only. ++void * camera_get_frame_buffer_addr(p_camera_context_t camera_context, unsigned int frame_buffer_id) ++{ ++ return (void*)((unsigned)camera_context->buffer_virtual + ++ camera_context->page_aligned_block_size * frame_buffer_id); ++} ++ ++// Return the block id ++int camera_get_frame_buffer_id(p_camera_context_t camera_context, void* address) ++{ ++ if(((unsigned)address >= (unsigned)camera_context->buffer_virtual) && ++ ((unsigned)address <= (unsigned)camera_context->buffer_virtual + camera_context->buf_size)) ++ { ++ return ((unsigned)address - ++ (unsigned)camera_context->buffer_virtual) / ++ camera_context->page_aligned_block_size; ++ } ++ ++ return -1; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Frame rate APIs ++ * ++ ***********************************************************************/ ++// Set desired frame rate ++void camera_set_capture_frame_rate(p_camera_context_t camera_context) ++{ ++ ci_set_frame_rate(camera_context->fps); ++} ++ ++// return current setting ++void camera_get_capture_frame_rate(p_camera_context_t camera_context) ++{ ++ camera_context->fps = ci_get_frame_rate(); ++} ++ ++ ++/*********************************************************************** ++ * ++ * Interrupt APIs ++ * ++ ***********************************************************************/ ++// set interrupt mask ++void camera_set_int_mask(p_camera_context_t cam_ctx, unsigned int mask) ++{ ++ pxa_dma_desc * end_des_virtual; ++ int dma_interrupt_on, i; ++ ++ // set CI interrupt ++ ci_set_int_mask( mask & CI_CICR0_INTERRUPT_MASK ); ++ ++ // set dma end interrupt ++ if( mask & CAMERA_INTMASK_END_OF_DMA ) ++ dma_interrupt_on = 1; ++ else ++ dma_interrupt_on = 0; ++ ++ // set fifo0 dma chains' flag ++ end_des_virtual = (pxa_dma_desc*)cam_ctx->fifo0_descriptors_virtual + cam_ctx->fifo0_num_descriptors - 1; ++ ++ for(i=0; i<cam_ctx->block_number; i++) ++ { ++ if(dma_interrupt_on) ++ end_des_virtual->dcmd |= DCMD_ENDIRQEN; ++ else ++ end_des_virtual->dcmd &= ~DCMD_ENDIRQEN; ++ ++ end_des_virtual += cam_ctx->fifo0_num_descriptors; ++ } ++} ++ ++// get interrupt mask ++unsigned int camera_get_int_mask(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *end_des_virtual; ++ unsigned int ret; ++ ++ // get CI mask ++ ret = ci_get_int_mask(); ++ ++ // get dma end mask ++ end_des_virtual = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + cam_ctx->fifo0_num_descriptors - 1; ++ ++ if(end_des_virtual->dcmd & DCMD_ENDIRQEN) ++ { ++ ret |= CAMERA_INTMASK_END_OF_DMA; ++ } ++ return ret; ++} ++ ++// clear interrupt status ++void camera_clear_int_status( p_camera_context_t camera_context, unsigned int status ) ++{ ++ ci_clear_int_status( (status & 0xFFFF) ); ++} ++ ++/*********************************************************************************** ++* Application interface * ++***********************************************************************************/ ++static int pxa_camera_open(struct video_device *dev, int flags) ++{ ++ dbg_print("start..."); ++ camera_context_t *cam_ctx; ++ ++ init_waitqueue_head(&camera_wait_q); ++ ++ if(pxa_camera_mem_init()) ++ { ++ dbg_print("DMA memory allocate failed!"); ++ return -1; ++ } ++ ++ ++ cam_ctx = g_camera_context; ++ ++#ifdef CONFIG_CAMERA_MT9M111 ++ cam_ctx->sensor_type = CAMERA_TYPE_MT9M111; ++ cam_ctx->capture_width = WIDTH_DEFT; ++ cam_ctx->capture_height = HEIGHT_DEFT; ++ cam_ctx->camera_functions = &mt9m111_func; ++#endif ++#ifdef CONFIG_CAMERA_OV9640 ++ cam_ctx->sensor_type = CAMERA_TYPE_OMNIVISION_9640; ++ cam_ctx->capture_width = 320; ++ cam_ctx->capture_height = 240; ++ cam_ctx->camera_functions = &ov9640_func; ++#endif ++ ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ ++ cam_ctx->fps = FRAMERATE_DEFT; ++ ++// cam_ctx->ost_reg_base = 0; ++// cam_ctx->gpio_reg_base = 0; ++// cam_ctx->ci_reg_base = 0; ++// cam_ctx->board_reg_base = 0; ++ ++ if(cam_ctx->dma_descriptors_virtual == NULL) ++ { ++ dbg_print("descriptors virtual memory not allocated!"); ++ return -1; ++ } ++ ++ if(cam_ctx->buffer_virtual == NULL) ++ { ++ dbg_print("buffer virtual memory not allocated!"); ++ return -1; ++ } ++ ++ cam_ctx->ost_reg_base = 0; ++ cam_ctx->gpio_reg_base = 0; ++ cam_ctx->ci_reg_base = 0; ++ cam_ctx->board_reg_base = 0; ++ ++ ++ if(camera_init(cam_ctx)) ++ { ++ dbg_print("camera_init faile!"); ++ return -1; ++ } ++ ++ dbg_print("PXA_CAMERA: pxa_camera_open success!"); ++ return 0; ++} ++ ++static void pxa_camera_close(struct video_device *dev) ++{ ++ camera_deinit(g_camera_context); ++ pxa_camera_mem_deinit(); ++ dbg_print("PXA_CAMERA: pxa_camera_close\n"); ++} ++ ++#define PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, size) \ ++do { \ ++ unsigned int len; \ ++ unsigned int remain_size = size; \ ++ while (remain_size > 0) { \ ++ if(remain_size > PAGE_SIZE) \ ++ len = PAGE_SIZE; \ ++ else \ ++ len = remain_size; \ ++ if(copy_to_user(buf, page_address(*p_page), len)) \ ++ return -EFAULT; \ ++ remain_size -= len; \ ++ buf += len; \ ++ p_page++; \ ++ } \ ++} while (0); ++ ++ ++static long pxa_camera_read(struct video_device *dev, ++ char *buf, ++ unsigned long count, ++ int noblock) ++{ ++ ++ struct page **p_page; ++ ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ if(still_image_mode == 1 && still_image_rdy == 1) ++ { ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo0_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo1_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo2_transfer_size); ++ ++ still_image_rdy = 0; ++ return cam_ctx->block_size; ++ } ++ ++ if(still_image_mode == 0) ++ { ++ if(first_video_frame == 1) ++ cam_ctx->block_tail = cam_ctx->block_header; ++ else ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ } ++ ++ first_video_frame = 0; ++ ++ if(cam_ctx->block_header == cam_ctx->block_tail) ++ { ++ task_waiting = 1; ++ interruptible_sleep_on (&camera_wait_q); ++ } ++ ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo0_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo1_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo2_transfer_size); ++ ++ return cam_ctx->block_size; ++} ++ ++struct reg_set_s ++{ ++ int val1; ++ int val2; ++}; ++ ++/*ioctl sub functions*/ ++static int pxa_camera_VIDIOCGCAP(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_capability vc; ++ dbg_print("VIDIOCGCAP"); ++ strcpy (vc.name, "Micron MT9M111"); ++ vc.maxwidth = MAX_WIDTH; ++ vc.maxheight = MAX_HEIGHT; ++ vc.minwidth = MIN_WIDTH; ++ vc.minheight = MIN_HEIGHT; ++ if(copy_to_user(param, &vc, sizeof(struct video_capability))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_VIDIOCGWIN(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_window vw; ++ dbg_print("VIDIOCGWIN"); ++ vw.width = cam_ctx->capture_width; ++ vw.height = cam_ctx->capture_height; ++ if(copy_to_user(param, &vw, sizeof(struct video_window))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_VIDIOCSWIN(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_window vw; ++ dbg_print("VIDIOCSWIN"); ++ if(copy_from_user(&vw, param, sizeof(vw))) ++ { ++ dbg_print("VIDIOCSWIN get parameter error!"); ++ return -EFAULT; ++ } ++ if(vw.width > MAX_WIDTH || vw.height > MAX_HEIGHT || vw.width < MIN_WIDTH || vw.height < MIN_HEIGHT) ++ { ++ dbg_print("VIDIOCSWIN error parameter!"); ++ dbg_print("vw.width:%d, MAX_WIDTH:%d, MIN_WIDTH:%d", vw.width, MAX_WIDTH, MIN_WIDTH); ++ dbg_print("vw.height:%d, MAX_HEIGHT:%d, MIN_HEIGHT:%d", vw.width, MAX_HEIGHT, MIN_HEIGHT); ++ return -EFAULT; ++ } ++ cam_ctx->capture_width = vw.width; ++ //make it in an even ++ cam_ctx->capture_width = (vw.width+1)/2; ++ cam_ctx->capture_width *= 2; ++ ++ cam_ctx->capture_height = (vw.height+1)/2; ++ cam_ctx->capture_height *= 2; ++ ++ return camera_set_capture_format(cam_ctx); ++} ++static int pxa_camera_VIDIOCSPICT(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_picture vp; ++ dbg_print("VIDIOCSPICT"); ++ if(copy_from_user(&vp, param, sizeof(vp))) ++ { ++ return -EFAULT; ++ } ++ cam_ctx->capture_output_format = vp.palette; ++ ++ return camera_set_capture_format(cam_ctx); ++ ++} ++ ++static int pxa_camera_VIDIOCGPICT(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_picture vp; ++ dbg_print("VIDIOCGPICT"); ++ vp.palette = cam_ctx->capture_output_format; ++ if(copy_to_user(param, &vp, sizeof(struct video_picture))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_VIDIOCCAPTURE(p_camera_context_t cam_ctx, void * param) ++{ ++ int capture_flag = (int)param; ++ dbg_print("VIDIOCCAPTURE"); ++ if(capture_flag > 0) ++ { ++ dbg_print("Still Image capture!"); ++ camera_capture_still_image(cam_ctx, 0); ++ } ++ else if(capture_flag == 0) ++ { ++ dbg_print("Video Image capture!"); ++ camera_start_video_capture(cam_ctx, 0); ++ } ++ else if(capture_flag == -1) ++ { ++ dbg_print("Capture stop!"); ++ camera_set_int_mask(cam_ctx, 0x3ff); ++ camera_stop_video_capture(cam_ctx); ++ } ++ else ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_VIDIOCGMBUF(p_camera_context_t cam_ctx, void * param) ++{ ++ struct video_mbuf vm; ++ int i; ++ ++ dbg_print("VIDIOCGMBUF"); ++ ++ memset(&vm, 0, sizeof(vm)); ++ vm.size = cam_ctx->buf_size; ++ vm.frames = cam_ctx->block_number; ++ for(i = 0; i < vm.frames; i++) ++ { ++ vm.offsets[i] = cam_ctx->page_aligned_block_size * i; ++ } ++ if(copy_to_user((void *)param, (void *)&vm, sizeof(vm))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_WCAM_VIDIOCSINFOR(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ struct reg_set_s reg_s; ++ int ret; ++ dbg_print("WCAM_VIDIOCSINFOR"); ++ ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ ++ cam_ctx->capture_input_format = reg_s.val1; ++ cam_ctx->capture_output_format = reg_s.val2; ++ ret=camera_set_capture_format(cam_ctx); ++ ci_dump(); ++ return ret; ++} ++static int pxa_camera_WCAM_VIDIOCGINFOR(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ struct reg_set_s reg_s; ++ dbg_print("WCAM_VIDIOCGINFOR"); ++ reg_s.val1 = cam_ctx->capture_input_format; ++ reg_s.val2 = cam_ctx->capture_output_format; ++ if(copy_to_user(param, ®_s, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++static int pxa_camera_WCAM_VIDIOCGCIREG(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ int reg_value, offset; ++ dbg_print("WCAM_VIDIOCGCIREG"); ++ if(copy_from_user(&offset, param, sizeof(int))) ++ { ++ return -EFAULT; ++ ++ } ++ reg_value = ci_get_reg_value (offset); ++ if(copy_to_user(param, ®_value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_WCAM_VIDIOCSCIREG(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ struct reg_set_s reg_s; ++ dbg_print("WCAM_VIDIOCSCIREG"); ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ ci_set_reg_value (reg_s.val1, reg_s.val2); ++ return 0; ++ ++} ++static int pxa_camera_WCAM_VIDIOCGCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ int reg_value, offset; ++ dbg_print("WCAM_VIDIOCGCAMREG"); ++ if(copy_from_user(&offset, param, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ reg_value = (int)mt9m111_reg_read((u16)offset); ++ ++ if(copy_to_user(param, ®_value, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++static int pxa_camera_WCAM_VIDIOCSCAMREG(p_camera_context_t cam_ctx, void * param) ++{ ++ struct reg_set_s reg_s; ++ dbg_print("WCAM_VIDIOCSCAMREG"); ++ ++ if(copy_from_user(®_s, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ mt9m111_reg_write((u16)reg_s.val1, (u16)reg_s.val2); ++ return 0; ++} ++ ++static int pxa_cam_WCAM_VIDIOCSFPS(p_camera_context_t cam_ctx, void * param) ++{ ++ struct {int fps, minfps;} cam_fps; ++ dbg_print("WCAM_VIDIOCSFPS"); ++ if(copy_from_user(&cam_fps, param, sizeof(int) * 2)) ++ { ++ return -EFAULT; ++ } ++ cam_ctx->fps = cam_fps.fps; ++ cam_ctx->mini_fps = cam_fps.minfps; ++ mt9m111_set_fps(cam_fps.fps, cam_fps.minfps); ++ return 0; ++} ++ ++ ++/*Set sensor size*/ ++static int pxa_cam_WCAM_VIDIOCSSSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ micron_window_size size; ++ dbg_print("WCAM_VIDIOCSSSIZE"); ++ ++ if(copy_from_user(&size, param, sizeof(micron_window_size))) ++ { ++ return -EFAULT; ++ } ++ ++ size.width = (size.width+1)/2 * 2; ++ size.height = (size.height+1)/2 * 2; ++ cam_ctx->sensor_width = size.width; ++ cam_ctx->sensor_height = size.height; ++ mt9m111_input_size(&size); ++ return 0; ++} ++ ++//set output size ++static int pxa_cam_WCAM_VIDIOCSOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ micron_window_size size; ++ CI_MP_TIMING timing; ++ dbg_print("WCAM_VIDIOCSOSIZE"); ++ ++ if(copy_from_user(&size, param, sizeof(micron_window_size))) ++ { ++ return -EFAULT; ++ } ++ ++ //make it in an even number ++ size.width = (size.width+1)/2 * 2; ++ size.height = (size.height+1)/2 * 2; ++ mt9m111_output_size(&size); ++ ++ cam_ctx->capture_width = size.width; ++ cam_ctx->capture_height = size.height; ++ timing.BFW = timing.BLW = 0; ++ ++ ci_configure_mp(cam_ctx->capture_width-1, cam_ctx->capture_height-1, &timing); ++ camera_ring_buf_init(cam_ctx); ++ ++ return 0; ++} ++ ++ ++ ++/*get sensor size */ ++static int pxa_cam_WCAM_VIDIOCGSSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ micron_window_size size; ++ dbg_print("WCAM_VIDIOCGSSIZE"); ++ mt9m111_get_input_size(&size); ++ if(copy_to_user(param, &size, sizeof(micron_window_size))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/*get output size*/ ++static int pxa_cam_WCAM_VIDIOCGOSIZE(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ micron_window_size size; ++ dbg_print("WCAM_VIDIOCGOSIZE"); ++ size.width = cam_ctx->capture_width; ++ size.height = cam_ctx->capture_height; ++ if(copy_to_user(param, &size, sizeof(micron_window_size))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/*set picture style*/ ++static int pxa_cam_WCAM_VIDIOCSSTYLE(p_camera_context_t cam_ctx, void * param) ++{ ++ dbg_print("WCAM_VIDIOCSSTYLE"); ++ cam_ctx->capture_style = (V4l_PIC_STYLE)param; ++ ++ if(cam_ctx->capture_style != V4l_STYLE_BLACK_WHITE && cam_ctx->capture_style != V4l_STYLE_SEPIA) ++ { ++ mt9m111_set_light(cam_ctx->capture_light); ++ } ++ ++ return mt9m111_set_style(cam_ctx->capture_style); ++} ++ ++ ++/*set picture light*/ ++static int pxa_cam_WCAM_VIDIOCSLIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ ++ dbg_print("WCAM_VIDIOCSLIGHT"); ++ cam_ctx->capture_light = (V4l_PIC_WB)param; ++ if(cam_ctx->capture_style != V4l_STYLE_BLACK_WHITE && cam_ctx->capture_style != V4l_STYLE_SEPIA) ++ { ++ return mt9m111_set_light((V4l_PIC_WB)param); ++ } ++ return 0; ++} ++ ++/*set picture brightness*/ ++static int pxa_cam_WCAM_VIDIOCSBRIGHT(p_camera_context_t cam_ctx, void * param) ++{ ++ dbg_print("WCAM_VIDIOCSBRIGHT"); ++ cam_ctx->capture_bright = (int)param; ++ return mt9m111_set_bright((int)param); ++} ++ ++/*set frame buffer count*/ ++static int pxa_cam_WCAM_VIDIOCSBUFCOUNT(p_camera_context_t cam_ctx, void * param) ++{ ++// dbg_print(""); ++ int count; ++ if(copy_from_user(&count, param, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ if(cam_ctx->block_number_max == 0) ++ { ++ dbg_print("windows size or format not setting!!"); ++ return -EFAULT; ++ } ++ ++ if(count < FRAMES_IN_BUFFER) ++ { ++ count = FRAMES_IN_BUFFER; ++ } ++ ++ if(count > cam_ctx->block_number_max) ++ { ++ count = cam_ctx->block_number_max; ++ } ++ ++ ++ cam_ctx->block_number = count; ++ cam_ctx->block_header = cam_ctx->block_tail = 0; ++ //generate dma descriptor chain ++ update_dma_chain(cam_ctx); ++ ++ if(copy_to_user(param, &count, sizeof(int))) ++ { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*get cur avaliable frames*/ ++static int pxa_cam_WCAM_VIDIOCGCURFRMS(p_camera_context_t cam_ctx, void * param) ++{ ++// dbg_print(""); ++ struct {int first, last;}pos; ++ pos.first = cam_ctx->block_tail; ++ pos.last = cam_ctx->block_header; ++ ++ if(copy_to_user(param, &pos, sizeof(pos))) ++ { ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int pxa_camera_ioctl(struct video_device *dev, unsigned int cmd, void *param) ++{ ++ //dbg_print ("mt9m111: ioctl cmd = %d\n",cmd); ++ switch (cmd) ++ { ++ /*get capture capability*/ ++ case VIDIOCGCAP: ++ return pxa_camera_VIDIOCGCAP(g_camera_context, param); ++ ++ /* get capture size */ ++ case VIDIOCGWIN: ++ return pxa_camera_VIDIOCGWIN(g_camera_context, param); ++ ++ /* set capture size. */ ++ case VIDIOCSWIN: ++ return pxa_camera_VIDIOCSWIN(g_camera_context, param); ++ ++ /*set capture output format*/ ++ case VIDIOCSPICT: ++ return pxa_camera_VIDIOCSPICT(g_camera_context, param); ++ ++ /*get capture output format*/ ++ case VIDIOCGPICT: ++ return pxa_camera_VIDIOCGPICT(g_camera_context, param); ++ ++ /*start capture */ ++ case VIDIOCCAPTURE: ++ return pxa_camera_VIDIOCCAPTURE(g_camera_context, param); ++ ++ /* mmap interface */ ++ case VIDIOCGMBUF: ++ return pxa_camera_VIDIOCGMBUF(g_camera_context, param); ++ ++ /* Application extended IOCTL. */ ++ /* Register access interface */ ++ case WCAM_VIDIOCSINFOR: ++ return pxa_camera_WCAM_VIDIOCSINFOR(g_camera_context, param); ++ ++ /*get capture format*/ ++ case WCAM_VIDIOCGINFOR: ++ return pxa_camera_WCAM_VIDIOCGINFOR(g_camera_context, param); ++ ++ /*get ci reg value*/ ++ case WCAM_VIDIOCGCIREG: ++ return pxa_camera_WCAM_VIDIOCGCIREG(g_camera_context, param); ++ ++ /*set ci reg*/ ++ case WCAM_VIDIOCSCIREG: ++ return pxa_camera_WCAM_VIDIOCSCIREG(g_camera_context, param); ++#ifdef CONFIG_CAMERA_MT9M111 ++ ++ /*read mt9m111 registers*/ ++ case WCAM_VIDIOCGCAMREG: ++ return pxa_camera_WCAM_VIDIOCGCAMREG(g_camera_context, param); ++ ++ /*write mt9m111 registers*/ ++ case WCAM_VIDIOCSCAMREG: ++ return pxa_camera_WCAM_VIDIOCSCAMREG(g_camera_context, param); ++ ++ /*set sensor size */ ++ case WCAM_VIDIOCSSSIZE: ++ return pxa_cam_WCAM_VIDIOCSSSIZE(g_camera_context, param); ++ ++ /*get sensor size */ ++ case WCAM_VIDIOCGSSIZE: ++ return pxa_cam_WCAM_VIDIOCGSSIZE(g_camera_context, param); ++ ++ /*set output size*/ ++ case WCAM_VIDIOCSOSIZE: ++ return pxa_cam_WCAM_VIDIOCSOSIZE(g_camera_context, param); ++ ++ /*get output size*/ ++ case WCAM_VIDIOCGOSIZE: ++ return pxa_cam_WCAM_VIDIOCGOSIZE(g_camera_context, param); ++ ++ /*set video mode fps*/ ++ case WCAM_VIDIOCSFPS: ++ return pxa_cam_WCAM_VIDIOCSFPS(g_camera_context, param); ++ ++#endif ++ /*set picture style*/ ++ case WCAM_VIDIOCSSTYLE: ++ return pxa_cam_WCAM_VIDIOCSSTYLE(g_camera_context, param); ++ ++ /*set picture light*/ ++ case WCAM_VIDIOCSLIGHT: ++ return pxa_cam_WCAM_VIDIOCSLIGHT(g_camera_context, param); ++ ++ /*set picture brightness*/ ++ case WCAM_VIDIOCSBRIGHT: ++ return pxa_cam_WCAM_VIDIOCSBRIGHT(g_camera_context, param); ++ /*set frame buffer count*/ ++ case WCAM_VIDIOCSBUFCOUNT: ++ return pxa_cam_WCAM_VIDIOCSBUFCOUNT(g_camera_context, param); ++ ++ /*get cur avaliable frames*/ ++ case WCAM_VIDIOCGCURFRMS: ++ return pxa_cam_WCAM_VIDIOCGCURFRMS(g_camera_context, param); ++ default: ++ { ++ //dbg_print ("mt9m111: Invalid ioctl parameters.cmd = %d\n",cmd); ++ return -ENOIOCTLCMD; ++ break; ++ } ++ } ++ return 0; ++} ++ ++static int pxa_camera_mmap(struct video_device *dev, const char *adr, unsigned long size) ++{ ++ unsigned long start = (unsigned long)adr; ++ camera_context_t *cam_ctx = g_camera_context; ++ struct page **p_page = cam_ctx->page_array; ++ ++ size = PAGE_ALIGN(size); ++ while (size > 0) ++ { ++ if(remap_page_range(start, page_to_phys(*p_page), PAGE_SIZE, PAGE_SHARED)) ++ { ++ return -EFAULT; ++ } ++ start += PAGE_SIZE; ++ p_page++; ++ size -= PAGE_SIZE; ++ } ++ return 0; ++ } ++ ++unsigned int pxa_camera_poll(struct video_device *dev, struct file *file, poll_table *wait) ++{ ++ camera_context_t *cam_ctx = g_camera_context; ++ static int waited = 0; ++ ++ poll_wait(file, &camera_wait_q, wait); ++ ++ if(still_image_mode == 1 && still_image_rdy == 1) ++ { ++ still_image_rdy = 0; ++ waited = 0; ++ return POLLIN | POLLRDNORM; ++ } ++ ++ if(first_video_frame == 1) ++ first_video_frame = 0; ++ else if(still_image_mode == 0 && waited != 1) ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ ++ if(cam_ctx->block_header == cam_ctx->block_tail) ++ { ++ //dbg_print ("enter waiting, tail = %d, header = %d \n", cam_ctx->block_tail, cam_ctx->block_header); ++ task_waiting = 1; ++ waited = 1; ++ //interruptible_sleep_on (&camera_wait_q); ++ return 0; ++ } ++ else ++ { ++ waited = 0; ++ } ++ ++ return POLLIN | POLLRDNORM; ++} ++ ++int pxa_camera_mem_deinit() ++{ ++ if(g_camera_context) ++ { ++ if(g_camera_context->dma_descriptors_virtual != NULL) ++ { ++ consistent_free(g_camera_context->dma_descriptors_virtual, ++ MAX_DESC_NUM * sizeof(pxa_dma_desc), ++ (int)g_camera_context->dma_descriptors_physical); ++ ++ g_camera_context->dma_descriptors_virtual = NULL; ++ ++ } ++ if(g_camera_context->buffer_virtual != NULL) ++ { ++ pxa_dma_buffer_free(g_camera_context); ++ g_camera_context->buffer_virtual = NULL; ++ } ++ kfree(g_camera_context); ++ g_camera_context = NULL; ++ } ++ ++ return 0; ++} ++ ++int pxa_camera_mem_init() ++{ ++ g_camera_context = kmalloc(sizeof(struct camera_context_s), GFP_KERNEL); ++ ++ if(g_camera_context == NULL) ++ { ++ dbg_print( "PXA_CAMERA: Cann't allocate buffer for camera control structure \n"); ++ return -1; ++ } ++ ++ memset(g_camera_context, 0, sizeof(struct camera_context_s)); ++ ++ g_camera_context->dma_started = 0; ++ g_camera_context->dma_descriptors_virtual = consistent_alloc(GFP_KERNEL, MAX_DESC_NUM * sizeof(pxa_dma_desc), ++ (void *)&(g_camera_context->dma_descriptors_physical)); ++ if(g_camera_context->dma_descriptors_virtual == NULL) ++ { ++ dbg_print("consistent alloc memory for dma_descriptors_virtual fail!"); ++ goto err_init; ++ } ++ ++ g_camera_context->buf_size = BUF_SIZE_DEFT; ++ g_camera_context->dma_descriptors_size = MAX_DESC_NUM; ++ ++ ++ if(pxa_dma_buffer_init(g_camera_context) != 0) ++ { ++ dbg_print("alloc memory for buffer_virtual %d bytes fail!", g_camera_context->buf_size); ++ goto err_init; ++ } ++#ifdef CONFIG_CAMERA_MT9M111 ++ // init function dispatch table ++ mt9m111_func.init = camera_func_mt9m111_init; ++ mt9m111_func.deinit = camera_func_mt9m111_deinit; ++ mt9m111_func.set_capture_format = camera_func_mt9m111_set_capture_format; ++ mt9m111_func.start_capture = camera_func_mt9m111_start_capture; ++ mt9m111_func.stop_capture = camera_func_mt9m111_stop_capture; ++ ++ g_camera_context->camera_functions = &mt9m111_func; ++#endif ++ dbg_print("success!"); ++ return 0; ++ ++err_init: ++ pxa_camera_mem_deinit(); ++ return -1; ++} ++ ++int pxa_camera_video_init(struct video_device *vdev) ++{ ++ return 0; ++} ++ ++static struct video_device vd = { ++ owner: THIS_MODULE, ++ name: "E680 camera", ++ type: VID_TYPE_CAPTURE, ++ hardware: VID_HARDWARE_PXA_CAMERA, /* FIXME */ ++ open: pxa_camera_open, ++ close: pxa_camera_close, ++ read: pxa_camera_read, ++ poll: pxa_camera_poll, ++ ioctl: pxa_camera_ioctl, ++ mmap: pxa_camera_mmap, ++ initialize: pxa_camera_video_init, ++ minor: -1, ++}; ++ ++ ++ ++ ++#define MIN(a, b) ((a) < (b) ? (a) : (b)) ++#define MAX_WRITE_LEN 12 ++static ssize_t camera_write (struct file *file, const char *buf, size_t count, loff_t * pos) ++{ ++ ++ char feedback[2*MAX_WRITE_LEN + 1] ={0}; ++ char feedback1[2*MAX_WRITE_LEN + 1] = {0}; ++ size_t n = count; ++ size_t l; ++ char c; ++ int i,x,y,t; ++ ++ u16 reg, value; ++ ++ MOD_INC_USE_COUNT; ++ if (n > 0) ++ { ++ l = MIN (n, MAX_WRITE_LEN); ++ if (copy_from_user (feedback, buf, l)) ++ { ++ count = -EFAULT; ++ } ++ else ++ { ++ if (l > 0 && feedback[l - 1] == '\n') ++ { ++ l -= 1; ++ } ++ feedback[l] = 0; ++ n -= l; ++ // flush remainder, if any ++ while (n > 0) ++ { ++ // Not too efficient, but it shouldn't matter ++ if (copy_from_user (&c, buf + (count - n), 1)) ++ { ++ count = -EFAULT; ++ break; ++ } ++ n -= 1; ++ } ++ } ++ } ++ ++ i=1; ++ x=1; ++ y=1; ++ if (count > 0 && feedback[0] == '{') ++ { ++ while(feedback[i] != '}' && i<=MAX_WRITE_LEN*2) ++ { ++ c= feedback[i]; ++ i++; ++ if(c>='a' && c<='f') ++ { ++ c-=0x20; ++ } ++ if(!((c>='0'&& c<='9')||(c>='A'&&c<='F')||c==',')) ++ { ++ continue; ++ } ++ feedback1[x++] = c; ++ } ++ ++ feedback1[x]='}'; ++ feedback1[0]='{'; ++ for(i=1;i<=x;i++) ++ { ++ if(feedback1[i] == ',') ++ { ++ y=3; ++ for(t=i-1;t>=1;t--) ++ { ++ if(y==0) ++ break; ++ feedback[y--]=feedback1[t]; ++ } ++ if(y>=1) ++ { ++ for(t=y;t>=1;t--) ++ { ++ feedback[t] = '0'; ++ } ++ } ++ } ++ ++ if(feedback1[i] == '}') ++ { ++ y=8; ++ for(t=i-1;feedback1[t]!=','&&t>=1;t--) ++ { ++ if(y==4) ++ break; ++ feedback[y--]=feedback1[t]; ++ } ++ if(y>=5) ++ { ++ for(t=y;t>=5;t--) ++ { ++ feedback[t] = '0'; ++ } ++ } ++ } ++ } ++ ++ ++ reg = 16 * 16 * (feedback[1]>='A'?feedback[1]-'A'+10:feedback[1]-0x30) + 16 * (feedback[2]>='A'?feedback[2]-'A'+10:feedback[2]-0x30) + (feedback[3]>='A'?feedback[3]-'A'+10:feedback[3]-0x30) ; ++ value = 16 * 16 * 16 * (feedback[5]>='A'?feedback[5]-'A'+10:feedback[5]-0x30) + 16 *16* (feedback[6]>='A'?feedback[6]-'A'+10:feedback[6]-0x30) + 16 * (feedback[7]>='A'?feedback[7]-'A'+10:feedback[7]-0x30) + (feedback[8]>='A'?feedback[8]-'A'+10:feedback[8]-0x30) ; ++ ++ if(reg == 0xFFF && value == 0xFFFF) ++ { ++ mt9m111_dump_register(0,0x2ff,NULL); ++ } ++ else if(reg == 0xFFF) ++ { ++ mt9m111_reg_read(value); ++ } ++ else ++ mt9m111_write(reg, value); ++ } ++ MOD_DEC_USE_COUNT; ++ ++ return (count); ++} ++ ++ ++static struct file_operations camera_funcs = { ++ read:NULL, ++ write:camera_write, ++}; ++ ++ ++static int __init pxa_camera_init(void) ++{ ++ struct proc_dir_entry *pw; ++ /* 1. mapping CI registers, so that we can access the CI */ ++ if(request_irq(IRQ_CAMERA, pxa_camera_irq, 0, "PXA Camera", &vd)) ++ { ++ dbg_print ("Camera interrupt register failed failed number \n"); ++ return -EIO; ++ } ++ dbg_print ("Camera interrupt register successful \n"); ++ ++ ++ ci_dma_y = pxa_request_dma("CI_Y",DMA_PRIO_HIGH, pxa_ci_dma_irq_y, &vd); ++ if(ci_dma_y < 0) ++ { ++ dbg_print( "PXA_CAMERA: Cann't request DMA for Y\n"); ++ return -EIO; ++ } ++ dbg_print( "PXA_CAMERA: Request DMA for Y successfully [%d]\n",ci_dma_y); ++ ++ ci_dma_cb = pxa_request_dma("CI_Cb",DMA_PRIO_HIGH, pxa_ci_dma_irq_cb, &vd); ++ if(ci_dma_cb < 0) ++ { ++ dbg_print( "PXA_CAMERA: Cann't request DMA for Cb\n"); ++ return -EIO; ++ } ++ dbg_print( "PXA_CAMERA: Request DMA for Cb successfully [%d]\n",ci_dma_cb); ++ ++ ci_dma_cr = pxa_request_dma("CI_Cr",DMA_PRIO_HIGH, pxa_ci_dma_irq_cr, &vd); ++ if(ci_dma_cr < 0) ++ { ++ dbg_print( "PXA_CAMERA: Cann't request DMA for Cr\n"); ++ return -EIO; ++ } ++ ++ dbg_print( "PXA_CAMERA: Request DMA for Cr successfully [%d]\n",ci_dma_cr); ++ ++ ++ DRCMR68 = ci_dma_y | DRCMR_MAPVLD; ++ DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; ++ DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; ++ ++#ifdef CONFIG_CAMERA_OV9640 ++ minor =1; ++#endif ++ ++#ifdef CONFIG_CAMERA_MT9M111 ++ minor =0 ; ++#endif ++ ++ if(video_register_device(&vd, VFL_TYPE_GRABBER, minor) < 0) ++ { ++ dbg_print("PXA_CAMERA: video_register_device failed\n"); ++ return -EIO; ++ } ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, camera_pm_callback); ++#endif ++ ++ dbg_print("PXA_CAMERA: video_register_device successfully. /dev/video%d \n",minor); ++ ++ if ((pw = create_proc_entry ("cam", 0666, 0)) == NULL) ++ { ++ return -ENOMEM; ++ } ++ pw->proc_fops = &camera_funcs; ++ ++ return 0; ++} ++ ++static void __exit pxa_camera_exit(void) ++{ ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ if(ci_dma_y) ++ { ++ pxa_free_dma(ci_dma_y); ++ ci_dma_y = 0; ++ } ++ if(ci_dma_cb) ++ { ++ pxa_free_dma(ci_dma_cb); ++ ci_dma_cb = 0; ++ } ++ if(ci_dma_cr) ++ { ++ pxa_free_dma(ci_dma_cr); ++ ci_dma_cr = 0; ++ } ++ ++ DRCMR68 = 0; ++ DRCMR69 = 0; ++ DRCMR70 = 0; ++ ++ pxa_camera_mem_deinit(); ++ ++ free_irq(IRQ_CAMERA, &vd); ++ ++ video_unregister_device(&vd); ++ ++ ++ remove_proc_entry ("cam", NULL); ++ ++} ++ ++ ++//------------------------------------------------------------------------------------------------------- ++// Configuration APIs ++//------------------------------------------------------------------------------------------------------- ++void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate) ++{ ++ unsigned int value; ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_FR_RATE_SMASK << CI_CICR4_FR_RATE_SHIFT); ++ value |= (unsigned)frate << CI_CICR4_FR_RATE_SHIFT; ++ CICR4 = value; ++} ++ ++CI_FRAME_CAPTURE_RATE ci_get_frame_rate(void) ++{ ++ unsigned int value; ++ value = CICR4; ++ return (CI_FRAME_CAPTURE_RATE)((value >> CI_CICR4_FR_RATE_SHIFT) & CI_CICR4_FR_RATE_SMASK); ++} ++ ++void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format) ++{ ++ ++ unsigned int value, tbit, rgbt_conv, rgb_conv, rgb_f, ycbcr_f, rgb_bpp, raw_bpp, cspace; ++ // write cicr1: preserve ppl value and data width value ++ dbg_print("0"); ++ value = CICR1; ++ dbg_print("1"); ++ value &= ( (CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT) | ((CI_CICR1_DW_SMASK) << CI_CICR1_DW_SHIFT)); ++ tbit = rgbt_conv = rgb_conv = rgb_f = ycbcr_f = rgb_bpp = raw_bpp = cspace = 0; ++ switch(input_format) ++ { ++ case CI_RAW8: ++ cspace = 0; ++ raw_bpp = 0; ++ break; ++ case CI_RAW9: ++ cspace = 0; ++ raw_bpp = 1; ++ break; ++ case CI_RAW10: ++ cspace = 0; ++ raw_bpp = 2; ++ break; ++ case CI_YCBCR422: ++ case CI_YCBCR422_PLANAR: ++ cspace = 2; ++ if(output_format == CI_YCBCR422_PLANAR) ++ { ++ ycbcr_f = 1; ++ } ++ break; ++ case CI_RGB444: ++ cspace = 1; ++ rgb_bpp = 0; ++ break; ++ case CI_RGB555: ++ cspace = 1; ++ rgb_bpp = 1; ++ if(output_format == CI_RGBT555_0) ++ { ++ rgbt_conv = 2; ++ tbit = 0; ++ } ++ else if(output_format == CI_RGBT555_1) ++ { ++ rgbt_conv = 2; ++ tbit = 1; ++ } ++ break; ++ case CI_RGB565: ++ cspace = 1; ++ rgb_bpp = 2; ++ rgb_f = 1; ++ break; ++ case CI_RGB666: ++ cspace = 1; ++ rgb_bpp = 3; ++ if(output_format == CI_RGB666_PACKED) ++ { ++ rgb_f = 1; ++ } ++ break; ++ case CI_RGB888: ++ case CI_RGB888_PACKED: ++ cspace = 1; ++ rgb_bpp = 4; ++ switch(output_format) ++ { ++ case CI_RGB888_PACKED: ++ rgb_f = 1; ++ break; ++ case CI_RGBT888_0: ++ rgbt_conv = 1; ++ tbit = 0; ++ break; ++ case CI_RGBT888_1: ++ rgbt_conv = 1; ++ tbit = 1; ++ break; ++ case CI_RGB666: ++ rgb_conv = 1; ++ break; ++ // RGB666 PACKED - JamesL ++ case CI_RGB666_PACKED: ++ rgb_conv = 1; ++ rgb_f = 1; ++ break; ++ // end ++ case CI_RGB565: ++ dbg_print("format : 565"); ++ rgb_conv = 2; ++ break; ++ case CI_RGB555: ++ rgb_conv = 3; ++ break; ++ case CI_RGB444: ++ rgb_conv = 4; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ dbg_print("2"); ++ value |= (tbit==1) ? CI_CICR1_TBIT : 0; ++ value |= rgbt_conv << CI_CICR1_RGBT_CONV_SHIFT; ++ value |= rgb_conv << CI_CICR1_RGB_CONV_SHIFT; ++ value |= (rgb_f==1) ? CI_CICR1_RBG_F : 0; ++ value |= (ycbcr_f==1) ? CI_CICR1_YCBCR_F : 0; ++ value |= rgb_bpp << CI_CICR1_RGB_BPP_SHIFT; ++ value |= raw_bpp << CI_CICR1_RAW_BPP_SHIFT; ++ value |= cspace << CI_CICR1_COLOR_SP_SHIFT; ++ CICR1 = value; ++ ++} ++ ++void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width) ++{ ++ unsigned int value; ++ ++ // write mode field in cicr0 ++ value = CICR0; ++ value &= ~(CI_CICR0_SIM_SMASK << CI_CICR0_SIM_SHIFT); ++ value |= (unsigned int)mode << CI_CICR0_SIM_SHIFT; ++ CICR0 = value; ++ ++ // write data width cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_DW_SMASK << CI_CICR1_DW_SHIFT); ++ value |= ((unsigned)data_width) << CI_CICR1_DW_SHIFT; ++ CICR1 = value; ++ return; ++} ++ ++void ci_configure_mp(unsigned int ppl, unsigned int lpf, CI_MP_TIMING* timing) ++{ ++ unsigned int value; ++ // write ppl field in cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); ++ value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; ++ CICR1 = value; ++ ++ // write BLW, ELW in cicr2 ++ value = CICR2; ++ value &= ~(CI_CICR2_BLW_SMASK << CI_CICR2_BLW_SHIFT | CI_CICR2_ELW_SMASK << CI_CICR2_ELW_SHIFT ); ++ value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; ++ CICR2 = value; ++ ++ // write BFW, LPF in cicr3 ++ value = CICR3; ++ value &= ~(CI_CICR3_BFW_SMASK << CI_CICR3_BFW_SHIFT | CI_CICR3_LPF_SMASK << CI_CICR3_LPF_SHIFT ); ++ value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; ++ value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; ++ CICR3 = value; ++ ++} ++ ++void ci_configure_sp(unsigned int ppl, unsigned int lpf, CI_SP_TIMING* timing) ++{ ++ unsigned int value; ++ ++ // write ppl field in cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); ++ value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; ++ CICR1 = value; ++ ++ // write cicr2 ++ value = CICR2; ++ value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; ++ value |= (timing->ELW & CI_CICR2_ELW_SMASK) << CI_CICR2_ELW_SHIFT; ++ value |= (timing->HSW & CI_CICR2_HSW_SMASK) << CI_CICR2_HSW_SHIFT; ++ value |= (timing->BFPW & CI_CICR2_BFPW_SMASK) << CI_CICR2_BFPW_SHIFT; ++ value |= (timing->FSW & CI_CICR2_FSW_SMASK) << CI_CICR2_FSW_SHIFT; ++ CICR2 = value; ++ ++ // write cicr3 ++ value = CICR3; ++ value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; ++ value |= (timing->EFW & CI_CICR3_EFW_SMASK) << CI_CICR3_EFW_SHIFT; ++ value |= (timing->VSW & CI_CICR3_VSW_SMASK) << CI_CICR3_VSW_SHIFT; ++ value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; ++ CICR3 = value; ++ return; ++} ++ ++void ci_configure_ms(unsigned int ppl, unsigned int lpf, CI_MS_TIMING* timing) ++{ ++ // the operation is same as Master-Parallel ++ ci_configure_mp(ppl, lpf, (CI_MP_TIMING*)timing); ++} ++ ++void ci_configure_ep(int parity_check) ++{ ++ unsigned int value; ++ ++ // write parity_enable field in cicr0 ++ value = CICR0; ++ if(parity_check) ++ { ++ value |= CI_CICR0_PAR_EN; ++ } ++ else ++ { ++ value &= ~CI_CICR0_PAR_EN; ++ } ++ CICR0 = value; ++ return; ++} ++ ++void ci_configure_es(int parity_check) ++{ ++ // the operationi is same as Embedded-Parallel ++ ci_configure_ep(parity_check); ++} ++ ++void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz) ++{ ++ unsigned int ciclk, value, div, cccr_l, K; ++ ++ // determine the LCLK frequency programmed into the CCCR. ++ cccr_l = (CCCR & 0x0000001F); ++ ++ if(cccr_l < 8) ++ K = 1; ++ else if(cccr_l < 17) ++ K = 2; ++ else ++ K = 3; ++ ++ ciclk = (13 * cccr_l) / K; ++ ++ div = (ciclk + mclk_khz) / ( 2 * mclk_khz ) - 1 ; ++ dbg_print("cccr=%xciclk=%d,cccr_l=%d,K=%d,div=%d\n",CCCR,ciclk,cccr_l,K,div); ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK<<CI_CICR4_DIV_SHIFT); ++ value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0; ++ value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0; ++ value |= div << CI_CICR4_DIV_SHIFT; ++ CICR4 = value; ++ return; ++} ++ ++void ci_set_polarity(int pclk_sample_falling, int hsync_active_low, int vsync_active_low) ++{ ++ dbg_print(""); ++ unsigned int value; ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCP | CI_CICR4_HSP | CI_CICR4_VSP); ++ value |= (pclk_sample_falling)? CI_CICR4_PCP : 0; ++ value |= (hsync_active_low) ? CI_CICR4_HSP : 0; ++ value |= (vsync_active_low) ? CI_CICR4_VSP : 0; ++ CICR4 = value; ++ return; ++} ++ ++void ci_set_fifo(unsigned int timeout, CI_FIFO_THRESHOLD threshold, int fifo1_enable, ++ int fifo2_enable) ++{ ++ unsigned int value; ++ dbg_print(""); ++ // write citor ++ CITOR = timeout; ++ ++ // write cifr: always enable fifo 0! also reset input fifo ++ value = CIFR; ++ value &= ~(CI_CIFR_FEN0 | CI_CIFR_FEN1 | CI_CIFR_FEN2 | CI_CIFR_RESETF | ++ CI_CIFR_THL_0_SMASK<<CI_CIFR_THL_0_SHIFT); ++ value |= (unsigned int)threshold << CI_CIFR_THL_0_SHIFT; ++ value |= (fifo1_enable) ? CI_CIFR_FEN1 : 0; ++ value |= (fifo2_enable) ? CI_CIFR_FEN2 : 0; ++ value |= CI_CIFR_RESETF | CI_CIFR_FEN0; ++ CIFR = value; ++} ++ ++void ci_reset_fifo() ++{ ++ unsigned int value; ++ value = CIFR; ++ value |= CI_CIFR_RESETF; ++ CIFR = value; ++} ++ ++void ci_set_int_mask(unsigned int mask) ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value &= ~CI_CICR0_INTERRUPT_MASK; ++ value |= (mask & CI_CICR0_INTERRUPT_MASK); ++ dbg_print("-----------value=0x%x\n",value); ++ CICR0 = value; ++ return; ++} ++ ++unsigned int ci_get_int_mask() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ return (value & CI_CICR0_INTERRUPT_MASK); ++} ++ ++void ci_clear_int_status(unsigned int status) ++{ ++ // write 1 to clear ++ CISR = status; ++} ++ ++unsigned int ci_get_int_status() ++{ ++ int value; ++ ++ value = CISR; ++ ++ return value; ++} ++ ++void ci_set_reg_value(unsigned int reg_offset, unsigned int value) ++{ ++ CI_REG((u32)(ci_regs_base) + reg_offset) = value; ++} ++ ++int ci_get_reg_value(unsigned int reg_offset) ++{ ++ int value; ++ ++ value = CI_REG((u32)(ci_regs_base) + reg_offset); ++ return value; ++} ++ ++//------------------------------------------------------------------------------------------------------- ++// Control APIs ++//------------------------------------------------------------------------------------------------------- ++int ci_init() ++{ ++// (unsigned long*)ci_regs_base = (unsigned long*)ioremap(CI_REGS_PHYS, CI_REG_SIZE); ++ ++// if(ci_regs_base == NULL) ++// { ++// dbg_print ("ci regs base apply failed \n"); ++// return -1; ++// } ++ ++ // clear all CI registers ++ CICR0 = 0x3FF; // disable all interrupts ++ CICR1 = 0; ++ CICR2 = 0; ++ CICR3 = 0; ++ CICR4 = 0; ++ CISR = ~0; ++ CIFR = 0; ++ CITOR = 0; ++ ++ // enable CI clock ++ CKEN |= CKEN24_CAMERA; ++ return 0; ++} ++ ++void ci_deinit() ++{ ++ // disable CI clock ++ CKEN &= ~CKEN24_CAMERA; ++} ++ ++void ci_enable(int dma_en) ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value |= CI_CICR0_ENB; ++ if(dma_en) { ++ value |= CI_CICR0_DMA_EN; ++ } ++ CICR0 = value; ++ return; ++} ++ ++int ci_disable(int quick) ++{ ++ volatile unsigned int value, mask; ++ int retry; ++ ++ // write control bit in cicr0 ++ value = CICR0; ++ if(quick) ++ { ++ value &= ~CI_CICR0_ENB; ++ mask = CI_CISR_CQD; ++ } ++ else ++ { ++ value |= CI_CICR0_DIS; ++ mask = CI_CISR_CDD; ++ } ++ CICR0 = value; ++ ++ // wait shutdown complete ++ retry = 50; ++ while ( retry-- > 0 ) ++ { ++ value = CISR; ++ if( value & mask ) ++ { ++ CISR = mask; ++ return 0; ++ } ++ mdelay(10); ++ } ++ ++ return -1; ++} ++ ++void ci_slave_capture_enable() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value |= CI_CICR0_SL_CAP_EN; ++ CICR0 = value; ++ return; ++} ++ ++void ci_slave_capture_disable() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value &= ~CI_CICR0_SL_CAP_EN; ++ CICR0 = value; ++ return; ++} ++ ++void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs) ++{ ++ ++ static int dma_repeated = 0; ++ camera_context_t *cam_ctx = g_camera_context; ++ int dcsr; ++ ++ //dbg_print (""); ++ dcsr = DCSR(channel); ++ DCSR(channel) = dcsr & ~DCSR_STOPIRQEN; ++#ifdef CONFIG_OV9640 ++ if(dma_repeated==1) ++ repeated_n++; ++ else ++ irq_n ++; ++#endif ++ if(irq_n <14) ++ { ++ irq_n++; ++ } ++ else ++ {irq_n=0; ++ dbg_print("got 15 frame !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); ++ } ++ if(still_image_mode == 1) ++ { ++ ++ if(task_waiting == 1) ++ { ++ wake_up_interruptible (&camera_wait_q); ++ task_waiting = 0; ++ } ++ //else ++ { ++ still_image_rdy = 1; ++ stop_dma_transfer(g_camera_context); ++ dbg_print("Photo ready!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); ++ } ++ } ++ else if(dma_repeated == 0 && ++ (cam_ctx->block_tail == ((cam_ctx->block_header + 2) % cam_ctx->block_number))) ++ { ++ dma_repeated = 1; ++ pxa_dma_repeat(cam_ctx); ++ //dbg_print ("DMA repeated."); ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ } ++ else if(dma_repeated == 1 && ++ (cam_ctx->block_tail != ((cam_ctx->block_header + 1) % cam_ctx->block_number)) && ++ (cam_ctx->block_tail != ((cam_ctx->block_header + 2) % cam_ctx->block_number))) ++ { ++ pxa_dma_continue(cam_ctx); ++ //dbg_print ("DMA continue."); ++ dma_repeated = 0; ++ /* ++ if(task_waiting == 1) ++ { ++ wake_up_interruptible (&camera_wait_q); ++ task_waiting = 0; ++ } ++ */ ++ } ++ else if(dma_repeated == 0) ++ { ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ /* ++ if(task_waiting == 1) ++ { ++ wake_up_interruptible (&camera_wait_q); ++ task_waiting = 0; ++ } ++ */ ++ } ++ ++ if(task_waiting == 1 && !(cam_ctx->block_header == cam_ctx->block_tail)) ++ { ++ wake_up_interruptible (&camera_wait_q); ++ task_waiting = 0; ++ } ++ ++ //dbg_print("Get a frame: block-tail = %d, block-header = %d \n", cam_ctx->block_tail, cam_ctx->block_header); ++} ++ ++void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs) ++{ ++ return; ++} ++ ++void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs) ++{ ++ return; ++} ++ ++ ++void pxa_camera_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int cisr; ++ static int dma_started=0; ++ camera_irq_n++; ++ disable_irq(IRQ_CAMERA); ++ cisr = CISR; ++ if(cisr & CI_CISR_SOF) ++ { ++ if(dma_started == 0) ++ { ++ dma_started = 1; ++ } ++ CISR |= CI_CISR_SOF; ++ } ++ if(cisr & CI_CISR_EOF) ++ { ++ CISR |= CI_CISR_EOF; ++ } ++ enable_irq(IRQ_CAMERA); ++} ++ ++void pxa_dma_repeat(camera_context_t *cam_ctx) ++{ ++ pxa_dma_desc *cnt_head, *cnt_tail; ++ int cnt_block; ++ ++ cnt_block = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ ++ // FIFO0 ++ (pxa_dma_desc *)cnt_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + ++ cnt_block * cam_ctx->fifo0_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ ++ // FIFO1 ++ if(cam_ctx->fifo1_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + ++ cnt_block * cam_ctx->fifo1_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ ++ // FIFO2 ++ if(cam_ctx->fifo2_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + ++ cnt_block * cam_ctx->fifo2_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ } ++ ++void pxa_dma_continue(camera_context_t *cam_ctx) ++{ ++ pxa_dma_desc *cnt_head, *cnt_tail; ++ pxa_dma_desc *next_head; ++ int cnt_block, next_block; ++ ++ cnt_block = cam_ctx->block_header; ++ next_block = (cnt_block + 1) % cam_ctx->block_number; ++ ++ // FIFO0 ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + ++ cnt_block * cam_ctx->fifo0_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; ++ ++ next_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + ++ next_block * cam_ctx->fifo0_num_descriptors; ++ ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ ++ // FIFO1 ++ if(cam_ctx->fifo1_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + ++ cnt_block * cam_ctx->fifo1_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; ++ ++ next_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + ++ next_block * cam_ctx->fifo1_num_descriptors; ++ ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ ++ // FIFO2 ++ if(cam_ctx->fifo2_transfer_size) ++ { ++ cnt_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + ++ cnt_block * cam_ctx->fifo2_num_descriptors; ++ ++ cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; ++ ++ next_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + ++ next_block * cam_ctx->fifo2_num_descriptors; ++ ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ return; ++ ++} ++ ++void ci_dump(void) ++{ ++ dbg_print ("CICR0 = 0x%8x ", CICR0); ++ dbg_print ("CICR1 = 0x%8x ", CICR1); ++ dbg_print ("CICR2 = 0x%8x ", CICR2); ++ dbg_print ("CICR3 = 0x%8x ", CICR3); ++ dbg_print ("CICR4 = 0x%8x ", CICR4); ++ dbg_print ("CISR = 0x%8x ", CISR); ++ dbg_print ("CITOR = 0x%8x ", CITOR); ++ dbg_print ("CIFR = 0x%8x ", CIFR); ++} ++ ++ ++module_init(pxa_camera_init); ++module_exit(pxa_camera_exit); ++ ++MODULE_DESCRIPTION("Bulverde Camera Interface driver"); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOL; +diff -Nurd linux-2.6.16.orig/drivers/media/video/pxa_camera_ov.c linux-2.6.16/drivers/media/video/pxa_camera_ov.c +--- linux-2.6.16.orig/drivers/media/video/pxa_camera_ov.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/pxa_camera_ov.c 2006-06-03 11:14:56.727265400 +0200 +@@ -0,0 +1,2449 @@ ++/* ++ * pxa_camera.c ++ * ++ * Bulverde Processor Camera Interface driver. ++ * ++ * Copyright (C) 2003, Intel Corporation ++ * Copyright (C) 2003, Montavista Software Inc. ++ * ++ * Author: Intel Corporation Inc. ++ * MontaVista Software, Inc. ++ * source@mvista.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/pagemap.h> ++#include <linux/wrapper.h> ++#include <linux/videodev.h> ++#include <linux/pci.h> ++#include <linux/pm.h> ++#include <linux/poll.h> ++#include <linux/wait.h> ++#ifdef CONFIG_DPM ++#include <linux/device.h> ++#include <asm/arch/ldm.h> ++#endif ++ ++#include <linux/types.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/arch/irqs.h> ++ ++ ++#include "camera.h" ++ ++ ++#ifdef CONFIG_CAMERA_OV9640 ++#define OV9640 ++#elif defined CONFIG_CAMERA_ADCM2700 ++#define ADCM2700 ++#elif defined CONFIG_CAMERA_ADCM2650 ++#define ADCM2650 ++#endif ++ ++#ifdef ADCM2650 ++#include "pxa_camera.h" ++#include "adcm2650.h" ++#include "adcm2650_hw.h" ++#endif ++ ++#ifdef ADCM2700 ++#include "adcm2700.h" ++#include "adcm2700_hw.h" ++#endif ++ ++#ifdef OV9640 ++#include "ov9640.h" ++#include "ov9640_hw.h" ++#endif ++ ++#define PREFIX "PXA camera: " ++ ++#ifdef ADCM2650 ++#define MAX_WIDTH 480 ++#define MAX_HEIGHT 640 ++#define MIN_WIDTH 72 ++#define MIN_HEIGHT 72 ++#endif ++ ++#ifdef ADCM2700 ++#define MAX_WIDTH 480 ++#define MAX_HEIGHT 640 ++#define MIN_WIDTH 72 ++#define MIN_HEIGHT 72 ++#endif ++ ++#ifdef OV9640 ++/* in ov9640.h */ ++#endif ++ ++#define MAX_BPP 32 ++#define WIDTH_DEFT 320 ++#define HEIGHT_DEFT 240 ++#define FRAMERATE_DEFT 0x0 ++ ++ ++/* ++ * It is required to have at least 3 frames in buffer ++ * in current implementation ++ */ ++#define FRAMES_IN_BUFFER 3 ++#define MIN_FRAMES_IN_BUFFER 3 ++#define MAX_FRAME_SIZE (MAX_WIDTH * MAX_HEIGHT * (MAX_BPP >> 3)) ++#define BUF_SIZE_DEFT (MAX_FRAME_SIZE * MIN_FRAMES_IN_BUFFER) ++#define SINGLE_DESC_TRANS_MAX PAGE_SIZE ++#define MAX_DESC_NUM ((MAX_FRAME_SIZE / SINGLE_DESC_TRANS_MAX + 1) *\ ++ MIN_FRAMES_IN_BUFFER*2) ++ ++#define MAX_BLOCK_NUM 20 ++ ++static camera_context_t *g_camera_context = NULL; ++#ifdef ADCM2650 ++static camera_function_t adcm2650_func; ++#endif ++#ifdef ADCM2700 ++static camera_function_t adcm2700_func; ++#endif ++#ifdef OV9640 ++static camera_function_t ov9640_func; ++#endif ++wait_queue_head_t camera_wait_q; ++ ++/* /dev/videoX registration number */ ++static int minor = 0; ++static int ci_dma_y = -1; ++static int ci_dma_cb = -1; ++static int ci_dma_cr = -1; ++volatile int task_waiting = 0; ++static int still_image_mode = 0; ++static int still_image_rdy = 0; ++static int first_video_frame = 0; ++ ++void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs); ++void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs); ++void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs); ++ ++static unsigned long ci_regs_base = 0; /* for CI registers IOMEM mapping */ ++ ++#define CI_REG(x) (* (volatile u32*)(x) ) ++#define CI_REG_SIZE 0x40 /* 0x5000_0000 --- 0x5000_0038 * 64K */ ++#define CI_REGS_PHYS 0x50000000 /* Start phyical address of CI registers */ ++/* placed in include/asm/arch/pxa_regs.h ++#define CICR0 CI_REG((u32)(ci_regs_base) + 0x00) ++#define CICR1 CI_REG((u32)(ci_regs_base) + 0x04) ++#define CICR2 CI_REG((u32)(ci_regs_base) + 0x08) ++#define CICR3 CI_REG((u32)(ci_regs_base) + 0x0c) ++#define CICR4 CI_REG((u32)(ci_regs_base) + 0x10) ++#define CISR CI_REG((u32)(ci_regs_base) + 0x14) ++#define CIFR CI_REG((u32)(ci_regs_base) + 0x18) ++#define CITOR CI_REG((u32)(ci_regs_base) + 0x1c) ++#define CIBR0 CI_REG((u32)(ci_regs_base) + 0x28) ++#define CIBR1 CI_REG((u32)(ci_regs_base) + 0x30) ++#define CIBR2 CI_REG((u32)(ci_regs_base) + 0x38) ++*/ ++/*********************************************************************** ++ * ++ * Declarations ++ * ++ ***********************************************************************/ ++ ++// map of camera image format (camera.h) ==> capture interface format (ci.h) ++static const CI_IMAGE_FORMAT FORMAT_MAPPINGS[] = { ++ CI_RAW8, //RAW ++ CI_RAW9, ++ CI_RAW10, ++ ++ CI_RGB444, //RGB ++ CI_RGB555, ++ CI_RGB565, ++ CI_RGB666_PACKED, //RGB Packed ++ CI_RGB666, ++ CI_RGB888_PACKED, ++ CI_RGB888, ++ CI_RGBT555_0, //RGB+Transparent bit 0 ++ CI_RGBT888_0, ++ CI_RGBT555_1, //RGB+Transparent bit 1 ++ CI_RGBT888_1, ++ ++ CI_INVALID_FORMAT, ++ CI_YCBCR422, //YCBCR ++ CI_YCBCR422_PLANAR, //YCBCR Planaried ++ CI_INVALID_FORMAT, ++ CI_INVALID_FORMAT ++}; ++ ++static int update_dma_chain(p_camera_context_t cam_ctx); ++void start_dma_transfer(p_camera_context_t cam_ctx, unsigned block_id); ++void stop_dma_transfer(p_camera_context_t cam_ctx); ++static int start_capture(p_camera_context_t cam_ctx, unsigned int block_id, unsigned int frames); ++ ++static void pxa_dma_repeat(camera_context_t * cam_ctx); ++static void pxa_dma_continue(camera_context_t * cam_ctx); ++ ++#ifdef ADCM2650 ++extern int adcm2650_pipeline_read(u16 reg_addr, u16 * reg_value); ++extern int adcm2650_pipeline_write(u16 reg_addr, u16 reg_value); ++#define sensor_pipeline_read adcm2650_pipeline_read ++#define sensor_pipeline_write adcm2650_pipeline_write ++ ++#endif ++ ++#ifdef ADCM2700 ++extern int adcm2700_pipeline_read(u16 reg_addr, u16 * reg_value); ++extern int adcm2700_pipeline_write(u16 reg_addr, u16 reg_value); ++#define sensor_pipeline_read adcm2700_pipeline_read ++#define sensor_pipeline_write adcm2700_pipeline_write ++#endif ++ ++#ifdef OV9640 ++//int ov9640_pipeline_read( u16 reg_addr, u16 * reg_value){return 0;} ++//int ov9640_pipeline_write( u16 reg_addr, u16 reg_value){return 0;} ++#define sensor_pipeline_read ov9640_read ++#define sensor_pipeline_write ov9640_write ++#endif ++/*************** ++ * ++ * DPM functions ++ * ++ ***************/ ++#ifdef CONFIG_DPM ++ ++static int last_buffer_id; ++ ++static int pxa_camera_dpm_suspend(struct device *dev, u32 state, u32 level) ++{ ++ DPRINTK(KERN_DEBUG PREFIX "DPM suspend (state %d, level %d)\n", state, level); ++ switch (level) { ++ case SUSPEND_POWER_DOWN: ++ if (g_camera_context->dma_started) { ++ DPRINTK(KERN_DEBUG PREFIX "DMA running, suspended\n"); ++ last_buffer_id = camera_get_last_frame_buffer_id(g_camera_context); ++ stop_dma_transfer(g_camera_context); ++ } ++ disable_irq(IRQ_CAMERA); ++ CKEN &= ~CKEN24_CAMERA; ++ break; ++ } ++ return 0; ++} ++ ++static int pxa_camera_dpm_resume(struct device *dev, u32 level) ++{ ++ DPRINTK(KERN_DEBUG PREFIX "DPM resume (level %d)\n", level); ++ switch (level) { ++ case RESUME_POWER_ON: ++ CKEN |= CKEN24_CAMERA; ++ enable_irq(IRQ_CAMERA); ++ if (g_camera_context->dma_started) { ++ DPRINTK(KERN_DEBUG PREFIX "resume DMA\n"); ++ start_dma_transfer(g_camera_context, last_buffer_id); ++ } ++ break; ++ } ++ return 0; ++} ++ ++static int pxa_camera_dpm_scale(struct bus_op_point *op, u32 level) ++{ ++ DPRINTK(KERN_DEBUG PREFIX "DPM scale (level %d)\n", level); ++ /* CCCR is changed - adjust clock */ ++ ci_set_clock(g_camera_context->clk_reg_base, 1, 1, 7 /* MCLK_DEFT in adcm2650.c */ ); ++ return 0; ++} ++ ++static struct device_driver pxa_camera_driver_ldm = { ++ name:"camera", ++ devclass:NULL, ++ probe:NULL, ++ suspend:pxa_camera_dpm_suspend, ++ resume:pxa_camera_dpm_resume, ++ scale:pxa_camera_dpm_scale, ++ remove:NULL, ++ constraints:NULL ++}; ++ ++static struct device pxa_camera_device_ldm = { ++ name:"PXA camera", ++ bus_id:"video", ++ driver:NULL, ++ power_state:DPM_POWER_ON ++}; ++ ++static void pxa_camera_ldm_register(void) ++{ ++ pxaebc_driver_register(&pxa_camera_driver_ldm); ++ pxaebc_device_register(&pxa_camera_device_ldm); ++} ++ ++static void pxa_camera_ldm_unregister(void) ++{ ++ pxaebc_driver_unregister(&pxa_camera_driver_ldm); ++ pxaebc_device_unregister(&pxa_camera_device_ldm); ++} ++#endif /* CONFIG_DPM */ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++static int resume_dma = 0; ++ ++static int pxa_camera_pm_suspend() ++{ ++ if (g_camera_context != NULL) { ++ if (g_camera_context->dma_started) { ++ dbg_print("camera running, suspended"); ++ stop_dma_transfer(g_camera_context); ++ resume_dma = 1; ++ } ++ } ++ ++ disable_irq(IRQ_CAMERA); ++ CKEN &= ~CKEN24_CAMERA; ++ return 0; ++} ++ ++static int pxa_camera_pm_resume() ++{ ++ CKEN |= CKEN24_CAMERA; ++ enable_irq(IRQ_CAMERA); ++ ++ DPRINTK(" in %s, camera running, resumed", __FUNCTION__); ++ if (g_camera_context != NULL) { ++ /* ++ */ ++ struct video_window vw; ++ vw.width = g_camera_context->capture_width; ++ vw.height = g_camera_context->capture_height; ++ ov9640_set_window(&vw); ++ ++ // set_bright(g_camera_context->capture_bright); ++ ov9640_set_expose_compensation(g_camera_context->capture_bright); ++ // set_fps(g_camera_context->fps, g_camera_context->mini_fps); ++ ov9640_set_fps(g_camera_context->fps); ++ // set_light(g_camera_context->capture_light); ++ ov9640_set_light_environment(g_camera_context->capture_light); ++ // set_style(g_camera_context->capture_style); ++ ov9640_set_special_effect(g_camera_context->capture_style); ++ ++ if (resume_dma == 1) { ++ camera_start_video_capture(g_camera_context, 0); ++ resume_dma = 0; ++ } ++ ++ } ++ ++ return 0; ++} ++static int camera_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch (req) { ++ case PM_SUSPEND: ++ pxa_camera_pm_suspend(); ++ break; ++ ++ case PM_RESUME: ++ pxa_camera_pm_resume(); ++ break; ++ ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++ ++/*********************************************************************** ++ * ++ * Private functions ++ * ++ ***********************************************************************/ ++ ++static int pxa_dma_buffer_init(p_camera_context_t cam_ctx) ++{ ++ struct page *page; ++ unsigned int pages; ++ unsigned int page_count; ++ ++ cam_ctx->pages_allocated = 0; ++ ++ pages = (PAGE_ALIGN(cam_ctx->buf_size) / PAGE_SIZE); ++ ++ cam_ctx->page_array = (struct page **) kmalloc(pages * sizeof(struct page *), GFP_KERNEL); ++ if (cam_ctx->page_array == NULL) { ++ return -ENOMEM; ++ } ++ memset(cam_ctx->page_array, 0, pages * sizeof(struct page *)); ++ ++ for (page_count = 0; page_count < pages; page_count++) { ++ page = alloc_page(GFP_KERNEL); ++ if (page == NULL) { ++ goto error; ++ } ++ cam_ctx->page_array[page_count] = page; ++ set_page_count(page, 1); ++ SetPageReserved(page); ++ } ++ cam_ctx->buffer_virtual = remap_page_array(cam_ctx->page_array, pages, GFP_KERNEL); ++ ++ if (cam_ctx->buffer_virtual == NULL) { ++ goto error; ++ } ++ ++ cam_ctx->pages_allocated = pages; ++ ++ return 0; ++ ++ error: ++ for (page_count = 0; page_count < pages; page_count++) { ++ if ((page = cam_ctx->page_array[page_count]) != NULL) { ++ ClearPageReserved(page); ++ set_page_count(page, 1); ++ put_page(page); ++ } ++ } ++ kfree(cam_ctx->page_array); ++ ++ return -ENOMEM; ++} ++ ++static void pxa_dma_buffer_free(p_camera_context_t cam_ctx) ++{ ++ struct page *page; ++ int page_count; ++ ++ if (cam_ctx->buffer_virtual == NULL) ++ return; ++ ++ vfree(cam_ctx->buffer_virtual); ++ ++ for (page_count = 0; page_count < cam_ctx->pages_allocated; page_count++) { ++ if ((page = cam_ctx->page_array[page_count]) != NULL) { ++ ClearPageReserved(page); ++ set_page_count(page, 1); ++ put_page(page); ++ } ++ } ++ kfree(cam_ctx->page_array); ++} ++ ++/* ++Generate dma descriptors ++Pre-condition: these variables must be set properly ++ block_number, fifox_transfer_size ++ dma_descriptors_virtual, dma_descriptors_physical, dma_descirptors_size ++Post-condition: these variables will be set ++ fifox_descriptors_virtual, fifox_descriptors_physical ++ fifox_num_descriptors ++*/ ++int update_dma_chain(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; ++ int des_transfer_size, remain_size; ++ unsigned int i, j; ++ ++ int target_page_num; ++ ++ // clear descriptor pointers ++ cam_ctx->fifo0_descriptors_virtual = cam_ctx->fifo0_descriptors_physical = 0; ++ cam_ctx->fifo1_descriptors_virtual = cam_ctx->fifo1_descriptors_physical = 0; ++ cam_ctx->fifo2_descriptors_virtual = cam_ctx->fifo2_descriptors_physical = 0; ++ ++ // calculate how many descriptors are needed per frame ++ cam_ctx->fifo0_num_descriptors = cam_ctx->pages_per_fifo0; ++ ++ cam_ctx->fifo1_num_descriptors = cam_ctx->pages_per_fifo1; ++ ++ cam_ctx->fifo2_num_descriptors = cam_ctx->pages_per_fifo2; ++ ++ // check if enough memory to generate descriptors ++ if ((cam_ctx->fifo0_num_descriptors + cam_ctx->fifo1_num_descriptors + ++ cam_ctx->fifo2_num_descriptors) * cam_ctx->block_number > cam_ctx->dma_descriptors_size) ++ return -1; ++ ++ // generate fifo0 dma chains ++ cam_ctx->fifo0_descriptors_virtual = (unsigned) cam_ctx->dma_descriptors_virtual; ++ cam_ctx->fifo0_descriptors_physical = (unsigned) cam_ctx->dma_descriptors_physical; ++ cur_des_virtual = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual; ++ cur_des_physical = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_physical; ++ ++ for (i = 0; i < cam_ctx->block_number; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo0_transfer_size; ++ ++ // assume the blocks are stored consecutively ++ target_page_num = cam_ctx->pages_per_block * i; ++ ++ for (j = 0; j < cam_ctx->fifo0_num_descriptors; j++) { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR0_PHY; // FIFO0 physical address ++ cur_des_virtual->dtadr = page_to_bus(cam_ctx->page_array[target_page_num]); ++ cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo0_descriptors_physical); ++ ++ // generate fifo1 dma chains ++ if (cam_ctx->fifo1_transfer_size) { ++ // record fifo1 descriptors' start address ++ cam_ctx->fifo1_descriptors_virtual = (unsigned) cur_des_virtual; ++ cam_ctx->fifo1_descriptors_physical = (unsigned) cur_des_physical; ++ ++ for (i = 0; i < cam_ctx->block_number; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo1_transfer_size; ++ ++ target_page_num = cam_ctx->pages_per_block * i + cam_ctx->pages_per_fifo0; ++ ++ for (j = 0; j < cam_ctx->fifo1_num_descriptors; j++) { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR1_PHY; // FIFO1 physical address ++ cur_des_virtual->dtadr = page_to_bus(cam_ctx->page_array[target_page_num]); ++ cur_des_virtual->dcmd = ++ des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo1_descriptors_physical); ++ } ++ // generate fifo2 dma chains ++ if (cam_ctx->fifo2_transfer_size) { ++ // record fifo1 descriptors' start address ++ cam_ctx->fifo2_descriptors_virtual = (unsigned) cur_des_virtual; ++ cam_ctx->fifo2_descriptors_physical = (unsigned) cur_des_physical; ++ ++ for (i = 0; i < cam_ctx->block_number; i++) { ++ // in each iteration, generate one dma chain for one frame ++ remain_size = cam_ctx->fifo2_transfer_size; ++ ++ target_page_num = cam_ctx->pages_per_block * i + ++ cam_ctx->pages_per_fifo0 + cam_ctx->pages_per_fifo1; ++ ++ for (j = 0; j < cam_ctx->fifo2_num_descriptors; j++) { ++ // set descriptor ++ if (remain_size > SINGLE_DESC_TRANS_MAX) ++ des_transfer_size = SINGLE_DESC_TRANS_MAX; ++ else ++ des_transfer_size = remain_size; ++ cur_des_virtual->ddadr = (unsigned) cur_des_physical + sizeof(pxa_dma_desc); ++ cur_des_virtual->dsadr = CIBR2_PHY; // FIFO2 physical address ++ cur_des_virtual->dtadr = page_to_bus(cam_ctx->page_array[target_page_num]); ++ cur_des_virtual->dcmd = ++ des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; ++ ++ // advance pointers ++ remain_size -= des_transfer_size; ++ cur_des_virtual++; ++ cur_des_physical++; ++ target_page_num++; ++ } ++ ++ // stop the dma transfer on one frame captured ++ last_des_virtual = cur_des_virtual - 1; ++ //last_des_virtual->ddadr |= 0x1; ++ } ++ last_des_virtual->ddadr = ((unsigned) cam_ctx->fifo2_descriptors_physical); ++ } ++ return 0; ++} ++ ++void start_dma_transfer(p_camera_context_t cam_ctx, unsigned block_id) ++{ ++ pxa_dma_desc *des_virtual, *des_physical; ++ ++ DPRINTK("in %s,cam_ctx->block_number =%d\n", __FUNCTION__, cam_ctx->block_number); ++ /* ++ if (block_id >= cam_ctx->block_number) ++ return; ++ */ ++ // start channel 0 ++ des_virtual = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual + block_id * cam_ctx->fifo0_num_descriptors; ++ des_physical = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_physical + block_id * cam_ctx->fifo0_num_descriptors; ++ ++ DDADR(cam_ctx->dma_channels[0]) = des_physical; ++ DCSR(cam_ctx->dma_channels[0]) |= DCSR_RUN; ++ ++ // start channel 1 ++ if (cam_ctx->fifo1_descriptors_virtual) { ++ des_virtual = (pxa_dma_desc *) cam_ctx->fifo1_descriptors_virtual + ++ block_id * cam_ctx->fifo1_num_descriptors; ++ des_physical = (pxa_dma_desc *) cam_ctx->fifo1_descriptors_physical + ++ block_id * cam_ctx->fifo1_num_descriptors; ++ DDADR(cam_ctx->dma_channels[1]) = des_physical; ++ DCSR(cam_ctx->dma_channels[1]) |= DCSR_RUN; ++ } ++ // start channel 2 ++ if (cam_ctx->fifo2_descriptors_virtual) { ++ des_virtual = (pxa_dma_desc *) cam_ctx->fifo2_descriptors_virtual + ++ block_id * cam_ctx->fifo2_num_descriptors; ++ des_physical = (pxa_dma_desc *) cam_ctx->fifo2_descriptors_physical + ++ block_id * cam_ctx->fifo2_num_descriptors; ++ DDADR(cam_ctx->dma_channels[2]) = des_physical; ++ DCSR(cam_ctx->dma_channels[2]) |= DCSR_RUN; ++ } ++ cam_ctx->dma_started = 1; ++} ++ ++void set_still_image_ready(int rdy) ++{ ++ still_image_rdy = rdy; ++} ++ ++void stop_dma_transfer(p_camera_context_t cam_ctx) ++{ ++ int ch0, ch1, ch2; ++ ++ ch0 = cam_ctx->dma_channels[0]; ++ ch1 = cam_ctx->dma_channels[1]; ++ ch2 = cam_ctx->dma_channels[2]; ++ DCSR(ch0) &= ~DCSR_RUN; ++ DCSR(ch1) &= ~DCSR_RUN; ++ DCSR(ch2) &= ~DCSR_RUN; ++ cam_ctx->dma_started = 0; ++#ifdef CONFIG_DPM ++#endif ++} ++int start_capture(p_camera_context_t cam_ctx, unsigned int block_id, unsigned int frames) ++{ ++ int status; ++ int i; ++ ++ // clear ci fifo ++ ci_reset_fifo(); ++ ci_clear_int_status(0xFFFFFFFF); ++ ++ // start dma ++ start_dma_transfer(cam_ctx, block_id); ++ ++ // start capture ++ status = cam_ctx->camera_functions->start_capture(cam_ctx, frames); ++ return status; ++} ++ ++/*********************************************************************** ++ * ++ * Init/Deinit APIs ++ * ++ ***********************************************************************/ ++int camera_init(p_camera_context_t cam_ctx) ++{ ++ int ret = 0; ++ int i; ++ ++// parameter check ++ if (cam_ctx->buffer_virtual == NULL || cam_ctx->buf_size == 0) ++ return STATUS_WRONG_PARAMETER; ++ if (cam_ctx->dma_descriptors_virtual == NULL || ++ cam_ctx->dma_descriptors_physical == NULL || cam_ctx->dma_descriptors_size == 0) ++ return STATUS_WRONG_PARAMETER; ++ if (cam_ctx->sensor_type > CAMERA_TYPE_MAX) ++ return STATUS_WRONG_PARAMETER; ++ if (cam_ctx->capture_input_format > CAMERA_IMAGE_FORMAT_MAX || ++ cam_ctx->capture_output_format > CAMERA_IMAGE_FORMAT_MAX) ++ return STATUS_WRONG_PARAMETER; ++ ++ // check the function dispatch table according to the sensor type ++ if (!cam_ctx->camera_functions) ++ return STATUS_WRONG_PARAMETER; ++ if (!cam_ctx->camera_functions->init || ++ !cam_ctx->camera_functions->deinit || ++ !cam_ctx->camera_functions->set_capture_format || ++ !cam_ctx->camera_functions->start_capture || !cam_ctx->camera_functions->stop_capture) ++ return STATUS_WRONG_PARAMETER; ++ ++ // init context status ++ for (i = 0; i < 3; i++) ++ cam_ctx->dma_channels[i] = 0xFF; ++ (int) cam_ctx->fifo0_descriptors_virtual = NULL; ++ (int) cam_ctx->fifo1_descriptors_virtual = NULL; ++ (int) cam_ctx->fifo2_descriptors_virtual = NULL; ++ (int) cam_ctx->fifo0_descriptors_physical = NULL; ++ (int) cam_ctx->fifo1_descriptors_physical = NULL; ++ (int) cam_ctx->fifo2_descriptors_physical = NULL; ++ ++ cam_ctx->fifo0_num_descriptors = 0; ++ cam_ctx->fifo1_num_descriptors = 0; ++ cam_ctx->fifo2_num_descriptors = 0; ++ ++ cam_ctx->fifo0_transfer_size = 0; ++ cam_ctx->fifo1_transfer_size = 0; ++ cam_ctx->fifo2_transfer_size = 0; ++ ++ cam_ctx->block_number = 0; ++ cam_ctx->block_size = 0; ++ cam_ctx->block_header = 0; ++ cam_ctx->block_tail = 0; ++ ++ // Enable hardware ++ camera_gpio_init(); ++ DPRINTK("gpio init\n"); ++ ++ // capture interface init ++ ci_init(); ++ ++ // sensor init ++ ret = cam_ctx->camera_functions->init(cam_ctx); ++ DPRINTK("after cam_ctx->camera_functions->init\n"); ++ if (ret) ++ goto camera_init_err; ++ ++ ++ cam_ctx->dma_channels[0] = ci_dma_y; ++ cam_ctx->dma_channels[1] = ci_dma_cb; ++ cam_ctx->dma_channels[2] = ci_dma_cr; ++ DRCMR68 = ci_dma_y | DRCMR_MAPVLD; ++ DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; ++ DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; ++ ++ ++ // set capture format ++ ret = camera_set_capture_format(cam_ctx); ++ if (ret) ++ goto camera_init_err; ++ ++ // set frame rate ++ //camera_set_capture_frame_rate(cam_ctx); ++ ++ return 0; ++ ++ camera_init_err: ++ camera_deinit(cam_ctx); ++ return -1; ++} ++ ++void camera_gpio_init() ++{ ++#ifdef ADCM2650 ++ set_GPIO_mode(27 | GPIO_ALT_FN_3_IN); /* CIF_DD[0] */ ++ set_GPIO_mode(114 | GPIO_ALT_FN_1_IN); /* CIF_DD[1] */ ++ set_GPIO_mode(116 | GPIO_ALT_FN_1_IN); /* CIF_DD[2] */ ++ set_GPIO_mode(115 | GPIO_ALT_FN_2_IN); /* CIF_DD[3] */ ++ set_GPIO_mode(90 | GPIO_ALT_FN_3_IN); /* CIF_DD[4] */ ++ set_GPIO_mode(91 | GPIO_ALT_FN_3_IN); /* CIF_DD[5] */ ++ set_GPIO_mode(17 | GPIO_ALT_FN_2_IN); /* CIF_DD[6] */ ++ set_GPIO_mode(12 | GPIO_ALT_FN_2_IN); /* CIF_DD[7] */ ++ set_GPIO_mode(23 | GPIO_ALT_FN_1_OUT); /* CIF_MCLK */ ++ set_GPIO_mode(26 | GPIO_ALT_FN_2_IN); /* CIF_PCLK */ ++ set_GPIO_mode(25 | GPIO_ALT_FN_1_IN); /* CIF_LV */ ++ set_GPIO_mode(24 | GPIO_ALT_FN_1_IN); /* CIF_FV */ ++#endif ++ ++#ifdef OV9640 ++ set_GPIO_mode(27 | GPIO_ALT_FN_3_IN); /* CIF_DD[0] */ ++ set_GPIO_mode(114 | GPIO_ALT_FN_1_IN); /* CIF_DD[1] */ ++ set_GPIO_mode(51 | GPIO_ALT_FN_1_IN); /* CIF_DD[2] */ ++ set_GPIO_mode(115 | GPIO_ALT_FN_2_IN); /* CIF_DD[3] */ ++ set_GPIO_mode(95 | GPIO_ALT_FN_2_IN); /* CIF_DD[4] */ ++ set_GPIO_mode(94 | GPIO_ALT_FN_2_IN); /* CIF_DD[5] */ ++ set_GPIO_mode(17 | GPIO_ALT_FN_2_IN); /* CIF_DD[6] */ ++ set_GPIO_mode(108 | GPIO_ALT_FN_1_IN); /* CIF_DD[7] */ ++ set_GPIO_mode(23 | GPIO_ALT_FN_1_OUT); /* CIF_MCLK */ ++ set_GPIO_mode(54 | GPIO_ALT_FN_3_IN); /* CIF_PCLK */ ++ set_GPIO_mode(85 | GPIO_ALT_FN_3_IN); /* CIF_LV */ ++ set_GPIO_mode(84 | GPIO_ALT_FN_3_IN); /* CIF_FV */ ++ set_GPIO_mode(50 | GPIO_OUT); /*CIF_PD */ ++ set_GPIO_mode(19 | GPIO_OUT); /*CIF_RST */ ++ ++#endif ++ ++#ifdef ADCM2700 ++ set_GPIO_mode(CIF_PD_MD); /*CIF_PD */ ++ GPCR(CIF_PD) |= GPIO_bit(CIF_PD); /*set to low */ ++ set_GPIO_mode(CIF_RST_MD); /*CIF_RST */ ++ GPSR(CIF_RST) |= GPIO_bit(CIF_RST); /*set to high */ ++ set_GPIO_mode(CIF_DD0_MD); /* CIF_DD[0] */ ++ set_GPIO_mode(CIF_DD1_MD); /* CIF_DD[1] */ ++ set_GPIO_mode(CIF_DD2_MD); /* CIF_DD[2] */ ++ set_GPIO_mode(CIF_DD3_MD); /* CIF_DD[3] */ ++ set_GPIO_mode(CIF_DD4_MD); /* CIF_DD[4] */ ++ set_GPIO_mode(CIF_DD5_MD); /* CIF_DD[5] */ ++ set_GPIO_mode(CIF_DD6_MD); /* CIF_DD[6] */ ++ set_GPIO_mode(CIF_DD7_MD); /* CIF_DD[7] */ ++ set_GPIO_mode(CIF_MCLK_MD); /* CIF_MCLK */ ++ set_GPIO_mode(CIF_PCLK_MD); /* CIF_PCLK */ ++ set_GPIO_mode(CIF_LV_MD); /* CIF_LV */ ++ set_GPIO_mode(CIF_FV_MD); /* CIF_FV */ ++ ++#endif ++ ++ return; ++} ++ ++int camera_deinit(p_camera_context_t cam_ctx) ++{ ++ int ret = 0; ++ ++ ret = cam_ctx->camera_functions->deinit(cam_ctx); ++ ++ // capture interface deinit ++ ci_deinit(); ++ return ret; ++} ++ ++/*********************************************************************** ++ * ++ * Capture APIs ++ * ++ ***********************************************************************/ ++// Set the image format ++ ++int camera_set_capture_format(p_camera_context_t cam_ctx) ++{ ++ int ret; ++ unsigned frame_size; ++ CI_IMAGE_FORMAT ci_input_format, ci_output_format; ++ CI_MP_TIMING timing; ++ ++ // set capture interface ++ if (cam_ctx->capture_input_format > CAMERA_IMAGE_FORMAT_MAX || ++ cam_ctx->capture_output_format > CAMERA_IMAGE_FORMAT_MAX) ++ return STATUS_WRONG_PARAMETER; ++ ci_input_format = FORMAT_MAPPINGS[cam_ctx->capture_input_format]; ++ ci_output_format = FORMAT_MAPPINGS[cam_ctx->capture_output_format]; ++ if (ci_input_format == CI_INVALID_FORMAT || ci_output_format == CI_INVALID_FORMAT) ++ return STATUS_WRONG_PARAMETER; ++ ci_set_image_format(ci_input_format, ci_output_format); ++ ++ // ring buffer init ++ switch (cam_ctx->capture_output_format) { ++ case CAMERA_IMAGE_FORMAT_RGB565: ++ frame_size = cam_ctx->capture_width * cam_ctx->capture_height * 2; ++ cam_ctx->fifo0_transfer_size = frame_size; ++ cam_ctx->fifo1_transfer_size = 0; ++ cam_ctx->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED: ++ frame_size = cam_ctx->capture_width * cam_ctx->capture_height * 2; ++ cam_ctx->fifo0_transfer_size = frame_size; ++ cam_ctx->fifo1_transfer_size = 0; ++ cam_ctx->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR: ++ frame_size = cam_ctx->capture_width * cam_ctx->capture_height * 2; ++ cam_ctx->fifo0_transfer_size = frame_size / 2; ++ cam_ctx->fifo1_transfer_size = frame_size / 4; ++ cam_ctx->fifo2_transfer_size = frame_size / 4; ++ break; ++// RGB666 support - JamesL ++ case CAMERA_IMAGE_FORMAT_RGB666_PLANAR: ++ frame_size = cam_ctx->capture_width * cam_ctx->capture_height * 4; ++ cam_ctx->fifo0_transfer_size = frame_size; ++ cam_ctx->fifo1_transfer_size = 0; ++ cam_ctx->fifo2_transfer_size = 0; ++ break; ++ case CAMERA_IMAGE_FORMAT_RGB666_PACKED: ++ frame_size = cam_ctx->capture_width * cam_ctx->capture_height * 3; ++ cam_ctx->fifo0_transfer_size = frame_size; ++ cam_ctx->fifo1_transfer_size = 0; ++ cam_ctx->fifo2_transfer_size = 0; ++ break; ++// RGB888 support - JamesL ++ case CAMERA_IMAGE_FORMAT_RGB888_PLANAR: ++ frame_size = cam_ctx->capture_width * cam_ctx->capture_height * 4; ++ cam_ctx->fifo0_transfer_size = frame_size; ++ cam_ctx->fifo1_transfer_size = 0; ++ cam_ctx->fifo2_transfer_size = 0; ++ break; ++// ++ default: ++ return STATUS_WRONG_PARAMETER; ++ break; ++ } ++ cam_ctx->block_size = frame_size; ++ ++ cam_ctx->pages_per_fifo0 = (PAGE_ALIGN(cam_ctx->fifo0_transfer_size) / PAGE_SIZE); ++ cam_ctx->pages_per_fifo1 = (PAGE_ALIGN(cam_ctx->fifo1_transfer_size) / PAGE_SIZE); ++ cam_ctx->pages_per_fifo2 = (PAGE_ALIGN(cam_ctx->fifo2_transfer_size) / PAGE_SIZE); ++ ++ cam_ctx->pages_per_block = cam_ctx->pages_per_fifo0 + cam_ctx->pages_per_fifo1 + cam_ctx->pages_per_fifo2; ++ ++ cam_ctx->page_aligned_block_size = cam_ctx->pages_per_block * PAGE_SIZE; ++ ++ cam_ctx->block_number = cam_ctx->pages_allocated / cam_ctx->pages_per_block; ++ cam_ctx->block_number_max = cam_ctx->pages_allocated / cam_ctx->pages_per_block; ++ DPRINTK("in %s,cam_ctx->block_number =%d \n", __FUNCTION__, cam_ctx->block_number); ++ ++ if (cam_ctx->block_number > 3) ++ cam_ctx->block_number = 3; ++ ++ if (cam_ctx->block_number > VIDEO_MAX_FRAME) ++ cam_ctx->block_number = VIDEO_MAX_FRAME; ++ ++ //cam_ctx->block_header = cam_ctx->block_tail = 0; ++ ++ // generate dma descriptor chain ++ ret = update_dma_chain(cam_ctx); ++ if (ret) ++ return -1; ++ timing.BFW = timing.BLW = 0; ++ ci_configure_mp(cam_ctx->capture_width - 1, cam_ctx->capture_height - 1, &timing); ++ DPRINTK("before cam_ctx->camera_functions->set_capture_format \n"); ++ // set sensor setting ++ ret = cam_ctx->camera_functions->set_capture_format(cam_ctx); ++ if (ret) ++ return ret; ++ ++ DPRINTK("after cam_ctx->camera_functions->set_capture_format \n"); ++ return 0; ++} ++ ++// take a picture and copy it into the ring buffer ++int camera_capture_still_image(p_camera_context_t cam_ctx, unsigned int block_id) ++{ ++ int status; ++ ++ // init buffer status & capture ++ cam_ctx->block_header = cam_ctx->block_tail = block_id; ++ cam_ctx->capture_status = 0; ++ status = start_capture(cam_ctx, block_id, 1); ++ ++ return status; ++} ++ ++// capture motion video and copy it to the ring buffer ++int camera_start_video_capture(p_camera_context_t cam_ctx, unsigned int block_id) ++{ ++ int status; ++ ++ // init buffer status & capture ++ cam_ctx->block_header = cam_ctx->block_tail = block_id; ++ cam_ctx->capture_status = CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS; ++ status = start_capture(cam_ctx, block_id, 0); ++ ++ return status; ++} ++ ++// disable motion video image capture ++void camera_stop_video_capture(p_camera_context_t cam_ctx) ++{ ++ int status; ++ ++ // stop capture ++ status = cam_ctx->camera_functions->stop_capture(cam_ctx); ++ ++ // stop dma ++ stop_dma_transfer(cam_ctx); ++ ++ // update the flag ++ if (!(cam_ctx->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ cam_ctx->capture_status &= ~CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS; ++ return; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Flow Control APIs ++ * ++ ***********************************************************************/ ++// continue capture image to next available buffer ++void camera_continue_transfer(p_camera_context_t cam_ctx) ++{ ++ // don't think we need this either. JR ++ // continue transfer on next block ++ start_dma_transfer(cam_ctx, cam_ctx->block_tail); ++} ++ ++// Return 1: there is available buffer, 0: buffer is full ++int camera_next_buffer_available(p_camera_context_t cam_ctx) ++{ ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ if (((cam_ctx->block_header + 1) % cam_ctx->block_number) != cam_ctx->block_tail) { ++ return 1; ++ } ++ cam_ctx->capture_status |= CAMERA_STATUS_RING_BUFFER_FULL; ++ ++ return 0; ++} ++ ++// Application supplies the FrameBufferID to the driver to tell it that the application has completed processing of ++// the given frame buffer, and that buffer is now available for re-use. ++void camera_release_frame_buffer(p_camera_context_t cam_ctx, unsigned int frame_buffer_id) ++{ ++ ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ ++ // restart video capture only if video capture is in progress and space is available for image capture ++ if ((cam_ctx->capture_status & CAMERA_STATUS_RING_BUFFER_FULL) && ++ (cam_ctx->capture_status & CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS)) { ++ if (((cam_ctx->block_header + 2) % cam_ctx->block_number) != cam_ctx->block_tail) { ++ cam_ctx->capture_status &= ~CAMERA_STATUS_RING_BUFFER_FULL; ++ start_capture(cam_ctx, cam_ctx->block_tail, 0); ++ } ++ } ++} ++ ++// Returns the FrameBufferID for the first filled frame ++// Note: -1 represents buffer empty ++int camera_get_first_frame_buffer_id(p_camera_context_t cam_ctx) ++{ ++ // not sure if this routine makes any sense.. JR ++ ++ // check whether buffer is empty ++ if ((cam_ctx->block_header == cam_ctx->block_tail) && ++ !(cam_ctx->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ return -1; ++ ++ // return the block header ++ return cam_ctx->block_header; ++} ++ ++// Returns the FrameBufferID for the last filled frame, this would be used if we were polling for image completion data, ++// or we wanted to make sure there were no frames waiting for us to process. ++// Note: -1 represents buffer empty ++int camera_get_last_frame_buffer_id(p_camera_context_t cam_ctx) ++{ ++ int ret; ++ ++ // check whether buffer is empty ++ if ((cam_ctx->block_header == cam_ctx->block_tail) && ++ !(cam_ctx->capture_status & CAMERA_STATUS_RING_BUFFER_FULL)) ++ return -1; ++ ++ // return the block before the block_tail ++ ret = (cam_ctx->block_tail + cam_ctx->block_number - 1) % cam_ctx->block_number; ++ return ret; ++} ++ ++/*********************************************************************** ++ * ++ * Buffer Info APIs ++ * ++ ***********************************************************************/ ++// Return: the number of frame buffers allocated for use. ++unsigned int camera_get_num_frame_buffers(p_camera_context_t cam_ctx) ++{ ++ return cam_ctx->block_number; ++} ++ ++// FrameBufferID is a number between 0 and N-1, where N is the total number of frame buffers in use. Returns the address of ++// the given frame buffer. The application will call this once for each frame buffer at application initialization only. ++void *camera_get_frame_buffer_addr(p_camera_context_t cam_ctx, unsigned int frame_buffer_id) ++{ ++ return (void *) ((unsigned) cam_ctx->buffer_virtual + cam_ctx->page_aligned_block_size * frame_buffer_id); ++} ++ ++// Return the block id ++int camera_get_frame_buffer_id(p_camera_context_t cam_ctx, void *address) ++{ ++ if (((unsigned) address >= ++ (unsigned) cam_ctx->buffer_virtual) && ++ ((unsigned) address <= (unsigned) cam_ctx->buffer_virtual + cam_ctx->buf_size)) { ++ return ((unsigned) address - (unsigned) cam_ctx->buffer_virtual) / cam_ctx->page_aligned_block_size; ++ } ++ return -1; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Frame rate APIs ++ * ++ ***********************************************************************/ ++// Set desired frame rate ++void camera_set_capture_frame_rate(p_camera_context_t cam_ctx) ++{ ++ ci_set_frame_rate(cam_ctx->frame_rate); ++ return; ++} ++ ++// return current setting ++void camera_get_capture_frame_rate(p_camera_context_t cam_ctx) ++{ ++ cam_ctx->frame_rate = ci_get_frame_rate(); ++ return; ++} ++ ++ ++/*********************************************************************** ++ * ++ * Interrupt APIs ++ * ++ ***********************************************************************/ ++// set interrupt mask ++void camera_set_int_mask(p_camera_context_t cam_ctx, unsigned int mask) ++{ ++ pxa_dma_desc *end_des_virtual; ++ int dma_interrupt_on; ++ unsigned int i; ++ ++ // set CI interrupt ++ ci_set_int_mask(mask & CI_CICR0_INTERRUPT_MASK); ++ ++ // set dma end interrupt ++ if (mask & CAMERA_INTMASK_END_OF_DMA) ++ dma_interrupt_on = 1; ++ else ++ dma_interrupt_on = 0; ++ ++ // set fifo0 dma chains' flag ++ end_des_virtual = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual + cam_ctx->fifo0_num_descriptors - 1; ++ for (i = 0; i < cam_ctx->block_number; i++) { ++ if (dma_interrupt_on) ++ end_des_virtual->dcmd |= DCMD_ENDIRQEN; ++ else ++ end_des_virtual->dcmd &= ~DCMD_ENDIRQEN; ++ end_des_virtual += cam_ctx->fifo0_num_descriptors; ++ } ++} ++ ++// get interrupt mask ++unsigned int camera_get_int_mask(p_camera_context_t cam_ctx) ++{ ++ pxa_dma_desc *end_des_virtual; ++ unsigned int ret; ++ ++ // get CI mask ++ ret = ci_get_int_mask(); ++ ++ // get dma end mask ++ end_des_virtual = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual + cam_ctx->fifo0_num_descriptors - 1; ++ if (end_des_virtual->dcmd & DCMD_ENDIRQEN) ++ ret |= CAMERA_INTMASK_END_OF_DMA; ++ ++ return ret; ++} ++ ++// clear interrupt status ++void camera_clear_int_status(p_camera_context_t cam_ctx, unsigned int status) ++{ ++ ci_clear_int_status((status & 0xFFFF)); ++} ++ ++/*********************************************************************************** ++* Application interface * ++***********************************************************************************/ ++static int pxa_camera_open(struct video_device *dev, int flags) ++{ ++ int status = -1; ++ camera_context_t *cam_ctx; ++ ++ init_waitqueue_head(&camera_wait_q); ++ if (pxa_camera_mem_init()) { ++ DPRINTK("DMA memory allocate failed!"); ++ return -1; ++ } ++ DPRINTK("in %s, after pxa_camera_mem_init \n", __FUNCTION__); ++ cam_ctx = g_camera_context; ++ if (atomic_read(&cam_ctx->refcount)) ++ return -EBUSY; ++ atomic_inc(&cam_ctx->refcount); ++ ++ ++#ifdef ADCM2650 ++ cam_ctx->sensor_type = CAMERA_TYPE_ADCM_2650; ++#endif ++#ifdef ADCM2700 ++ cam_ctx->sensor_type = CAMERA_TYPE_ADCM_2700; ++#endif ++#ifdef OV9640 ++ cam_ctx->sensor_type = CAMERA_TYPE_OMNIVISION_9640; ++#endif ++ cam_ctx->capture_width = WIDTH_DEFT; ++ cam_ctx->capture_height = HEIGHT_DEFT; ++ cam_ctx->capture_input_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->capture_output_format = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ cam_ctx->frame_rate = FRAMERATE_DEFT; ++ ++ // init function dispatch table ++#ifdef ADCM2650 ++ adcm2650_func.init = camera_func_adcm2650_init; ++ adcm2650_func.deinit = camera_func_adcm2650_deinit; ++ adcm2650_func.set_capture_format = camera_func_adcm2650_set_capture_format; ++ adcm2650_func.start_capture = camera_func_adcm2650_start_capture; ++ adcm2650_func.stop_capture = camera_func_adcm2650_stop_capture; ++ cam_ctx->camera_functions = &adcm2650_func; ++#endif ++ ++#ifdef ADCM2700 ++ adcm2700_func.init = camera_func_adcm2700_init; ++ adcm2700_func.deinit = camera_func_adcm2700_deinit; ++ adcm2700_func.set_capture_format = camera_func_adcm2700_set_capture_format; ++ adcm2700_func.start_capture = camera_func_adcm2700_start_capture; ++ adcm2700_func.stop_capture = camera_func_adcm2700_stop_capture; ++ cam_ctx->camera_functions = &adcm2700_func; ++#endif ++ ++#ifdef OV9640 ++ ov9640_func.init = camera_func_ov9640_init; ++ ov9640_func.deinit = camera_func_ov9640_deinit; ++ ov9640_func.set_capture_format = camera_func_ov9640_set_capture_format; ++ ov9640_func.start_capture = camera_func_ov9640_start_capture; ++ ov9640_func.stop_capture = camera_func_ov9640_stop_capture; ++ ov9640_func.command = camera_func_ov9640_command; ++ cam_ctx->camera_functions = &ov9640_func; ++#endif ++ ++ cam_ctx->ost_reg_base = 0; ++ cam_ctx->gpio_reg_base = 0; ++ cam_ctx->ci_reg_base = 0; ++ cam_ctx->board_reg_base = 0; ++ still_image_rdy = 0; ++ ++ /* FIXME: handle camera_init() errors ? */ ++ status = camera_init(cam_ctx); ++ DPRINTK(KERN_DEBUG PREFIX "camera opened\n"); ++ status = 0; ++ return status; ++} ++ ++static void pxa_camera_close(struct video_device *dev) ++{ ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ DPRINTK(KERN_DEBUG PREFIX "camera closed\n"); ++ atomic_dec(&cam_ctx->refcount); ++ camera_deinit(cam_ctx); ++ pxa_camera_mem_deinit(); ++} ++ ++#define PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, size) \ ++do { \ ++ unsigned int len; \ ++ unsigned int remain_size = size; \ ++ while (remain_size > 0) { \ ++ if (remain_size > PAGE_SIZE) \ ++ len = PAGE_SIZE; \ ++ else \ ++ len = remain_size; \ ++ if (copy_to_user(buf, page_address(*p_page), len)) \ ++ return -EFAULT; \ ++ remain_size -= len; \ ++ buf += len; \ ++ p_page++; \ ++ } \ ++} while (0); ++ ++ ++static long pxa_camera_read(struct video_device *dev, char *buf, unsigned long count, int noblock) ++{ ++ struct page **p_page; ++ ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ if (still_image_mode == 1) { ++ while (still_image_rdy != 1) ++ mdelay(1); ++ /* ++ if (cam_ctx->capture_width ==1280 && cam_ctx->capture_height==960) ++ cam_ctx->block_tail = cam_ctx->block_header = 0; ++ else if (cam_ctx->capture_width==960 && cam_ctx->capture_height==480) ++ cam_ctx->block_tail = cam_ctx->block_header = 2; ++ DPRINTK("cam_ctx->block_number =%d \n",cam_ctx->block_number); ++ cam_ctx->camera_functions->stop_capture(cam_ctx); ++ */ ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo0_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo1_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo2_transfer_size); ++ ++ still_image_rdy = 0; ++ return cam_ctx->block_size; ++ } ++ if (still_image_mode == 0) { ++ if (first_video_frame == 1) ++ cam_ctx->block_tail = cam_ctx->block_header; ++ else ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ } ++ ++ first_video_frame = 0; ++ ++ if (cam_ctx->block_header == cam_ctx->block_tail) { ++ if (still_image_mode == 0) { ++ task_waiting = 1; ++ interruptible_sleep_on(&camera_wait_q); ++ } else { ++ while (still_image_rdy != 1) { ++ DPRINTK("wait still_image_rdy =1 \n"); ++ mdelay(1); ++ } ++ } ++ } ++ ++ p_page = &cam_ctx->page_array[cam_ctx->block_tail * cam_ctx->pages_per_block]; ++ ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo0_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo1_transfer_size); ++ PXA_CAMERA_BUFFER_COPY_TO_USER(buf, p_page, cam_ctx->fifo2_transfer_size); ++ ++ return cam_ctx->block_size; ++} ++ ++int camera_sleep() ++{ ++ interruptible_sleep_on(&camera_wait_q); ++} ++ ++struct reg_set_s { ++ int val1; ++ int val2; ++}; ++ ++static int pxa_camera_ioctl(struct video_device *dev, unsigned int cmd, void *param) ++{ ++ int retval = 0; ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ switch (cmd) { ++/* V4L Standard IOCTL. */ ++ case VIDIOCGCAP: ++ { ++ struct video_capability vc; ++ strcpy(vc.name, "Bulverde Camera"); ++ vc.maxwidth = MAX_WIDTH; ++ vc.maxheight = MAX_HEIGHT; ++#ifdef OV9640 ++ vc.maxwidth = 1280; ++ vc.maxheight = 960; ++#endif ++ vc.minwidth = MIN_WIDTH; ++ vc.minheight = MIN_HEIGHT; ++ if (copy_to_user(param, &vc, sizeof(struct video_capability))) ++ return -EFAULT; ++ break; ++ } ++ ++ ++ case VIDIOCSPICT: ++ { ++ struct video_picture vp; ++ if (copy_from_user(&vp, param, sizeof(vp))) { ++ retval = -EFAULT; ++ break; ++ } ++ cam_ctx->capture_output_format = vp.palette; ++ retval = camera_set_capture_format(cam_ctx); ++ break; ++ } ++ case VIDIOCGPICT: ++ { ++ struct video_picture vp; ++ vp.palette = cam_ctx->capture_output_format; ++ if (copy_to_user(param, &vp, sizeof(struct video_picture))) ++ retval = -EFAULT; ++ break; ++ } ++ ++ case VIDIOCCAPTURE: ++ { ++ int capture_flag; ++ ++ capture_flag = (int) param; ++/* Still Image Capture */ ++ if (capture_flag == STILL_IMAGE) { ++ camera_set_int_mask(cam_ctx, 0x3ff | 0x0400); ++ still_image_mode = 1; ++ task_waiting = 0; ++ camera_capture_still_image(cam_ctx, 0); ++ cam_ctx->block_header = 0; ++ cam_ctx->block_tail = 0; ++ break; ++ } ++/* Video Capture Start */ ++ else if (capture_flag == VIDEO_START) { ++ camera_set_int_mask(cam_ctx, 0x3ff | 0x0400); ++ cam_ctx->block_header = 0; ++ cam_ctx->block_tail = 0; ++ still_image_mode = 0; ++ first_video_frame = 1; ++ camera_start_video_capture(cam_ctx, 0); ++ break; ++ } ++/* Video Capture Stop */ ++ else if (capture_flag == VIDEO_STOP) { ++ camera_set_int_mask(cam_ctx, 0x3ff); ++ camera_stop_video_capture(cam_ctx); ++ break; ++ } else { ++ retval = -EFAULT; ++ break; ++ } ++ } ++ ++/* mmap interface */ ++ case VIDIOCGMBUF: ++ { ++ struct video_mbuf vm; ++ int i; ++ ++ memset(&vm, 0, sizeof(vm)); ++ vm.size = cam_ctx->buf_size; ++ vm.frames = cam_ctx->block_number; ++ for (i = 0; i < vm.frames; i++) ++ vm.offsets[i] = cam_ctx->page_aligned_block_size * i; ++ ++ if (copy_to_user((void *) param, (void *) &vm, sizeof(vm))) ++ retval = -EFAULT; ++ break; ++ } ++ ++/* Application extended IOCTL. */ ++/* Register access interface */ ++ case WCAM_VIDIOCSINFOR: ++ { ++ struct reg_set_s reg_s; ++ if (copy_from_user(®_s, param, sizeof(int) * 2)) { ++ retval = -EFAULT; ++ break; ++ } ++ cam_ctx->capture_input_format = reg_s.val1; ++ cam_ctx->capture_output_format = reg_s.val2; ++ ++ retval = camera_set_capture_format(cam_ctx); ++ DPRINTK("WCAM_VIDIOCSINFOR retval=%d\n", retval); ++ break; ++ } ++ ++ case WCAM_VIDIOCGINFOR: ++ { ++ struct reg_set_s reg_s; ++ reg_s.val1 = cam_ctx->capture_input_format; ++ reg_s.val2 = cam_ctx->capture_output_format; ++ if (copy_to_user(param, ®_s, sizeof(int) * 2)) ++ retval = -EFAULT; ++ break; ++ } ++ ++ case WCAM_VIDIOCGCIREG: ++ { ++ struct reg_set_s reg_s; ++ if (copy_from_user(®_s, param, sizeof(int) * 2)) { ++ retval = -EFAULT; ++ break; ++ } ++ ++ reg_s.val2 = ci_get_reg_value(reg_s.val1); ++ if (copy_to_user(param, ®_s, sizeof(int) * 2)) ++ retval = -EFAULT; ++ break; ++ } ++ ++ case WCAM_VIDIOCSCIREG: ++ { ++ struct reg_set_s reg_s; ++ if (copy_from_user(®_s, param, sizeof(int) * 2)) { ++ retval = -EFAULT; ++ break; ++ } ++ ci_set_reg_value(reg_s.val1, reg_s.val2); ++ break; ++ } ++ ++ case WCAM_VIDIOCGCAMREG: ++ { ++ struct reg_set_s reg_s; ++ if (copy_from_user(®_s, param, sizeof(int) * 2)) { ++ retval = -EFAULT; ++ break; ++ } ++ sensor_pipeline_read((u16) reg_s.val1, (u16 *) & reg_s.val2); ++ DPRINTK("WCAM_VIDIOCGCAMREG reg.val1=0x%x,reg.val2=0x%x\n", reg_s.val1, reg_s.val2); ++ if (copy_to_user(param, ®_s, sizeof(int) * 2)) ++ retval = -EFAULT; ++ ci_dump(); ++ break; ++ } ++ ++ case WCAM_VIDIOCSCAMREG: ++ { ++ struct reg_set_s reg_s; ++ if (copy_from_user(®_s, param, sizeof(int) * 2)) { ++ retval = -EFAULT; ++ break; ++ } ++ sensor_pipeline_write((u16) reg_s.val1, (u16) reg_s.val2); ++ break; ++ } ++ /*set frame buffer count */ ++ case WCAM_VIDIOCSBUFCOUNT: ++ { ++ int count; ++ if (copy_from_user(&count, param, sizeof(int))) { ++ return -EFAULT; ++ } ++ if (cam_ctx->block_number_max == 0) { ++ dbg_print("windows size or format not setting!!"); ++ return -EFAULT; ++ } ++ ++ if (count >= FRAMES_IN_BUFFER && count <= cam_ctx->block_number_max) { ++ cam_ctx->block_number = count; ++ cam_ctx->block_header = cam_ctx->block_tail = 0; ++ // generate dma descriptor chain ++ update_dma_chain(cam_ctx); ++ } ++ ++ count = cam_ctx->block_number; ++ ++ if (copy_to_user(param, &count, sizeof(int))) { ++ return -EFAULT; ++ } ++ ++ } ++ break; ++ /*get cur avaliable frames */ ++ case WCAM_VIDIOCGCURFRMS: ++ { ++ struct { ++ int first, last; ++ } pos; ++ pos.first = cam_ctx->block_tail; ++ pos.last = cam_ctx->block_header; ++ ++ if (copy_to_user(param, &pos, sizeof(pos))) { ++ return -EFAULT; ++ } ++ } ++ ++ break; ++ ++ default: ++ { ++ int ret; ++ DPRINTK("in _ioctl default command,param=%d!!!!!!!!!!!!!!!!!!!!\n", param); ++ ret = cam_ctx->camera_functions->command(cam_ctx, cmd, param); ++ DPRINTK("cam_ctx->camera_functions->command ret=%d\n", ret); ++ retval = ret; ++ if (ret) { ++ DPRINTK(KERN_WARNING PREFIX "invalid ioctl %x\n", cmd); ++ retval = -ENOIOCTLCMD; ++ } ++ break; ++ } ++ } ++ return retval; ++} ++ ++static int pxa_camera_mmap(struct video_device *dev, const char *adr, unsigned long size) ++{ ++ unsigned long start = (unsigned long) adr; ++ camera_context_t *cam_ctx = g_camera_context; ++ struct page **p_page = cam_ctx->page_array; ++ ++ size = PAGE_ALIGN(size); ++ while (size > 0) { ++ if (remap_page_range(start, page_to_phys(*p_page), PAGE_SIZE, PAGE_SHARED)) { ++ return -EFAULT; ++ } ++ start += PAGE_SIZE; ++ p_page++; ++ size -= PAGE_SIZE; ++ } ++ return 0; ++} ++ ++unsigned int pxa_camera_poll(struct video_device *dev, struct file *file, poll_table * wait) ++{ ++ camera_context_t *cam_ctx = g_camera_context; ++ static int waited = 0; ++ ++ poll_wait(file, &camera_wait_q, wait); ++ ++ if (still_image_mode == 1) ++ if (still_image_rdy == 1) { ++ still_image_rdy = 0; ++ write_balance(); ++ return POLLIN | POLLRDNORM; ++ } ++ //else ++ // return 0; ++ if (first_video_frame == 1) ++ first_video_frame = 0; ++ else if (still_image_mode == 0 && waited != 1) ++ cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; ++ ++ if (cam_ctx->block_header == cam_ctx->block_tail) { ++ DPRINTK("enter poll waiting, tail = %d, header = %d \n", cam_ctx->block_tail, cam_ctx->block_header); ++ task_waiting = 1; ++ waited = 1; ++ //interruptible_sleep_on(&camera_wait_q); ++ return 0; ++ } else ++ waited = 0; ++ ++ write_balance(); ++ return POLLIN | POLLRDNORM; ++} ++ ++ ++int pxa_camera_video_init(struct video_device *vdev) ++{ ++ DPRINTK(KERN_DEBUG PREFIX "camera initialized\n"); ++ return 0; ++} ++ ++ ++static struct video_device vd = { ++ owner:THIS_MODULE, ++ name:"PXA Camera", ++ type:VID_TYPE_CAPTURE, ++ hardware:VID_HARDWARE_PXA_CAMERA, /* FIXME */ ++ open:pxa_camera_open, ++ close:pxa_camera_close, ++ read:pxa_camera_read, ++ poll:pxa_camera_poll, ++ ioctl:pxa_camera_ioctl, ++ mmap:pxa_camera_mmap, ++ initialize:pxa_camera_video_init, ++ minor:-1, ++}; ++ ++int pxa_camera_mem_deinit() ++{ ++ camera_context_t *cam_ctx = g_camera_context; ++ if (ci_regs_base) ++ iounmap((unsigned long *) ci_regs_base); ++ if (g_camera_context) { ++ if (cam_ctx->dma_descriptors_virtual) { ++ consistent_free(cam_ctx->dma_descriptors_virtual, ++ MAX_DESC_NUM * sizeof(pxa_dma_desc), (int) cam_ctx->dma_descriptors_physical); ++ g_camera_context->dma_descriptors_virtual = NULL; ++ } ++ ++ if (cam_ctx->buffer_virtual) { ++ pxa_dma_buffer_free(cam_ctx); ++ g_camera_context->buffer_virtual = NULL; ++ ++ } ++ ++ kfree(g_camera_context); ++ g_camera_context = NULL; ++ } ++ return 0; ++} ++ ++int pxa_camera_mem_init() ++{ ++ p_camera_context_t cam_ctx; ++ (unsigned long *) ci_regs_base = (unsigned long *) ioremap(CI_REGS_PHYS, CI_REG_SIZE); ++ if (!ci_regs_base) { ++ DPRINTK(KERN_ERR PREFIX "can't remap I/O registers at %x\n", CI_REGS_PHYS); ++ return -1; ++ } ++ ++ cam_ctx = (camera_context_t *) ++ kmalloc(sizeof(struct camera_context_s), GFP_KERNEL); ++ if (cam_ctx == NULL) { ++ DPRINTK(KERN_WARNING PREFIX "can't allocate buffer for camera control structure\n"); ++ return -1; ++ } ++ g_camera_context = cam_ctx; ++ memset(g_camera_context, 0, sizeof(struct camera_context_s)); ++ atomic_set(&cam_ctx->refcount, 0); ++ cam_ctx->dma_started = 0; ++ ++ cam_ctx->dma_descriptors_virtual = ++ consistent_alloc(GFP_KERNEL, MAX_DESC_NUM * sizeof(pxa_dma_desc), ++ (void *) &cam_ctx->dma_descriptors_physical); ++ if (cam_ctx->dma_descriptors_virtual == NULL) { ++ DPRINTK(KERN_WARNING PREFIX ++ "memory allocation for DMA descriptors (%ld bytes) failed\n", ++ MAX_DESC_NUM * sizeof(pxa_dma_desc)); ++ goto err_mem; ++ } ++ ++ cam_ctx->buf_size = BUF_SIZE_DEFT; ++ ++ if (pxa_dma_buffer_init(cam_ctx) != 0) { ++ DPRINTK(KERN_WARNING PREFIX ++ "memory allocation for capture buffer (%d bytes) failed\n", cam_ctx->buf_size); ++ goto err_mem; ++ } ++ ++ cam_ctx->dma_descriptors_size = MAX_DESC_NUM; ++ return 0; ++ err_mem: ++ pxa_camera_mem_deinit(); ++ return -ENXIO; ++} ++ ++static int __init pxa_camera_init(void) ++{ ++ camera_context_t *cam_ctx = NULL; ++ int err; ++ ++ /* 1. mapping CI registers, so that we can access the CI */ ++ if ((err = request_irq(IRQ_CAMERA, pxa_camera_irq, 0, "PXA Camera", &vd))) { ++ DPRINTK(KERN_WARNING PREFIX "camera interrupt register failed, error %d\n", err); ++ return -ENXIO; ++ } ++ ci_dma_y = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, pxa_ci_dma_irq_y, &vd); ++ if (ci_dma_y < 0) { ++ DPRINTK(KERN_WARNING PREFIX "can't request DMA for Y\n"); ++ goto err_init; ++ } ++ ci_dma_cb = pxa_request_dma("CI_Cb", DMA_PRIO_HIGH, pxa_ci_dma_irq_cb, &vd); ++ if (ci_dma_cb < 0) { ++ DPRINTK(KERN_WARNING PREFIX "can't request DMA for Cb\n"); ++ goto err_init; ++ } ++ ci_dma_cr = pxa_request_dma("CI_Cr", DMA_PRIO_HIGH, pxa_ci_dma_irq_cr, &vd); ++ if (ci_dma_cr < 0) { ++ DPRINTK(KERN_WARNING PREFIX "can't request DMA for Cr\n"); ++ goto err_init; ++ } ++ ++ DRCMR68 = ci_dma_y | DRCMR_MAPVLD; ++ DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; ++ DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; ++ ++ ++ if (video_register_device(&vd, VFL_TYPE_GRABBER, minor) < 0) { ++ DPRINTK(KERN_WARNING PREFIX "can't register video device\n"); ++ goto err_init; ++ } ++#ifdef CONFIG_DPM ++ pxa_camera_ldm_register(); ++#endif ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, camera_pm_callback); ++#endif ++ ++ ++ DPRINTK(KERN_NOTICE PREFIX "video device registered, use device /dev/video%d \n", minor); ++ return 0; ++ ++ err_init: ++ free_irq(IRQ_CAMERA, &vd); ++ ++ if (ci_dma_y >= 0) ++ pxa_free_dma(ci_dma_y); ++ ++ if (ci_dma_cb >= 0) ++ pxa_free_dma(ci_dma_cb); ++ ++ if (ci_dma_cr >= 0) ++ pxa_free_dma(ci_dma_cr); ++ ++ DRCMR68 = 0; ++ DRCMR69 = 0; ++ DRCMR70 = 0; ++ ++ return 0; ++} ++ ++static void __exit pxa_camera_exit(void) ++{ ++ camera_context_t *cam_ctx = g_camera_context; ++#ifdef CONFIG_DPM ++ pxa_camera_ldm_unregister(); ++#endif ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ ++ video_unregister_device(&vd); ++ ++ free_irq(IRQ_CAMERA, &vd); ++ ++ if (ci_dma_y >= 0) ++ pxa_free_dma(ci_dma_y); ++ ++ if (ci_dma_cb >= 0) ++ pxa_free_dma(ci_dma_cb); ++ ++ if (ci_dma_cr >= 0) ++ pxa_free_dma(ci_dma_cr); ++ ++ DRCMR68 = 0; ++ DRCMR69 = 0; ++ DRCMR70 = 0; ++ ++ pxa_camera_mem_deinit(); ++ ++} ++ ++//------------------------------------------------------------------------------------------------------- ++// Configuration APIs ++//------------------------------------------------------------------------------------------------------- ++void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate) ++{ ++ unsigned int value; ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_FR_RATE_SMASK << CI_CICR4_FR_RATE_SHIFT); ++ value |= (unsigned) frate << CI_CICR4_FR_RATE_SHIFT; ++ CICR4 = value; ++} ++ ++CI_FRAME_CAPTURE_RATE ci_get_frame_rate(void) ++{ ++ unsigned int value; ++ value = CICR4; ++ return (CI_FRAME_CAPTURE_RATE) ((value >> CI_CICR4_FR_RATE_SHIFT) & CI_CICR4_FR_RATE_SMASK); ++} ++ ++void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format) ++{ ++ unsigned int value, tbit, rgbt_conv, rgb_conv, rgb_f, ycbcr_f, rgb_bpp, raw_bpp, cspace; ++ ++ // write cicr1: preserve ppl value and data width value ++ value = CICR1; ++ value &= ((CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT) | ((CI_CICR1_DW_SMASK) << CI_CICR1_DW_SHIFT)); ++ tbit = rgbt_conv = rgb_conv = rgb_f = ycbcr_f = rgb_bpp = raw_bpp = cspace = 0; ++ switch (input_format) { ++ case CI_RAW8: ++ cspace = 0; ++ raw_bpp = 0; ++ break; ++ case CI_RAW9: ++ cspace = 0; ++ raw_bpp = 1; ++ break; ++ case CI_RAW10: ++ cspace = 0; ++ raw_bpp = 2; ++ break; ++ case CI_YCBCR422: ++ case CI_YCBCR422_PLANAR: ++ cspace = 2; ++ if (output_format == CI_YCBCR422_PLANAR) { ++ ycbcr_f = 1; ++ } ++ break; ++ case CI_RGB444: ++ cspace = 1; ++ rgb_bpp = 0; ++ break; ++ case CI_RGB555: ++ cspace = 1; ++ rgb_bpp = 1; ++ if (output_format == CI_RGBT555_0) { ++ rgbt_conv = 2; ++ tbit = 0; ++ } else if (output_format == CI_RGBT555_1) { ++ rgbt_conv = 2; ++ tbit = 1; ++ } ++ break; ++ case CI_RGB565: ++ cspace = 1; ++ rgb_bpp = 2; ++ rgb_f = 1; ++ break; ++ case CI_RGB666: ++ cspace = 1; ++ rgb_bpp = 3; ++ if (output_format == CI_RGB666_PACKED) { ++ rgb_f = 1; ++ } ++ break; ++ case CI_RGB888: ++ case CI_RGB888_PACKED: ++ cspace = 1; ++ rgb_bpp = 4; ++ switch (output_format) { ++ case CI_RGB888_PACKED: ++ rgb_f = 1; ++ break; ++ case CI_RGBT888_0: ++ rgbt_conv = 1; ++ tbit = 0; ++ break; ++ case CI_RGBT888_1: ++ rgbt_conv = 1; ++ tbit = 1; ++ break; ++ case CI_RGB666: ++ rgb_conv = 1; ++ break; ++// RGB666 PACKED - JamesL ++ case CI_RGB666_PACKED: ++ rgb_conv = 1; ++ rgb_f = 1; ++ break; ++// end ++ case CI_RGB565: ++ rgb_conv = 2; ++ break; ++ case CI_RGB555: ++ rgb_conv = 3; ++ break; ++ case CI_RGB444: ++ rgb_conv = 4; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ value |= (tbit == 1) ? CI_CICR1_TBIT : 0; ++ value |= rgbt_conv << CI_CICR1_RGBT_CONV_SHIFT; ++ value |= rgb_conv << CI_CICR1_RGB_CONV_SHIFT; ++ value |= (rgb_f == 1) ? CI_CICR1_RBG_F : 0; ++ value |= (ycbcr_f == 1) ? CI_CICR1_YCBCR_F : 0; ++ value |= rgb_bpp << CI_CICR1_RGB_BPP_SHIFT; ++ value |= raw_bpp << CI_CICR1_RAW_BPP_SHIFT; ++ value |= cspace << CI_CICR1_COLOR_SP_SHIFT; ++ CICR1 = value; ++ ++ return; ++} ++ ++void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width) ++{ ++ unsigned int value; ++ ++ // write mode field in cicr0 ++ value = CICR0; ++ value &= ~(CI_CICR0_SIM_SMASK << CI_CICR0_SIM_SHIFT); ++ value |= (unsigned int) mode << CI_CICR0_SIM_SHIFT; ++ CICR0 = value; ++ ++ // write data width cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_DW_SMASK << CI_CICR1_DW_SHIFT); ++ value |= ((unsigned) data_width) << CI_CICR1_DW_SHIFT; ++ CICR1 = value; ++ return; ++} ++ ++void ci_configure_mp(unsigned int ppl, unsigned int lpf, CI_MP_TIMING * timing) ++{ ++ unsigned int value; ++ ++ // write ppl field in cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); ++ value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; ++ CICR1 = value; ++ ++ // write BLW, ELW in cicr2 ++ value = CICR2; ++ value &= ~(CI_CICR2_BLW_SMASK << CI_CICR2_BLW_SHIFT | CI_CICR2_ELW_SMASK << CI_CICR2_ELW_SHIFT); ++ value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; ++ CICR2 = value; ++ ++ // write BFW, LPF in cicr3 ++ value = CICR3; ++ value &= ~(CI_CICR3_BFW_SMASK << CI_CICR3_BFW_SHIFT | CI_CICR3_LPF_SMASK << CI_CICR3_LPF_SHIFT); ++ value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; ++ value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; ++ CICR3 = value; ++ return; ++} ++ ++void ci_configure_sp(unsigned int ppl, unsigned int lpf, CI_SP_TIMING * timing) ++{ ++ unsigned int value; ++ ++ // write ppl field in cicr1 ++ value = CICR1; ++ value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); ++ value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; ++ CICR1 = value; ++ ++ // write cicr2 ++ value = CICR2; ++ value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; ++ value |= (timing->ELW & CI_CICR2_ELW_SMASK) << CI_CICR2_ELW_SHIFT; ++ value |= (timing->HSW & CI_CICR2_HSW_SMASK) << CI_CICR2_HSW_SHIFT; ++ value |= (timing->BFPW & CI_CICR2_BFPW_SMASK) << CI_CICR2_BFPW_SHIFT; ++ value |= (timing->FSW & CI_CICR2_FSW_SMASK) << CI_CICR2_FSW_SHIFT; ++ CICR2 = value; ++ ++ // write cicr3 ++ value = CICR3; ++ value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; ++ value |= (timing->EFW & CI_CICR3_EFW_SMASK) << CI_CICR3_EFW_SHIFT; ++ value |= (timing->VSW & CI_CICR3_VSW_SMASK) << CI_CICR3_VSW_SHIFT; ++ value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; ++ CICR3 = value; ++ return; ++} ++ ++void ci_configure_ms(unsigned int ppl, unsigned int lpf, CI_MS_TIMING * timing) ++{ ++ // the operation is same as Master-Parallel ++ ci_configure_mp(ppl, lpf, (CI_MP_TIMING *) timing); ++} ++ ++void ci_configure_ep(int parity_check) ++{ ++ unsigned int value; ++ ++ // write parity_enable field in cicr0 ++ value = CICR0; ++ if (parity_check) { ++ value |= CI_CICR0_PAR_EN; ++ } else { ++ value &= ~CI_CICR0_PAR_EN; ++ } ++ CICR0 = value; ++ return; ++} ++ ++void ci_configure_es(int parity_check) ++{ ++ // the operationi is same as Embedded-Parallel ++ ci_configure_ep(parity_check); ++} ++ ++void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz) ++{ ++ unsigned int ciclk = 0, value, div, cccr_l, K; ++ ++ // determine the LCLK frequency programmed into the CCCR. ++ cccr_l = (CCCR & 0x0000001F); ++ ++ if (cccr_l < 8) // L = [2 - 7] ++ ciclk = (13 * cccr_l) * 100; ++ else if (cccr_l < 17) // L = [8 - 16] ++ ciclk = ((13 * cccr_l) * 100) >> 1; ++ else if (cccr_l < 32) // L = [17 - 31] ++ ciclk = ((13 * cccr_l) * 100) >> 2; ++ DPRINTK("the mclk_khz = %d \n", mclk_khz); ++ ++ // want a divisor that gives us a clock rate as close to, but not more than the given mclk. ++ div = (ciclk + mclk_khz) / (2 * mclk_khz) - 1; ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK << CI_CICR4_DIV_SHIFT); ++ value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0; ++ value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0; ++ value |= div << CI_CICR4_DIV_SHIFT; ++ CICR4 = value; ++ return; ++} ++ ++ ++void ci_set_polarity(int pclk_sample_falling, int hsync_active_low, int vsync_active_low) ++{ ++ unsigned int value; ++ ++ // write cicr4 ++ value = CICR4; ++ value &= ~(CI_CICR4_PCP | CI_CICR4_HSP | CI_CICR4_VSP); ++ value |= (pclk_sample_falling) ? CI_CICR4_PCP : 0; ++ value |= (hsync_active_low) ? CI_CICR4_HSP : 0; ++ value |= (vsync_active_low) ? CI_CICR4_VSP : 0; ++ CICR4 = value; ++ return; ++} ++ ++void ci_set_fifo(unsigned int timeout, CI_FIFO_THRESHOLD threshold, int fifo1_enable, int fifo2_enable) ++{ ++ unsigned int value; ++ ++ // write citor ++ CITOR = timeout; ++ ++ // write cifr: always enable fifo 0! also reset input fifo ++ value = CIFR; ++ value &= ~(CI_CIFR_FEN0 | CI_CIFR_FEN1 | CI_CIFR_FEN2 | CI_CIFR_RESETF | ++ CI_CIFR_THL_0_SMASK << CI_CIFR_THL_0_SHIFT); ++ value |= (unsigned int) threshold << CI_CIFR_THL_0_SHIFT; ++ value |= (fifo1_enable) ? CI_CIFR_FEN1 : 0; ++ value |= (fifo2_enable) ? CI_CIFR_FEN2 : 0; ++ value |= CI_CIFR_RESETF | CI_CIFR_FEN0; ++ CIFR = value; ++ return; ++} ++ ++void ci_reset_fifo() ++{ ++ unsigned int value; ++ value = CIFR; ++ value |= CI_CIFR_RESETF; ++ CIFR = value; ++} ++ ++void ci_set_int_mask(unsigned int mask) ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value &= ~CI_CICR0_INTERRUPT_MASK; ++ value |= (mask & CI_CICR0_INTERRUPT_MASK); ++ CICR0 = value; ++ return; ++} ++ ++unsigned int ci_get_int_mask() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ return (value & CI_CICR0_INTERRUPT_MASK); ++} ++ ++void ci_clear_int_status(unsigned int status) ++{ ++ // write 1 to clear ++ CISR = status; ++} ++ ++unsigned int ci_get_int_status() ++{ ++ int value; ++ ++ value = CISR; ++ ++ return value; ++} ++ ++void ci_set_reg_value(unsigned int reg_offset, unsigned int value) ++{ ++ CI_REG((u32) (ci_regs_base) + reg_offset) = value; ++} ++ ++int ci_get_reg_value(unsigned int reg_offset) ++{ ++ int value; ++ ++ value = CI_REG((u32) (ci_regs_base) + reg_offset); ++ return value; ++} ++ ++//------------------------------------------------------------------------------------------------------- ++// Control APIs ++//------------------------------------------------------------------------------------------------------- ++int ci_init() ++{ ++ // clear all CI registers ++ CICR0 = 0x3FF; // disable all interrupts ++ CICR1 = 0; ++ CICR2 = 0; ++ CICR3 = 0; ++ CICR4 = 0; ++ CISR = ~0; ++ CIFR = 0; ++ CITOR = 0; ++ ++ // enable CI clock ++ CKEN |= CKEN24_CAMERA; ++ return 0; ++} ++ ++void ci_deinit() ++{ ++ // disable CI clock ++ CKEN &= ~CKEN24_CAMERA; ++} ++ ++void ci_enable(int dma_en) ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value |= CI_CICR0_ENB; ++ if (dma_en) { ++ value |= CI_CICR0_DMA_EN; ++ } ++ CICR0 = value; ++ return; ++} ++ ++int ci_disable(int quick) ++{ ++ volatile unsigned int value, mask; ++ int retry; ++ ++ // write control bit in cicr0 ++ value = CICR0; ++ if (quick) { ++ value &= ~CI_CICR0_ENB; ++ mask = CI_CISR_CQD; ++ } else { ++ value |= CI_CICR0_DIS; ++ mask = CI_CISR_CDD; ++ } ++ CICR0 = value; ++ ++ // wait shutdown complete ++ retry = 50; ++ while (retry-- > 0) { ++ value = CISR; ++ if (value & mask) { ++ CISR = mask; ++ return 0; ++ } ++ mdelay(10); ++ } ++ ++ return -1; ++} ++ ++void ci_slave_capture_enable() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value |= CI_CICR0_SL_CAP_EN; ++ CICR0 = value; ++ return; ++} ++ ++void ci_slave_capture_disable() ++{ ++ unsigned int value; ++ ++ // write mask in cicr0 ++ value = CICR0; ++ value &= ~CI_CICR0_SL_CAP_EN; ++ CICR0 = value; ++ return; ++} ++ ++void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs) ++{ ++ int dcsr; ++ static int dma_repeated = 0; ++ static unsigned int count = 0; ++ ++ camera_context_t *cam_ctx = g_camera_context; ++ ++ dcsr = DCSR(channel); ++ DCSR(channel) = dcsr & ~DCSR_STOPIRQEN; ++ if (!((count++) % 100)) ++ DPRINTK("int occure\n"); ++ if (still_image_mode == 1) { ++ DPRINTK("pxa_ci_dma_irq_y interrupt,task_waiting =%d, still_image_rdy=%d\n", ++ task_waiting, still_image_rdy); ++ if (task_waiting == 1) { ++ DPRINTK("task waiting"); ++ wake_up_interruptible(&camera_wait_q); ++ task_waiting = 0; ++ } ++ still_image_rdy = 1; ++ } else if (dma_repeated == 0 && (cam_ctx->block_tail == ((cam_ctx->block_header + 2) % cam_ctx->block_number))) { ++ dma_repeated = 1; ++ pxa_dma_repeat(cam_ctx); ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ } else if (dma_repeated == 1 && (cam_ctx->block_tail != ((cam_ctx->block_header + 1) % cam_ctx->block_number)) ++ && (cam_ctx->block_tail != ((cam_ctx->block_header + 2) % cam_ctx->block_number))) { ++ pxa_dma_continue(cam_ctx); ++ dma_repeated = 0; ++ } else if (dma_repeated == 0) { ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ } ++ if (task_waiting == 1 && !(cam_ctx->block_header == cam_ctx->block_tail)) { ++ wake_up_interruptible(&camera_wait_q); ++ task_waiting = 0; ++ } ++} ++ ++void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs) ++{ ++ return; ++} ++ ++void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs) ++{ ++ return; ++} ++ ++inline static void pxa_ci_dma_stop(camera_context_t * cam_ctx) ++{ ++ int ch0, ch1, ch2; ++ ++ ch0 = cam_ctx->dma_channels[0]; ++ ch1 = cam_ctx->dma_channels[1]; ++ ch2 = cam_ctx->dma_channels[2]; ++ DCSR(ch0) &= ~DCSR_RUN; ++ DCSR(ch1) &= ~DCSR_RUN; ++ DCSR(ch2) &= ~DCSR_RUN; ++} ++ ++ ++void pxa_dma_start(camera_context_t * cam_ctx) ++{ ++ unsigned char cnt_blk; ++ pxa_dma_desc *cnt_desc; ++ ++ cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++ cnt_blk = (unsigned char) cam_ctx->block_header; ++ ++ cnt_desc = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_physical + cnt_blk * cam_ctx->fifo0_num_descriptors; ++ ++ DDADR(cam_ctx->dma_channels[0]) = cnt_desc; ++ DCSR(cam_ctx->dma_channels[0]) |= DCSR_RUN; ++ ++ if (cam_ctx->fifo1_num_descriptors) { ++ cnt_desc = ++ (pxa_dma_desc *) cam_ctx->fifo1_descriptors_physical + cnt_blk * cam_ctx->fifo1_num_descriptors; ++ DDADR(cam_ctx->dma_channels[1]) = cnt_desc; ++ DCSR(cam_ctx->dma_channels[1]) |= DCSR_RUN; ++ } ++ ++ if (cam_ctx->fifo2_num_descriptors) { ++ cnt_desc = ++ (pxa_dma_desc *) cam_ctx->fifo2_descriptors_physical + cnt_blk * cam_ctx->fifo2_num_descriptors; ++ DDADR(cam_ctx->dma_channels[2]) = cnt_desc; ++ DCSR(cam_ctx->dma_channels[2]) |= DCSR_RUN; ++ } ++ ++ return; ++} ++ ++ ++void pxa_camera_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int cisr; ++ static int dma_started = 0; ++ ++ disable_irq(IRQ_CAMERA); ++ ++ cisr = CISR; ++ if (cisr & CI_CISR_SOF) { ++ DPRINTK("CI_CISR_SOF \n"); ++ if (dma_started == 0) { ++ dma_started = 1; ++ } ++ CISR |= CI_CISR_SOF; ++ } ++ if (cisr & CI_CISR_EOF) { ++ DPRINTK("CI_CISR_EOF\n"); ++ CISR |= CI_CISR_EOF; ++ //wake_up_interruptible(&camera_wait_q); ++ } ++ enable_irq(IRQ_CAMERA); ++} ++ ++void pxa_dma_repeat(camera_context_t * cam_ctx) ++{ ++ pxa_dma_desc *cnt_head, *cnt_tail; ++ int cnt_block; ++ ++ cnt_block = (cam_ctx->block_header + 1) % cam_ctx->block_number; ++// FIFO0 ++ (pxa_dma_desc *) cnt_head = ++ (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual + cnt_block * cam_ctx->fifo0_num_descriptors; ++ cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++// FIFO1 ++ if (cam_ctx->fifo1_transfer_size) { ++ cnt_head = ++ (pxa_dma_desc *) cam_ctx->fifo1_descriptors_virtual + cnt_block * cam_ctx->fifo1_num_descriptors; ++ cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ } ++// FIFO2 ++ if (cam_ctx->fifo2_transfer_size) { ++ cnt_head = ++ (pxa_dma_desc *) cam_ctx->fifo2_descriptors_virtual + cnt_block * cam_ctx->fifo2_num_descriptors; ++ cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; ++ cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ return; ++} ++ ++void pxa_dma_continue(camera_context_t * cam_ctx) ++{ ++ pxa_dma_desc *cnt_head, *cnt_tail; ++ pxa_dma_desc *next_head; ++ int cnt_block, next_block; ++ ++ cnt_block = cam_ctx->block_header; ++ next_block = (cnt_block + 1) % cam_ctx->block_number; ++// FIFO0 ++ cnt_head = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual + cnt_block * cam_ctx->fifo0_num_descriptors; ++ cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; ++ next_head = (pxa_dma_desc *) cam_ctx->fifo0_descriptors_virtual + next_block * cam_ctx->fifo0_num_descriptors; ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++// FIFO1 ++ if (cam_ctx->fifo1_transfer_size) { ++ cnt_head = ++ (pxa_dma_desc *) cam_ctx->fifo1_descriptors_virtual + cnt_block * cam_ctx->fifo1_num_descriptors; ++ cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; ++ next_head = ++ (pxa_dma_desc *) cam_ctx->fifo1_descriptors_virtual + next_block * cam_ctx->fifo1_num_descriptors; ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ } ++// FIFO2 ++ if (cam_ctx->fifo2_transfer_size) { ++ cnt_head = ++ (pxa_dma_desc *) cam_ctx->fifo2_descriptors_virtual + cnt_block * cam_ctx->fifo2_num_descriptors; ++ cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; ++ next_head = ++ (pxa_dma_desc *) cam_ctx->fifo2_descriptors_virtual + next_block * cam_ctx->fifo2_num_descriptors; ++ cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); ++ } ++ return; ++ ++} ++ ++void ci_dump(void) ++{ ++ DPRINTK("CICR0 = 0x%8x \n", CICR0); ++ DPRINTK("CICR1 = 0x%8x \n", CICR1); ++ DPRINTK("CICR2 = 0x%8x \n", CICR2); ++ DPRINTK("CICR3 = 0x%8x \n", CICR3); ++ DPRINTK("CICR4 = 0x%8x \n", CICR4); ++ DPRINTK("CISR = 0x%8x \n", CISR); ++ DPRINTK("CITOR = 0x%8x \n", CITOR); ++ DPRINTK("CIFR = 0x%8x \n", CIFR); ++} ++ ++module_init(pxa_camera_init); ++module_exit(pxa_camera_exit); ++ ++MODULE_DESCRIPTION("Bulverde Camera Interface driver"); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOLS; +diff -Nurd linux-2.6.16.orig/drivers/media/video/saa7127.c linux-2.6.16/drivers/media/video/saa7127.c +--- linux-2.6.16.orig/drivers/media/video/saa7127.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/saa7127.c 2006-06-03 11:14:55.289483976 +0200 +@@ -141,6 +141,7 @@ + static const struct i2c_reg_value saa7129_init_config_extra[] = { + { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, + { SAA7127_REG_VTRIG, 0xfa }, ++ { 0, 0 } + }; + + static const struct i2c_reg_value saa7127_init_config_common[] = { +diff -Nurd linux-2.6.16.orig/drivers/media/video/tuner-types.c linux-2.6.16/drivers/media/video/tuner-types.c +--- linux-2.6.16.orig/drivers/media/video/tuner-types.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/tuner-types.c 2006-06-03 11:14:55.290483824 +0200 +@@ -1087,8 +1087,8 @@ + /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ + + static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { +- { 16 * 175.75 /*MHz*/, 0x01, }, +- { 16 * 410.25 /*MHz*/, 0x02, }, ++ { 16 * 130.00 /*MHz*/, 0x01, }, ++ { 16 * 364.50 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }; + +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-button.c linux-2.6.16/drivers/misc/ezx/ezx-button.c +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-button.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-button.c 2006-06-03 11:14:56.303329848 +0200 +@@ -0,0 +1,476 @@ ++/* ++ * linux/drivers/char/ezx-button.c --- button driver on ezx ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Zhou Qiong, Jay Jia ++ * Created: Dec 16, 2003 ++ * Copyright: Motorola 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. ++ * ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 headset judgement condition reverse ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 reorganise file header ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/time.h> ++#include <linux/timer.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/delay.h> ++#include <linux/apm_bios.h> ++ ++#include <asm/hardware.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/semaphore.h> ++#include <asm/mach-types.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx.h> ++ ++#include "ssp_pcap.h" ++#include "ezx-button.h" ++ ++#define DEBUG ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++#endif ++ ++#define FULL(queue) ((queue.head+1==queue.tail)||(queue.head+1-NR_BUTTONS==queue.tail)) ++ ++struct button_queue{ ++ unsigned short button_buffer[NR_BUTTONS]; ++ unsigned int head; ++ unsigned int tail; ++}; ++ ++static struct timer_list lockscreen_timer; ++static struct timer_list answer_timer; ++ ++static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ ++static struct button_queue buttonevent; ++ ++static int answer_flag=0; ++int lockscreen_flag=0; ++ ++static int first_open=0; ++static int before_emu=0; ++static int before_charge_500mA=0; ++static int before_charge_0mA=0; ++ ++void usb_cable_event_handler(unsigned short cable_event) ++{ ++ if(!FULL(buttonevent)) ++ { ++ buttonevent.button_buffer[buttonevent.head] = cable_event; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++ wake_up_interruptible(&button_wait_queue); ++ printk("usb cable event = %d\n", cable_event); ++ } ++} ++ ++static int button_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) ++{ ++ int data, ret; ++ ++ switch(cmd){ ++/* ++*/ ++ case BUTTON_GET_HEADSETSTATUS: ++ data = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); ++ if(data) ++ ret = HEADSET_IN; ++ else ++ ret = HEADSET_OUT; ++ return put_user(ret, (int *)arg); ++/* ++*/ ++ case BUTTON_GET_FLIPSTATUS: ++ data = GPLR(GPIO_FLIP_PIN) & GPIO_bit(GPIO_FLIP_PIN); ++ if(!data) ++ ret = FLIP_OFF; ++ else ++ ret = FLIP_ON; ++ lockscreen_flag = ret; ++ return put_user(ret, (int *)arg); ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static unsigned int button_poll(struct file *file, poll_table *wait) ++{ ++ poll_wait(file, &button_wait_queue, wait); ++ if(buttonevent.head != buttonevent.tail) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++/* ++ * This function is called when a user space program attempts to read ++ * /dev/button. It puts the device to sleep on the wait queue until ++ * irq handler writes some data to the buffer and flushes ++ * the queue, at which point it writes the data out to the device and ++ * returns the number of characters it has written. This function is ++ * reentrant, so that many processes can be attempting to read from the ++ * device at any one time. ++ */ ++ ++static int button_read (struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int retval = 0; ++ ++ if (buttonevent.head == buttonevent.tail) ++ { ++ add_wait_queue(&button_wait_queue, &wait); ++ current->state = TASK_INTERRUPTIBLE; ++ ++ while (buttonevent.head == buttonevent.tail) ++ { ++ if (file->f_flags & O_NONBLOCK) ++ { ++ retval = -EAGAIN; ++ break; ++ } ++ if (signal_pending(current)) ++ { ++ retval = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&button_wait_queue, &wait); ++ } ++ ++ if (retval) ++ return retval; ++ ++ while ((buttonevent.head != buttonevent.tail) && (retval + sizeof(unsigned short)) <= count) ++ { ++ if (copy_to_user(buffer+retval, buttonevent.button_buffer+buttonevent.tail, sizeof(unsigned short))) ++ return -EFAULT; ++ buttonevent.tail = (buttonevent.tail+1)%(NR_BUTTONS); ++ retval += sizeof(unsigned short); ++ } ++ ++ return retval; ++} ++ ++static void scan_lockscreen_button(unsigned long parameters) ++{ ++ unsigned long data; ++ int bdelay = BUTTON_INTERVAL; ++ ++#ifdef DEBUG ++ printk("enter scan_lockscreen_button\n"); ++#endif ++ data = GPLR(GPIO_FLIP_PIN); ++ if(!(data & GPIO_bit(GPIO_FLIP_PIN))) // lockscreen - 0 ++ { ++ lockscreen_flag = 0; ++ if(!FULL(buttonevent)) ++ { ++ buttonevent.button_buffer[buttonevent.head] = FLIP | KEYDOWN; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++#ifdef CONFIG_KEYPAD_E680 ++ ssp_pcap_screenlock_lock(0); ++#endif ++ wake_up_interruptible(&button_wait_queue); ++#ifdef CONFIG_APM ++ apm_queue_event(KRNL_FLIP_OFF); ++#endif ++ ++#ifdef DEBUG ++ printk("LockScreen keydown\n"); ++#endif ++ } ++ } ++ else // lockscreen - 1 ++ { ++ lockscreen_flag = 1; ++ if(!FULL(buttonevent)) ++ { ++ buttonevent.button_buffer[buttonevent.head] = FLIP | KEYUP; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++#ifdef CONFIG_KEYPAD_E680 ++ ssp_pcap_screenlock_unlock(0); ++#endif ++ wake_up_interruptible(&button_wait_queue); ++#ifdef CONFIG_APM ++ apm_queue_event(KRNL_FLIP_ON); ++#endif ++ ++#ifdef DEBUG ++ printk("LockScreen keyup\n"); ++#endif ++ } ++ } ++} ++ ++static void scan_answer_button(unsigned long parameters) ++{ ++ int ssp_pcap_bit_status; ++ int bdelay = BUTTON_INTERVAL; ++ ++#ifdef DEBUG ++ printk("enter scan_answer_button\n"); ++#endif ++ /* read pcap register to check if headjack is in */ ++// ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); ++// if( ssp_pcap_bit_status != 0 ) /* headjack is in */ ++ { ++ ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_MB2SNS); ++ if(ssp_pcap_bit_status == 0) // keydown ++ { ++ answer_flag ++; ++ if((!FULL(buttonevent))&&((answer_flag==1)||((answer_flag%NR_REPEAT)==0))) ++ { ++ buttonevent.button_buffer[buttonevent.head] = ANSWER | KEYDOWN; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++ wake_up_interruptible(&button_wait_queue); ++#ifdef DEBUG ++ printk("answer keydown\n"); ++#endif ++ } ++ answer_timer.expires = (jiffies + bdelay); ++ add_timer (&answer_timer); ++ } ++ else if(answer_flag) // keyup ++ { ++ del_timer(&answer_timer); ++ answer_flag = 0; ++ if(!FULL(buttonevent)) ++ { ++ buttonevent.button_buffer[buttonevent.head] = ANSWER | KEYUP; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++ wake_up_interruptible(&button_wait_queue); ++#ifdef DEBUG ++ printk("answer keyup\n"); ++#endif ++ } ++ } ++ } ++} ++ ++static void lockscreen_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int bdelay = 10; /* The delay, in jiffies */ ++ ++ del_timer (&lockscreen_timer); ++ lockscreen_timer.expires = (jiffies + bdelay); ++ add_timer (&lockscreen_timer); ++} ++ ++void answer_button_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++#if 0 ++ int bdelay = BUTTON_DELAY; /* The delay, in jiffies */ ++ ++ del_timer (&answer_timer); ++ answer_timer.expires = (jiffies + bdelay); ++ add_timer (&answer_timer); ++ printk("answer_button_handler\n"); ++#endif ++ scan_answer_button(0); ++} ++ ++void headset_in_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ if(!FULL(buttonevent)) ++ { ++ buttonevent.button_buffer[buttonevent.head] = HEADSET_INT | KEYDOWN; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++ wake_up_interruptible(&button_wait_queue); ++ printk("headset button insert\n"); ++ answer_flag = 0; ++ } ++} ++ ++ ++void headset_out_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ if(!FULL(buttonevent)) ++ { ++ buttonevent.button_buffer[buttonevent.head] = HEADSET_INT | KEYUP; ++ buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); ++ wake_up_interruptible(&button_wait_queue); ++ printk("headset button remove\n"); ++ answer_flag = 0; ++ } ++} ++ ++#ifdef CONFIG_PM ++static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ break; ++ ++ case PM_RESUME: ++ break; ++ } ++ return 0; ++} ++#endif ++ ++static int count=0; ++static int button_release(struct inode * inode, struct file * file) ++{ ++ int i; ++ ++ count --; ++ if(count) ++ { ++ return -EBUSY; ++ } ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I); /* clear interrupt */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M); /* mask interrupt */ ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_A1I); /* clear interrupt */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_A1M); /* mask interrupt */ ++ ++ // init gpio12 input, ++// GPDR(GPIO_LOCK_SCREEN_PIN) &= 0xFFFFEFFF; ++ GPDR(GPIO_FLIP_PIN) &= ~(GPIO_bit(GPIO_FLIP_PIN)); ++ del_timer (&lockscreen_timer); ++ del_timer (&answer_timer); ++ free_irq(IRQ_GPIO(GPIO_FLIP_PIN), NULL); ++ ++ for(i=0; i<NR_BUTTONS; i++) ++ buttonevent.button_buffer[i] = 0; ++ buttonevent.head = 0; ++ buttonevent.tail = 0; ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++#ifdef DEBUG ++ printk("button device released\n"); ++#endif ++ ++ return 0; ++} ++ ++static int button_open(struct inode * inode, struct file * file) ++{ ++ int i, data; ++ ++ if(count) ++ { ++ return -EBUSY; ++ } ++ ++ count ++; ++ for(i=0; i<NR_BUTTONS; i++) ++ buttonevent.button_buffer[i] = 0; ++ buttonevent.head = 0; ++ buttonevent.tail = 0; ++ ++ init_timer (&lockscreen_timer); ++ lockscreen_timer.function = scan_lockscreen_button; ++ init_timer (&answer_timer); ++ answer_timer.function = scan_answer_button; ++ GAFR(GPIO_FLIP_PIN) &= ~(3<<(2*(GPIO_bit(GPIO_FLIP_PIN) & 0xf))); ++ GPDR(GPIO_FLIP_PIN) |= GPIO_bit(GPIO_FLIP_PIN); ++ udelay(10); ++ set_GPIO_IRQ_edge(GPIO_FLIP_PIN, GPIO_FALLING_EDGE | GPIO_RISING_EDGE); ++ if (request_irq (IRQ_GPIO(GPIO_FLIP_PIN), lockscreen_handler, SA_INTERRUPT, "flip", NULL)) ++ { ++ printk (KERN_WARNING "flip irq is free.\n"); ++ return -EIO; ++ } ++ ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_A1I); /* clear interrupt */ ++ udelay(10); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_A1M); /* unmask interrupt */ ++ data = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); ++ if(data) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I); ++ udelay(10); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_MB2M); ++ } ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); ++#endif ++ ++#ifdef DEBUG ++ printk("button device opened\n"); ++#endif ++ ++#ifdef CONFIG_KEYPAD_E680 ++ data = GPLR(GPIO_FLIP_PIN) & GPIO_bit(GPIO_FLIP_PIN); ++ if(!data) ++ ssp_pcap_screenlock_lock(0); ++#endif ++ ++ first_open = 1; ++ return 0; ++} ++ ++/* add button_ioctl to check flip status */ ++static struct file_operations button_fops = { ++ owner: THIS_MODULE, ++ open: button_open, ++ release: button_release, ++ read: button_read, ++ poll: button_poll, ++ ioctl: button_ioctl, ++}; ++ ++/* ++ * This structure is the misc device structure, which specifies the minor ++ * device number (158 in this case), the name of the device (for /proc/misc), ++ * and the address of the above file operations structure. ++ */ ++ ++static struct miscdevice button_misc_device = { ++ BUTTON_MINOR, ++ "button", ++ &button_fops, ++}; ++ ++/* ++ * This function is called to initialise the driver, either from misc.c at ++ * bootup if the driver is compiled into the kernel, or from init_module ++ * below at module insert time. It attempts to register the device node ++ * and the IRQ and fails with a warning message if either fails, though ++ * neither ever should because the device number and IRQ are unique to ++ * this driver. ++ */ ++ ++static int __init button_init(void) ++{ ++ if (misc_register (&button_misc_device)) { ++ printk (KERN_WARNING "button: Couldn't register device 10, " ++ "%d.\n", BUTTON_MINOR); ++ return -EBUSY; ++ } ++} ++ ++static void __exit button_exit (void) ++{ ++ misc_deregister(&button_misc_device); ++} ++ ++module_init(button_init); ++module_exit(button_exit); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-button.h linux-2.6.16/drivers/misc/ezx/ezx-button.h +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-button.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-button.h 2006-06-03 11:14:56.303329848 +0200 +@@ -0,0 +1,84 @@ ++/* ++ * linux/drivers/char/ezx-button.h ++ * author: zhouqiong ++ * company: Motorola BJDC ++ * date: 11/6/2002 ++ */ ++/* modified by zq, Jan 15,2003 ++ * (1) add flip status ioctl definition ++ */ ++#include <linux/ioctl.h> ++ ++/* Various defines: */ ++#define BUTTON_DELAY 1 /* How many jiffies to wait */ ++#define BUTTON_INTERVAL 10 /* How many jiffies to interval */ ++#define VERSION "0.1" /* Driver version number */ ++#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/button */ ++ ++/* single button */ ++#define FLIP 0x80 ++#define ANSWER 0x81 ++#define HEADSET_INT 0x82 ++#define EMU_CHARGER_500mA 0x83 ++#define EMU_USB 0x84 ++#define EMU_CHARGER_0 0x85 ++ ++#define NR_BUTTONS 256 ++ ++#define BUTTON_IOCTL_BASE 0xde ++#define BUTTON_GET_FLIPSTATUS _IOR(BUTTON_IOCTL_BASE, 1,int) ++#define BUTTON_GET_HEADSETSTATUS _IOR(BUTTON_IOCTL_BASE, 2,int) ++#define BUTTON_GET_EMU_CABLE _IOR(BUTTON_IOCTL_BASE, 3,int) ++#define BUTTON_GET_EMU_CHARGER _IOR(BUTTON_IOCTL_BASE, 4,int) ++#define BUTTON_USB_CABLE_IN _IOR(BUTTON_IOCTL_BASE, 5,int) ++#define BUTTON_USB_CABLE_OUT _IOR(BUTTON_IOCTL_BASE, 6,int) ++#define BUTTON_CHARGER_CAP _IOR(BUTTON_IOCTL_BASE, 7,int) ++#define BUTTON_USB_DEV_TYPE _IOR(BUTTON_IOCTL_BASE, 8,int) ++#define NR_REPEAT 5 ++#define FLIP_ON 1 ++#define FLIP_OFF 0 ++#define HEADSET_IN 0 ++#define HEADSET_OUT 1 ++#define EMU_CABLE_BEFORE 1 ++#define EMU_CHARGE_500mA_BEFORE 1 ++#define EMU_CHARGE_0mA_BEFORE 2 ++ ++#define KEYDOWN 0x8000 ++#define KEYUP 0x0000 ++//#define LOCKSCREEN 0x84 ++#define LOCKSCREEN FLIP ++//# define BUTTON_GET_LOCKSCREENSTATUS _IOR(BUTTON_IOCTL_BASE, 3,int) ++# define BUTTON_GET_LOCKSCREENSTATUS BUTTON_GET_FLIPSTATUS ++//#define LOCKSCREEN_ON 1 ++#define LOCKSCREEN_ON FLIP_OFF ++//#define LOCKSCREEN_OFF 0 ++#define LOCKSCREEN_OFF FLIP_ON ++ ++#ifndef u16 ++#define u16 unsigned short ++#endif ++/* usb cable event */ ++#define USB_CABLE_IN 0xa0 ++#define USB_CABLE_OUT 0xa1 ++#define USB_CABLE_500mA 0xa2 ++#define USB_CABLE_0mA 0xa3 ++#define NETMONITOR_CABLE 0xa4 ++#define MODEM_CABLE 0xa5 ++#define APLOG_CABLE 0xa6 ++#define CFG11_CABLE 0xa7 ++#define DSPLOG_CABLE 0xa8 ++#define USBNET_CABLE 0xa9 ++#define PST_CABLE 0xaa ++#define MASSSTORAGE_CABLE 0xab ++#define UNKNOWN_CABLE 0xff ++/*add function*/ ++extern void answer_button_handler(int irq, void *dev_id, struct pt_regs *regs); ++extern void headset_in_handler(int irq, void *dev_id, struct pt_regs *regs); ++extern void headset_out_handler(int irq, void *dev_id, struct pt_regs *regs); ++/* ++extern void emu_charger_500mA_handler(void); ++extern void emu_usb_in_handler(void); ++extern void emu_usb_out_handler(void); ++extern void emu_charger_0(void); ++*/ ++extern void usb_cable_event_handler(unsigned short cable_event); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-emu.c linux-2.6.16/drivers/misc/ezx/ezx-emu.c +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-emu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-emu.c 2006-06-03 11:14:56.305329544 +0200 +@@ -0,0 +1,1185 @@ ++#ifdef EMU_PIHF_FEATURE ++/* ++ * linux/drivers/misc/ezx-emu.c --- EMU driver on ezx ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Cheng Xuefeng ++ * Created: April 30, 2004 ++ * Copyright: Motorola 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 <linux/init.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/time.h> ++#include <linux/timer.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/delay.h> ++#include <linux/apm_bios.h> ++ ++#include <asm/hardware.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/semaphore.h> ++#include <asm/mach-types.h> ++#include "ssp_pcap.h" ++#include "ezx-emu.h" ++ ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx.h> ++ ++#define DEBUG ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++#endif ++ ++#ifdef EMU_INTERFACE_DEBUG ++#define EMU_DBG(fmt,args...) printk("EMU:"fmt,##args); ++#else ++#define EMU_DBG(fmt,args...) ++#endif ++ ++EXPORT_SYMBOL(emu_switch_to); ++ ++extern void emu_switch_to(T_EMU_SWITCH_TO to); ++ ++#define EMU_YES (1) ++#define EMU_NO (0) ++ ++/* 1ms */ ++#define EMU_PIHF_DPLUS_INIT_INTERVAL (1) ++ ++static int emu_is_int = EMU_NO; ++static int emu_is_wait = EMU_NO; ++ ++typedef enum{ ++ EMU_USB = 0, ++ EMU_SPD, ++ EMU_PIHF, /*EMU_PIHF is a subset of EMU_SPD*/ ++ EMU_EIHF ++} T_EMU_CURRENT_DEVICE; ++ ++typedef enum{ ++ EMU_MODE_UART =0, ++ EMU_MODE_USB, ++ EMU_MODE_AUDIO_MONO, ++ EMU_MODE_AUDIO_STEREO ++} T_EMU_MODE; ++ ++static T_EMU_CURRENT_DEVICE emu_current_device = EMU_USB; ++static T_EMU_MODE emu_current_mode = EMU_MODE_USB; ++ ++static DECLARE_WAIT_QUEUE_HEAD(emu_wait_queue); /* Used for blocking read */ ++ ++static int emucount=0; ++ ++ ++static void emu_handle_int(int irq,void *dev,struct pt_regs *regs); ++ ++/* This will be export to other modules. For other feature, developer should ++ * add related T_EMU_SWITCH_TO type as requriement. ++ */ ++void emu_switch_to(T_EMU_SWITCH_TO to) ++{ ++ switch(to) ++ { ++ case EMU_SWITCH_TO_NO_DEV: ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_NO_DEV\n"); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ ++ /* Disable the PCAP transceiver both for USB and RS232 */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ ++ /* Set the Bulverde GPIO */ ++ pxa_gpio_mode(GPIO34_USB_P2_2_MD); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_USB_P2_1_MD); ++ pxa_gpio_mode(GPIO36_USB_P2_4_MD); ++ pxa_gpio_mode(GPIO39_USB_P2_6_MD); //pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_USB_P2_5_MD); ++ pxa_gpio_mode(GPIO53_USB_P2_3_MD); ++ break; ++ case EMU_SWITCH_TO_UART: ++ ++ /* set the PCAP as UART mode */ ++ /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_SERIAL_PORT);*/ ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN)) ++ { ++ EMU_DBG("Before SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB clean\n"); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ } ++ else ++ { ++ return; ++ } ++ ++ /* This must be set. */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR); ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_UART:set txd high\n"); ++ set_GPIO(GPIO39_FFTXD); ++ ++ /* set other USB related GPIO direcction to IN first */ ++ pxa_gpio_mode(GPIO34_USB_P2_2_MD); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ ++ /* Init UART related GPIO */ ++ pxa_gpio_mode(GPIO39_FFTXD_MD); ++ pxa_gpio_mode(GPIO53_FFRXD_MD); ++ CKEN |= CKEN6_FFUART; ++ ++ /* set the MUX1/2 to data mode */ ++ clr_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++ emu_current_mode = EMU_MODE_UART; ++ break; ++ case EMU_SWITCH_TO_USB: ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_USB\n"); ++ /* set the 6 USB related GPIOs as USB function*/ ++ pxa_gpio_mode(GPIO34_USB_P2_2_MD); ++ pxa_gpio_mode(GPIO35_USB_P2_1_MD); ++ pxa_gpio_mode(GPIO36_USB_P2_4_MD); ++ pxa_gpio_mode(GPIO39_USB_P2_6_MD); ++ pxa_gpio_mode(GPIO40_USB_P2_5_MD); ++ pxa_gpio_mode(GPIO53_USB_P2_3_MD); ++ UP2OCR = 0x02000000; ++ ++ /* set the PCAP as UART mode */ ++ /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_HIGH_USB_PORT);*/ ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB)) ++ { ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB)) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ } ++ } ++ ++ /* set the MUX1/2 to data mode */ ++ clr_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++ emu_current_mode = EMU_MODE_USB; ++ break; ++ case EMU_SWITCH_TO_AUDIO_MONO: ++ /* This will not change the PCAP audio related ++ * register. Just change the MUX1/2. Switching ++ * the audio path is controlled by other driver. ++ */ ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_MONO\n"); ++ ++ clr_GPIO(GPIO39_VPOUT); ++ mdelay(1); ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ ++ /* set the MUX1/2 to mono mode */ ++ set_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++ emu_current_mode = EMU_MODE_AUDIO_MONO; ++ break; ++ case EMU_SWITCH_TO_AUDIO_STEREO: ++ /* This will not change the PCAP audio related ++ * register. Just change the MUX1/2. Switching ++ * the audio path is controlled by other driver. ++ */ ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_STEREO\n"); ++ clr_GPIO(GPIO39_VPOUT); ++ pxa_gpio_mode(GPIO34_USB_P2_@ | GPIO_IN); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ ++ /* set the MUX1/2 to stereo mode */ ++ set_GPIO(GPIO_EMU_MUX1); ++ set_GPIO(GPIO_EMU_MUX2); ++ emu_current_mode = EMU_MODE_AUDIO_STEREO; ++ break; ++ default: ++ break; ++ } ++ return; ++} ++ ++ ++static int emu_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) ++{ ++ int ret; ++ long val; ++ ++ switch(cmd){ ++ ++ /* Switch the MUX1/2 and set the GPIOs */ ++ case EMU_SW_TO_UART: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_UART:before change\n"); ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ break; ++ ++ case EMU_SW_TO_USB: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_USB:before change\n"); ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ break; ++ ++ case EMU_SW_TO_AUDIO_MONO: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_MONO:before change\n"); ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); ++ break; ++ ++ case EMU_SW_TO_AUDIO_STEREO: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_STEREO: not support...\n"); ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); ++ break; ++ ++ case EMU_SMART_SPD_INIT: ++ ++ EMU_DBG("emu_ioctl:EMU_SPD_INIT\n"); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); ++ mdelay(EMU_PIHF_DPLUS_INIT_INTERVAL); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); ++ ++ /* init to UART mode */ ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ ++ EMU_DBG("emu_ioctl:set GPIO 86\n"); ++ /* For SNP_INT_CTL, the inactive state is low. ++ * That means the ID line is high. ++ */ ++ pxa_gpio_mode(GPIO_SNP_INT_CTL|GPIO_OUT); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ ++ EMU_DBG("emu_ioctl:before request_irq()\n"); ++ ++ udelay(10); ++ ++ set_GPIO_IRQ_edge(GPIO_SNP_INT_IN,GPIO_FALLING_EDGE|GPIO_RISING_EDGE); ++ ++ if (request_irq(IRQ_GPIO(GPIO_SNP_INT_IN),emu_handle_int, ++ SA_INTERRUPT|SA_SAMPLE_RANDOM, ++ "EMU SNP interrupt",(void*)1) ++ ) ++ { ++ printk(KERN_WARNING"can't get EMU snp_int irq\n"); ++ return -EIO; ++ } ++ ++ emu_current_device = EMU_SPD; ++ break; ++ ++ /* EMU PIHF */ ++ case EMU_PIHF_INIT: ++ EMU_DBG("%s,%s:EMU_PIHF_INIT",__FILE__,__FUNCTION__); ++ ++ /* init to UART mode */ ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ ++ emu_current_device = EMU_PIHF; ++ break; ++ case EMU_PIHF_SNP_INT_CTL: ++ EMU_DBG("emu_ioctl:got the SNP_INT_CTL...\n"); ++ /* For SNP_INT_CTL, the inactive state is low. ++ * That means the ID line is high. ++ */ ++ ret = get_user(val,(long *)arg); ++ if (ret) ++ return ret; ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ set_GPIO(GPIO_SNP_INT_CTL); ++ mdelay(val); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ break; ++ ++ case EMU_PIHF_ID_LOW: ++ EMU_DBG("emu_ioctl:EMU_PIHF_ID_LOW\n"); ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ set_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ break; ++ ++ case EMU_PIHF_ID_HIGH: ++ EMU_DBG("emu_ioctl:EMU_PIHF_ID_HIGH\n"); ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ break; ++ ++ /* EMU EIHF */ ++ case EMU_EIHF_INIT: ++ emu_current_device = EMU_EIHF; ++ break; ++ ++ case EMU_EIHF_MUTE: ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ break; ++ ++ case EMU_EIHF_UNMUTE: ++ set_GPIO(GPIO_SNP_INT_CTL); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static unsigned int emu_poll(struct file *file, poll_table *wait) ++{ ++ if (emu_is_int == EMU_NO) ++ { ++ EMU_DBG("%s,%s:emu_is_int is NO\n",__FILE__,__FUNCTION__); ++ emu_is_wait = EMU_YES; ++ poll_wait(file, &emu_wait_queue, wait); ++ } ++ else ++ { ++ EMU_DBG("%s,%s:emu_is_int is YES\n",__FILE__,__FUNCTION__); ++ emu_is_int = EMU_NO; ++ } ++ return POLLIN | POLLRDNORM; ++} ++/* ++ * This function is called when a user space program attempts to read ++ * /dev/emu. It puts the device to sleep on the wait queue until ++ * irq handler writes some data to the buffer and flushes ++ * the queue, at which point it writes the data out to the device and ++ * returns the number of characters it has written. This function is ++ * reentrant, so that many processes can be attempting to read from the ++ * device at any one time. ++ */ ++ ++static int emu_read (struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int retval = 0; ++ ++ EMU_DBG("%s,%s:enter ...\n",__FILE__,__FUNCTION__); ++ if (EMU_NO == emu_is_int) ++ { ++ EMU_DBG("%s,%s:emu_is_int is NO\n",__FILE__,__FUNCTION__); ++ add_wait_queue(&emu_wait_queue, &wait); ++ current->state = TASK_INTERRUPTIBLE; ++ ++ while (EMU_NO == emu_is_int) ++ { ++ if (file->f_flags & O_NONBLOCK) ++ { ++ retval = -EAGAIN; ++ break; ++ } ++ if (signal_pending(current)) ++ { ++ retval = -ERESTARTSYS; ++ break; ++ } ++ emu_is_wait = EMU_YES; ++ EMU_DBG("%s,%s:before schedule()\n",__FILE__,__FUNCTION__); ++ schedule(); ++ } ++ current->state = TASK_RUNNING; ++ EMU_DBG("%s,%s:after wake up\n",__FILE__,__FUNCTION__); ++ remove_wait_queue(&emu_wait_queue, &wait); ++ } ++ ++ return retval; ++} ++ ++#ifdef CONFIG_PM ++static int emu_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ EMU_DBG("emu_pm_callback\n"); ++ switch(req) ++ { ++ case PM_SUSPEND: ++ EMU_DBG("emu_pm_callback:PM_SUSPEND\n"); ++ /* Disable the PCAP transceiver both for USB and RS232 */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ ++ /* Set the Bulverde GPIO */ ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ PGSR(GPIO34_TXENB)|=GPIO_bit(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ break; ++ ++ case PM_RESUME: ++ ++ if ( emucount != 0) ++ { ++ switch ( emu_current_device) ++ { ++ case EMU_PIHF: ++ ++ EMU_DBG("emu_pm_callback:EMU_PIHF\n"); ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ ++ switch(emu_current_mode) ++ { ++ case EMU_MODE_UART: ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ break; ++ case EMU_MODE_USB: ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ break; ++ case EMU_MODE_AUDIO_MONO: ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); ++ break; ++ case EMU_MODE_AUDIO_STEREO: ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); ++ break; ++ default: ++ break; ++ } ++ break; ++ case EMU_EIHF: ++ /* Should not come here since the EIHF must have the charger. */ ++ break; ++ case EMU_USB: ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++ } ++ return 0; ++} ++#endif ++ ++static int emu_release(struct inode * inode, struct file * file) ++{ ++ int i; ++ ++ if ( emucount > 0) ++ emucount --; ++ ++ if(emucount) ++ { ++ return -EBUSY; ++ } ++ ++ if ( EMU_PIHF == emu_current_device) ++ free_irq(IRQ_GPIO(GPIO_SNP_INT_IN),NULL); ++ ++ EMU_DBG("emu_release:freed irq...%d\n",IRQ_GPIO(87)); ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++#ifdef DEBUG ++ EMU_DBG("emu_release:emu device released\n"); ++#endif ++ ++ return 0; ++} ++ ++static void emu_handle_int(int irq,void *dev,struct pt_regs *regs) ++{ ++ EMU_DBG("%s,%s:got the interrupt...\n",__FILE__,__FUNCTION__); ++ if ( EMU_YES == emu_is_wait ) ++ { ++ EMU_DBG("%s,%s:emu_is_wait is YES...\n",__FILE__,__FUNCTION__); ++ wake_up_interruptible(&emu_wait_queue); ++ emu_is_wait = EMU_NO; ++ } ++ else ++ { ++ EMU_DBG("%s,%s:emu_is_wait is NO...\n",__FILE__,__FUNCTION__); ++ emu_is_int = EMU_YES; ++ } ++ EMU_DBG("emu_handle_int:after wake up...\n"); ++} ++ ++static int emu_open(struct inode * inode, struct file * file) ++{ ++ int i, data; ++ int ret; ++ ++ /* emucount could only be 1 or 0 */ ++ if(emucount) ++ { ++ return -EBUSY; ++ } ++ emucount ++; ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, emu_pm_callback); ++#endif ++ EMU_DBG("emu_open:emu device opened\n"); ++ return 0; ++} ++ ++/* add emu_ioctl to check flip status */ ++static struct file_operations emu_fops = { ++ owner: THIS_MODULE, ++ open: emu_open, ++ release: emu_release, ++ read: emu_read, ++ poll: emu_poll, ++ ioctl: emu_ioctl, ++}; ++ ++/* ++ * This structure is the misc device structure, which specifies the minor ++ * device number (165 in this case), the name of the device (for /proc/misc), ++ * and the address of the above file operations structure. ++ */ ++ ++static struct miscdevice emu_misc_device = { ++ EMU_MINOR, ++ "emu", ++ &emu_fops, ++}; ++ ++/* ++ * This function is called to initialise the driver, either from misc.c at ++ * bootup if the driver is compiled into the kernel, or from init_module ++ * below at module insert time. It attempts to register the device node ++ * and the IRQ and fails with a warning message if either fails, though ++ * neither ever should because the device number and IRQ are unique to ++ * this driver. ++ */ ++ ++static int __init emu_init(void) ++{ ++ pxa_gpio_mode(GPIO_SNP_INT_IN | GPIO_IN); ++ pxa_gpio_mode(GPIO_EMU_MUX1 | GPIO_OUT); ++ pxa_gpio_mode(GPIO_EMU_MUX2 | GPIO_OUT); ++ ++ if (misc_register (&emu_misc_device)) { ++ EMU_DBG (KERN_WARNING "emu: Couldn't register device 10, " ++ "%d.\n", EMU_MINOR); ++ return -EBUSY; ++ } ++} ++ ++static void __exit emu_exit (void) ++{ ++ misc_deregister(&emu_misc_device); ++} ++ ++ ++module_init(emu_init); ++module_exit(emu_exit); ++#else /* EMU_PIHF_FEATURE */ ++ ++/* ++ * linux/drivers/misc/ezx-emu.c --- EMU driver on ezx ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Cheng Xuefeng ++ * Created: April 30, 2004 ++ * Copyright: Motorola 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 <linux/init.h> ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/time.h> ++#include <linux/timer.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/delay.h> ++#include <linux/apm_bios.h> ++ ++#include <asm/hardware.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/semaphore.h> ++#include <asm/mach-types.h> ++#include "ssp_pcap.h" ++#include "ezx-emu.h" ++ ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx.h> ++ ++#define DEBUG ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++#endif ++ ++#ifdef EMU_INTERFACE_DEBUG ++#define EMU_DBG(fmt,args...) printk("EMU:"fmt,##args); ++#else ++#define EMU_DBG(fmt,args...) ++#endif ++ ++EXPORT_SYMBOL(emu_switch_to); ++ ++extern void emu_switch_to(T_EMU_SWITCH_TO to); ++ ++#define EMU_YES (0) ++#define EMU_NO (1) ++ ++/* 1ms */ ++#define EMU_PIHF_DPLUS_INIT_INTERVAL (1) ++ ++static int emu_is_int = EMU_NO; ++static int emu_is_wait = EMU_NO; ++ ++typedef enum{ ++ EMU_USB = 0, ++ EMU_PIHF, ++ EMU_EIHF ++} T_EMU_CURRENT_DEVICE; ++ ++typedef enum{ ++ EMU_MODE_UART =0, ++ EMU_MODE_USB, ++ EMU_MODE_AUDIO_MONO, ++ EMU_MODE_AUDIO_STEREO ++} T_EMU_MODE; ++ ++static T_EMU_CURRENT_DEVICE emu_current_device = EMU_USB; ++static T_EMU_MODE emu_current_mode = EMU_MODE_USB; ++ ++static DECLARE_WAIT_QUEUE_HEAD(emu_wait_queue); /* Used for blocking read */ ++ ++static int emucount=0; ++ ++ ++static void emu_handle_int(int irq,void *dev,struct pt_regs *regs); ++ ++/* This will be export to other modules. For other feature, developer should ++ * add related T_EMU_SWITCH_TO type as requriement. ++ */ ++void emu_switch_to(T_EMU_SWITCH_TO to) ++{ ++ switch(to) ++ { ++ case EMU_SWITCH_TO_NO_DEV: ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_NO_DEV\n"); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ ++ /* Disable the PCAP transceiver both for USB and RS232 */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ ++ /* Set the Bulverde GPIO */ ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ break; ++ case EMU_SWITCH_TO_UART: ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_UART\n"); ++ /* set other USB related GPIO direcction to IN first */ ++ set_GPIO(GPIO39_VPOUT); ++ ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_IN); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ ++ /* Init UART related GPIO */ ++ pxa_gpio_mode(GPIO39_FFTXD_MD); ++ pxa_gpio_mode(GPIO53_FFRXD_MD); ++ CKEN |= CKEN6_FFUART; ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_UART:set txd high\n"); ++ ++ /* set the PCAP as UART mode */ ++ /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_SERIAL_PORT);*/ ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN)) ++ { ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ } ++ else ++ { ++ return; ++ } ++ ++ /* set the MUX1/2 to data mode */ ++ clr_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++ emu_current_mode = EMU_MODE_UART; ++ break; ++ case EMU_SWITCH_TO_USB: ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_USB\n"); ++ /* set the 6 USB related GPIOs as USB function*/ ++ pxa_gpio_mode(GPIO34_USB_P2_2_MD); ++ pxa_gpio_mode(GPIO35_XRXD_MD); ++ pxa_gpio_mode(GPIO36_VMOUT_MD); ++ pxa_gpio_mode(GPIO39_VPOUT_MD); ++ pxa_gpio_mode(GPIO40_VPIN_MD); ++ pxa_gpio_mode(GPIO53_VMIN_MD); ++ UP2OCR = 0x02000000; ++ ++ /* set the PCAP as UART mode */ ++ /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_HIGH_USB_PORT);*/ ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB)) ++ { ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB)) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ } ++ } ++ ++ /* set the MUX1/2 to data mode */ ++ clr_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++ emu_current_mode = EMU_MODE_USB; ++ break; ++ case EMU_SWITCH_TO_AUDIO_MONO: ++ /* This will not change the PCAP audio related ++ * register. Just change the MUX1/2. Switching ++ * the audio path is controlled by other driver. ++ */ ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_MONO\n"); ++ ++ clr_GPIO(GPIO39_VPOUT); ++ mdelay(1); ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ ++ /* set the MUX1/2 to mono mode */ ++ set_GPIO(GPIO_EMU_MUX1); ++ clr_GPIO(GPIO_EMU_MUX2); ++ ++ emu_current_mode = EMU_MODE_AUDIO_MONO; ++ break; ++ case EMU_SWITCH_TO_AUDIO_STEREO: ++ /* This will not change the PCAP audio related ++ * register. Just change the MUX1/2. Switching ++ * the audio path is controlled by other driver. ++ */ ++ EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_STEREO\n"); ++ clr_GPIO(GPIO39_VPOUT); ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ ++ /* set the MUX1/2 to stereo mode */ ++ set_GPIO(GPIO_EMU_MUX1); ++ set_GPIO(GPIO_EMU_MUX2); ++ emu_current_mode = EMU_MODE_AUDIO_STEREO; ++ break; ++ default: ++ break; ++ } ++ return; ++} ++ ++ ++static int emu_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) ++{ ++ int ret; ++ long val; ++ ++ switch(cmd){ ++ ++ /* Switch the MUX1/2 and set the GPIOs */ ++ case EMU_SW_TO_UART: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_UART:before change\n"); ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ break; ++ ++ case EMU_SW_TO_USB: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_USB:before change\n"); ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ break; ++ ++ case EMU_SW_TO_AUDIO_MONO: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_MONO:before change\n"); ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); ++ break; ++ ++ case EMU_SW_TO_AUDIO_STEREO: ++ EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_STEREO: not support...\n"); ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); ++ break; ++ ++ /* EMU PIHF */ ++ case EMU_PIHF_INIT: ++ EMU_DBG("%s,%s:EMU_PIHF_INIT",__FILE__,__FUNCTION__); ++ ++ /* init to UART mode */ ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ ++ EMU_DBG("emu_ioctl:set GPIO 86\n"); ++ /* For SNP_INT_CTL, the inactive state is low. ++ * That means the ID line is high. ++ */ ++ pxa_gpio_mode(GPIO_SNP_INT_CTL|GPIO_OUT); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ ++ EMU_DBG("emu_ioctl:before request_irq()\n"); ++ ++ udelay(10); ++ ++ set_GPIO_IRQ_edge(GPIO_SNP_INT_IN,GPIO_FALLING_EDGE|GPIO_RISING_EDGE); ++ ++#if 0 ++ if(GPLR(GPIO_SNP_INT_IN) & GPIO_bit(GPIO_SNP_INT_IN)) ++ { ++ EMU_DBG("emu_ioctl:87 is high\n"); ++ } ++ else ++ { ++ EMU_DBG("emu_ioctl:87 is low\n"); ++ } ++#endif ++ ++ if (request_irq(IRQ_GPIO(GPIO_SNP_INT_IN),emu_handle_int, ++ SA_INTERRUPT|SA_SAMPLE_RANDOM, ++ "EMU SNP interrupt",(void*)1) ++ ) ++ { ++ printk(KERN_WARNING"can't get EMU snp_int irq\n"); ++ return -EIO; ++ } ++ ++ emu_current_device = EMU_PIHF; ++ break; ++ case EMU_PIHF_SNP_INT_CTL: ++ EMU_DBG("emu_ioctl:got the SNP_INT_CTL...\n"); ++ /* For SNP_INT_CTL, the inactive state is low. ++ * That means the ID line is high. ++ */ ++ ret = get_user(val,(long *)arg); ++ if (ret) ++ return ret; ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ set_GPIO(GPIO_SNP_INT_CTL); ++ mdelay(val); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ break; ++ ++ case EMU_PIHF_ID_LOW: ++ EMU_DBG("emu_ioctl:EMU_PIHF_ID_LOW\n"); ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ set_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ break; ++ ++ case EMU_PIHF_ID_HIGH: ++ EMU_DBG("emu_ioctl:EMU_PIHF_ID_HIGH\n"); ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ break; ++ ++ case EMU_PIHF_INIT_DPLUS_CTL: ++ EMU_DBG("emu_ioctl:EMU_PIHF_INIT_DPLUS_CTL\n"); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); ++ mdelay(EMU_PIHF_DPLUS_INIT_INTERVAL); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); ++ break; ++ ++ /* EMU EIHF */ ++ case EMU_EIHF_INIT: ++ emu_current_device = EMU_EIHF; ++ break; ++ ++ case EMU_EIHF_MUTE: ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ break; ++ ++ case EMU_EIHF_UNMUTE: ++ set_GPIO(GPIO_SNP_INT_CTL); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static unsigned int emu_poll(struct file *file, poll_table *wait) ++{ ++ if (emu_is_int == EMU_NO) ++ { ++ emu_is_wait = EMU_YES; ++ poll_wait(file, &emu_wait_queue, wait); ++ } ++ else ++ { ++ emu_is_int = EMU_NO; ++ } ++ return POLLIN | POLLRDNORM; ++} ++/* ++ * This function is called when a user space program attempts to read ++ * /dev/emu. It puts the device to sleep on the wait queue until ++ * irq handler writes some data to the buffer and flushes ++ * the queue, at which point it writes the data out to the device and ++ * returns the number of characters it has written. This function is ++ * reentrant, so that many processes can be attempting to read from the ++ * device at any one time. ++ */ ++ ++static int emu_read (struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int retval = 0; ++ ++ if (EMU_NO == emu_is_int) ++ { ++ add_wait_queue(&emu_wait_queue, &wait); ++ current->state = TASK_INTERRUPTIBLE; ++ ++ while (EMU_NO == emu_is_int) ++ { ++ if (file->f_flags & O_NONBLOCK) ++ { ++ retval = -EAGAIN; ++ break; ++ } ++ if (signal_pending(current)) ++ { ++ retval = -ERESTARTSYS; ++ break; ++ } ++ emu_is_wait = EMU_YES; ++ schedule(); ++ } ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&emu_wait_queue, &wait); ++ } ++ ++ return retval; ++} ++ ++#ifdef CONFIG_PM ++static int emu_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ EMU_DBG("emu_pm_callback\n"); ++ switch(req) ++ { ++ case PM_SUSPEND: ++ EMU_DBG("emu_pm_callback:PM_SUSPEND\n"); ++ /* Disable the PCAP transceiver both for USB and RS232 */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ ++ /* Set the Bulverde GPIO */ ++ pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); ++ set_GPIO(GPIO34_TXENB); ++ PGSR(GPIO34_TXENB)|=GPIO_bit(GPIO34_TXENB); ++ pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); ++ pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); ++ pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); ++ pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); ++ break; ++ ++ case PM_RESUME: ++ ++ if ( emucount != 0) ++ { ++ switch ( emu_current_device) ++ { ++ case EMU_PIHF: ++ ++ EMU_DBG("emu_pm_callback:EMU_PIHF\n"); ++ disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ clr_GPIO(GPIO_SNP_INT_CTL); ++ enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); ++ ++ switch(emu_current_mode) ++ { ++ case EMU_MODE_UART: ++ emu_switch_to(EMU_SWITCH_TO_UART); ++ break; ++ case EMU_MODE_USB: ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ break; ++ case EMU_MODE_AUDIO_MONO: ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); ++ break; ++ case EMU_MODE_AUDIO_STEREO: ++ emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); ++ break; ++ default: ++ break; ++ } ++ break; ++ case EMU_EIHF: ++ /* Should not come here since the EIHF must have the charger. */ ++ break; ++ case EMU_USB: ++ emu_switch_to(EMU_SWITCH_TO_USB); ++ break; ++ default: ++ break; ++ } ++ } ++ break; ++ } ++ return 0; ++} ++#endif ++ ++static int emu_release(struct inode * inode, struct file * file) ++{ ++ int i; ++ ++ if ( emucount > 0) ++ emucount --; ++ ++ if(emucount) ++ { ++ return -EBUSY; ++ } ++ ++ if ( EMU_PIHF == emu_current_device) ++ free_irq(IRQ_GPIO(GPIO_SNP_INT_IN),NULL); ++ ++ EMU_DBG("emu_release:freed irq...%d\n",IRQ_GPIO(87)); ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++#ifdef DEBUG ++ EMU_DBG("emu_release:emu device released\n"); ++#endif ++ ++ return 0; ++} ++ ++static void emu_handle_int(int irq,void *dev,struct pt_regs *regs) ++{ ++ EMU_DBG("emu_handle_int:got the interrupt...\n"); ++ if ( EMU_YES == emu_is_wait ) ++ { ++ wake_up_interruptible(&emu_wait_queue); ++ emu_is_wait = EMU_NO; ++ } ++ else ++ { ++ emu_is_int = EMU_YES; ++ } ++ EMU_DBG("emu_handle_int:after wake up...\n"); ++} ++ ++static int emu_open(struct inode * inode, struct file * file) ++{ ++ int i, data; ++ int ret; ++ ++ /* emucount could only be 1 or 0 */ ++ if(emucount) ++ { ++ return -EBUSY; ++ } ++ emucount ++; ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, emu_pm_callback); ++#endif ++ EMU_DBG("emu_open:emu device opened\n"); ++ return 0; ++} ++ ++/* add emu_ioctl to check flip status */ ++static struct file_operations emu_fops = { ++ owner: THIS_MODULE, ++ open: emu_open, ++ release: emu_release, ++ read: emu_read, ++ poll: emu_poll, ++ ioctl: emu_ioctl, ++}; ++ ++/* ++ * This structure is the misc device structure, which specifies the minor ++ * device number (165 in this case), the name of the device (for /proc/misc), ++ * and the address of the above file operations structure. ++ */ ++ ++static struct miscdevice emu_misc_device = { ++ EMU_MINOR, ++ "emu", ++ &emu_fops, ++}; ++ ++/* ++ * This function is called to initialise the driver, either from misc.c at ++ * bootup if the driver is compiled into the kernel, or from init_module ++ * below at module insert time. It attempts to register the device node ++ * and the IRQ and fails with a warning message if either fails, though ++ * neither ever should because the device number and IRQ are unique to ++ * this driver. ++ */ ++ ++static int __init emu_init(void) ++{ ++ pxa_gpio_mode(GPIO_SNP_INT_IN | GPIO_IN); ++ ++ if (misc_register (&emu_misc_device)) { ++ EMU_DBG (KERN_WARNING "emu: Couldn't register device 10, " ++ "%d.\n", EMU_MINOR); ++ return -EBUSY; ++ } ++} ++ ++static void __exit emu_exit (void) ++{ ++ misc_deregister(&emu_misc_device); ++} ++ ++ ++module_init(emu_init); ++module_exit(emu_exit); ++#endif /* EMU_PIHF_FEATURE */ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-emu.h linux-2.6.16/drivers/misc/ezx/ezx-emu.h +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-emu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-emu.h 2006-06-03 11:14:56.305329544 +0200 +@@ -0,0 +1,93 @@ ++#ifdef EMU_PIHF_FEATURE ++/* ++ * linux/drivers/emu/ezx-emu.h ++ * author: Cheng Xuefeng ++ * company: Motorola Inc. ++ * date: 30/4/2004 ++ */ ++#include <linux/ioctl.h> ++ ++/* Various defines: */ ++#define VERSION "0.1" /* Driver version number */ ++#define EMU_MINOR 250 /* Major 10, Minor 250, /dev/emu */ ++ ++/* single button */ ++ ++#define EMU_IOCTL_BASE 0xdf ++ ++/* Switch the Mux1/2 and set the GPIOs */ ++#define EMU_SW_TO_UART _IO(EMU_IOCTL_BASE, 1) ++#define EMU_SW_TO_USB _IO(EMU_IOCTL_BASE, 2) ++#define EMU_SW_TO_AUDIO_MONO _IO(EMU_IOCTL_BASE, 3) ++#define EMU_SW_TO_AUDIO_STEREO _IO(EMU_IOCTL_BASE, 4) ++#define EMU_SMART_SPD_INIT _IO(EMU_IOCTL_BASE, 5) ++ ++/* EMU PIHF */ ++#define EMU_PIHF_INIT _IOW(EMU_IOCTL_BASE, 21,int) ++/*#define EMU_PIHF_GET_STATUS _IOR(EMU_IOCTL_BASE, 12,int)*/ ++#define EMU_PIHF_SNP_INT_CTL _IOR(EMU_IOCTL_BASE, 23,int) ++#define EMU_PIHF_ID_LOW _IO(EMU_IOCTL_BASE, 24) ++#define EMU_PIHF_ID_HIGH _IO(EMU_IOCTL_BASE, 25) ++ ++/* EMU EIHF */ ++#define EMU_EIHF_INIT _IOW(EMU_IOCTL_BASE, 31,int) ++#define EMU_EIHF_MUTE _IO(EMU_IOCTL_BASE, 32) ++#define EMU_EIHF_UNMUTE _IO(EMU_IOCTL_BASE, 33) ++ ++typedef enum{ ++ EMU_SWITCH_TO_UART = 0, ++ EMU_SWITCH_TO_USB, ++ EMU_SWITCH_TO_AUDIO_MONO, ++ EMU_SWITCH_TO_AUDIO_STEREO, ++ EMU_SWITCH_TO_NO_DEV ++} T_EMU_SWITCH_TO; ++ ++void emu_switch_to(T_EMU_SWITCH_TO to); ++ ++#else /* EMU_PIHF_FEATURE */ ++ ++/* ++ * linux/drivers/emu/ezx-emu.h ++ * author: Cheng Xuefeng ++ * company: Motorola Inc. ++ * date: 30/4/2004 ++ */ ++#include <linux/ioctl.h> ++ ++/* Various defines: */ ++#define VERSION "0.1" /* Driver version number */ ++#define EMU_MINOR 250 /* Major 10, Minor 250, /dev/emu */ ++ ++/* single button */ ++ ++#define EMU_IOCTL_BASE 0xdf ++ ++/* Switch the Mux1/2 and set the GPIOs */ ++#define EMU_SW_TO_UART _IO(EMU_IOCTL_BASE, 1) ++#define EMU_SW_TO_USB _IO(EMU_IOCTL_BASE, 2) ++#define EMU_SW_TO_AUDIO_MONO _IO(EMU_IOCTL_BASE, 3) ++#define EMU_SW_TO_AUDIO_STEREO _IO(EMU_IOCTL_BASE, 4) ++ ++/* EMU PIHF */ ++#define EMU_PIHF_INIT _IOW(EMU_IOCTL_BASE, 21,int) ++/*#define EMU_PIHF_GET_STATUS _IOR(EMU_IOCTL_BASE, 12,int)*/ ++#define EMU_PIHF_SNP_INT_CTL _IOR(EMU_IOCTL_BASE, 23,int) ++#define EMU_PIHF_ID_LOW _IO(EMU_IOCTL_BASE, 24) ++#define EMU_PIHF_ID_HIGH _IO(EMU_IOCTL_BASE, 25) ++#define EMU_PIHF_INIT_DPLUS_CTL _IO(EMU_IOCTL_BASE, 26) ++ ++/* EMU EIHF */ ++#define EMU_EIHF_INIT _IOW(EMU_IOCTL_BASE, 31,int) ++#define EMU_EIHF_MUTE _IO(EMU_IOCTL_BASE, 32) ++#define EMU_EIHF_UNMUTE _IO(EMU_IOCTL_BASE, 33) ++ ++typedef enum{ ++ EMU_SWITCH_TO_UART = 0, ++ EMU_SWITCH_TO_USB, ++ EMU_SWITCH_TO_AUDIO_MONO, ++ EMU_SWITCH_TO_AUDIO_STEREO, ++ EMU_SWITCH_TO_NO_DEV ++} T_EMU_SWITCH_TO; ++ ++void emu_switch_to(T_EMU_SWITCH_TO to); ++#endif /* EMU_PIHF_FEATURE */ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-log.c linux-2.6.16/drivers/misc/ezx/ezx-log.c +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-log.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-log.c 2006-06-03 11:14:56.306329392 +0200 +@@ -0,0 +1,183 @@ ++/* ++ * Kernel panic log interface for Linux on A760(XScale PXA262). ++ * ++ * Copyright (c) 2000 Motorola ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * 0.01 2003-07-01 zxf <w19962@motorola.com> ++ * - initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/mtd/mtd.h> ++ ++#include <asm/io.h> ++#include <asm/uaccess.h> ++ ++#include "log.h" ++ ++#define A760_LOG_NAME "A760" ++#define A760_LOG_START 0x01fc0000 ++#define A760_LOG_SIZE 0x00020000 ++ ++#define E680_LOG_NAME "E680" ++#define E680_LOG_START 0x01fc0000 ++#define E680_LOG_SIZE 0x00020000 ++ ++#define A780_LOG_NAME "A780" ++#define A780_LOG_START 0x01fc0000 ++#define A780_LOG_SIZE 0x00020000 ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++#define LOG_NAME E680_LOG_NAME ++#define LOG_START E680_LOG_START ++#define LOG_SIZE E680_LOG_SIZE ++#elif CONFIG_ARCH_EZX_A780 ++#define LOG_NAME A780_LOG_NAME ++#define LOG_START A780_LOG_START ++#define LOG_SIZE A780_LOG_SIZE ++#else ++#define LOG_NAME A760_LOG_NAME ++#define LOG_START A760_LOG_START ++#define LOG_SIZE A760_LOG_SIZE ++#endif ++ ++static ssize_t log_read(const char *buf, size_t count, loff_t *ppos); ++static ssize_t log_write(const char *buf, size_t count); ++ ++static struct log_area flash_log = { ++ name: LOG_NAME, //"A760", ++ start: LOG_START, // LOGO_ADDR is 0x01fc0000 ++ size: LOG_SIZE, ++ write: log_write, ++ read: log_read, ++}; ++ ++/* ++ * Here the read implementation should not impact mtd device. ++ * Most part of the read function is coming from mtdchar.c ++ */ ++#define MAX_KMALLOC_SIZE 0x20000 ++static ssize_t log_read(const char *buf, size_t count, loff_t *ppos) ++{ ++ struct mtd_info *mtd; ++ size_t retlen=0; ++ size_t total_retlen=0; ++ int ret=0; ++ int len; ++ char *kbuf; ++ ++ mtd = get_mtd_device(NULL, 3); ++ if (!mtd) ++ return -ENODEV; ++ ++ while (count) { ++ if (count > MAX_KMALLOC_SIZE) ++ len = MAX_KMALLOC_SIZE; ++ else ++ len = count; ++ ++ kbuf=kmalloc(len,GFP_KERNEL); ++ if (!kbuf) ++ return -ENOMEM; ++ ++ ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); ++ if (!ret) { ++ *ppos += retlen; ++ if (copy_to_user(buf, kbuf, retlen)) { ++ kfree(kbuf); ++ return -EFAULT; ++ } ++ else ++ total_retlen += retlen; ++ ++ count -= retlen; ++ buf += retlen; ++ } ++ else { ++ kfree(kbuf); ++ return ret; ++ } ++ ++ kfree(kbuf); ++ } ++ ++ return total_retlen; ++} ++ ++static ssize_t log_write(const char *buf, size_t count) ++{ ++ int i; ++ ssize_t ret; ++ void *area; ++ unsigned short *buffer; ++ volatile unsigned short *ptr; ++ ++ //printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); ++ ++ area = __ioremap(flash_log.start, flash_log.size, 0); ++ if (!area) ++ return -ENOMEM; ++ ++ ptr = (unsigned short *)area; ++ ret = count; ++ ++#define EZX_A760 ++#ifdef EZX_A760 ++ /* wait state ready */ ++ *ptr = 0x70; ++ while (!((*ptr) & 0x80)); ++ ++ /* unlock the block */ ++ *ptr = 0x60; *ptr = 0xd0; ++ while (!((*ptr) & 0x80)); ++ ++ /* erase the block */ ++ *ptr = 0x20; *ptr = 0xd0; ++ while (!((*ptr) & 0x80)); ++ ++#elif EZX_BVD ++ // bvd platform ++ // same as A760 ++#endif ++ ++ /* program the block */ ++ if(count > flash_log.size) ++ count = flash_log.size; ++ count = count / sizeof(unsigned short); /* it doesn't matter to lose a little data */ ++ buffer = (unsigned short *)buf; ++ for (i = 0; i < count; i++, ptr++) { ++ *ptr = 0x40; ++ *ptr = *buffer++; ++ while (!((*ptr) & 0x80)); ++ } ++ ++ //printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); ++ __iounmap(area); ++ return ret; ++} ++ ++ ++static int __init ezxlog_init(void) ++{ ++ return log_register(&flash_log); ++} ++ ++static void __exit ezxlog_exit(void) ++{ ++ log_unregister(&flash_log); ++} ++ ++module_init(ezxlog_init); ++module_exit(ezxlog_exit); ++ ++MODULE_AUTHOR("zxf <w19962@motorola.com>"); ++MODULE_DESCRIPTION("A760 Kernel panic log interface"); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOLS; +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-ts.c linux-2.6.16/drivers/misc/ezx/ezx-ts.c +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-ts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-ts.c 2006-06-03 11:14:56.307329240 +0200 +@@ -0,0 +1,910 @@ ++/* ++ * linux/drivers/char/ezx-ts.c ++ * ++ * Copyright (C) 2002 Lili Jiang, All Rights Reserved. ++ * ++ * ++ * June, 2002 Lili Jiang, create ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/poll.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/sched.h> ++#include <linux/completion.h> ++#include <linux/string.h> ++#include <linux/pm.h> ++#include <linux/config.h> ++#include <linux/fb.h> ++ ++#include <asm/semaphore.h> ++#include <asm/hardware.h> ++#include <asm/arch/irqs.h> ++#include <linux/timex.h> ++#include <linux/interrupt.h> ++ ++#include <asm/arch/pxa-regs.h> ++ ++#include "ezx-ts.h" ++#include "ssp_pcap.h" ++ ++#define DEBUG 0 /*change it when formal release*/ ++#if DEBUG ++# define TS_DPRINTK(s...) printk(s) ++#else ++# define TS_DPRINTK(s...) ++#endif ++ ++/* ++ * 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. ++ */ ++struct ts_event { ++ u16 pressure; ++ u16 x; ++ u16 y; ++ u16 pad; ++// struct timeval stamp; ++}; ++ ++static struct timer_list ezx_ts_penup_timer; ++ ++static struct irqaction ezx_ts_custom_timer_irq = { ++ name: "ezx_ts_custom_timer", ++}; ++ ++static u8 bSetPenupTimer = 0; ++static u8 bFirstPen = 0; ++//static unsigned long penCurJiffies = 0; ++static unsigned int penSampleCount = 0; ++static u32 tspenSampleCount = 0; ++static u32 tsDiscardDataCount = 0; ++ ++typedef enum ++{ ++ PRESSURE, ++ COORDINATE ++}EZX_TS_READ_STATE; ++ ++EZX_TS_READ_STATE ezx_ts_read_state = PRESSURE; ++ ++#define TS_NR_EVENTS 128 ++/*250 //pay attention to that haed and tail is defined as u8*/ ++ ++#define TS_EDGE_MIN_LIMIT (0) /* 10 */ ++#define TS_EDGE_MAX_LIMIT (1023) ++ ++/* jiffies : 10ms, pen shake 50ms????? */ ++//#define EZX_TS_READ_MIN_SPACE 10 /*100//5*/ ++//#define EZX_TS_PENUP_TIMEOUT_MS 8 ++ ++#define EZX_TS_PENSAMPLE_TIMEOUT_MS 2 ++ //8,6 ++//#define EZX_TS_HWR_TIMEOUT_MS 2 ++ ++#define QT_ONEPEN_SAMPLES_NUM 1 ++ //3,5 ++//#define HWR_ONEPEN_SAMPLES_NUM 1 ++ ++#define CUSTOM_ONEPEN_SAMPLES_NUM 1 ++#define EZX_TS_CUSTOM_TIMEOUT_MS 12 ++ //15ms ++#define X_DIFF 85 ++#define Y_DIFF 75 ++#define MIN_X_HOLD 5 ++#define MIN_Y_HOLD 4 ++#define SAMPLE_COUNT_NOT_JUMPER 20 ++ ++typedef enum ++{ ++ EZX_PEN_NORMAL, ++ EZX_PEN_CUSTOM ++}EZX_TS_PEN_STYLE; ++ ++static EZX_TS_PEN_STYLE gPenStyle = EZX_PEN_NORMAL; ++static u8 gPenSamplesNum = QT_ONEPEN_SAMPLES_NUM; ++//static u32 gHwrTimer = EZX_TS_HWR_TIMEOUT_MS; ++static u32 gCustomTimer = EZX_TS_CUSTOM_TIMEOUT_MS; ++static u8 getPenUp = 0; ++ ++struct ezx_ts_info { ++ /*struct ucb1x00 *ucb;*/ ++ struct fasync_struct *fasync; ++ wait_queue_head_t read_wait; ++ ++ /* ++ struct semaphore irq_wait; ++ struct semaphore sem; ++ struct completion init_exit; ++ struct task_struct *rtask; ++ */ ++ u16 x_cur; /*store the current pen value read from ADC*/ ++ u16 y_cur; /*store the current pen value read from ADC */ ++ u16 cur_pressure; ++ u16 x_pre; ++ u16 y_pre; ++ u8 evt_head; ++ u8 evt_tail; ++ struct ts_event events[TS_NR_EVENTS]; /* buffer for store pen data*/ ++/* ++ int restart:1; ++ int adcsync:1; ++ ++#ifdef CONFIG_PM ++ struct pm_dev *pmdev; ++#endif ++*/ ++}; ++ ++static struct ezx_ts_info ezxts; ++ ++#define EZX_TS_SHAKE_SAMPLES 3 ++static u8 ezx_ts_shake_samples_count = 0; ++static struct ts_event ezx_ts_shake_samples[EZX_TS_SHAKE_SAMPLES]; ++ ++static int ezx_ts_init(void); ++static void ezx_ts_exit(void); ++static int ezx_ts_open(struct inode *inode, struct file * filp); ++static int ezx_ts_release(struct inode *inode, struct file *filp); ++static ssize_t ezx_ts_read(struct file* filp, char* buffer, size_t count, loff_t *ppos); ++static unsigned int ezx_ts_poll(struct file* filp, struct poll_table_struct * wait); ++static int ezx_ts_fasync(int fd, struct file* filp, int mode); ++ ++/* internal function */ ++static void ezx_ts_init_penEvent(void); ++static void ezx_ts_pen_touch_handler(void); ++static void ezx_ts_penup_timeout(unsigned long data); ++static void ezx_ts_set_timer(struct timer_list *timer, void (*timer_timeout)(unsigned long), signed long timeout); ++static void ezx_ts_check_pen_samples(void); ++static void ezx_ts_evt_add(u16 pressure, u16 x, u16 y); ++static struct ts_event ezx_ts_get_onedata(void); ++ ++/* for setup ezx ts self timer,begin */ ++static void ezx_ts_custom_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ TS_DPRINTK("ezx_ts_custom_timer_interrupt entered.jiffies: %d\n@@@\n", jiffies); ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ ++ /* clear this timer */ ++ OIER &= ~OIER_E3; ++ OSSR = OSSR_M3; /* Clear match on timer 2 */ ++} ++ ++static void ezx_ts_custom_setup_timer() ++{ ++ ezx_ts_custom_timer_irq.handler = ezx_ts_custom_timer_interrupt; ++ setup_irq(IRQ_OST3, &ezx_ts_custom_timer_irq); ++} ++ ++ ++static void ezx_ts_custom_timer_start(void) ++{ ++ OIER |= OIER_E3; ++ //OSMR2 = OSCR + sleep_limit * LATCH; //OSCR: 0x40A00010 ++ OSMR3 = OSCR + (gCustomTimer * HZ * LATCH) /1000; ++} ++ ++static void ezx_ts_custom_timer_stop(void) ++{ ++ OIER &= ~OIER_E3; ++ OSSR = OSSR_M3; /* Clear match on timer 2 */ ++} ++ ++/* for setup ezx ts self timer, end */ ++ ++ ++static void ezx_ts_init_penEvent(void) ++{ ++ int i; ++ ++ ezxts.x_cur = 0; ++ ezxts.y_cur = 0; ++ ezxts.x_pre = 0; ++ ezxts.y_pre = 0; ++ ezxts.cur_pressure = PEN_UP; ++ ++ for (i = 0; i < TS_NR_EVENTS; i++) ++ { ++ ezxts.events[i].pressure=(u16)0; ++ ezxts.events[i].x=(u16)0; ++ ezxts.events[i].y=(u16)0; ++ ezxts.events[i].pad=(u16)0; ++ } ++ ezxts.evt_head = 0; ++ ezxts.evt_tail = 0; ++ ++ gPenStyle = EZX_PEN_NORMAL; ++ gPenSamplesNum = QT_ONEPEN_SAMPLES_NUM; ++ //gHwrTimer = EZX_TS_HWR_TIMEOUT_MS; ++ gCustomTimer = EZX_TS_CUSTOM_TIMEOUT_MS; ++} ++ ++ ++static void ezx_ts_pen_touch_handler(void) ++{ ++ SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ ezx_ts_read_state = PRESSURE; ++ ezxts.x_pre = 0; ++ ezxts.y_pre = 0; ++ ++ TS_DPRINTK("ezx_ts pen touch handler done.\n"); ++} ++ ++static void ezx_ts_penup_timeout(unsigned long data) ++{ ++ TS_DPRINTK("@@@\nIn pen drag! jiffies: %d\n@@@\n", jiffies); ++ bSetPenupTimer = 0; ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++} ++ ++static void ezx_ts_check_pen_samples(void) ++{ ++ if ( (ezx_ts_read_state == COORDINATE) && (penSampleCount != 0 ) ) ++ { ++ int k; ++ if (penSampleCount < gPenSamplesNum) ++ { ++ for ( k = 0; k < (gPenSamplesNum - penSampleCount); k++) ++ { ++ ezx_ts_evt_add(PEN_DOWN, ezxts.x_cur, ezxts.y_cur); ++ TS_DPRINTK("ezx_ts_add_additional_samples: %d\n", k); ++ } ++ } ++ TS_DPRINTK("ezx_ts_evt_add: PEN_UP\n"); ++ //ezx_ts_evt_add(PEN_UP, 0, 0); ++ } ++ ++ if (bSetPenupTimer) ++ { ++ del_timer(&ezx_ts_penup_timer); ++ bSetPenupTimer = 0; ++ TS_DPRINTK("^^^^Delete penup timer1.\n"); ++ } ++ penSampleCount = 0; ++} ++ ++static void ezx_ts_set_timer(struct timer_list *timer, void (*timer_timeout)(unsigned long), ++ signed long timeout) ++{ ++ init_timer(timer); ++ timer->expires = timeout + jiffies; ++ timer->data = (unsigned long) current; ++ timer->function = timer_timeout; ++ ++ add_timer(timer); ++ //TS_DPRINTK("ezx_ts set timer done.\n"); ++} ++ ++static void ezx_ts_evt_add(u16 pressure, u16 x, u16 y) ++{ ++ int next_head; ++ int last_head; ++ /* if pen_up, then copy pressure=0, last_evt.x y to current evt*/ ++ ++ next_head = ezxts.evt_head + 1; ++ if (next_head == TS_NR_EVENTS) ++ { ++ next_head = 0; ++ } ++ ++ last_head = ezxts.evt_head - 1; ++ if (last_head == -1) ++ { ++ last_head = TS_NR_EVENTS - 1; ++ } ++ ++/* if (next_head != ezxts.evt_tail)*/ ++ //{ ++ if ( pressure == PEN_DOWN) ++ { ++/* if ( (penSampleCount >1) && ((penCurJiffies + EZX_TS_READ_MIN_SPACE) < jiffies)) ++ { ++ // see two ~ four data or just ignore the data except the first one???? ++ return; ++ } ++ else*/ ++ //{ ++ ezxts.events[ezxts.evt_head].pressure = pressure; ++ ezxts.events[ezxts.evt_head].x = x; ++ ezxts.events[ezxts.evt_head].y = y; ++ TS_DPRINTK("ezx_store: x: %d, y :%d, pressure: 0x%x\n", x, y, pressure); ++ //} ++ } ++ else ++ { ++ ezxts.events[ezxts.evt_head].pressure = pressure; ++ ezxts.events[ezxts.evt_head].x = ezxts.events[last_head].x; ++ ezxts.events[ezxts.evt_head].y = ezxts.events[last_head].y; ++ TS_DPRINTK("ezx_store: PEN_UP\n"); ++ } ++ //} ++// do_gettimeofday(&(ezxts.events[ezxts.evt_head].stamp)); ++ ezxts.evt_head = next_head; ++ ++ if (ezxts.evt_head == ezxts.evt_tail) ++ { ++ if ( ++ezxts.evt_tail == TS_NR_EVENTS ) ++ ezxts.evt_tail = 0; ++ } ++ ++ if (ezxts.fasync) ++ kill_fasync(&ezxts.fasync, SIGIO, POLL_IN); ++ wake_up_interruptible(&ezxts.read_wait); ++} ++ ++static struct ts_event ezx_ts_get_onedata(void) ++{ ++ int cur = ezxts.evt_tail; ++ ++ if (++ezxts.evt_tail == TS_NR_EVENTS) ++ ezxts.evt_tail = 0; ++ ++ return ezxts.events[cur]; ++} ++ ++/***************************************************************************** ++ * FUNCTION NAME : ezx_ts_open() ++ * ++ * INPUTS: ++ * ++ * OUTPUTS: pen info from ts event structure ++ * ++ * VALUE RETURNED: none ++ * ++ * DESCRIPTION: ++ * i) Increase this device module used count. ++ * ii) Initialize a buffer for store data read from touch screen interface. ++ * iii) Initialize touch screen interface hardware. ++ * iv) Setup touch screen wait queue. ++***************************************************************************** ++ */ ++static int ezx_ts_open(struct inode *inode, struct file * filp) ++{ ++ struct ezx_ts_info *ts = &ezxts; ++ ++/* ssp_pcap_init(); // change to _start_kernel ++ ssp_pcap_open(); */ ++ ssp_pcap_open(SSP_PCAP_TS_OPEN); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ ++ ezx_ts_init_penEvent(); ++ filp->private_data = ts; ++ ++ ++ TS_DPRINTK("ezx touch screen driver opened\n"); ++ return 0; ++} ++ ++/* Decrease this device module used count. */ ++static int ezx_ts_release(struct inode *inode, struct file *filp) ++{ ++ ezx_ts_init_penEvent(); ++ ezx_ts_fasync(-1, filp, 0); ++ ++ TS_DPRINTK("ezx touch screen driver closed\n"); ++ return 0; ++} ++ ++/***************************************************************************** ++ * FUNCTION NAME : ezx_ts_read ++ * ++ * INPUTS: ++ * ++ * OUTPUTS: pen info from ts event structure ++ * ++ * VALUE RETURNED: none ++ * ++ * DESCRIPTION: ++ * This is used for UI app to call. ++ * If device is opened by nonblock mode then copy available data from the ts event buffer ++ * to user buffer and return the actual read data count, if device is opened by block mode ++ * and no data available then sleep until the required data count be read completed. ++ * ++ * CAUTIONS: ++ * ++ * ++ ***************************************************************************** ++ */ ++static ssize_t ezx_ts_read(struct file* filp, char* buffer, size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ struct ezx_ts_info *ts = filp->private_data; ++ char *ptr = buffer; ++ int err = 0; ++ struct ts_event evt; ++ ++ add_wait_queue(&ts->read_wait, &wait); ++ while (count >= sizeof(struct ts_event)) ++ { ++ err = -ERESTARTSYS; ++ if (signal_pending(current)) ++ break; ++ if ((ts)->evt_head != (ts)->evt_tail) ++ { ++ evt = ezx_ts_get_onedata(); /*evt_tail pos changed in this func*/ ++ err = copy_to_user(ptr, &evt, sizeof(struct ts_event)); ++ ++ if (err) ++ break; ++ //printk("ezx_ts_read: x:%d, y:%d, pressure:0x%x\n", evt.x, evt.y, evt.pressure); ++ ptr += sizeof(struct ts_event); ++ count -= sizeof(struct ts_event); ++ continue; ++ } ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ err = -EAGAIN; ++ if (filp->f_flags & O_NONBLOCK) ++ break; ++ schedule(); ++ } ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&(ts->read_wait), &wait); ++ ++ return ptr == buffer ? err : ptr - buffer; ++ ++} ++ ++/* ++This function is used in nonblock mode to determine whether it can read data from touch screen ++device without blocking. ++Call poll_wait to wait until read operation status changed then return POLLIN (flag of device can be ++read without blocking) | POLLRDNORM (flag of data is available) bit mask if there is readable data ++now. ++*/ ++ ++static unsigned int ezx_ts_poll(struct file* filp, struct poll_table_struct * wait) ++{ ++ struct ezx_ts_info *ts = filp->private_data; ++ int ret = 0; ++ ++ if ( ts != NULL) ++ { ++ TS_DPRINTK("ezx_ts_poll.\n"); ++ poll_wait(filp, &ts->read_wait, wait); ++ if (ts->evt_head != ts->evt_tail) ++ { ++ TS_DPRINTK("ezx_ts_poll: ts->evt_head != ts->evt_tail\n"); ++ ret = POLLIN | POLLRDNORM; ++ } ++ } ++ ++ return ret; ++} ++ ++/* Setup fasync queue for touch screen device. */ ++ ++static int ezx_ts_fasync(int fd, struct file* filp, int mode) ++{ ++ struct ezx_ts_info *ts = filp->private_data; ++ ++ if ( ts != NULL) ++ { ++ TS_DPRINTK("ezx_ts_fasync.\n"); ++ return fasync_helper(fd, filp, mode, &ts->fasync); ++ } ++ else return 0; ++} ++ ++static int ++ezx_ts_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) ++{ ++ int res = 0; ++ ++ TS_DPRINTK("ezx_ts_ioctl: arg is %d\n", arg); ++ switch (cmd) { ++/* ++ case SETTONORMAL: ++ TS_DPRINTK("ezx_ts_ioctl_test: This is SETTONORMAL.\n"); ++ gPenStyle = EZX_PEN_NORMAL; ++ gPenSamplesNum = QT_ONEPEN_SAMPLES_NUM; ++ //gHwrTimer = EZX_TS_HWR_TIMEOUT_MS; ++ gCustomTimer = EZX_TS_CUSTOM_TIMEOUT_MS; ++ break; ++ ++ case SETTOHWR: ++ TS_DPRINTK("ezx_ts_ioctl_test: This is SETTOHWR.\n"); ++ gPenStyle = EZX_PEN_HWR; ++ gPenSamplesNum = HWR_ONEPEN_SAMPLES_NUM; ++ if ( (arg > 0 ) && (arg < 100) ) ++ { ++ gHwrTimer = arg; ++ TS_DPRINTK("ezx_ts_ioctl_test: gHwrTimer is %d.\n", gHwrTimer); ++ } ++ break; ++ ++ case SETTOCUSTOM: ++ TS_DPRINTK("ezx_ts_ioctl_test: This is SETTOCUSTOM.\n"); ++ gPenStyle = EZX_PEN_CUSTOM; ++ gPenSamplesNum = CUSTOM_ONEPEN_SAMPLES_NUM; ++ if ( (arg > 0 ) && (arg < 100) ) ++ { ++ gCustomTimer = arg; ++ TS_DPRINTK("ezx_ts_ioctl_test: gCustomTimer is %d.\n", gCustomTimer); ++ } ++ break; ++ case GETPENSTYLE: ++ TS_DPRINTK("ezx_ts_ioctl_test: This is GETPENSTYLE.\n"); ++ put_user(gPenStyle, (u32*)arg); ++ break; ++ default: ++ res = -EINVAL; ++*/ ++ } ++ ++ return res; ++} ++ ++/***************************************************************************** ++ * FUNCTION NAME : ezx_ts_touch_interrupt ++ * ++ * INPUTS: ++ * ++ * ++ * OUTPUTS: ++ * ++ * ++ * VALUE RETURNED: ++ * ++ * ++ * DESCRIPTION: ++ * This is touch screen touch interrupt service routine called by PCAP module when touch screen ++ * interrupt happened. First eliminate shake signal to get stable touch screen press information. ++ * Then write instruction to PCAP register to read ADC conversion value of pressed spot x,y coordinate ++ * and return. ++ * ++ * CAUTIONS: ++ * ++ * ++ * ++ ***************************************************************************** ++ */ ++void ezx_ts_touch_interrupt(int irq, void* dev_id, struct pt_regs *regs) ++{ ++ TS_DPRINTK("ezx_ts_touch_irq happened.\n"); ++ ezx_ts_shake_samples_count = 0; ++ //TS_DPRINTK("ezx_ts_touch_irq excuted.\n"); ++ ezx_ts_check_pen_samples(); ++ ezx_ts_pen_touch_handler(); ++ ++} ++ ++/***************************************************************************** ++ * FUNCTION NAME : ezx_ts_dataReadok_interrupt ++ * ++ * INPUTS: call PCAP API to read x,y ++ * ++ * OUTPUTS: Store the pen info to ts event structure ++ * ++ * VALUE RETURNED: none ++ * ++ * DESCRIPTION: ++ * This is called by PCAP module to deal with the touch screen press raw information read from ADC ++ * when ADC data conversion finished. It performs write the data to ts event buffer for user to ++ * read out. ++ * ++ * CAUTIONS: Consider pen shake ++ * ++ * ++ ***************************************************************************** ++ */ ++void ezx_ts_dataReadok_interrupt(int irq, void* dev_id, struct pt_regs *regs) ++{ ++ static u16 pressure; ++ u16 x; ++ u16 y; ++ U16 tempx,tempy; ++ ++ if (SSP_PCAP_TSI_get_XY_value(&x, &y) != SSP_PCAP_SUCCESS) ++ { ++ return; ++ } ++ /* convert x,y???? */ ++ // TS_DPRINTK( "ezx_ts_get_XY_value: x:%d, y:%d\n",x, y); ++ /* TS_DPRINTK( "\nezx_ts before convert: x:%d, y:%d\n",x, y);*/ ++ ++ if ( ezx_ts_read_state == PRESSURE) ++ { ++ if (( y >= TS_EDGE_MAX_LIMIT ) || (y <= TS_EDGE_MIN_LIMIT)) ++ { ++ TS_DPRINTK("ezx_ts_datareadok_irq: PEN_UP.\n"); ++ pressure = PEN_UP; ++ ezxts.cur_pressure = PEN_UP; ++ ++ /*ezx_ts_check_pen_samples();*/ ++ if ( getPenUp == 0 ) ++ { ++ ezx_ts_evt_add( pressure, 0, 0); ++ } ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ return; ++ } ++ else ++ { ++ TS_DPRINTK("ezx_ts_datareadok_irq: PEN_DOWN.\n"); ++ getPenUp = 0; ++ pressure = PEN_DOWN; ++ ezxts.cur_pressure = PEN_DOWN; ++ tspenSampleCount = 0; ++ ezxts.x_pre = 0; ++ ezxts.y_pre = 0; ++ bFirstPen = 1 ; ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ ezx_ts_read_state = COORDINATE; ++ ++ //TS_DPRINTK("ezx_ts_datareadok_irq: Begin read XY.\n"); ++ return; ++ } ++ } ++ else if ( ezx_ts_read_state == COORDINATE) ++ {/* ++ u8 count; ++ ++ count = 0; ++ while ( (( x <= TS_EDGE_MIN_LIMIT)||( x >= TS_EDGE_MAX_LIMIT) || ++ ( y <= TS_EDGE_MIN_LIMIT)||( y >= TS_EDGE_MAX_LIMIT)) ++ && (count++ < 15) ) ++ { ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ } ++ */ ++ if ( ( x <= TS_EDGE_MIN_LIMIT)||( x >= TS_EDGE_MAX_LIMIT) || ++ ( y <= TS_EDGE_MIN_LIMIT)||( y >= TS_EDGE_MAX_LIMIT) ) ++ { /* regard it as PEN_UP */ ++ pressure = PEN_UP; ++ ezxts.cur_pressure = PEN_UP; ++ x = 0; ++ y = 0; ++ tspenSampleCount = 0; ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ /*del_timer(&ezx_ts_read_timer);*/ ++ ezx_ts_check_pen_samples(); ++ ezx_ts_evt_add( pressure, 0, 0); ++ /* SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM);*/ ++ ezx_ts_read_state = PRESSURE; ++ getPenUp = 1; ++ TS_DPRINTK( "ezx_ts Invalid x,y position: PEN_UP?\n"); ++ return; ++ } ++ getPenUp = 0; ++ penSampleCount++; ++ //TS_DPRINTK("ezx_ts_datareadok_irq: Begin store XY %d.\n", penSampleCount); ++ ++ if ( gPenStyle == EZX_PEN_CUSTOM ) ++ { ++ if ( ((ezxts.x_pre == 0) && (ezxts.y_pre == 0)) ++ || ( (ezxts.x_pre != 0) && (ezxts.y_pre != 0) ++ &&(!((abs(ezxts.x_pre - x) > X_DIFF) || (abs(ezxts.y_pre - y) > Y_DIFF))) ) ++ ) ++ { ++ //TS_DPRINTK("ezx_ts_datareadok_irq: diff <= XY_DIFF.\n"); ++ ++ ezxts.x_pre = x; ++ ezxts.y_pre = y; ++ ++ TS_DPRINTK("ezx_ts_datareadok_irq:x_pre=%d,y_pre=%d\n", ezxts.x_pre, ezxts.y_pre); ++ ezxts.x_cur = x; ++ ezxts.y_cur = y; ++ ezx_ts_evt_add(pressure, ezxts.x_cur, ezxts.y_cur); ++ //printk("ezx_ts_datareadok_irq_custom add pressure0x%x,x_cur%d,y_cur%d\n",pressure,ezxts.x_cur,ezxts.y_cur); ++ ezx_ts_custom_timer_start(); ++ } ++ else ++ { ++ //TS_DPRINTK("ezx_ts_datareadok_irq: DIFF > XY_DIFF\n"); ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ TS_DPRINTK("ezx_ts_datareadok_irq:x_pre=%d,y_pre=%d, x=%d,y=%d\n", ezxts.x_pre, ezxts.y_pre,x,y); ++ } ++ ++ ++ /* ++ if ( ezx_ts_shake_samples_count < EZX_TS_SHAKE_SAMPLES ) ++ { ++ ezx_ts_shake_samples[ezx_ts_shake_samples_count].x = x; ++ ezx_ts_shake_samples[ezx_ts_shake_samples_count].y = y; ++ ezx_ts_shake_samples[ezx_ts_shake_samples_count++].pressure = PEN_DOWN; ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ TS_DPRINTK("ezx_ts_read_shake_samples%d:x=%d,y=%d\n", ezx_ts_shake_samples_count,x,y); ++ } ++ if (ezx_ts_shake_samples_count >= EZX_TS_SHAKE_SAMPLES) ++ { ++ if ( (abs(ezx_ts_shake_samples[0].x - ezx_ts_shake_samples[1].x) > X_DIFF) || ++ (abs(ezx_ts_shake_samples[0].y - ezx_ts_shake_samples[1].y) > Y_DIFF) || ++ (abs(ezx_ts_shake_samples[1].x - ezx_ts_shake_samples[2].x) > X_DIFF) || ++ (abs(ezx_ts_shake_samples[1].y - ezx_ts_shake_samples[2].y) > Y_DIFF) ++ ) ++ { ++ // throw these data and re-read ++ ezx_ts_shake_samples_count = 0; ++ } ++ else //save to ts_event queue ++ { ++ ezxts.x_pre = ezxts.x_cur; ++ ezxts.y_pre = ezxts.y_cur; ++ TS_DPRINTK("ezx_ts_datareadok_irq:x_pre=%d,y_pre=%d\n", ezxts.x_pre, ezxts.y_pre); ++ ezxts.x_cur = (ezx_ts_shake_samples[0].x + ezx_ts_shake_samples[1].x + ezx_ts_shake_samples[2].x) / 3; ++ ezxts.y_cur = (ezx_ts_shake_samples[0].y + ezx_ts_shake_samples[1].y + ezx_ts_shake_samples[2].y) / 3;; ++ ezx_ts_shake_samples_count = 0; ++ ezx_ts_evt_add(pressure, ezxts.x_cur, ezxts.y_cur); ++ } ++ ezx_ts_custom_timer_start(); ++ } ++ */ ++ } ++ else ++ { ++ /* ezxts.x_pre and ezxts.y_pre store the last position */ ++ tspenSampleCount ++; ++ if(1 == tspenSampleCount) ++ { ++ ezxts.x_cur = x; ++ ezxts.y_cur = y; ++ if( 0 == bSetPenupTimer ) ++ { ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ } ++ } ++ else if (2 == tspenSampleCount) ++ { ++ tspenSampleCount = 0; ++ ++ tempx = (ezxts.x_cur > x? ezxts.x_cur - x:x - ezxts.x_cur); ++ tempy = (ezxts.y_cur > y? ezxts.y_cur - y:y - ezxts.y_cur); ++ if(tempx <= X_DIFF && tempy <= Y_DIFF ) ++ { ++ x = (x+ezxts.x_cur)/2; ++ y = (y+ezxts.y_cur)/2; ++ if( 1 == bFirstPen) ++ { ++ bFirstPen = 0; ++ ezxts.x_pre = x; ++ ezxts.y_pre = y; ++ } ++ tempx = ( ezxts.x_pre > x? ezxts.x_pre -x:x - ezxts.x_pre); ++ tempy = ( ezxts.y_pre > y? ezxts.y_pre -y:y - ezxts.y_pre); ++ if(tempx <= X_DIFF && tempy <= Y_DIFF ) ++ { ++ tsDiscardDataCount = 0; ++ if(tempx > MIN_X_HOLD || tempy > MIN_Y_HOLD) ++ { ++ ezxts.x_pre = x; ++ ezxts.y_pre = y; ++ } ++ ezx_ts_evt_add(pressure, ezxts.x_pre, ezxts.y_pre); ++ if ( bSetPenupTimer == 0 ) ++ { ++ ezx_ts_set_timer(&ezx_ts_penup_timer, ezx_ts_penup_timeout, ++ EZX_TS_PENSAMPLE_TIMEOUT_MS); ++ TS_DPRINTK("ezx_ts_datareadok_irq: set timer pen sample\n"); ++ bSetPenupTimer = 1; ++ } ++ } ++ else ++ { ++ ++ tsDiscardDataCount ++; ++ if(tsDiscardDataCount > SAMPLE_COUNT_NOT_JUMPER) ++ { ++ tsDiscardDataCount = 0; ++ ezxts.x_pre = x; ++ ezxts.y_pre = y; ++ ezx_ts_evt_add(pressure, ezxts.x_pre, ezxts.y_pre); ++ if ( bSetPenupTimer == 0 ) ++ { ++ ezx_ts_set_timer(&ezx_ts_penup_timer, ezx_ts_penup_timeout, ++ EZX_TS_PENSAMPLE_TIMEOUT_MS); ++ TS_DPRINTK("ezx_ts_datareadok_irq: set timer pen sample\n"); ++ bSetPenupTimer = 1; ++ } ++ } ++ else if( 0 == bSetPenupTimer ) ++ { ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ } ++ } ++ } ++ else ++ { ++ if( 0 == bSetPenupTimer ) ++ { ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ } ++ } ++ } ++ else /* discard the case */ ++ { ++ tspenSampleCount = 0; ++ if( 0 == bSetPenupTimer ) ++ { ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ } ++ } ++ } ++ /*if (penSampleCount >= gPenSamplesNum) ++ { ++ penSampleCount = 0; ++ }*/ ++ //TS_DPRINTK("ezx_ts_datareadok_irq: read XY finished.\n"); ++ } ++ ++} ++ ++ ++static struct file_operations ezx_ts_fops = { ++ .owner = THIS_MODULE, ++ .read = ezx_ts_read, ++ .poll = ezx_ts_poll, ++ .open = ezx_ts_open, ++ .release = ezx_ts_release, ++ .fasync = ezx_ts_fasync, ++ .ioctl = ezx_ts_ioctl, ++}; ++ ++/* ++ * miscdevice structure for misc driver registration. ++ */ ++static struct miscdevice ezx_ts_dev = ++{ ++ .minor = EZX_TS_MINOR_ID, ++ .name = "ezx_ts", ++ .fops = &ezx_ts_fops, ++}; ++ ++/*Register touch screen device in misc devices.*/ ++static int ezx_ts_init(void) ++{ ++ int ret; ++ ++ init_waitqueue_head(&ezxts.read_wait); ++ ret = misc_register(&ezx_ts_dev); ++ ++ if (ret<0) ++ { ++ printk("ezx_ts_dev: failed to registering the device\n"); ++ } ++ ezx_ts_custom_setup_timer(); ++ ++ TS_DPRINTK("ezx_ts_init done.\n"); ++ return ret; ++} ++ ++/*Unregister touch screen device.*/ ++static void ezx_ts_exit(void) ++{ ++ ++ if (bSetPenupTimer) ++ { ++ del_timer(&ezx_ts_penup_timer); ++ bSetPenupTimer = 0; ++ } ++ ++ ezx_ts_custom_timer_stop(); ++ ++ misc_deregister(&ezx_ts_dev); ++ ++ TS_DPRINTK("ezx touch screen driver removed\n"); ++} ++ ++module_init(ezx_ts_init); ++module_exit(ezx_ts_exit); ++ ++MODULE_DESCRIPTION("ezx touchscreen driver"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ezx-ts.h linux-2.6.16/drivers/misc/ezx/ezx-ts.h +--- linux-2.6.16.orig/drivers/misc/ezx/ezx-ts.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ezx-ts.h 2006-06-03 11:14:56.308329088 +0200 +@@ -0,0 +1,22 @@ ++/*
++ * linux/drivers/char/ezx-ts.c
++ *
++ * Copyright (C) 2002 Lili Jiang, All Rights Reserved.
++ *
++ *
++ * June, 2002 Lili Jiang, create
++ */
++
++#ifndef _EZXTS_H
++#define _EZXTS_H
++
++#define EZX_TS_MINOR_ID 14
++
++#define PEN_UP 0
++#define PEN_DOWN 0xffff
++
++/* extern functio nfor PCAP */
++void ezx_ts_touch_interrupt(int irq, void* dev_id, struct pt_regs *regs);
++void ezx_ts_dataReadok_interrupt(int irq, void* dev_id, struct pt_regs *regs);
++
++#endif //_EZXTS_H
+diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/fmradio.c linux-2.6.16/drivers/misc/ezx/fmradio.c +--- linux-2.6.16.orig/drivers/misc/ezx/fmradio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/fmradio.c 2006-06-03 11:14:56.308329088 +0200 +@@ -0,0 +1,249 @@ ++/* ++ * linux/drivers/i2c/fmradio.c ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Jay Jia ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola 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 <linux/tty.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/bitops.h> ++#include <linux/param.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <linux/pm.h> ++#include <linux/apm_bios.h> ++#include <asm/arch-pxa/irqs.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/timer.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/i2c.h> ++#include <linux/videodev.h> ++#include <linux/kdev_t.h> ++#include <asm/semaphore.h> ++ ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++ ++#include "../../../sound/oss/ezx-common.h" ++#include "fmradio.h" ++ ++#define I2C_FMRADIO 0x81 ++ ++static int fmradio_adapter_attach(struct i2c_adapter *adap); ++static int fmradio_detach(struct i2c_client *client); ++static int fmradio_client_register(struct i2c_client *client); ++static int fmradio_client_unregister(struct i2c_client *client); ++/* ----------------------------------------------------------------------- */ ++static struct i2c_driver driver = { ++ .owner = THIS_MODULE, ++ .name = "fmradio driver", ++ .id = I2C_FMRADIO, ++ //.flags = I2C_DF_DUMMY, ++ .attach_adapter = fmradio_adapter_attach, ++ .detach_client = fmradio_detach, ++}; ++ ++static struct i2c_adapter fmradio_adapter = { ++ .owner = THIS_MODULE, ++ .name = "fmradio adapter", ++ .id = I2C_FMRADIO, ++ .client_register = fmradio_client_register, ++ .client_unregister = fmradio_client_unregister, ++}; ++ ++static struct i2c_client client_template = { ++ .name = "(unset)", ++ .adapter = &fmradio_adapter, ++}; ++ ++struct i2c_client *fmradio_client; ++ ++static int fmradio_open(struct inode *inode, struct file *file) ++{ ++ if( audioonflag & (DSP16_DEVICE|PHONE_DEVICE) ){ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 open FM EBUSY because 0x%X device is using the sound hardware.\n",audioonflag ); ++#endif ++ return -EBUSY; ++ } ++ ++ ++ poweron_mixer(FM_DEVICE); ++ //MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int fmradio_close(struct inode * inode, struct file *file) ++{ ++ unsigned int flags; ++ unsigned char standby[5] = {0x2a, 0x48, 0xa1, 0xdf, 0x40}; ++ ++ //MOD_DEC_USE_COUNT; ++ //e680_boomer_path_tmp_mono_lineout (); //mute boomer ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ //write standby command ++ i2c_master_send (fmradio_client, standby, 5); ++ local_irq_restore(flags); ++ shutdown_mixer(FM_DEVICE); ++ ++ return 0; ++} ++ ++ ++static int fmradio_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ return mixer_ioctl(inode, file, cmd, arg); ++} ++ ++static ssize_t fmradio_read(struct file *file, char *buf, size_t count, loff_t *ptr) ++{ ++ char *tmp; ++ int ret; ++ unsigned int flags; ++ ++ /* copy user space data to kernel space. */ ++ tmp = kmalloc(count,GFP_KERNEL); ++ if (tmp==NULL) ++ return -ENOMEM; ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_recv(fmradio_client,tmp,count); ++ local_irq_restore(flags); ++ if (ret >= 0) ++ copy_to_user(buf,tmp,count); ++ kfree(tmp); ++ return ret; ++} ++static ssize_t fmradio_write(struct file *file, const char *buf, size_t count, loff_t *ptr) ++{ ++ int ret; ++ char *tmp; ++// char data[4]={0x18,0x7d,0xbd,0xcd}; ++// char freq[5]={0x2e,0x56,0x41,0x11,0x40}; ++// unsigned char s[5]={0, 0, 0, 0, 0}; ++ ++// mixer_write(data,4); ++// i2c_master_send(fmradio_client,freq,5); ++// printk("fmradio test code\n"); ++// mdelay(300); ++// i2c_master_recv(fmradio_client, s, 5); ++// printk("s0=%02x s1=%02x s2=%02x s3=%02x s4=%02x \n",s[0],s[1],s[2],s[3],s[4]); ++ ++ unsigned int flags; ++ /* copy user space data to kernel space. */ ++ tmp = kmalloc(count,GFP_KERNEL); ++ if (tmp==NULL) ++ return -ENOMEM; ++ if (copy_from_user(tmp,buf,count)) { ++ kfree(tmp); ++ return -EFAULT; ++ } ++ local_irq_save(flags); ++ enable_irq(IRQ_I2C); ++ ret = i2c_master_send(fmradio_client,tmp,count); ++ local_irq_restore(flags); ++ kfree(tmp); ++ return ret; ++} ++ ++static int fmradio_client_register(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++ ++static int fmradio_client_unregister(struct i2c_client *client) ++{ ++ ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++static struct file_operations fmradio_fops = { ++ read: fmradio_read, ++ write: fmradio_write, ++ ioctl: fmradio_ioctl, ++ open: fmradio_open, ++ release: fmradio_close, ++}; ++ ++static struct miscdevice fmradio_misc_device = { ++ FMRADIO_MINOR, ++ FMRADIO_NAME, ++ &fmradio_fops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int fmradio_adapter_attach(struct i2c_adapter *adap) ++{ ++ if(! (fmradio_client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) ++ return -ENOMEM; ++ memcpy(fmradio_client,&client_template,sizeof(struct i2c_client)); ++ fmradio_client->adapter = adap; ++ ++ fmradio_client->addr = 0x60; ++ ++ printk("adapter %s\n",adap->name); ++ i2c_attach_client(fmradio_client); ++ ++ return 0; ++} ++ ++static int fmradio_detach(struct i2c_client *client) ++{ ++ i2c_detach_client(fmradio_client); ++ return 0; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int fmradio_init_module(void) ++{ ++ int res; ++ ++ res = i2c_add_driver(&driver); ++ if( res < 0 ) ++ { ++ printk("error in add fmradio i2c driver\n"); ++ return res; ++ } ++ ++ if (misc_register (&fmradio_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register fmradio driver\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static void fmradio_cleanup_module(void) ++{ ++ i2c_del_driver(&driver); ++ misc_deregister(&fmradio_misc_device); ++} ++ ++module_init(fmradio_init_module); ++module_exit(fmradio_cleanup_module); ++MODULE_AUTHOR("Jay Jia"); ++MODULE_LICENSE("GPL"); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/fmradio.h linux-2.6.16/drivers/misc/ezx/fmradio.h +--- linux-2.6.16.orig/drivers/misc/ezx/fmradio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/fmradio.h 2006-06-03 11:14:56.309328936 +0200 +@@ -0,0 +1,7 @@ ++#ifndef __FMRADIO_H ++#define __FMRADIO_H ++ ++#define FMRADIO_NAME "fmradio" ++#define FMRADIO_MINOR 198 ++ ++#endif +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/Kconfig linux-2.6.16/drivers/misc/ezx/Kconfig +--- linux-2.6.16.orig/drivers/misc/ezx/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/Kconfig 2006-06-03 11:14:56.302330000 +0200 +@@ -0,0 +1,20 @@ ++# ++# Misc strange devices ++# ++ ++menu "Motorola EZX devices" ++ ++config KEYPAD_A780 ++ tristate "Device driver for Motorola A780 keypad" ++ ++config KEYPAD_E680 ++ tristate "Device driver for Motorola E680 keypad" ++ ++config KEYLIGHT_A780 ++ tristate "Device driver for Motorola A780 keylight" ++ ++config FMRADIO_E680 ++ tristate "Device driver for Motorola E680 FM Radio" ++ ++endmenu ++ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/keylight.c linux-2.6.16/drivers/misc/ezx/keylight.c +--- linux-2.6.16.orig/drivers/misc/ezx/keylight.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/keylight.c 2006-06-03 11:14:56.309328936 +0200 +@@ -0,0 +1,236 @@ ++/* ++ * linux/drivers/misc/keylight.c --- key backlight driver on ezx ++ * ++ * Support for the Motorola Ezx A780 Development Platform. ++ * ++ * Author: Jay Jia ++ * Created: Feb 16, 2004 ++ * Copyright: Motorola 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 <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <linux/init.h> ++#include <linux/miscdevice.h> ++#include <linux/interrupt.h> ++#include <linux/pm.h> ++#include "keylight.h" ++#include "ssp_pcap.h" ++#include <linux/delay.h> ++ ++static int keylight_open_cnt = 0; ++static int main_current_brightness = 0xf; ++static int aux_current_brightness = 0x1f; ++ ++MODULE_LICENSE("GPL"); ++ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++#endif ++ ++static int keylight_open(struct inode *inode,struct file *file) ++{ ++ keylight_open_cnt++; ++ ++ return 0; ++} ++ ++static int keylight_close(struct inode *inode,struct file *file) ++{ ++ keylight_open_cnt--; ++ ++ if ( keylight_open_cnt == 0 ) ++ { ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4); ++ } ++ ++ return 0; ++} ++ ++static void keylight_main_turn_off(void) ++{ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4); ++} ++ ++static void keylight_aux_turn_off(void) ++{ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4); ++} ++ ++static void keylight_main_turn_on(void) ++{ ++ int i,count; ++ ++ for( i=0; i<5; i++) ++ { ++ count = 1<<i; ++ switch ( main_current_brightness & count ) ++ { ++ case 1: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0); ++ break; ++ case 2: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1); ++ break; ++ case 4: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2); ++ break; ++ case 8: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3); ++ break; ++ case 16: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++static void keylight_aux_turn_on(void) ++{ ++ int i,count; ++ ++ for( i=0; i<5; i++) ++ { ++ count = 1<<i; ++ switch ( aux_current_brightness & count ) ++ { ++ case 1: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0); ++ break; ++ case 2: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1); ++ break; ++ case 4: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2); ++ break; ++ case 8: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3); ++ break; ++ case 16: ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++static int keylight_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg) ++{ ++ int ret = 0; ++ ++ switch( cmd ) ++ { ++ case KEYLIGHT_MAIN_ON: ++ keylight_main_turn_on(); ++ break; ++ case KEYLIGHT_MAIN_OFF: ++ keylight_main_turn_off(); ++ break; ++ case KEYLIGHT_MAIN_SETTING: ++ main_current_brightness = arg & 0x1f; ++ break; ++ case KEYLIGHT_AUX_ON: ++ keylight_aux_turn_on(); ++ break; ++ case KEYLIGHT_AUX_OFF: ++ keylight_aux_turn_off(); ++ break; ++ case KEYLIGHT_AUX_SETTING: ++ ret = -EINVAL; ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++static int ezx_keylight_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ break; ++ case PM_RESUME: ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++ ++static struct file_operations keylight_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = keylight_ioctl, ++ .open = keylight_open, ++ .release = keylight_close, ++}; ++ ++static struct miscdevice keylight_dev = { ++ KEYLIGHT_MINOR, ++ "keylight", ++ &keylight_fops, ++}; ++ ++int init_keylight(void) ++{ ++ int ret; ++ ++ ret = misc_register(&keylight_dev); ++ if( ret < 0 ){ ++ printk("Sorry,registering the keylight device failed.\n"); ++ return ret; ++ } ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, ezx_keylight_pm_callback); ++#endif ++#if 0 ++ for(ret=0;ret<32;ret++) ++ { ++ aux_current_brightness=ret; ++ keylight_aux_turn_on(); ++ main_current_brightness=ret; ++ keylight_main_turn_on(); ++ mdelay(2000); ++ } ++#endif ++ return 0; ++} ++void clean_keylight(void) ++{ ++ misc_deregister(&keylight_dev); ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++} ++ ++module_init(init_keylight); ++module_exit(clean_keylight); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/keylight.h linux-2.6.16/drivers/misc/ezx/keylight.h +--- linux-2.6.16.orig/drivers/misc/ezx/keylight.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/keylight.h 2006-06-03 11:14:56.309328936 +0200 +@@ -0,0 +1,20 @@ ++#ifndef KEYLIGHT_H ++#define KEYLIGHT_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define KEYLIGHT_MINOR 168 ++#define KEYLIGHT_MAIN_ON 0xf0 ++#define KEYLIGHT_AUX_ON 0xf1 ++#define KEYLIGHT_MAIN_OFF 0xf2 ++#define KEYLIGHT_AUX_OFF 0xf3 ++#define KEYLIGHT_MAIN_SETTING 0xf4 ++#define KEYLIGHT_AUX_SETTING 0xf5 ++ ++#ifdef __cplusplus ++} ++#endif ++#endif ++ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/keypad.c linux-2.6.16/drivers/misc/ezx/keypad.c +--- linux-2.6.16.orig/drivers/misc/ezx/keypad.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/keypad.c 2006-06-03 11:14:56.853246248 +0200 +@@ -0,0 +1,1499 @@ ++/* ++ * linux/drivers/char/keypad.c ++ * ++ * (c) Copyright Motorola 2003, All rights reserved. ++ */ ++ ++/* ++ * This driver is for three devices: /dev/keypad, /dev/keypadB and ++ * /dev/keypadI. ++ * /dev/keypad would be used for reading the key event buffer. ++ * It can be opened by one process at a time. ++ * /dev/keypadB would be used for ioctl(KEYPAD_IOC_GETBITMAP). ++ * It can be opened by one process at a time. ++ * /dev/keypadI would be used for ioctl(KEYPAD_IOC_INSERT_EVENT). ++ * It can be opened any number of times simultaneously. ++ * ++ * The bulverde specification is ambiguous about when interrupts happen ++ * for released keys. We were told by Intel that we won't ++ * get interrupts for released keys except in the case when multiple ++ * keys were down and they've all been released. So we implemented ++ * a timer to poll for changes in key states. ++ * ++ * The E680 P2 hardware gives us interrupts when any key is released, ++ * whether it was the only key down or not, and whether it's the last ++ * of multiple keys to be released or not. We don't know whether this ++ * behavior will continue in future hardware releases, so the release ++ * timer is still in the code, #ifdef'd with USE_RELEASE_TIMER. On the ++ * P2 hardware, the code works with or without USE_RELEASE_TIMER defined. ++ * If the release interrupts are always going to happen, we can remove ++ * the #ifdef'd code. ++ * ++ * With the P2 hardware, the power key bit in the KPDK register is always ++ * on. We don't know if this is correct behavior or not, but in any case ++ * it certainly causes trouble to have that key autorepeating indefinitely, ++ * or to be checking indefinitely for the key to be released (if we're doing ++ * release polling). ++ * ++ * For now, any_keys_down() returns 0 if the power key is the only one down. ++ * . At interrupt time, if the power key is the only one down we don't ++ * set the autorepeat timer or release timer. ++ * . When the release timer goes off, if the power key is the only one ++ * still down we don't set the timer again. ++ * . When the autorepeat timer goes off, if the power key is the only ++ * one down we don't generate any events. ++ * In autorepeat_timer_went_off, if there are non-power keys down, while we're ++ * looking through the whole bitmap of keys down we ignore the power key. ++ */ ++ ++#include <linux/tty.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/bitops.h> ++#include <linux/param.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <linux/pm.h> ++#include <linux/apm_bios.h> ++#include "keypad.h" ++#include <asm/arch/irqs.h> ++#include <asm/arch/pxa-regs.h> ++ ++#include <asm/arch/ezx.h> ++ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++static struct pm_dev *keypadI_pm_dev; ++static int kpc_res,kpkdi_res; ++#endif ++static int GPIO_TC_MM_STATE = 1; ++/* ++ * This is the number of microseconds we wait before checking to see if any ++ * keys have been released. ++ */ ++#define RDELAY 200 ++ ++#define KEYBUF_EMPTY() (keybuf_start == keybuf_end) ++#define KEYBUF_FULL() ( ((keybuf_end+1)%KEYBUF_SIZE) == keybuf_start) ++#define KEYBUF_INC(x) ((x) = (((x)+1) % KEYBUF_SIZE)) ++ ++static int keypad_open (struct inode *, struct file *); ++static int keypad_close (struct inode *, struct file *); ++static int keypad_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++static unsigned int keypad_poll (struct file *, poll_table *); ++static ssize_t keypad_read (struct file *, char *, size_t, loff_t *); ++ ++static int keypadB_open (struct inode *, struct file *); ++static int keypadB_close (struct inode *, struct file *); ++static int keypadB_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++static unsigned int keypadB_poll (struct file *, poll_table *); ++ ++static int keypadI_open(struct inode *, struct file *); ++static int keypadI_close(struct inode *, struct file *); ++static int keypadI_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++ ++static irqreturn_t kp_interrupt (int, void *, struct pt_regs *); ++#ifdef USE_RELEASE_TIMER ++static void release_timer_went_off (unsigned long); ++static void do_scan(void); ++#endif ++static void autorepeat_timer_went_off (unsigned long); ++ ++static int add_to_keybuf (unsigned short); ++static int add_events (unsigned long *, unsigned long *); ++static int insert_event (unsigned short); ++static unsigned short get_from_keybuf (void); ++static void scan_to_bitmap ++ (unsigned long, unsigned long, unsigned long, unsigned long *); ++static inline void set_bitmap_to_zero(unsigned long b[]); ++static inline void copy_bitmap(unsigned long dest[], unsigned long source[]); ++static inline void turn_on_bit(unsigned long map[], int); ++static inline void turn_off_bit(unsigned long map[], int); ++static inline int any_keys_down (unsigned long *); ++ ++/* ++ * keybuf is a circular buffer to hold keypad events. ++ * keybuf_start is the index of the first event. ++ * keybuf_end is one more than the index of the last event. ++ * The buffer is empty when keybuf_start == keybuf_end. ++ * We only use KEYBUF_SIZE-1 entries in the buffer so we can tell ++ * when it's full without needing another variable to tell us. ++ * The buffer is full when (keybuf_end+1)%KEYBUF_SIZE == keybuf_start. ++ */ ++static unsigned short keybuf[KEYBUF_SIZE]; ++static int keybuf_start = 0; ++static int keybuf_end = 0; ++ ++static DECLARE_WAIT_QUEUE_HEAD(keypad_wait); ++static spinlock_t keypad_lock = SPIN_LOCK_UNLOCKED; ++ ++static int reading_opens = 0; ++static int bitmap_opens = 0; ++ ++/* previous bitmap of keys down */ ++static unsigned long oldkeybitmap[NUM_WORDS_IN_BITMAP]; ++/* current bitmap of keys down */ ++static unsigned long keybitmap[NUM_WORDS_IN_BITMAP]; ++/* last bitmap read by ioctl */ ++static unsigned long lastioctlbitmap[NUM_WORDS_IN_BITMAP]; ++ ++static unsigned long kpas = 0; /* last value of kpas */ ++static unsigned long kpasmkp0 = 0; /* last value of kpasmkp0 */ ++static unsigned long kpasmkp1 = 0; /* last value of kpasmkp1 */ ++static unsigned long kpasmkp2 = 0; /* last value of kpasamkp2*/ ++static unsigned long kpdk = 0; /* last value of kpdk */ ++ ++#ifdef USE_RELEASE_TIMER ++static struct timer_list key_release_timer; ++static int key_release_interval = RDELAY * HZ/1000; ++#endif ++ ++static int do_autorepeat = 1; ++static long jiffies_to_first_repeat = 30; ++static long jiffies_to_next_repeat = 30; ++static struct timer_list autorepeat_timer; ++ ++extern int lockscreen_flag; ++ ++static int ++keypad_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypad_open\n"); ++#endif ++ spin_lock(keypad_lock); ++ if (reading_opens > 0) ++ { ++ spin_unlock(keypad_lock); ++ return -EBUSY; ++ } ++ reading_opens++; ++ spin_unlock(keypad_lock); ++ ++ return 0; ++} ++ ++static int ++keypadB_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypadB_open\n"); ++#endif ++ spin_lock(keypad_lock); ++ if (bitmap_opens > 0) ++ { ++ spin_unlock(keypad_lock); ++ return -EBUSY; ++ } ++ bitmap_opens++; ++ /* ++ * poll returns when lastioctlbitmap is different from keybitmap. ++ * we set lastioctlbitmap to keybitmap here so that a poll right ++ * after an open returns when the bitmap is different from when ++ * the open was done, not when the bitmap is different from the ++ * last time some other process read it ++ */ ++ copy_bitmap(lastioctlbitmap, keybitmap); ++ spin_unlock(keypad_lock); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++#ifdef CONFIG_PM ++static int keypadI_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ break; ++ case PM_RESUME: ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ if(GPIO_TC_MM_STATE == 1) ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ else ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++#endif ++ ++static int ++keypadI_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypadI_open\n"); ++#endif ++#if defined(CONFIG_KEYPAD_E680) || defined (CONFIG_KEYPAD_E680_MODULE) ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ ++ return 0; ++} ++ ++static int ++keypad_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_close\n"); ++#endif ++ /* ++ * this decrement of reading_opens doesn't have to be protected because ++ * it can only be executed to close the single open of /dev/keypad ++ */ ++ reading_opens--; ++ return 0; ++} ++ ++static int ++keypadB_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadB_close\n"); ++#endif ++ /* ++ * this decrement of bitmap_opens doesn't have to be protected because ++ * it can only be executed to close the single open of /dev/keypadB ++ */ ++ bitmap_opens--; ++ return 0; ++} ++ ++static int ++keypadI_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadI_close\n"); ++#endif ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ ++ return 0; ++} ++ ++/** ++ * Add the specified event to the key buffer. ++ * This should be called with keypad_lock locked. ++ */ ++static int ++add_to_keybuf (unsigned short event) ++{ ++ if (KEYBUF_FULL()) ++ { ++ return -ENOMEM; ++ } ++ ++ keybuf[keybuf_end] = event; ++ KEYBUF_INC (keybuf_end); ++ ++#ifdef CONFIG_APM ++ apm_queue_event(KRNL_KEYPAD, NULL); ++#endif ++ //printk("add keypad event = %x\n", event); ++ return 0; ++} ++ ++/* ++ * code[c*8+r] is the key code for the key that's down when there's a 1 ++ * in column c, row r of the scan registers. ++ */ ++ ++#if defined(CONFIG_KEYPAD_V700) || defined (CONFIG_KEYPAD_V700_MODULE) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_RIGHT, ++ KEYPAD_POUND, KEYPAD_0, KEYPAD_9, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_2, KEYPAD_4, KEYPAD_6, KEYPAD_8, ++ KEYPAD_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_MENU, KEYPAD_1, KEYPAD_3, KEYPAD_5, ++ KEYPAD_STAR, KEYPAD_VOLUP, KEYPAD_VOLDOWN, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, ++ KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, KEYPAD_NONE ++}; ++ ++/* end CONFIG_KEYPAD_V700 */ ++#elif defined(CONFIG_E680_P4A) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_RIGHT, KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_GAME_L, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_A, KEYPAD_B, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++}; ++ ++/* end CONFIG_E680_P4A */ ++#elif defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_RIGHT, KEYPAD_LEFT, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_NONE, KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ ++}; ++/*end CONFIG_KEYPAD_E680 */ ++#elif defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_OK, KEYPAD_1, KEYPAD_4, KEYPAD_7, ++ KEYPAD_STAR, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_MENU, KEYPAD_2, KEYPAD_5, KEYPAD_8, ++ KEYPAD_0, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_CANCEL, KEYPAD_3, KEYPAD_6, KEYPAD_9, ++ KEYPAD_POUND, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_JOG_UP, KEYPAD_JOG_MIDDLE, KEYPAD_JOG_DOWN, KEYPAD_LEFT, ++ KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 4 */ ++ KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_PTT, KEYPAD_UP, ++ KEYPAD_RIGHT, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++}; ++#endif ++ ++/* ++ * Decode the specified scan register values into the bitmap pointed ++ * to by the last argument. The bitmap will contain a 1 ++ * for each key that's down. ++ * ++ * Only the 1st two of the four scan registers are used. ++ */ ++static void ++scan_to_bitmap(unsigned long kpas, unsigned long kpasmkp0, ++ unsigned long kpasmkp1, unsigned long bitmap[]) ++{ ++ int row, col; ++ int bitnum; ++ unsigned long scanmap; ++#if defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ int keep; ++#endif ++ ++ set_bitmap_to_zero (bitmap); ++ ++ if ((kpas & KPAS_MUKP) == MUKP_NO_KEYS) ++ { ++ return; ++ } ++ ++ if ((kpas & KPAS_MUKP) == MUKP_ONE_KEY) ++ { ++ row = (kpas & KPAS_RP) >> 4; ++ col = kpas & KPAS_CP; ++ turn_on_bit (bitmap, scanbit_to_keycode[col*8 + row]); ++ return; ++ } ++ ++ /* reach here if multiple keys */ ++ scanmap = (kpasmkp0 & 0x7f) | ((kpasmkp0 & 0x7f0000) >> 8) | ++ ((kpasmkp1 & 0x7f) << 16) | ((kpasmkp1 & 0x7f0000) << 8); ++ while ((bitnum = ffs(scanmap)) != 0) ++ { ++ /* ++ * ffs returns bit numbers starting with 1, so subtract 1 to index ++ * into scanbit_to_keycode[] ++ */ ++ turn_on_bit (bitmap, scanbit_to_keycode[bitnum-1]); ++ scanmap &= ~(1<<(bitnum-1)); ++ } ++#if defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ kpasmkp2 = KPASMKP2; ++ if ((kpasmkp1 & 0x180000) || (kpasmkp2 & 0x18)) ++ keep = 1; ++ else ++ keep = 0; ++ if ( keep ) ++ kpasmkp2 &= 0xfffffffe; ++ while ((bitnum = ffs(kpasmkp2)) !=0) ++ { ++ turn_on_bit (bitmap, scanbit_to_keycode[32+bitnum-1]); ++ kpasmkp2 &= ~(1<<(bitnum-1)); ++ } ++#endif ++} ++ ++/* ++ * Add events indicated by the difference between the last scan (oldbitmap) ++ * and this one (newbitmap) to the input buffer. ++ * Return nonzero right away if any of the events can't be added. ++ * A zero return means all the events were added. ++ * This should be called with keypad_lock locked. ++ */ ++static int ++add_events (unsigned long *oldbitmap, unsigned long *newbitmap) ++{ ++ unsigned long tmpmap, onebitmap; ++ int bitnum, i, ret; ++ ++ /* generate events for keys that were down before and are up now */ ++ for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) ++ { ++ tmpmap = oldbitmap[i]; ++ while ((bitnum = ffs(tmpmap)) != 0) ++ { ++ onebitmap = 1<<(bitnum-1); ++ if ((newbitmap[i] & onebitmap) == 0) ++ { ++ ret = add_to_keybuf(bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYUP)); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ tmpmap &= ~onebitmap; ++ } ++ } ++ /* generate events for down keys that were up before */ ++ for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) ++ { ++ tmpmap = newbitmap[i]; ++ while ((bitnum = ffs(tmpmap)) != 0) ++ { ++ onebitmap = 1<<(bitnum-1); ++ if ((oldbitmap[i] & onebitmap) == 0) ++ { ++ ret = add_to_keybuf ++ (bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYDOWN)); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ tmpmap &= ~onebitmap; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * do the INSERT_EVENT ioctl ++ */ ++static int ++insert_event (unsigned short event) ++{ ++ unsigned long flags; ++ int ret; ++ ++ if (KEYCODE(event) > KEYPAD_MAXCODE) ++ { ++ printk(KERN_WARNING " inserted key code %d too big\n", ++ KEYCODE(event)); ++ return -EINVAL; ++ } ++ spin_lock_irqsave(&keypad_lock, flags); ++ if (KEY_IS_DOWN(event)) ++ { ++ turn_on_bit(keybitmap, KEYCODE(event)); ++ } ++ else ++ { ++ turn_off_bit (keybitmap, event); ++ } ++ if ((ret = add_to_keybuf(event)) < 0) ++ { ++ spin_unlock_irqrestore(&keypad_lock,flags); ++ return ret; ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ return 0; ++} ++ ++static int ++keypad_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int interval; /* debounce interval */ ++ int imkp; /* Ignore Multiple Key Press bit */ ++ struct autorepeatinfo ar; /* autorepeat information */ ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypad_ioctl: 0x%x\n", cmd); ++#endif ++ switch (cmd) ++ { ++ case KEYPAD_IOC_INSERT_EVENT: ++ return insert_event ((unsigned short)arg); ++ break; ++ case KEYPAD_IOC_GET_DEBOUNCE_INTERVAL: ++ interval = KPKDI & KPKDI_BITS; ++ return put_user(interval, (unsigned long *)arg); ++ break; ++ case KEYPAD_IOC_SET_DEBOUNCE_INTERVAL: ++ interval = (unsigned short)arg; ++ if (interval > KPKDI_BITS) ++ { ++ return -EINVAL; ++ } ++ KPKDI &= ~KPKDI_BITS; ++ KPKDI |= interval; ++ break; ++ case KEYPAD_IOC_GET_IMKP_SETTING: ++ imkp = ((KPC & KPC_IMKP) == KPC_IMKP); ++ return put_user(imkp, (unsigned char *)arg); ++ break; ++ case KEYPAD_IOC_SET_IMKP_SETTING: ++ imkp = (unsigned char)arg; ++ if (imkp) ++ { ++ KPC |= KPC_IMKP; ++ } ++ else ++ { ++ KPC &= ~KPC_IMKP; ++ } ++ break; ++ case KEYPAD_IOC_SET_AUTOREPEAT: ++ if (copy_from_user (&ar, (void *)arg, ++ sizeof(struct autorepeatinfo)) != 0) ++ { ++ return -EFAULT; ++ } ++ do_autorepeat = ar.r_repeat; ++ /* times are specified in milliseconds; convert to jiffies */ ++ jiffies_to_first_repeat = ar.r_time_to_first_repeat * HZ/1000; ++ jiffies_to_next_repeat = ar.r_time_between_repeats * HZ/1000; ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int ++keypadB_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long flags; ++ int ret; ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypadB_ioctl: 0x%x\n", cmd); ++#endif ++ if (cmd == KEYPAD_IOC_INSERT_EVENT) ++ { ++ return insert_event ((unsigned short)arg); ++ } ++ else if (cmd == KEYPAD_IOC_GETBITMAP) ++ { ++ spin_lock_irqsave(&keypad_lock, flags); ++ ret = copy_to_user ((void *)arg, keybitmap, ++ NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); ++ copy_bitmap (lastioctlbitmap, keybitmap); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return (ret != 0) ? -EFAULT : 0; ++ } ++ else ++ { ++ return -ENOTTY; ++ } ++} ++ ++static int ++keypadI_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long flags; ++ int ret; ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypadI_ioctl: 0x%x\n", cmd); ++#endif ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ if( cmd == KEYPADI_TURN_ON_LED ) ++ { ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ GPIO_TC_MM_STATE = 0; ++ PGSR3 &= ~GPIO_bit(GPIO_TC_MM_EN); ++ return 0; ++ } ++ if( cmd == KEYPADI_TURN_OFF_LED ) ++ { ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ GPIO_TC_MM_STATE = 1; ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++ return 0; ++ } ++#endif ++ ++ if (cmd == KEYPAD_IOC_INSERT_EVENT) ++ { ++ return insert_event ((unsigned short)arg); ++ } ++ else if (cmd == KEYPAD_IOC_GETBITMAP) ++ { ++ spin_lock_irqsave(&keypad_lock, flags); ++ ret = copy_to_user ((void *)arg, keybitmap, ++ NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); ++ copy_bitmap (lastioctlbitmap, keybitmap); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return (ret != 0) ? -EFAULT : 0; ++ } ++ else ++ { ++ return -ENOTTY; ++ } ++} ++ ++static unsigned int ++keypad_poll( struct file *file, poll_table * wait ) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_poll\n"); ++#endif ++ poll_wait(file, &keypad_wait, wait); ++ ++ if (!KEYBUF_EMPTY()) ++ { ++ return (POLLIN | POLLRDNORM); ++ } ++ return 0; ++} ++ ++static unsigned int ++keypadB_poll( struct file *file, poll_table * wait ) ++{ ++ int i; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadB_poll\n"); ++#endif ++ poll_wait(file, &keypad_wait, wait); ++ ++ for (i=0; i < NUM_WORDS_IN_BITMAP; i++) ++ { ++ if (lastioctlbitmap[i] != keybitmap[i]) ++ { ++ return (POLLIN | POLLRDNORM); ++ } ++ } ++ return 0; ++} ++ ++static unsigned short ++get_from_keybuf(void) ++{ ++ unsigned short event; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock, flags); ++ event = keybuf[keybuf_start]; ++ KEYBUF_INC (keybuf_start); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return event; ++} ++ ++static ssize_t ++keypad_read(struct file *file, char *buf, size_t count, loff_t *ptr) ++{ ++ int i, ret; ++ unsigned short event; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_read\n"); ++#endif ++ /* Can't seek (pread) on this device */ ++ if (ptr != &file->f_pos) ++ { ++ return -ESPIPE; ++ } ++ ++ if (count == 0) ++ { ++ return 0; ++ } ++ ++ if (KEYBUF_EMPTY()) ++ { ++ /* buffer is empty */ ++ /* if not blocking return */ ++ if (file->f_flags & O_NONBLOCK) ++ { ++ return -EAGAIN; ++ } ++ /* blocking, so wait for input */ ++ ret = wait_event_interruptible(keypad_wait, !KEYBUF_EMPTY()); ++ if (ret) ++ { ++ return ret; ++ } ++ } ++ ++ i = 0; ++ /* copy events until we have what the user asked for or we run out */ ++ while ((i+1 < count) && !KEYBUF_EMPTY()) ++ { ++ event = get_from_keybuf(); ++ if ((ret = put_user(event, (unsigned short *)buf)) != 0) ++ { ++ return ret; ++ } ++ buf += EVENTSIZE; ++ i += EVENTSIZE; ++ } ++ return i; ++} ++ ++#ifdef CONFIG_PM ++static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int pksr; ++ ++ pksr = PKSR; ++ PKSR = 0xfffff; ++ switch(req) ++ { ++ case PM_SUSPEND: ++ kpc_res = KPC; ++ kpkdi_res = KPKDI; ++ set_bitmap_to_zero (oldkeybitmap); ++ set_bitmap_to_zero (keybitmap); ++ set_bitmap_to_zero (lastioctlbitmap); ++ kpas = 0; ++ kpasmkp0 = 0; ++ kpasmkp1 = 0; ++ kpasmkp2 = 0; ++ kpdk = 0; ++ break; ++ case PM_RESUME: ++ KPC = kpc_res; ++ KPKDI = kpkdi_res; ++#ifdef CONFIG_APM ++#if defined(CONFIG_E680_P4A) ++ if (pksr & 0xe4400) /*93 97 100 101 102 key is pressed (switch on) */ ++ { ++ apm_queue_event(KRNL_KEYPAD); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ if (pksr & 0xee400) /*93 96 97 98 190 101 102 key is pressed */ ++ { ++ apm_queue_event(KRNL_KEYPAD); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ if (pksr & 0x2000) ++ turn_on_bit (keybitmap, KEYPAD_A); ++ if (pksr & 0x8000) ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ printk("pksr = %x\n",pksr); ++ if (pksr & 0xec400) /* 93 97 98 100 101 102 key is pressed */ ++ { ++ apm_queue_event(KRNL_KEYPAD); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#endif ++ ++ break; ++ } ++ return 0; ++} ++#endif ++ ++/* for /dev/keypad */ ++static struct file_operations ++keypad_fops = { ++ read: keypad_read, ++ llseek: no_llseek, ++ poll: keypad_poll, ++ ioctl: keypad_ioctl, ++ open: keypad_open, ++ release: keypad_close, ++}; ++ ++static struct miscdevice ++keypad_misc_device = { ++ KEYPAD_MINOR, ++ KEYPAD_NAME, ++ &keypad_fops, ++}; ++ ++/* ++ * for /dev/keypadB. ++ * read() isn't defined here. calls to read() will return -1 with EINVAL. ++ */ ++static struct file_operations ++keypadB_fops = { ++ llseek: no_llseek, ++ poll: keypadB_poll, ++ ioctl: keypadB_ioctl, ++ open: keypadB_open, ++ release: keypadB_close, ++}; ++ ++static struct miscdevice ++keypadB_misc_device = { ++ KEYPAD_BITMAP_MINOR, ++ KEYPAD_BITMAP_NAME, ++ &keypadB_fops, ++}; ++ ++/* ++ * for /dev/keypadI. ++ * read() isn't defined here. calls to read() will return -1 with EINVAL. ++ */ ++static struct file_operations ++keypadI_fops = { ++ llseek: no_llseek, ++ ioctl: keypadI_ioctl, ++ open: keypadI_open, ++ release: keypadI_close, ++}; ++ ++static struct miscdevice ++keypadI_misc_device = { ++ KEYPAD_INSERT_MINOR, ++ KEYPAD_INSERT_NAME, ++ &keypadI_fops, ++}; ++ ++#ifdef CONFIG_PANIC_LOG ++static u32 panic_bug_used =0; ++#endif ++ ++/* Interrupt Handler for KEYPAD */ ++static irqreturn_t ++kp_interrupt(int irq, void *ptr, struct pt_regs *regs) ++{ ++ unsigned long flags; ++ unsigned long kpc_val; ++ ++#ifdef USE_RELEASE_TIMER ++ del_timer (&key_release_timer); ++#endif ++ del_timer (&autorepeat_timer); ++ spin_lock_irqsave(&keypad_lock,flags); ++ ++ /* ack interrupt */ ++ kpc_val = KPC; ++ ++ /* matrix interrupt */ ++ if (kpc_val & KPC_MI) ++ { ++/* ++ * The Intel driver turned on KPC_AS here. It doesn't seem that we ++ * would need to do that, because getting an interrupt means that ++ * a scan was just done. For now, I've commented out the setting ++ * and clearing of this bit. ++ KPC |= KPC_AS; ++ */ ++ while (KPAS & KPAS_SO) ++ { ++ /* Wait for the Scan On bit to go off before */ ++ /* reading the scan registers. */ ++ NULL; ++ }; ++ ++ kpas = KPAS; ++ kpasmkp0 = KPASMKP0; ++ kpasmkp1 = KPASMKP1; ++ kpasmkp2 = KPASMKP2; ++ ++ } ++ ++ /* direct interrupt */ ++ if (kpc_val & KPC_DI) ++ { ++ kpdk = KPDK; ++ /* ++ * reading the register turns off the "key pressed since last read" ++ * bit if it was on, so we turn it off ++ */ ++ kpdk &= ~KPDK_DKP; ++ } ++#ifdef CONFIG_PANIC_LOG ++ if ((kpdk & KPDK_DK0)&&(kpasmkp1& 0x00020000)) ++ { ++ if(0 == panic_bug_used) ++ { ++ panic_bug_used = 1; ++ BUG(); ++ } ++ } ++#endif ++ copy_bitmap (oldkeybitmap, keybitmap); ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++#elif defined(CONFIG_KEYPAD_E680) ++ if (kpdk & KPDK_DK0) /* VR key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++ if (kpdk & KPDK_DK3) ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++ ++#elif defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ ++ (void) add_events (oldkeybitmap, keybitmap); ++ ++ /* If any keys are down, set a timer to check for key release */ ++ /* and one for autorepeat if that's on. */ ++ if (any_keys_down (keybitmap)) ++ { ++#ifdef USE_RELEASE_TIMER ++ key_release_timer.expires = (jiffies + key_release_interval); ++ add_timer (&key_release_timer); ++#endif ++ if (do_autorepeat) ++ { ++ autorepeat_timer.expires = (jiffies + jiffies_to_first_repeat); ++ add_timer (&autorepeat_timer); ++ } ++ } ++ ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ //printk("keypad interrupt occurred\n"); ++ return IRQ_HANDLED; ++} ++ ++#ifdef USE_RELEASE_TIMER ++/* ++ * This is called when the key release timer goes off. That's the ++ * only time it should be called. Check for changes in what keys ++ * are down. ++ */ ++static void ++release_timer_went_off(unsigned long unused) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock,flags); ++ do_scan(); ++ /* If any keys are still down, set the timer going again. */ ++ if (any_keys_down (keybitmap)) ++ { ++ mod_timer (&key_release_timer, jiffies + key_release_interval); ++ } ++ else ++ { ++ del_timer (&autorepeat_timer); ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++} ++#endif ++ ++/* ++ * This is called when the autorepeat timer goes off. ++ */ ++static void ++autorepeat_timer_went_off(unsigned long unused) ++{ ++ int i, bitnum; ++ unsigned long tmp; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock,flags); ++ if (!any_keys_down (keybitmap)) ++ { ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return; ++ } ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ tmp = keybitmap[NUM_WORDS_IN_BITMAP-i-1]; ++ while ((bitnum = ffs(tmp)) != 0) ++ { ++ tmp &= ~(1<<(bitnum-1)); ++ /* see explanation at top of file */ ++ if ( (bitnum + (32*i)) == KEYPAD_POWER ) ++ { ++ continue; ++ } ++ (void) add_to_keybuf( (bitnum + (32*i)) | KEYDOWN ); ++ } ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ ++ mod_timer (&autorepeat_timer, jiffies + jiffies_to_next_repeat); ++} ++ ++#ifdef USE_RELEASE_TIMER ++/* ++ * Do a scan and add key events for anything that's different from the ++ * last scan. We assume keypad_lock is locked when this is called ++ * (by release_timer_went_off). ++ */ ++static void ++do_scan(void) ++{ ++ unsigned long kpas_new, kpasmkp0_new, kpasmkp1_new; ++ unsigned long kpdk_new; ++ int change; ++ ++ /* Initiate an automatic scan */ ++ KPC |= KPC_AS; ++ /* Wait for the Scan On bit to go off before */ ++ /* reading the scan registers. */ ++ while (KPAS & KPAS_SO) ++ { ++ NULL; ++ }; ++ kpas_new = KPAS; ++ kpasmkp0_new = KPASMKP0; ++ kpasmkp1_new = KPASMKP1; ++ kpdk_new = KPDK; ++ /* ++ * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off ++ */ ++ kpdk_new &= ~KPDK_DKP; ++ KPC &= ~KPC_AS; ++ ++ change = ((kpas_new != kpas) || ++ (kpasmkp0_new != kpasmkp0) || ++ (kpasmkp1_new != kpasmkp1) || ++ (kpdk_new != kpdk)); ++ ++ if (change) ++ { ++ kpas = kpas_new; ++ kpasmkp0 = kpasmkp0_new; ++ kpasmkp1 = kpasmkp1_new; ++ kpdk = kpdk_new; ++ ++ copy_bitmap (oldkeybitmap, keybitmap); ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); ++#if defined(CONFIG_E680_P4A) || defined(CONFIG_E680_P4A_MODULE) ++ if (kpdk & KPDK_DK0) /* screen lock key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++#elif defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ if (kpdk & KPDK_DK0) /* screen lock key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++ if (kpdk & KPDK_DK3) ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++ ++#elif defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ add_events (oldkeybitmap, keybitmap); ++ ++ wake_up_interruptible (&keypad_wait); ++ } ++} ++#endif ++ ++/* ++ * set all words in the specified bitmap to 0 ++ */ ++static inline void set_bitmap_to_zero(unsigned long b[]) { ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ b[i]=0; ++ } ++} ++ ++/* ++ * copy source bitmap to destination bitmap ++ */ ++static inline void copy_bitmap(unsigned long dest[], unsigned long source[]) { ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ dest[i]=source[i]; ++ } ++} ++ ++/* ++ * Turn on the bit position in map for the specified key code. ++ * Bit numbers start with 1 (not 0) and increase moving left within ++ * words and within the array. ++ * Bit 1 is the rightmost bit in map[NUM_WORDS_IN_BITMAP-1]. ++ * Bit 33 is the rightmost bit in map[NUM_WORDS_IN_BITMAP-2]. ++ */ ++static inline void ++turn_on_bit(unsigned long map[], int code) ++{ ++ int word, pos, p; ++ ++ /* if we have 2 words, bits 1-32 are in map[1], 33-64 in map[0] */ ++ word = (NUM_WORDS_IN_BITMAP - 1) - ((code-1) / 32); ++ /* ++ * bit 1 is 1<<0, bit 2 is 1<<1, ... bit 32 is 1 << 31, all in map[1] ++ * bit 33 is 1<<0, bit 34 is 1<<1, ... in map[0] ++ * we want this: ++ * code pos ++ * 1 0 ++ * 2 1 ++ * ... ++ * 31 30 ++ * 32 31 ++ * 33 0 ++ * 34 1 ++ * ... ++ */ ++ pos = (p = (code % 32)) == 0 ? 31 : p-1; ++ map[word] |= (1<<pos); ++} ++ ++/* ++ * Turn off the bit position in map for the specified key code. ++ * Bit positions start with 1 (not 0). ++ */ ++static inline void ++turn_off_bit(unsigned long map[], int code) ++{ ++ int word, pos, p; ++ ++ word = (NUM_WORDS_IN_BITMAP - 1) - ((code-1) / 32); ++ pos = (p = (code % 32)) == 0 ? 31 : p-1; ++ map[word] &= ~(1<<pos); ++} ++ ++/* ++ * Return 1 if any bits are down in map[] ++ */ ++static inline int ++any_keys_down (unsigned long *map) ++{ ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ /* don't count the power key */ ++ if ((i == 0) && (*map == 0x10)) ++ { ++ map++; ++ continue; ++ } ++ if (*map++) ++ { ++ return 1; ++ } ++ } ++ return 0; ++} ++static int ++__init keypad_init(void) ++{ ++ int err; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_init\n"); ++#endif ++ ++ set_bitmap_to_zero (oldkeybitmap); ++ set_bitmap_to_zero (keybitmap); ++ set_bitmap_to_zero (lastioctlbitmap); ++ ++ /* set up gpio */ ++#if defined (CONFIG_KEYPAD_V700) || defined(CONFIG_KEYPAD_V700_MODULE) ++ pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); /* KP_MKIN<6> */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); /* KP_MKIN<5> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_E680_P4A) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++#elif defined (CONFIG_KEYPAD_A780) || defined (CONFIG_KEYPAD_A780_MODULE) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ ++#elif defined(CONFIG_KEYPAD_MAINSTONE) || defined(CONFIG_KEYPAD_MAINSTONE_MODULE) ++ /* from Intel driver */ ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#endif ++ ++ /* set keypad control register */ ++ KPC = (KPC_ASACT | /* automatic scan on activity */ ++ KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ ++#if defined (CONFIG_KEYPAD_V700) || defined(CONFIG_KEYPAD_V700_MODULE) ++ (3<<23) | /* 4 columns */ ++ (6<<26) | /* 7 rows */ ++#elif defined(CONFIG_E680_P4A) ++ (3<<23) | /* 4 columns */ ++ (2<<26) | /* 3 rows */ ++ (4<<6) | /* 4# direct key */ ++#elif defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ (5<<23) | /* 4 columns */ ++ (4<<26) | /* 3 rows */ ++ (5<<6) | /* 5# direct keys */ ++#elif defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ (4<<23) | /* 5 columns */ ++ (4<<26) | /* 5 rows */ ++ (0<<6) | /* 1# direct keys */ ++#endif ++ KPC_MS_ALL); /* scan all columns */ ++ ++ CKEN |= CKEN19_KEYPAD; ++ ++ err = request_irq (IRQ_KEYPAD, kp_interrupt, 0, "Keypad", NULL); ++ if (err) ++ { ++ printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", ++ IRQ_KEYPAD, err); ++ CKEN &= ~CKEN19_KEYPAD; ++ return -ENODEV; ++ } ++ ++ if (misc_register (&keypad_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypad driver\n"); ++ return -EIO; ++ } ++ if (misc_register (&keypadB_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypadB driver\n"); ++ misc_deregister(&keypad_misc_device); ++ return -EIO; ++ } ++ if (misc_register (&keypadI_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypadI driver\n"); ++ misc_deregister(&keypad_misc_device); ++ misc_deregister(&keypadB_misc_device); ++ return -EIO; ++ } ++ ++#ifdef USE_RELEASE_TIMER ++ init_timer (&key_release_timer); ++ key_release_timer.function = release_timer_went_off; ++#endif ++ init_timer (&autorepeat_timer); ++ autorepeat_timer.function = autorepeat_timer_went_off; ++ ++ /* ++ * we want the phone to be able to tell the status of the screen ++ * lock switch at power-up time ++ */ ++ kpdk = KPDK; /* read direct key register */ ++ /* ++ * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off ++ */ ++ kpdk &= ~KPDK_DKP; ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++#elif defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#elif defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); ++#if defined(CONFIG_E680_P4A) ++/*93,97,100,101,102*/ ++ PKWR = 0xe4400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++/*93,96,97,98,100,101,102*/ ++ PKWR = 0xee400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_A780) || defined(CONFIG_KEYPAD_A780_MODULE) ++/*93,97,98,100,101,102*/ ++ PKWR = 0xec400; ++/*103 104 105 106 107*/ ++ PGSR3 |= 0xf80; ++#endif ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++#ifdef CONFIG_PM ++ keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); ++ PGSR3 |= 0x8; ++#endif ++#endif ++ ++ KPC |= (KPC_DIE | KPC_MIE); ++ KPKDI = 0x40; ++ return 0; ++} ++ ++static void ++__exit keypad_exit(void) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_exit\n"); ++#endif ++ misc_deregister(&keypad_misc_device); ++ misc_deregister(&keypadB_misc_device); ++ misc_deregister(&keypadI_misc_device); ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) || defined(CONFIG_KEYPAD_E680_MODULE) ++#ifdef CONFIG_PM ++ pm_unregister(keypadI_pm_dev); ++#endif ++#endif ++ ++ CKEN &= ~CKEN19_KEYPAD; ++} ++ ++module_init (keypad_init); ++module_exit (keypad_exit); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/keypad-e398.c linux-2.6.16/drivers/misc/ezx/keypad-e398.c +--- linux-2.6.16.orig/drivers/misc/ezx/keypad-e398.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/keypad-e398.c 2006-06-03 11:14:56.338324528 +0200 +@@ -0,0 +1,1497 @@ ++/* ++ * linux/drivers/char/keypad.c ++ * ++ * (c) Copyright Motorola 2003, All rights reserved. ++ */ ++ ++/* ++ * This driver is for three devices: /dev/keypad, /dev/keypadB and ++ * /dev/keypadI. ++ * /dev/keypad would be used for reading the key event buffer. ++ * It can be opened by one process at a time. ++ * /dev/keypadB would be used for ioctl(KEYPAD_IOC_GETBITMAP). ++ * It can be opened by one process at a time. ++ * /dev/keypadI would be used for ioctl(KEYPAD_IOC_INSERT_EVENT). ++ * It can be opened any number of times simultaneously. ++ * ++ * The bulverde specification is ambiguous about when interrupts happen ++ * for released keys. We were told by Intel that we won't ++ * get interrupts for released keys except in the case when multiple ++ * keys were down and they've all been released. So we implemented ++ * a timer to poll for changes in key states. ++ * ++ * The E680 P2 hardware gives us interrupts when any key is released, ++ * whether it was the only key down or not, and whether it's the last ++ * of multiple keys to be released or not. We don't know whether this ++ * behavior will continue in future hardware releases, so the release ++ * timer is still in the code, #ifdef'd with USE_RELEASE_TIMER. On the ++ * P2 hardware, the code works with or without USE_RELEASE_TIMER defined. ++ * If the release interrupts are always going to happen, we can remove ++ * the #ifdef'd code. ++ * ++ * With the P2 hardware, the power key bit in the KPDK register is always ++ * on. We don't know if this is correct behavior or not, but in any case ++ * it certainly causes trouble to have that key autorepeating indefinitely, ++ * or to be checking indefinitely for the key to be released (if we're doing ++ * release polling). ++ * ++ * For now, any_keys_down() returns 0 if the power key is the only one down. ++ * . At interrupt time, if the power key is the only one down we don't ++ * set the autorepeat timer or release timer. ++ * . When the release timer goes off, if the power key is the only one ++ * still down we don't set the timer again. ++ * . When the autorepeat timer goes off, if the power key is the only ++ * one down we don't generate any events. ++ * In autorepeat_timer_went_off, if there are non-power keys down, while we're ++ * looking through the whole bitmap of keys down we ignore the power key. ++ */ ++ ++#include <linux/tty.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/bitops.h> ++#include <linux/param.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <linux/pm.h> ++#include <linux/apm_bios.h> ++#include "keypad.h" ++#include <asm/arch/irqs.h> ++#include "asm/arch/ezx.h" ++ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++static struct pm_dev *keypadI_pm_dev; ++static int kpc_res,kpkdi_res; ++static int GPIO_TC_MM_STATE = 1; ++extern unsigned char pxafb_ezx_getLCD_status(void); ++#endif ++/* ++ * This is the number of microseconds we wait before checking to see if any ++ * keys have been released. ++ */ ++#define RDELAY 200 ++ ++#define KEYBUF_EMPTY() (keybuf_start == keybuf_end) ++#define KEYBUF_FULL() ( ((keybuf_end+1)%KEYBUF_SIZE) == keybuf_start) ++#define KEYBUF_INC(x) ((x) = (((x)+1) % KEYBUF_SIZE)) ++ ++static int keypad_open (struct inode *, struct file *); ++static int keypad_close (struct inode *, struct file *); ++static int keypad_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++static unsigned int keypad_poll (struct file *, poll_table *); ++static ssize_t keypad_read (struct file *, char *, size_t, loff_t *); ++ ++static int keypadB_open (struct inode *, struct file *); ++static int keypadB_close (struct inode *, struct file *); ++static int keypadB_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++static unsigned int keypadB_poll (struct file *, poll_table *); ++ ++static int keypadI_open(struct inode *, struct file *); ++static int keypadI_close(struct inode *, struct file *); ++static int keypadI_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++ ++static void kp_interrupt (int, void *, struct pt_regs *); ++#ifdef USE_RELEASE_TIMER ++static void release_timer_went_off (unsigned long); ++static void do_scan(void); ++#endif ++static void autorepeat_timer_went_off (unsigned long); ++ ++static int add_to_keybuf (unsigned short); ++static int add_events (unsigned long *, unsigned long *); ++static int insert_event (unsigned short); ++static unsigned short get_from_keybuf (void); ++static void scan_to_bitmap ++ (unsigned long, unsigned long, unsigned long, unsigned long *); ++static inline void set_bitmap_to_zero(unsigned long b[]); ++static inline void copy_bitmap(unsigned long dest[], unsigned long source[]); ++static inline void turn_on_bit(unsigned long map[], int); ++static inline void turn_off_bit(unsigned long map[], int); ++static inline int any_keys_down (unsigned long *); ++ ++/* ++ * keybuf is a circular buffer to hold keypad events. ++ * keybuf_start is the index of the first event. ++ * keybuf_end is one more than the index of the last event. ++ * The buffer is empty when keybuf_start == keybuf_end. ++ * We only use KEYBUF_SIZE-1 entries in the buffer so we can tell ++ * when it's full without needing another variable to tell us. ++ * The buffer is full when (keybuf_end+1)%KEYBUF_SIZE == keybuf_start. ++ */ ++static unsigned short keybuf[KEYBUF_SIZE]; ++static int keybuf_start = 0; ++static int keybuf_end = 0; ++ ++static DECLARE_WAIT_QUEUE_HEAD(keypad_wait); ++static spinlock_t keypad_lock = SPIN_LOCK_UNLOCKED; ++ ++static int reading_opens = 0; ++static int bitmap_opens = 0; ++ ++/* previous bitmap of keys down */ ++static unsigned long oldkeybitmap[NUM_WORDS_IN_BITMAP]; ++/* current bitmap of keys down */ ++static unsigned long keybitmap[NUM_WORDS_IN_BITMAP]; ++/* last bitmap read by ioctl */ ++static unsigned long lastioctlbitmap[NUM_WORDS_IN_BITMAP]; ++ ++static unsigned long kpas = 0; /* last value of kpas */ ++static unsigned long kpasmkp0 = 0; /* last value of kpasmkp0 */ ++static unsigned long kpasmkp1 = 0; /* last value of kpasmkp1 */ ++static unsigned long kpasmkp2 = 0; /* last value of kpasamkp2*/ ++static unsigned long kpdk = 0; /* last value of kpdk */ ++ ++#ifdef USE_RELEASE_TIMER ++static struct timer_list key_release_timer; ++static int key_release_interval = RDELAY * HZ/1000; ++#endif ++ ++static int do_autorepeat = 1; ++static long jiffies_to_first_repeat = 30; ++static long jiffies_to_next_repeat = 30; ++static struct timer_list autorepeat_timer; ++ ++extern int lockscreen_flag; ++ ++static int ++keypad_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypad_open\n"); ++#endif ++ spin_lock(keypad_lock); ++ if (reading_opens > 0) ++ { ++ spin_unlock(keypad_lock); ++ return -EBUSY; ++ } ++ reading_opens++; ++ spin_unlock(keypad_lock); ++ ++ return 0; ++} ++ ++static int ++keypadB_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypadB_open\n"); ++#endif ++ spin_lock(keypad_lock); ++ if (bitmap_opens > 0) ++ { ++ spin_unlock(keypad_lock); ++ return -EBUSY; ++ } ++ bitmap_opens++; ++ /* ++ * poll returns when lastioctlbitmap is different from keybitmap. ++ * we set lastioctlbitmap to keybitmap here so that a poll right ++ * after an open returns when the bitmap is different from when ++ * the open was done, not when the bitmap is different from the ++ * last time some other process read it ++ */ ++ copy_bitmap(lastioctlbitmap, keybitmap); ++ spin_unlock(keypad_lock); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_KEYPAD_E680) ++#ifdef CONFIG_PM ++static int keypadI_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ break; ++ case PM_RESUME: ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ if(GPIO_TC_MM_STATE == 1) ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ else ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++#endif ++ ++static int ++keypadI_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypadI_open\n"); ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ ++ return 0; ++} ++ ++static int ++keypad_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_close\n"); ++#endif ++ /* ++ * this decrement of reading_opens doesn't have to be protected because ++ * it can only be executed to close the single open of /dev/keypad ++ */ ++ reading_opens--; ++ return 0; ++} ++ ++static int ++keypadB_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadB_close\n"); ++#endif ++ /* ++ * this decrement of bitmap_opens doesn't have to be protected because ++ * it can only be executed to close the single open of /dev/keypadB ++ */ ++ bitmap_opens--; ++ return 0; ++} ++ ++static int ++keypadI_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadI_close\n"); ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ ++ return 0; ++} ++ ++/** ++ * Add the specified event to the key buffer. ++ * This should be called with keypad_lock locked. ++ */ ++static int ++add_to_keybuf (unsigned short event) ++{ ++ if (KEYBUF_FULL()) ++ { ++ return -ENOMEM; ++ } ++ ++ keybuf[keybuf_end] = event; ++ KEYBUF_INC (keybuf_end); ++ ++#if CONFIG_APM ++ queue_apm_event(KRNL_KEYPAD, NULL); ++#endif ++ printk("add keypad event = %x\n", event); ++ return 0; ++} ++ ++/* ++ * code[c*8+r] is the key code for the key that's down when there's a 1 ++ * in column c, row r of the scan registers. ++ */ ++ ++#if defined(CONFIG_KEYPAD_V700) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_RIGHT, ++ KEYPAD_POUND, KEYPAD_0, KEYPAD_9, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_2, KEYPAD_4, KEYPAD_6, KEYPAD_8, ++ KEYPAD_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_MENU, KEYPAD_1, KEYPAD_3, KEYPAD_5, ++ KEYPAD_STAR, KEYPAD_VOLUP, KEYPAD_VOLDOWN, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, ++ KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, KEYPAD_NONE ++}; ++ ++/* end CONFIG_KEYPAD_V700 */ ++#elif defined(CONFIG_E680_P4A) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_RIGHT, KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_GAME_L, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_A, KEYPAD_B, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++}; ++ ++/* end CONFIG_E680_P4A */ ++#elif defined(CONFIG_KEYPAD_E680) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_RIGHT, KEYPAD_LEFT, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_NONE, KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ ++}; ++/*end CONFIG_KEYPAD_E680 */ ++#elif defined(CONFIG_KEYPAD_A780) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_OK, KEYPAD_1, KEYPAD_4, KEYPAD_7, ++ KEYPAD_STAR, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_MENU, KEYPAD_2, KEYPAD_5, KEYPAD_8, ++ KEYPAD_0, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_CANCEL, KEYPAD_3, KEYPAD_6, KEYPAD_9, ++ KEYPAD_POUND, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_JOG_UP, KEYPAD_JOG_MIDDLE, KEYPAD_PTT, KEYPAD_HOME, ++ KEYPAD_JOG_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 4 */ ++ KEYPAD_UP, KEYPAD_CENTER, KEYPAD_LEFT, KEYPAD_RIGHT, ++ KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++}; ++#endif ++ ++/* ++ * Decode the specified scan register values into the bitmap pointed ++ * to by the last argument. The bitmap will contain a 1 ++ * for each key that's down. ++ * ++ * Only the 1st two of the four scan registers are used. ++ */ ++static void ++scan_to_bitmap(unsigned long kpas, unsigned long kpasmkp0, ++ unsigned long kpasmkp1, unsigned long bitmap[]) ++{ ++ int row, col; ++ int bitnum; ++ unsigned long scanmap; ++#if defined(CONFIG_KEYPAD_A780) ++ int keep; ++#endif ++ ++ set_bitmap_to_zero (bitmap); ++ ++ if ((kpas & KPAS_MUKP) == MUKP_NO_KEYS) ++ { ++ return; ++ } ++ ++ if ((kpas & KPAS_MUKP) == MUKP_ONE_KEY) ++ { ++ row = (kpas & KPAS_RP) >> 4; ++ col = kpas & KPAS_CP; ++ turn_on_bit (bitmap, scanbit_to_keycode[col*8 + row]); ++ return; ++ } ++ ++ /* reach here if multiple keys */ ++ scanmap = (kpasmkp0 & 0x7f) | ((kpasmkp0 & 0x7f0000) >> 8) | ++ ((kpasmkp1 & 0x7f) << 16) | ((kpasmkp1 & 0x7f0000) << 8); ++ while ((bitnum = ffs(scanmap)) != 0) ++ { ++ /* ++ * ffs returns bit numbers starting with 1, so subtract 1 to index ++ * into scanbit_to_keycode[] ++ */ ++ turn_on_bit (bitmap, scanbit_to_keycode[bitnum-1]); ++ scanmap &= ~(1<<(bitnum-1)); ++ } ++#if defined(CONFIG_KEYPAD_A780) ++ kpasmkp2 = KPASMKP2; ++ printk("kpasmkp0 = 0x\n", kpasmkp0); ++ printk("kpasmkp1 = 0x\n", kpasmkp1); ++ printk("kpasmkp2 = 0x\n", kpasmkp2); ++ if( (kpasmkp2 != 1) || (kpasmkp2 != 2) | (kpasmkp2 != 4) | (kpasmkp2 != 8) | (kpasmkp2 != 16) ) ++ return; ++ while ((bitnum = ffs(kpasmkp2)) !=0) ++ { ++ turn_on_bit (bitmap, scanbit_to_keycode[32+bitnum-1]); ++ kpasmkp2 &= ~(1<<(bitnum-1)); ++ } ++#endif ++} ++ ++/* ++ * Add events indicated by the difference between the last scan (oldbitmap) ++ * and this one (newbitmap) to the input buffer. ++ * Return nonzero right away if any of the events can't be added. ++ * A zero return means all the events were added. ++ * This should be called with keypad_lock locked. ++ */ ++static int ++add_events (unsigned long *oldbitmap, unsigned long *newbitmap) ++{ ++ unsigned long tmpmap, onebitmap; ++ int bitnum, i, ret; ++ ++ /* generate events for keys that were down before and are up now */ ++ for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) ++ { ++ tmpmap = oldbitmap[i]; ++ while ((bitnum = ffs(tmpmap)) != 0) ++ { ++ onebitmap = 1<<(bitnum-1); ++ if ((newbitmap[i] & onebitmap) == 0) ++ { ++ ret = add_to_keybuf(bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYUP)); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ tmpmap &= ~onebitmap; ++ } ++ } ++ /* generate events for down keys that were up before */ ++ for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) ++ { ++ tmpmap = newbitmap[i]; ++ while ((bitnum = ffs(tmpmap)) != 0) ++ { ++ onebitmap = 1<<(bitnum-1); ++ if ((oldbitmap[i] & onebitmap) == 0) ++ { ++ ret = add_to_keybuf ++ (bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYDOWN)); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ tmpmap &= ~onebitmap; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * do the INSERT_EVENT ioctl ++ */ ++static int ++insert_event (unsigned short event) ++{ ++ unsigned long flags; ++ int ret; ++ ++ if (KEYCODE(event) > KEYPAD_MAXCODE) ++ { ++ printk(KERN_WARNING " inserted key code %d too big\n", ++ KEYCODE(event)); ++ return -EINVAL; ++ } ++ spin_lock_irqsave(&keypad_lock, flags); ++ if (KEY_IS_DOWN(event)) ++ { ++ turn_on_bit(keybitmap, KEYCODE(event)); ++ } ++ else ++ { ++ turn_off_bit (keybitmap, event); ++ } ++ if ((ret = add_to_keybuf(event)) < 0) ++ { ++ spin_unlock_irqrestore(&keypad_lock,flags); ++ return ret; ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ return 0; ++} ++ ++static int ++keypad_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int interval; /* debounce interval */ ++ int imkp; /* Ignore Multiple Key Press bit */ ++ struct autorepeatinfo ar; /* autorepeat information */ ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypad_ioctl: 0x%x\n", cmd); ++#endif ++ switch (cmd) ++ { ++ case KEYPAD_IOC_INSERT_EVENT: ++ return insert_event ((unsigned short)arg); ++ break; ++ case KEYPAD_IOC_GET_DEBOUNCE_INTERVAL: ++ interval = KPKDI & KPKDI_BITS; ++ return put_user(interval, (unsigned long *)arg); ++ break; ++ case KEYPAD_IOC_SET_DEBOUNCE_INTERVAL: ++ interval = (unsigned short)arg; ++ if (interval > KPKDI_BITS) ++ { ++ return -EINVAL; ++ } ++ KPKDI &= ~KPKDI_BITS; ++ KPKDI |= interval; ++ break; ++ case KEYPAD_IOC_GET_IMKP_SETTING: ++ imkp = ((KPC & KPC_IMKP) == KPC_IMKP); ++ return put_user(imkp, (unsigned char *)arg); ++ break; ++ case KEYPAD_IOC_SET_IMKP_SETTING: ++ imkp = (unsigned char)arg; ++ if (imkp) ++ { ++ KPC |= KPC_IMKP; ++ } ++ else ++ { ++ KPC &= ~KPC_IMKP; ++ } ++ break; ++ case KEYPAD_IOC_SET_AUTOREPEAT: ++ if (copy_from_user (&ar, (void *)arg, ++ sizeof(struct autorepeatinfo)) != 0) ++ { ++ return -EFAULT; ++ } ++ do_autorepeat = ar.r_repeat; ++ /* times are specified in milliseconds; convert to jiffies */ ++ jiffies_to_first_repeat = ar.r_time_to_first_repeat * HZ/1000; ++ jiffies_to_next_repeat = ar.r_time_between_repeats * HZ/1000; ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int ++keypadB_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long flags; ++ int ret; ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypadB_ioctl: 0x%x\n", cmd); ++#endif ++ if (cmd == KEYPAD_IOC_INSERT_EVENT) ++ { ++ return insert_event ((unsigned short)arg); ++ } ++ else if (cmd == KEYPAD_IOC_GETBITMAP) ++ { ++ spin_lock_irqsave(&keypad_lock, flags); ++ ret = copy_to_user ((void *)arg, keybitmap, ++ NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); ++ copy_bitmap (lastioctlbitmap, keybitmap); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return (ret != 0) ? -EFAULT : 0; ++ } ++ else ++ { ++ return -ENOTTY; ++ } ++} ++ ++static int ++keypadI_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long flags; ++ int ret; ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypadI_ioctl: 0x%x\n", cmd); ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ if( cmd == KEYPADI_TURN_ON_LED ) ++ { ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ GPIO_TC_MM_STATE = 0; ++ PGSR3 &= ~GPIO_bit(GPIO_TC_MM_EN); ++ return 0; ++ } ++ if( cmd == KEYPADI_TURN_OFF_LED ) ++ { ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ GPIO_TC_MM_STATE = 1; ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++ return 0; ++ } ++#endif ++ ++ if (cmd == KEYPAD_IOC_INSERT_EVENT) ++ { ++ return insert_event ((unsigned short)arg); ++ } ++ else if (cmd == KEYPAD_IOC_GETBITMAP) ++ { ++ spin_lock_irqsave(&keypad_lock, flags); ++ ret = copy_to_user ((void *)arg, keybitmap, ++ NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); ++ copy_bitmap (lastioctlbitmap, keybitmap); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return (ret != 0) ? -EFAULT : 0; ++ } ++ else ++ { ++ return -ENOTTY; ++ } ++} ++ ++static unsigned int ++keypad_poll( struct file *file, poll_table * wait ) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_poll\n"); ++#endif ++ poll_wait(file, &keypad_wait, wait); ++ ++ if (!KEYBUF_EMPTY()) ++ { ++ return (POLLIN | POLLRDNORM); ++ } ++ return 0; ++} ++ ++static unsigned int ++keypadB_poll( struct file *file, poll_table * wait ) ++{ ++ int i; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadB_poll\n"); ++#endif ++ poll_wait(file, &keypad_wait, wait); ++ ++ for (i=0; i < NUM_WORDS_IN_BITMAP; i++) ++ { ++ if (lastioctlbitmap[i] != keybitmap[i]) ++ { ++ return (POLLIN | POLLRDNORM); ++ } ++ } ++ return 0; ++} ++ ++static unsigned short ++get_from_keybuf(void) ++{ ++ unsigned short event; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock, flags); ++ event = keybuf[keybuf_start]; ++ KEYBUF_INC (keybuf_start); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return event; ++} ++ ++static ssize_t ++keypad_read(struct file *file, char *buf, size_t count, loff_t *ptr) ++{ ++ int i, ret; ++ unsigned short event; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_read\n"); ++#endif ++ /* Can't seek (pread) on this device */ ++ if (ptr != &file->f_pos) ++ { ++ return -ESPIPE; ++ } ++ ++ if (count == 0) ++ { ++ return 0; ++ } ++ ++ if (KEYBUF_EMPTY()) ++ { ++ /* buffer is empty */ ++ /* if not blocking return */ ++ if (file->f_flags & O_NONBLOCK) ++ { ++ return -EAGAIN; ++ } ++ /* blocking, so wait for input */ ++ ret = wait_event_interruptible(keypad_wait, !KEYBUF_EMPTY()); ++ if (ret) ++ { ++ return ret; ++ } ++ } ++ ++ i = 0; ++ /* copy events until we have what the user asked for or we run out */ ++ while ((i+1 < count) && !KEYBUF_EMPTY()) ++ { ++ event = get_from_keybuf(); ++ if ((ret = put_user(event, (unsigned short *)buf)) != 0) ++ { ++ return ret; ++ } ++ buf += EVENTSIZE; ++ i += EVENTSIZE; ++ } ++ return i; ++} ++ ++#ifdef CONFIG_PM ++static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int pksr; ++ ++ pksr = PKSR; ++ PKSR = 0xfffff; ++ switch(req) ++ { ++ case PM_SUSPEND: ++ kpc_res = KPC; ++ kpkdi_res = KPKDI; ++ set_bitmap_to_zero (oldkeybitmap); ++ set_bitmap_to_zero (keybitmap); ++ set_bitmap_to_zero (lastioctlbitmap); ++ kpas = 0; ++ kpasmkp0 = 0; ++ kpasmkp1 = 0; ++ kpasmkp2 = 0; ++ kpdk = 0; ++ break; ++ case PM_RESUME: ++ KPC = kpc_res; ++ KPKDI = kpkdi_res; ++#if CONFIG_APM ++#if defined(CONFIG_E680_P4A) ++ if (pksr & 0xe4400) /*93 97 100 101 102 key is pressed (switch on) */ ++ { ++ queue_apm_event(KRNL_KEYPAD, NULL); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ if (pksr & 0xee400) /*93 96 97 98 190 101 102 key is pressed */ ++ { ++ queue_apm_event(KRNL_KEYPAD, NULL); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ if (pksr & 0x2000) ++ turn_on_bit (keybitmap, KEYPAD_A); ++ if (pksr & 0x8000) ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_A780) ++ printk("pksr = %x\n",pksr); ++ if (pksr & 0xec400) /* 93 97 98 100 101 102 key is pressed */ ++ { ++ queue_apm_event(KRNL_KEYPAD, NULL); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#endif ++ ++ break; ++ } ++ return 0; ++} ++#endif ++ ++/* for /dev/keypad */ ++static struct file_operations ++keypad_fops = { ++ read: keypad_read, ++ llseek: no_llseek, ++ poll: keypad_poll, ++ ioctl: keypad_ioctl, ++ open: keypad_open, ++ release: keypad_close, ++}; ++ ++static struct miscdevice ++keypad_misc_device = { ++ KEYPAD_MINOR, ++ KEYPAD_NAME, ++ &keypad_fops, ++}; ++ ++/* ++ * for /dev/keypadB. ++ * read() isn't defined here. calls to read() will return -1 with EINVAL. ++ */ ++static struct file_operations ++keypadB_fops = { ++ llseek: no_llseek, ++ poll: keypadB_poll, ++ ioctl: keypadB_ioctl, ++ open: keypadB_open, ++ release: keypadB_close, ++}; ++ ++static struct miscdevice ++keypadB_misc_device = { ++ KEYPAD_BITMAP_MINOR, ++ KEYPAD_BITMAP_NAME, ++ &keypadB_fops, ++}; ++ ++/* ++ * for /dev/keypadI. ++ * read() isn't defined here. calls to read() will return -1 with EINVAL. ++ */ ++static struct file_operations ++keypadI_fops = { ++ llseek: no_llseek, ++ ioctl: keypadI_ioctl, ++ open: keypadI_open, ++ release: keypadI_close, ++}; ++ ++static struct miscdevice ++keypadI_misc_device = { ++ KEYPAD_INSERT_MINOR, ++ KEYPAD_INSERT_NAME, ++ &keypadI_fops, ++}; ++ ++#ifdef CONFIG_PANIC_LOG ++static u32 panic_bug_used =0; ++#endif ++ ++/* Interrupt Handler for KEYPAD */ ++static void ++kp_interrupt(int irq, void *ptr, struct pt_regs *regs) ++{ ++ unsigned long flags; ++ unsigned long kpc_val; ++ ++#ifdef USE_RELEASE_TIMER ++ del_timer (&key_release_timer); ++#endif ++ del_timer (&autorepeat_timer); ++ spin_lock_irqsave(&keypad_lock,flags); ++ ++ /* ack interrupt */ ++ kpc_val = KPC; ++ ++ /* matrix interrupt */ ++ if (kpc_val & KPC_MI) ++ { ++/* ++ * The Intel driver turned on KPC_AS here. It doesn't seem that we ++ * would need to do that, because getting an interrupt means that ++ * a scan was just done. For now, I've commented out the setting ++ * and clearing of this bit. ++ KPC |= KPC_AS; ++ */ ++ while (KPAS & KPAS_SO) ++ { ++ /* Wait for the Scan On bit to go off before */ ++ /* reading the scan registers. */ ++ NULL; ++ }; ++ ++ kpas = KPAS; ++ kpasmkp0 = KPASMKP0; ++ kpasmkp1 = KPASMKP1; ++ kpasmkp2 = KPASMKP2; ++ ++ } ++ ++ /* direct interrupt */ ++ if (kpc_val & KPC_DI) ++ { ++ kpdk = KPDK; ++ /* ++ * reading the register turns off the "key pressed since last read" ++ * bit if it was on, so we turn it off ++ */ ++ kpdk &= ~KPDK_DKP; ++ } ++ ++ copy_bitmap (oldkeybitmap, keybitmap); ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++#elif defined(CONFIG_KEYPAD_E680) ++ if (kpdk & KPDK_DK0) /* VR key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++ if (kpdk & KPDK_DK3) ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++ ++#elif defined(CONFIG_KEYPAD_A780) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ ++#ifdef CONFIG_PANIC_LOG ++ if ((kpdk & KPDK_DK0)&&(kpasmkp1& 0x00020000)) ++ { ++ if(0 == panic_bug_used) ++ { ++ panic_bug_used = 1; ++ BUG(); ++ } ++ } ++#endif ++ ++ (void) add_events (oldkeybitmap, keybitmap); ++ ++ /* If any keys are down, set a timer to check for key release */ ++ /* and one for autorepeat if that's on. */ ++ if (any_keys_down (keybitmap)) ++ { ++#ifdef USE_RELEASE_TIMER ++ key_release_timer.expires = (jiffies + key_release_interval); ++ add_timer (&key_release_timer); ++#endif ++ if (do_autorepeat) ++ { ++ autorepeat_timer.expires = (jiffies + jiffies_to_first_repeat); ++ add_timer (&autorepeat_timer); ++ } ++ } ++ ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ printk("keypad interrupt occurred\n"); ++} ++ ++#ifdef USE_RELEASE_TIMER ++/* ++ * This is called when the key release timer goes off. That's the ++ * only time it should be called. Check for changes in what keys ++ * are down. ++ */ ++static void ++release_timer_went_off(unsigned long unused) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock,flags); ++ do_scan(); ++ /* If any keys are still down, set the timer going again. */ ++ if (any_keys_down (keybitmap)) ++ { ++ mod_timer (&key_release_timer, jiffies + key_release_interval); ++ } ++ else ++ { ++ del_timer (&autorepeat_timer); ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++} ++#endif ++ ++/* ++ * This is called when the autorepeat timer goes off. ++ */ ++static void ++autorepeat_timer_went_off(unsigned long unused) ++{ ++ int i, bitnum; ++ unsigned long tmp; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock,flags); ++ if (!any_keys_down (keybitmap)) ++ { ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return; ++ } ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ tmp = keybitmap[NUM_WORDS_IN_BITMAP-i-1]; ++ while ((bitnum = ffs(tmp)) != 0) ++ { ++ tmp &= ~(1<<(bitnum-1)); ++ /* see explanation at top of file */ ++ if ( (bitnum + (32*i)) == KEYPAD_POWER ) ++ { ++ continue; ++ } ++ (void) add_to_keybuf( (bitnum + (32*i)) | KEYDOWN ); ++ } ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ ++ mod_timer (&autorepeat_timer, jiffies + jiffies_to_next_repeat); ++} ++ ++#ifdef USE_RELEASE_TIMER ++/* ++ * Do a scan and add key events for anything that's different from the ++ * last scan. We assume keypad_lock is locked when this is called ++ * (by release_timer_went_off). ++ */ ++static void ++do_scan(void) ++{ ++ unsigned long kpas_new, kpasmkp0_new, kpasmkp1_new; ++ unsigned long kpdk_new; ++ int change; ++ ++ /* Initiate an automatic scan */ ++ KPC |= KPC_AS; ++ /* Wait for the Scan On bit to go off before */ ++ /* reading the scan registers. */ ++ while (KPAS & KPAS_SO) ++ { ++ NULL; ++ }; ++ kpas_new = KPAS; ++ kpasmkp0_new = KPASMKP0; ++ kpasmkp1_new = KPASMKP1; ++ kpdk_new = KPDK; ++ /* ++ * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off ++ */ ++ kpdk_new &= ~KPDK_DKP; ++ KPC &= ~KPC_AS; ++ ++ change = ((kpas_new != kpas) || ++ (kpasmkp0_new != kpasmkp0) || ++ (kpasmkp1_new != kpasmkp1) || ++ (kpdk_new != kpdk)); ++ ++ if (change) ++ { ++ kpas = kpas_new; ++ kpasmkp0 = kpasmkp0_new; ++ kpasmkp1 = kpasmkp1_new; ++ kpdk = kpdk_new; ++ ++ copy_bitmap (oldkeybitmap, keybitmap); ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* screen lock key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++#elif defined(CONFIG_KEYPAD_E680) ++ if (kpdk & KPDK_DK0) /* screen lock key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++ if (kpdk & KPDK_DK3) ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++ ++#elif defined(CONFIG_KEYPAD_A780) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ add_events (oldkeybitmap, keybitmap); ++ ++ wake_up_interruptible (&keypad_wait); ++ } ++} ++#endif ++ ++/* ++ * set all words in the specified bitmap to 0 ++ */ ++static inline void set_bitmap_to_zero(unsigned long b[]) { ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ b[i]=0; ++ } ++} ++ ++/* ++ * copy source bitmap to destination bitmap ++ */ ++static inline void copy_bitmap(unsigned long dest[], unsigned long source[]) { ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ dest[i]=source[i]; ++ } ++} ++ ++/* ++ * Turn on the bit position in map for the specified key code. ++ * Bit numbers start with 1 (not 0) and increase moving left within ++ * words and within the array. ++ * Bit 1 is the rightmost bit in map[NUM_WORDS_IN_BITMAP-1]. ++ * Bit 33 is the rightmost bit in map[NUM_WORDS_IN_BITMAP-2]. ++ */ ++static inline void ++turn_on_bit(unsigned long map[], int code) ++{ ++ int word, pos, p; ++ ++ /* if we have 2 words, bits 1-32 are in map[1], 33-64 in map[0] */ ++ word = (NUM_WORDS_IN_BITMAP - 1) - ((code-1) / 32); ++ /* ++ * bit 1 is 1<<0, bit 2 is 1<<1, ... bit 32 is 1 << 31, all in map[1] ++ * bit 33 is 1<<0, bit 34 is 1<<1, ... in map[0] ++ * we want this: ++ * code pos ++ * 1 0 ++ * 2 1 ++ * ... ++ * 31 30 ++ * 32 31 ++ * 33 0 ++ * 34 1 ++ * ... ++ */ ++ pos = (p = (code % 32)) == 0 ? 31 : p-1; ++ map[word] |= (1<<pos); ++} ++ ++/* ++ * Turn off the bit position in map for the specified key code. ++ * Bit positions start with 1 (not 0). ++ */ ++static inline void ++turn_off_bit(unsigned long map[], int code) ++{ ++ int word, pos, p; ++ ++ word = (NUM_WORDS_IN_BITMAP - 1) - ((code-1) / 32); ++ pos = (p = (code % 32)) == 0 ? 31 : p-1; ++ map[word] &= ~(1<<pos); ++} ++ ++/* ++ * Return 1 if any bits are down in map[] ++ */ ++static inline int ++any_keys_down (unsigned long *map) ++{ ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ /* don't count the power key */ ++ if ((i == 0) && (*map == 0x10)) ++ { ++ map++; ++ continue; ++ } ++ if (*map++) ++ { ++ return 1; ++ } ++ } ++ return 0; ++} ++static int ++__init keypad_init(void) ++{ ++ int err; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_init\n"); ++#endif ++ ++ set_bitmap_to_zero (oldkeybitmap); ++ set_bitmap_to_zero (keybitmap); ++ set_bitmap_to_zero (lastioctlbitmap); ++ ++ /* set up gpio */ ++#if defined (CONFIG_KEYPAD_V700) ++ pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); /* KP_MKIN<6> */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); /* KP_MKIN<5> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_E680_P4A) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_KEYPAD_E680) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++#elif defined (CONFIG_KEYPAD_A780) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ ++#elif defined(CONFIG_KEYPAD_MAINSTONE) ++ /* from Intel driver */ ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#endif ++ ++ /* set keypad control register */ ++ KPC = (KPC_ASACT | /* automatic scan on activity */ ++ KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ ++#if defined (CONFIG_KEYPAD_V700) ++ (3<<23) | /* 4 columns */ ++ (6<<26) | /* 7 rows */ ++#elif defined(CONFIG_E680_P4A) ++ (3<<23) | /* 4 columns */ ++ (2<<26) | /* 3 rows */ ++ (4<<6) | /* 4# direct key */ ++#elif defined(CONFIG_KEYPAD_E680) ++ (5<<23) | /* 4 columns */ ++ (4<<26) | /* 3 rows */ ++ (5<<6) | /* 5# direct keys */ ++#elif defined(CONFIG_KEYPAD_A780) ++ (4<<23) | /* 5 columns */ ++ (4<<26) | /* 5 rows */ ++ (0<<6) | /* 1# direct keys */ ++#endif ++ KPC_MS7_0); /* scan all columns */ ++ ++ CKEN |= CKEN19_KEYPAD; ++ ++ err = request_irq (IRQ_KEYPAD, kp_interrupt, 0, "Keypad", NULL); ++ if (err) ++ { ++ printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", ++ IRQ_KEYPAD, err); ++ CKEN &= ~CKEN19_KEYPAD; ++ return -ENODEV; ++ } ++ ++ if (misc_register (&keypad_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypad driver\n"); ++ return -EIO; ++ } ++ if (misc_register (&keypadB_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypadB driver\n"); ++ misc_deregister(&keypad_misc_device); ++ return -EIO; ++ } ++ if (misc_register (&keypadI_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypadI driver\n"); ++ misc_deregister(&keypad_misc_device); ++ misc_deregister(&keypadB_misc_device); ++ return -EIO; ++ } ++ ++#ifdef USE_RELEASE_TIMER ++ init_timer (&key_release_timer); ++ key_release_timer.function = release_timer_went_off; ++#endif ++ init_timer (&autorepeat_timer); ++ autorepeat_timer.function = autorepeat_timer_went_off; ++ ++ /* ++ * we want the phone to be able to tell the status of the screen ++ * lock switch at power-up time ++ */ ++ kpdk = KPDK; /* read direct key register */ ++ /* ++ * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off ++ */ ++ kpdk &= ~KPDK_DKP; ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++#elif defined(CONFIG_KEYPAD_E680) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#elif defined(CONFIG_KEYPAD_A780) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); ++#if defined(CONFIG_E680_P4A) ++/*93,97,100,101,102*/ ++ PKWR = 0xe4400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++/*93,96,97,98,100,101,102*/ ++ PKWR = 0xee400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_A780) ++/*93,97,98,100,101,102*/ ++ PKWR = 0xec400; ++/*103 104 105 106 107*/ ++ PGSR3 |= 0xf80; ++#endif ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) ++#ifdef CONFIG_PM ++ keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); ++ PGSR3 |= 0x8; ++#endif ++#endif ++ ++ KPC |= (KPC_DIE | KPC_MIE); ++ KPKDI = 0x40; ++ return 0; ++} ++ ++static void ++__exit keypad_exit(void) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_exit\n"); ++#endif ++ misc_deregister(&keypad_misc_device); ++ misc_deregister(&keypadB_misc_device); ++ misc_deregister(&keypadI_misc_device); ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) ++#ifdef CONFIG_PM ++ pm_unregister(keypadI_pm_dev); ++#endif ++#endif ++ ++ CKEN &= ~CKEN19_KEYPAD; ++} ++ ++module_init (keypad_init); ++module_exit (keypad_exit); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/keypad.h linux-2.6.16/drivers/misc/ezx/keypad.h +--- linux-2.6.16.orig/drivers/misc/ezx/keypad.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/keypad.h 2006-06-03 11:14:56.342323920 +0200 +@@ -0,0 +1,104 @@ ++#ifndef __DRIVER_CHAR_KEYPAD_H ++#define __DRIVER_CHAR_KEYPAD_H ++ ++/* ++ * linux/drivers/char/keypad.h ++ * ++ * (c) Copyright Motorola 2003, All rights reserved. ++ */ ++ ++#include <asm/hardware.h> ++#include <linux/keypad.h> ++ ++/** ++ * /dev/keypad is the main keypad device. Opening this device provides access ++ * for read(), ioctl() and poll()/select(). Only one process at a time ++ * can open this device. ++ */ ++#define KEYPAD_NAME "keypad" ++#define KEYPAD_MINOR 0xf0 /* 240 */ ++ ++/** ++ * /dev/keypadB can be opened for ioctl() and poll()/select(). ++ * Only one process at a time can open this device. ++ */ ++#define KEYPAD_BITMAP_NAME "keypadB" ++#define KEYPAD_BITMAP_MINOR 0xf1 /* 241 */ ++ ++/** ++ * /dev/keypadI can be opened for ioctl(INSERT_EVENT). ++ * Any number of devices can open this simultaneously. ++ */ ++#define KEYPAD_INSERT_NAME "keypadI" ++#define KEYPAD_INSERT_MINOR 0xf2 /* 242 */ ++ ++/* ++ * KEYBUF_SIZE must be a power of 2 to avoid performance-destroying ++ * integer divisions in the compiled code. ++ * Each keypad event is a short, so a buffer n bytes long can hold ++ * n/2 keypad events. ++ */ ++#define KEYBUF_SIZE 256 ++ ++#if 0 ++#define KPC __REG(0x41500000) /* control register */ ++#define KPDK __REG(0x41500008) /* direct key register */ ++#define KPAS __REG(0x41500020) /* automatic scan register */ ++#define KPASMKP0 __REG(0x41500028) /* auto scan multiple key press reg 0 */ ++#define KPASMKP1 __REG(0x41500030) /* auto scan multiple key press reg 1 */ ++#define KPKDI __REG(0x41500048) /* debounce interval register */ ++ ++#define KPC_RSRVD0 0x80000000 /* reserved */ ++#define KPC_AS 0x40000000 /* automatic scan */ ++#define KPC_ASACT 0x20000000 /* automatic scan on activity */ ++#define KPC_MKRN 0x1c000000 /* number of matrix keypad rows - 1 */ ++#define KPC_MKCN 0x03800000 /* number of matrix keypad columns - 1 */ ++#define KPC_MI 0x00400000 /* matrix interrupt, reset when read */ ++#define KPC_IMKP 0x00200000 /* ignore multiple key press */ ++#define KPC_MS7_0 0x001fe000 /* MS7-MS0 assert to scan columns */ ++#define KPC_MS7 0x00100000 /* MS7 assert to scan column */ ++#define KPC_MS6 0x00080000 /* MS6 assert to scan column */ ++#define KPC_MS5 0x00040000 /* MS5 assert to scan column */ ++#define KPC_MS4 0x00020000 /* MS4 assert to scan column */ ++#define KPC_MS3 0x00010000 /* MS3 assert to scan column */ ++#define KPC_MS2 0x00008000 /* MS2 assert to scan column */ ++#define KPC_MS1 0x00004000 /* MS1 assert to scan column */ ++#define KPC_MS0 0x00002000 /* MS0 assert to scan column */ ++#define KPC_ME 0x00001000 /* matrix keypad enable */ ++#define KPC_MIE 0x00000800 /* matrix interrupt enable */ ++#define KPC_RSRVD1 0x00000600 /* reserved */ ++#define KPC_DKN 0x000001c0 /* number of direct keys - 1 */ ++#define KPC_DI 0x00000020 /* direct interrupt bit, reset when read */ ++#define KPC_RSRVD2 0x00000010 /* reserved */ ++#define KPC_REE1 0x00000008 /* rotary encoder 1 enable */ ++#define KPC_REE0 0x00000004 /* rotary encoder 0 enable */ ++#define KPC_DE 0x00000002 /* direct keypad enable */ ++#define KPC_DIE 0x00000001 /* direct keypad interrupt enable */ ++ ++#define KPC_7rows 0x18000000 /* 6 in KPC_MKRN */ ++#define KPC_4cols 0x01800000 /* 3 in KPC_MKCN */ ++/* ++ * bits in Direct Key register ++ */ ++#define KPDK_DKP (0x1 << 31) /* on if direct key pressed since last read */ ++#define KPDK_DK7 (0x1 << 7) ++#define KPDK_DK6 (0x1 << 6) ++#define KPDK_DK5 (0x1 << 5) ++#define KPDK_DK4 (0x1 << 4) ++#define KPDK_DK3 (0x1 << 3) ++#define KPDK_DK2 (0x1 << 2) ++#define KPDK_DK1 (0x1 << 1) ++#define KPDK_DK0 (0x1 << 0) ++ ++ ++#endif ++ ++#define KPKDI_BITS 0xff /* bits in KPKDI register for debounce interval */ ++#define KPAS_MUKP 0x7c000000 /* KPAS bits 30-26 */ ++#define MUKP_NO_KEYS 0x00000000 /* value of MUKP if no keys are down */ ++#define MUKP_ONE_KEY 0x04000000 /* value of MUKP if one key is down */ ++#define KPAS_SO 0x80000000 /* scan on bit */ ++#define KPAS_RP 0x000000f0 /* row of single key */ ++#define KPAS_CP 0x0000000f /* column of single key */ ++ ++#endif /* __DRIVER_CHAR_KEYPAD_H */ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/keypad-panasonic.c linux-2.6.16/drivers/misc/ezx/keypad-panasonic.c +--- linux-2.6.16.orig/drivers/misc/ezx/keypad-panasonic.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/keypad-panasonic.c 2006-06-03 11:14:56.340324224 +0200 +@@ -0,0 +1,1569 @@ ++/* ++ * linux/drivers/char/keypad.c ++ * ++ * (c) Copyright Motorola 2003, All rights reserved. ++ */ ++ ++/* ++ * This driver is for three devices: /dev/keypad, /dev/keypadB and ++ * /dev/keypadI. ++ * /dev/keypad would be used for reading the key event buffer. ++ * It can be opened by one process at a time. ++ * /dev/keypadB would be used for ioctl(KEYPAD_IOC_GETBITMAP). ++ * It can be opened by one process at a time. ++ * /dev/keypadI would be used for ioctl(KEYPAD_IOC_INSERT_EVENT). ++ * It can be opened any number of times simultaneously. ++ * ++ * The bulverde specification is ambiguous about when interrupts happen ++ * for released keys. We were told by Intel that we won't ++ * get interrupts for released keys except in the case when multiple ++ * keys were down and they've all been released. So we implemented ++ * a timer to poll for changes in key states. ++ * ++ * The E680 P2 hardware gives us interrupts when any key is released, ++ * whether it was the only key down or not, and whether it's the last ++ * of multiple keys to be released or not. We don't know whether this ++ * behavior will continue in future hardware releases, so the release ++ * timer is still in the code, #ifdef'd with USE_RELEASE_TIMER. On the ++ * P2 hardware, the code works with or without USE_RELEASE_TIMER defined. ++ * If the release interrupts are always going to happen, we can remove ++ * the #ifdef'd code. ++ * ++ * With the P2 hardware, the power key bit in the KPDK register is always ++ * on. We don't know if this is correct behavior or not, but in any case ++ * it certainly causes trouble to have that key autorepeating indefinitely, ++ * or to be checking indefinitely for the key to be released (if we're doing ++ * release polling). ++ * ++ * For now, any_keys_down() returns 0 if the power key is the only one down. ++ * . At interrupt time, if the power key is the only one down we don't ++ * set the autorepeat timer or release timer. ++ * . When the release timer goes off, if the power key is the only one ++ * still down we don't set the timer again. ++ * . When the autorepeat timer goes off, if the power key is the only ++ * one down we don't generate any events. ++ * In autorepeat_timer_went_off, if there are non-power keys down, while we're ++ * looking through the whole bitmap of keys down we ignore the power key. ++ */ ++ ++#include <linux/tty.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/bitops.h> ++#include <linux/param.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <linux/pm.h> ++#include <linux/apm_bios.h> ++#include "keypad.h" ++#include <asm/arch/irqs.h> ++#include "asm/arch/ezx.h" ++#include <linux/delay.h> ++ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++static struct pm_dev *keypadI_pm_dev; ++static int kpc_res,kpkdi_res; ++static int GPIO_TC_MM_STATE = 1; ++extern unsigned char pxafb_ezx_getLCD_status(void); ++#endif ++/* ++ * This is the number of microseconds we wait before checking to see if any ++ * keys have been released. ++ */ ++#define RDELAY 200 ++ ++#define KEYBUF_EMPTY() (keybuf_start == keybuf_end) ++#define KEYBUF_FULL() ( ((keybuf_end+1)%KEYBUF_SIZE) == keybuf_start) ++#define KEYBUF_INC(x) ((x) = (((x)+1) % KEYBUF_SIZE)) ++ ++static int keypad_open (struct inode *, struct file *); ++static int keypad_close (struct inode *, struct file *); ++static int keypad_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++static unsigned int keypad_poll (struct file *, poll_table *); ++static ssize_t keypad_read (struct file *, char *, size_t, loff_t *); ++ ++static int keypadB_open (struct inode *, struct file *); ++static int keypadB_close (struct inode *, struct file *); ++static int keypadB_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++static unsigned int keypadB_poll (struct file *, poll_table *); ++ ++static int keypadI_open(struct inode *, struct file *); ++static int keypadI_close(struct inode *, struct file *); ++static int keypadI_ioctl (struct inode *, struct file *, ++ unsigned int, unsigned long); ++ ++static void kp_interrupt (int, void *, struct pt_regs *); ++#ifdef USE_RELEASE_TIMER ++static void release_timer_went_off (unsigned long); ++static void do_scan(void); ++#endif ++static void autorepeat_timer_went_off (unsigned long); ++ ++static int add_to_keybuf (unsigned short); ++static int add_events (unsigned long *, unsigned long *); ++static int insert_event (unsigned short); ++static unsigned short get_from_keybuf (void); ++static void scan_to_bitmap ++ (unsigned long, unsigned long, unsigned long, unsigned long *); ++static inline void set_bitmap_to_zero(unsigned long b[]); ++static inline void copy_bitmap(unsigned long dest[], unsigned long source[]); ++static inline void turn_on_bit(unsigned long map[], int); ++static inline void turn_off_bit(unsigned long map[], int); ++static inline int any_keys_down (unsigned long *); ++ ++/* ++ * keybuf is a circular buffer to hold keypad events. ++ * keybuf_start is the index of the first event. ++ * keybuf_end is one more than the index of the last event. ++ * The buffer is empty when keybuf_start == keybuf_end. ++ * We only use KEYBUF_SIZE-1 entries in the buffer so we can tell ++ * when it's full without needing another variable to tell us. ++ * The buffer is full when (keybuf_end+1)%KEYBUF_SIZE == keybuf_start. ++ */ ++static unsigned short keybuf[KEYBUF_SIZE]; ++static int keybuf_start = 0; ++static int keybuf_end = 0; ++ ++static DECLARE_WAIT_QUEUE_HEAD(keypad_wait); ++static spinlock_t keypad_lock = SPIN_LOCK_UNLOCKED; ++ ++static int reading_opens = 0; ++static int bitmap_opens = 0; ++ ++/* previous bitmap of keys down */ ++static unsigned long oldkeybitmap[NUM_WORDS_IN_BITMAP]; ++/* current bitmap of keys down */ ++static unsigned long keybitmap[NUM_WORDS_IN_BITMAP]; ++/* last bitmap read by ioctl */ ++static unsigned long lastioctlbitmap[NUM_WORDS_IN_BITMAP]; ++ ++static unsigned long kpas = 0; /* last value of kpas */ ++static unsigned long kpasmkp0 = 0; /* last value of kpasmkp0 */ ++static unsigned long kpasmkp1 = 0; /* last value of kpasmkp1 */ ++static unsigned long kpasmkp2 = 0; /* last value of kpasmkp2 */ ++static unsigned long kpdk = 0; /* last value of kpdk */ ++ ++#ifdef USE_RELEASE_TIMER ++static struct timer_list key_release_timer; ++static int key_release_interval = RDELAY * HZ/1000; ++#endif ++ ++static int do_autorepeat = 1; ++static long jiffies_to_first_repeat = 30; ++static long jiffies_to_next_repeat = 30; ++static struct timer_list autorepeat_timer; ++ ++extern int lockscreen_flag; ++ ++static int ++keypad_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypad_open\n"); ++#endif ++ spin_lock(keypad_lock); ++ if (reading_opens > 0) ++ { ++ spin_unlock(keypad_lock); ++ return -EBUSY; ++ } ++ reading_opens++; ++ spin_unlock(keypad_lock); ++ ++ return 0; ++} ++ ++static int ++keypadB_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypadB_open\n"); ++#endif ++ spin_lock(keypad_lock); ++ if (bitmap_opens > 0) ++ { ++ spin_unlock(keypad_lock); ++ return -EBUSY; ++ } ++ bitmap_opens++; ++ /* ++ * poll returns when lastioctlbitmap is different from keybitmap. ++ * we set lastioctlbitmap to keybitmap here so that a poll right ++ * after an open returns when the bitmap is different from when ++ * the open was done, not when the bitmap is different from the ++ * last time some other process read it ++ */ ++ copy_bitmap(lastioctlbitmap, keybitmap); ++ spin_unlock(keypad_lock); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_KEYPAD_E680) ++#ifdef CONFIG_PM ++static int keypadI_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ break; ++ case PM_RESUME: ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ if(GPIO_TC_MM_STATE == 1) ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ else ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif ++#endif ++ ++static int ++keypadI_open(struct inode *inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG "keypadI_open\n"); ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ ++ return 0; ++} ++ ++static int ++keypad_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_close\n"); ++#endif ++ /* ++ * this decrement of reading_opens doesn't have to be protected because ++ * it can only be executed to close the single open of /dev/keypad ++ */ ++ reading_opens--; ++ return 0; ++} ++ ++static int ++keypadB_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadB_close\n"); ++#endif ++ /* ++ * this decrement of bitmap_opens doesn't have to be protected because ++ * it can only be executed to close the single open of /dev/keypadB ++ */ ++ bitmap_opens--; ++ return 0; ++} ++ ++static int ++keypadI_close(struct inode * inode, struct file *file) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadI_close\n"); ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ ++ return 0; ++} ++ ++/** ++ * Add the specified event to the key buffer. ++ * This should be called with keypad_lock locked. ++ */ ++static int ++add_to_keybuf (unsigned short event) ++{ ++ if (KEYBUF_FULL()) ++ { ++ return -ENOMEM; ++ } ++ keybuf[keybuf_end] = event; ++ KEYBUF_INC (keybuf_end); ++ ++#if CONFIG_APM ++ queue_apm_event(KRNL_KEYPAD, NULL); ++#endif ++ printk("add keypad event = %x\n", event); ++ return 0; ++} ++ ++/* ++ * code[c*8+r] is the key code for the key that's down when there's a 1 ++ * in column c, row r of the scan registers. ++ */ ++ ++#if defined(CONFIG_KEYPAD_V700) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_RIGHT, ++ KEYPAD_POUND, KEYPAD_0, KEYPAD_9, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_2, KEYPAD_4, KEYPAD_6, KEYPAD_8, ++ KEYPAD_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_MENU, KEYPAD_1, KEYPAD_3, KEYPAD_5, ++ KEYPAD_STAR, KEYPAD_VOLUP, KEYPAD_VOLDOWN, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, ++ KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, KEYPAD_NONE ++}; ++ ++/* end CONFIG_KEYPAD_V700 */ ++#elif defined(CONFIG_E680_P4A) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_RIGHT, KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_GAME_L, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_A, KEYPAD_B, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++}; ++ ++/* end CONFIG_E680_P4A */ ++#elif defined(CONFIG_KEYPAD_E680) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_UP, KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_RIGHT, KEYPAD_LEFT, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_NONE, KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, KEYPAD_NONE, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ ++}; ++/*end CONFIG_KEYPAD_E680 */ ++#elif defined(CONFIG_KEYPAD_A780) ++int ++scanbit_to_keycode[] = { ++ /* col 0 */ ++ KEYPAD_OK, KEYPAD_1, KEYPAD_4, KEYPAD_7, ++ KEYPAD_STAR, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 1 */ ++ KEYPAD_MENU, KEYPAD_2, KEYPAD_5, KEYPAD_8, ++ KEYPAD_0, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 2 */ ++ KEYPAD_CANCEL, KEYPAD_3, KEYPAD_6, KEYPAD_9, ++ KEYPAD_POUND, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 3 */ ++ KEYPAD_JOG_UP, KEYPAD_JOG_MIDDLE, KEYPAD_PTT, KEYPAD_NONE, ++ KEYPAD_JOG_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++ /* col 4 */ ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_HOME, ++ KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, ++}; ++#endif ++ ++/* ++ * Decode the specified scan register values into the bitmap pointed ++ * to by the last argument. The bitmap will contain a 1 ++ * for each key that's down. ++ * ++ * Only the 1st two of the four scan registers are used. ++ */ ++static void ++scan_to_bitmap(unsigned long kpas, unsigned long kpasmkp0, ++ unsigned long kpasmkp1, unsigned long bitmap[]) ++{ ++ int row, col; ++ int bitnum; ++ unsigned long scanmap; ++ ++ set_bitmap_to_zero (bitmap); ++ ++ if ((kpas & KPAS_MUKP) == MUKP_NO_KEYS) ++ { ++ return; ++ } ++ ++ if ((kpas & KPAS_MUKP) == MUKP_ONE_KEY) ++ { ++ row = (kpas & KPAS_RP) >> 4; ++ col = kpas & KPAS_CP; ++#if defined(CONFIG_KEYPAD_A780) ++ if( !((row == 3)&&(col == 3)) ) ++ { ++#endif ++ turn_on_bit (bitmap, scanbit_to_keycode[col*8 + row]); ++#if defined(CONFIG_KEYPAD_A780) ++ } ++#endif ++ ++ return; ++ } ++ ++ /* reach here if multiple keys */ ++ scanmap = (kpasmkp0 & 0x7f) | ((kpasmkp0 & 0x7f0000) >> 8) | ++ ((kpasmkp1 & 0x7f) << 16) | ((kpasmkp1 & 0x7f0000) << 8); ++ while ((bitnum = ffs(scanmap)) != 0) ++ { ++ /* ++ * ffs returns bit numbers starting with 1, so subtract 1 to index ++ * into scanbit_to_keycode[] ++ */ ++ turn_on_bit (bitmap, scanbit_to_keycode[bitnum-1]); ++ scanmap &= ~(1<<(bitnum-1)); ++ } ++#if defined(CONFIG_KEYPAD_A780) ++ kpasmkp2 = KPASMKP2; ++ kpasmkp2 &= 0x8; ++ while ((bitnum = ffs(kpasmkp2)) !=0) ++ { ++ turn_on_bit (bitmap, scanbit_to_keycode[32+bitnum-1]); ++ kpasmkp2 &= ~(1<<(bitnum-1)); ++ } ++#endif ++} ++ ++/* ++ * Add events indicated by the difference between the last scan (oldbitmap) ++ * and this one (newbitmap) to the input buffer. ++ * Return nonzero right away if any of the events can't be added. ++ * A zero return means all the events were added. ++ * This should be called with keypad_lock locked. ++ */ ++static int ++add_events (unsigned long *oldbitmap, unsigned long *newbitmap) ++{ ++ unsigned long tmpmap, onebitmap; ++ int bitnum, i, ret; ++ ++ /* generate events for keys that were down before and are up now */ ++ for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) ++ { ++ tmpmap = oldbitmap[i]; ++ while ((bitnum = ffs(tmpmap)) != 0) ++ { ++ onebitmap = 1<<(bitnum-1); ++ if ((newbitmap[i] & onebitmap) == 0) ++ { ++ ret = add_to_keybuf(bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYUP)); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ tmpmap &= ~onebitmap; ++ } ++ } ++ /* generate events for down keys that were up before */ ++ for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) ++ { ++ tmpmap = newbitmap[i]; ++ while ((bitnum = ffs(tmpmap)) != 0) ++ { ++ onebitmap = 1<<(bitnum-1); ++ if ((oldbitmap[i] & onebitmap) == 0) ++ { ++ ret = add_to_keybuf ++ (bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYDOWN)); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ tmpmap &= ~onebitmap; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * do the INSERT_EVENT ioctl ++ */ ++static int ++insert_event (unsigned short event) ++{ ++ unsigned long flags; ++ int ret; ++ ++ if (KEYCODE(event) > KEYPAD_MAXCODE) ++ { ++ printk(KERN_WARNING " inserted key code %d too big\n", ++ KEYCODE(event)); ++ return -EINVAL; ++ } ++ spin_lock_irqsave(&keypad_lock, flags); ++ if (KEY_IS_DOWN(event)) ++ { ++ turn_on_bit(keybitmap, KEYCODE(event)); ++ } ++ else ++ { ++ turn_off_bit (keybitmap, event); ++ } ++ if ((ret = add_to_keybuf(event)) < 0) ++ { ++ spin_unlock_irqrestore(&keypad_lock,flags); ++ return ret; ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ return 0; ++} ++ ++static int ++keypad_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int interval; /* debounce interval */ ++ int imkp; /* Ignore Multiple Key Press bit */ ++ struct autorepeatinfo ar; /* autorepeat information */ ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypad_ioctl: 0x%x\n", cmd); ++#endif ++ switch (cmd) ++ { ++ case KEYPAD_IOC_INSERT_EVENT: ++ return insert_event ((unsigned short)arg); ++ break; ++ case KEYPAD_IOC_GET_DEBOUNCE_INTERVAL: ++ interval = KPKDI & KPKDI_BITS; ++ return put_user(interval, (unsigned long *)arg); ++ break; ++ case KEYPAD_IOC_SET_DEBOUNCE_INTERVAL: ++ interval = (unsigned short)arg; ++ if (interval > KPKDI_BITS) ++ { ++ return -EINVAL; ++ } ++ KPKDI &= ~KPKDI_BITS; ++ KPKDI |= interval; ++ break; ++ case KEYPAD_IOC_GET_IMKP_SETTING: ++ imkp = ((KPC & KPC_IMKP) == KPC_IMKP); ++ return put_user(imkp, (unsigned char *)arg); ++ break; ++ case KEYPAD_IOC_SET_IMKP_SETTING: ++ imkp = (unsigned char)arg; ++ if (imkp) ++ { ++ KPC |= KPC_IMKP; ++ } ++ else ++ { ++ KPC &= ~KPC_IMKP; ++ } ++ break; ++ case KEYPAD_IOC_SET_AUTOREPEAT: ++ if (copy_from_user (&ar, (void *)arg, ++ sizeof(struct autorepeatinfo)) != 0) ++ { ++ return -EFAULT; ++ } ++ do_autorepeat = ar.r_repeat; ++ /* times are specified in milliseconds; convert to jiffies */ ++ jiffies_to_first_repeat = ar.r_time_to_first_repeat * HZ/1000; ++ jiffies_to_next_repeat = ar.r_time_between_repeats * HZ/1000; ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int ++keypadB_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long flags; ++ int ret; ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypadB_ioctl: 0x%x\n", cmd); ++#endif ++ if (cmd == KEYPAD_IOC_INSERT_EVENT) ++ { ++ return insert_event ((unsigned short)arg); ++ } ++ else if (cmd == KEYPAD_IOC_GETBITMAP) ++ { ++ spin_lock_irqsave(&keypad_lock, flags); ++ ret = copy_to_user ((void *)arg, keybitmap, ++ NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); ++ copy_bitmap (lastioctlbitmap, keybitmap); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return (ret != 0) ? -EFAULT : 0; ++ } ++ else ++ { ++ return -ENOTTY; ++ } ++} ++ ++static int ++keypadI_ioctl (struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long flags; ++ int ret; ++ ++#ifdef KDEBUG ++ printk (KERN_DEBUG "keypadI_ioctl: 0x%x\n", cmd); ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ if( cmd == KEYPADI_TURN_ON_LED ) ++ { ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ GPIO_TC_MM_STATE = 0; ++ PGSR3 &= ~GPIO_bit(GPIO_TC_MM_EN); ++ return 0; ++ } ++ if( cmd == KEYPADI_TURN_OFF_LED ) ++ { ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ GPIO_TC_MM_STATE = 1; ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++ return 0; ++ } ++#endif ++ ++ if (cmd == KEYPAD_IOC_INSERT_EVENT) ++ { ++ return insert_event ((unsigned short)arg); ++ } ++ else if (cmd == KEYPAD_IOC_GETBITMAP) ++ { ++ spin_lock_irqsave(&keypad_lock, flags); ++ ret = copy_to_user ((void *)arg, keybitmap, ++ NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); ++ copy_bitmap (lastioctlbitmap, keybitmap); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return (ret != 0) ? -EFAULT : 0; ++ } ++ else ++ { ++ return -ENOTTY; ++ } ++} ++ ++static unsigned int ++keypad_poll( struct file *file, poll_table * wait ) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_poll\n"); ++#endif ++ poll_wait(file, &keypad_wait, wait); ++ ++ if (!KEYBUF_EMPTY()) ++ { ++ return (POLLIN | POLLRDNORM); ++ } ++ return 0; ++} ++ ++static unsigned int ++keypadB_poll( struct file *file, poll_table * wait ) ++{ ++ int i; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypadB_poll\n"); ++#endif ++ poll_wait(file, &keypad_wait, wait); ++ ++ for (i=0; i < NUM_WORDS_IN_BITMAP; i++) ++ { ++ if (lastioctlbitmap[i] != keybitmap[i]) ++ { ++ return (POLLIN | POLLRDNORM); ++ } ++ } ++ return 0; ++} ++ ++static unsigned short ++get_from_keybuf(void) ++{ ++ unsigned short event; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock, flags); ++ event = keybuf[keybuf_start]; ++ KEYBUF_INC (keybuf_start); ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return event; ++} ++ ++static ssize_t ++keypad_read(struct file *file, char *buf, size_t count, loff_t *ptr) ++{ ++ int i, ret; ++ unsigned short event; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_read\n"); ++#endif ++ /* Can't seek (pread) on this device */ ++ if (ptr != &file->f_pos) ++ { ++ return -ESPIPE; ++ } ++ ++ if (count == 0) ++ { ++ return 0; ++ } ++ ++ if (KEYBUF_EMPTY()) ++ { ++ /* buffer is empty */ ++ /* if not blocking return */ ++ if (file->f_flags & O_NONBLOCK) ++ { ++ return -EAGAIN; ++ } ++ /* blocking, so wait for input */ ++ ret = wait_event_interruptible(keypad_wait, !KEYBUF_EMPTY()); ++ if (ret) ++ { ++ return ret; ++ } ++ } ++ ++ i = 0; ++ /* copy events until we have what the user asked for or we run out */ ++ while ((i+1 < count) && !KEYBUF_EMPTY()) ++ { ++ event = get_from_keybuf(); ++ if ((ret = put_user(event, (unsigned short *)buf)) != 0) ++ { ++ return ret; ++ } ++ buf += EVENTSIZE; ++ i += EVENTSIZE; ++ } ++ return i; ++} ++ ++#ifdef CONFIG_PM ++static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int pksr; ++ ++ pksr = PKSR; ++ PKSR = 0xfffff; ++ switch(req) ++ { ++ case PM_SUSPEND: ++ kpc_res = KPC; ++ kpkdi_res = KPKDI; ++ set_bitmap_to_zero (oldkeybitmap); ++ set_bitmap_to_zero (keybitmap); ++ set_bitmap_to_zero (lastioctlbitmap); ++ kpas = 0; ++ kpasmkp0 = 0; ++ kpasmkp1 = 0; ++ kpasmkp2 = 0; ++ kpdk = 0; ++ break; ++ case PM_RESUME: ++ KPC = kpc_res; ++ KPKDI = kpkdi_res; ++#if CONFIG_APM ++#if defined(CONFIG_E680_P4A) ++ if (pksr & 0xe4400) /*93 97 100 101 102 key is pressed (switch on) */ ++ { ++ queue_apm_event(KRNL_KEYPAD, NULL); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++ if (pksr & 0xee400) /*93 96 97 98 190 101 102 key is pressed */ ++ { ++ queue_apm_event(KRNL_KEYPAD, NULL); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ if (pksr & 0x2000) ++ turn_on_bit (keybitmap, KEYPAD_A); ++ if (pksr & 0x8000) ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_A780) ++ printk("pksr = %x\n",pksr); ++ if (pksr & 0xec400) /* 93 97 98 100 101 102 key is pressed */ ++ { ++ queue_apm_event(KRNL_KEYPAD, NULL); ++ if (pksr & 0x400) ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#endif ++ ++ break; ++ } ++ return 0; ++} ++#endif ++ ++/* for /dev/keypad */ ++static struct file_operations ++keypad_fops = { ++ read: keypad_read, ++ llseek: no_llseek, ++ poll: keypad_poll, ++ ioctl: keypad_ioctl, ++ open: keypad_open, ++ release: keypad_close, ++}; ++ ++static struct miscdevice ++keypad_misc_device = { ++ KEYPAD_MINOR, ++ KEYPAD_NAME, ++ &keypad_fops, ++}; ++ ++/* ++ * for /dev/keypadB. ++ * read() isn't defined here. calls to read() will return -1 with EINVAL. ++ */ ++static struct file_operations ++keypadB_fops = { ++ llseek: no_llseek, ++ poll: keypadB_poll, ++ ioctl: keypadB_ioctl, ++ open: keypadB_open, ++ release: keypadB_close, ++}; ++ ++static struct miscdevice ++keypadB_misc_device = { ++ KEYPAD_BITMAP_MINOR, ++ KEYPAD_BITMAP_NAME, ++ &keypadB_fops, ++}; ++ ++/* ++ * for /dev/keypadI. ++ * read() isn't defined here. calls to read() will return -1 with EINVAL. ++ */ ++static struct file_operations ++keypadI_fops = { ++ llseek: no_llseek, ++ ioctl: keypadI_ioctl, ++ open: keypadI_open, ++ release: keypadI_close, ++}; ++ ++static struct miscdevice ++keypadI_misc_device = { ++ KEYPAD_INSERT_MINOR, ++ KEYPAD_INSERT_NAME, ++ &keypadI_fops, ++}; ++ ++#ifdef CONFIG_PANIC_LOG ++static u32 panic_bug_used =0; ++static int panic_key = 0; ++#endif ++ ++/* Interrupt Handler for KEYPAD */ ++static void ++kp_interrupt(int irq, void *ptr, struct pt_regs *regs) ++{ ++ unsigned long flags; ++ unsigned long kpc_val; ++ ++#ifdef USE_RELEASE_TIMER ++ del_timer (&key_release_timer); ++#endif ++ del_timer (&autorepeat_timer); ++ spin_lock_irqsave(&keypad_lock,flags); ++ ++ /* ack interrupt */ ++ kpc_val = KPC; ++ ++ /* matrix interrupt */ ++ if (kpc_val & KPC_MI) ++ { ++/* ++ * The Intel driver turned on KPC_AS here. It doesn't seem that we ++ * would need to do that, because getting an interrupt means that ++ * a scan was just done. For now, I've commented out the setting ++ * and clearing of this bit. ++ KPC |= KPC_AS; ++ */ ++ while (KPAS & KPAS_SO) ++ { ++ /* Wait for the Scan On bit to go off before */ ++ /* reading the scan registers. */ ++ NULL; ++ }; ++ ++ kpas = KPAS; ++ kpasmkp0 = KPASMKP0; ++ kpasmkp1 = KPASMKP1; ++ kpasmkp2 = KPASMKP2; ++ ++ } ++ ++ /* direct interrupt */ ++ if (kpc_val & KPC_DI) ++ { ++ kpdk = KPDK; ++ /* ++ * reading the register turns off the "key pressed since last read" ++ * bit if it was on, so we turn it off ++ */ ++ kpdk &= ~KPDK_DKP; ++ } ++ ++ copy_bitmap (oldkeybitmap, keybitmap); ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++#elif defined(CONFIG_KEYPAD_E680) ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); ++ if (kpdk & KPDK_DK0) /* VR key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++ if (kpdk & KPDK_DK3) ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++ ++#elif defined(CONFIG_KEYPAD_A780) ++#ifdef CONFIG_PANIC_LOG ++ panic_key = 0; ++#endif ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1 & 0xfff7ffff, keybitmap); ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++#ifdef CONFIG_PANIC_LOG ++ panic_key = 1; ++#endif ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++#if defined(CONFIG_KEYPAD_A780) ++ kpasmkp2 = KPASMKP2; ++ if ( (kpasmkp2 & 0x17) || (kpasmkp1 & 0x80000) ) ++ { ++ if( kpasmkp2 == 0x5 && kpasmkp1 == 0x80000 ) ++ { ++ printk("Jay Up key pressed\n"); ++ turn_on_bit(keybitmap, KEYPAD_UP); ++ } ++ else ++ { ++ if( kpasmkp2 == 0x14 && kpasmkp1 == 0x80000) ++ { ++ printk("Jay Right key pressed\n"); ++ turn_on_bit(keybitmap, KEYPAD_RIGHT); ++ } ++ else ++ { ++ if( kpasmkp2 == 0x12 && kpasmkp1 == 0x80000) ++ { ++ printk("Jay Down key pressed\n"); ++ turn_on_bit(keybitmap, KEYPAD_DOWN); ++ } ++ else ++ { ++ if( kpasmkp2 == 0x3 && kpasmkp1 == 0x80000) ++ { ++ printk("Jay Left key pressed\n"); ++ turn_on_bit(keybitmap, KEYPAD_LEFT); ++ } ++ else ++ { ++ if( kpasmkp1 == 0x80000 && (kpasmkp2 & 0x17) == 0) ++ ++ { ++ printk("Jay Center key pressed\n"); ++ turn_on_bit(keybitmap, KEYPAD_CENTER); ++ } ++ } ++ } ++ } ++ } ++ } ++#endif ++ ++ ++ (void) add_events (oldkeybitmap, keybitmap); ++ ++ /* If any keys are down, set a timer to check for key release */ ++ /* and one for autorepeat if that's on. */ ++ if (any_keys_down (keybitmap)) ++ { ++#ifdef USE_RELEASE_TIMER ++ key_release_timer.expires = (jiffies + key_release_interval); ++ add_timer (&key_release_timer); ++#endif ++ if (do_autorepeat) ++ { ++ autorepeat_timer.expires = (jiffies + jiffies_to_first_repeat); ++ add_timer (&autorepeat_timer); ++ } ++ } ++ ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ printk("keypad interrupt occurred\n"); ++} ++ ++#ifdef USE_RELEASE_TIMER ++/* ++ * This is called when the key release timer goes off. That's the ++ * only time it should be called. Check for changes in what keys ++ * are down. ++ */ ++static void ++release_timer_went_off(unsigned long unused) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&keypad_lock,flags); ++ do_scan(); ++ /* If any keys are still down, set the timer going again. */ ++ if (any_keys_down (keybitmap)) ++ { ++ mod_timer (&key_release_timer, jiffies + key_release_interval); ++ } ++ else ++ { ++ del_timer (&autorepeat_timer); ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++} ++#endif ++ ++/* ++ * This is called when the autorepeat timer goes off. ++ */ ++static void ++autorepeat_timer_went_off(unsigned long unused) ++{ ++ int i, bitnum; ++ unsigned long tmp; ++ unsigned long flags; ++ ++#ifdef CONFIG_PANIC_LOG ++ int temp_key; ++ if( panic_key == 1 ) ++ { ++ kpc_res = KPC; ++ /* Initiate a manual scan */ ++ KPC &= ~(KPC_AS | KPC_ASACT | KPC_MIE | KPC_MS0 | KPC_MS1 | KPC_MS2 | KPC_MS3 | KPC_MS4 | KPC_MS5 | KPC_MS6 | KPC_MS7); ++ /* reading the scan registers. */ ++ KPC |= 0x10000; ++ mdelay(0x64); ++ temp_key = KPMK & 0xff; ++// KPC |= (KPC_ASACT | KPC_MS0 | KPC_MS1 | KPC_MS2 | KPC_MS3 | KPC_MS4 | KPC_MS5 | KPC_MS6 | KPC_MS7); ++ KPC = kpc_res; ++ ++ printk("temp_key = %x\n", temp_key); ++ ++ if ( temp_key == 0x2 ) ++ { ++ if(0 == panic_bug_used) ++ { ++ panic_bug_used = 1; ++ BUG(); ++ } ++ } ++ } ++#endif ++ ++ spin_lock_irqsave(&keypad_lock,flags); ++ if (!any_keys_down (keybitmap)) ++ { ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ return; ++ } ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ tmp = keybitmap[NUM_WORDS_IN_BITMAP-i-1]; ++ while ((bitnum = ffs(tmp)) != 0) ++ { ++ tmp &= ~(1<<(bitnum-1)); ++ /* see explanation at top of file */ ++ if ( (bitnum + (32*i)) == KEYPAD_POWER ) ++ { ++ continue; ++ } ++ (void) add_to_keybuf( (bitnum + (32*i)) | KEYDOWN ); ++ } ++ } ++ spin_unlock_irqrestore(&keypad_lock, flags); ++ wake_up_interruptible (&keypad_wait); ++ ++ mod_timer (&autorepeat_timer, jiffies + jiffies_to_next_repeat); ++} ++ ++#ifdef USE_RELEASE_TIMER ++/* ++ * Do a scan and add key events for anything that's different from the ++ * last scan. We assume keypad_lock is locked when this is called ++ * (by release_timer_went_off). ++ */ ++static void ++do_scan(void) ++{ ++ unsigned long kpas_new, kpasmkp0_new, kpasmkp1_new; ++ unsigned long kpdk_new; ++ int change; ++ ++ /* Initiate an automatic scan */ ++ KPC |= KPC_AS; ++ /* Wait for the Scan On bit to go off before */ ++ /* reading the scan registers. */ ++ while (KPAS & KPAS_SO) ++ { ++ NULL; ++ }; ++ kpas_new = KPAS; ++ kpasmkp0_new = KPASMKP0; ++ kpasmkp1_new = KPASMKP1; ++ kpdk_new = KPDK; ++ /* ++ * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off ++ */ ++ kpdk_new &= ~KPDK_DKP; ++ KPC &= ~KPC_AS; ++ ++ change = ((kpas_new != kpas) || ++ (kpasmkp0_new != kpasmkp0) || ++ (kpasmkp1_new != kpasmkp1) || ++ (kpdk_new != kpdk)); ++ ++ if (change) ++ { ++ kpas = kpas_new; ++ kpasmkp0 = kpasmkp0_new; ++ kpasmkp1 = kpasmkp1_new; ++ kpdk = kpdk_new; ++ ++ copy_bitmap (oldkeybitmap, keybitmap); ++ scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* screen lock key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++#elif defined(CONFIG_KEYPAD_E680) ++ if (kpdk & KPDK_DK0) /* screen lock key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ /* power key is connected to GPIO97 as GPIO input */ ++ if (kpdk & KPDK_DK3) ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++ ++#elif defined(CONFIG_KEYPAD_A780) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ add_events (oldkeybitmap, keybitmap); ++ ++ wake_up_interruptible (&keypad_wait); ++ } ++} ++#endif ++ ++/* ++ * set all words in the specified bitmap to 0 ++ */ ++static inline void set_bitmap_to_zero(unsigned long b[]) { ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ b[i]=0; ++ } ++} ++ ++/* ++ * copy source bitmap to destination bitmap ++ */ ++static inline void copy_bitmap(unsigned long dest[], unsigned long source[]) { ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ dest[i]=source[i]; ++ } ++} ++ ++/* ++ * Turn on the bit position in map for the specified key code. ++ * Bit numbers start with 1 (not 0) and increase moving left within ++ * words and within the array. ++ * Bit 1 is the rightmost bit in map[NUM_WORDS_IN_BITMAP-1]. ++ * Bit 33 is the rightmost bit in map[NUM_WORDS_IN_BITMAP-2]. ++ */ ++static inline void ++turn_on_bit(unsigned long map[], int code) ++{ ++ int word, pos, p; ++ ++ /* if we have 2 words, bits 1-32 are in map[1], 33-64 in map[0] */ ++ word = (NUM_WORDS_IN_BITMAP - 1) - ((code-1) / 32); ++ /* ++ * bit 1 is 1<<0, bit 2 is 1<<1, ... bit 32 is 1 << 31, all in map[1] ++ * bit 33 is 1<<0, bit 34 is 1<<1, ... in map[0] ++ * we want this: ++ * code pos ++ * 1 0 ++ * 2 1 ++ * ... ++ * 31 30 ++ * 32 31 ++ * 33 0 ++ * 34 1 ++ * ... ++ */ ++ pos = (p = (code % 32)) == 0 ? 31 : p-1; ++ map[word] |= (1<<pos); ++} ++ ++/* ++ * Turn off the bit position in map for the specified key code. ++ * Bit positions start with 1 (not 0). ++ */ ++static inline void ++turn_off_bit(unsigned long map[], int code) ++{ ++ int word, pos, p; ++ ++ word = (NUM_WORDS_IN_BITMAP - 1) - ((code-1) / 32); ++ pos = (p = (code % 32)) == 0 ? 31 : p-1; ++ map[word] &= ~(1<<pos); ++} ++ ++/* ++ * Return 1 if any bits are down in map[] ++ */ ++static inline int ++any_keys_down (unsigned long *map) ++{ ++ int i; ++ for (i=0;i<NUM_WORDS_IN_BITMAP;i++) ++ { ++ /* don't count the power key */ ++ if ((i == 0) && (*map == 0x10)) ++ { ++ map++; ++ continue; ++ } ++ if (*map++) ++ { ++ return 1; ++ } ++ } ++ return 0; ++} ++static int ++__init keypad_init(void) ++{ ++ int err; ++ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_init\n"); ++#endif ++ ++ set_bitmap_to_zero (oldkeybitmap); ++ set_bitmap_to_zero (keybitmap); ++ set_bitmap_to_zero (lastioctlbitmap); ++ ++ /* set up gpio */ ++#if defined(CONFIG_KEYPAD_V700) ++ pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); /* KP_MKIN<6> */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); /* KP_MKIN<5> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_E680_P4A) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#elif defined(CONFIG_KEYPAD_E680) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ ++ pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(GPIO_TC_MM_EN); ++ GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); ++#elif defined(CONFIG_KEYPAD_A780) ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ ++ pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ ++ pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++ pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ ++#elif defined(CONFIG_KEYPAD_MAINSTONE) ++ /* from Intel driver */ ++ pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); ++ pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ ++ pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ ++ pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ ++ pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ ++ pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ ++ pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ ++ pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ ++#endif ++ ++ /* set keypad control register */ ++ KPC = (KPC_ASACT | /* automatic scan on activity */ ++ KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ ++#if defined(CONFIG_KEYPAD_V700) ++ (3<<23) | /* 4 columns */ ++ (6<<26) | /* 7 rows */ ++#elif defined(CONFIG_E680_P4A) ++ (3<<23) | /* 4 columns */ ++ (2<<26) | /* 3 rows */ ++ (4<<6) | /* 4# direct key */ ++#elif defined(CONFIG_KEYPAD_E680) ++ (5<<23) | /* 4 columns */ ++ (4<<26) | /* 3 rows */ ++ (5<<6) | /* 5# direct keys */ ++#elif defined(CONFIG_KEYPAD_A780) ++ KPC_IMKP | ++ (4<<23) | /* 5 columns */ ++ (4<<26) | /* 5 rows */ ++ (0<<6) | /* 1# direct keys */ ++#endif ++ KPC_MS7_0); /* scan all columns */ ++ ++ CKEN |= CKEN19_KEYPAD; ++ ++ err = request_irq (IRQ_KEYPAD, kp_interrupt, 0, "Keypad", NULL); ++ if (err) ++ { ++ printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", ++ IRQ_KEYPAD, err); ++ CKEN &= ~CKEN19_KEYPAD; ++ return -ENODEV; ++ } ++ ++ if (misc_register (&keypad_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypad driver\n"); ++ return -EIO; ++ } ++ if (misc_register (&keypadB_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypadB driver\n"); ++ misc_deregister(&keypad_misc_device); ++ return -EIO; ++ } ++ if (misc_register (&keypadI_misc_device)) ++ { ++ printk(KERN_ERR "Couldn't register keypadI driver\n"); ++ misc_deregister(&keypad_misc_device); ++ misc_deregister(&keypadB_misc_device); ++ return -EIO; ++ } ++ ++#ifdef USE_RELEASE_TIMER ++ init_timer (&key_release_timer); ++ key_release_timer.function = release_timer_went_off; ++#endif ++ init_timer (&autorepeat_timer); ++ autorepeat_timer.function = autorepeat_timer_went_off; ++ ++ /* ++ * we want the phone to be able to tell the status of the screen ++ * lock switch at power-up time ++ */ ++ kpdk = KPDK; /* read direct key register */ ++ /* ++ * reading the register turns off the "key pressed since last read" bit ++ * if it was on, so we turn it off ++ */ ++ kpdk &= ~KPDK_DKP; ++#if defined(CONFIG_E680_P4A) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++#elif defined(CONFIG_KEYPAD_E680) ++ if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++ if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_POWER); ++ } ++ if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_A); ++ } ++ if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_B); ++ } ++#elif defined(CONFIG_KEYPAD_A780) ++ if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ ++ { ++ turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); ++ } ++#endif ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); ++#if defined(CONFIG_E680_P4A) ++/*93,97,100,101,102*/ ++ PKWR = 0xe4400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_E680) ++/*93,96,97,98,100,101,102*/ ++ PKWR = 0xee400; ++/*103 104 105 106*/ ++ PGSR3 |= 0x780; ++#endif ++#if defined(CONFIG_KEYPAD_A780) ++/*93,97,98,100,101,102*/ ++ PKWR = 0xec400; ++/*103 104 105 106 107*/ ++ PGSR3 |= 0xf80; ++#endif ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) ++#ifdef CONFIG_PM ++ keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); ++ PGSR3 |= 0x8; ++#endif ++#endif ++ ++ KPC |= (KPC_DIE | KPC_MIE); ++ KPKDI = 0x40; ++ return 0; ++ ++} ++ ++static void ++__exit keypad_exit(void) ++{ ++#ifdef KDEBUG ++ printk(KERN_DEBUG " keypad_exit\n"); ++#endif ++ misc_deregister(&keypad_misc_device); ++ misc_deregister(&keypadB_misc_device); ++ misc_deregister(&keypadI_misc_device); ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ ++#if defined(CONFIG_KEYPAD_E680) ++#ifdef CONFIG_PM ++ pm_unregister(keypadI_pm_dev); ++#endif ++#endif ++ ++ CKEN &= ~CKEN19_KEYPAD; ++} ++ ++module_init (keypad_init); ++module_exit (keypad_exit); +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/log.c linux-2.6.16/drivers/misc/ezx/log.c +--- linux-2.6.16.orig/drivers/misc/ezx/log.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/log.c 2006-06-03 11:14:56.343323768 +0200 +@@ -0,0 +1,287 @@ ++/* ++ * Kernel panic log interface for Linux. ++ * ++ * Copyright (c) 2000 Motorola ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * 0.01 2003-07-01 zxf <w19962@motorola.com> ++ * - initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/rtc.h> ++#include <linux/notifier.h> ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include "log.h" ++ ++#include <linux/fb.h> ++#include "../video/pxafb.h" ++ ++#define LOGDRV_MINOR 188 ++ ++static struct log_area *log = NULL; ++struct log_cmdline log_cmdline; ++ ++static int __init log_setup(char *str) ++{ ++ struct log_cmdline *c; ++ ++ c = &log_cmdline; ++ memcpy(c->name, str, sizeof(c->name)); ++ ++ return 1; ++} ++ ++__setup("paniclog=", log_setup); ++ ++void panic_trig(const char *str, struct pt_regs *regs, int err) ++{ ++ if (log) ++ die(str, regs, err); ++} ++EXPORT_SYMBOL(panic_trig); ++ ++int log_register(struct log_area *log_f) ++{ ++ if (strcmp(log_cmdline.name, log_f->name) == 0) ++ log = log_f; ++ return 0; ++} ++ ++int log_unregister(struct log_area *log_f) ++{ ++ log = NULL; ++ return 0; ++} ++ ++static loff_t logdrv_lseek(struct file *file, loff_t offset, int orig) ++{ ++ switch (orig) { ++ case 0: ++ /* SEEK_SET */ ++ file->f_pos = offset; ++ break; ++ case 1: ++ /* SEEK_CUR */ ++ file->f_pos += offset; ++ break; ++ case 2: ++ /* SEEK_END */ ++ file->f_pos = log->size + offset; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (file->f_pos < 0) ++ file->f_pos = 0; ++ else if (file->f_pos >= log->size) ++ file->f_pos = log->size - 1; ++ ++ return file->f_pos; ++} ++ ++static int logdrv_open(struct inode *inode, struct file *file) ++{ ++ if (!log) { ++ printk("Not register mechine specific log structure!\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int logdrv_close(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static ssize_t logdrv_read(struct file *file, char *buf, size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ if (count > log->size - p) ++ count = log->size - p; ++ if (log->read) ++ return log->read(buf, count, ppos); ++ ++ if (copy_to_user((void *)buf, (void *)(log->start + *ppos), count)) ++ return -EFAULT; ++ ++ *ppos += count; ++ return count; ++} ++ ++static struct file_operations logdrv_fops = { ++ owner: THIS_MODULE, ++ llseek: logdrv_lseek, ++ read: logdrv_read, ++ open: logdrv_open, ++ release: logdrv_close, ++}; ++ ++static struct miscdevice logdrv_miscdev = { ++ LOGDRV_MINOR, ++ "log drv", ++ &logdrv_fops ++}; ++ ++extern void logbuf_info(char **st, unsigned long *cnt); ++extern struct pxafb_info *pxafbi; ++extern int get_irq_list(char *buf); ++ ++extern atomic_t vm_committed_space; ++void dump_proc_meminfo(void) ++{ ++ struct sysinfo i; ++ char buf[1024]; ++ int len; ++ int pg_size, committed; ++ ++#define K(x) ((x) << (PAGE_SHIFT - 10)) ++#define B(x) ((unsigned long long)(x) << PAGE_SHIFT) ++ ++ si_meminfo(&i); ++ si_swapinfo(&i); ++ ++ pg_size = atomic_read(&page_cache_size) - i.bufferram ; ++ committed = atomic_read(&vm_committed_space); ++ ++ len = sprintf(buf, " total: used: free: shared: buffers: cached:\n" ++ "Mem: %8Lu %8Lu %8Lu %8Lu %8Lu %8Lu\n" ++ "Swap: %8Lu %8Lu %8Lu\n", ++ B(i.totalram), B(i.totalram-i.freeram), B(i.freeram), ++ B(i.sharedram), B(i.bufferram), ++ B(pg_size), B(i.totalswap), ++ B(i.totalswap-i.freeswap), B(i.freeswap)); ++ ++ len += sprintf(buf+len, ++ "MemTotal: %8lu kB\n" ++ "MemFree: %8lu kB\n" ++ "MemShared: %8lu kB\n" ++ "Buffers: %8lu kB\n" ++ "Cached: %8lu kB\n" ++ "SwapCached: %8lu kB\n" ++ "Active: %8u kB\n" ++ "Inactive: %8u kB\n" ++ "HighTotal: %8lu kB\n" ++ "HighFree: %8lu kB\n" ++ "LowTotal: %8lu kB\n" ++ "LowFree: %8lu kB\n" ++ "SwapTotal: %8lu kB\n" ++ "SwapFree: %8lu kB\n" ++ "Committed_AS: %8u kB\n", ++ K(i.totalram), ++ K(i.freeram), ++ K(i.sharedram), ++ K(i.bufferram), ++ K(pg_size - swapper_space.nrpages), ++ K(swapper_space.nrpages), ++ K(nr_active_pages), ++ K(nr_inactive_pages), ++ K(i.totalhigh), ++ K(i.freehigh), ++ K(i.totalram-i.totalhigh), ++ K(i.freeram-i.freehigh), ++ K(i.totalswap), ++ K(i.freeswap), ++ K(committed)); ++ ++ printk(KERN_EMERG " [meminfo] len 0x%x\n %s\n", len, buf); ++} ++ ++int panic_log_notify(struct notifier_block *self, unsigned long code, void *unused) ++{ ++ unsigned long count; ++ char *start; ++ ++ printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); //RCNR); ++ ++ if(pxafbi) ++ { ++ int i; ++ unsigned long *p; ++ printk(KERN_EMERG " pxafbi->map_cpu: 0x%x, size 0x%x\n", pxafbi->map_cpu, pxafbi->map_size); ++ p = (unsigned long)(pxafbi->map_cpu); ++ for(i=0; i<(pxafbi->map_size/sizeof(unsigned long)); i++) ++ *p++ = 0x0; ++ printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); ++ } ++ ++ if(1) ++ { ++ // cat /proc/interrupts ++ char buf[1024]; ++ int len; ++ ++ len = get_irq_list(buf); ++ printk(KERN_EMERG " [interrupts] len 0x%x\n", len); ++ printk(KERN_EMERG "%s\n", buf); ++ } ++ ++ if(1) ++ { ++ // cat /proc/meminfo ++ dump_proc_meminfo(); ++ } ++ ++ /* Below 2 lines will overwrite useful information if log_buf is not large enough */ ++ printk(KERN_EMERG "****** show task state when panic *******\n"); ++ show_state(); ++ ++ /* get syslog buf info: start position, number of chars */ ++ logbuf_info(&start, &count); ++ ++ /* write information to log area */ ++ if (log && log->write) ++ log->write(start, count); ++ ++ printk(KERN_EMERG "OK, Now we exit panic log function!\n"); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block panic_log_nb = { ++ panic_log_notify, ++ NULL, ++ 0 ++}; ++ ++extern struct notifier_block *panic_notifier_list; ++static int __init log_init(void) ++{ ++ misc_register(&logdrv_miscdev); ++ return notifier_chain_register(&panic_notifier_list, &panic_log_nb); ++} ++ ++static void __exit log_exit(void) ++{ ++ notifier_chain_unregister(&panic_notifier_list, &panic_log_nb); ++ misc_deregister(&logdrv_miscdev); ++} ++ ++module_init(log_init); ++module_exit(log_exit); ++ ++EXPORT_SYMBOL(log_register); ++EXPORT_SYMBOL(log_unregister); ++ ++MODULE_AUTHOR("zxf <w19962@motorola.com>"); ++MODULE_DESCRIPTION("Kernel panic log interface"); ++MODULE_LICENSE("GPL"); ++ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/log.h linux-2.6.16/drivers/misc/ezx/log.h +--- linux-2.6.16.orig/drivers/misc/ezx/log.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/log.h 2006-06-03 11:14:56.343323768 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * Kernel panic log interface for Linux on A760(XScale PXA262). ++ * ++ * Copyright (c) 2000 Motorola ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * 0.01 2003-07-01 zxf <w19962@motorola.com> ++ * - initial release ++ */ ++ ++#ifndef _PANIC_LOG_H_ ++#define _PANIC_LOG_H_ ++ ++#include <linux/fs.h> ++ ++struct log_area { ++ char name[8]; ++ unsigned long start; ++ unsigned long size; ++ ssize_t (*write) (const char *buf, size_t count); ++ ssize_t (*read) (const char *buf, size_t count, loff_t *ppos); ++}; ++ ++struct log_cmdline { ++ char name[8]; ++}; ++ ++extern int log_register(struct log_area *log_f); ++extern int log_unregister(struct log_area *log_f); ++ ++#endif /* _PANIC_LOG_H_ */ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/Makefile linux-2.6.16/drivers/misc/ezx/Makefile +--- linux-2.6.16.orig/drivers/misc/ezx/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/Makefile 2006-06-03 11:14:57.145201864 +0200 +@@ -0,0 +1,13 @@ ++ ++obj-$(CONFIG_PXA_EZX) += ssp_pcap_main.o ezx-emu.o # ezx-ts.o ezx-button.o ++ ++# obj-$(CONFIG_EZX) += keypad.o keypad-panasonic.o keypad-e398.o ++ ++obj-$(CONFIG_KEYPAD_A780) += keypad.o ++obj-$(CONFIG_KEYPAD_E680) += keypad.o ++obj-$(CONFIG_KEYLIGHT_A780) += keylight.o ++obj-$(CONFIG_FMRADIO_E680) += fmradio.o ++ ++obj-$(CONFIG_PANIC_LOG) += log.o ++obj-$(CONFIG_ARCH_EZX) += ezx_log.o ++ +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ssp_pcap.h linux-2.6.16/drivers/misc/ezx/ssp_pcap.h +--- linux-2.6.16.orig/drivers/misc/ezx/ssp_pcap.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ssp_pcap.h 2006-06-03 11:14:56.289331976 +0200 +@@ -0,0 +1,673 @@ ++/* (c) Copyright Motorola Beijing 2002 all rights reserved. ++ ++ Project Name : EZX ++ Project No. : ++ Title : ++ File Name : ++ Description : ++ ++ ************** REVISION HISTORY ********************************************** ++ Date Author Reference ++ ======== ========== ========================== ++ 2002-07-01 weiqiang lin create ++*/ ++#ifndef SSP_PCAP_H ++#define SSP_PCAP_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define SSP_vibrate_start_command() SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) ++ ++#define SSP_vibrate_stop_command() SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) ++ ++#define SSP_PCAP_REGISTER_VALUE_LENGTH 16 ++ ++#define SSP_PCAP_REGISTER_WRITE_OP_BIT 0x80000000 ++#define SSP_PCAP_REGISTER_READ_OP_BIT 0x00000000 ++ ++#define SSP_PCAP_REGISTER_VALUE_UP_WORD_MASK 0xffff0000 ++#define SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK 0x0000ffff ++ ++#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff ++#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff ++#define SSP_PCAP_REGISTER_ADDRESS_MASK 0x7c000000 ++#define SSP_PCAP_REGISTER_ADDRESS_SHIFT 26 ++#define SSP_PCAP_REGISTER_NUMBER 32 ++ ++#define SSP_PCAP_ADC_START_VALUE_SET_MASK 0xfffffc00 ++#define SSP_PCAP_ADC_START_VALUE 0x000001dd ++ ++ ++#define SSP_PCAP_PHONE_CDC_CLOCK_MASK 0x000001c0 ++#define SSP_PCAP_STEREO_SAMPLE_RATE_MASK 0x00000f00 ++#define SSP_PCAP_STEREO_BCLK_TIME_SLOT_MASK 0x00018000 ++#define SSP_PCAP_STEREO_CLOCK_MASK 0x0000001c ++#define SSP_PCAP_DIGITAL_AUDIO_MODE_MASK 0x00006000 ++#define SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK 0x000e0000 ++#define SSP_PCAP_MONO_PGA_MASK 0x00180000 ++ ++#define SSP_PCAP_VIBRATOR_VOLTAGE_LEVEL_MASK 0x00300000 ++ ++#define SSP_PCAP_AUDIO_IN_GAIN_MASK 0x0000001f ++#define SSP_PCAP_AUDIO_IN_GAIN_SHIFT 0 ++#define SSP_PCAP_AUDIO_OUT_GAIN_MASK 0x0001e000 ++#define SSP_PCAP_AUDIO_OUT_GAIN_SHIFT 13 ++ ++ ++#define SSP_PCAP_ADD1_VALUE_MASK 0x000003ff ++#define SSP_PCAP_ADD1_VALUE_SHIFT 0 ++#define SSP_PCAP_ADD2_VALUE_MASK 0x000ffc00 ++#define SSP_PCAP_ADD2_VALUE_SHIFT 10 ++ ++ ++#define PCAP_AUDIO_IN_GAIN_MAX_VALUE 31 ++#define PCAP_AUDIO_OUT_GAIN_MAX_VALUE 15 ++ ++#define PCAP_CLEAR_INTERRUPT_REGISTER 0x00141fdf ++#define PCAP_MASK_ALL_INTERRUPT 0x0013ffff ++ ++#define SSP_PCAP_TS_KEEPER_TIMER 100 /* 1 second */ ++#define START_ADC_DELAY_TIMER 1991 /* 540 us */ ++ ++#define SSP_SEND_PM_ALART_INTERVAL 1000 *HZ/1000 /* 1 second */ ++#define SSP_SEND_MSG_USB_ACCESSORY_INFO_DEBOUNCE 200 *HZ/1000 /* 200ms */ ++ ++struct ssp_interrupt_info ++{ ++ u32 type; ++ u32 status; ++ void* privdata; ++}; ++ ++#ifndef U8 ++#define U8 unsigned char ++#endif ++ ++#ifndef U32 ++#define U32 unsigned long ++#endif ++ ++#ifndef U16 ++#define U16 unsigned short ++#endif ++ ++#ifndef P_U16 ++#define P_U16 U16* ++#endif ++ ++#ifndef P_U32 ++#define P_U32 U32* ++#endif ++ ++#define SSP_SELECT_BUFFER (volatile unsigned long *)(0xf4000000) ++ ++#define SSP_SR_RNE 0x00000008 ++#define SSP_PCAP_BASE 0x00001000 ++/************************ STRUCTURES, ENUMS, AND TYPEDEFS **************************/ ++typedef enum accessoryStatus ++{ ++ ACCESSORY_DEVICE_STATUS_DETACHED = 0, ++ ACCESSORY_DEVICE_STATUS_ATTACHED , ++ ACCESSORY_DEVICE_STATUS_UNKNOW =0x000000ff ++}ACCESSORY_DEVICE_STATUS; ++ ++typedef enum accessoryType ++{ ++ ACCESSORY_DEVICE_NONE = 0, ++ ACCESSORY_DEVICE_SERIAL_PORT , ++ ACCESSORY_DEVICE_USB_PORT , ++ ACCESSORY_DEVICE_UNKNOW =0x000000ff ++}ACCESSORY_TYPE; ++ ++typedef enum pcapReturnStatus ++{ ++ SSP_PCAP_SUCCESS = 0, ++ SSP_PCAP_ERROR_REGISTER = SSP_PCAP_BASE+1, ++ SSP_PCAP_ERROR_VALUE = SSP_PCAP_BASE+2, ++ ++ SSP_PCAP_NOT_RUN = SSP_PCAP_BASE+0xff ++}SSP_PCAP_STATUS; ++ ++typedef enum pcapPortType ++{ ++ SSP_PCAP_SERIAL_PORT = 0x00000000, ++ SSP_PCAP_LOW_USB_PORT = 0x00000001, ++ SSP_PCAP_HIGH_USB_PORT = 0x00000002, ++ SSP_PCAP_UNKNOW_PORT = 0x000000ff ++}SSP_PCAP_PORT_TYPE; ++ ++typedef enum pcapInitDriverType ++{ ++ SSP_PCAP_TS_OPEN = 0x00000000, ++ SSP_PCAP_AUDIO_OPEN = 0x00000001, ++ SSP_PCAP_UNKNOW_DRIVER_OPEN = 0x000000ff ++}SSP_PCAP_INIT_DRIVER_TYPE; ++ ++ ++typedef enum pcapReturnBitStatus ++{ ++ SSP_PCAP_BIT_ZERO = 0x00000000, ++ SSP_PCAP_BIT_ONE = 0x00000001, ++ SSP_PCAP_BIT_ERROR = 0xff000000 ++}SSP_PCAP_BIT_STATUS; ++ ++typedef enum pcapCDCClkType ++{ ++ PCAP_CDC_CLK_IN_13M0 = 0x00000000, ++ PCAP_CDC_CLK_IN_15M36 = 0x00000040, ++ PCAP_CDC_CLK_IN_16M8 = 0x00000080, ++ PCAP_CDC_CLK_IN_19M44 = 0x000000c0, ++ PCAP_CDC_CLK_IN_26M0 = 0x00000100 ++}PHONE_CDC_CLOCK_TYPE; ++ ++typedef enum pcapST_SR ++{ ++ PCAP_ST_SAMPLE_RATE_8K = 0x00000000, ++ PCAP_ST_SAMPLE_RATE_11K = 0x00000100, ++ PCAP_ST_SAMPLE_RATE_12K = 0x00000200, ++ PCAP_ST_SAMPLE_RATE_16K = 0x00000300, ++ PCAP_ST_SAMPLE_RATE_22K = 0x00000400, ++ PCAP_ST_SAMPLE_RATE_24K = 0x00000500, ++ PCAP_ST_SAMPLE_RATE_32K = 0x00000600, ++ PCAP_ST_SAMPLE_RATE_44K = 0x00000700, ++ PCAP_ST_SAMPLE_RATE_48K = 0x00000800 ++}ST_SAMPLE_RATE_TYPE; ++ ++typedef enum pcapST_BCLK ++{ ++ PCAP_ST_BCLK_SLOT_16 = 0x00000000, ++ PCAP_ST_BCLK_SLOT_8 = 0x00008000, ++ PCAP_ST_BCLK_SLOT_4 = 0x00010000, ++ PCAP_ST_BCLK_SLOT_2 = 0x00018000, ++}ST_BCLK_TIME_SLOT_TYPE; ++ ++typedef enum pcapST_CLK ++{ ++ PCAP_ST_CLK_PLL_CLK_IN_13M0 = 0x00000000, ++ PCAP_ST_CLK_PLL_CLK_IN_15M36 = 0x00000004, ++ PCAP_ST_CLK_PLL_CLK_IN_16M8 = 0x00000008, ++ PCAP_ST_CLK_PLL_CLK_IN_19M44 = 0x0000000c, ++ PCAP_ST_CLK_PLL_CLK_IN_26M0 = 0x00000010, ++ PCAP_ST_CLK_PLL_CLK_IN_EXT_MCLK = 0x00000014, ++ PCAP_ST_CLK_PLL_CLK_IN_FSYNC = 0x00000018, ++ PCAP_ST_CLK_PLL_CLK_IN_BITCLK = 0x0000001c ++}ST_CLK_TYPE; ++ ++typedef enum pcapDigitalAudioInterfaceMode ++{ ++ PCAP_DIGITAL_AUDIO_INTERFACE_NORMAL = 0x00000000, ++ PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK = 0x00002000, ++ PCAP_DIGITAL_AUDIO_INTERFACE_I2S = 0x00004000 ++}DIG_AUD_MODE_TYPE; ++ ++typedef enum pcapMono ++{ ++ PCAP_MONO_PGA_R_L_STEREO = 0x00000000, ++ PCAP_MONO_PGA_RL = 0x00080000, ++ PCAP_MONO_PGA_RL_3DB = 0x00100000, ++ PCAP_MONO_PGA_RL_6DB = 0x00180000 ++}MONO_TYPE; ++ ++typedef enum pcapVibratorVoltageLevel ++{ ++ PCAP_VIBRATOR_VOLTAGE_LEVEL0 = 0x00000000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL1 = 0x00100000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL2 = 0x00200000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL3 = 0x00300000 ++}VibratorVoltageLevel_TYPE; ++ ++typedef enum pcapTouchScreenMode ++{ ++ PCAP_TS_POSITION_X_MEASUREMENT = 0x00000000, ++ PCAP_TS_POSITION_XY_MEASUREMENT = 0x00020000, ++ PCAP_TS_PRESSURE_MEASUREMENT = 0x00040000, ++ PCAP_TS_PLATE_X_MEASUREMENT = 0x00060000, ++ PCAP_TS_PLATE_Y_MEASUREMENT = 0x00080000, ++ PCAP_TS_STANDBY_MODE = 0x000a0000, ++ PCAP_TS_NONTS_MODE = 0x000c0000 ++}TOUCH_SCREEN_DETECT_TYPE; ++ ++typedef enum pcapADJRegister ++{ ++ SSP_PCAP_ADJ_ISR_REGISTER = 0x00, ++ SSP_PCAP_ADJ_MSR_REGISTER = 0x01, ++ SSP_PCAP_ADJ_PSTAT_REGISTER = 0x02, ++ SSP_PCAP_ADJ_VREG2_REGISTER = 0x06, ++ SSP_PCAP_ADJ_AUX_VREG_REGISTER = 0x07, ++ SSP_PCAP_ADJ_BATT_DAC_REGISTER = 0x08, ++ SSP_PCAP_ADJ_ADC1_REGISTER = 0x09, ++ SSP_PCAP_ADJ_ADC2_REGISTER = 0x0a, ++ SSP_PCAP_ADJ_AUD_CODEC_REGISTER = 0x0b, ++ SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER = 0x0c, ++ SSP_PCAP_ADJ_ST_DAC_REGISTER = 0x0d, ++ SSP_PCAP_ADJ_BUSCTRL_REGISTER = 0x14, ++ SSP_PCAP_ADJ_PERIPH_REGISTER = 0x15, ++ SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER = 0x18, ++ SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER = 0x1a, ++ SSP_PCAP_ADJ_GP_REG_REGISTER = 0x1b ++}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER; ++ ++typedef enum pcapADJBit_SetType ++{ ++ SSP_PCAP_ADJ_BIT_ISR_ADCDONEI = 0x00000001, ++ SSP_PCAP_ADJ_BIT_ISR_TSI = 0x00000002, ++ SSP_PCAP_ADJ_BIT_ISR_1HZI = 0x00000004, ++ SSP_PCAP_ADJ_BIT_ISR_WHI = 0x00000008, ++ SSP_PCAP_ADJ_BIT_ISR_WLI = 0x00000010, ++ SSP_PCAP_ADJ_BIT_ISR_TODAI = 0x00000020, ++ SSP_PCAP_ADJ_BIT_ISR_USB4VI = 0x00000040, ++ SSP_PCAP_ADJ_BIT_ISR_ONOFFI = 0x00000080, ++ SSP_PCAP_ADJ_BIT_ISR_ONOFF2I = 0x00000100, ++ SSP_PCAP_ADJ_BIT_ISR_USB1VI = 0x00000200, ++ SSP_PCAP_ADJ_BIT_ISR_MOBPORTI = 0x00000400, ++ SSP_PCAP_ADJ_BIT_ISR_MB2I = 0x00000800, ++ SSP_PCAP_ADJ_BIT_ISR_A1I = 0x00001000, ++ SSP_PCAP_ADJ_BIT_ISR_STI = 0x00002000, ++ SSP_PCAP_ADJ_BIT_ISR_PCI = 0x00004000, ++ SSP_PCAP_ADJ_BIT_ISR_WARMI = 0x00008000, ++ SSP_PCAP_ADJ_BIT_ISR_EOLI = 0x00010000, ++ SSP_PCAP_ADJ_BIT_ISR_CLKI = 0x00020000, ++ SSP_PCAP_ADJ_BIT_ISR_SYS_RSTI = 0x00040000, ++ SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I = 0x00100000, ++ SSP_PCAP_ADJ_BIT_ISR_SOFT_RESETI = 0x00200000, ++ SSP_PCAP_ADJ_BIT_ISR_MNEXBI = 0x00400000, ++ ++ SSP_PCAP_ADJ_BIT_MSR_ADCDONEM = 0x04000001, ++ SSP_PCAP_ADJ_BIT_MSR_TSM = 0x04000002, ++ SSP_PCAP_ADJ_BIT_MSR_1HZM = 0x04000004, ++ SSP_PCAP_ADJ_BIT_MSR_WHM = 0x04000008, ++ SSP_PCAP_ADJ_BIT_MSR_WLM = 0x04000010, ++ SSP_PCAP_ADJ_BIT_MSR_TODAM = 0x04000020, ++ SSP_PCAP_ADJ_BIT_MSR_USB4VM = 0x04000040, ++ SSP_PCAP_ADJ_BIT_MSR_ONOFFM = 0x04000080, ++ SSP_PCAP_ADJ_BIT_MSR_ONOFF2M = 0x04000100, ++ SSP_PCAP_ADJ_BIT_MSR_USB1VM = 0x04000200, ++ SSP_PCAP_ADJ_BIT_MSR_MOBPORTM = 0x04000400, ++ SSP_PCAP_ADJ_BIT_MSR_MB2M = 0x04000800, ++ SSP_PCAP_ADJ_BIT_MSR_A1M = 0x04001000, ++ SSP_PCAP_ADJ_BIT_MSR_STM = 0x04002000, ++ SSP_PCAP_ADJ_BIT_MSR_PCM = 0x04004000, ++ SSP_PCAP_ADJ_BIT_MSR_WARMM = 0x04008000, ++ SSP_PCAP_ADJ_BIT_MSR_EOLM = 0x04010000, ++ SSP_PCAP_ADJ_BIT_MSR_CLKM = 0x04020000, ++ SSP_PCAP_ADJ_BIT_MSR_SYS_RSTM = 0x04040000, ++ SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M = 0x04100000, ++ SSP_PCAP_ADJ_BIT_MSR_SOFT_RESETM = 0x04200000, ++ SSP_PCAP_ADJ_BIT_MSR_MNEXBM = 0x04400000, ++ ++ SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V = 0x08000040, ++ SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS = 0x08000080, ++ SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS2 = 0x08000100, ++ SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V = 0x08000200, ++ SSP_PCAP_ADJ_BIT_PSTAT_MOBSENSB = 0x08000400, ++ SSP_PCAP_ADJ_BIT_PSTAT_MB2SNS = 0x08000800, ++ SSP_PCAP_ADJ_BIT_PSTAT_A1SNS = 0x08001000, ++ SSP_PCAP_ADJ_BIT_PSTAT_MSTB = 0x08002000, ++ SSP_PCAP_ADJ_BIT_PSTAT_EOL_STAT = 0x08010000, ++ SSP_PCAP_ADJ_BIT_PSTAT_CLK_STAT = 0x08020000, ++ SSP_PCAP_ADJ_BIT_PSTAT_SYS_RST = 0x08040000, ++ SSP_PCAP_ADJ_BIT_PSTAT_BATTFBSNS = 0x08080000, ++ SSP_PCAP_ADJ_BIT_PSTAT_BATT_DET_IN_SNS = 0x08200000, ++ SSP_PCAP_ADJ_BIT_PSTAT_MNEXBSNS = 0x08400000, ++ SSP_PCAP_ADJ_BIT_PSTAT_WARM_SYS_RST = 0x08800000, ++ ++ SSP_PCAP_ADJ_BIT_VREG2_V1_STBY = 0x18000001, ++ SSP_PCAP_ADJ_BIT_VREG2_V2_STBY = 0x18000002, ++ SSP_PCAP_ADJ_BIT_VREG2_V3_STBY = 0x18000004, ++ SSP_PCAP_ADJ_BIT_VREG2_V4_STBY = 0x18000008, ++ SSP_PCAP_ADJ_BIT_VREG2_V5_STBY = 0x18000010, ++ SSP_PCAP_ADJ_BIT_VREG2_V6_STBY = 0x18000020, ++ SSP_PCAP_ADJ_BIT_VREG2_V7_STBY = 0x18000040, ++ SSP_PCAP_ADJ_BIT_VREG2_V8_STBY = 0x18000080, ++ SSP_PCAP_ADJ_BIT_VREG2_V9_STBY = 0x18000100, ++ SSP_PCAP_ADJ_BIT_VREG2_V10_STBY = 0x18000200, ++ SSP_PCAP_ADJ_BIT_VREG2_V1_LOWPWR = 0x18000400, ++ SSP_PCAP_ADJ_BIT_VREG2_V2_LOWPWR = 0x18000800, ++ SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR = 0x18001000, ++ SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR = 0x18002000, ++ SSP_PCAP_ADJ_BIT_VREG2_V5_LOWPWR = 0x18004000, ++ SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR = 0x18008000, ++ SSP_PCAP_ADJ_BIT_VREG2_V7_LOWPWR = 0x18010000, ++ SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR = 0x18020000, ++ SSP_PCAP_ADJ_BIT_VREG2_V9_LOWPWR = 0x18040000, ++ SSP_PCAP_ADJ_BIT_VREG2_V10_LOWPWR = 0x18080000, ++ ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_EN = 0x1c000002, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_0 = 0x1c000004, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_1 = 0x1c000008, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN = 0x1c000010, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0 = 0x1c000020, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1 = 0x1c000040, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN = 0x1c000080, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_0 = 0x1c000100, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_1 = 0x1c000200, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_2 = 0x1c000400, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_3 = 0x1c000800, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_EN = 0x1c001000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_0 = 0x1c002000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_1 = 0x1c004000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM2_EN = 0x1c010000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_EN = 0x1c020000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_0 = 0x1c040000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN = 0x1c080000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_0 = 0x1c100000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_1 = 0x1c200000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_STBY = 0x1c400000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_LOWPWR = 0x1c800000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_SW3_STBY = 0x1d000000, ++ ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC0 = 0x20000001, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC1 = 0x20000002, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC2 = 0x20000004, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC3 = 0x20000008, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC4 = 0x20000010, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC5 = 0x20000020, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC6 = 0x20000040, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC7 = 0x20000080, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_B_FDBK = 0x20000100, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EXT_ISENSE = 0x20000200, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN0 = 0x20000400, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN1 = 0x20000800, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN2 = 0x20001000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN3 = 0x20002000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_I_COIN = 0x20004000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_COIN_CH_EN = 0x20008000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL0 = 0x20020000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL1 = 0x20040000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL2 = 0x20080000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_CMP_EN = 0x20100000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_BATT_DET_EN = 0x20200000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_THERMBIAS_CTRL = 0x20400000, ++ ++ SSP_PCAP_ADJ_BIT_ADC1_ADEN = 0x24000001, ++ SSP_PCAP_ADJ_BIT_ADC1_RAND = 0x24000002, ++ SSP_PCAP_ADJ_BIT_ADC1_AD_SEL1 = 0x24000004, ++ SSP_PCAP_ADJ_BIT_ADC1_AD_SEL2 = 0x24000008, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA10 = 0x24000010, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA11 = 0x24000020, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA12 = 0x24000040, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA20 = 0x24000080, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA21 = 0x24000100, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA22 = 0x24000200, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO0 = 0x24000400, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO1 = 0x24000800, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO2 = 0x24001000, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO3 = 0x24002000, ++ SSP_PCAP_ADJ_BIT_ADC1_ATOX = 0x24004000, ++ SSP_PCAP_ADJ_BIT_ADC1_MTR1 = 0x24008000, ++ SSP_PCAP_ADJ_BIT_ADC1_MTR2 = 0x24010000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M0 = 0x24020000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M1 = 0x24040000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M2 = 0x24080000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR = 0x24100000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_REFENB = 0x24200000, ++ SSP_PCAP_ADJ_BIT_ADC1_BATT_I_POLARITY = 0x24400000, ++ SSP_PCAP_ADJ_BIT_ADC1_BATT_I_ADC = 0x24800000, ++ ++ SSP_PCAP_ADJ_BIT_ADC2_ADD10 = 0x28000001, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD11 = 0x28000002, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD12 = 0x28000004, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD13 = 0x28000008, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD14 = 0x28000010, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD15 = 0x28000020, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD16 = 0x28000040, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD17 = 0x28000080, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD18 = 0x28000100, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD19 = 0x28000200, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD20 = 0x28000400, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD21 = 0x28000800, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD22 = 0x28001000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD23 = 0x28002000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD24 = 0x28004000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD25 = 0x28008000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD26 = 0x28010000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD27 = 0x28020000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD28 = 0x28040000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD29 = 0x28080000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADINC1 = 0x28100000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADINC2 = 0x28200000, ++ SSP_PCAP_ADJ_BIT_ADC2_ASC = 0x28400000, ++ ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF = 0x2c000001, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB = 0x2c000002, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF = 0x2c000004, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS = 0x2c000008, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DLM = 0x2c000010, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH = 0x2c000020, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK0 = 0x2c000040, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK1 = 0x2c000080, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK2 = 0x2c000100, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV = 0x2c000200, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV = 0x2c000400, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET = 0x2c000800, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN = 0x2c001000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN = 0x2c002000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K = 0x2c004000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN = 0x2c008000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL = 0x2c010000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2_MUX = 0x2c020000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG0 = 0x2c040000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG1 = 0x2c080000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG2 = 0x2c100000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG3 = 0x2c200000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG4 = 0x2c400000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG_PRI_ADJ = 0x2c800000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_PRI_ADJ = 0x2c200000, ++ ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN = 0x30000001, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN = 0x30000002, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A4_EN = 0x30000010, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN = 0x30000020, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN = 0x30000040, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP = 0x30000080, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW = 0x30000100, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW = 0x30000200, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW = 0x30000400, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN = 0x30000800, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN = 0x30001000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG0 = 0x30002000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG1 = 0x30004000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG2 = 0x30008000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG3 = 0x30010000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL = 0x30020000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO0 = 0x30080000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO1 = 0x30100000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG_PRI_ADJ = 0x30200000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO_PRI_ADJ = 0x30400000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ0 = 0x30800000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ1 = 0x31000000, ++ ++ SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC = 0x34000001, ++ SSP_PCAP_ADJ_BIT_ST_DAC_STDET_EN = 0x34000002, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK0 = 0x34000004, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK1 = 0x34000008, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK2 = 0x34000010, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN = 0x34000020, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC = 0x34000040, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN = 0x34000080, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR0 = 0x34000100, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR1 = 0x34000200, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR2 = 0x34000400, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR3 = 0x34000800, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC = 0x34001000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS0 = 0x34002000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS1 = 0x34004000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_BCLK0 = 0x34008000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_BCLK1 = 0x34010000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV = 0x34020000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV = 0x34040000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL = 0x34080000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_PRI_ADJ = 0x35000000, ++ ++ SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB = 0x50000001, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_SUSPEND = 0x50000002, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU = 0x50000004, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD = 0x50000008, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN = 0x50000010, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS = 0x50000020, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_MSTR_EN = 0x50000040, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VBUS_PD_ENB = 0x50000080, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_CURRLIM = 0x50000100, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB = 0x50000200, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR = 0x50000400, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_SE0_CONN = 0x50000800, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PDM = 0x50001000, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_BUS_PRI_ADJ = 0x51000000, ++ ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0 = 0x54000001, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1 = 0x54000002, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2 = 0x54000004, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3 = 0x54000008, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4 = 0x54000010, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_EN = 0x54000020, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_EN = 0x54000040, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL0 = 0x54000080, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL1 = 0x54000100, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL2 = 0x54000200, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL3 = 0x54000400, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL0 = 0x54000800, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL1 = 0x54001000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL2 = 0x54002000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL3 = 0x54004000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I0 = 0x54008000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I1 = 0x54010000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I0 = 0x54020000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I1 = 0x54040000, ++ SSP_PCAP_ADJ_BIT_PERIPH_SKIP = 0x54080000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0 = 0x54100000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1 = 0x54200000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2 = 0x54400000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3 = 0x54800000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4 = 0x55000000, ++ ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY = 0x60000001, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR = 0x60000002, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_STBY = 0x60000004, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_LOWPWR = 0x60000008, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_STBY = 0x60000010, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_LOWPWR = 0x60000020, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM_LOWPWR = 0x60000040, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM2_LOWPWR = 0x60000080, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00 = 0x60000100, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01 = 0x60000200, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10 = 0x60000400, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11 = 0x60000800, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS = 0x60001000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS = 0x60002000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS = 0x60004000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS = 0x60008000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE00 = 0x60010000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE01 = 0x60020000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE10 = 0x60040000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE11 = 0x60080000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW20_DVS = 0x60100000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW21_DVS = 0x60200000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW22_DVS = 0x60400000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW23_DVS = 0x60800000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY = 0x61000000, ++ ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG0 = 0x68000001, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG1 = 0x68000002, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG2 = 0x68000004, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG3 = 0x68000008, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG4 = 0x68000010, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN = 0x68000020, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX = 0x68000040, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN = 0x68000080, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX = 0x68000100, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX = 0x68000200, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2 = 0x68000400, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1 = 0x68000800, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1ID_TX = 0x68001000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1_CONFIG = 0x68002000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG = 0x68004000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A2_CONFIG = 0x68008000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR = 0x68080000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_STBY = 0x68100000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2 = 0x68200000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG_PRI_ADJ = 0x68400000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ0 = 0x68800000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ1 = 0x69000000, ++ ++ SSP_PCAP_ADJ_BIT_SYS_RST_CLR = 0x6c000001, ++ SSP_PCAP_ADJ_BIT_SYS_RST_MODE0 = 0x6c000002, ++ SSP_PCAP_ADJ_BIT_SYS_RST_MODE1 = 0x6c000004, ++ SSP_PCAP_ADJ_BIT_SYS_VFLASH_0 = 0x6c000008, ++ SSP_PCAP_ADJ_BIT_SYS_VFLASH_1 = 0x6c000010, ++ SSP_PCAP_ADJ_BIT_SYS_MID_SELECT = 0x6c000020, ++ SSP_PCAP_ADJ_BIT_SYS_MID_FET = 0x6c000040, ++ SSP_PCAP_ADJ_BIT_SYS_MAIN_LOW = 0x6c000080, ++ SSP_PCAP_ADJ_BIT_SYS_BATTFB_DIS = 0x6c000100, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG9 = 0x6c000200, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG10 = 0x6c000400, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG11 = 0x6c000800, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG12 = 0x6c001000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG13 = 0x6c002000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG14 = 0x6c004000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG15 = 0x6c008000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG16 = 0x6c010000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG17 = 0x6c020000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG18 = 0x6c040000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG19 = 0x6c080000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG20 = 0x6c100000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG21 = 0x6c200000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG22 = 0x6c400000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG23 = 0x6c800000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG24 = 0x6d000000 ++ ++}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE; ++ ++/************************ FUNCTION PROTOTYPES **************************************/ ++extern void ssp_pcap_init(void); ++extern void ssp_pcap_release(void); ++ ++extern void ssp_pcap_open(SSP_PCAP_INIT_DRIVER_TYPE portType); ++extern void ssp_pcap_close(void); ++ ++extern void ssp_pcap_intoSleep_callBack(void); ++extern void ssp_pcap_wakeUp_callBack(void); ++ ++ ++extern SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,U32 ssp_pcap_register_value); ++extern SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,P_U32 p_ssp_pcap_register_value); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register ) ; ++ ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_mode_set(TOUCH_SCREEN_DETECT_TYPE mode_Type ); ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_start_XY_read(void); ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_get_XY_value(P_U16 p_x,P_U16 p_y); ++extern SSP_PCAP_STATUS SSP_PCAP_CDC_CLK_set(PHONE_CDC_CLOCK_TYPE clkType); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_CDC_SR_set(ST_SAMPLE_RATE_TYPE srType); ++extern SSP_PCAP_STATUS SSP_PCAP_BCLK_set(ST_BCLK_TIME_SLOT_TYPE bclkType); ++extern SSP_PCAP_STATUS SSP_PCAP_STCLK_set(ST_CLK_TYPE stClkType); ++extern SSP_PCAP_STATUS SSP_PCAP_DIG_AUD_FS_set(DIG_AUD_MODE_TYPE fsType); ++extern SSP_PCAP_STATUS SSP_PCAP_AUDIG_set(U32 audioInGain); ++extern SSP_PCAP_STATUS SSP_PCAP_MONO_set(MONO_TYPE monoType); ++extern SSP_PCAP_STATUS SSP_PCAP_AUDOG_set(U32 audioOutGain); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_V_VIB_level_set(VibratorVoltageLevel_TYPE VIBLevelType); ++extern SSP_PCAP_STATUS SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_PORT_TYPE portType); ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_audio_in_status(void); ++ ++/* for log */ ++extern void pcap_log_add_pure_data(u8* pData,u32 len); ++extern void pcap_log_add_data(u8* pData,u32 len); ++ ++/* screen lock on/off handler */ ++extern void ssp_pcap_screenlock_lock(u32 data); ++extern void ssp_pcap_screenlock_unlock(u32 data); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff -Nurd linux-2.6.16.orig/drivers/misc/ezx/ssp_pcap_main.c linux-2.6.16/drivers/misc/ezx/ssp_pcap_main.c +--- linux-2.6.16.orig/drivers/misc/ezx/ssp_pcap_main.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/misc/ezx/ssp_pcap_main.c 2006-06-03 11:14:57.146201712 +0200 +@@ -0,0 +1,2655 @@ ++/* (c) Copyright Motorola 2002, All rights reserved. ++ Motorola Confidential Proprietary ++ Contains confidential proprietary information of Motorola, Inc. ++ Reverse engineering is prohibited. ++ The copyright notice does not imply publication. ++ ++ Project Name : EZX ++ Project No. : ++ Title : ++ File Name : ++ Description : ++ ++ ************** REVISION HISTORY ********************************************** ++ Date Author Reference ++ ======== ========== ========================== ++ 2002-07-02 weiqiang lin create ++ 2004-02-09 weiqiang lin update PM for Bulverde OS libdd74345. ++ 2004-04-13 weiqiang lin update accessory usb attach and detach ++ 2004-04-27 weiqiang lin send the USB accessory detach/attach information to PM ++ 2004-05-11 weiqiang lin after sleep TC_MM_EN will be high else will be low ++ 2004-06-24 Cheng Xuefeng remove the SSP_PCAP_configure_USB_UART_transeiver() ++ 2004-08-19 weiqiang lin after sleep set SW1 output 1.3V and low power mode and when headset button press/release, send an event to PM ++ 2004-08-31 weiqiang lin remove the headset button press/release event to PM. ++*/ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/fb.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/init.h> ++#include <linux/apm_bios.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++ ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx.h> ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#include "ssp_pcap.h" ++#define SSP_PCAP_OPERATE_WITH_SPI ++ ++static u32 ssp_pcap_operate_pin_with_inverter; ++static u32 ssp_pcap_rxd_pin_with_inverter; ++//#define SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ ++#ifdef _DEBUG_BOARD ++#define SSP_PCAP_DEBUG_BOARD ++#endif ++ ++/* 0 -- unlock 1- lock */ ++static u32 ssp_pcap_screenlock_status; ++static struct timer_list ssp_pcap_screenlock_timer; ++static void ssp_pcap_screenlock_lockhandler(u32 data); ++ ++static struct timer_list ssp_start_adc_timer; ++static struct timer_list ssp_tsi_timer; ++static struct timer_list ssp_usb_accessory_debounce_timer; ++ ++static U32 ssp_pcap_status = 0; ++static U32 ssp_pcap_registerValue[SSP_PCAP_REGISTER_NUMBER] = {0}; ++ ++SSP_PCAP_BIT_STATUS SSP_PCAP_get_audio_in_status(void); ++SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,U32 ssp_pcap_register_value); ++SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,P_U32 p_ssp_pcap_register_value); ++ ++SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register ) ; ++ ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++static wait_queue_head_t ssp_pcap_send_wait; ++static U32 ssp_pcap_readValue; ++static irqreturn_t ssp_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ); ++void ssp_put_intoData(U32 pcapValue); ++#endif ++ ++static spinlock_t pcapoperation_lock = SPIN_LOCK_UNLOCKED; ++static irqreturn_t ssp_pcap_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ); ++//static U32 ssp_pcapRegisterReadOut = 0; ++ ++//static void usb_hardware_switch(void); ++ ++//static struct timer_list usb_switch_timer; ++ ++void ssp_pcap_init(void); ++void ssp_pcap_release(void); ++void ssp_pcap_clear_int(void); ++void ssp_pcap_intoSleepCallBack(void); ++void ssp_pcap_wakeUpCallBack(void); ++ ++extern int usb_gpio_init(void); ++extern int stop_usb(void); ++static void ssp_tsi_keeper(u32 data); ++static void ssp_usb_accessory_debounce_handler(u32 data); ++ ++extern void ezx_ts_dataReadok_interrupt(int irq,void* dev_id, struct pt_regs *regs); ++extern void ezx_ts_touch_interrupt(int irq,void* dev_id, struct pt_regs *regs); ++void (*headjack_change_interrupt_routine)(int ch,void *dev_id,struct pt_regs *regs); ++void (*mic_change_interrupt_routine)(int ch,void *dev_id,struct pt_regs *regs); ++//extern u8 pxafb_ezx_getLCD_status(void); ++ ++int (*cable_hotplug_attach)(ACCESSORY_DEVICE_STATUS status); ++static struct ssp_interrupt_info sspUsbAccessoryInfo; ++ ++void SSP_PCAP_MMCSD_poweroff(void) ++{ ++#if defined(CONFIG_PXA_EZX_E680) ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); ++#else ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN); ++#endif ++} ++EXPORT_SYMBOL(SSP_PCAP_MMCSD_poweroff); ++ ++void SSP_PCAP_MMCSD_poweron(void) ++{ ++#if defined(CONFIG_PXA_EZX_E680) ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); ++#elif defined(CONFIG_PXA_EZX_A780) ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN); ++#endif ++} ++EXPORT_SYMBOL(SSP_PCAP_MMCSD_poweron); ++ ++void SSP_PCAP_MMCSD_voltage(unsigned char bits) ++{ ++ unsigned int tmp; ++ SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_AUX_VREG_REGISTER, &tmp); ++#if defined(CONFIG_PXA_EZX_E680) ++ tmp &= 0xffffff9f; /* zero all vaux2 bits */ ++ tmp |= (bits & 0x3) << 5; ++#elif defined(CONFIG_PXA_EZX_A780) ++ tmp &= 0xfffff0ff; /* zero all vaux3 bits */ ++ tmp |= (bits & 0xf) << 8; ++#endif ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUX_VREG_REGISTER, tmp); ++} ++EXPORT_SYMBOL(SSP_PCAP_MMCSD_voltage); ++ ++static void accessory_bus_detect_handler(ACCESSORY_TYPE type,ACCESSORY_DEVICE_STATUS status,void* privdata ) ++{ ++ sspUsbAccessoryInfo.type = (u32)type; ++ sspUsbAccessoryInfo.status = (u32)status; ++ sspUsbAccessoryInfo.privdata = privdata; ++ del_timer(&ssp_usb_accessory_debounce_timer); ++ ssp_usb_accessory_debounce_timer.data = ( unsigned long ) &sspUsbAccessoryInfo; ++ /* 2 seconds protect timer */ ++ ssp_usb_accessory_debounce_timer.expires = jiffies + SSP_SEND_MSG_USB_ACCESSORY_INFO_DEBOUNCE; ++ add_timer(&ssp_usb_accessory_debounce_timer); ++ return; ++} ++ ++static void ssp_usb_accessory_debounce_handler(u32 data) ++{ ++ struct ssp_interrupt_info * pMyInfo; ++ ACCESSORY_TYPE type; ++ ACCESSORY_DEVICE_STATUS status; ++ ++ pMyInfo = (struct ssp_interrupt_info *)data; ++ type = ( ACCESSORY_TYPE) pMyInfo->type; ++ status = ( ACCESSORY_DEVICE_STATUS) pMyInfo->status; ++ ++ switch(type) ++ { ++ case ACCESSORY_DEVICE_USB_PORT: ++ if (cable_hotplug_attach) ++ (*cable_hotplug_attach)(status); ++ switch(status) ++ { ++ case ACCESSORY_DEVICE_STATUS_DETACHED: ++ apm_queue_event(KRNL_ACCS_DETACH); ++ break; ++ case ACCESSORY_DEVICE_STATUS_ATTACHED: ++ apm_queue_event(KRNL_ACCS_ATTACH); ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ return; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: log system stored in buffer. it can output via FFUART. also you can change a little to other output mode. ++ ++ INPUTS: none. ++ ++ ++ OUTPUTS: none. ++ ++ ++ IMPORTANT NOTES: the macro PCAP_LOG_FFUART_OUT is a switch. ++ it is auto-output to FFUART every PCAP_LOG_OUTPUT_TIMER seconds ++ ++ ++---------------------------------------------------------------------------*/ ++/* record log system by linwq */ ++//#define PCAP_LOG_FFUART_OUT ++ ++#ifdef PCAP_LOG_FFUART_OUT ++static struct timer_list pcap_outlog_timer; ++ ++#define PCAP_LOG_OUTPUT_TIMER 60 ++#define PCAP_LOG_RECORD_LENGTH 50000 ++ ++unsigned char pcap_log_data[PCAP_LOG_RECORD_LENGTH]; ++ ++u8* pcap_log_now_address = pcap_log_data; ++#define PCAP_LOG_START_ADDRESS pcap_log_data ++#define PCAP_LOG_END_ADDRESS pcap_log_data + PCAP_LOG_RECORD_LENGTH ++u32 pcap_log_len = 0; ++ ++void pcap_log_add_pure_data(u8* pData,u32 len) ++{ ++ u32 i; ++ if ((pData ==NULL)|| len == 0) ++ return; ++ for(i = 0;i<len;i++) ++ { ++ *pcap_log_now_address ++ = pData[i]; ++ if( PCAP_LOG_END_ADDRESS == pcap_log_now_address ) ++ pcap_log_now_address = PCAP_LOG_START_ADDRESS; ++ pcap_log_len++; ++ if(pcap_log_len >= PCAP_LOG_RECORD_LENGTH) ++ pcap_log_len = PCAP_LOG_RECORD_LENGTH; ++ } ++ return; ++} ++ ++void pcap_log_add_data(u8* pData,u32 len) ++{ ++ u32 i; ++ u8 temp[20]; ++ if ((pData ==NULL)|| len == 0) ++ return; ++ sprintf(temp,"\n <%d MS>",(int)(OSCR/3686)); ++ for(i = 0;i<(u32)strlen(temp);i++) ++ { ++ *pcap_log_now_address ++ = temp[i]; ++ if( PCAP_LOG_END_ADDRESS == pcap_log_now_address ) ++ pcap_log_now_address = PCAP_LOG_START_ADDRESS; ++ pcap_log_len++; ++ if(pcap_log_len >= PCAP_LOG_RECORD_LENGTH) ++ pcap_log_len = PCAP_LOG_RECORD_LENGTH; ++ } ++ ++ for(i = 0;i<len;i++) ++ { ++ *pcap_log_now_address ++ = pData[i]; ++ if( PCAP_LOG_END_ADDRESS == pcap_log_now_address ) ++ pcap_log_now_address = PCAP_LOG_START_ADDRESS; ++ pcap_log_len++; ++ if(pcap_log_len >= PCAP_LOG_RECORD_LENGTH) ++ pcap_log_len = PCAP_LOG_RECORD_LENGTH; ++ } ++ return; ++} ++ ++static void pcap_log_output_from_ffuart(void) ++{ ++ u32 i; ++ u32 ssp_ffuart_dll,ssp_ffuart_dlh; ++ u8 ssp_ffuart_cken = 1,ssp_ffuart_en = 1; ++ if(0 == pcap_log_len) ++ return; ++ ++ /* if cable in NOT UART cable, should return */ ++ printk("\n *********log out ************* \n <%d jiffies>log:",(int)jiffies); ++ local_irq_disable(); ++ if(!(CKEN&CKEN6_FFUART)) ++ { ++ ssp_ffuart_cken = 0; ++ CKEN |= CKEN6_FFUART; ++ pcap_log_add_data("FFUART CLK not ENABLE!",strlen("FFUART CLK not ENABLE!")); ++ } ++ ++ FFLCR = (FFLCR&0xff)|0x80; ++ ssp_ffuart_dll = FFDLL&0xff; ++ ssp_ffuart_dlh = FFDLH&0xff; ++ FFLCR = FFLCR&0x7f; ++ ++ if((0x08 !=ssp_ffuart_dll)||(0x00 != ssp_ffuart_dlh)) ++ { ++ FFLCR = 0x83; ++ FFDLL = 0x08; ++ FFDLH = 0; ++ FFLCR = 0x03; ++ } ++ ++ if(!(FFIER&0x00000040)) ++ { ++ ssp_ffuart_en = 0; ++ FFIER |= 0x00000040; ++ pcap_log_add_data("FFUART model not ENABLE!",strlen("FFUART model not ENABLE!")); ++ } ++ ++ for(i=0;i<pcap_log_len;i++) ++ { ++ while((FFLSR &0x40) == 0); ++ FFTHR = pcap_log_data[i]; ++ } ++ if(!ssp_ffuart_cken) ++ { ++ CKEN &= ~CKEN6_FFUART; ++ } ++ ++ ++ if((0x08 !=ssp_ffuart_dll)||(0x00 != ssp_ffuart_dlh)) ++ { ++ FFLCR = 0x83; ++ FFDLL = ssp_ffuart_dll; ++ FFDLH = ssp_ffuart_dlh; ++ FFLCR = 0x03; ++ } ++ ++ if(!ssp_ffuart_en) ++ { ++ CKEN &= ~CKEN6_FFUART; ++ } ++ local_irq_enable(); ++ ++ printk("\n ********* log end ************ \n"); ++} ++ ++static void pcap_log_output_from_stuart(void) ++{ ++ u32 i; ++ u32 ssp_stuart_dll,ssp_stuart_dlh; ++ u8 ssp_stuart_cken = 1,ssp_stuart_en = 1; ++ if(0 == pcap_log_len) ++ return; ++ ++ /* if cable in NOT UART cable, should return */ ++ printk("\n *********log out ************* \n <%d jiffies>log:",(int)jiffies); ++ local_irq_disable(); ++ if(!(CKEN&CKEN5_STUART)) ++ { ++ ssp_stuart_cken = 0; ++ CKEN |= CKEN5_STUART; ++ pcap_log_add_data("STUART CLK not ENABLE!",strlen("STUART CLK not ENABLE!")); ++ } ++ ++ STLCR = (STLCR&0xff)|0x80; ++ ssp_stuart_dll = STDLL&0xff; ++ ssp_stuart_dlh = STDLH&0xff; ++ STLCR &= 0x7f; ++ ++ if((0x08 !=ssp_stuart_dll)||(0x00 != ssp_stuart_dlh)) ++ { ++ STLCR = 0x83; ++ STDLL = 0x08; ++ STDLH = 0; ++ STLCR = 0x03; ++ } ++ ++ if(!(STIER&0x00000040)) ++ { ++ ssp_stuart_en = 0; ++ STIER |= 0x00000040; ++ pcap_log_add_data("STUART model not ENABLE!",strlen("STUART model not ENABLE!")); ++ }ACCESSORY_DEVICE_STATUS ++ ++ for(i=0;i<pcap_log_len;i++) ++ { ++ while((STLSR &0x40) == 0); ++ STTHR = pcap_log_data[i]; ++ } ++ if(!ssp_stuart_cken) ++ { ++ CKEN &= ~CKEN5_STUART; ++ } ++ ++ ++ if((0x08 !=ssp_stuart_dll)||(0x00 != ssp_stuart_dlh)) ++ { ++ STLCR = 0x83; ++ STDLL = ssp_stuart_dll; ++ STDLH = ssp_stuart_dlh; ++ STLCR = 0x03; ++ } ++ ++ if(!ssp_stuart_en) ++ { ++ CKEN &= ~CKEN5_STUART; ++ } ++ local_irq_enable(); ++ ++ printk("\n ********* log end ************ \n"); ++} ++ ++ ++static void pcap_output_log_handler( u32 data) ++{ ++ pcap_log_output_from_stuart(); ++ ++ pcap_outlog_timer.function = pcap_output_log_handler; ++ pcap_outlog_timer.expires = (jiffies + PCAP_LOG_OUTPUT_TIMER * HZ); ++ add_timer(&pcap_outlog_timer); ++} ++ ++static void pcap_output_log_init(void) ++{ ++ init_timer(&pcap_outlog_timer); ++ pcap_outlog_timer.function = pcap_output_log_handler; ++ pcap_outlog_timer.expires = (jiffies + 2*PCAP_LOG_OUTPUT_TIMER * HZ); ++ add_timer(&pcap_outlog_timer); ++} ++/* record log end */ ++#else ++void pcap_log_add_pure_data(u8* pData,u32 len) ++{ ++ return; ++} ++ ++void pcap_log_add_data(u8* pData,u32 len) ++{ ++ return; ++} ++#endif ++ ++void ssp_pcap_screenlock_lock(u32 data) ++{ ++ u32 flags; ++ save_flags(flags); ++ local_irq_disable(); ++ del_timer(&ssp_tsi_timer); ++ ssp_pcap_clear_int(); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ ssp_pcap_screenlock_status = 1 ; ++ restore_flags(flags); ++} ++ ++void ssp_pcap_screenlock_unlock(u32 data) ++{ ++ u32 flags; ++ save_flags(flags); ++ local_irq_disable(); ++ del_timer(&ssp_pcap_screenlock_timer); ++ ssp_pcap_clear_int(); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ ssp_pcap_screenlock_status = 0 ; ++ restore_flags(flags); ++} ++ ++static void ssp_pcap_screenlock_lockhandler(u32 data) ++{ ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("lockscreen timer arrived!",strlen("lockscreen timer arrived!")); ++#endif ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ return; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: GPIO init for operating PCAP via GPIO mode. ++ ++ INPUTS: none. ++ ++ ++ OUTPUTS: none. ++ ++ ++ IMPORTANT NOTES: auto-recognized pcap's CE signal. init PCAP's register. ++ ++ ++---------------------------------------------------------------------------*/ ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ ++static u32 test_pcap_cs_rxd(void) ++{ ++ u32 ret = FALSE; ++ u32 temp; ++ /* write a data 0x0003ffff to IMR */ ++ SSP_PCAP_write_data_to_PCAP(1, 0x0003ffff); ++ SSP_PCAP_read_data_from_PCAP(1, &temp); ++ if( 0x0003ffff == temp) ++ ret = TRUE; ++ return ret; ++} ++ ++static void ssp_pcap_gpioInit(void) ++{ ++ u32 i; ++ u32 tempValue; ++ u32 ret; ++ /* stop SPI port work mode disable SPI clock */ ++ SSCR0 = 0x00000000; ++ CKEN &= ~CKEN23_SSP1; ++ ++ /* the four PIN as GPIO mode */ ++ pxa_gpio_mode(GPIO_SPI_CLK|GPIO_OUT); ++ pxa_gpio_mode(GPIO_SPI_CE|GPIO_OUT); ++ pxa_gpio_mode(GPIO_SPI_MOSI|GPIO_OUT); ++ pxa_gpio_mode(GPIO_SPI_MISO|GPIO_IN); ++ ++ /* test pcap's CE with inverter??? */ ++ ssp_pcap_operate_pin_with_inverter = 0; ++ ssp_pcap_rxd_pin_with_inverter = 0; ++ ++ /* deassert SEC_CE */ ++ GPCR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ for(i=0;i<500;i++); ++ ret = test_pcap_cs_rxd(); ++ ++ if (FALSE == ret) ++ { ++ ssp_pcap_operate_pin_with_inverter = 0; ++ ssp_pcap_rxd_pin_with_inverter = 1; ++ /* deassert SEC_CE */ ++ GPCR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ for(i=0;i<500;i++); ++ ret = test_pcap_cs_rxd(); ++ } ++ ++ if (FALSE == ret) ++ { ++ ssp_pcap_operate_pin_with_inverter = 1; ++ ssp_pcap_rxd_pin_with_inverter = 0; ++ /* deassert SEC_CE */ ++ GPSR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ for(i=0;i<500;i++); ++ ret = test_pcap_cs_rxd(); ++ } ++ ++ ++ if (FALSE == ret) ++ { ++ ssp_pcap_operate_pin_with_inverter = 1; ++ ssp_pcap_rxd_pin_with_inverter = 1; ++ /* deassert SEC_CE */ ++ GPSR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ for(i=0;i<500;i++); ++ ret = test_pcap_cs_rxd(); ++ } ++ ++ if (FALSE == ret ) ++ { ++ printk("\n Bulverde can not communicate with PCAP!!!!"); ++ return; ++ } ++ ++ SSP_PCAP_write_data_to_PCAP(1, 0x0013ffff); ++ ++ for(i=0; i<32 ;i++) ++ { ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_read_data_from_PCAP(i,&tempValue)) ++ { ++ ssp_pcap_registerValue[i] = tempValue; ++ } ++ else ++ { ++ ssp_pcap_registerValue[i] = 0; ++ } ++ } ++ return; ++} ++ ++ ++static void ssp_pcap_gpioClkControl(u32 bitValue) ++{ ++ if(bitValue) ++ { ++ GPSR(GPIO_SPI_CLK) = GPIO_bit(GPIO_SPI_CLK); ++ } ++ else ++ { ++ GPCR(GPIO_SPI_CLK) = GPIO_bit(GPIO_SPI_CLK); ++ } ++} ++ ++static void ssp_pcap_gpioFrmControl(u32 bitValue) ++{ ++ if( ssp_pcap_operate_pin_with_inverter ) ++ { ++ if(bitValue) ++ { ++ GPCR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ } ++ else ++ { ++ GPSR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ } ++ } ++ else ++ { ++ if(bitValue) ++ { ++ GPSR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ } ++ else ++ { ++ GPCR(GPIO_SPI_CE) = GPIO_bit(GPIO_SPI_CE); ++ } ++ } ++} ++ ++static void ssp_pcap_gpioTxdControl(u32 bitValue) ++{ ++ if(bitValue) ++ { ++ GPSR(GPIO_SPI_MOSI) = GPIO_bit(GPIO_SPI_MOSI); ++ } ++ else ++ { ++ GPCR(GPIO_SPI_MOSI) = GPIO_bit(GPIO_SPI_MOSI); ++ } ++} ++ ++static u32 ssp_pcap_gpioRxdGetStatus(void) ++{ ++ if(ssp_pcap_rxd_pin_with_inverter) ++ { ++ if( GPLR(GPIO_SPI_MISO)&GPIO_bit(GPIO_SPI_MISO) ) ++ { ++ return SSP_PCAP_BIT_ZERO; ++ } ++ else ++ { ++ return SSP_PCAP_BIT_ONE; ++ } ++ } ++ else ++ { ++ if( GPLR(GPIO_SPI_MISO)&GPIO_bit(GPIO_SPI_MISO) ) ++ { ++ return SSP_PCAP_BIT_ONE; ++ } ++ else ++ { ++ return SSP_PCAP_BIT_ZERO; ++ } ++ } ++} ++ ++static void ssp_pcap_gpioWrite(u32 pcapValue) ++{ ++ u32 tempValue; ++ u32 loopValue = 0x80000000; ++ int i; ++ /* prepare for starting the frame */ ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ ssp_pcap_gpioFrmControl(SSP_PCAP_BIT_ZERO); ++ ssp_pcap_gpioTxdControl(SSP_PCAP_BIT_ZERO); ++ ++ /* start the data transfering frame */ ++ ssp_pcap_gpioFrmControl(SSP_PCAP_BIT_ONE); ++ for(i=0;i<32;i++) ++ { ++ tempValue = pcapValue&loopValue; ++ /* setup data bit to TXD line */ ++ ssp_pcap_gpioTxdControl(tempValue); ++ /* create clock */ ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ONE); ++ loopValue = loopValue/2; ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ } ++ /* end the frame */ ++ ssp_pcap_gpioFrmControl(SSP_PCAP_BIT_ZERO); ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( " \n Write END \n " ); ++#endif ++ return; ++} ++ ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++ ++static void ssp_pcap_gpioRead( u32 registerNumber,u32* pPcapValue) ++{ ++ int i; ++ u32 tempValue; ++ u32 loopValue = 0x80000000; ++ ++ /* prepare for starting the frame */ ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ ssp_pcap_gpioFrmControl(SSP_PCAP_BIT_ZERO); ++ ssp_pcap_gpioTxdControl(SSP_PCAP_BIT_ZERO); ++ ++ /* start the data transfering frame */ ++ ssp_pcap_gpioFrmControl(SSP_PCAP_BIT_ONE); ++ /* indictaor it's a read data command */ ++ ssp_pcap_gpioTxdControl(SSP_PCAP_BIT_ZERO); ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ONE); ++ loopValue = loopValue/2; ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ ++ for(i=0; i<5;i++) ++ { ++ /* here maybe can be optimized */ ++ tempValue = registerNumber&(loopValue/0x04000000); ++ ssp_pcap_gpioTxdControl(tempValue); ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ONE); ++ loopValue = loopValue/2; ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ } ++ ++ /* the dead bit */ ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ONE); ++ loopValue = loopValue/2; ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ ++ tempValue = 0; ++ for(i=0;i<25;i++) ++ { ++ tempValue |= loopValue*ssp_pcap_gpioRxdGetStatus(); ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ONE); ++ loopValue = loopValue/2; ++ ssp_pcap_gpioClkControl(SSP_PCAP_BIT_ZERO); ++ } ++ /* end the data frame */ ++ ssp_pcap_gpioFrmControl(SSP_PCAP_BIT_ZERO); ++ if(pPcapValue) ++ { ++ *pPcapValue = tempValue; ++ } ++ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk(" \n Read Data end \n"); ++#endif ++ return ; ++} ++ ++#endif ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ ++void SSPTest(void) ++{ ++ char string[80]; ++ u32 i,j,k; ++ u16 x,y; ++ u32 tempValue; ++ // ssp_pcap_init(); ++// ssp_pcap_open(); ++ printk(" \n ****************************** \n SSP TEST \n *****************\n "); ++// SSP_vibrate_start_command(); ++// for(i=0; i<100000000; i++); ++// SSP_vibrate_stop_command(); ++ SSP_PCAP_write_data_to_PCAP(3,0x0fffffff); ++ ++ SSP_PCAP_read_data_from_PCAP(0,&k); ++ SSP_PCAP_write_data_to_PCAP(0,k); ++ ++ for(i =0;i<32;i++) ++ { ++ SSP_PCAP_read_data_from_PCAP(i,&k); ++ sprintf(string,"pcap register %d = 0x%x! \n",i,k); ++ printk(string); ++ } ++ ++ SSP_PCAP_read_data_from_PCAP(0,&k); ++ SSP_PCAP_write_data_to_PCAP(0,k); ++ ++ ++// SSP_PCAP_write_data_to_PCAP(9,0x000a0000); ++ printk( "\n ************* \n test TS position start \n "); ++ ++ for(i=0;i<10000;i++) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ if(tempValue) ++ { ++ ++ sprintf(string, "GEDR0 = %x ICPR = %x ICMR= %x \n ",GEDR0,ICPR,ICMR ); ++ printk(string); ++ GEDR0 = GEDR0; ++ ICPR = ICPR; ++ ++ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ ++ SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ tempValue = 0 ; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ } ++ SSP_PCAP_TSI_get_XY_value(&x,&y); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ ++ sprintf(string,"\n TS xy pressure X=%d y=%d \n",x,y); ++ printk(string); ++ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ ++ SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ tempValue = 0 ; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ } ++ SSP_PCAP_TSI_get_XY_value(&x,&y); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ ++ sprintf(string,"\n TS xy pressure X=%d y=%d \n",x,y); ++ printk(string); ++ ++ ++ SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ tempValue = 0 ; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ } ++ SSP_PCAP_TSI_get_XY_value(&x,&y); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ ++ sprintf(string,"\n TS xy possition X=%d y=%d \n",x,y); ++ printk(string); ++ ++ SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ tempValue = 0 ; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ } ++ SSP_PCAP_TSI_get_XY_value(&x,&y); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ ++ sprintf(string,"\n TS xy pressure X=%d y=%d \n",x,y); ++ printk(string); ++ ++ i = 0; ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M); ++ // SSP_PCAP_write_data_to_PCAP(9,0x000a0000); ++ ++ } ++ for(j=0;j<60000;j++); ++ } ++ printk(" TS pressure test start \n "); ++ ++ SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ tempValue = 0 ; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_ADCDONEI); ++ } ++ SSP_PCAP_TSI_get_XY_value(&x,&y); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONEI); ++ ++ sprintf(string,"\n TS xy pressure X=%d y=%d \n",x,y); ++ printk(string); ++ ++ SSP_PCAP_read_data_from_PCAP(0,&tempValue); ++ ++ sprintf(string," before clean ISR = %x \n ", tempValue ); ++ printk(string); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_read_data_from_PCAP(0,&tempValue); ++ sprintf(string," after clean ISR = %x \n ", tempValue ); ++ printk(string); ++ GEDR0 = GEDR0; ++ ICPR = ICPR; ++ ++ tempValue = 0; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_TSI); ++ tempValue &= 0x00000001; ++ } ++ SSP_PCAP_read_data_from_PCAP(0,&tempValue); ++ SSP_PCAP_read_data_from_PCAP(1,&k); ++ sprintf(string, " MSR = %8x ISR= %8x, GEDR0 = %8x ICPR = %8x \n",k,tempValue,GEDR0,ICPR); ++ printk(string); ++ GEDR0 = GEDR0; ++ ICPR = ICPR; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); ++ SSP_PCAP_TSI_start_XY_read(); ++ tempValue = 0; ++ while(!tempValue) ++ { ++ tempValue = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ tempValue &= 0x00000001; ++ } ++ for(i=0;i<60000;i++); ++ SSP_PCAP_read_data_from_PCAP(0,&tempValue); ++ sprintf(string," ISR =%8x GEDR0 =%8x ICPR = %8x \n",tempValue,GEDR0,ICPR); ++ printk(string); ++ SSP_PCAP_TSI_get_XY_value(&x,&y); ++ sprintf(string," TS pressure x = %d y= %d \n" ,x,y ); ++ printk(string); ++ return; ++} ++#else ++static u32 test_pcap_spi(void) ++{ ++ u32 ret = FALSE; ++ int i; ++ u32 temp; ++ /* write a data 0x0003ffff to IMR */ ++ SSP_PCAP_write_data_to_PCAP(1, 0x0003ffff); ++ SSP_PCAP_read_data_from_PCAP(1, &temp); ++ if( 0x0003ffff == temp) ++ ret = TRUE; ++ ++ SSP_PCAP_write_data_to_PCAP(1, 0x0013ffff); ++ ++ for(i=0; i<32 ;i++) ++ { ++ if(SSP_PCAP_SUCCESS == SSP_PCAP_read_data_from_PCAP(i,&temp)) ++ { ++ ssp_pcap_registerValue[i] = temp; ++ } ++ else ++ { ++ ssp_pcap_registerValue[i] = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++#endif ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++static int pcap_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ ssp_pcap_intoSleepCallBack(); ++ break; ++ case PM_RESUME: ++ ssp_pcap_wakeUpCallBack(); ++ break; ++ } ++ return 0; ++} ++static int ssp_pcap_init_is_ok = 0; ++void ssp_pcap_init(void) ++{ ++#ifdef SSP_PCAP_DEBUG_BOARD ++ U32 tempValue; ++#endif ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ char debugStr[100]; ++ sprintf(debugStr,"\n ***************** \n SSP init start \n"); ++ printk(debugStr); ++#endif ++ ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++ CKEN |= CKEN23_SSP1; ++ pxa_gpio_mode(29|GPIO_ALT_FN_3_OUT); ++ pxa_gpio_mode(GPIO24_SFRM_MD); ++ pxa_gpio_mode(GPIO25_STXD_MD); ++ pxa_gpio_mode(GPIO26_SRXD_MD); ++ ++ SSCR1 = SSCR1_TxTresh(1) | SSCR1_RxTresh(1); ++ SSCR0 = 0x00000000; ++ SSCR0 = SSCR0_DataSize(16) | SSCR0_EDSS | SSCR0_SSE | SSCR0_SerClkDiv(1); ++ ++ init_waitqueue_head(&ssp_pcap_send_wait); ++ //request_irq(IRQ_SSP,ssp_interrupt_routine,0,"SSP received the data irq ",NULL); ++ ++ test_pcap_spi(); ++#else ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk(" \n ********************* \n SSP GPIO mode init \n"); ++#endif ++ if(!ssp_pcap_init_is_ok) ++ { ++ ssp_pcap_gpioInit(); ++ ssp_pcap_init_is_ok = 1; ++ } ++#endif ++ ++#ifdef SSP_PCAP_DEBUG_BOARD ++ printk("\n ********************* \n SSP DEBUG BOARD init \n "); ++ tempValue = GPDR2; ++ tempValue = tempValue&0x0001ffff; ++ tempValue |= 0x00010000; ++ GPDR2 = tempValue; ++ GAFR2_U = 0x00000002; ++#endif ++ pxa_gpio_mode(GPIO_PCAP_SEC_INT | GPIO_IN); ++ set_GPIO_IRQ_edge(GPIO_PCAP_SEC_INT,GPIO_RISING_EDGE); ++ ++ //request_irq(IRQ_GPIO1,ssp_pcap_interrupt_routine,0,"PCAP request irq ",NULL); ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_output_log_init(); ++#endif ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk(" \n *********************** \n SSP init END \n "); ++#endif ++ init_timer(&ssp_tsi_timer); ++ ssp_tsi_timer.function = ssp_tsi_keeper; ++ ++ init_timer(&ssp_usb_accessory_debounce_timer); ++ ssp_usb_accessory_debounce_timer.function = ssp_usb_accessory_debounce_handler; ++ ++ ssp_pcap_screenlock_status = 0 ; ++ init_timer(&ssp_pcap_screenlock_timer); ++ ssp_pcap_screenlock_timer.function = ssp_pcap_screenlock_lockhandler; ++ ++ /* since in GPIO init, we have gotten the register's value. */ ++// SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_MSR_USB4VM ); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_ISR_USB4VI); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_USB4VM); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_ISR_USB1VI); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_USB1VM); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ ++ /* set SW1 sleep to keep SW1 1.3v in sync mode */ ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10 ); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11 ); ++ /* SW1 active in sync mode */ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00 ); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01); ++ /* at SW1 -core voltage to 1.30V */ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS); ++ ++ /* when STANDY2 PIN ACTIVE (high) set V3-- sram V8 -- pll off */ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_VREG2_V3_STBY); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR); ++ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_VREG2_V8_STBY); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR); ++ ++ /* when STANDY2 PIN ACTIVE (high) set V4-- lcd only for e680 V6 --- camera for e680 */ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_VREG2_V4_STBY); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR); ++ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_VREG2_V6_STBY); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR); ++ ++ /* set Vc to low power mode when AP sleep */ ++ //SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY); ++ ++ /* set VAUX2 to voltage 2.775V and low power mode when AP sleep */ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN ); ++ ++ PGSR(GPIO34_TXENB) |= GPIO_bit(GPIO34_TXENB); ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V )) ++ { ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_ATTACHED,NULL); ++ } ++ else ++ { ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_DETACHED,NULL); ++ } ++ /* register pm callback function */ ++ /* only for temp solution 2004-05-10 */ ++#ifdef PCAP2_V1.4_AND_BEFORE ++ pxa_gpio_mode(GPIO_TC_MM_EN | GPIO_OUT ); ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ PGSR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ /* the PM callback will move to apm.c */ ++// pcap_pm_dev = pm_register(PM_SYS_DEV,0,pcap_pm_callback); ++ return; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void pcap_switch_off_usb(void) ++{ ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ if(!ssp_pcap_init_is_ok) ++ { ++ ssp_pcap_gpioInit(); ++ ssp_pcap_init_is_ok = 1; ++ } ++#endif ++ /* only for PST tool recognize the USB cable */ ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V )) ++ { ++ SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ } ++ return; ++} ++ ++void pcap_switch_on_usb(void) ++{ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V )) ++ { ++// stop_ffuart(); ++// usb_gpio_init(); ++ } ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void ssp_pcap_release(void) ++{ ++/* the PM callback will move to apm.c */ ++// pm_unregister(pcap_pm_dev); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void ssp_pcap_open(SSP_PCAP_INIT_DRIVER_TYPE portType) ++{ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ u32 i; ++ u32 tempValue; ++#endif ++#ifdef SSP_PCAP_DEBUG_BOARD ++ /* select the primary SPI of PCAP */ ++ *SSP_SELECT_BUFFER = 0x00000094; ++ SSP_PCAP_write_data_to_PCAP(3, 0x00100002); ++ SSP_PCAP_write_data_to_PCAP(20,0x010000a4); ++ SSP_PCAP_bit_set(0x58080000 ); ++ SSP_PCAP_TSI_mode_set(PCAP_TS_STANDBY_MODE); ++ *SSP_SELECT_BUFFER = 0x00000070; ++#endif ++ switch(portType) ++ { ++ case SSP_PCAP_TS_OPEN: ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk(" \n SSP TS open!!! "); ++#endif ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_TS_REFENB ); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I); ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC2_ADINC1); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC2_ADINC2); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_ATO0); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_ATO1); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_ATO2); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_ATO3); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_ATOX); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_MTR1); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ADC1_MTR2); ++ SSP_PCAP_TSI_mode_set(PCAP_TS_STANDBY_MODE); ++ /* send the usb accessory infomation to PM */ ++ if((ACCESSORY_TYPE) sspUsbAccessoryInfo.type == ACCESSORY_DEVICE_USB_PORT) ++ { ++ if( (ACCESSORY_DEVICE_STATUS )sspUsbAccessoryInfo.status == ACCESSORY_DEVICE_STATUS_ATTACHED ) ++ apm_queue_event(KRNL_ACCS_ATTACH); ++ else ++ apm_queue_event(KRNL_ACCS_DETACH); ++ } ++ break; ++ case SSP_PCAP_AUDIO_OPEN: ++ break; ++ default: ++ break; ++ } ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ for(i=0;i<32;i++) ++ { ++ SSP_PCAP_read_data_from_PCAP(i, &tempValue); ++ printk("\n PCAP register %d = 0x%x!",i,tempValue); ++ } ++#endif ++ return; ++} ++EXPORT_SYMBOL(ssp_pcap_open); ++EXPORT_SYMBOL(SSP_PCAP_bit_set); ++EXPORT_SYMBOL(SSP_PCAP_bit_clean); ++ ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void ssp_pcap_close(void) ++{ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_MSR_REGISTER,PCAP_MASK_ALL_INTERRUPT); ++ return; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void ssp_pcap_intoSleepCallBack(void) ++{ ++ /* set TS_REF to low power mode */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M); ++ /* set SPI_CLK as input PIN */; ++ GPDR(GPIO_SPI_CLK) &= ~GPIO_bit(GPIO_SPI_CLK); ++ /* set SPI_MOSI as input PIN */ ++ GPDR(GPIO_SPI_MOSI) &= ~GPIO_bit(GPIO_SPI_MOSI); ++ /* set PCAP's CE pin to dessert signal SPI_CE must be in range of 0~31 PIN */ ++ if(ssp_pcap_operate_pin_with_inverter) ++ { ++ PGSR0 |= GPIO_bit(GPIO_SPI_CE); ++ } ++ else ++ { ++ PGSR0 &= ~GPIO_bit(GPIO_SPI_CE); ++ } ++} ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void ssp_pcap_wakeUpCallBack(void) ++{ ++#ifdef PCAP2_V1.4_AND_BEFORE ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++#endif ++ /* set SPI_CLK to output PIN */; ++ GPDR(GPIO_SPI_CLK) |= GPIO_bit(GPIO_SPI_CLK) ; ++ /* set SPI_MOSI to output PIN */ ++ GPDR(GPIO_SPI_MOSI) |= GPIO_bit(GPIO_SPI_MOSI); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_MB2M); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_PORT_TYPE portType) ++{ ++ SSP_PCAP_STATUS ret = SSP_PCAP_SUCCESS; ++ switch(portType) ++ { ++ case SSP_PCAP_SERIAL_PORT: ++ /* according to HW requirement, do not clear VUSB_EN 2004-05-11 */ ++ //ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ if(SSP_PCAP_SUCCESS == ret) ++ { ++ ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ } ++ break; ++ case SSP_PCAP_LOW_USB_PORT: ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ if(SSP_PCAP_SUCCESS == ret) ++ { ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB); ++ } ++ if(SSP_PCAP_SUCCESS == ret) ++ { ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ } ++ break; ++ case SSP_PCAP_HIGH_USB_PORT: ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); ++ if(SSP_PCAP_SUCCESS == ret) ++ { ++ ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB); ++ } ++ if(SSP_PCAP_SUCCESS == ret) ++ { ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); ++ } ++ break; ++ default: ++ ret = SSP_PCAP_NOT_RUN ; ++ break; ++ } ++ return ret; ++} ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++ ++SSP_PCAP_STATUS SSP_PCAP_TSI_mode_set(TOUCH_SCREEN_DETECT_TYPE mode_Type ) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ADC1_REGISTER]&(~SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK); ++ tempValue = tempValue|mode_Type; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ADC1_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_TSI_start_XY_read(void) ++{ ++ SSP_PCAP_STATUS ret = SSP_PCAP_SUCCESS; ++ U32 tempValue; ++#ifdef PCAP2_V1.4_AND_BEFORE ++ /* invert the TC_MM_EN pin to alert BP */ ++ u32 i; ++ if(GPLR(GPIO_TC_MM_EN)&GPIO_bit(GPIO_TC_MM_EN)) ++ { ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ } ++ else ++ { ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ } ++ for(i=0;i<0x00002000;i++); ++ if(GPLR(GPIO_TC_MM_EN)&GPIO_bit(GPIO_TC_MM_EN)) ++ { ++ GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ } ++ else ++ { ++ GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); ++ } ++#endif ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ADC1_REGISTER]&SSP_PCAP_ADC_START_VALUE_SET_MASK; ++ tempValue |= SSP_PCAP_ADC_START_VALUE; ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ADC1_REGISTER,tempValue); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ADC2_ASC); ++ return ret; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: y reads TSX1's ADC value in ADD2 register, x reads TSY1's ADC value in ADD1 register. ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_TSI_get_XY_value(P_U16 p_x,P_U16 p_y) ++{ ++ U32 tempValue; ++ SSP_PCAP_STATUS ret = SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_ADC2_REGISTER,&tempValue); ++ if( SSP_PCAP_SUCCESS != ret) ++ return ret; ++ if(ssp_pcap_screenlock_status) ++ { ++ *p_x = 0; ++ *p_y = 0; ++ SSP_PCAP_TSI_mode_set(PCAP_TS_STANDBY_MODE); ++ mod_timer(&ssp_pcap_screenlock_timer,jiffies + SSP_PCAP_TS_KEEPER_TIMER); ++ return ret; ++ } ++ if(tempValue&0x00400000) ++ return SSP_PCAP_ERROR_VALUE; ++ if(p_x) ++ { ++ *p_x = (U16)(tempValue&SSP_PCAP_ADD1_VALUE_MASK); ++ } ++ if(p_y) ++ { ++ *p_y = (U16)((tempValue&SSP_PCAP_ADD2_VALUE_MASK)>>SSP_PCAP_ADD2_VALUE_SHIFT); ++ } ++ SSP_PCAP_TSI_mode_set(PCAP_TS_STANDBY_MODE); ++ return ret; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++ ++SSP_PCAP_STATUS SSP_PCAP_CDC_CLK_set(PHONE_CDC_CLOCK_TYPE clkType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUD_CODEC_REGISTER]&(~SSP_PCAP_PHONE_CDC_CLOCK_MASK); ++ tempValue = tempValue|clkType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_V_VIB_level_set(VibratorVoltageLevel_TYPE VIBLevelType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUX_VREG_REGISTER]&(~SSP_PCAP_VIBRATOR_VOLTAGE_LEVEL_MASK); ++ tempValue = tempValue|VIBLevelType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUX_VREG_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_CDC_SR_set(ST_SAMPLE_RATE_TYPE srType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_STEREO_SAMPLE_RATE_MASK); ++ tempValue = tempValue|srType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_BCLK_set(ST_BCLK_TIME_SLOT_TYPE bclkType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_STEREO_BCLK_TIME_SLOT_MASK); ++ tempValue = tempValue|bclkType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_STCLK_set(ST_CLK_TYPE stClkType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_STEREO_CLOCK_MASK); ++ tempValue = tempValue|stClkType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_DIG_AUD_FS_set(DIG_AUD_MODE_TYPE fsType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_DIGITAL_AUDIO_MODE_MASK); ++ tempValue = tempValue|fsType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_AUDIG_set(U32 audioInGain) ++{ ++ U32 tempValue; ++ if (audioInGain > PCAP_AUDIO_IN_GAIN_MAX_VALUE) ++ return SSP_PCAP_ERROR_VALUE; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER]&(~SSP_PCAP_AUDIO_IN_GAIN_MASK); ++ ++ /* shoulb be better like this tempValue |= audioInGain <<SSP_PCAP_AUDIO_IN_GAIN_SHIFT; */ ++ tempValue = tempValue|audioInGain; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_MONO_set(MONO_TYPE monoType) ++{ ++ U32 tempValue; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER]&(~SSP_PCAP_MONO_PGA_MASK); ++ tempValue = tempValue|monoType; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER,tempValue); ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_AUDOG_set(U32 audioOutGain) ++{ ++ U32 tempValue; ++ if (audioOutGain > PCAP_AUDIO_OUT_GAIN_MAX_VALUE) ++ return SSP_PCAP_ERROR_VALUE; ++ tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER]&(~SSP_PCAP_AUDIO_OUT_GAIN_MASK); ++ tempValue |= audioOutGain <<SSP_PCAP_AUDIO_OUT_GAIN_SHIFT; ++ return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER,tempValue); ++} ++ ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++static int int_executed = 0; ++/* ssp has received 2 bytes, the function will be invoked. */ ++static irqreturn_t ssp_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ) ++{ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk("\n SSP INTERRUPT WAS CALLED \n "); ++#endif ++ if(SSSR&SSP_SR_RNE) ++ { ++#if 0 ++ ssp_pcap_readValue = (SSDR&SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK)<<16; ++ if(SSSR&SSP_SR_RNE) ++ { ++ ssp_pcap_readValue += (SSDR&SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK); ++ if(SSSR&SSP_SR_RNE) ++ { ++ while(SSSR&SSP_SR_RNE) ++ { ++ ssp_pcap_readValue = (SSDR&SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK); ++ } ++ ssp_pcap_readValue = 0; ++ } ++ } ++#else ++ ssp_pcap_readValue = SSDR; ++#endif ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk("\n SSP INTERRUPT send wakeup info \n "); ++#endif ++ //wake_up(&ssp_pcap_send_wait); ++ int_executed = 1; ++ } ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk("\n SSP INTERRUPT EXIT \n "); ++#endif ++ return IRQ_HANDLED; ++} ++ ++#endif ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++ ++static void ssp_tsi_keeper(u32 data) ++{ ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("TS timer arrived!",strlen("TS timer arrived!")); ++#endif ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_MSR_TSM)) ++ { ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_ISR_TSI); ++ SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ } ++ return; ++} ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++void ssp_pcap_clear_int(void) ++{ ++ U32 tempValue; ++ U32 tempClearInterrupt; ++ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n ************************ \n SSP interrupt by GPIO from sleep. "); ++#endif ++ /* should care the return value */ ++ SSP_PCAP_read_data_from_PCAP( SSP_PCAP_ADJ_ISR_REGISTER,&tempValue); ++ tempClearInterrupt = tempValue&(SSP_PCAP_ADJ_BIT_ISR_MB2I|SSP_PCAP_ADJ_BIT_ISR_STI|SSP_PCAP_ADJ_BIT_ISR_A1I|SSP_PCAP_ADJ_BIT_ISR_USB1VI|SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I|SSP_PCAP_ADJ_BIT_ISR_TSI|SSP_PCAP_ADJ_BIT_ISR_USB4VI); ++ ++ /* send the data to ISR register to clear the interrupt flag */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ISR_REGISTER,tempClearInterrupt); ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I&tempValue) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n SSP ADC interrupt should be discarded." ); ++#endif ++ } ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_TSI&tempValue) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n SSP TSI should be discarded. "); ++#endif ++ } ++ ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_USB4VI&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_USB4VM)) ++ { ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V)) ++ { ++ /* maybe we can support low speed USB how to do??? */ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n SSP USB4VI need handle. "); ++#endif ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_ATTACHED,NULL); ++ } ++ } ++ } ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_USB1VI&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_USB1VM)) ++ { ++ if(SSP_PCAP_BIT_ONE != SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n SSP USB_VBUS less than 1V! need handle."); ++#endif ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_DETACHED,NULL); ++ } ++ } ++ } ++ ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_A1I&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_A1M)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n A1_INT insert/remove case, need to handle. ISR =%x ",tempValue ); ++#endif ++ /* earpiece insert/remove need handler */ ++ if (headjack_change_interrupt_routine) ++ (*headjack_change_interrupt_routine)(0,NULL,NULL); ++ } ++ } ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_MB2I&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_MB2M)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n MIC insert/remove case, need to handle! ISR =%x ",tempValue ); ++#endif ++ //queue_apm_event(KRNL_KEYPAD,NULL); ++ /* mic insert/remove or answer/end call handler */ ++ if(mic_change_interrupt_routine) ++ (*mic_change_interrupt_routine)(0,NULL,NULL); ++ } ++ } ++ return; ++} ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++static u32 ssp_pcap_last_jiffies = 0; ++ ++static void ssp_pcap_ts_send_pMmessage(void) ++{ ++ u32 temp = jiffies - ssp_pcap_last_jiffies; ++ ++ if( temp >SSP_SEND_PM_ALART_INTERVAL) ++ { ++ ssp_pcap_last_jiffies = (u32) jiffies; ++ apm_queue_event(KRNL_TOUCHSCREEN); ++ } ++ return; ++} ++ ++static irqreturn_t ssp_pcap_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ) ++{ ++ u32 pcap_repeat_num; ++ U32 tempValue; ++ u32 tempClearInterrupt; ++#ifdef PCAP_LOG_FFUART_OUT ++ u8 temp[100]; ++ pcap_log_add_data("SSP interrupt by GPIO.",strlen("\n SSP interrupt by GPIO.")); ++#endif ++ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n ************************ \n SSP interrupt by GPIO. "); ++#endif ++ /* should care the return value */ ++ pcap_repeat_num = 0; ++intRepeat: ++ SSP_PCAP_read_data_from_PCAP( SSP_PCAP_ADJ_ISR_REGISTER,&tempValue); ++ tempClearInterrupt = tempValue&(SSP_PCAP_ADJ_BIT_ISR_MB2I|SSP_PCAP_ADJ_BIT_ISR_STI|SSP_PCAP_ADJ_BIT_ISR_A1I|SSP_PCAP_ADJ_BIT_ISR_USB1VI|SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I|SSP_PCAP_ADJ_BIT_ISR_TSI|SSP_PCAP_ADJ_BIT_ISR_USB4VI); ++ ++ /* send the data to ISR register to clear the interrupt flag */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ISR_REGISTER,tempClearInterrupt); ++ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk("\n w17202 TSI = 0x%x ",tempClearInterrupt); ++#endif ++ if(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M)) ++ { ++ /* call read XY callback function */ ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("SSP ADC interrupt need handle.",strlen("SSP ADC interrupt need handle.")); ++#endif ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n ************************** \n SSP ADC interrupt need handle." ); ++#endif ++ ssp_pcap_ts_send_pMmessage(); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ADC1_ADEN); ++ /* 2 seconds protect timer */ ++ /* better used it after linux 2.4.17 */ ++ mod_timer(&ssp_tsi_timer,jiffies + SSP_PCAP_TS_KEEPER_TIMER); ++ //ezx_ts_dataReadok_interrupt(0,NULL,NULL); ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n ************************** \n SSP ADC interrupt should be discarded." ); ++#endif ++ } ++ } ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_TSI&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_TSM)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n ************************* \n SSP TSI need handle."); ++#endif ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("SSP TSI need handle.",strlen("SSP TSI need handle.")); ++#endif ++ ssp_pcap_ts_send_pMmessage(); ++ //if ( pxafb_ezx_getLCD_status() ) ++ if (1) ++ { ++ /* call touch panel callbcak function */ ++ SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM); ++ /* 2 seconds protect timer */ ++ /* better used it after linux 2.4.17 */ ++ mod_timer(&ssp_tsi_timer,jiffies + SSP_PCAP_TS_KEEPER_TIMER);; ++ //ezx_ts_touch_interrupt(0,NULL,NULL); ++ } ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP TSI should be discarded."); ++#endif ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("SSP TSI need not handle.",strlen("SSP TSI need not handle.")); ++#endif ++ } ++ } ++ ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_USB4VI&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_USB4VM)) ++ { ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V)) ++ { ++ /* maybe we can support low speed USB how to do??? */ ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP USB4VI need handle."); ++#endif ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("SSP USB4VI need handle.",strlen("SSP USB4VI need handle.")); ++#endif ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_ATTACHED,NULL); ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n ************************* \n SSP USB4VI low need NOT handle same as USB1VI low."); ++#endif ++ } ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP USB4VI should be discarded."); ++#endif ++ } ++ } ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_USB1VI&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_USB1VM)) ++ { ++ if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP USB_VBUS greater than 1V!"); ++#endif ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP USB_VBUS less than 1V! need handle."); ++#endif ++ accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_DETACHED,NULL); ++ } ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP USB1VI should be discarded."); ++#endif ++ } ++ } ++ ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_A1I&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_A1M)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n A1_INT insert/remove case, need to handle. ISR =%x ",tempValue ); ++#endif ++#ifdef PCAP_LOG_FFUART_OUT ++ sprintf(temp,"A1_INT insert/remove case, need to handle. ISR =%x ",tempValue ); ++ pcap_log_add_data(temp,strlen(temp)); ++#endif ++ /* earpiece insert/remove need handler */ ++ if (headjack_change_interrupt_routine) ++ (*headjack_change_interrupt_routine)(0,NULL,NULL); ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n A1_INT should be discarded." ); ++#endif ++ } ++ } ++ ++ if(SSP_PCAP_ADJ_BIT_ISR_MB2I&tempValue) ++ { ++ if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_MB2M)) ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n MIC insert/remove case, need to handle! ISR =%x ",tempValue ); ++#endif ++#ifdef PCAP_LOG_FFUART_OUT ++ sprintf(temp,"MIC insert/remove case, need to handle! ISR =%x ",tempValue ); ++ pcap_log_add_data(temp,strlen(temp)); ++#endif ++ //queue_apm_event(KRNL_KEYPAD,NULL); ++ /* mic insert/remove or answer/end call handler */ ++ if (mic_change_interrupt_routine) ++ (*mic_change_interrupt_routine)(0,NULL,NULL); ++ } ++ else ++ { ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk( "\n************************* \n SSP MB2I should be discarded."); ++#endif ++ } ++ } ++ if(GPLR0&0x00000002) ++ { ++ /* this case is a very critical case. */ ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("repeat pcap int!",strlen("repeat pcap int!")); ++#endif ++ if(pcap_repeat_num<10) ++ { ++ pcap_repeat_num++; ++ goto intRepeat; ++ } ++ else ++ { ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("repeat pcap exceed 10 times!",strlen("repeat pcap exceed 10 times!")); ++#endif ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++ ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++ ++void ssp_put_intoData(U32 pcapValue) ++{ ++ /* disable all interrupt or disable the SSP (zero to SSE) */ ++ local_irq_disable(); ++ SSDR = pcapValue; ++ local_irq_enable(); ++#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION ++ printk("ssp_put_intoData = 0x%08x\n", pcapValue); ++#endif ++ return; ++} ++ ++#endif ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER sspPcapRegister,U32 registerValue) ++{ ++ u32 pcapTempValue ; ++ unsigned long flags; ++ /* prevent the process schedule out and mask the PCAP's interrupt handler */ ++ //ICMR &= ~(1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ save_flags(flags); ++ //local_irq_disable(); ++#endif ++ spin_lock(&pcapoperation_lock); ++ ++ if(!test_and_set_bit(0,&ssp_pcap_status)) ++ { ++ switch(sspPcapRegister) ++ { ++#ifdef SSP_PCAP_DEBUG_BOARD ++ case 3: ++ case 22: ++#endif ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++ ssp_pcap_registerValue[sspPcapRegister] = registerValue&SSP_PCAP_REGISTER_VALUE_MASK; ++ pcapTempValue = SSP_PCAP_REGISTER_WRITE_OP_BIT|(sspPcapRegister<<SSP_PCAP_REGISTER_ADDRESS_SHIFT )|(ssp_pcap_registerValue[sspPcapRegister]); ++ ++ printk(KERN_ERR "write 0x%08x to register %u\n", registerValue, sspPcapRegister); ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++ ssp_put_intoData(pcapTempValue); ++ //SSITR_P1 = 0x40; ++ //interruptible_sleep_on(&ssp_pcap_send_wait); ++ do { ++ ssp_interrupt_routine(0, NULL, NULL); ++ } while (int_executed == 0); ++ int_executed = 0; ++ /* here need to judge the wakeup reason and handle it */ ++#else ++ ssp_pcap_gpioWrite(pcapTempValue); ++#endif ++ clear_bit(0,&ssp_pcap_status); ++ ++ /* Now it's OK */ ++ spin_unlock(&pcapoperation_lock); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ restore_flags(flags); ++#endif ++ //ICMR |= (1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++/* ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("write pcap end!",strlen("write pcap end!")); ++#endif ++*/ ++ return SSP_PCAP_SUCCESS; ++ /* maybe here should NOT be a break */ ++ break; ++ default: ++ clear_bit(0,&ssp_pcap_status); ++ ++ /* Now it's OK */ ++ spin_unlock(&pcapoperation_lock); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ restore_flags(flags); ++#endif ++ //ICMR |= (1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++/* ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("write pcap error register!",strlen("write pcap error register!")); ++#endif ++*/ ++ return SSP_PCAP_ERROR_REGISTER; ++ /* maybe here should NOT be a break */ ++ break; ++ } ++ } ++ else ++ { ++ ++ /* Now it's OK */ ++ spin_unlock(&pcapoperation_lock); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ restore_flags(flags); ++#endif ++ //ICMR |= (1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++/* ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("write pcap not run!",strlen("write pcap not run!")); ++#endif ++*/ ++ return SSP_PCAP_NOT_RUN; ++ } ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER sspPcapRegister,P_U32 pSspPcapRegisterValue) ++{ ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++ U32 pcapTempValue; ++#endif ++ unsigned long flags; ++/* ++#ifdef PCAP_LOG_FFUART_OUT ++ pcap_log_add_data("read pcap start!",strlen("read pcap start!")); ++#endif ++*/ ++ /* prevent the process schedule out and mask the PCAP's interrupt handler */ ++ //ICMR &= ~(1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ save_flags(flags); ++ //local_irq_disable(); ++#endif ++ spin_lock(&pcapoperation_lock); ++ ++ if(!test_and_set_bit(0,&ssp_pcap_status)) ++ { ++ switch(sspPcapRegister) ++ { ++#ifdef SSP_PCAP_DEBUG_BOARD ++ case 3: ++ case 22: ++#endif ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++#ifdef SSP_PCAP_OPERATE_WITH_SPI ++ pcapTempValue = SSP_PCAP_REGISTER_READ_OP_BIT|(sspPcapRegister<<SSP_PCAP_REGISTER_ADDRESS_SHIFT ); ++ ssp_put_intoData(pcapTempValue); ++ //SSITR_P1 = 0x40; ++ /* sleep with timeout */ ++ //interruptible_sleep_on(&ssp_pcap_send_wait); ++ do { ++ ssp_interrupt_routine(0, NULL, NULL); ++ } while (int_executed == 0); ++ int_executed = 0; ++ ++ /* here need to judge the wakeup reason and handle it */ ++// if (signal_pending(current)) { ++// ret = -ERESTARTSYS; ++// break; ++// } ++ *pSspPcapRegisterValue = ssp_pcap_readValue; ++#else ++ ssp_pcap_gpioRead(sspPcapRegister,pSspPcapRegisterValue); ++#endif ++ ssp_pcap_registerValue[sspPcapRegister] = *pSspPcapRegisterValue&SSP_PCAP_REGISTER_VALUE_MASK; ++ ++ printk(KERN_ERR "Read from Register %u: 0x%08x\n", sspPcapRegister, ++ *pSspPcapRegisterValue&SSP_PCAP_REGISTER_VALUE_MASK); ++ clear_bit(0,&ssp_pcap_status); ++ ++ /* Now it's OK */ ++ spin_unlock(&pcapoperation_lock); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ restore_flags(flags); ++#endif ++ //ICMR |= (1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++ return SSP_PCAP_SUCCESS; ++ /* maybe here should NOT be a break */ ++ break; ++ default: ++ clear_bit(0,&ssp_pcap_status); ++ ++ /* Now it's OK */ ++ spin_unlock(&pcapoperation_lock); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ restore_flags(flags); ++#endif ++ //ICMR |= (1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++ return SSP_PCAP_ERROR_REGISTER; ++ /* maybe here should NOT be a break */ ++ break; ++ } ++ } ++ else ++ { ++ /* Now it's OK */ ++ spin_unlock(&pcapoperation_lock); ++#ifndef SSP_PCAP_OPERATE_WITH_SPI ++ restore_flags(flags); ++#endif ++ //ICMR |= (1<<(GPIO1_RST+PXA_IRQ_SKIP)); ++ return SSP_PCAP_NOT_RUN; ++ } ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) ++{ ++ U32 sspPcapRegisterBitValue; ++ SSP_PCAP_STATUS ret; ++ U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ switch(sspPcapRegister) ++ { ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ ssp_pcap_registerValue[sspPcapRegister] = 0; ++#ifdef SSP_PCAP_DEBUG_BOARD ++ case 22: ++#endif ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++ ++ sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); ++ ssp_pcap_registerValue[sspPcapRegister] |= sspPcapRegisterBitValue; ++ /* should care the return value */ ++ ret =SSP_PCAP_write_data_to_PCAP(sspPcapRegister,ssp_pcap_registerValue[sspPcapRegister]); ++ return SSP_PCAP_SUCCESS; ++ break; ++ default: ++ return SSP_PCAP_ERROR_REGISTER; ++ break; ++ } ++ return SSP_PCAP_SUCCESS; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) ++{ ++ U32 sspPcapRegisterBitValue; ++ SSP_PCAP_STATUS ret; ++ U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ switch(sspPcapRegister) ++ { ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ ssp_pcap_registerValue[sspPcapRegister] = 0; ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++ sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); ++ ssp_pcap_registerValue[sspPcapRegister] &= ~sspPcapRegisterBitValue; ++ /* should care the return value */ ++ ret =SSP_PCAP_write_data_to_PCAP(sspPcapRegister,ssp_pcap_registerValue[sspPcapRegister]); ++ return SSP_PCAP_SUCCESS; ++ break; ++ default: ++ return SSP_PCAP_ERROR_REGISTER; ++ break; ++ } ++ return SSP_PCAP_SUCCESS; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) ++{ ++ U32 sspPcapRegisterBitValue; ++ U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ switch(sspPcapRegister) ++ { ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++ sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); ++ sspPcapRegisterBitValue &= ssp_pcap_registerValue[sspPcapRegister]; ++ if(sspPcapRegisterBitValue) ++ { ++ return SSP_PCAP_BIT_ONE; ++ } ++ else ++ { ++ return SSP_PCAP_BIT_ZERO; ++ } ++ break; ++ default: ++ return SSP_PCAP_BIT_ERROR; ++ break; ++ } ++ return SSP_PCAP_BIT_ERROR; ++} ++ ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) ++{ ++ U32 sspPcapTempRegisterValue; ++ U32 sspPcapRegisterBitValue; ++ SSP_PCAP_STATUS ret; ++ U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; ++ ++ switch(sspPcapRegister) ++ { ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++ sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); ++ /* should care the return value */ ++ ret = SSP_PCAP_read_data_from_PCAP(sspPcapRegister,&sspPcapTempRegisterValue); ++ sspPcapRegisterBitValue &= sspPcapTempRegisterValue; ++ if(sspPcapRegisterBitValue) ++ { ++ return SSP_PCAP_BIT_ONE; ++ } ++ else ++ { ++ return SSP_PCAP_BIT_ZERO; ++ } ++ break; ++ default: ++ return SSP_PCAP_BIT_ERROR; ++ break; ++ } ++ return SSP_PCAP_BIT_ERROR; ++} ++/*--------------------------------------------------------------------------- ++ DESCRIPTION: ++ ++ INPUTS: ++ ++ ++ OUTPUTS: ++ ++ ++ IMPORTANT NOTES: ++ ++ ++---------------------------------------------------------------------------*/ ++U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER sspPcapRegister ) ++{ ++ switch(sspPcapRegister) ++ { ++ case SSP_PCAP_ADJ_ISR_REGISTER: ++ case SSP_PCAP_ADJ_MSR_REGISTER: ++ case SSP_PCAP_ADJ_PSTAT_REGISTER: ++ case SSP_PCAP_ADJ_VREG2_REGISTER: ++ case SSP_PCAP_ADJ_AUX_VREG_REGISTER: ++ case SSP_PCAP_ADJ_BATT_DAC_REGISTER: ++ case SSP_PCAP_ADJ_ADC1_REGISTER: ++ case SSP_PCAP_ADJ_ADC2_REGISTER: ++ case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: ++ case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_ST_DAC_REGISTER: ++ case SSP_PCAP_ADJ_BUSCTRL_REGISTER: ++ case SSP_PCAP_ADJ_PERIPH_REGISTER: ++ case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: ++ case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: ++ case SSP_PCAP_ADJ_GP_REG_REGISTER: ++ return ssp_pcap_registerValue[sspPcapRegister]; ++ break; ++ default: ++ return SSP_PCAP_ERROR_REGISTER; ++ break; ++ } ++} ++#ifdef __cplusplus ++} ++#endif +diff -Nurd linux-2.6.16.orig/drivers/misc/Kconfig linux-2.6.16/drivers/misc/Kconfig +--- linux-2.6.16.orig/drivers/misc/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/misc/Kconfig 2006-06-03 11:14:56.301330152 +0200 +@@ -30,3 +30,4 @@ + + endmenu + ++source "drivers/misc/ezx/Kconfig" +diff -Nurd linux-2.6.16.orig/drivers/misc/Makefile linux-2.6.16/drivers/misc/Makefile +--- linux-2.6.16.orig/drivers/misc/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/misc/Makefile 2006-06-03 11:14:56.302330000 +0200 +@@ -5,3 +5,4 @@ + + obj-$(CONFIG_IBM_ASM) += ibmasm/ + obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ ++obj-$(CONFIG_PXA_EZX) += ezx/ +diff -Nurd linux-2.6.16.orig/drivers/mmc/pxamci.c linux-2.6.16/drivers/mmc/pxamci.c +--- linux-2.6.16.orig/drivers/mmc/pxamci.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/mmc/pxamci.c 2006-06-03 11:14:57.040217824 +0200 +@@ -60,6 +60,8 @@ + unsigned int power_mode; + struct pxamci_platform_data *pdata; + ++ unsigned int bus_width; ++ + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; +@@ -178,6 +180,9 @@ + if (cmd->flags & MMC_RSP_BUSY) + cmdat |= CMDAT_BUSY; + ++ if (host->bus_width == MMC_BUS_WIDTH_4) ++ cmdat |= CMDAT_SD_4DAT; ++ + #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) + switch (RSP_TYPE(mmc_resp_type(cmd))) { + case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */ +@@ -329,8 +334,13 @@ + if (ireg & DATA_TRAN_DONE) + handled |= pxamci_data_done(host, stat); + } ++ if (!handled) { ++ unsigned int stat = readl(host->base + MMC_STAT); ++ printk("PXAMCI: stat %08x\n", stat); ++ } + +- return IRQ_RETVAL(handled); ++ //return IRQ_RETVAL(handled); ++ return IRQ_HANDLED; + } + + static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -405,8 +415,12 @@ + host->cmdat |= CMDAT_INIT; + } + +- DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n", +- host->clkrt, host->cmdat); ++ /* Store bus width for later */ ++ if (host->mmc->caps & MMC_CAP_4_BIT_DATA) ++ host->bus_width = ios->bus_width; ++ ++ DBG("pxamci_set_ios: clkrt = %x cmdat = %x width = %x\n", ++ host->clkrt, host->cmdat, host->bus_width); + } + + static struct mmc_host_ops pxamci_ops = { +@@ -454,6 +468,9 @@ + mmc->ops = &pxamci_ops; + mmc->f_min = CLOCKRATE_MIN; + mmc->f_max = CLOCKRATE_MAX; ++#ifdef CONFIG_PXA27x ++ //mmc->caps = MMC_CAP_4_BIT_DATA; ++#endif + + /* + * We can do SG-DMA, but we don't because we never know how much +diff -Nurd linux-2.6.16.orig/drivers/mmc/pxamci.h linux-2.6.16/drivers/mmc/pxamci.h +--- linux-2.6.16.orig/drivers/mmc/pxamci.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/mmc/pxamci.h 2006-06-03 11:14:56.944232416 +0200 +@@ -47,6 +47,11 @@ + #define SPI_EN (1 << 0) + + #define MMC_CMDAT 0x0010 ++#define CMDAT_SDIO_RESUME (1 << 13) /* PXA27x */ ++#define CMDAT_SDIO_SUSPEND (1 << 12) /* PXA27x */ ++#define CMDAT_SDIO_INT_EN (1 << 11) /* PXA27x */ ++#define CMDAT_STOP_TRAN (1 << 10) /* PXA27x */ ++#define CMDAT_SD_4DAT (1 << 8) /* PXA27x */ + #define CMDAT_DMAEN (1 << 7) + #define CMDAT_INIT (1 << 6) + #define CMDAT_BUSY (1 << 5) +diff -Nurd linux-2.6.16.orig/drivers/mtd/maps/Kconfig linux-2.6.16/drivers/mtd/maps/Kconfig +--- linux-2.6.16.orig/drivers/mtd/maps/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/mtd/maps/Kconfig 2006-06-03 11:14:56.881241992 +0200 +@@ -621,6 +621,13 @@ + help + This enables access to the flash chip on the Sharp SL Series of PDAs. + ++config MTD_PXA27x ++ tristate "Map driver for Intel PXA27x" ++ depends on MTD && ARCH_PXA ++ help ++ This enables access to the flash chip on the Intel PXA27x ++ ++ + config MTD_PLATRAM + tristate "Map driver for platform device RAM (mtd-ram)" + depends on MTD +diff -Nurd linux-2.6.16.orig/drivers/mtd/maps/Makefile linux-2.6.16/drivers/mtd/maps/Makefile +--- linux-2.6.16.orig/drivers/mtd/maps/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/mtd/maps/Makefile 2006-06-03 11:14:56.359321336 +0200 +@@ -71,3 +71,4 @@ + obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o + obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o + obj-$(CONFIG_MTD_TQM834x) += tqm834x.o ++obj-$(CONFIG_MTD_PXA27x) += pxa27x.o +diff -Nurd linux-2.6.16.orig/drivers/mtd/maps/pxa27x.c linux-2.6.16/drivers/mtd/maps/pxa27x.c +--- linux-2.6.16.orig/drivers/mtd/maps/pxa27x.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/mtd/maps/pxa27x.c 2006-06-03 11:14:56.881241992 +0200 +@@ -0,0 +1,188 @@ ++/* ++ * $Id: $ ++ * ++ * Map driver for the PXA27x ++ * ++ * Author: Harald Welte ++ * Copyright: (C) 2001 MontaVista Software 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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/dma-mapping.h> ++#include <linux/slab.h> ++ ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/mainstone.h> ++ ++#define WINDOW_ADDR 0x0 ++#define WINDOW_SIZE (32*1024*1024) ++#define WINDOW_CACHE_ADDR 0x0 ++#define WINDOW_CACHE_SIZE 0x1a00000 ++ ++static void pxa27x_map_inval_cache(struct map_info *map, unsigned long from, ++ ssize_t len) ++{ ++#if 0 ++ unsigned long endaddress, i, j; ++ endaddress = from + len -1; ++ from &= ~(32-1); ++ endaddress &= ~(32-1); ++ for (i = from; i <= endaddress; i += 32) ++ asm("mcr p15, 0, %0, c7, c6, 1"::"r"(i)); ++ ++ asm( "mrc p15, 0, %0, c2, c0, 0\n" ++ "mov %0, %0\n" ++ "sub pc, pc #4" ++ :"=r"(j)); ++#else ++ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE); ++#endif ++} ++ ++ ++struct map_info pxa27x_map = { ++ .name = "PXA27x flash", ++ .size = WINDOW_SIZE, ++ .phys = WINDOW_ADDR, ++ .inval_cache = &pxa27x_map_inval_cache, ++}; ++ ++#if defined (CONFIG_PXA_EZX_A780) || defined (CONFIG_PXA_EZX_E680) ++static struct mtd_partition pxa27x_partitions[] = { ++ { ++ .name = "Bootloader", ++ .size = 0x00020000, ++ .offset = 0, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "Kernel", ++ .size = 0x000e0000, ++ .offset = 0x00020000, ++ } , { ++ .name = "rootfs", ++ .size = 0x018e0000, ++ .offset = 0x00120000, ++ } , { ++ .name = "VFM_Filesystem", ++ .size = 0x00580000, ++ .offset = 0x01a00000, ++ } , { ++ .name = "setup", ++ .size = 0x00020000, ++ .offset = 0x01fa0000, ++ } , { ++ .name = "Logo", ++ .size = 0x00020000, ++ .offset = 0x01fc0000, ++ }, ++}; ++#else ++#error "please define partition for this PXA27x implementation" ++#endif ++ ++ ++static struct mtd_info *mymtd; ++static struct mtd_partition *parsed_parts; ++ ++static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; ++ ++static int __init init_pxa27x(void) ++{ ++ struct mtd_partition *parts; ++ int nb_parts = 0; ++ int parsed_nr_parts = 0; ++ char *part_type = "static"; ++ ++ pxa27x_map.bankwidth = (BOOT_DEF & 1) ? 2 : 4; ++ ++ printk("Probing PXA27x flash at physical address 0x%08x (%d-bit bankwidth)\n", ++ WINDOW_ADDR, pxa27x_map.bankwidth * 8); ++ pxa27x_map.virt = ioremap(pxa27x_map.phys, pxa27x_map.size); ++ ++ if (!pxa27x_map.virt) { ++ printk("Failed to ioremap\n"); ++ return -EIO; ++ } ++ ++ mymtd = do_map_probe("cfi_probe", &pxa27x_map); ++ if (!mymtd) { ++ iounmap((void *)pxa27x_map.virt); ++ return -ENXIO; ++ } ++ mymtd->owner = THIS_MODULE; ++ ++#if 0 ++ /* ioremap the first flash chip as cacheable */ ++ pxa27x_map.cached = ioremap_cached(pxa27x_map.phys, pxa27x_map.size); ++ if (!pxa27x_map.cached) { ++ printk("Failed to do cacheable-ioremap\n"); ++ iounmap((void *)pxa27x_map.virt); ++ return -EIO; ++ } ++#endif ++ simple_map_init(&pxa27x_map); ++ ++ if (parsed_nr_parts == 0) { ++ int ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); ++ ++ if (ret > 0) { ++ part_type = "RedBoot"; ++ parsed_nr_parts = ret; ++ } ++ } ++ ++ if (parsed_nr_parts > 0) { ++ parts = parsed_parts; ++ nb_parts = parsed_nr_parts; ++ } else { ++ parts = pxa27x_partitions; ++ nb_parts = ARRAY_SIZE(pxa27x_partitions); ++ } ++ ++ if (nb_parts) { ++ printk(KERN_NOTICE "Using %s partition definition\n", part_type); ++ add_mtd_partitions(mymtd, parts, nb_parts); ++ } else { ++ add_mtd_device(mymtd); ++ } ++#if 0 ++ if (ret = ezx_partition_init()) ++#endif ++ return 0; ++} ++ ++static void __exit cleanup_pxa27x(void) ++{ ++ if (mymtd) { ++ del_mtd_partitions(mymtd); ++ map_destroy(mymtd); ++ if (parsed_parts) ++ kfree(parsed_parts); ++ } ++ if (pxa27x_map.virt) ++ iounmap((void *)pxa27x_map.virt); ++ if (pxa27x_map.cached) ++ iounmap((void *)pxa27x_map.cached); ++ return; ++} ++ ++module_init(init_pxa27x); ++module_exit(cleanup_pxa27x); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); ++MODULE_DESCRIPTION("MTD map driver for Motorola EZX platform"); +diff -Nurd linux-2.6.16.orig/drivers/mtd/nand/Kconfig linux-2.6.16/drivers/mtd/nand/Kconfig +--- linux-2.6.16.orig/drivers/mtd/nand/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/mtd/nand/Kconfig 2006-06-03 11:14:55.290483824 +0200 +@@ -178,17 +178,16 @@ + Even if you leave this disabled, you can enable BBT writes at module + load time (assuming you build diskonchip as a module) with the module + parameter "inftl_bbt_write=1". +- +- config MTD_NAND_SHARPSL +- bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" +- depends on MTD_NAND && ARCH_PXA +- +- config MTD_NAND_NANDSIM +- bool "Support for NAND Flash Simulator" +- depends on MTD_NAND && MTD_PARTITIONS + ++config MTD_NAND_SHARPSL ++ tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" ++ depends on MTD_NAND && ARCH_PXA ++ ++config MTD_NAND_NANDSIM ++ tristate "Support for NAND Flash Simulator" ++ depends on MTD_NAND && MTD_PARTITIONS + help + The simulator may simulate verious NAND flash chips for the + MTD nand layer. +- ++ + endmenu +diff -Nurd linux-2.6.16.orig/drivers/net/e1000/e1000_main.c linux-2.6.16/drivers/net/e1000/e1000_main.c +--- linux-2.6.16.orig/drivers/net/e1000/e1000_main.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/e1000/e1000_main.c 2006-06-03 11:14:55.294483216 +0200 +@@ -3851,6 +3851,7 @@ + skb_shinfo(skb)->nr_frags++; + skb->len += length; + skb->data_len += length; ++ skb->truesize += length; + } + + e1000_rx_checksum(adapter, staterr, +diff -Nurd linux-2.6.16.orig/drivers/net/irda/irda-usb.c linux-2.6.16/drivers/net/irda/irda-usb.c +--- linux-2.6.16.orig/drivers/net/irda/irda-usb.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/irda/irda-usb.c 2006-06-03 11:14:55.295483064 +0200 +@@ -740,7 +740,7 @@ + struct sk_buff *newskb; + struct sk_buff *dataskb; + struct urb *next_urb; +- int docopy; ++ unsigned int len, docopy; + + IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length); + +@@ -851,10 +851,11 @@ + dataskb->dev = self->netdev; + dataskb->mac.raw = dataskb->data; + dataskb->protocol = htons(ETH_P_IRDA); ++ len = dataskb->len; + netif_rx(dataskb); + + /* Keep stats up to date */ +- self->stats.rx_bytes += dataskb->len; ++ self->stats.rx_bytes += len; + self->stats.rx_packets++; + self->netdev->last_rx = jiffies; + +diff -Nurd linux-2.6.16.orig/drivers/net/sky2.c linux-2.6.16/drivers/net/sky2.c +--- linux-2.6.16.orig/drivers/net/sky2.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/sky2.c 2006-06-03 11:14:55.297482760 +0200 +@@ -579,8 +579,8 @@ + reg = gma_read16(hw, port, GM_PHY_ADDR); + gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); + +- for (i = 0; i < GM_MIB_CNT_SIZE; i++) +- gma_read16(hw, port, GM_MIB_CNT_BASE + 8 * i); ++ for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4) ++ gma_read16(hw, port, i); + gma_write16(hw, port, GM_PHY_ADDR, reg); + + /* transmit control */ +diff -Nurd linux-2.6.16.orig/drivers/net/sky2.h linux-2.6.16/drivers/net/sky2.h +--- linux-2.6.16.orig/drivers/net/sky2.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/sky2.h 2006-06-03 11:14:55.298482608 +0200 +@@ -1380,6 +1380,7 @@ + /* MIB Counters */ + #define GM_MIB_CNT_BASE 0x0100 /* Base Address of MIB Counters */ + #define GM_MIB_CNT_SIZE 44 /* Number of MIB Counters */ ++#define GM_MIB_CNT_END 0x025C /* Last MIB counter */ + + /* + * MIB Counters base address definitions (low word) - +diff -Nurd linux-2.6.16.orig/drivers/net/wireless/hostap/hostap_80211_tx.c linux-2.6.16/drivers/net/wireless/hostap/hostap_80211_tx.c +--- linux-2.6.16.orig/drivers/net/wireless/hostap/hostap_80211_tx.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/wireless/hostap/hostap_80211_tx.c 2006-06-03 11:14:55.299482456 +0200 +@@ -469,7 +469,7 @@ + } + + if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && +- !(fc & IEEE80211_FCTL_VERS)) { ++ !(fc & IEEE80211_FCTL_PROTECTED)) { + no_encrypt = 1; + PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " + "unencrypted EAPOL frame\n", dev->name); +diff -Nurd linux-2.6.16.orig/drivers/net/wireless/ipw2200.c linux-2.6.16/drivers/net/wireless/ipw2200.c +--- linux-2.6.16.orig/drivers/net/wireless/ipw2200.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/wireless/ipw2200.c 2006-06-03 11:14:55.305481544 +0200 +@@ -9956,9 +9956,8 @@ + return -EINVAL; + down(&p->sem); + memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); +- for (i = IPW_EEPROM_DATA; +- i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) +- ipw_write8(p, i, p->eeprom[i]); ++ for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) ++ ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]); + up(&p->sem); + return 0; + } +diff -Nurd linux-2.6.16.orig/drivers/net/wireless/Kconfig linux-2.6.16/drivers/net/wireless/Kconfig +--- linux-2.6.16.orig/drivers/net/wireless/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/net/wireless/Kconfig 2006-06-03 11:14:55.299482456 +0200 +@@ -239,7 +239,8 @@ + + config AIRO + tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" +- depends on NET_RADIO && ISA_DMA_API && CRYPTO && (PCI || BROKEN) ++ depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) ++ select CRYPTO + ---help--- + This is the standard Linux driver to support Cisco/Aironet ISA and + PCI 802.11 wireless cards. +@@ -374,6 +375,7 @@ + config PCMCIA_SPECTRUM + tristate "Symbol Spectrum24 Trilogy PCMCIA card support" + depends on NET_RADIO && PCMCIA && HERMES ++ select FW_LOADER + ---help--- + + This is a driver for 802.11b cards using RAM-loadable Symbol +@@ -387,6 +389,7 @@ + config AIRO_CS + tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" + depends on NET_RADIO && PCMCIA && (BROKEN || !M32R) ++ select CRYPTO + ---help--- + This is the standard Linux driver to support Cisco/Aironet PCMCIA + 802.11 wireless cards. This driver is the same as the Aironet +diff -Nurd linux-2.6.16.orig/drivers/pcmcia/ds.c linux-2.6.16/drivers/pcmcia/ds.c +--- linux-2.6.16.orig/drivers/pcmcia/ds.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/pcmcia/ds.c 2006-06-03 11:14:55.306481392 +0200 +@@ -546,7 +546,7 @@ + tmp = vers1->str + vers1->ofs[i]; + + length = strlen(tmp) + 1; +- if ((length < 3) || (length > 255)) ++ if ((length < 2) || (length > 255)) + continue; + + p_dev->prod_id[i] = kmalloc(sizeof(char) * length, +diff -Nurd linux-2.6.16.orig/drivers/scsi/3w-9xxx.c linux-2.6.16/drivers/scsi/3w-9xxx.c +--- linux-2.6.16.orig/drivers/scsi/3w-9xxx.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/scsi/3w-9xxx.c 2006-06-03 11:14:55.308481088 +0200 +@@ -85,7 +85,7 @@ + #include "3w-9xxx.h" + + /* Globals */ +-#define TW_DRIVER_VERSION "2.26.02.005" ++#define TW_DRIVER_VERSION "2.26.02.007" + static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; + static unsigned int twa_device_extension_count; + static int twa_major = -1; +@@ -1944,9 +1944,13 @@ + } + if (tw_dev->srb[request_id]->use_sg == 1) { + struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; +- char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; ++ char *buf; ++ unsigned long flags = 0; ++ local_irq_save(flags); ++ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length); + kunmap_atomic(buf - sg->offset, KM_IRQ0); ++ local_irq_restore(flags); + } + } + } /* End twa_scsiop_execute_scsi_complete() */ +diff -Nurd linux-2.6.16.orig/drivers/scsi/3w-xxxx.c linux-2.6.16/drivers/scsi/3w-xxxx.c +--- linux-2.6.16.orig/drivers/scsi/3w-xxxx.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/scsi/3w-xxxx.c 2006-06-03 11:14:55.309480936 +0200 +@@ -1508,10 +1508,12 @@ + struct scsi_cmnd *cmd = tw_dev->srb[request_id]; + void *buf; + unsigned int transfer_len; ++ unsigned long flags = 0; + + if (cmd->use_sg) { + struct scatterlist *sg = + (struct scatterlist *)cmd->request_buffer; ++ local_irq_save(flags); + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + transfer_len = min(sg->length, len); + } else { +@@ -1526,6 +1528,7 @@ + + sg = (struct scatterlist *)cmd->request_buffer; + kunmap_atomic(buf - sg->offset, KM_IRQ0); ++ local_irq_restore(flags); + } + } + +diff -Nurd linux-2.6.16.orig/drivers/scsi/sata_mv.c linux-2.6.16/drivers/scsi/sata_mv.c +--- linux-2.6.16.orig/drivers/scsi/sata_mv.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/scsi/sata_mv.c 2006-06-03 11:14:55.311480632 +0200 +@@ -1102,6 +1102,7 @@ + void __iomem *port_mmio = mv_ap_base(ap); + struct mv_port_priv *pp = ap->private_data; + u32 out_ptr; ++ u8 ata_status; + + out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + +@@ -1109,6 +1110,8 @@ + assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == + pp->rsp_consumer); + ++ ata_status = pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT; ++ + /* increment our consumer index... */ + pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer); + +@@ -1123,7 +1126,7 @@ + writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS); + + /* Return ATA status register for completed CRPB */ +- return (pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT); ++ return ata_status; + } + + /** +@@ -1192,7 +1195,6 @@ + u32 hc_irq_cause; + int shift, port, port0, hard_port, handled; + unsigned int err_mask; +- u8 ata_status = 0; + + if (hc == 0) { + port0 = 0; +@@ -1210,6 +1212,7 @@ + hc,relevant,hc_irq_cause); + + for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { ++ u8 ata_status = 0; + ap = host_set->ports[port]; + hard_port = port & MV_PORT_MASK; /* range 0-3 */ + handled = 0; /* ensure ata_status is set if handled++ */ +diff -Nurd linux-2.6.16.orig/drivers/serial/pxa.c linux-2.6.16/drivers/serial/pxa.c +--- linux-2.6.16.orig/drivers/serial/pxa.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/serial/pxa.c 2006-06-03 11:14:56.994224816 +0200 +@@ -30,6 +30,10 @@ + #define SUPPORT_SYSRQ + #endif + ++#define pxa_buggy_port(x) ({ \ ++ int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); \ ++ ((x) == PORT_PXA && (cpu_ver & ~1) == 0x69052100); }) ++ + #include <linux/module.h> + #include <linux/ioport.h> + #include <linux/init.h> +@@ -43,6 +47,8 @@ + #include <linux/tty.h> + #include <linux/tty_flip.h> + #include <linux/serial_core.h> ++#include <linux/dpm.h> ++#include <linux/notifier.h> + + #include <asm/io.h> + #include <asm/hardware.h> +@@ -57,6 +63,7 @@ + unsigned char mcr; + unsigned int lsr_break_flag; + unsigned int cken; ++ unsigned int baud; + char *name; + }; + +@@ -205,6 +212,8 @@ + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); ++ if (pxa_buggy_port(up->port.type)) ++ serial_pxa_irq(up->port.irq, NULL, NULL); + } + } + +@@ -302,6 +311,9 @@ + + mcr |= up->mcr; + ++ if (pxa_buggy_port(up->port.type) && up->port.irq != 0) ++ mcr ^= UART_MCR_OUT2; ++ + serial_out(up, UART_MCR, mcr); + } + +@@ -405,6 +417,14 @@ + (void) serial_in(up, UART_IIR); + (void) serial_in(up, UART_MSR); + ++#ifdef CONFIG_PXA_EZX ++ if (port->line == 1) { ++ ezx_bt_reset(0); ++ ezx_bt_wakeup(0); ++ ezx_bt_reset(1); ++ } ++#endif ++ + return 0; + } + +@@ -434,6 +454,11 @@ + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial_out(up, UART_FCR, 0); ++ ++#ifdef CONFIG_PXA_EZX ++ if (port->line == 1) ++ ezx_bt_wakeup(1); ++#endif + } + + static void +@@ -473,6 +498,7 @@ + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); ++ up->baud = baud; // save for DPM scale callback + + if ((up->port.uartclk / quot) < (2400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; +@@ -817,6 +843,44 @@ + return 0; + } + ++static int serial_pxa_scale(struct notifier_block *self, ++ unsigned long level, void *newop) ++{ ++ int n=0;int i=0; ++ int ccsr=CCSR; ++ n=sizeof(serial_pxa_ports)/sizeof(struct uart_pxa_port); ++ ++ for (i=0; i<n; ++i) { ++ struct uart_pxa_port *up = (struct uart_pxa_port *) &serial_pxa_ports[i]; ++ ++ if(up->baud) { ++ unsigned int quot; ++ ++ if ((ccsr & (1<<30))){ ++ if (up->port.uartclk == 13000000) ++ return 0; ++ ++ /*if PPLL is Off (clocking with 13MHz now)*/ ++ up->port.uartclk = 13000000; ++ } else { ++ if (up->port.uartclk == 921600 * 16) ++ return 0; ++ ++ /*clocking with 14.7456 MHz*/ ++ up->port.uartclk = 921600 * 16; ++ } ++ ++ quot = uart_get_divisor(&up->port, up->baud); ++ serial_out(up, UART_LCR, up->lcr | UART_LCR_DLAB);/* set DLAB */ ++ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ ++ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ ++ serial_out(up, UART_LCR, up->lcr); /* reset DLAB */ ++ } ++ } ++ ++ return 0; ++} ++ + static int serial_pxa_probe(struct platform_device *dev) + { + serial_pxa_ports[dev->id].port.dev = &dev->dev; +@@ -848,6 +912,10 @@ + }, + }; + ++static struct notifier_block serial_pxa_nb = { ++ .notifier_call = serial_pxa_scale, ++}; ++ + int __init serial_pxa_init(void) + { + int ret; +@@ -860,6 +928,11 @@ + if (ret != 0) + uart_unregister_driver(&serial_pxa_reg); + ++#ifdef CONFIG_DPM ++ if (! ret) ++ dpm_register_scale(&serial_pxa_nb, SCALE_POSTCHANGE); ++#endif ++ + return ret; + } + +@@ -867,6 +940,9 @@ + { + platform_driver_unregister(&serial_pxa_driver); + uart_unregister_driver(&serial_pxa_reg); ++#ifdef CONFIG_DPM ++ dpm_unregister_scale(&serial_pxa_nb, SCALE_POSTCHANGE); ++#endif + } + + module_init(serial_pxa_init); +diff -Nurd linux-2.6.16.orig/drivers/usb/core/message.c linux-2.6.16/drivers/usb/core/message.c +--- linux-2.6.16.orig/drivers/usb/core/message.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/core/message.c 2006-06-03 11:14:55.312480480 +0200 +@@ -1388,11 +1388,13 @@ + if (dev->state != USB_STATE_ADDRESS) + usb_disable_device (dev, 1); // Skip ep0 + +- i = dev->bus_mA - cp->desc.bMaxPower * 2; +- if (i < 0) +- dev_warn(&dev->dev, "new config #%d exceeds power " +- "limit by %dmA\n", +- configuration, -i); ++ if (cp) { ++ i = dev->bus_mA - cp->desc.bMaxPower * 2; ++ if (i < 0) ++ dev_warn(&dev->dev, "new config #%d exceeds power " ++ "limit by %dmA\n", ++ configuration, -i); ++ } + + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, +diff -Nurd linux-2.6.16.orig/drivers/usb/gadget/ether.c linux-2.6.16/drivers/usb/gadget/ether.c +--- linux-2.6.16.orig/drivers/usb/gadget/ether.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/gadget/ether.c 2006-06-03 11:14:55.991377272 +0200 +@@ -246,7 +246,9 @@ + #endif + + #ifdef CONFIG_USB_GADGET_PXA27X +-#define DEV_CONFIG_CDC ++#define DEV_CONFIG_SUBSET ++extern struct usb_ep* pxa27x_ep_config(struct usb_gadget *gadget, ++ struct usb_endpoint_descriptor *desc,int config,int interface,int alt); + #endif + + #ifdef CONFIG_USB_GADGET_AT91 +@@ -2271,7 +2273,27 @@ + + /* all we really need is bulk IN/OUT */ + usb_ep_autoconfig_reset (gadget); ++#ifdef CONFIG_USB_GADGET_PXA27X ++#ifdef CONFIG_USB_ETH_RNDIS ++ in_ep = pxa27x_ep_config (gadget, &fs_source_desc, ++ DEV_RNDIS_CONFIG_VALUE, ++ (int)rndis_data_intf.bInterfaceNumber, ++ (int)rndis_data_intf.bAlternateSetting); ++#elif defined(DEV_CONFIG_CDC) ++ in_ep = pxa27x_ep_config (gadget, &fs_source_desc, ++ DEV_CONFIG_VALUE, ++ (int)data_intf.bInterfaceNumber, ++ (int)data_intf.bAlternateSetting); ++#elif defined(DEV_CONFIG_SUBSET) ++ in_ep = pxa27x_ep_config (gadget, &fs_source_desc, ++ DEV_CONFIG_VALUE, ++ (int)subset_data_intf.bInterfaceNumber, ++ (int)subset_data_intf.bAlternateSetting); ++ ++#endif //CONFIG_USB_ETH_RNDIS ++#else + in_ep = usb_ep_autoconfig (gadget, &fs_source_desc); ++#endif //CONFIG_USB_GADGET_PXA27X + if (!in_ep) { + autoconf_fail: + dev_err (&gadget->dev, +@@ -2281,7 +2303,26 @@ + } + in_ep->driver_data = in_ep; /* claim */ + ++#ifdef CONFIG_USB_GADGET_PXA27X ++#ifdef CONFIG_USB_ETH_RNDIS ++ out_ep = pxa27x_ep_config (gadget, &fs_sink_desc, ++ DEV_RNDIS_CONFIG_VALUE, ++ (int)rndis_data_intf.bInterfaceNumber, ++ (int)rndis_data_intf.bAlternateSetting); ++#elif defined(DEV_CONFIG_CDC) ++ out_ep = pxa27x_ep_config (gadget, &fs_sink_desc, ++ DEV_CONFIG_VALUE, ++ (int)data_intf.bInterfaceNumber, ++ (int)data_intf.bAlternateSetting); ++#elif defined(DEV_CONFIG_SUBSET) ++ out_ep = pxa27x_ep_config (gadget, &fs_sink_desc, ++ DEV_CONFIG_VALUE, ++ (int)subset_data_intf.bInterfaceNumber, ++ (int)subset_data_intf.bAlternateSetting); ++#endif //CONFIG_USB_ETH_RNDIS ++#else + out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); ++#endif //CONFIG_USB_GADGET_PXA27X + if (!out_ep) + goto autoconf_fail; + out_ep->driver_data = out_ep; /* claim */ +@@ -2291,7 +2332,22 @@ + * Since some hosts expect one, try to allocate one anyway. + */ + if (cdc || rndis) { ++#ifdef CONFIG_USB_GADGET_PXA27X ++#ifdef CONFIG_USB_ETH_RNDIS ++ status_ep = pxa27x_ep_config (gadget, &fs_status_desc, ++ DEV_RNDIS_CONFIG_VALUE, ++ (int)rndis_control_intf.bInterfaceNumber, ++ (int)rndis_control_intf.bAlternateSetting); ++#elif defined(DEV_CONFIG_CDC) ++ status_ep = pxa27x_ep_config (gadget, &fs_status_desc, ++ DEV_CONFIG_VALUE, ++ (int)control_intf.bInterfaceNumber, ++ (int)control_intf.bAlternateSetting); ++ ++#endif //CONFIG_USB_ETH_RNDIS ++#else + status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); ++#endif //CONFIG_USB_GADGET_PXA27X + if (status_ep) { + status_ep->driver_data = status_ep; /* claim */ + } else if (rndis) { +@@ -2300,10 +2356,12 @@ + gadget->name); + return -ENODEV; + #ifdef DEV_CONFIG_CDC ++#ifndef CONFIG_USB_GADGET_PXA27X + /* pxa25x only does CDC subset; often used with RNDIS */ + } else if (cdc) { + control_intf.bNumEndpoints = 0; + /* FIXME remove endpoint from descriptor list */ ++#endif //CONFIG_USB_GADGET_PXA27X + #endif + } + } +diff -Nurd linux-2.6.16.orig/drivers/usb/gadget/Kconfig linux-2.6.16/drivers/usb/gadget/Kconfig +--- linux-2.6.16.orig/drivers/usb/gadget/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/gadget/Kconfig 2006-06-03 11:14:55.946384112 +0200 +@@ -121,6 +121,28 @@ + default y if USB_ETH + default y if USB_G_SERIAL + ++config USB_GADGET_PXA27X ++ boolean "PXA 27x" ++ depends on ARCH_PXA && PXA27x ++ help ++ Intel's PXA 27x series XScale ARM-5TE processors include ++ an integrated full speed USB 1.1 device controller. ++ ++ Say "y" to link the driver statically, or "m" to build a ++ dynamically linked module called "pxa27x_udc" and force all ++ gadget drivers to also be dynamically linked. ++ ++config USB_PXA27X ++ tristate ++ depends on USB_GADGET_PXA27X ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ ++config USB_PXA27X_DMA ++ bool # "Use DMA support" ++ depends on USB_GADGET_PXA27X ++ default n ++ + config USB_GADGET_GOKU + boolean "Toshiba TC86C001 'Goku-S'" + depends on PCI +diff -Nurd linux-2.6.16.orig/drivers/usb/gadget/Makefile linux-2.6.16/drivers/usb/gadget/Makefile +--- linux-2.6.16.orig/drivers/usb/gadget/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/gadget/Makefile 2006-06-03 11:14:55.946384112 +0200 +@@ -7,6 +7,7 @@ + obj-$(CONFIG_USB_GOKU) += goku_udc.o + obj-$(CONFIG_USB_OMAP) += omap_udc.o + obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o ++obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o + + # + # USB gadget drivers +diff -Nurd linux-2.6.16.orig/drivers/usb/gadget/pxa27x_udc.c linux-2.6.16/drivers/usb/gadget/pxa27x_udc.c +--- linux-2.6.16.orig/drivers/usb/gadget/pxa27x_udc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/usb/gadget/pxa27x_udc.c 2006-06-03 11:14:55.949383656 +0200 +@@ -0,0 +1,2349 @@ ++/* ++ * linux/drivers/usb/gadget/pxa27x_udc.c ++ * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers ++ * ++ * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) ++ * Copyright (C) 2003 Robert Schwebel, Pengutronix ++ * Copyright (C) 2003 Benedikt Spranger, Pengutronix ++ * Copyright (C) 2003 David Brownell ++ * Copyright (C) 2003 Joshua Wise ++ * Copyright (C) 2004 Intel Corporation ++ * Copyright (C) 2005 SDG Systems, LLC (Aric Blumer) ++ * ++ * 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 ++ * ++ */ ++ ++#undef DEBUG ++ // #define DEBUG 1 ++ //#define VERBOSE DBG_VERBOSE ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <linux/errno.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/timer.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/proc_fs.h> ++#include <linux/mm.h> ++#include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++ ++#include <asm/byteorder.h> ++#include <asm/dma.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++#include <asm/mach-types.h> ++#include <asm/unaligned.h> ++#include <asm/hardware.h> ++#include <asm/arch/pxa-regs.h> ++ ++#include <linux/usb_ch9.h> ++#include <linux/usb_gadget.h> ++ ++#include <asm/arch/udc.h> ++ ++ ++/* ++ * This driver handles the USB Device Controller (UDC) in Intel's PXA 27777777x ++ * series processors. ++ * Such controller drivers work with a gadget driver. The gadget driver ++ * returns descriptors, implements configuration and data protocols used ++ * by the host to interact with this device, and allocates endpoints to ++ * the different protocol interfaces. The controller driver virtualizes ++ * usb hardware so that the gadget drivers will be more portable. ++ * ++ * This UDC hardware wants to implement a bit too much USB protocol, so ++ * it constrains the sorts of USB configuration change events that work. ++ * The errata for these chips are misleading; some "fixed" bugs from ++ * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. ++ */ ++ ++#define DRIVER_VERSION "21-Jul-2005" ++#define DRIVER_DESC "PXA 27x USB Device Controller driver" ++ ++ ++static const char driver_name [] = "pxa27x_udc"; ++ ++static const char ep0name [] = "ep0"; ++ ++ ++#define USE_DMA ++//#define DISABLE_TEST_MODE ++ ++#ifdef CONFIG_PROC_FS ++#define UDC_PROC_FILE ++#endif ++ ++#include "pxa27x_udc.h" ++ ++#if 0 ++#ifdef CONFIG_EMBEDDED ++/* few strings, and little code to use them */ ++#undef DEBUG ++#undef UDC_PROC_FILE ++#endif ++#endif ++ ++#ifdef USE_DMA ++static int use_dma = 1; ++module_param(use_dma, bool, 0); ++MODULE_PARM_DESC (use_dma, "true to use dma"); ++ ++static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r); ++static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req); ++ ++#define DMASTR " (dma support)" ++ ++#else /* !USE_DMA */ ++#define DMASTR " (pio only)" ++#endif ++ ++#ifdef CONFIG_USB_PXA27X_SMALL ++#define SIZE_STR " (small)" ++#else ++#define SIZE_STR "" ++#endif ++ ++#ifdef DISABLE_TEST_MODE ++/* (mode == 0) == no undocumented chip tweaks ++ * (mode & 1) == double buffer bulk IN ++ * (mode & 2) == double buffer bulk OUT ++ * ... so mode = 3 (or 7, 15, etc) does it for both ++ */ ++static ushort fifo_mode = 0; ++module_param(fifo_mode, ushort, 0); ++MODULE_PARM_DESC (fifo_mode, "pxa27x udc fifo mode"); ++#endif ++ ++#define UDCISR0_IR0 0x3 ++#define UDCISR_INT_MASK (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP) ++#define UDCICR_INT_MASK UDCISR_INT_MASK ++ ++#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME) ++/* --------------------------------------------------------------------------- ++ * endpoint related parts of the api to the usb controller hardware, ++ * used by gadget driver; and the inner talker-to-hardware core. ++ * --------------------------------------------------------------------------- ++ */ ++ ++static void pxa27x_ep_fifo_flush (struct usb_ep *ep); ++static void nuke (struct pxa27x_ep *, int status); ++ ++static void pio_irq_enable(int ep_num) ++{ ++ if (ep_num < 16) ++ UDCICR0 |= 3 << (ep_num * 2); ++ else { ++ ep_num -= 16; ++ UDCICR1 |= 3 << (ep_num * 2); ++ } ++} ++ ++static void pio_irq_disable(int ep_num) ++{ ++ ep_num &= 0xf; ++ if (ep_num < 16) ++ UDCICR0 &= ~(3 << (ep_num * 2)); ++ else { ++ ep_num -= 16; ++ UDCICR1 &= ~(3 << (ep_num * 2)); ++ } ++} ++ ++/* The UDCCR reg contains mask and interrupt status bits, ++ * so using '|=' isn't safe as it may ack an interrupt. ++ */ ++#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_UDE) ++ ++static inline void udc_set_mask_UDCCR(int mask) ++{ ++ UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); ++} ++ ++static inline void udc_clear_mask_UDCCR(int mask) ++{ ++ UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); ++} ++ ++static inline void udc_ack_int_UDCCR(int mask) ++{ ++ /* udccr contains the bits we dont want to change */ ++ __u32 udccr = UDCCR & UDCCR_MASK_BITS; ++ ++ UDCCR = udccr | (mask & ~UDCCR_MASK_BITS); ++} ++ ++/* ++ * endpoint enable/disable ++ * ++ * we need to verify the descriptors used to enable endpoints. since pxa27x ++ * endpoint configurations are fixed, and are pretty much always enabled, ++ * there's not a lot to manage here. ++ * ++ * because pxa27x can't selectively initialize bulk (or interrupt) endpoints, ++ * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except ++ * for a single interface (with only the default altsetting) and for gadget ++ * drivers that don't halt endpoints (not reset by set_interface). that also ++ * means that if you use ISO, you must violate the USB spec rule that all ++ * iso endpoints must be in non-default altsettings. ++ */ ++static int pxa27x_ep_enable (struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct pxa27x_ep *ep; ++ struct pxa27x_udc *dev; ++ ++ ep = container_of (_ep, struct pxa27x_ep, ep); ++ if (!_ep || !desc || _ep->name == ep0name ++ || desc->bDescriptorType != USB_DT_ENDPOINT ++ || ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { ++ DMSG("%s, bad ep or descriptor\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* xfer types must match, except that interrupt ~= bulk */ ++ if( ep->ep_type != USB_ENDPOINT_XFER_BULK ++ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { ++ DMSG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); ++ return -EINVAL; ++ } ++ ++ /* hardware _could_ do smaller, but driver doesn't */ ++ if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK ++ && le16_to_cpu (desc->wMaxPacketSize) ++ != BULK_FIFO_SIZE) ++ || !desc->wMaxPacketSize) { ++ DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); ++ return -ERANGE; ++ } ++ ++ dev = ep->dev; ++ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { ++ DMSG("%s, bogus device state\n", __FUNCTION__); ++ return -ESHUTDOWN; ++ } ++ ++ ep->desc = desc; ++ ep->dma = -1; ++ ep->stopped = 0; ++ ep->pio_irqs = ep->dma_irqs = 0; ++ ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize); ++ ++ /* flush fifo (mostly for OUT buffers) */ ++ pxa27x_ep_fifo_flush (_ep); ++ ++ /* ... reset halt state too, if we could ... */ ++ ++#ifdef USE_DMA ++ /* for (some) bulk and ISO endpoints, try to get a DMA channel and ++ * bind it to the endpoint. otherwise use PIO. ++ */ ++ DMSG("%s: called attributes=%d\n", __FUNCTION__, ep->ep_type); ++ switch (ep->ep_type) { ++ case USB_ENDPOINT_XFER_ISOC: ++ if (le16_to_cpu(desc->wMaxPacketSize) % 32) ++ break; ++ // fall through ++ case USB_ENDPOINT_XFER_BULK: ++ if (!use_dma || !ep->reg_drcmr) ++ break; ++ ep->dma = pxa_request_dma ((char *)_ep->name, ++ (le16_to_cpu (desc->wMaxPacketSize) > 64) ++ ? DMA_PRIO_MEDIUM /* some iso */ ++ : DMA_PRIO_LOW, ++ dma_nodesc_handler, ep); ++ if (ep->dma >= 0) { ++ *ep->reg_drcmr = DRCMR_MAPVLD | ep->dma; ++ DMSG("%s using dma%d\n", _ep->name, ep->dma); ++ } ++ default: ++ break; ++ } ++#endif ++ DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); ++ return 0; ++} ++ ++static int pxa27x_ep_disable (struct usb_ep *_ep) ++{ ++ struct pxa27x_ep *ep; ++ ++ ep = container_of (_ep, struct pxa27x_ep, ep); ++ if (!_ep || !ep->desc) { ++ DMSG("%s, %s not enabled\n", __FUNCTION__, ++ _ep ? ep->ep.name : NULL); ++ return -EINVAL; ++ } ++ nuke (ep, -ESHUTDOWN); ++ ++#ifdef USE_DMA ++ if (ep->dma >= 0) { ++ *ep->reg_drcmr = 0; ++ pxa_free_dma (ep->dma); ++ ep->dma = -1; ++ } ++#endif ++ ++ /* flush fifo (mostly for IN buffers) */ ++ pxa27x_ep_fifo_flush (_ep); ++ ++ ep->desc = 0; ++ ep->stopped = 1; ++ ++ DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* for the pxa27x, these can just wrap kmalloc/kfree. gadget drivers ++ * must still pass correctly initialized endpoints, since other controller ++ * drivers may care about how it's currently set up (dma issues etc). ++ */ ++ ++/* ++ * pxa27x_ep_alloc_request - allocate a request data structure ++ */ ++static struct usb_request * ++pxa27x_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) ++{ ++ struct pxa27x_request *req; ++ ++ req = kmalloc (sizeof *req, gfp_flags); ++ if (!req) ++ return 0; ++ ++ memset (req, 0, sizeof *req); ++ INIT_LIST_HEAD (&req->queue); ++ return &req->req; ++} ++ ++ ++/* ++ * pxa27x_ep_free_request - deallocate a request data structure ++ */ ++static void ++pxa27x_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct pxa27x_request *req; ++ ++ req = container_of(_req, struct pxa27x_request, req); ++ WARN_ON (!list_empty (&req->queue)); ++ kfree(req); ++} ++ ++ ++/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's ++ * no device-affinity and the heap works perfectly well for i/o buffers. ++ * It wastes much less memory than dma_alloc_coherent() would, and even ++ * prevents cacheline (32 bytes wide) sharing problems. ++ */ ++static void * ++pxa27x_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, ++ dma_addr_t *dma, unsigned gfp_flags) ++{ ++ char *retval; ++ ++ retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM)); ++ if (retval) ++ *dma = virt_to_bus (retval); ++ return retval; ++} ++ ++static void ++pxa27x_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, ++ unsigned bytes) ++{ ++ kfree (buf); ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * done - retire a request; caller blocked irqs ++ */ ++static void done(struct pxa27x_ep *ep, struct pxa27x_request *req, int status) ++{ ++ list_del_init(&req->queue); ++ if (likely (req->req.status == -EINPROGRESS)) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ if (status && status != -ESHUTDOWN) ++ DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n", ++ ep->ep.name, &req->req, status, ++ req->req.actual, req->req.length); ++ ++ /* don't modify queue heads during completion callback */ ++ req->req.complete(&ep->ep, &req->req); ++} ++ ++ ++static inline void ep0_idle (struct pxa27x_udc *dev) ++{ ++ dev->ep0state = EP0_IDLE; ++ LED_EP0_OFF; ++} ++ ++static int ++write_packet(volatile u32 *uddr, struct pxa27x_request *req, unsigned max) ++{ ++ u32 *buf; ++ int length, count, remain; ++ ++ buf = (u32*)(req->req.buf + req->req.actual); ++ prefetch(buf); ++ ++ /* how big will this packet be? */ ++ length = min(req->req.length - req->req.actual, max); ++ req->req.actual += length; ++ ++ remain = length & 0x3; ++ count = length & ~(0x3); ++ ++ while (likely(count)) { ++ *uddr = *buf++; ++ count -= 4; ++ } ++ ++ if (remain) { ++ volatile u8* reg=(u8*)uddr; ++ char *rd =(u8*)buf; ++ ++ while (remain--) { ++ *reg=*rd++; ++ } ++ } ++ ++ return length; ++} ++ ++/* ++ * write to an IN endpoint fifo, as many packets as possible. ++ * irqs will use this to write the rest later. ++ * caller guarantees at least one packet buffer is ready (or a zlp). ++ */ ++static int ++write_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) ++{ ++ unsigned max; ++ ++ max = le16_to_cpu(ep->desc->wMaxPacketSize); ++ do { ++ int count; ++ int is_last, is_short; ++ ++ count = write_packet(ep->reg_udcdr, req, max); ++ ++ /* last packet is usually short (or a zlp) */ ++ if (unlikely (count != max)) ++ is_last = is_short = 1; ++ else { ++ if (likely(req->req.length != req->req.actual) ++ || req->req.zero) ++ is_last = 0; ++ else ++ is_last = 1; ++ /* interrupt/iso maxpacket may not fill the fifo */ ++ is_short = unlikely (max < ep->fifo_size); ++ } ++ ++ DMSG("wrote %s count:%d bytes%s%s %d left %p\n", ++ ep->ep.name, count, ++ is_last ? "/L" : "", is_short ? "/S" : "", ++ req->req.length - req->req.actual, &req->req); ++ ++ /* let loose that packet. maybe try writing another one, ++ * double buffering might work. TSP, TPC, and TFS ++ * bit values are the same for all normal IN endpoints. ++ */ ++ *ep->reg_udccsr = UDCCSR_PC; ++ if (is_short) ++ *ep->reg_udccsr = UDCCSR_SP; ++ ++ /* requests complete when all IN data is in the FIFO */ ++ if (is_last) { ++ done (ep, req, 0); ++ if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) { ++ pio_irq_disable (ep->ep_num); ++#ifdef USE_DMA ++ /* unaligned data and zlps couldn't use dma */ ++ if (unlikely(!list_empty(&ep->queue))) { ++ req = list_entry(ep->queue.next, ++ struct pxa27x_request, queue); ++ kick_dma(ep,req); ++ return 0; ++ } ++#endif ++ } ++ return 1; ++ } ++ ++ // TODO experiment: how robust can fifo mode tweaking be? ++ // double buffering is off in the default fifo mode, which ++ // prevents TFS from being set here. ++ ++ } while (*ep->reg_udccsr & UDCCSR_FS); ++ return 0; ++} ++ ++/* caller asserts req->pending (ep0 irq status nyet cleared); starts ++ * ep0 data stage. these chips want very simple state transitions. ++ */ ++static inline ++void ep0start(struct pxa27x_udc *dev, u32 flags, const char *tag) ++{ ++ UDCCSR0 = flags|UDCCSR0_SA|UDCCSR0_OPC; ++ UDCISR0 = UDCICR_INT(0, UDC_INT_FIFOERROR | UDC_INT_PACKETCMP); ++ dev->req_pending = 0; ++ DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n", ++ __FUNCTION__, tag, UDCCSR0, flags); ++} ++ ++static int ++write_ep0_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) ++{ ++ unsigned count; ++ int is_short; ++ ++ count = write_packet(&UDCDR0, req, EP0_FIFO_SIZE); ++ ep->dev->stats.write.bytes += count; ++ ++ /* last packet "must be" short (or a zlp) */ ++ is_short = (count != EP0_FIFO_SIZE); ++ ++ DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count, ++ req->req.length - req->req.actual, &req->req); ++ ++ if (unlikely (is_short)) { ++ if (ep->dev->req_pending) ++ ep0start(ep->dev, UDCCSR0_IPR, "short IN"); ++ else ++ UDCCSR0 = UDCCSR0_IPR; ++ ++ count = req->req.length; ++ done (ep, req, 0); ++ ep0_idle(ep->dev); ++#if 0 ++ /* This seems to get rid of lost status irqs in some cases: ++ * host responds quickly, or next request involves config ++ * change automagic, or should have been hidden, or ... ++ * ++ * FIXME get rid of all udelays possible... ++ */ ++ if (count >= EP0_FIFO_SIZE) { ++ count = 100; ++ do { ++ if ((UDCCSR0 & UDCCSR0_OPC) != 0) { ++ /* clear OPC, generate ack */ ++ UDCCSR0 = UDCCSR0_OPC; ++ break; ++ } ++ count--; ++ udelay(1); ++ } while (count); ++ } ++#endif ++ } else if (ep->dev->req_pending) ++ ep0start(ep->dev, 0, "IN"); ++ return is_short; ++} ++ ++ ++/* ++ * read_fifo - unload packet(s) from the fifo we use for usb OUT ++ * transfers and put them into the request. caller should have made ++ * sure there's at least one packet ready. ++ * ++ * returns true if the request completed because of short packet or the ++ * request buffer having filled (and maybe overran till end-of-packet). ++ */ ++static int ++read_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) ++{ ++ for (;;) { ++ u32 *buf; ++ int bufferspace, count, is_short; ++ ++ /* make sure there's a packet in the FIFO.*/ ++ if (unlikely ((*ep->reg_udccsr & UDCCSR_PC) == 0)) ++ break; ++ buf =(u32*) (req->req.buf + req->req.actual); ++ prefetchw(buf); ++ bufferspace = req->req.length - req->req.actual; ++ ++ /* read all bytes from this packet */ ++ if (likely (*ep->reg_udccsr & UDCCSR_BNE)) { ++ count = 0x3ff & *ep->reg_udcbcr; ++ req->req.actual += min (count, bufferspace); ++ } else /* zlp */ ++ count = 0; ++ ++ is_short = (count < ep->ep.maxpacket); ++ DMSG("read %s udccsr:%02x, count:%d bytes%s req %p %d/%d\n", ++ ep->ep.name, *ep->reg_udccsr, count, ++ is_short ? "/S" : "", ++ &req->req, req->req.actual, req->req.length); ++ ++// dump_regs(ep->ep_num ); ++ count = min(count, bufferspace); ++ while (likely (count > 0)) { ++ *buf++ = *ep->reg_udcdr; ++ count -= 4; ++ } ++ DMSG("Buf:0x%p\n", req->req.buf); ++ ++ *ep->reg_udccsr = UDCCSR_PC; ++ /* RPC/RSP/RNE could now reflect the other packet buffer */ ++ ++ /* completion */ ++ if (is_short || req->req.actual == req->req.length) { ++ done (ep, req, 0); ++ if (list_empty(&ep->queue)) ++ pio_irq_disable (ep->ep_num); ++ return 1; ++ } ++ ++ /* finished that packet. the next one may be waiting... */ ++ } ++ return 0; ++} ++ ++/* ++ * special ep0 version of the above. no UBCR0 or double buffering; status ++ * handshaking is magic. most device protocols don't need control-OUT. ++ * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other ++ * protocols do use them. ++ */ ++static int ++read_ep0_fifo (struct pxa27x_ep *ep, struct pxa27x_request *req) ++{ ++ u32 *buf, word; ++ unsigned bufferspace; ++ ++ buf = (u32*) (req->req.buf + req->req.actual); ++ bufferspace = req->req.length - req->req.actual; ++ ++ while (UDCCSR0 & UDCCSR0_RNE) { ++ word = UDCDR0; ++ ++ if (unlikely (bufferspace == 0)) { ++ /* this happens when the driver's buffer ++ * is smaller than what the host sent. ++ * discard the extra data. ++ */ ++ if (req->req.status != -EOVERFLOW) ++ DMSG("%s overflow\n", ep->ep.name); ++ req->req.status = -EOVERFLOW; ++ } else { ++ *buf++ = word; ++ req->req.actual += 4; ++ bufferspace -= 4; ++ } ++ } ++ ++ UDCCSR0 = UDCCSR0_OPC ; ++ ++ /* completion */ ++ if (req->req.actual >= req->req.length) ++ return 1; ++ ++ /* finished that packet. the next one may be waiting... */ ++ return 0; ++} ++ ++#ifdef USE_DMA ++ ++#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE) ++static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req) ++{ ++ u32 dcmd = 0; ++ u32 len = req->req.length; ++ u32 buf = req->req.dma; ++ u32 fifo = io_v2p ((u32)ep->reg_udcdr); ++ ++ buf += req->req.actual; ++ len -= req->req.actual; ++ ep->dma_con = 0; ++ ++ DMSG("%s: req:0x%p length:%d, actual:%d dma:%d\n", ++ __FUNCTION__, &req->req, req->req.length, ++ req->req.actual,ep->dma); ++ ++ /* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */ ++ DCSR(ep->dma) = DCSR_NODESC; ++ if (buf & 0x3) ++ DALGN |= 1 << ep->dma; ++ else ++ DALGN &= ~(1 << ep->dma); ++ ++ if (ep->dir_in) { ++ DSADR(ep->dma) = buf; ++ DTADR(ep->dma) = fifo; ++ if (len > MAX_IN_DMA) { ++ len= MAX_IN_DMA; ++ ep->dma_con =1 ; ++ } else if (len >= ep->ep.maxpacket) { ++ if ((ep->dma_con = (len % ep->ep.maxpacket) != 0)) ++ len = ep->ep.maxpacket; ++ } ++ dcmd = len | DCMD_BURST32 | DCMD_WIDTH4 | DCMD_ENDIRQEN ++ | DCMD_FLOWTRG | DCMD_INCSRCADDR; ++ } else { ++ DSADR(ep->dma) = fifo; ++ DTADR(ep->dma) = buf; ++ dcmd = len | DCMD_BURST32 | DCMD_WIDTH4 | DCMD_ENDIRQEN ++ | DCMD_FLOWSRC | DCMD_INCTRGADDR; ++ } ++ *ep->reg_udccsr = UDCCSR_DME; ++ DCMD(ep->dma) = dcmd; ++ DCSR(ep->dma) = DCSR_NODESC | DCSR_EORIRQEN \ ++ | ((ep->dir_in) ? DCSR_STOPIRQEN : 0); ++ *ep->reg_drcmr = ep->dma | DRCMR_MAPVLD; ++ DCSR(ep->dma) |= DCSR_RUN; ++} ++ ++static void cancel_dma(struct pxa27x_ep *ep) ++{ ++ struct pxa27x_request *req; ++ u32 tmp; ++ ++ if (DCSR(ep->dma) == 0 || list_empty(&ep->queue)) ++ return; ++ ++ DMSG("hehe dma:%d,dcsr:0x%x\n", ep->dma, DCSR(ep->dma)); ++ DCSR(ep->dma) = 0; ++ while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0) ++ cpu_relax(); ++ ++ req = list_entry(ep->queue.next, struct pxa27x_request, queue); ++ tmp = DCMD(ep->dma) & DCMD_LENGTH; ++ req->req.actual = req->req.length - tmp; ++ ++ /* the last tx packet may be incomplete, so flush the fifo. ++ * FIXME correct req.actual if we can ++ */ ++ *ep->reg_udccsr = UDCCSR_FEF; ++} ++ ++static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r) ++{ ++ struct pxa27x_ep *ep = _ep; ++ struct pxa27x_request *req, *req_next; ++ u32 dcsr, tmp, completed; ++ ++ local_irq_disable(); ++ ++ req = list_entry(ep->queue.next, struct pxa27x_request, queue); ++ ++ DMSG("%s, buf:0x%p\n",__FUNCTION__, req->req.buf); ++ ++ ep->dma_irqs++; ++ ep->dev->stats.irqs++; ++ HEX_DISPLAY(ep->dev->stats.irqs); ++ ++ completed = 0; ++ ++ dcsr = DCSR(dmach); ++ DCSR(ep->dma) &= ~DCSR_RUN; ++ ++ if (dcsr & DCSR_BUSERR) { ++ DCSR(dmach) = DCSR_BUSERR; ++ printk(KERN_ERR " Buss Error\n"); ++ req->req.status = -EIO; ++ completed = 1; ++ } else if (dcsr & DCSR_ENDINTR) { ++ DCSR(dmach) = DCSR_ENDINTR; ++ if (ep->dir_in) { ++ tmp = req->req.length - req->req.actual; ++ /* Last packet is a short one*/ ++ if ( tmp < ep->ep.maxpacket) { ++ int count = 0; ++ ++ *ep->reg_udccsr = UDCCSR_SP | \ ++ (*ep->reg_udccsr & UDCCSR_MASK); ++ /*Wait for packet out */ ++ while( (count++ < 10000) && \ ++ !(*ep->reg_udccsr & UDCCSR_FS)); ++ if (count >= 10000) ++ DMSG("Failed to send packet\n"); ++ else ++ DMSG("%s: short packet sent len:%d," ++ "length:%d,actual:%d\n", __FUNCTION__, ++ tmp, req->req.length, req->req.actual); ++ req->req.actual = req->req.length; ++ completed = 1; ++ /* There are still packets to transfer */ ++ } else if ( ep->dma_con) { ++ DMSG("%s: more packets,length:%d,actual:%d\n", ++ __FUNCTION__,req->req.length, ++ req->req.actual); ++ req->req.actual += ep->ep.maxpacket; ++ completed = 0; ++ } else { ++ DMSG("%s: no more packets,length:%d," ++ "actual:%d\n", __FUNCTION__, ++ req->req.length, req->req.actual); ++ req->req.actual = req->req.length; ++ completed = 1; ++ } ++ } else { ++ req->req.actual = req->req.length; ++ completed = 1; ++ } ++ } else if (dcsr & DCSR_ENRINTR) { //Only happened in OUT DMA ++ int remain,udccsr ; ++ ++ DCSR(dmach) = DCSR_ENRINTR; ++ remain = DCMD(dmach) & DCMD_LENGTH; ++ req->req.actual = req->req.length - remain; ++ ++ udccsr = *ep->reg_udccsr; ++ if (udccsr & UDCCSR_SP) { ++ *ep->reg_udccsr = UDCCSR_PC | (udccsr & UDCCSR_MASK); ++ completed = 1; ++ } ++ DMSG("%s: length:%d actual:%d\n", ++ __FUNCTION__, req->req.length, req->req.actual); ++ } else ++ DMSG("%s: Others dma:%d DCSR:0x%x DCMD:0x%x\n", ++ __FUNCTION__, dmach, DCSR(dmach), DCMD(dmach)); ++ ++ if (likely(completed)) { ++ if (req->queue.next != &ep->queue) { ++ req_next = list_entry(req->queue.next, ++ struct pxa27x_request, queue); ++ kick_dma(ep, req_next); ++ } ++ done(ep, req, 0); ++ } else { ++ kick_dma(ep, req); ++ } ++ ++ local_irq_enable(); ++} ++ ++#endif ++/*-------------------------------------------------------------------------*/ ++ ++static int ++pxa27x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) ++{ ++ struct pxa27x_ep *ep; ++ struct pxa27x_request *req; ++ struct pxa27x_udc *dev; ++ unsigned long flags; ++ ++ req = container_of(_req, struct pxa27x_request, req); ++ if (unlikely (!_req || !_req->complete || !_req->buf|| ++ !list_empty(&req->queue))) { ++ DMSG("%s, bad params\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ ep = container_of(_ep, struct pxa27x_ep, ep); ++ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { ++ DMSG("%s, bad ep\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ DMSG("%s, ep point %d is queue\n", __FUNCTION__, ep->ep_num); ++ ++ dev = ep->dev; ++ if (unlikely (!dev->driver ++ || dev->gadget.speed == USB_SPEED_UNKNOWN)) { ++ DMSG("%s, bogus device state\n", __FUNCTION__); ++ return -ESHUTDOWN; ++ } ++ ++ /* iso is always one packet per request, that's the only way ++ * we can report per-packet status. that also helps with dma. ++ */ ++ if (unlikely (ep->ep_type == USB_ENDPOINT_XFER_ISOC ++ && req->req.length > le16_to_cpu ++ (ep->desc->wMaxPacketSize))) ++ return -EMSGSIZE; ++ ++#ifdef USE_DMA ++ // FIXME caller may already have done the dma mapping ++ if (ep->dma >= 0) { ++ _req->dma = dma_map_single(dev->dev, _req->buf, _req->length, ++ (ep->dir_in) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ } ++#endif ++ ++ DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", ++ _ep->name, _req, _req->length, _req->buf); ++ ++ local_irq_save(flags); ++ ++ _req->status = -EINPROGRESS; ++ _req->actual = 0; ++ ++ /* kickstart this i/o queue? */ ++ if (list_empty(&ep->queue) && !ep->stopped) { ++ if (ep->desc == 0 /* ep0 */) { ++ unsigned length = _req->length; ++ ++ switch (dev->ep0state) { ++ case EP0_IN_DATA_PHASE: ++ dev->stats.write.ops++; ++ if (write_ep0_fifo(ep, req)) ++ req = 0; ++ break; ++ ++ case EP0_OUT_DATA_PHASE: ++ dev->stats.read.ops++; ++ if (dev->req_pending) ++ ep0start(dev, UDCCSR0_IPR, "OUT"); ++ if (length == 0 || ((UDCCSR0 & UDCCSR0_RNE) != 0 ++ && read_ep0_fifo(ep, req))) { ++ ep0_idle(dev); ++ done(ep, req, 0); ++ req = 0; ++ } ++ break; ++ case EP0_NO_ACTION: ++ ep0_idle(dev); ++ req=0; ++ break; ++ default: ++ DMSG("ep0 i/o, odd state %d\n", dev->ep0state); ++ local_irq_restore (flags); ++ return -EL2HLT; ++ } ++#ifdef USE_DMA ++ /* either start dma or prime pio pump */ ++ } else if (ep->dma >= 0) { ++ kick_dma(ep, req); ++#endif ++ /* can the FIFO can satisfy the request immediately? */ ++ } else if (ep->dir_in ++ && (*ep->reg_udccsr & UDCCSR_FS) != 0 ++ && write_fifo(ep, req)) { ++ req = 0; ++ } else if ((*ep->reg_udccsr & UDCCSR_FS) != 0 ++ && read_fifo(ep, req)) { ++ req = 0; ++ } ++ DMSG("req:%p,ep->desc:%p,ep->dma:%d\n", req, ep->desc, ep->dma); ++ if (likely (req && ep->desc) && ep->dma < 0) ++ pio_irq_enable(ep->ep_num); ++ } ++ ++ /* pio or dma irq handler advances the queue. */ ++ if (likely (req != 0)) ++ list_add_tail(&req->queue, &ep->queue); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++ ++/* ++ * nuke - dequeue ALL requests ++ */ ++static void nuke(struct pxa27x_ep *ep, int status) ++{ ++ struct pxa27x_request *req; ++ ++ /* called with irqs blocked */ ++#ifdef USE_DMA ++ if (ep->dma >= 0 && !ep->stopped) ++ cancel_dma(ep); ++#endif ++ while (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, struct pxa27x_request, queue); ++ done(ep, req, status); ++ } ++ if (ep->desc) ++ pio_irq_disable (ep->ep_num); ++} ++ ++ ++/* dequeue JUST ONE request */ ++static int pxa27x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct pxa27x_ep *ep; ++ struct pxa27x_request *req; ++ unsigned long flags; ++ ++ ep = container_of(_ep, struct pxa27x_ep, ep); ++ if (!_ep || ep->ep.name == ep0name) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ /* make sure it's actually queued on this endpoint */ ++ list_for_each_entry (req, &ep->queue, queue) { ++ if (&req->req == _req) ++ break; ++ } ++ if (&req->req != _req) { ++ local_irq_restore(flags); ++ return -EINVAL; ++ } ++ ++#ifdef USE_DMA ++ if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) { ++ cancel_dma(ep); ++ done(ep, req, -ECONNRESET); ++ /* restart i/o */ ++ if (!list_empty(&ep->queue)) { ++ req = list_entry(ep->queue.next, ++ struct pxa27x_request, queue); ++ kick_dma(ep, req); ++ } ++ } else ++#endif ++ done(ep, req, -ECONNRESET); ++ ++ local_irq_restore(flags); ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int pxa27x_ep_set_halt(struct usb_ep *_ep, int value) ++{ ++ struct pxa27x_ep *ep; ++ unsigned long flags; ++ ++ DMSG("%s is called\n", __FUNCTION__); ++ ep = container_of(_ep, struct pxa27x_ep, ep); ++ if (unlikely (!_ep ++ || (!ep->desc && ep->ep.name != ep0name)) ++ || ep->ep_type == USB_ENDPOINT_XFER_ISOC) { ++ DMSG("%s, bad ep\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ if (value == 0) { ++ /* this path (reset toggle+halt) is needed to implement ++ * SET_INTERFACE on normal hardware. but it can't be ++ * done from software on the PXA UDC, and the hardware ++ * forgets to do it as part of SET_INTERFACE automagic. ++ */ ++ DMSG("only host can clear %s halt\n", _ep->name); ++ return -EROFS; ++ } ++ ++ local_irq_save(flags); ++ ++ if (ep->dir_in && ((*ep->reg_udccsr & UDCCSR_FS) == 0 ++ || !list_empty(&ep->queue))) { ++ local_irq_restore(flags); ++ return -EAGAIN; ++ } ++ ++ /* FST bit is the same for control, bulk in, bulk out, interrupt in */ ++ *ep->reg_udccsr = UDCCSR_FST|UDCCSR_FEF; ++ ++ /* ep0 needs special care */ ++ if (!ep->desc) { ++ start_watchdog(ep->dev); ++ ep->dev->req_pending = 0; ++ ep->dev->ep0state = EP0_STALL; ++ LED_EP0_OFF; ++ ++ /* and bulk/intr endpoints like dropping stalls too */ ++ } else { ++ unsigned i; ++ for (i = 0; i < 1000; i += 20) { ++ if (*ep->reg_udccsr & UDCCSR_SST) ++ break; ++ udelay(20); ++ } ++ } ++ local_irq_restore(flags); ++ ++ DBG(DBG_VERBOSE, "%s halt\n", _ep->name); ++ return 0; ++} ++ ++static int pxa27x_ep_fifo_status(struct usb_ep *_ep) ++{ ++ struct pxa27x_ep *ep; ++ ++ ep = container_of(_ep, struct pxa27x_ep, ep); ++ if (!_ep) { ++ DMSG("%s, bad ep\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ /* pxa can't report unclaimed bytes from IN fifos */ ++ if (ep->dir_in) ++ return -EOPNOTSUPP; ++ if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN ++ || (*ep->reg_udccsr & UDCCSR_FS) == 0) ++ return 0; ++ else ++ return (*ep->reg_udcbcr & 0xfff) + 1; ++} ++ ++static void pxa27x_ep_fifo_flush(struct usb_ep *_ep) ++{ ++ struct pxa27x_ep *ep; ++ ++ ep = container_of(_ep, struct pxa27x_ep, ep); ++ if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) { ++ DMSG("%s, bad ep\n", __FUNCTION__); ++ return; ++ } ++ ++ /* toggle and halt bits stay unchanged */ ++ ++ /* for OUT, just read and discard the FIFO contents. */ ++ if (!ep->dir_in) { ++ while (((*ep->reg_udccsr) & UDCCSR_BNE) != 0) ++ (void) *ep->reg_udcdr; ++ return; ++ } ++ ++ /* most IN status is the same, but ISO can't stall */ ++ *ep->reg_udccsr = UDCCSR_PC|UDCCSR_FST|UDCCSR_TRN ++ | (ep->ep_type == USB_ENDPOINT_XFER_ISOC) ++ ? 0 : UDCCSR_SST; ++} ++ ++ ++static struct usb_ep_ops pxa27x_ep_ops = { ++ .enable = pxa27x_ep_enable, ++ .disable = pxa27x_ep_disable, ++ ++ .alloc_request = pxa27x_ep_alloc_request, ++ .free_request = pxa27x_ep_free_request, ++ ++ .alloc_buffer = pxa27x_ep_alloc_buffer, ++ .free_buffer = pxa27x_ep_free_buffer, ++ ++ .queue = pxa27x_ep_queue, ++ .dequeue = pxa27x_ep_dequeue, ++ ++ .set_halt = pxa27x_ep_set_halt, ++ .fifo_status = pxa27x_ep_fifo_status, ++ .fifo_flush = pxa27x_ep_fifo_flush, ++}; ++ ++ ++/* --------------------------------------------------------------------------- ++ * device-scoped parts of the api to the usb controller hardware ++ * --------------------------------------------------------------------------- ++ */ ++ ++static int pxa27x_udc_get_frame(struct usb_gadget *_gadget) ++{ ++ return (UDCFNR & 0x3FF); ++} ++ ++static int pxa27x_udc_wakeup(struct usb_gadget *_gadget) ++{ ++ /* host may not have enabled remote wakeup */ ++ if ((UDCCR & UDCCR_DWRE) == 0) ++ return -EHOSTUNREACH; ++ udc_set_mask_UDCCR(UDCCR_UDR); ++ return 0; ++} ++ ++static const struct usb_gadget_ops pxa27x_udc_ops = { ++ .get_frame = pxa27x_udc_get_frame, ++ .wakeup = pxa27x_udc_wakeup, ++ // current versions must always be self-powered ++}; ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++#ifdef UDC_PROC_FILE ++ ++static const char proc_node_name [] = "driver/udc"; ++ ++static int ++udc_proc_read(char *page, char **start, off_t off, int count, ++ int *eof, void *_dev) ++{ ++ char *buf = page; ++ struct pxa27x_udc *dev = _dev; ++ char *next = buf; ++ unsigned size = count; ++ unsigned long flags; ++ int i, t; ++ u32 tmp; ++ ++ if (off != 0) ++ return 0; ++ ++ local_irq_save(flags); ++ ++ /* basic device status */ ++ t = scnprintf(next, size, DRIVER_DESC "\n" ++ "%s version: %s\nGadget driver: %s\n", ++ driver_name, DRIVER_VERSION SIZE_STR DMASTR, ++ dev->driver ? dev->driver->driver.name : "(none)"); ++ size -= t; ++ next += t; ++ ++ /* registers for device and ep0 */ ++ t = scnprintf(next, size, ++ "uicr %02X.%02X, usir %02X.%02x, ufnr %02X\n", ++ UDCICR1, UDCICR0, UDCISR1, UDCISR0, UDCFNR); ++ size -= t; ++ next += t; ++ ++ tmp = UDCCR; ++ t = scnprintf(next, size,"udccr %02X =%s%s%s%s%s%s%s%s%s%s, con=%d,inter=%d,altinter=%d\n", tmp, ++ (tmp & UDCCR_OEN) ? " oen":"", ++ (tmp & UDCCR_AALTHNP) ? " aalthnp":"", ++ (tmp & UDCCR_AHNP) ? " rem" : "", ++ (tmp & UDCCR_BHNP) ? " rstir" : "", ++ (tmp & UDCCR_DWRE) ? " dwre" : "", ++ (tmp & UDCCR_SMAC) ? " smac" : "", ++ (tmp & UDCCR_EMCE) ? " emce" : "", ++ (tmp & UDCCR_UDR) ? " udr" : "", ++ (tmp & UDCCR_UDA) ? " uda" : "", ++ (tmp & UDCCR_UDE) ? " ude" : "", ++ (tmp & UDCCR_ACN) >> UDCCR_ACN_S, ++ (tmp & UDCCR_AIN) >> UDCCR_AIN_S, ++ (tmp & UDCCR_AAISN)>> UDCCR_AAISN_S ); ++ ++ size -= t; ++ next += t; ++ ++ tmp = UDCCSR0; ++ t = scnprintf(next, size, ++ "udccsr0 %02X =%s%s%s%s%s%s%s\n", tmp, ++ (tmp & UDCCSR0_SA) ? " sa" : "", ++ (tmp & UDCCSR0_RNE) ? " rne" : "", ++ (tmp & UDCCSR0_FST) ? " fst" : "", ++ (tmp & UDCCSR0_SST) ? " sst" : "", ++ (tmp & UDCCSR0_DME) ? " dme" : "", ++ (tmp & UDCCSR0_IPR) ? " ipr" : "", ++ (tmp & UDCCSR0_OPC) ? " opc" : ""); ++ size -= t; ++ next += t; ++ ++ if (!dev->driver) ++ goto done; ++ ++ t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", ++ dev->stats.write.bytes, dev->stats.write.ops, ++ dev->stats.read.bytes, dev->stats.read.ops, ++ dev->stats.irqs); ++ size -= t; ++ next += t; ++ ++ /* dump endpoint queues */ ++ for (i = 0; i < UDC_EP_NUM; i++) { ++ struct pxa27x_ep *ep = &dev->ep [i]; ++ struct pxa27x_request *req; ++ int t; ++ ++ if (i != 0) { ++ const struct usb_endpoint_descriptor *d; ++ ++ d = ep->desc; ++ if (!d) ++ continue; ++ tmp = *dev->ep [i].reg_udccsr; ++ t = scnprintf(next, size, ++ "%s max %d %s udccs %02x udccr:0x%x\n", ++ ep->ep.name, le16_to_cpu (d->wMaxPacketSize), ++ (ep->dma >= 0) ? "dma" : "pio", tmp, ++ *dev->ep[i].reg_udccr); ++ /* TODO translate all five groups of udccs bits! */ ++ ++ } else /* ep0 should only have one transfer queued */ ++ t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n", ++ ep->pio_irqs); ++ if (t <= 0 || t > size) ++ goto done; ++ size -= t; ++ next += t; ++ ++ if (list_empty(&ep->queue)) { ++ t = scnprintf(next, size, "\t(nothing queued)\n"); ++ if (t <= 0 || t > size) ++ goto done; ++ size -= t; ++ next += t; ++ continue; ++ } ++ list_for_each_entry(req, &ep->queue, queue) { ++#ifdef USE_DMA ++ if (ep->dma >= 0 && req->queue.prev == &ep->queue) ++ t = scnprintf(next, size, ++ "\treq %p len %d/%d " ++ "buf %p (dma%d dcmd %08x)\n", ++ &req->req, req->req.actual, ++ req->req.length, req->req.buf, ++ ep->dma, DCMD(ep->dma) ++ // low 13 bits == bytes-to-go ++ ); ++ else ++#endif ++ t = scnprintf(next, size, ++ "\treq %p len %d/%d buf %p\n", ++ &req->req, req->req.actual, ++ req->req.length, req->req.buf); ++ if (t <= 0 || t > size) ++ goto done; ++ size -= t; ++ next += t; ++ } ++ } ++ ++done: ++ local_irq_restore(flags); ++ *eof = 1; ++ return count - size; ++} ++ ++#define create_proc_files() \ ++ create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev) ++#define remove_proc_files() \ ++ remove_proc_entry(proc_node_name, NULL) ++ ++#else /* !UDC_PROC_FILE */ ++#define create_proc_files() do {} while (0) ++#define remove_proc_files() do {} while (0) ++ ++#endif /* UDC_PROC_FILE */ ++ ++/* "function" sysfs attribute */ ++static ssize_t ++show_function (struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ struct pxa27x_udc *dev = dev_get_drvdata (_dev); ++ ++ if (!dev->driver ++ || !dev->driver->function ++ || strlen (dev->driver->function) > PAGE_SIZE) ++ return 0; ++ return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function); ++} ++static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * udc_disable - disable USB device controller ++ */ ++static void udc_disable(struct pxa27x_udc *dev) ++{ ++ UDCICR0 = UDCICR1 = 0x00000000; ++ ++ udc_clear_mask_UDCCR(UDCCR_UDE); ++ ++ /* Disable clock for USB device */ ++ pxa_set_cken(CKEN11_USB, 0); ++ ++ ep0_idle (dev); ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ LED_CONNECTED_OFF; ++ dev->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); ++} ++ ++ ++/* ++ * udc_reinit - initialize software state ++ */ ++static void udc_reinit(struct pxa27x_udc *dev) ++{ ++ u32 i; ++ ++ dev->ep0state = EP0_IDLE; ++ ++ /* basic endpoint records init */ ++ for (i = 0; i < UDC_EP_NUM; i++) { ++ struct pxa27x_ep *ep = &dev->ep[i]; ++ ++ ep->stopped = 0; ++ ep->pio_irqs = ep->dma_irqs = 0; ++ } ++ dev->configuration = 0; ++ dev->interface = 0; ++ dev->alternate = 0; ++ /* the rest was statically initialized, and is read-only */ ++} ++ ++/* until it's enabled, this UDC should be completely invisible ++ * to any USB host. ++ */ ++static void udc_enable (struct pxa27x_udc *dev) ++{ ++ udc_clear_mask_UDCCR(UDCCR_UDE); ++ ++ // MST_MSCWR2 &= ~(MST_MSCWR2_nUSBC_SC); ++ ++ /* Enable clock for USB device */ ++ pxa_set_cken(CKEN11_USB, 1); ++ ++ UDCICR0 = UDCICR1 = 0; ++ ++ ep0_idle(dev); ++ dev->gadget.speed = USB_SPEED_FULL; ++ dev->stats.irqs = 0; ++ ++ udc_set_mask_UDCCR(UDCCR_UDE); ++ udelay (2); ++ if (UDCCR & UDCCR_EMCE) ++ { ++ printk(KERN_ERR ": There are error in configuration, udc disabled\n"); ++ } ++ ++ /* caller must be able to sleep in order to cope ++ * with startup transients. ++ */ ++ msleep(100); ++ ++ /* enable suspend/resume and reset irqs */ ++ UDCICR1 = UDCICR1_IECC | UDCICR1_IERU | UDCICR1_IESU | UDCICR1_IERS; ++ ++ /* enable ep0 irqs */ ++ UDCICR0 = UDCICR_INT(0,UDCICR_INT_MASK); ++#if 0 ++ for(i=1; i < UDC_EP_NUM; i++) { ++ if (dev->ep[i].assigned) ++ pio_irq_enable(i); ++ } ++#endif ++ dev->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); ++} ++ ++ ++/* when a driver is successfully registered, it will receive ++ * control requests including set_configuration(), which enables ++ * non-control requests. then usb traffic follows until a ++ * disconnect is reported. then a host may connect again, or ++ * the driver might get unbound. ++ */ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ struct pxa27x_udc *dev = the_controller; ++ int retval; ++#if 0 ++ DMSG("dev=0x%x, driver=0x%x, speed=%d," ++ "bind=0x%x, unbind=0x%x, disconnect=0x%x, setup=0x%x\n", ++ (unsigned)dev, (unsigned)driver, driver->speed, ++ (unsigned)driver->bind, (unsigned)driver->unbind, ++ (unsigned)driver->disconnect, (unsigned)driver->setup); ++#endif ++ if (!driver || driver->speed != USB_SPEED_FULL ++ || !driver->bind ++ || !driver->unbind ++ || !driver->disconnect ++ || !driver->setup) ++ return -EINVAL; ++ if (!dev) ++ return -ENODEV; ++ if (dev->driver) ++ return -EBUSY; ++ ++ /* first hook up the driver ... */ ++ dev->driver = driver; ++ dev->gadget.dev.driver = &driver->driver; ++ ++ device_add (&dev->gadget.dev); ++ retval = driver->bind(&dev->gadget); ++ if (retval) { ++ DMSG("bind to driver %s --> error %d\n", ++ driver->driver.name, retval); ++ device_del (&dev->gadget.dev); ++ ++ dev->driver = 0; ++ dev->gadget.dev.driver = 0; ++ return retval; ++ } ++ device_create_file(dev->dev, &dev_attr_function); ++ ++ /* ... then enable host detection and ep0; and we're ready ++ * for set_configuration as well as eventual disconnect. ++ * NOTE: this shouldn't power up until later. ++ */ ++ DMSG("registered gadget driver '%s'\n", driver->driver.name); ++ udc_enable(dev); ++ dump_state(dev); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++static void ++stop_activity(struct pxa27x_udc *dev, struct usb_gadget_driver *driver) ++{ ++ int i; ++ ++ DMSG("Trace path 1\n"); ++ /* don't disconnect drivers more than once */ ++ if (dev->gadget.speed == USB_SPEED_UNKNOWN) ++ driver = 0; ++ dev->gadget.speed = USB_SPEED_UNKNOWN; ++ ++ /* prevent new request submissions, kill any outstanding requests */ ++ for (i = 0; i < UDC_EP_NUM; i++) { ++ struct pxa27x_ep *ep = &dev->ep[i]; ++ ++ ep->stopped = 1; ++ nuke(ep, -ESHUTDOWN); ++ } ++ del_timer_sync(&dev->timer); ++ ++ /* report disconnect; the driver is already quiesced */ ++ if (driver) ++ driver->disconnect(&dev->gadget); ++ ++ /* re-init driver-visible data structures */ ++ udc_reinit(dev); ++} ++ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct pxa27x_udc *dev = the_controller; ++ ++ if (!dev) ++ return -ENODEV; ++ if (!driver || driver != dev->driver) ++ return -EINVAL; ++ ++ local_irq_disable(); ++ udc_disable(dev); ++ stop_activity(dev, driver); ++ local_irq_enable(); ++ ++ driver->unbind(&dev->gadget); ++ dev->driver = 0; ++ ++ device_del (&dev->gadget.dev); ++ device_remove_file(dev->dev, &dev_attr_function); ++ ++ DMSG("unregistered gadget driver '%s'\n", driver->driver.name); ++ dump_state(dev); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++#ifndef enable_disconnect_irq ++#define enable_disconnect_irq() do {} while (0) ++#define disable_disconnect_irq() do {} while (0) ++#endif ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static inline void clear_ep_state (struct pxa27x_udc *dev) ++{ ++ unsigned i; ++ ++ /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint ++ * fifos, and pending transactions mustn't be continued in any case. ++ */ ++ for (i = 1; i < UDC_EP_NUM; i++) ++ nuke(&dev->ep[i], -ECONNABORTED); ++} ++ ++static void udc_watchdog(unsigned long _dev) ++{ ++ struct pxa27x_udc *dev = (void *)_dev; ++ ++ local_irq_disable(); ++ if (dev->ep0state == EP0_STALL ++ && (UDCCSR0 & UDCCSR0_FST) == 0 ++ && (UDCCSR0 & UDCCSR0_SST) == 0) { ++ UDCCSR0 = UDCCSR0_FST|UDCCSR0_FTF; ++ DBG(DBG_VERBOSE, "ep0 re-stall\n"); ++ start_watchdog(dev); ++ } ++ local_irq_enable(); ++} ++ ++static void handle_ep0 (struct pxa27x_udc *dev) ++{ ++ u32 udccsr0 = UDCCSR0; ++ struct pxa27x_ep *ep = &dev->ep [0]; ++ struct pxa27x_request *req; ++ union { ++ struct usb_ctrlrequest r; ++ u8 raw [8]; ++ u32 word [2]; ++ } u; ++ ++ if (list_empty(&ep->queue)) ++ req = 0; ++ else ++ req = list_entry(ep->queue.next, struct pxa27x_request, queue); ++ ++ /* clear stall status */ ++ if (udccsr0 & UDCCSR0_SST) { ++ nuke(ep, -EPIPE); ++ UDCCSR0 = UDCCSR0_SST; ++ del_timer(&dev->timer); ++ ep0_idle(dev); ++ } ++ ++ /* previous request unfinished? non-error iff back-to-back ... */ ++ if ((udccsr0 & UDCCSR0_SA) != 0 && dev->ep0state != EP0_IDLE) { ++ nuke(ep, 0); ++ del_timer(&dev->timer); ++ ep0_idle(dev); ++ } ++ ++ switch (dev->ep0state) { ++ case EP0_NO_ACTION: ++ printk(KERN_INFO"%s: Busy\n", __FUNCTION__); ++ /*Fall through */ ++ case EP0_IDLE: ++ /* late-breaking status? */ ++ udccsr0 = UDCCSR0; ++ ++ /* start control request? */ ++ if (likely((udccsr0 & (UDCCSR0_OPC|UDCCSR0_SA|UDCCSR0_RNE)) ++ == (UDCCSR0_OPC|UDCCSR0_SA|UDCCSR0_RNE))) { ++ int i; ++ ++ nuke (ep, -EPROTO); ++ /* read SETUP packet */ ++ for (i = 0; i < 2; i++) { ++ if (unlikely(!(UDCCSR0 & UDCCSR0_RNE))) { ++bad_setup: ++ DMSG("SETUP %d!\n", i); ++ goto stall; ++ } ++ u.word [i] = UDCDR0; ++ } ++ if (unlikely((UDCCSR0 & UDCCSR0_RNE) != 0)) ++ goto bad_setup; ++ ++ le16_to_cpus (&u.r.wValue); ++ le16_to_cpus (&u.r.wIndex); ++ le16_to_cpus (&u.r.wLength); ++ ++ LED_EP0_ON; ++ ++ DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n", ++ u.r.bRequestType, u.r.bRequest, ++ u.r.wValue, u.r.wIndex, u.r.wLength); ++ /* cope with automagic for some standard requests. */ ++ dev->req_std = (u.r.bRequestType & USB_TYPE_MASK) ++ == USB_TYPE_STANDARD; ++ dev->req_config = 0; ++ dev->req_pending = 1; ++#if 0 ++ switch (u.r.bRequest) { ++ /* hardware was supposed to hide this */ ++ case USB_REQ_SET_CONFIGURATION: ++ case USB_REQ_SET_INTERFACE: ++ case USB_REQ_SET_ADDRESS: ++ printk(KERN_ERR "Should not come here\n"); ++ break; ++ } ++ ++#endif ++ if (u.r.bRequestType & USB_DIR_IN) ++ dev->ep0state = EP0_IN_DATA_PHASE; ++ else ++ dev->ep0state = EP0_OUT_DATA_PHASE; ++ i = dev->driver->setup(&dev->gadget, &u.r); ++ ++ if (i < 0) { ++ /* hardware automagic preventing STALL... */ ++ if (dev->req_config) { ++ /* hardware sometimes neglects to tell ++ * tell us about config change events, ++ * so later ones may fail... ++ */ ++ WARN("config change %02x fail %d?\n", ++ u.r.bRequest, i); ++ return; ++ /* TODO experiment: if has_cfr, ++ * hardware didn't ACK; maybe we ++ * could actually STALL! ++ */ ++ } ++ DBG(DBG_VERBOSE, "protocol STALL, " ++ "%02x err %d\n", UDCCSR0, i); ++stall: ++ /* the watchdog timer helps deal with cases ++ * where udc seems to clear FST wrongly, and ++ * then NAKs instead of STALLing. ++ */ ++ ep0start(dev, UDCCSR0_FST|UDCCSR0_FTF, "stall"); ++ start_watchdog(dev); ++ dev->ep0state = EP0_STALL; ++ LED_EP0_OFF; ++ ++ /* deferred i/o == no response yet */ ++ } else if (dev->req_pending) { ++ if (likely(dev->ep0state == EP0_IN_DATA_PHASE ++ || dev->req_std || u.r.wLength)) ++ ep0start(dev, 0, "defer"); ++ else ++ ep0start(dev, UDCCSR0_IPR, "defer/IPR"); ++ } ++ ++ /* expect at least one data or status stage irq */ ++ return; ++ ++ } else { ++ /* some random early IRQ: ++ * - we acked FST ++ * - IPR cleared ++ * - OPC got set, without SA (likely status stage) ++ */ ++ UDCCSR0 = udccsr0 & (UDCCSR0_SA|UDCCSR0_OPC); ++ } ++ break; ++ case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ ++ if (udccsr0 & UDCCSR0_OPC) { ++ UDCCSR0 = UDCCSR0_OPC|UDCCSR0_FTF; ++ DBG(DBG_VERBOSE, "ep0in premature status\n"); ++ if (req) ++ done(ep, req, 0); ++ ep0_idle(dev); ++ } else /* irq was IPR clearing */ { ++ if (req) { ++ /* this IN packet might finish the request */ ++ (void) write_ep0_fifo(ep, req); ++ } /* else IN token before response was written */ ++ } ++ break; ++ case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ ++ if (udccsr0 & UDCCSR0_OPC) { ++ if (req) { ++ /* this OUT packet might finish the request */ ++ if (read_ep0_fifo(ep, req)) ++ done(ep, req, 0); ++ /* else more OUT packets expected */ ++ } /* else OUT token before read was issued */ ++ } else /* irq was IPR clearing */ { ++ DBG(DBG_VERBOSE, "ep0out premature status\n"); ++ if (req) ++ done(ep, req, 0); ++ ep0_idle(dev); ++ } ++ break; ++ case EP0_STALL: ++ UDCCSR0 = UDCCSR0_FST; ++ break; ++ } ++ UDCISR0 = UDCISR_INT(0, UDCISR_INT_MASK); ++} ++ ++ ++static void handle_ep(struct pxa27x_ep *ep) ++{ ++ struct pxa27x_request *req; ++ int completed; ++ u32 udccsr=0; ++ ++ DMSG("%s is called\n", __FUNCTION__); ++ do { ++ completed = 0; ++ if (likely (!list_empty(&ep->queue))) { ++ req = list_entry(ep->queue.next, ++ struct pxa27x_request, queue); ++ } else ++ req = 0; ++ ++// udccsr = *ep->reg_udccsr; ++ DMSG("%s: req:%p, udcisr0:0x%x udccsr %p:0x%x\n", __FUNCTION__, ++ req, UDCISR0, ep->reg_udccsr, *ep->reg_udccsr); ++ if (unlikely(ep->dir_in)) { ++ udccsr = (UDCCSR_SST | UDCCSR_TRN) & *ep->reg_udccsr; ++ if (unlikely (udccsr)) ++ *ep->reg_udccsr = udccsr; ++ ++ if (req && likely ((*ep->reg_udccsr & UDCCSR_FS) != 0)) ++ completed = write_fifo(ep, req); ++ ++ } else { ++ udccsr = (UDCCSR_SST | UDCCSR_TRN) & *ep->reg_udccsr; ++ if (unlikely(udccsr)) ++ *ep->reg_udccsr = udccsr; ++ ++ /* fifos can hold packets, ready for reading... */ ++ if (likely(req)) { ++ completed = read_fifo(ep, req); ++ } else { ++ pio_irq_disable (ep->ep_num); ++ *ep->reg_udccsr = UDCCSR_FEF; ++ DMSG("%s: no req for out data\n", ++ __FUNCTION__); ++ } ++ } ++ ep->pio_irqs++; ++ } while (completed); ++} ++ ++static void pxa27x_change_configuration (struct pxa27x_udc *dev) ++{ ++ struct usb_ctrlrequest req ; ++ ++ req.bRequestType = 0; ++ req.bRequest = USB_REQ_SET_CONFIGURATION; ++ req.wValue = dev->configuration; ++ req.wIndex = 0; ++ req.wLength = 0; ++ ++ dev->ep0state = EP0_NO_ACTION; ++ dev->driver->setup(&dev->gadget, &req); ++ ++} ++ ++static void pxa27x_change_interface (struct pxa27x_udc *dev) ++{ ++ struct usb_ctrlrequest req; ++ ++ req.bRequestType = USB_RECIP_INTERFACE; ++ req.bRequest = USB_REQ_SET_INTERFACE; ++ req.wValue = dev->alternate; ++ req.wIndex = dev->interface; ++ req.wLength = 0; ++ ++ dev->ep0state = EP0_NO_ACTION; ++ dev->driver->setup(&dev->gadget, &req); ++} ++ ++/* ++ * pxa27x_udc_irq - interrupt handler ++ * ++ * avoid delays in ep0 processing. the control handshaking isn't always ++ * under software control (pxa250c0 and the pxa255 are better), and delays ++ * could cause usb protocol errors. ++ */ ++static irqreturn_t ++pxa27x_udc_irq(int irq, void *_dev, struct pt_regs *r) ++{ ++ struct pxa27x_udc *dev = _dev; ++ int handled; ++ ++ dev->stats.irqs++; ++ HEX_DISPLAY(dev->stats.irqs); ++ ++// printk("\n"); ++ DBG(DBG_VERBOSE, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, " ++ "UDCCR:0x%08x\n", UDCISR0, UDCISR1, UDCCR); ++ do { ++ u32 udcir = UDCISR1 & 0xF8000000; ++ ++ handled = 0; ++ ++ /* SUSpend Interrupt Request */ ++ if (unlikely(udcir & UDCISR1_IESU)) { ++ UDCISR1 = UDCISR1_IESU; ++ handled = 1; ++ DBG(DBG_VERBOSE, "USB suspend\n"); ++ if (dev->gadget.speed != USB_SPEED_UNKNOWN ++ && dev->driver ++ && dev->driver->suspend) ++ dev->driver->suspend(&dev->gadget); ++ ep0_idle (dev); ++ } ++ ++ /* RESume Interrupt Request */ ++ if (unlikely(udcir & UDCISR1_IERU)) { ++ UDCISR1 = UDCISR1_IERU; ++ handled = 1; ++ DBG(DBG_VERBOSE, "USB resume\n"); ++ ++ if (dev->gadget.speed != USB_SPEED_UNKNOWN ++ && dev->driver ++ && dev->driver->resume) ++ dev->driver->resume(&dev->gadget); ++ } ++ ++ if (unlikely(udcir & UDCISR1_IECC)) { ++ unsigned config, interface, alternate; ++ ++ handled = 1; ++ DBG(DBG_VERBOSE, "USB SET_CONFIGURATION or " ++ "SET_INTERFACE command received\n"); ++ ++ UDCCR |= UDCCR_SMAC; ++ ++ config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S; ++ ++ if (dev->configuration != config) { ++ dev->configuration = config; ++ pxa27x_change_configuration(dev) ; ++ } ++ ++ interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S; ++ alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S; ++ ++ if ( (dev->configuration != interface) || \ ++ (dev->alternate != alternate)){ ++ dev->interface = config; ++ dev->alternate = alternate; ++ pxa27x_change_interface(dev); ++ } ++ ++ UDCISR1 = UDCISR1_IECC; ++ DMSG("%s: con:%d,inter:%d,alt:%d\n", ++ __FUNCTION__, config,interface, alternate); ++ } ++ ++ /* ReSeT Interrupt Request - USB reset */ ++ if (unlikely(udcir & UDCISR1_IERS)) { ++ UDCISR1 = UDCISR1_IERS; ++ handled = 1; ++ ++ if ((UDCCR & UDCCR_UDA) == 0) { ++ DBG(DBG_VERBOSE, "USB reset start\n"); ++ ++ /* reset driver and endpoints, ++ * in case that's not yet done ++ */ ++ stop_activity (dev, dev->driver); ++ ++ } ++ INFO("USB reset\n"); ++ dev->gadget.speed = USB_SPEED_FULL; ++ memset(&dev->stats, 0, sizeof dev->stats); ++ ++ } else { ++ u32 udcisr0 = UDCISR0 ; ++ u32 udcisr1 = UDCISR1 & 0xFFFF; ++ int i; ++ ++ if (unlikely (!udcisr0 && !udcisr1)) ++ continue; ++ ++ DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", udcisr1,udcisr0); ++ ++ /* control traffic */ ++ if (udcisr0 & UDCISR0_IR0) { ++ dev->ep[0].pio_irqs++; ++ handle_ep0(dev); ++ handled = 1; ++ } ++ ++ udcisr0 >>= 2; ++ /* endpoint data transfers */ ++ for (i = 1; udcisr0!=0 && i < 16; udcisr0>>=2,i++) { ++ UDCISR0 = UDCISR_INT(i, UDCISR_INT_MASK); ++ ++ if (udcisr0 & UDC_INT_FIFOERROR) ++ printk(KERN_ERR" Endpoint %d Fifo error\n", i); ++ if (udcisr0 & UDC_INT_PACKETCMP) { ++ handle_ep(&dev->ep[i]); ++ handled = 1; ++ } ++ ++ } ++ ++ for (i = 0; udcisr1!=0 && i < 8; udcisr1 >>= 2, i++) { ++ UDCISR1 = UDCISR_INT(i, UDCISR_INT_MASK); ++ ++ if (udcisr1 & UDC_INT_FIFOERROR) { ++ printk(KERN_ERR" Endpoint %d fifo error\n", (i+16)); ++ } ++ ++ if (udcisr1 & UDC_INT_PACKETCMP) { ++ handle_ep(&dev->ep[i+16]); ++ handled = 1; ++ } ++ } ++ } ++ ++ /* we could also ask for 1 msec SOF (SIR) interrupts */ ++ ++ } while (handled); ++ return IRQ_HANDLED; ++} ++ ++static inline void validate_fifo_size(struct pxa27x_ep *pxa_ep, u8 bmAttributes) ++{ ++ switch (bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_CONTROL: ++ pxa_ep->fifo_size = EP0_FIFO_SIZE; ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ pxa_ep->fifo_size = ISO_FIFO_SIZE; ++ break; ++ case USB_ENDPOINT_XFER_BULK: ++ pxa_ep->fifo_size = BULK_FIFO_SIZE; ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ pxa_ep->fifo_size = INT_FIFO_SIZE; ++ break; ++ default: ++ break; ++ } ++} ++ ++static void udc_init_ep(struct pxa27x_udc *dev) ++{ ++ int i; ++ ++ INIT_LIST_HEAD (&dev->gadget.ep_list); ++ INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); ++ ++ for (i = 0; i < UDC_EP_NUM; i++) { ++ struct pxa27x_ep *ep = &dev->ep[i]; ++ ++ ep->dma = -1; ++ if (i != 0) { ++ memset(ep, 0, sizeof(*ep)); ++ } ++ INIT_LIST_HEAD (&ep->queue); ++ } ++} ++#define NAME_SIZE 18 ++ ++struct usb_ep* pxa27x_ep_config( ++ struct usb_gadget *gadget, ++ struct usb_endpoint_descriptor *desc, ++ int config, int interface, int alt ++) ++{ ++ u32 tmp ; ++ unsigned i; ++ char* name; ++ struct usb_ep * ep = NULL; ++ struct pxa27x_ep *pxa_ep = NULL; ++ struct pxa27x_udc *dev = the_controller; ++ ++ DMSG("pxa27x_config_ep is called\n"); ++ DMSG(" usb endpoint descriptor is:\n" ++ " bLength:%d\n" ++ " bDescriptorType:%x\n" ++ " bEndpointAddress:%x\n" ++ " bmAttributes:%x\n" ++ " wMaxPacketSize:%d\n", ++ desc->bLength, ++ desc->bDescriptorType,desc->bEndpointAddress, ++ desc->bmAttributes,desc->wMaxPacketSize); ++ ++ for (i = 1; i < UDC_EP_NUM; i++) { ++ if(!dev->ep[i].assigned) { ++ pxa_ep = &dev->ep[i]; ++ pxa_ep->assigned = 1; ++ pxa_ep->ep_num = i; ++ break; ++ } ++ } ++ if (unlikely(i == UDC_EP_NUM)) { ++ printk(KERN_ERR __FILE__ ": Failed to find a spare endpoint\n"); ++ return ep; ++ } ++ ++ ++ ep = &pxa_ep->ep; ++ ++ pxa_ep->dev = dev; ++ pxa_ep->desc = desc; ++ pxa_ep->pio_irqs = pxa_ep->dma_irqs = 0; ++ pxa_ep->dma = -1; ++ ++ if (!(desc->bEndpointAddress & 0xF)) ++ desc->bEndpointAddress |= i; ++ ++ if (!(desc->wMaxPacketSize)) { ++ validate_fifo_size(pxa_ep, desc->bmAttributes); ++ desc->wMaxPacketSize = pxa_ep->fifo_size; ++ } else ++ pxa_ep->fifo_size = desc->wMaxPacketSize; ++ ++ pxa_ep->dir_in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0; ++ pxa_ep->ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; ++ pxa_ep->stopped = 1; ++ pxa_ep->dma_con = 0; ++ pxa_ep->config = config; ++ pxa_ep->interface = interface; ++ pxa_ep->aisn = alt; ++ ++ pxa_ep->reg_udccsr = &UDCCSR0 + i; ++ pxa_ep->reg_udcbcr = &UDCBCR0 + i; ++ pxa_ep->reg_udcdr = &UDCDR0 + i ; ++ pxa_ep->reg_udccr = &UDCCRA - 1 + i; ++#ifdef USE_DMA ++ pxa_ep->reg_drcmr = &DRCMR24 + i; ++#endif ++ ++#if 0 ++ DMSG("udccsr=0x%8x, udcbcr=0x%8x, udcdr=0x%8x," ++ "udccr0=0x%8x\n", ++ (unsigned)pxa_ep->reg_udccsr, ++ (unsigned)pxa_ep->reg_udcbcr, ++ (unsigned)pxa_ep->reg_udcdr, ++ (unsigned)pxa_ep->reg_udccr); ++#endif ++ /* Configure UDCCR */ ++ tmp = 0; ++ tmp |= (pxa_ep->config << UDCCONR_CN_S) & UDCCONR_CN; ++ tmp |= (pxa_ep->interface << UDCCONR_IN_S) & UDCCONR_IN; ++ tmp |= (pxa_ep->aisn << UDCCONR_AISN_S) & UDCCONR_AISN; ++ tmp |= (desc->bEndpointAddress << UDCCONR_EN_S) & UDCCONR_EN; ++ tmp |= (pxa_ep->ep_type << UDCCONR_ET_S) & UDCCONR_ET; ++ tmp |= (pxa_ep->dir_in) ? UDCCONR_ED : 0; ++ tmp |= (min(pxa_ep->fifo_size, (unsigned)desc->wMaxPacketSize) \ ++ << UDCCONR_MPS_S ) & UDCCONR_MPS; ++ tmp |= UDCCONR_DE | UDCCONR_EE; ++// tmp |= UDCCONR_EE; ++ ++ *pxa_ep->reg_udccr = tmp; ++ ++#ifdef USE_DMA ++ /* Only BULK use DMA */ ++ if ((pxa_ep->ep_type & USB_ENDPOINT_XFERTYPE_MASK)\ ++ == USB_ENDPOINT_XFER_BULK) ++ *pxa_ep->reg_udccsr = UDCCSR_DME; ++#endif ++ ++ DMSG("UDCCR: 0x%p is 0x%x\n", pxa_ep->reg_udccr,*pxa_ep->reg_udccr); ++ ++ /* Fill ep name*/ ++ name = kmalloc(NAME_SIZE, GFP_KERNEL); ++ if (!name) { ++ printk(KERN_ERR "%s: Error\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ switch (pxa_ep->ep_type) { ++ case USB_ENDPOINT_XFER_BULK: ++ sprintf(name, "Bulk-%s-%d", (pxa_ep->dir_in ? "in":"out"), i); ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ sprintf(name, "Interrupt-%s-%d", (pxa_ep->dir_in ? \ ++ "in":"out"), i); ++ break; ++ default: ++ sprintf(name, "endpoint-%s-%d", (pxa_ep->dir_in ? \ ++ "in":"out"), i); ++ break; ++ } ++ ep->name = name; ++ ++ ep->ops = &pxa27x_ep_ops; ++ ep->maxpacket = min((ushort)pxa_ep->fifo_size, desc->wMaxPacketSize); ++ ++ list_add_tail (&ep->ep_list, &gadget->ep_list); ++ return ep; ++} ++ ++EXPORT_SYMBOL(pxa27x_ep_config); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void nop_release (struct device *dev) ++{ ++ DMSG("%s %s\n", __FUNCTION__, dev->bus_id); ++} ++ ++/* this uses load-time allocation and initialization (instead of ++ * doing it at run-time) to save code, eliminate fault paths, and ++ * be more obviously correct. ++ */ ++static struct pxa27x_udc memory = { ++ .gadget = { ++ .ops = &pxa27x_udc_ops, ++ .ep0 = &memory.ep[0].ep, ++ .name = driver_name, ++ .dev = { ++ .bus_id = "gadget", ++ .release = nop_release, ++ }, ++ }, ++ ++ /* control endpoint */ ++ .ep[0] = { ++ .ep = { ++ .name = ep0name, ++ .ops = &pxa27x_ep_ops, ++ .maxpacket = EP0_FIFO_SIZE, ++ }, ++ .dev = &memory, ++ .reg_udccsr = &UDCCSR0, ++ .reg_udcdr = &UDCDR0, ++ } ++}; ++ ++#define CP15R0_VENDOR_MASK 0xffffe000 ++ ++#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/xscale */ ++ ++/* ++ * probe - binds to the platform device ++ */ ++static int __init pxa27x_udc_probe(struct device *_dev) ++{ ++ struct pxa27x_udc *dev = &memory; ++ int retval; ++ u32 chiprev; ++ ++ /* insist on Intel/ARM/XScale */ ++ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); ++ if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { ++ printk(KERN_ERR "%s: not XScale!\n", driver_name); ++ return -ENODEV; ++ } ++ /* other non-static parts of init */ ++ dev->dev = _dev; ++ dev->mach = _dev->platform_data; ++ ++ init_timer(&dev->timer); ++ dev->timer.function = udc_watchdog; ++ dev->timer.data = (unsigned long) dev; ++ ++ device_initialize(&dev->gadget.dev); ++ dev->gadget.dev.parent = _dev; ++ dev->gadget.dev.dma_mask = _dev->dma_mask; ++ ++ the_controller = dev; ++ dev_set_drvdata(_dev, dev); ++ ++ udc_disable(dev); ++ udc_init_ep(dev); ++ udc_reinit(dev); ++ ++ /* irq setup after old hardware state is cleaned up */ ++ retval = request_irq(IRQ_USB, pxa27x_udc_irq, ++ SA_INTERRUPT, driver_name, dev); ++ if (retval != 0) { ++ printk(KERN_ERR "%s: can't get irq %i, err %d\n", ++ driver_name, IRQ_USB, retval); ++ return -EBUSY; ++ } ++ dev->got_irq = 1; ++ ++ create_proc_files(); ++ ++ return 0; ++} ++ ++static int __exit pxa27x_udc_remove(struct device *_dev) ++{ ++ struct pxa27x_udc *dev = _dev->driver_data; ++ ++ udc_disable(dev); ++ remove_proc_files(); ++ usb_gadget_unregister_driver(dev->driver); ++ ++ if (dev->got_irq) { ++ free_irq(IRQ_USB, dev); ++ dev->got_irq = 0; ++ } ++ if (machine_is_lubbock() && dev->got_disc) { ++ free_irq(LUBBOCK_USB_DISC_IRQ, dev); ++ dev->got_disc = 0; ++ } ++ dev_set_drvdata(_dev, 0); ++ the_controller = 0; ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static void pxa27x_udc_shutdown(struct device *_dev) ++{ ++ struct pxa27x_udc *dev = (struct pxa27x_udc*)dev_get_drvdata(_dev); ++ ++ udc_disable(dev); ++} ++ ++static int pxa27x_udc_suspend(struct device *_dev, pm_message_t state) ++{ ++ int i; ++ struct pxa27x_udc *dev = (struct pxa27x_udc*)dev_get_drvdata(_dev); ++ ++ DMSG("%s is called\n", __FUNCTION__); ++ dev->udccsr0 = UDCCSR0; ++ for(i=1; (i<UDC_EP_NUM); i++) { ++ if (dev->ep[i].assigned) { ++ struct pxa27x_ep *ep = &dev->ep[i]; ++ ++ ep->udccsr_value = *ep->reg_udccsr; ++ ep->udccr_value = *ep->reg_udccr; ++ DMSG("EP%d, udccsr:0x%x, udccr:0x%x\n", ++ i, *ep->reg_udccsr, *ep->reg_udccr); ++ } ++ } ++ ++ udc_clear_mask_UDCCR(UDCCR_UDE); ++ pxa_set_cken(CKEN11_USB, 0); ++ // MST_MSCWR2 |= MST_MSCWR2_nUSBC_SC; ++ ++ return 0; ++} ++ ++static int pxa27x_udc_resume(struct device *_dev) ++{ ++ int i; ++ struct pxa27x_udc *dev = (struct pxa27x_udc*)dev_get_drvdata(_dev); ++ ++ DMSG("%s is called\n", __FUNCTION__); ++ ++ UDCCSR0 = dev->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME); ++ for (i=1; i < UDC_EP_NUM; i++) { ++ if (dev->ep[i].assigned) { ++ struct pxa27x_ep *ep = &dev->ep[i]; ++ ++ *ep->reg_udccsr = ep->udccsr_value; ++ *ep->reg_udccr = ep->udccr_value; ++ DMSG("EP%d, udccsr:0x%x, udccr:0x%x\n", ++ i, *ep->reg_udccsr, *ep->reg_udccr); ++ } ++ } ++ udc_enable(dev); ++ /* OTGPH bit is set when sleep mode is entered. ++ * it indicates that OTG pad is retaining its state. ++ * Upon exit from sleep mode and before clearing OTGPH, ++ * Software must configure the USB OTG pad, UDC, and UHC ++ * to the state they were in before entering sleep mode.*/ ++ PSSR |= PSSR_OTGPH; ++ return 0; ++} ++#endif ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct device_driver udc_driver = { ++ .name = "pxa2xx-udc", ++ .bus = &platform_bus_type, ++ .probe = pxa27x_udc_probe, ++ .remove = __exit_p(pxa27x_udc_remove), ++ ++#ifdef CONFIG_PM ++ // FIXME power management support ++ .shutdown = pxa27x_udc_shutdown, ++ .suspend = pxa27x_udc_suspend, ++ .resume = pxa27x_udc_resume ++#endif ++}; ++ ++static int __init udc_init(void) ++{ ++ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); ++ return driver_register(&udc_driver); ++} ++module_init(udc_init); ++ ++static void __exit udc_exit(void) ++{ ++ driver_unregister(&udc_driver); ++} ++module_exit(udc_exit); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); ++MODULE_LICENSE("GPL"); ++ +diff -Nurd linux-2.6.16.orig/drivers/usb/gadget/pxa27x_udc.h linux-2.6.16/drivers/usb/gadget/pxa27x_udc.h +--- linux-2.6.16.orig/drivers/usb/gadget/pxa27x_udc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/drivers/usb/gadget/pxa27x_udc.h 2006-06-03 11:14:55.950383504 +0200 +@@ -0,0 +1,332 @@ ++/* ++ * linux/drivers/usb/gadget/pxa27x_udc.h ++ * Intel PXA27x on-chip full speed USB device controller ++ * ++ * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * Copyright (C) 2003 David Brownell ++ * Copyright (C) 2004 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef __LINUX_USB_GADGET_PXA27X_H ++#define __LINUX_USB_GADGET_PXA27X_H ++ ++#include <linux/types.h> ++ ++struct pxa27x_udc; ++ ++struct pxa27x_ep { ++ struct usb_ep ep; ++ struct pxa27x_udc *dev; ++ ++ const struct usb_endpoint_descriptor *desc; ++ struct list_head queue; ++ unsigned long pio_irqs; ++ unsigned long dma_irqs; ++ ++ int dma; ++ unsigned fifo_size; ++ unsigned ep_num; ++ unsigned ep_type; ++ ++ unsigned stopped : 1; ++ unsigned dma_con : 1; ++ unsigned dir_in : 1; ++ unsigned assigned : 1; ++ ++ unsigned config; ++ unsigned interface; ++ unsigned aisn; ++ /* UDCCSR = UDC Control/Status Register for this EP ++ * UBCR = UDC Byte Count Remaining (contents of OUT fifo) ++ * UDCDR = UDC Endpoint Data Register (the fifo) ++ * UDCCR = UDC Endpoint Configuration Registers ++ * DRCM = DMA Request Channel Map ++ */ ++ volatile u32 *reg_udccsr; ++ volatile u32 *reg_udcbcr; ++ volatile u32 *reg_udcdr; ++ volatile u32 *reg_udccr; ++#ifdef USE_DMA ++ volatile u32 *reg_drcmr; ++#define drcmr(n) .reg_drcmr = & DRCMR ## n , ++#else ++#define drcmr(n) ++#endif ++ ++#ifdef CONFIG_PM ++ unsigned udccsr_value; ++ unsigned udccr_value; ++#endif ++}; ++ ++struct pxa27x_request { ++ struct usb_request req; ++ struct list_head queue; ++}; ++ ++enum ep0_state { ++ EP0_IDLE, ++ EP0_IN_DATA_PHASE, ++ EP0_OUT_DATA_PHASE, ++// EP0_END_XFER, ++ EP0_STALL, ++ EP0_NO_ACTION ++}; ++ ++#define EP0_FIFO_SIZE ((unsigned)16) ++#define BULK_FIFO_SIZE ((unsigned)64) ++#define ISO_FIFO_SIZE ((unsigned)256) ++#define INT_FIFO_SIZE ((unsigned)8) ++ ++struct udc_stats { ++ struct ep0stats { ++ unsigned long ops; ++ unsigned long bytes; ++ } read, write; ++ unsigned long irqs; ++}; ++ ++#ifdef CONFIG_USB_PXA27X_SMALL ++/* when memory's tight, SMALL config saves code+data. */ ++//#undef USE_DMA ++//#define UDC_EP_NUM 3 ++#endif ++ ++#ifndef UDC_EP_NUM ++#define UDC_EP_NUM 24 ++#endif ++ ++struct pxa27x_udc { ++ struct usb_gadget gadget; ++ struct usb_gadget_driver *driver; ++ ++ enum ep0_state ep0state; ++ struct udc_stats stats; ++ unsigned got_irq : 1, ++ got_disc : 1, ++ has_cfr : 1, ++ req_pending : 1, ++ req_std : 1, ++ req_config : 1; ++ ++#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200)) ++ struct timer_list timer; ++ ++ struct device *dev; ++ struct pxa2xx_udc_mach_info *mach; ++ u64 dma_mask; ++ struct pxa27x_ep ep [UDC_EP_NUM]; ++ ++ unsigned configuration, ++ interface, ++ alternate; ++#ifdef CONFIG_PM ++ unsigned udccsr0; ++#endif ++}; ++ ++/*-------------------------------------------------------------------------*/ ++#if 0 ++#ifdef DEBUG ++#define HEX_DISPLAY(n) do { \ ++ if (machine_is_mainstone())\ ++ { MST_LEDDAT1 = (n); } \ ++ } while(0) ++ ++#define HEX_DISPLAY1(n) HEX_DISPLAY(n) ++ ++#define HEX_DISPLAY2(n) do { \ ++ if (machine_is_mainstone()) \ ++ { MST_LEDDAT2 = (n); } \ ++ } while(0) ++ ++#endif /* DEBUG */ ++#endif ++/*-------------------------------------------------------------------------*/ ++ ++/* LEDs are only for debug */ ++#ifndef HEX_DISPLAY ++#define HEX_DISPLAY(n) do {} while(0) ++#endif ++ ++#ifndef LED_CONNECTED_ON ++#define LED_CONNECTED_ON do {} while(0) ++#define LED_CONNECTED_OFF do {} while(0) ++#endif ++#ifndef LED_EP0_ON ++#define LED_EP0_ON do {} while (0) ++#define LED_EP0_OFF do {} while (0) ++#endif ++ ++static struct pxa27x_udc *the_controller; ++ ++#if 0 ++/*-------------------------------------------------------------------------*/ ++ ++ ++/* one GPIO should be used to detect host disconnect */ ++static inline int is_usb_connected(void) ++{ ++ if (!the_controller->mach->udc_is_connected) ++ return 1; ++ return the_controller->mach->udc_is_connected(); ++} ++ ++/* one GPIO should force the host to see this device (or not) */ ++static inline void make_usb_disappear(void) ++{ ++ if (!the_controller->mach->udc_command) ++ return; ++ the_controller->mach->udc_command(PXA27X_UDC_CMD_DISCONNECT); ++} ++ ++static inline void let_usb_appear(void) ++{ ++ if (!the_controller->mach->udc_command) ++ return; ++ the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); ++} ++#endif ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * Debugging support vanishes in non-debug builds. DBG_NORMAL should be ++ * mostly silent during normal use/testing, with no timing side-effects. ++ */ ++#define DBG_NORMAL 1 /* error paths, device state transitions */ ++#define DBG_VERBOSE 2 /* add some success path trace info */ ++#define DBG_NOISY 3 /* ... even more: request level */ ++#define DBG_VERY_NOISY 4 /* ... even more: packet level */ ++ ++#ifdef DEBUG ++ ++static const char *state_name[] = { ++ "EP0_IDLE", ++ "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", ++ "EP0_END_XFER", "EP0_STALL" ++}; ++ ++#define DMSG(stuff...) printk(KERN_ERR "udc: " stuff) ++ ++#ifdef VERBOSE ++# define UDC_DEBUG DBG_VERBOSE ++#else ++# define UDC_DEBUG DBG_NORMAL ++#endif ++ ++static void __attribute__ ((__unused__)) ++dump_udccr(const char *label) ++{ ++ u32 udccr = UDCCR; ++ DMSG("%s 0x%08x =%s%s%s%s%s%s%s%s%s%s, con=%d,inter=%d,altinter=%d\n", ++ label, udccr, ++ (udccr & UDCCR_OEN) ? " oen":"", ++ (udccr & UDCCR_AALTHNP) ? " aalthnp":"", ++ (udccr & UDCCR_AHNP) ? " rem" : "", ++ (udccr & UDCCR_BHNP) ? " rstir" : "", ++ (udccr & UDCCR_DWRE) ? " dwre" : "", ++ (udccr & UDCCR_SMAC) ? " smac" : "", ++ (udccr & UDCCR_EMCE) ? " emce" : "", ++ (udccr & UDCCR_UDR) ? " udr" : "", ++ (udccr & UDCCR_UDA) ? " uda" : "", ++ (udccr & UDCCR_UDE) ? " ude" : "", ++ (udccr & UDCCR_ACN) >> UDCCR_ACN_S, ++ (udccr & UDCCR_AIN) >> UDCCR_AIN_S, ++ (udccr & UDCCR_AAISN)>> UDCCR_AAISN_S ); ++} ++ ++static void __attribute__ ((__unused__)) ++dump_udccsr0(const char *label) ++{ ++ u32 udccsr0 = UDCCSR0; ++ ++ DMSG("%s %s 0x%08x =%s%s%s%s%s%s%s\n", ++ label, state_name[the_controller->ep0state], udccsr0, ++ (udccsr0 & UDCCSR0_SA) ? " sa" : "", ++ (udccsr0 & UDCCSR0_RNE) ? " rne" : "", ++ (udccsr0 & UDCCSR0_FST) ? " fst" : "", ++ (udccsr0 & UDCCSR0_SST) ? " sst" : "", ++ (udccsr0 & UDCCSR0_DME) ? " dme" : "", ++ (udccsr0 & UDCCSR0_IPR) ? " ipr" : "", ++ (udccsr0 & UDCCSR0_OPC) ? " opr" : ""); ++} ++ ++static void __attribute__ ((__unused__)) ++dump_state(struct pxa27x_udc *dev) ++{ ++ unsigned i; ++ ++ DMSG("%s, udcicr %02X.%02X, udcsir %02X.%02x, udcfnr %02X\n", ++ state_name[dev->ep0state], ++ UDCICR1, UDCICR0, UDCISR1, UDCISR0, UDCFNR); ++ dump_udccr("udccr"); ++ ++ if (!dev->driver) { ++ DMSG("no gadget driver bound\n"); ++ return; ++ } else ++ DMSG("ep0 driver '%s'\n", dev->driver->driver.name); ++ ++ ++ dump_udccsr0 ("udccsr0"); ++ DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n", ++ dev->stats.write.bytes, dev->stats.write.ops, ++ dev->stats.read.bytes, dev->stats.read.ops); ++ ++ for (i = 1; i < UDC_EP_NUM; i++) { ++ if (dev->ep [i].desc == 0) ++ continue; ++ DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccsr); ++ } ++} ++ ++#if 0 ++static void dump_regs(u8 ep) ++{ ++ DMSG("EP:%d UDCCSR:0x%08x UDCBCR:0x%08x\n UDCCR:0x%08x\n", ++ ep,UDCCSN(ep), UDCBCN(ep), UDCCN(ep)); ++} ++static void dump_req (struct pxa27x_request *req) ++{ ++ struct usb_request *r = &req->req; ++ ++ DMSG("%s: buf:0x%08x length:%d dma:0x%08x actual:%d\n", ++ __FUNCTION__, (unsigned)r->buf, r->length, ++ r->dma, r->actual); ++} ++#endif ++ ++#else ++ ++#define DMSG(stuff...) do{}while(0) ++ ++#define dump_udccr(x) do{}while(0) ++#define dump_udccsr0(x) do{}while(0) ++#define dump_state(x) do{}while(0) ++ ++#define UDC_DEBUG ((unsigned)0) ++ ++#endif ++ ++#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0) ++ ++#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) ++#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) ++ ++ ++#endif /* __LINUX_USB_GADGET_PXA27X_H */ +diff -Nurd linux-2.6.16.orig/drivers/usb/gadget/serial.c linux-2.6.16/drivers/usb/gadget/serial.c +--- linux-2.6.16.orig/drivers/usb/gadget/serial.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/gadget/serial.c 2006-06-03 11:14:55.965381224 +0200 +@@ -1439,22 +1439,40 @@ + __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); + } + +- usb_ep_autoconfig_reset(gadget); + ++ usb_ep_autoconfig_reset(gadget); ++#ifdef CONFIG_USB_GADGET_PXA27X ++ ep = pxa27x_ep_config(gadget, &gs_fullspeed_in_desc, ++ 1, gs_bulk_interface_desc.bInterfaceNumber, ++ gs_bulk_interface_desc.bAlternateSetting); ++#else + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); ++#endif + if (!ep) + goto autoconf_fail; + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + ++#ifdef CONFIG_USB_GADGET_PXA27X ++ ep = pxa27x_ep_config(gadget, &gs_fullspeed_out_desc, ++ 1, gs_bulk_interface_desc.bInterfaceNumber, ++ gs_bulk_interface_desc.bAlternateSetting); ++#else + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); ++#endif + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + if (use_acm) { ++#ifdef CONFIG_USB_GADGET_PXA27X ++ ep = pxa27x_ep_config(gadget, &gs_fullspeed_notify_desc, ++ 1, gs_control_interface_desc.bInterfaceNumber, ++ gs_control_interface_desc.bAlternateSetting); ++#else + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); ++#endif + if (!ep) { + printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name); + goto autoconf_fail; +diff -Nurd linux-2.6.16.orig/drivers/usb/host/ehci-sched.c linux-2.6.16/drivers/usb/host/ehci-sched.c +--- linux-2.6.16.orig/drivers/usb/host/ehci-sched.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/host/ehci-sched.c 2006-06-03 11:14:55.313480328 +0200 +@@ -707,6 +707,7 @@ + } else { + u32 addr; + int think_time; ++ int hs_transfers; + + addr = dev->ttport << 24; + if (!ehci_is_TDI(ehci) +@@ -719,6 +720,7 @@ + think_time = dev->tt ? dev->tt->think_time : 0; + stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( + dev->speed, is_input, 1, maxp)); ++ hs_transfers = max (1u, (maxp + 187) / 188); + if (is_input) { + u32 tmp; + +@@ -727,12 +729,11 @@ + stream->usecs = HS_USECS_ISO (1); + stream->raw_mask = 1; + +- /* pessimistic c-mask */ +- tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp) +- / (125 * 1000); +- stream->raw_mask |= 3 << (tmp + 9); ++ /* c-mask as specified in USB 2.0 11.18.4 3.c */ ++ tmp = (1 << (hs_transfers + 2)) - 1; ++ stream->raw_mask |= tmp << (8 + 2); + } else +- stream->raw_mask = smask_out [maxp / 188]; ++ stream->raw_mask = smask_out [hs_transfers - 1]; + bandwidth = stream->usecs + stream->c_usecs; + bandwidth /= 1 << (interval + 2); + +diff -Nurd linux-2.6.16.orig/drivers/usb/serial/console.c linux-2.6.16/drivers/usb/serial/console.c +--- linux-2.6.16.orig/drivers/usb/serial/console.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/serial/console.c 2006-06-03 11:14:55.314480176 +0200 +@@ -54,7 +54,7 @@ + * serial.c code, except that the specifier is "ttyUSB" instead + * of "ttyS". + */ +-static int __init usb_console_setup(struct console *co, char *options) ++static int usb_console_setup(struct console *co, char *options) + { + struct usbcons_info *info = &usbcons_info; + int baud = 9600; +diff -Nurd linux-2.6.16.orig/drivers/usb/serial/option.c linux-2.6.16/drivers/usb/serial/option.c +--- linux-2.6.16.orig/drivers/usb/serial/option.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/serial/option.c 2006-06-03 11:14:55.314480176 +0200 +@@ -582,14 +582,14 @@ + portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ +- for (j = 0; j <= N_IN_URB; ++j) { ++ for (j = 0; j < N_IN_URB; ++j) { + portdata->in_urbs[j] = option_setup_urb (serial, + port->bulk_in_endpointAddress, USB_DIR_IN, port, + portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); + } + + /* outdat endpoints */ +- for (j = 0; j <= N_OUT_URB; ++j) { ++ for (j = 0; j < N_OUT_URB; ++j) { + portdata->out_urbs[j] = option_setup_urb (serial, + port->bulk_out_endpointAddress, USB_DIR_OUT, port, + portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); +diff -Nurd linux-2.6.16.orig/drivers/usb/storage/Kconfig linux-2.6.16/drivers/usb/storage/Kconfig +--- linux-2.6.16.orig/drivers/usb/storage/Kconfig 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/usb/storage/Kconfig 2006-06-03 11:14:55.315480024 +0200 +@@ -48,7 +48,8 @@ + + config USB_STORAGE_ISD200 + bool "ISD-200 USB/ATA Bridge support" +- depends on USB_STORAGE && BLK_DEV_IDE ++ depends on USB_STORAGE ++ depends on BLK_DEV_IDE=y || BLK_DEV_IDE=USB_STORAGE + ---help--- + Say Y here if you want to use USB Mass Store devices based + on the In-Systems Design ISD-200 USB/ATA bridge. +diff -Nurd linux-2.6.16.orig/drivers/video/cfbimgblt.c linux-2.6.16/drivers/video/cfbimgblt.c +--- linux-2.6.16.orig/drivers/video/cfbimgblt.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/video/cfbimgblt.c 2006-06-03 11:14:55.315480024 +0200 +@@ -169,7 +169,7 @@ + + while (j--) { + l--; +- color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor; ++ color = (*s & (1 << l)) ? fgcolor : bgcolor; + val |= FB_SHIFT_HIGH(color, shift); + + /* Did the bitshift spill bits to the next long? */ +diff -Nurd linux-2.6.16.orig/drivers/video/fbmem.c linux-2.6.16/drivers/video/fbmem.c +--- linux-2.6.16.orig/drivers/video/fbmem.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/video/fbmem.c 2006-06-03 11:14:55.316479872 +0200 +@@ -669,13 +669,19 @@ + total_size = info->fix.smem_len; + + if (p > total_size) +- return 0; ++ return -EFBIG; + +- if (count >= total_size) ++ if (count > total_size) { ++ err = -EFBIG; + count = total_size; ++ } ++ ++ if (count + p > total_size) { ++ if (!err) ++ err = -ENOSPC; + +- if (count + p > total_size) + count = total_size - p; ++ } + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); +@@ -717,7 +723,7 @@ + + kfree(buffer); + +- return (err) ? err : cnt; ++ return (cnt) ? cnt : err; + } + + #ifdef CONFIG_KMOD +diff -Nurd linux-2.6.16.orig/drivers/video/i810/i810_main.c linux-2.6.16/drivers/video/i810/i810_main.c +--- linux-2.6.16.orig/drivers/video/i810/i810_main.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/video/i810/i810_main.c 2006-06-03 11:14:55.318479568 +0200 +@@ -1508,7 +1508,7 @@ + int size = ((cursor->image.width + 7) >> 3) * + cursor->image.height; + int i; +- u8 *data = kmalloc(64 * 8, GFP_KERNEL); ++ u8 *data = kmalloc(64 * 8, GFP_ATOMIC); + + if (data == NULL) + return -ENOMEM; +diff -Nurd linux-2.6.16.orig/drivers/video/pxafb.c linux-2.6.16/drivers/video/pxafb.c +--- linux-2.6.16.orig/drivers/video/pxafb.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/video/pxafb.c 2006-06-03 11:14:55.931386392 +0200 +@@ -1000,6 +1000,39 @@ + #define pxafb_resume NULL + #endif + ++#ifdef CONFIG_DPM ++#include <linux/dpm.h> ++ ++#define WAIT_FOR_LCD_INTR(reg,intr,timeout) ({ \ ++ int __done =0; \ ++ int __t = timeout; \ ++ while (__t) { \ ++ __done = (reg) & (intr); \ ++ if (__done) break; \ ++ udelay(50); \ ++ __t--; \ ++ } \ ++ __done; \ ++}) ++ ++static int pxafb_scale(struct notifier_block *nb, unsigned long val, void *data) ++{ ++#if 0 // Without disable.enable overlays, doesn't work well yet ++ struct pxafb_info *fbi = TO_INF(nb, scale); ++ u_int pcd; ++ ++ LCSR = 0xffffffff; /* Clear LCD Status Register */ ++ LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ ++ LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ ++ WAIT_FOR_LCD_INTR(LCSR,LCSR_LDD,20); ++ pcd = get_pcd(fbi->fb.var.pixclock); ++ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); ++ pxafb_enable_controller(fbi); ++#endif ++ return 0; ++} ++#endif ++ + /* + * pxafb_map_video_memory(): + * Allocates the DRAM memory for the frame buffer. This buffer is +@@ -1367,6 +1400,10 @@ + cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER); + #endif ++#ifdef CONFIG_DPM ++ fbi->scale.notifier_call = pxafb_scale; ++ dpm_register_scale(&fbi->scale, SCALE_POSTCHANGE); ++#endif + + /* + * Ok, now enable the LCD controller +diff -Nurd linux-2.6.16.orig/drivers/video/pxafb.h linux-2.6.16/drivers/video/pxafb.h +--- linux-2.6.16.orig/drivers/video/pxafb.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/drivers/video/pxafb.h 2006-06-03 11:14:55.932386240 +0200 +@@ -95,6 +95,10 @@ + struct notifier_block freq_transition; + struct notifier_block freq_policy; + #endif ++ ++#ifdef CONFIG_DPM ++ struct notifier_block scale; ++#endif + }; + + #define TO_INF(ptr,member) container_of(ptr,struct pxafb_info,member) +diff -Nurd linux-2.6.16.orig/fs/9p/vfs_inode.c linux-2.6.16/fs/9p/vfs_inode.c +--- linux-2.6.16.orig/fs/9p/vfs_inode.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/9p/vfs_inode.c 2006-06-03 11:14:55.319479416 +0200 +@@ -614,6 +614,7 @@ + + sb = dir->i_sb; + v9ses = v9fs_inode2v9ses(dir); ++ dentry->d_op = &v9fs_dentry_operations; + dirfid = v9fs_fid_lookup(dentry->d_parent); + + if (!dirfid) { +@@ -681,8 +682,6 @@ + goto FreeFcall; + + fid->qid = fcall->params.rstat.stat.qid; +- +- dentry->d_op = &v9fs_dentry_operations; + v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); + + d_add(dentry, inode); +diff -Nurd linux-2.6.16.orig/fs/char_dev.c linux-2.6.16/fs/char_dev.c +--- linux-2.6.16.orig/fs/char_dev.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/char_dev.c 2006-06-03 11:14:55.319479416 +0200 +@@ -15,6 +15,7 @@ + #include <linux/module.h> + #include <linux/smp_lock.h> + #include <linux/devfs_fs_kernel.h> ++#include <linux/seq_file.h> + + #include <linux/kobject.h> + #include <linux/kobj_map.h> +@@ -26,8 +27,6 @@ + + static struct kobj_map *cdev_map; + +-#define MAX_PROBE_HASH 255 /* random */ +- + static DECLARE_MUTEX(chrdevs_lock); + + static struct char_device_struct { +@@ -38,93 +37,29 @@ + char name[64]; + struct file_operations *fops; + struct cdev *cdev; /* will die */ +-} *chrdevs[MAX_PROBE_HASH]; ++} *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; + + /* index in the above */ + static inline int major_to_index(int major) + { +- return major % MAX_PROBE_HASH; +-} +- +-struct chrdev_info { +- int index; +- struct char_device_struct *cd; +-}; +- +-void *get_next_chrdev(void *dev) +-{ +- struct chrdev_info *info; +- +- if (dev == NULL) { +- info = kmalloc(sizeof(*info), GFP_KERNEL); +- if (!info) +- goto out; +- info->index=0; +- info->cd = chrdevs[info->index]; +- if (info->cd) +- goto out; +- } else { +- info = dev; +- } +- +- while (info->index < ARRAY_SIZE(chrdevs)) { +- if (info->cd) +- info->cd = info->cd->next; +- if (info->cd) +- goto out; +- /* +- * No devices on this chain, move to the next +- */ +- info->index++; +- info->cd = (info->index < ARRAY_SIZE(chrdevs)) ? +- chrdevs[info->index] : NULL; +- if (info->cd) +- goto out; +- } +- +-out: +- return info; +-} +- +-void *acquire_chrdev_list(void) +-{ +- down(&chrdevs_lock); +- return get_next_chrdev(NULL); +-} +- +-void release_chrdev_list(void *dev) +-{ +- up(&chrdevs_lock); +- kfree(dev); ++ return major % CHRDEV_MAJOR_HASH_SIZE; + } + ++#ifdef CONFIG_PROC_FS + +-int count_chrdev_list(void) ++void chrdev_show(struct seq_file *f, off_t offset) + { + struct char_device_struct *cd; +- int i, count; + +- count = 0; +- +- for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) { +- for (cd = chrdevs[i]; cd; cd = cd->next) +- count++; ++ if (offset < CHRDEV_MAJOR_HASH_SIZE) { ++ down(&chrdevs_lock); ++ for (cd = chrdevs[offset]; cd; cd = cd->next) ++ seq_printf(f, "%3d %s\n", cd->major, cd->name); ++ up(&chrdevs_lock); + } +- +- return count; + } + +-int get_chrdev_info(void *dev, int *major, char **name) +-{ +- struct chrdev_info *info = dev; +- +- if (info->cd == NULL) +- return 1; +- +- *major = info->cd->major; +- *name = info->cd->name; +- return 0; +-} ++#endif /* CONFIG_PROC_FS */ + + /* + * Register a single major with a specified minor range. +diff -Nurd linux-2.6.16.orig/fs/cifs/cifsencrypt.c linux-2.6.16/fs/cifs/cifsencrypt.c +--- linux-2.6.16.orig/fs/cifs/cifsencrypt.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/cifs/cifsencrypt.c 2006-06-03 11:14:55.320479264 +0200 +@@ -56,9 +56,6 @@ + int rc = 0; + char smb_signature[20]; + +- /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ +- /* BB remember to add code to save expected sequence number in midQ entry BB */ +- + if((cifs_pdu == NULL) || (server == NULL)) + return -EINVAL; + +@@ -85,20 +82,33 @@ + static int cifs_calc_signature2(const struct kvec * iov, int n_vec, + const char * key, char * signature) + { +- struct MD5Context context; +- +- if((iov == NULL) || (signature == NULL)) +- return -EINVAL; ++ struct MD5Context context; ++ int i; + +- MD5Init(&context); +- MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); ++ if((iov == NULL) || (signature == NULL)) ++ return -EINVAL; + +-/* MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); */ /* BB FIXME BB */ ++ MD5Init(&context); ++ MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); ++ for(i=0;i<n_vec;i++) { ++ if(iov[i].iov_base == NULL) { ++ cERROR(1,("null iovec entry")); ++ return -EIO; ++ } else if(iov[i].iov_len == 0) ++ break; /* bail out if we are sent nothing to sign */ ++ /* The first entry includes a length field (which does not get ++ signed that occupies the first 4 bytes before the header */ ++ if(i==0) { ++ if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */ ++ break; /* nothing to sign or corrupt header */ ++ MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4); ++ } else ++ MD5Update(&context,iov[i].iov_base, iov[i].iov_len); ++ } + +- MD5Final(signature,&context); ++ MD5Final(signature,&context); + +- return -EOPNOTSUPP; +-/* return 0; */ ++ return 0; + } + + +diff -Nurd linux-2.6.16.orig/fs/cifs/dir.c linux-2.6.16/fs/cifs/dir.c +--- linux-2.6.16.orig/fs/cifs/dir.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/cifs/dir.c 2006-06-03 11:14:55.320479264 +0200 +@@ -441,6 +441,20 @@ + cifs_sb = CIFS_SB(parent_dir_inode->i_sb); + pTcon = cifs_sb->tcon; + ++ /* ++ * Don't allow the separator character in a path component. ++ * The VFS will not allow "/", but "\" is allowed by posix. ++ */ ++ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { ++ int i; ++ for (i = 0; i < direntry->d_name.len; i++) ++ if (direntry->d_name.name[i] == '\\') { ++ cFYI(1, ("Invalid file name")); ++ FreeXid(xid); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ + /* can not grab the rename sem here since it would + deadlock in the cases (beginning of sys_rename itself) + in which we already have the sb rename sem */ +diff -Nurd linux-2.6.16.orig/fs/compat.c linux-2.6.16/fs/compat.c +--- linux-2.6.16.orig/fs/compat.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/compat.c 2006-06-03 11:14:55.321479112 +0200 +@@ -1215,6 +1215,10 @@ + if (ret < 0) + goto out; + ++ ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE); ++ if (ret) ++ goto out; ++ + fnv = NULL; + if (type == READ) { + fn = file->f_op->read; +diff -Nurd linux-2.6.16.orig/fs/ext3/resize.c linux-2.6.16/fs/ext3/resize.c +--- linux-2.6.16.orig/fs/ext3/resize.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/ext3/resize.c 2006-06-03 11:14:55.330477744 +0200 +@@ -974,6 +974,7 @@ + if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { + ext3_warning(sb, __FUNCTION__, + "multiple resizers run on filesystem!"); ++ unlock_super(sb); + err = -EBUSY; + goto exit_put; + } +diff -Nurd linux-2.6.16.orig/fs/fuse/file.c linux-2.6.16/fs/fuse/file.c +--- linux-2.6.16.orig/fs/fuse/file.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/fuse/file.c 2006-06-03 11:14:55.330477744 +0200 +@@ -397,8 +397,12 @@ + return -EINTR; + + err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); +- if (!err) +- fuse_send_readpages(data.req, file, inode); ++ if (!err) { ++ if (data.req->num_pages) ++ fuse_send_readpages(data.req, file, inode); ++ else ++ fuse_put_request(fc, data.req); ++ } + return err; + } + +diff -Nurd linux-2.6.16.orig/fs/locks.c linux-2.6.16/fs/locks.c +--- linux-2.6.16.orig/fs/locks.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/locks.c 2006-06-03 11:14:55.331477592 +0200 +@@ -2212,7 +2212,12 @@ + + lock_kernel(); + j = 0; +- rcu_read_lock(); ++ ++ /* ++ * We are not taking a ref to the file structures, so ++ * we need to acquire ->file_lock. ++ */ ++ spin_lock(&files->file_lock); + fdt = files_fdtable(files); + for (;;) { + unsigned long set; +@@ -2230,7 +2235,7 @@ + set >>= 1; + } + } +- rcu_read_unlock(); ++ spin_unlock(&files->file_lock); + unlock_kernel(); + } + EXPORT_SYMBOL(steal_locks); +diff -Nurd linux-2.6.16.orig/fs/nfsd/nfs3proc.c linux-2.6.16/fs/nfsd/nfs3proc.c +--- linux-2.6.16.orig/fs/nfsd/nfs3proc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/nfsd/nfs3proc.c 2006-06-03 11:14:55.332477440 +0200 +@@ -682,7 +682,7 @@ + PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), + PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), + PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), +- PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE), ++ PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4), + PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), + PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), + PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), +diff -Nurd linux-2.6.16.orig/fs/nfsd/nfs4proc.c linux-2.6.16/fs/nfsd/nfs4proc.c +--- linux-2.6.16.orig/fs/nfsd/nfs4proc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/nfsd/nfs4proc.c 2006-06-03 11:14:55.333477288 +0200 +@@ -975,7 +975,7 @@ + */ + static struct svc_procedure nfsd_procedures4[2] = { + PROC(null, void, void, void, RC_NOCACHE, 1), +- PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE) ++ PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) + }; + + struct svc_version nfsd_version4 = { +diff -Nurd linux-2.6.16.orig/fs/nfsd/nfsproc.c linux-2.6.16/fs/nfsd/nfsproc.c +--- linux-2.6.16.orig/fs/nfsd/nfsproc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/nfsd/nfsproc.c 2006-06-03 11:14:55.333477288 +0200 +@@ -553,7 +553,7 @@ + PROC(none, void, void, none, RC_NOCACHE, ST), + PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), + PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), +- PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE), ++ PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4), + PROC(none, void, void, none, RC_NOCACHE, ST), + PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), + PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), +diff -Nurd linux-2.6.16.orig/fs/open.c linux-2.6.16/fs/open.c +--- linux-2.6.16.orig/fs/open.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/open.c 2006-06-03 11:14:55.334477136 +0200 +@@ -330,7 +330,10 @@ + + asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length) + { +- return do_sys_ftruncate(fd, length, 1); ++ long ret = do_sys_ftruncate(fd, length, 1); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + /* LFS versions of truncate are only needed on 32 bit machines */ +@@ -342,7 +345,10 @@ + + asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length) + { +- return do_sys_ftruncate(fd, length, 0); ++ long ret = do_sys_ftruncate(fd, length, 0); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + #endif + +@@ -1083,20 +1089,30 @@ + + asmlinkage long sys_open(const char __user *filename, int flags, int mode) + { ++ long ret; ++ + if (force_o_largefile()) + flags |= O_LARGEFILE; + +- return do_sys_open(AT_FDCWD, filename, flags, mode); ++ ret = do_sys_open(AT_FDCWD, filename, flags, mode); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + EXPORT_SYMBOL_GPL(sys_open); + + asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, + int mode) + { ++ long ret; ++ + if (force_o_largefile()) + flags |= O_LARGEFILE; + +- return do_sys_open(dfd, filename, flags, mode); ++ ret = do_sys_open(dfd, filename, flags, mode); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + EXPORT_SYMBOL_GPL(sys_openat); + +diff -Nurd linux-2.6.16.orig/fs/partitions/check.c linux-2.6.16/fs/partitions/check.c +--- linux-2.6.16.orig/fs/partitions/check.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/partitions/check.c 2006-06-03 11:14:55.334477136 +0200 +@@ -345,6 +345,7 @@ + char *name; + static char *block_str = "block:"; + int size; ++ char *s; + + size = strlen(block_str) + strlen(disk->disk_name) + 1; + name = kmalloc(size, GFP_KERNEL); +@@ -352,6 +353,10 @@ + return NULL; + strcpy(name, block_str); + strcat(name, disk->disk_name); ++ /* ewww... some of these buggers have / in name... */ ++ s = strchr(name, '/'); ++ if (s) ++ *s = '!'; + return name; + } + +diff -Nurd linux-2.6.16.orig/fs/proc/base.c linux-2.6.16/fs/proc/base.c +--- linux-2.6.16.orig/fs/proc/base.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/proc/base.c 2006-06-03 11:14:55.902390800 +0200 +@@ -167,6 +167,10 @@ + PROC_TID_OOM_SCORE, + PROC_TID_OOM_ADJUST, + ++#ifdef CONFIG_DPM ++ PROC_TGID_DPM, ++#endif ++ + /* Add new entries before this */ + PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */ + }; +@@ -221,6 +225,9 @@ + #ifdef CONFIG_AUDITSYSCALL + E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO), + #endif ++#ifdef CONFIG_DPM ++ E(PROC_TGID_DPM, "dpmstate", S_IFREG|S_IRUGO|S_IWUSR), ++#endif + {0,0,NULL,0} + }; + static struct pid_entry tid_base_stuff[] = { +@@ -294,16 +301,20 @@ + + files = get_files_struct(task); + if (files) { +- rcu_read_lock(); ++ /* ++ * We are not taking a ref to the file structure, so we must ++ * hold ->file_lock. ++ */ ++ spin_lock(&files->file_lock); + file = fcheck_files(files, fd); + if (file) { + *mnt = mntget(file->f_vfsmnt); + *dentry = dget(file->f_dentry); +- rcu_read_unlock(); ++ spin_unlock(&files->file_lock); + put_files_struct(files); + return 0; + } +- rcu_read_unlock(); ++ spin_unlock(&files->file_lock); + put_files_struct(files); + } + return -ENOENT; +@@ -432,10 +443,10 @@ + goto out_mm; /* Shh! No looking before we're done */ + + len = mm->arg_end - mm->arg_start; +- ++ + if (len > PAGE_SIZE) + len = PAGE_SIZE; +- ++ + res = access_process_vm(task, mm->arg_start, buffer, len, 0); + + // If the nul at the end of args has been overwritten, then +@@ -783,18 +794,18 @@ + goto out; + + ret = 0; +- ++ + mm = get_task_mm(task); + if (!mm) + goto out_free; + + ret = -EIO; +- ++ + if (file->private_data != (void*)((long)current->self_exec_id)) + goto out_put; + + ret = 0; +- ++ + while (count > 0) { + int this_len, retval; + +@@ -810,7 +821,7 @@ + ret = -EFAULT; + break; + } +- ++ + ret += retval; + src += retval; + buf += retval; +@@ -862,7 +873,7 @@ + copied += retval; + buf += retval; + dst += retval; +- count -= retval; ++ count -= retval; + } + *ppos = dst; + free_page((unsigned long) page); +@@ -1096,7 +1107,7 @@ + + if (!tmp) + return -ENOMEM; +- ++ + inode = dentry->d_inode; + path = d_path(dentry, mnt, tmp, PAGE_SIZE); + len = PTR_ERR(path); +@@ -1304,7 +1315,7 @@ + struct proc_inode *ei; + + /* We need a new inode */ +- ++ + inode = new_inode(sb); + if (!inode) + goto out; +@@ -1462,6 +1473,56 @@ + return ~0U; + } + ++#ifdef CONFIG_DPM ++#include <linux/dpm.h> ++ ++extern int dpm_set_task_state_by_name(struct task_struct *, char *, ssize_t); ++ ++static ssize_t proc_dpm_read(struct file * file, char __user * buf, ++ size_t count, loff_t *ppos) ++{ ++ struct task_struct *task = proc_task(file->f_dentry->d_inode); ++ int len; ++ char lbuf[80]; ++ ++ if (*ppos != 0) ++ return 0; ++ ++ len = sprintf(lbuf,"%s\n", task->dpm_state == DPM_NO_STATE ? ++ "none" : dpm_state_names[task->dpm_state]); ++ ++ if (copy_to_user(buf, lbuf, len)) ++ return -EFAULT; ++ ++ *ppos += len; ++ return len; ++} ++ ++static ssize_t proc_dpm_write(struct file * file, const char * buf, ++ size_t count, loff_t *ppos) ++{ ++ struct task_struct *task = proc_task(file->f_dentry->d_inode); ++ char lbuf[80]; ++ int error; ++ ssize_t len; ++ ++ len = (count < 80) ? count : 79; ++ ++ if (copy_from_user(lbuf, buf, len)) ++ return -EFAULT; ++ ++ lbuf[79] = 0; ++ error = dpm_set_task_state_by_name(task, lbuf, len); ++ *ppos += count; ++ return error ? error : count; ++} ++ ++static struct file_operations proc_dpm_operations = { ++ .read = proc_dpm_read, ++ .write = proc_dpm_write, ++}; ++#endif ++ + /* SMP-safe */ + static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) + { +@@ -1485,7 +1546,12 @@ + if (!files) + goto out_unlock; + inode->i_mode = S_IFLNK; +- rcu_read_lock(); ++ ++ /* ++ * We are not taking a ref to the file structure, so we must ++ * hold ->file_lock. ++ */ ++ spin_lock(&files->file_lock); + file = fcheck_files(files, fd); + if (!file) + goto out_unlock2; +@@ -1493,7 +1559,7 @@ + inode->i_mode |= S_IRUSR | S_IXUSR; + if (file->f_mode & 2) + inode->i_mode |= S_IWUSR | S_IXUSR; +- rcu_read_unlock(); ++ spin_unlock(&files->file_lock); + put_files_struct(files); + inode->i_op = &proc_pid_link_inode_operations; + inode->i_size = 64; +@@ -1503,7 +1569,7 @@ + return NULL; + + out_unlock2: +- rcu_read_unlock(); ++ spin_unlock(&files->file_lock); + put_files_struct(files); + out_unlock: + iput(inode); +@@ -1551,8 +1617,8 @@ + if (!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + +- length = security_getprocattr(task, +- (char*)file->f_dentry->d_name.name, ++ length = security_getprocattr(task, ++ (char*)file->f_dentry->d_name.name, + (void*)page, count); + if (length >= 0) + length = simple_read_from_buffer(buf, count, ppos, (char *)page, length); +@@ -1562,32 +1628,32 @@ + + static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, + size_t count, loff_t *ppos) +-{ ++{ + struct inode * inode = file->f_dentry->d_inode; +- char *page; +- ssize_t length; +- struct task_struct *task = proc_task(inode); ++ char *page; ++ ssize_t length; ++ struct task_struct *task = proc_task(inode); + +- if (count > PAGE_SIZE) +- count = PAGE_SIZE; ++ if (count > PAGE_SIZE) ++ count = PAGE_SIZE; + if (*ppos != 0) { + /* No partial writes. */ + return -EINVAL; + } +- page = (char*)__get_free_page(GFP_USER); +- if (!page) ++ page = (char*)__get_free_page(GFP_USER); ++ if (!page) + return -ENOMEM; +- length = -EFAULT; +- if (copy_from_user(page, buf, count)) ++ length = -EFAULT; ++ if (copy_from_user(page, buf, count)) + goto out; + +- length = security_setprocattr(task, +- (char*)file->f_dentry->d_name.name, ++ length = security_setprocattr(task, ++ (char*)file->f_dentry->d_name.name, + (void*)page, count); + out: + free_page((unsigned long) page); + return length; +-} ++} + + static struct file_operations proc_pid_attr_operations = { + .read = proc_pid_attr_read, +@@ -1603,7 +1669,7 @@ + static int get_tid_list(int index, unsigned int *tids, struct inode *dir); + + /* SMP-safe */ +-static struct dentry *proc_pident_lookup(struct inode *dir, ++static struct dentry *proc_pident_lookup(struct inode *dir, + struct dentry *dentry, + struct pid_entry *ents) + { +@@ -1787,6 +1853,12 @@ + inode->i_fop = &proc_loginuid_operations; + break; + #endif ++#ifdef CONFIG_DPM ++ case PROC_TGID_DPM: ++ inode->i_op = &proc_fd_inode_operations; ++ inode->i_fop = &proc_dpm_operations; ++ break; ++#endif + default: + printk("procfs: impossible type (%d)",p->type); + iput(inode); +@@ -1888,7 +1960,7 @@ + char tmp[30]; + sprintf(tmp, "%d", current->tgid); + return ERR_PTR(vfs_follow_link(nd,tmp)); +-} ++} + + static struct inode_operations proc_self_inode_operations = { + .readlink = proc_self_readlink, +@@ -1939,7 +2011,7 @@ + * + * Shrink the /proc directory that was used by the just killed thread. + */ +- ++ + void proc_pid_flush(struct dentry *proc_dentry) + { + might_sleep(); +diff -Nurd linux-2.6.16.orig/fs/proc/proc_misc.c linux-2.6.16/fs/proc/proc_misc.c +--- linux-2.6.16.orig/fs/proc/proc_misc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/proc/proc_misc.c 2006-06-03 11:14:55.337476680 +0200 +@@ -249,144 +249,60 @@ + return seq_open(file, &cpuinfo_op); + } + +-enum devinfo_states { +- CHR_HDR, +- CHR_LIST, +- BLK_HDR, +- BLK_LIST, +- DEVINFO_DONE +-}; +- +-struct devinfo_state { +- void *chrdev; +- void *blkdev; +- unsigned int num_records; +- unsigned int cur_record; +- enum devinfo_states state; ++static struct file_operations proc_cpuinfo_operations = { ++ .open = cpuinfo_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, + }; + +-static void *devinfo_start(struct seq_file *f, loff_t *pos) ++static int devinfo_show(struct seq_file *f, void *v) + { +- struct devinfo_state *info = f->private; ++ int i = *(loff_t *) v; + +- if (*pos) { +- if ((info) && (*pos <= info->num_records)) +- return info; +- return NULL; ++ if (i < CHRDEV_MAJOR_HASH_SIZE) { ++ if (i == 0) ++ seq_printf(f, "Character devices:\n"); ++ chrdev_show(f, i); ++ } else { ++ i -= CHRDEV_MAJOR_HASH_SIZE; ++ if (i == 0) ++ seq_printf(f, "\nBlock devices:\n"); ++ blkdev_show(f, i); + } +- info = kmalloc(sizeof(*info), GFP_KERNEL); +- f->private = info; +- info->chrdev = acquire_chrdev_list(); +- info->blkdev = acquire_blkdev_list(); +- info->state = CHR_HDR; +- info->num_records = count_chrdev_list(); +- info->num_records += count_blkdev_list(); +- info->num_records += 2; /* Character and Block headers */ +- *pos = 1; +- info->cur_record = *pos; +- return info; ++ return 0; + } + +-static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) ++static void *devinfo_start(struct seq_file *f, loff_t *pos) + { +- int idummy; +- char *ndummy; +- struct devinfo_state *info = f->private; +- +- switch (info->state) { +- case CHR_HDR: +- info->state = CHR_LIST; +- (*pos)++; +- /*fallthrough*/ +- case CHR_LIST: +- if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) { +- /* +- * The character dev list is complete +- */ +- info->state = BLK_HDR; +- } else { +- info->chrdev = get_next_chrdev(info->chrdev); +- } +- (*pos)++; +- break; +- case BLK_HDR: +- info->state = BLK_LIST; +- (*pos)++; +- break; +- case BLK_LIST: +- if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) { +- /* +- * The block dev list is complete +- */ +- info->state = DEVINFO_DONE; +- } else { +- info->blkdev = get_next_blkdev(info->blkdev); +- } +- (*pos)++; +- break; +- case DEVINFO_DONE: +- (*pos)++; +- info->cur_record = *pos; +- info = NULL; +- break; +- default: +- break; +- } +- if (info) +- info->cur_record = *pos; +- return info; ++ if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) ++ return pos; ++ return NULL; + } + +-static void devinfo_stop(struct seq_file *f, void *v) ++static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) + { +- struct devinfo_state *info = f->private; +- +- if (info) { +- release_chrdev_list(info->chrdev); +- release_blkdev_list(info->blkdev); +- f->private = NULL; +- kfree(info); +- } ++ (*pos)++; ++ if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) ++ return NULL; ++ return pos; + } + +-static int devinfo_show(struct seq_file *f, void *arg) ++static void devinfo_stop(struct seq_file *f, void *v) + { +- int major; +- char *name; +- struct devinfo_state *info = f->private; +- +- switch(info->state) { +- case CHR_HDR: +- seq_printf(f,"Character devices:\n"); +- /* fallthrough */ +- case CHR_LIST: +- if (!get_chrdev_info(info->chrdev,&major,&name)) +- seq_printf(f,"%3d %s\n",major,name); +- break; +- case BLK_HDR: +- seq_printf(f,"\nBlock devices:\n"); +- /* fallthrough */ +- case BLK_LIST: +- if (!get_blkdev_info(info->blkdev,&major,&name)) +- seq_printf(f,"%3d %s\n",major,name); +- break; +- default: +- break; +- } +- +- return 0; ++ /* Nothing to do */ + } + +-static struct seq_operations devinfo_op = { +- .start = devinfo_start, +- .next = devinfo_next, +- .stop = devinfo_stop, +- .show = devinfo_show, ++static struct seq_operations devinfo_ops = { ++ .start = devinfo_start, ++ .next = devinfo_next, ++ .stop = devinfo_stop, ++ .show = devinfo_show + }; + +-static int devinfo_open(struct inode *inode, struct file *file) ++static int devinfo_open(struct inode *inode, struct file *filp) + { +- return seq_open(file, &devinfo_op); ++ return seq_open(filp, &devinfo_ops); + } + + static struct file_operations proc_devinfo_operations = { +@@ -396,13 +312,6 @@ + .release = seq_release, + }; + +-static struct file_operations proc_cpuinfo_operations = { +- .open = cpuinfo_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = seq_release, +-}; +- + extern struct seq_operations vmstat_op; + static int vmstat_open(struct inode *inode, struct file *file) + { +diff -Nurd linux-2.6.16.orig/fs/proc/vmcore.c linux-2.6.16/fs/proc/vmcore.c +--- linux-2.6.16.orig/fs/proc/vmcore.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/proc/vmcore.c 2006-06-03 11:14:55.337476680 +0200 +@@ -103,8 +103,8 @@ + size_t buflen, loff_t *fpos) + { + ssize_t acc = 0, tmp; +- size_t tsz, nr_bytes; +- u64 start; ++ size_t tsz; ++ u64 start, nr_bytes; + struct vmcore *curr_m = NULL; + + if (buflen == 0 || *fpos >= vmcore_size) +diff -Nurd linux-2.6.16.orig/fs/reiserfs/xattr_acl.c linux-2.6.16/fs/reiserfs/xattr_acl.c +--- linux-2.6.16.orig/fs/reiserfs/xattr_acl.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/reiserfs/xattr_acl.c 2006-06-03 11:14:55.338476528 +0200 +@@ -408,8 +408,9 @@ + acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); + reiserfs_read_unlock_xattrs(inode->i_sb); + reiserfs_read_unlock_xattr_i(inode); +- ret = acl ? 1 : 0; +- posix_acl_release(acl); ++ ret = (acl && !IS_ERR(acl)); ++ if (ret) ++ posix_acl_release(acl); + } + + return ret; +diff -Nurd linux-2.6.16.orig/fs/sysfs/dir.c linux-2.6.16/fs/sysfs/dir.c +--- linux-2.6.16.orig/fs/sysfs/dir.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/sysfs/dir.c 2006-06-03 11:14:55.348475008 +0200 +@@ -302,6 +302,7 @@ + * Drop reference from dget() on entrance. + */ + dput(dentry); ++ kobj->dentry = NULL; + } + + int sysfs_rename_dir(struct kobject * kobj, const char *new_name) +diff -Nurd linux-2.6.16.orig/fs/sysfs/file.c linux-2.6.16/fs/sysfs/file.c +--- linux-2.6.16.orig/fs/sysfs/file.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/sysfs/file.c 2006-06-03 11:14:55.348475008 +0200 +@@ -183,7 +183,7 @@ + return -ENOMEM; + + if (count >= PAGE_SIZE) +- count = PAGE_SIZE; ++ count = PAGE_SIZE - 1; + error = copy_from_user(buffer->page,buf,count); + buffer->needs_read_fill = 1; + return error ? -EFAULT : count; +diff -Nurd linux-2.6.16.orig/fs/sysfs/inode.c linux-2.6.16/fs/sysfs/inode.c +--- linux-2.6.16.orig/fs/sysfs/inode.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/sysfs/inode.c 2006-06-03 11:14:55.349474856 +0200 +@@ -227,12 +227,16 @@ + void sysfs_hash_and_remove(struct dentry * dir, const char * name) + { + struct sysfs_dirent * sd; +- struct sysfs_dirent * parent_sd = dir->d_fsdata; ++ struct sysfs_dirent * parent_sd; ++ ++ if (!dir) ++ return; + + if (dir->d_inode == NULL) + /* no inode means this hasn't been made visible yet */ + return; + ++ parent_sd = dir->d_fsdata; + mutex_lock(&dir->d_inode->i_mutex); + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if (!sd->s_element) +diff -Nurd linux-2.6.16.orig/fs/sysfs/symlink.c linux-2.6.16/fs/sysfs/symlink.c +--- linux-2.6.16.orig/fs/sysfs/symlink.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/sysfs/symlink.c 2006-06-03 11:14:55.349474856 +0200 +@@ -66,6 +66,7 @@ + if (!error) + return 0; + ++ kobject_put(target); + kfree(sl->link_name); + exit2: + kfree(sl); +diff -Nurd linux-2.6.16.orig/fs/xfs/linux-2.6/xfs_aops.c linux-2.6.16/fs/xfs/linux-2.6/xfs_aops.c +--- linux-2.6.16.orig/fs/xfs/linux-2.6/xfs_aops.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/xfs/linux-2.6/xfs_aops.c 2006-06-03 11:14:55.350474704 +0200 +@@ -616,7 +616,7 @@ + acceptable = (type == IOMAP_UNWRITTEN); + else if (buffer_delay(bh)) + acceptable = (type == IOMAP_DELAY); +- else if (buffer_mapped(bh)) ++ else if (buffer_dirty(bh) && buffer_mapped(bh)) + acceptable = (type == 0); + else + break; +diff -Nurd linux-2.6.16.orig/fs/xfs/linux-2.6/xfs_iops.c linux-2.6.16/fs/xfs/linux-2.6/xfs_iops.c +--- linux-2.6.16.orig/fs/xfs/linux-2.6/xfs_iops.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/fs/xfs/linux-2.6/xfs_iops.c 2006-06-03 11:14:55.350474704 +0200 +@@ -673,8 +673,7 @@ + if (ia_valid & ATTR_ATIME) { + vattr.va_mask |= XFS_AT_ATIME; + vattr.va_atime = attr->ia_atime; +- if (ia_valid & ATTR_ATIME_SET) +- inode->i_atime = attr->ia_atime; ++ inode->i_atime = attr->ia_atime; + } + if (ia_valid & ATTR_MTIME) { + vattr.va_mask |= XFS_AT_MTIME; +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/debug-macro.S linux-2.6.16/include/asm-arm/arch-pxa/debug-macro.S +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/debug-macro.S 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/debug-macro.S 2006-06-03 11:14:56.255337144 +0200 +@@ -14,15 +14,59 @@ + #include "hardware.h" + + .macro addruart,rx +- mrc p15, 0, \rx, c1, c0 +- tst \rx, #1 @ MMU enabled? +- moveq \rx, #0x40000000 @ physical +- movne \rx, #io_p2v(0x40000000) @ virtual +- orr \rx, \rx, #0x00100000 ++@ mrc p15, 0, \rx, c1, c0 ++@ tst \rx, #1 @ MMU enabled? ++ mov \rx, #0x40000000 @ physical ++@ moveq \rx, #0x40000000 @ physical ++@ movne \rx, #io_p2v(0x40000000) @ virtual ++ orr \rx, \rx, #0x00700000 ++ .endm ++ ++ .macro inituart,rd,rx ++ ldr \rd, =0x41300004 @ CKEN ++ ldr \rx, [\rd] ++ orr \rx, \rx, #0x20 ++ str \rx, [\rd] ++ ++ ldr \rd, =0x40E0005C ++ ldr \rx, [\rd] ++ bic \rx, \rx, #0xF0000000 @ clear GPIO46/47 config ++ orr \rx, \rx, #0x60000000 @ set GPIO46: AF2, GPIO47: AF1 ++ str \rx, [\rd] ++ ldr \rd, =0x40E00010 ++ ldr \rx, [\rd] ++ bic \rx, \rx, #0x0000c000 @ clear GPIO46/47 direction ++ orr \rx, \rx, #0x00008000 @ set GPIO 47 out, 46 in ++ str \rx, [\rd] ++ ++ addruart \rd ++ mov \rx, #0x83 @ DLAB = 1 ++ strb \rx, [\rd, #0x0c] ++ ++ mov \rx, #0x08 @ Divisor 8 => 115200 bps ++ strb \rx, [\rd, #0x00] ++ ++ mov \rx, #0x00 ++ strb \rx, [\rd, #0x04] @ Divisor high = 0 ++ ++ mov \rx, #0x03 ++ strb \rx, [\rd, #0x0c] @ DLAB = 0, n81 ++ ++ mov \rx, #0x00 ++ strb \rx, [\rd, #0x10] @ MCR = 0 ++ ++ mov \rx, #0x00 ++ strb \rx, [\rd, #0x28] @ disable autobaud ++ ++ mov \rx, #0x40 ++ strb \rx, [\rd, #0x04] @ IER UUE (UART Enable) + .endm + + .macro senduart,rd,rx +- str \rd, [\rx, #0] ++1000: ldr r12, [\rx, #0x14] ++ tst r12, #(1 << 6) ++ beq 1000b ++ strb \rd, [\rx, #0] + .endm + + .macro busyuart,rd,rx +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/dpm.h linux-2.6.16/include/asm-arm/arch-pxa/dpm.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/dpm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/dpm.h 2006-06-03 11:14:55.926387152 +0200 +@@ -0,0 +1,157 @@ ++/* ++ * include/asm-arm/arch-pxa/dpm.h ++ * ++ * Bulverde-specific definitions for DPM. If further PXA boards are ++ * supported in the future, will split into board-specific files. ++ * ++ * 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 ++ * ++ * Copyright (C) 2002 MontaVista Software <source@mvista.com> ++ * ++ * Based on arch/ppc/platforms/ibm405lp_dpm.h by Bishop Brock. ++ */ ++ ++#ifndef __ASM_ARM_PXA_DPM_H__ ++#define __ASM_ARM_PXA_DPM_H__ ++ ++/* ++ * machine dependent operating state ++ * ++ * An operating state is a cpu execution state that has implications for power ++ * management. The DPM will select operating points based largely on the ++ * current operating state. ++ * ++ * DPM_STATES is the number of supported operating states. Valid operating ++ * states are from 0 to DPM_STATES-1 but when setting an operating state the ++ * kernel should only specify a state from the set of "base states" and should ++ * do so by name. During the context switch the new operating state is simply ++ * extracted from current->dpm_state. ++ * ++ * task states: ++ * ++ * APIs that reference task states use the range -(DPM_TASK_STATE_LIMIT + 1) ++ * through +DPM_TASK_STATE_LIMIT. This value is added to DPM_TASK_STATE to ++ * obtain the downward or upward adjusted task state value. The ++ * -(DPM_TASK_STATE_LIMIT + 1) value is interpreted specially, and equates to ++ * DPM_NO_STATE. ++ * ++ * Tasks inherit their task operating states across calls to ++ * fork(). DPM_TASK_STATE is the default operating state for all tasks, and is ++ * inherited from init. Tasks can change (or have changed) their tasks states ++ * using the DPM_SET_TASK_STATE variant of the sys_dpm() system call. */ ++ ++#define DPM_NO_STATE -1 ++ ++#define DPM_IDLE_TASK_STATE 0 ++#define DPM_IDLE_STATE 1 ++#define DPM_SLEEP_STATE 2 ++#define DPM_BASE_STATES 3 ++ ++#define DPM_TASK_STATE_LIMIT 4 ++#define DPM_TASK_STATE (DPM_BASE_STATES + DPM_TASK_STATE_LIMIT) ++#define DPM_STATES (DPM_TASK_STATE + DPM_TASK_STATE_LIMIT + 1) ++#define DPM_TASK_STATES (DPM_STATES - DPM_BASE_STATES) ++ ++/* ++ *length of DPM_STATE_NAMES is DPM_STATES, ++ */ ++#define DPM_STATE_NAMES \ ++{ "idle-task", "idle", "sleep",\ ++ "task-4", "task-3", "task-2", "task-1",\ ++ "task", \ ++ "task+1", "task+2", "task+3", "task+4" \ ++} ++ ++/* Operating point parameters */ ++#define DPM_MD_V 0 /* Voltage */ ++#define DPM_MD_PLL_L 1 /* L */ ++#define DPM_MD_PLL_N 2 /* N */ ++#define DPM_MD_PLL_B 3 /* B */ ++#define DPM_MD_HALF_TURBO 4 /* Cuts turbo mode in half */ ++#define DPM_MD_CCCRA 5 /* The A bit in the CCCR is ++ for MEMC clocks */ ++#define DPM_MD_CPLL_ON 6 /* Core PLL on/off */ ++#define DPM_MD_PPLL_ON 7 /* Peripheral PLL on/off */ ++#define DPM_MD_SLEEP_MODE 8 /* Sleep mode, from pm.h */ ++#define DPM_MD_PLL_LCD 9 /* calculated value */ ++ ++ ++enum ++{ ++ CPUMODE_RUN, ++ CPUMODE_IDLE, ++ CPUMODE_STANDBY, ++ CPUMODE_SLEEP, ++ CPUMODE_RESERVED, ++ CPUMODE_SENSE, ++ CPUMODE_RESERVED2, ++ CPUMODE_DEEPSLEEP, ++}; ++ ++/* this is the number of specifiable operating point parameters, ++ * used by arch-independent DPM-core driver ++ */ ++#define DPM_PP_NBR 10 ++#define DPM_PARAM_NAMES {"v","l","n","b","ht","a","cpll", "ppll","sleep", "lcd"}; ++ ++#ifndef __ASSEMBLER__ ++ ++#include <linux/types.h> ++#include <linux/proc_fs.h> ++#include <asm/hardware.h> ++#include <asm/arch/pxa-regs.h> ++ ++#define dpm_time() (OSCR) ++#define DPM_NSEC_PER_TICK 308 /* nanoseconds per tick */ ++#define dpm_time_to_usec(ticks) ({ \ ++ unsigned long long quot = \ ++ ((ticks) * DPM_NSEC_PER_TICK * 2 + 1); \ ++ do_div(quot, (unsigned long) 1000*2); \ ++ quot; }) ++ ++struct dpm_regs { ++ unsigned int cccr; ++ unsigned int clkcfg; ++ unsigned int voltage; /*This is not a register.*/ ++}; ++ ++/* Instances of this structure define valid Bulverde operating points for DPM. ++ Voltages are represented in mV, and frequencies are represented in KHz. */ ++ ++struct dpm_md_opt { ++ /* Specified values */ ++ int v; /* Target voltage in mV*/ ++ int l; /* Run Mode to Oscillator ratio */ ++ int n; /* Turbo-Mode to Run-Mode ratio */ ++ int b; /* Fast Bus Mode */ ++ int half_turbo;/* Half Turbo bit */ ++ int cccra; /* the 'A' bit of the CCCR register, ++ alternate MEMC clock */ ++ int cpll_enabled; /* core PLL is ON? (Bulverde >="C0" feature)*/ ++ int ppll_enabled; /* peripherial PLL is ON? (Bulverde >="C0" feature)*/ ++ ++ int sleep_mode; ++ /*Calculated values*/ ++ unsigned int lcd; /*in KHz */ ++ unsigned int lpj; /*New value for loops_per_jiffy */ ++ unsigned int cpu; /*CPU frequency in KHz */ ++ unsigned int turbo; /* Turbo bit in clkcfg */ ++ ++ struct dpm_regs regs; /* Register values */ ++}; ++ ++#endif /* __ASSEMBLER__ */ ++#endif /* __ASM_BULVERDE_DPM_H__ */ ++ +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/ezx-compat.h linux-2.6.16/include/asm-arm/arch-pxa/ezx-compat.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/ezx-compat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/ezx-compat.h 2006-06-03 11:14:56.255337144 +0200 +@@ -0,0 +1,14 @@ ++#ifndef _EZX_COMPAT_H ++#define _EZX_COMPAT_H ++ ++#define GPIO_is_high(x) (GPLR(x) & GPIO_bit(x)) ++#define set_GPIO(x) (GPSR(x) = GPIO_bit(x)) ++#define clr_GPIO(x) (GPCR(x) = GPIO_bit(x)) ++ ++#define GPIO_FALLING_EDGE 1 ++#define GPIO_RISING_EDGE 2 ++#define GPIO_BOTH_EDGES 3 ++ ++extern int set_GPIO_IRQ_edge(int irq, int type); ++ ++#endif +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/ezx.h linux-2.6.16/include/asm-arm/arch-pxa/ezx.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/ezx.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/ezx.h 2006-06-03 11:14:56.256336992 +0200 +@@ -0,0 +1,221 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/ezx.h ++ * ++ * Specific macro defines for Motorola Ezx Development Platform ++ * ++ * Author: Zhuang Xiaofan ++ * Created: Nov 25, 2003 ++ * Copyright: Motorola 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. ++ */ ++ ++/* support E680 p3 and ealier PCB */ ++//#define E680_P3_AND_EARLY ++ ++/* ++ * Flags in memory for sleep use ++ */ ++#define FLAG_ADDR PHYS_OFFSET ++#define RESUME_ADDR (PHYS_OFFSET + 4) ++#define BPSIG_ADDR (PHYS_OFFSET + 8) ++ ++#define USER_OFF_FLAG 0x5a5a5a5a ++#define SLEEP_FLAG 0x6b6b6b6b ++#define OFF_FLAG 0x7c7c7c7c ++#define REFLASH_FLAG 0x0C1D2E3F ++#define PASS_THRU_FLAG 0x12345678 ++ ++#define WDI_FLAG 0xbb00dead ++#define NO_FLAG 0xaa00dead ++ ++/* ++ * GPIO control pin, have to change when hardware lock down ++ */ ++ ++#ifdef E680_P3_AND_EARLY ++ ++/* shakehand with BP's PIN */ ++#define GPIO_BP_RDY 0 /* BP_RDY */ ++#define GPIO_BB_WDI 13 /* BB_WDI */ ++#define GPIO_BB_WDI2 3 /* BB_WDI2 */ ++#define GPIO_BB_RESET 57 /* BB_RESET */ ++#define GPIO_MCU_INT_SW 115 /* MCU_INT_SW */ ++#define GPIO_TC_MM_EN 89 /* TC_MM_EN */ ++ ++/* control PCAP direct PIN */ ++#define GPIO_WDI_AP 4 /* WDI_AP */ ++#define GPIO_SYS_RESTART 55 /* restart PCAP power */ ++#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ ++ ++/* communicate with PCAP's PIN */ ++#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ ++#define GPIO_SPI_CLK 23 /* PCAP SPI port clock */ ++#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ ++#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ ++#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ ++ ++/* blue tooth control PIN */ ++#define GPIO_BT_WAKEUP 2 /* AP wake up bluetooth module */ ++#define GPIO_BT_HOSTWAKE 14 /* bluetooth module wake up Ap module */ ++#define GPIO_BT_RESET 56 /* AP reset bluetooth module */ ++ ++/* control LCD high - OFF low -- ON */ ++#define GPIO_LCD_OFF 116 /* control LCD */ ++ ++/* FFUART PIN */ ++#define GPIO_ICL_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++ ++#elif defined(A780_P1_AND_EARLY) ++ ++/* shakehand with BP's PIN */ ++#define GPIO_BP_RDY 0 /* BP_RDY */ ++#define GPIO_BB_WDI 13 /* BB_WDI */ ++#define GPIO_BB_WDI2 3 /* BB_WDI2 */ ++#define GPIO_BB_RESET 82 /* BB_RESET */ ++#define GPIO_MCU_INT_SW 57 /* MCU_INT_SW */ ++#define GPIO_TC_MM_EN 89 /* TC_MM_EN */ ++ ++/* control PCAP direct PIN */ ++#define GPIO_WDI_AP 4 /* WDI_AP */ ++#define GPIO_SYS_RESTART 55 /* restart PCAP power */ ++#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ ++ ++/* communicate with PCAP's PIN */ ++#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ ++#define GPIO_SPI_CLK 29 /* PCAP SPI port clock */ ++#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ ++#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ ++#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ ++ ++/* blue tooth control PIN */ ++#define GPIO_BT_WAKEUP 2 /* AP wake up bluetooth module */ ++#define GPIO_BT_HOSTWAKE 14 /* bluetooth module wake up Ap module */ ++#define GPIO_BT_RESET 56 /* AP reset bluetooth module */ ++ ++/* control LCD high - OFF low -- ON */ ++#define GPIO_LCD_OFF 116 /* control LCD */ ++ ++/* FFUART PIN */ ++#define GPIO_ICL_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++ ++#else ++ ++/* shakehand with BP's PIN */ ++#define GPIO_BP_RDY 0 /* BP_RDY */ ++#define GPIO_BB_WDI 13 /* BB_WDI */ ++#define GPIO_BB_WDI2 3 /* BB_WDI2 */ ++#define GPIO_BB_RESET 82 /* BB_RESET */ ++#define GPIO_MCU_INT_SW 57 /* MCU_INT_SW */ ++#define GPIO_TC_MM_EN 99 /* TC_MM_EN */ ++ ++/* control PCAP direct PIN */ ++#define GPIO_WDI_AP 4 /* WDI_AP */ ++#define GPIO_SYS_RESTART 55 /* restart PCAP power */ ++//#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ ++ ++/* communicate with PCAP's PIN */ ++#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ ++#define GPIO_SPI_CLK 29 /* PCAP SPI port clock */ ++#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ ++#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ ++#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ ++ ++/* blue tooth control PIN */ ++#define GPIO_BT_WAKEUP 28 /* AP wake up bluetooth module */ ++#define GPIO_BT_HOSTWAKE 14 /* AP wake up bluetooth module */ ++#define GPIO_BT_RESET 48 /* AP reset bluetooth module */ ++ ++/* control LCD high - OFF low -- ON */ ++#define GPIO_LCD_OFF 116 /* control LCD */ ++ ++/* FFUART PIN */ ++#define GPIO_ICL_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++ ++#endif ++/* ++ * ezx platform, wake up source edge detect bit ++ */ ++#define PEDR_INT_SEC 1 ++ ++#define GPIO_FLIP_PIN 12 ++/*E680 screen lock button*/ ++ ++#define GPIO_LOCK_SCREEN_PIN GPIO_FLIP_PIN ++ ++/* MMC interface */ ++#define GPIO_MMC_DETECT 11 ++#define GPIO_MMC_CLK 32 ++#define GPIO_MMC_DATA0 92 ++#define GPIO_MMC_WP 107 ++#define GPIO_MMC_DATA1 109 ++#define GPIO_MMC_DATA2 110 ++#define GPIO_MMC_DATA3 111 ++#define GPIO_MMC_CMD 112 ++ ++/* interface function */ ++#define GPIO_MMC_CLK_MD (GPIO_MMC_CLK | GPIO_ALT_FN_2_OUT) ++#define GPIO_MMC_DATA0_MD (GPIO_MMC_DATA0 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++#define GPIO_MMC_DATA1_MD (GPIO_MMC_DATA1 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++#define GPIO_MMC_DATA2_MD (GPIO_MMC_DATA2 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++#define GPIO_MMC_DATA3_MD (GPIO_MMC_DATA3 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++ ++#define GPIO_MMC_CMD_MD (GPIO_MMC_CMD | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) ++ ++/* EMU GPIO 119 ---MUX2 120 --- MUX1 */ ++#define GPIO_EMU_MUX1 120 ++#define GPIO_EMU_MUX2 119 ++#define GPIO_SNP_INT_CTL 86 ++#define GPIO_SNP_INT_IN 87 ++ ++ ++/* audio related pins */ ++#define AP_13MHZ_OUTPUT_PIN 9 ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++#define GPIO_VA_SEL_BUL 79 ++#define GPIO_FLT_SEL_BUL 80 /* out filter select pin */ ++#define GPIO_MIDI_RESET 78 /* GPIO used by MIDI chipset */ ++#define GPIO_MIDI_CS 33 ++#define GPIO_MIDI_IRQ 15 ++#define GPIO_MIDI_NPWE 49 ++#define GPIO_MIDI_RDY 18 ++#endif ++ ++#ifdef CONFIG_ARCH_EZX_A780 ++#define GPIO_HW_ATTENUATE_A780 96 /* hw noise attenuation be used or bypassed, for receiver or louderspeaker mode */ ++#endif ++ ++ ++/* bp status pin */ ++#define GPIO_BP_STATE 41 ++ ++/* define usb related pin */ ++#define GPIO34_TXENB 34 ++#define GPIO35_XRXD 35 ++#define GPIO36_VMOUT 36 ++#define GPIO39_VPOUT 39 ++#define GPIO40_VPIN 40 ++#define GPIO53_VMIN 53 ++ ++/* USB client 6 pin defination */ ++#define GPIO34_TXENB_MD (GPIO34_TXENB | GPIO_ALT_FN_1_OUT) ++#define GPIO35_XRXD_MD (GPIO35_XRXD | GPIO_ALT_FN_2_IN ) ++#define GPIO36_VMOUT_MD (GPIO36_VMOUT | GPIO_ALT_FN_1_OUT) ++#define GPIO39_VPOUT_MD (GPIO39_VPOUT | GPIO_ALT_FN_1_OUT) ++#define GPIO40_VPIN_MD (GPIO40_VPIN | GPIO_ALT_FN_3_IN ) ++#define GPIO53_VMIN_MD (GPIO53_VMIN | GPIO_ALT_FN_2_IN ) ++ ++#define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++ +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/ezx-pcap.h linux-2.6.16/include/asm-arm/arch-pxa/ezx-pcap.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/ezx-pcap.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/ezx-pcap.h 2006-06-03 11:14:56.898239408 +0200 +@@ -0,0 +1,665 @@ ++/* (c) Copyright Motorola Beijing 2002 all rights reserved. ++ ++ Project Name : EZX ++ Project No. : ++ Title : ++ File Name : ++ Description : ++ ++ ************** REVISION HISTORY ********************************************** ++ Date Author Reference ++ ======== ========== ========================== ++ 2002-07-01 weiqiang lin create ++*/ ++#ifndef SSP_PCAP_H ++#define SSP_PCAP_H ++ ++#define SSP_vibrate_start_command() SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) ++ ++#define SSP_vibrate_stop_command() SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) ++ ++#define SSP_PCAP_REGISTER_VALUE_LENGTH 16 ++ ++#define SSP_PCAP_REGISTER_WRITE_OP_BIT 0x80000000 ++#define SSP_PCAP_REGISTER_READ_OP_BIT 0x00000000 ++ ++#define SSP_PCAP_REGISTER_VALUE_UP_WORD_MASK 0xffff0000 ++#define SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK 0x0000ffff ++ ++#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff ++#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff ++#define SSP_PCAP_REGISTER_ADDRESS_MASK 0x7c000000 ++#define SSP_PCAP_REGISTER_ADDRESS_SHIFT 26 ++#define SSP_PCAP_REGISTER_NUMBER 32 ++ ++#define SSP_PCAP_ADC_START_VALUE_SET_MASK 0xfffffc00 ++#define SSP_PCAP_ADC_START_VALUE 0x000001dd ++ ++ ++#define SSP_PCAP_PHONE_CDC_CLOCK_MASK 0x000001c0 ++#define SSP_PCAP_STEREO_SAMPLE_RATE_MASK 0x00000f00 ++#define SSP_PCAP_STEREO_BCLK_TIME_SLOT_MASK 0x00018000 ++#define SSP_PCAP_STEREO_CLOCK_MASK 0x0000001c ++#define SSP_PCAP_DIGITAL_AUDIO_MODE_MASK 0x00006000 ++#define SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK 0x000e0000 ++#define SSP_PCAP_MONO_PGA_MASK 0x00180000 ++ ++#define SSP_PCAP_VIBRATOR_VOLTAGE_LEVEL_MASK 0x00300000 ++ ++#define SSP_PCAP_AUDIO_IN_GAIN_MASK 0x0000001f ++#define SSP_PCAP_AUDIO_IN_GAIN_SHIFT 0 ++#define SSP_PCAP_AUDIO_OUT_GAIN_MASK 0x0001e000 ++#define SSP_PCAP_AUDIO_OUT_GAIN_SHIFT 13 ++ ++ ++#define SSP_PCAP_ADD1_VALUE_MASK 0x000003ff ++#define SSP_PCAP_ADD1_VALUE_SHIFT 0 ++#define SSP_PCAP_ADD2_VALUE_MASK 0x000ffc00 ++#define SSP_PCAP_ADD2_VALUE_SHIFT 10 ++ ++ ++#define PCAP_AUDIO_IN_GAIN_MAX_VALUE 31 ++#define PCAP_AUDIO_OUT_GAIN_MAX_VALUE 15 ++ ++#define PCAP_CLEAR_INTERRUPT_REGISTER 0x00141fdf ++#define PCAP_MASK_ALL_INTERRUPT 0x0013ffff ++ ++#define SSP_PCAP_TS_KEEPER_TIMER 100 /* 1 second */ ++#define START_ADC_DELAY_TIMER 1991 /* 540 us */ ++ ++#define SSP_SEND_PM_ALART_INTERVAL 1000 *HZ/1000 /* 1 second */ ++#define SSP_SEND_MSG_USB_ACCESSORY_INFO_DEBOUNCE 200 *HZ/1000 /* 200ms */ ++ ++struct ssp_interrupt_info ++{ ++ u32 type; ++ u32 status; ++ void* privdata; ++}; ++ ++#ifndef U8 ++#define U8 unsigned char ++#endif ++ ++#ifndef U32 ++#define U32 unsigned long ++#endif ++ ++#ifndef U16 ++#define U16 unsigned short ++#endif ++ ++#ifndef P_U16 ++#define P_U16 U16* ++#endif ++ ++#ifndef P_U32 ++#define P_U32 U32* ++#endif ++ ++#define SSP_SELECT_BUFFER (volatile unsigned long *)(0xf4000000) ++ ++#define SSP_SR_RNE 0x00000008 ++#define SSP_PCAP_BASE 0x00001000 ++/************************ STRUCTURES, ENUMS, AND TYPEDEFS **************************/ ++typedef enum accessoryStatus ++{ ++ ACCESSORY_DEVICE_STATUS_DETACHED = 0, ++ ACCESSORY_DEVICE_STATUS_ATTACHED , ++ ACCESSORY_DEVICE_STATUS_UNKNOW =0x000000ff ++}ACCESSORY_DEVICE_STATUS; ++ ++typedef enum accessoryType ++{ ++ ACCESSORY_DEVICE_NONE = 0, ++ ACCESSORY_DEVICE_SERIAL_PORT , ++ ACCESSORY_DEVICE_USB_PORT , ++ ACCESSORY_DEVICE_UNKNOW =0x000000ff ++}ACCESSORY_TYPE; ++ ++typedef enum pcapReturnStatus ++{ ++ SSP_PCAP_SUCCESS = 0, ++ SSP_PCAP_ERROR_REGISTER = SSP_PCAP_BASE+1, ++ SSP_PCAP_ERROR_VALUE = SSP_PCAP_BASE+2, ++ ++ SSP_PCAP_NOT_RUN = SSP_PCAP_BASE+0xff ++}SSP_PCAP_STATUS; ++ ++typedef enum pcapPortType ++{ ++ SSP_PCAP_SERIAL_PORT = 0x00000000, ++ SSP_PCAP_LOW_USB_PORT = 0x00000001, ++ SSP_PCAP_HIGH_USB_PORT = 0x00000002, ++ SSP_PCAP_UNKNOW_PORT = 0x000000ff ++}SSP_PCAP_PORT_TYPE; ++ ++typedef enum pcapInitDriverType ++{ ++ SSP_PCAP_TS_OPEN = 0x00000000, ++ SSP_PCAP_AUDIO_OPEN = 0x00000001, ++ SSP_PCAP_UNKNOW_DRIVER_OPEN = 0x000000ff ++}SSP_PCAP_INIT_DRIVER_TYPE; ++ ++ ++typedef enum pcapReturnBitStatus ++{ ++ SSP_PCAP_BIT_ZERO = 0x00000000, ++ SSP_PCAP_BIT_ONE = 0x00000001, ++ SSP_PCAP_BIT_ERROR = 0xff000000 ++}SSP_PCAP_BIT_STATUS; ++ ++typedef enum pcapCDCClkType ++{ ++ PCAP_CDC_CLK_IN_13M0 = 0x00000000, ++ PCAP_CDC_CLK_IN_15M36 = 0x00000040, ++ PCAP_CDC_CLK_IN_16M8 = 0x00000080, ++ PCAP_CDC_CLK_IN_19M44 = 0x000000c0, ++ PCAP_CDC_CLK_IN_26M0 = 0x00000100 ++}PHONE_CDC_CLOCK_TYPE; ++ ++typedef enum pcapST_SR ++{ ++ PCAP_ST_SAMPLE_RATE_8K = 0x00000000, ++ PCAP_ST_SAMPLE_RATE_11K = 0x00000100, ++ PCAP_ST_SAMPLE_RATE_12K = 0x00000200, ++ PCAP_ST_SAMPLE_RATE_16K = 0x00000300, ++ PCAP_ST_SAMPLE_RATE_22K = 0x00000400, ++ PCAP_ST_SAMPLE_RATE_24K = 0x00000500, ++ PCAP_ST_SAMPLE_RATE_32K = 0x00000600, ++ PCAP_ST_SAMPLE_RATE_44K = 0x00000700, ++ PCAP_ST_SAMPLE_RATE_48K = 0x00000800 ++}ST_SAMPLE_RATE_TYPE; ++ ++typedef enum pcapST_BCLK ++{ ++ PCAP_ST_BCLK_SLOT_16 = 0x00000000, ++ PCAP_ST_BCLK_SLOT_8 = 0x00008000, ++ PCAP_ST_BCLK_SLOT_4 = 0x00010000, ++ PCAP_ST_BCLK_SLOT_2 = 0x00018000, ++}ST_BCLK_TIME_SLOT_TYPE; ++ ++typedef enum pcapST_CLK ++{ ++ PCAP_ST_CLK_PLL_CLK_IN_13M0 = 0x00000000, ++ PCAP_ST_CLK_PLL_CLK_IN_15M36 = 0x00000004, ++ PCAP_ST_CLK_PLL_CLK_IN_16M8 = 0x00000008, ++ PCAP_ST_CLK_PLL_CLK_IN_19M44 = 0x0000000c, ++ PCAP_ST_CLK_PLL_CLK_IN_26M0 = 0x00000010, ++ PCAP_ST_CLK_PLL_CLK_IN_EXT_MCLK = 0x00000014, ++ PCAP_ST_CLK_PLL_CLK_IN_FSYNC = 0x00000018, ++ PCAP_ST_CLK_PLL_CLK_IN_BITCLK = 0x0000001c ++}ST_CLK_TYPE; ++ ++typedef enum pcapDigitalAudioInterfaceMode ++{ ++ PCAP_DIGITAL_AUDIO_INTERFACE_NORMAL = 0x00000000, ++ PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK = 0x00002000, ++ PCAP_DIGITAL_AUDIO_INTERFACE_I2S = 0x00004000 ++}DIG_AUD_MODE_TYPE; ++ ++typedef enum pcapMono ++{ ++ PCAP_MONO_PGA_R_L_STEREO = 0x00000000, ++ PCAP_MONO_PGA_RL = 0x00080000, ++ PCAP_MONO_PGA_RL_3DB = 0x00100000, ++ PCAP_MONO_PGA_RL_6DB = 0x00180000 ++}MONO_TYPE; ++ ++typedef enum pcapVibratorVoltageLevel ++{ ++ PCAP_VIBRATOR_VOLTAGE_LEVEL0 = 0x00000000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL1 = 0x00100000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL2 = 0x00200000, ++ PCAP_VIBRATOR_VOLTAGE_LEVEL3 = 0x00300000 ++}VibratorVoltageLevel_TYPE; ++ ++typedef enum pcapTouchScreenMode ++{ ++ PCAP_TS_POSITION_X_MEASUREMENT = 0x00000000, ++ PCAP_TS_POSITION_XY_MEASUREMENT = 0x00020000, ++ PCAP_TS_PRESSURE_MEASUREMENT = 0x00040000, ++ PCAP_TS_PLATE_X_MEASUREMENT = 0x00060000, ++ PCAP_TS_PLATE_Y_MEASUREMENT = 0x00080000, ++ PCAP_TS_STANDBY_MODE = 0x000a0000, ++ PCAP_TS_NONTS_MODE = 0x000c0000 ++}TOUCH_SCREEN_DETECT_TYPE; ++ ++typedef enum pcapADJRegister ++{ ++ SSP_PCAP_ADJ_ISR_REGISTER = 0x00, ++ SSP_PCAP_ADJ_MSR_REGISTER = 0x01, ++ SSP_PCAP_ADJ_PSTAT_REGISTER = 0x02, ++ SSP_PCAP_ADJ_VREG2_REGISTER = 0x06, ++ SSP_PCAP_ADJ_AUX_VREG_REGISTER = 0x07, ++ SSP_PCAP_ADJ_BATT_DAC_REGISTER = 0x08, ++ SSP_PCAP_ADJ_ADC1_REGISTER = 0x09, ++ SSP_PCAP_ADJ_ADC2_REGISTER = 0x0a, ++ SSP_PCAP_ADJ_AUD_CODEC_REGISTER = 0x0b, ++ SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER = 0x0c, ++ SSP_PCAP_ADJ_ST_DAC_REGISTER = 0x0d, ++ SSP_PCAP_ADJ_BUSCTRL_REGISTER = 0x14, ++ SSP_PCAP_ADJ_PERIPH_REGISTER = 0x15, ++ SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER = 0x18, ++ SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER = 0x1a, ++ SSP_PCAP_ADJ_GP_REG_REGISTER = 0x1b ++}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER; ++ ++typedef enum pcapADJBit_SetType ++{ ++ SSP_PCAP_ADJ_BIT_ISR_ADCDONEI = 0x00000001, ++ SSP_PCAP_ADJ_BIT_ISR_TSI = 0x00000002, ++ SSP_PCAP_ADJ_BIT_ISR_1HZI = 0x00000004, ++ SSP_PCAP_ADJ_BIT_ISR_WHI = 0x00000008, ++ SSP_PCAP_ADJ_BIT_ISR_WLI = 0x00000010, ++ SSP_PCAP_ADJ_BIT_ISR_TODAI = 0x00000020, ++ SSP_PCAP_ADJ_BIT_ISR_USB4VI = 0x00000040, ++ SSP_PCAP_ADJ_BIT_ISR_ONOFFI = 0x00000080, ++ SSP_PCAP_ADJ_BIT_ISR_ONOFF2I = 0x00000100, ++ SSP_PCAP_ADJ_BIT_ISR_USB1VI = 0x00000200, ++ SSP_PCAP_ADJ_BIT_ISR_MOBPORTI = 0x00000400, ++ SSP_PCAP_ADJ_BIT_ISR_MB2I = 0x00000800, ++ SSP_PCAP_ADJ_BIT_ISR_A1I = 0x00001000, ++ SSP_PCAP_ADJ_BIT_ISR_STI = 0x00002000, ++ SSP_PCAP_ADJ_BIT_ISR_PCI = 0x00004000, ++ SSP_PCAP_ADJ_BIT_ISR_WARMI = 0x00008000, ++ SSP_PCAP_ADJ_BIT_ISR_EOLI = 0x00010000, ++ SSP_PCAP_ADJ_BIT_ISR_CLKI = 0x00020000, ++ SSP_PCAP_ADJ_BIT_ISR_SYS_RSTI = 0x00040000, ++ SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I = 0x00100000, ++ SSP_PCAP_ADJ_BIT_ISR_SOFT_RESETI = 0x00200000, ++ SSP_PCAP_ADJ_BIT_ISR_MNEXBI = 0x00400000, ++ ++ SSP_PCAP_ADJ_BIT_MSR_ADCDONEM = 0x04000001, ++ SSP_PCAP_ADJ_BIT_MSR_TSM = 0x04000002, ++ SSP_PCAP_ADJ_BIT_MSR_1HZM = 0x04000004, ++ SSP_PCAP_ADJ_BIT_MSR_WHM = 0x04000008, ++ SSP_PCAP_ADJ_BIT_MSR_WLM = 0x04000010, ++ SSP_PCAP_ADJ_BIT_MSR_TODAM = 0x04000020, ++ SSP_PCAP_ADJ_BIT_MSR_USB4VM = 0x04000040, ++ SSP_PCAP_ADJ_BIT_MSR_ONOFFM = 0x04000080, ++ SSP_PCAP_ADJ_BIT_MSR_ONOFF2M = 0x04000100, ++ SSP_PCAP_ADJ_BIT_MSR_USB1VM = 0x04000200, ++ SSP_PCAP_ADJ_BIT_MSR_MOBPORTM = 0x04000400, ++ SSP_PCAP_ADJ_BIT_MSR_MB2M = 0x04000800, ++ SSP_PCAP_ADJ_BIT_MSR_A1M = 0x04001000, ++ SSP_PCAP_ADJ_BIT_MSR_STM = 0x04002000, ++ SSP_PCAP_ADJ_BIT_MSR_PCM = 0x04004000, ++ SSP_PCAP_ADJ_BIT_MSR_WARMM = 0x04008000, ++ SSP_PCAP_ADJ_BIT_MSR_EOLM = 0x04010000, ++ SSP_PCAP_ADJ_BIT_MSR_CLKM = 0x04020000, ++ SSP_PCAP_ADJ_BIT_MSR_SYS_RSTM = 0x04040000, ++ SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M = 0x04100000, ++ SSP_PCAP_ADJ_BIT_MSR_SOFT_RESETM = 0x04200000, ++ SSP_PCAP_ADJ_BIT_MSR_MNEXBM = 0x04400000, ++ ++ SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V = 0x08000040, ++ SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS = 0x08000080, ++ SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS2 = 0x08000100, ++ SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V = 0x08000200, ++ SSP_PCAP_ADJ_BIT_PSTAT_MOBSENSB = 0x08000400, ++ SSP_PCAP_ADJ_BIT_PSTAT_MB2SNS = 0x08000800, ++ SSP_PCAP_ADJ_BIT_PSTAT_A1SNS = 0x08001000, ++ SSP_PCAP_ADJ_BIT_PSTAT_MSTB = 0x08002000, ++ SSP_PCAP_ADJ_BIT_PSTAT_EOL_STAT = 0x08010000, ++ SSP_PCAP_ADJ_BIT_PSTAT_CLK_STAT = 0x08020000, ++ SSP_PCAP_ADJ_BIT_PSTAT_SYS_RST = 0x08040000, ++ SSP_PCAP_ADJ_BIT_PSTAT_BATTFBSNS = 0x08080000, ++ SSP_PCAP_ADJ_BIT_PSTAT_BATT_DET_IN_SNS = 0x08200000, ++ SSP_PCAP_ADJ_BIT_PSTAT_MNEXBSNS = 0x08400000, ++ SSP_PCAP_ADJ_BIT_PSTAT_WARM_SYS_RST = 0x08800000, ++ ++ SSP_PCAP_ADJ_BIT_VREG2_V1_STBY = 0x18000001, ++ SSP_PCAP_ADJ_BIT_VREG2_V2_STBY = 0x18000002, ++ SSP_PCAP_ADJ_BIT_VREG2_V3_STBY = 0x18000004, ++ SSP_PCAP_ADJ_BIT_VREG2_V4_STBY = 0x18000008, ++ SSP_PCAP_ADJ_BIT_VREG2_V5_STBY = 0x18000010, ++ SSP_PCAP_ADJ_BIT_VREG2_V6_STBY = 0x18000020, ++ SSP_PCAP_ADJ_BIT_VREG2_V7_STBY = 0x18000040, ++ SSP_PCAP_ADJ_BIT_VREG2_V8_STBY = 0x18000080, ++ SSP_PCAP_ADJ_BIT_VREG2_V9_STBY = 0x18000100, ++ SSP_PCAP_ADJ_BIT_VREG2_V10_STBY = 0x18000200, ++ SSP_PCAP_ADJ_BIT_VREG2_V1_LOWPWR = 0x18000400, ++ SSP_PCAP_ADJ_BIT_VREG2_V2_LOWPWR = 0x18000800, ++ SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR = 0x18001000, ++ SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR = 0x18002000, ++ SSP_PCAP_ADJ_BIT_VREG2_V5_LOWPWR = 0x18004000, ++ SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR = 0x18008000, ++ SSP_PCAP_ADJ_BIT_VREG2_V7_LOWPWR = 0x18010000, ++ SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR = 0x18020000, ++ SSP_PCAP_ADJ_BIT_VREG2_V9_LOWPWR = 0x18040000, ++ SSP_PCAP_ADJ_BIT_VREG2_V10_LOWPWR = 0x18080000, ++ ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_EN = 0x1c000002, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_0 = 0x1c000004, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_1 = 0x1c000008, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN = 0x1c000010, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0 = 0x1c000020, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1 = 0x1c000040, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN = 0x1c000080, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_0 = 0x1c000100, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_1 = 0x1c000200, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_2 = 0x1c000400, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_3 = 0x1c000800, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_EN = 0x1c001000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_0 = 0x1c002000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_1 = 0x1c004000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM2_EN = 0x1c010000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_EN = 0x1c020000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_0 = 0x1c040000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN = 0x1c080000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_0 = 0x1c100000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_1 = 0x1c200000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_STBY = 0x1c400000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_LOWPWR = 0x1c800000, ++ SSP_PCAP_ADJ_BIT_AUX_VREG_SW3_STBY = 0x1d000000, ++ ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC0 = 0x20000001, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC1 = 0x20000002, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC2 = 0x20000004, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC3 = 0x20000008, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC4 = 0x20000010, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC5 = 0x20000020, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC6 = 0x20000040, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_DAC7 = 0x20000080, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_B_FDBK = 0x20000100, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EXT_ISENSE = 0x20000200, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN0 = 0x20000400, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN1 = 0x20000800, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN2 = 0x20001000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN3 = 0x20002000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_I_COIN = 0x20004000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_COIN_CH_EN = 0x20008000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL0 = 0x20020000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL1 = 0x20040000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL2 = 0x20080000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_CMP_EN = 0x20100000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_BATT_DET_EN = 0x20200000, ++ SSP_PCAP_ADJ_BIT_BATT_DAC_THERMBIAS_CTRL = 0x20400000, ++ ++ SSP_PCAP_ADJ_BIT_ADC1_ADEN = 0x24000001, ++ SSP_PCAP_ADJ_BIT_ADC1_RAND = 0x24000002, ++ SSP_PCAP_ADJ_BIT_ADC1_AD_SEL1 = 0x24000004, ++ SSP_PCAP_ADJ_BIT_ADC1_AD_SEL2 = 0x24000008, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA10 = 0x24000010, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA11 = 0x24000020, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA12 = 0x24000040, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA20 = 0x24000080, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA21 = 0x24000100, ++ SSP_PCAP_ADJ_BIT_ADC1_ADA22 = 0x24000200, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO0 = 0x24000400, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO1 = 0x24000800, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO2 = 0x24001000, ++ SSP_PCAP_ADJ_BIT_ADC1_ATO3 = 0x24002000, ++ SSP_PCAP_ADJ_BIT_ADC1_ATOX = 0x24004000, ++ SSP_PCAP_ADJ_BIT_ADC1_MTR1 = 0x24008000, ++ SSP_PCAP_ADJ_BIT_ADC1_MTR2 = 0x24010000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M0 = 0x24020000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M1 = 0x24040000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_M2 = 0x24080000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR = 0x24100000, ++ SSP_PCAP_ADJ_BIT_ADC1_TS_REFENB = 0x24200000, ++ SSP_PCAP_ADJ_BIT_ADC1_BATT_I_POLARITY = 0x24400000, ++ SSP_PCAP_ADJ_BIT_ADC1_BATT_I_ADC = 0x24800000, ++ ++ SSP_PCAP_ADJ_BIT_ADC2_ADD10 = 0x28000001, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD11 = 0x28000002, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD12 = 0x28000004, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD13 = 0x28000008, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD14 = 0x28000010, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD15 = 0x28000020, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD16 = 0x28000040, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD17 = 0x28000080, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD18 = 0x28000100, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD19 = 0x28000200, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD20 = 0x28000400, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD21 = 0x28000800, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD22 = 0x28001000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD23 = 0x28002000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD24 = 0x28004000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD25 = 0x28008000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD26 = 0x28010000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD27 = 0x28020000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD28 = 0x28040000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADD29 = 0x28080000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADINC1 = 0x28100000, ++ SSP_PCAP_ADJ_BIT_ADC2_ADINC2 = 0x28200000, ++ SSP_PCAP_ADJ_BIT_ADC2_ASC = 0x28400000, ++ ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF = 0x2c000001, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB = 0x2c000002, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF = 0x2c000004, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS = 0x2c000008, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DLM = 0x2c000010, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH = 0x2c000020, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK0 = 0x2c000040, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK1 = 0x2c000080, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK2 = 0x2c000100, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV = 0x2c000200, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV = 0x2c000400, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET = 0x2c000800, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN = 0x2c001000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN = 0x2c002000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K = 0x2c004000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN = 0x2c008000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL = 0x2c010000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2_MUX = 0x2c020000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG0 = 0x2c040000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG1 = 0x2c080000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG2 = 0x2c100000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG3 = 0x2c200000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG4 = 0x2c400000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG_PRI_ADJ = 0x2c800000, ++ SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_PRI_ADJ = 0x2c200000, ++ ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN = 0x30000001, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN = 0x30000002, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A4_EN = 0x30000010, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN = 0x30000020, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN = 0x30000040, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP = 0x30000080, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW = 0x30000100, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW = 0x30000200, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW = 0x30000400, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN = 0x30000800, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN = 0x30001000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG0 = 0x30002000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG1 = 0x30004000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG2 = 0x30008000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG3 = 0x30010000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL = 0x30020000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO0 = 0x30080000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO1 = 0x30100000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG_PRI_ADJ = 0x30200000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO_PRI_ADJ = 0x30400000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ0 = 0x30800000, ++ SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ1 = 0x31000000, ++ ++ SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC = 0x34000001, ++ SSP_PCAP_ADJ_BIT_ST_DAC_STDET_EN = 0x34000002, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK0 = 0x34000004, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK1 = 0x34000008, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK2 = 0x34000010, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN = 0x34000020, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC = 0x34000040, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN = 0x34000080, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR0 = 0x34000100, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR1 = 0x34000200, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR2 = 0x34000400, ++ SSP_PCAP_ADJ_BIT_ST_DAC_SR3 = 0x34000800, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC = 0x34001000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS0 = 0x34002000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS1 = 0x34004000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_BCLK0 = 0x34008000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_BCLK1 = 0x34010000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV = 0x34020000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV = 0x34040000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL = 0x34080000, ++ SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_PRI_ADJ = 0x35000000, ++ ++ SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB = 0x50000001, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_SUSPEND = 0x50000002, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU = 0x50000004, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD = 0x50000008, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN = 0x50000010, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS = 0x50000020, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_MSTR_EN = 0x50000040, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_VBUS_PD_ENB = 0x50000080, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_CURRLIM = 0x50000100, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB = 0x50000200, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR = 0x50000400, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_SE0_CONN = 0x50000800, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PDM = 0x50001000, ++ SSP_PCAP_ADJ_BIT_BUSCTRL_BUS_PRI_ADJ = 0x51000000, ++ ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0 = 0x54000001, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1 = 0x54000002, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2 = 0x54000004, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3 = 0x54000008, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4 = 0x54000010, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_EN = 0x54000020, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_EN = 0x54000040, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL0 = 0x54000080, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL1 = 0x54000100, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL2 = 0x54000200, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL3 = 0x54000400, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL0 = 0x54000800, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL1 = 0x54001000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL2 = 0x54002000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL3 = 0x54004000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I0 = 0x54008000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I1 = 0x54010000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I0 = 0x54020000, ++ SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I1 = 0x54040000, ++ SSP_PCAP_ADJ_BIT_PERIPH_SKIP = 0x54080000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0 = 0x54100000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1 = 0x54200000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2 = 0x54400000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3 = 0x54800000, ++ SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4 = 0x55000000, ++ ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY = 0x60000001, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR = 0x60000002, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_STBY = 0x60000004, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_LOWPWR = 0x60000008, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_STBY = 0x60000010, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_LOWPWR = 0x60000020, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM_LOWPWR = 0x60000040, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM2_LOWPWR = 0x60000080, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00 = 0x60000100, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01 = 0x60000200, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10 = 0x60000400, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11 = 0x60000800, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS = 0x60001000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS = 0x60002000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS = 0x60004000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS = 0x60008000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE00 = 0x60010000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE01 = 0x60020000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE10 = 0x60040000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE11 = 0x60080000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW20_DVS = 0x60100000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW21_DVS = 0x60200000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW22_DVS = 0x60400000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW23_DVS = 0x60800000, ++ SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY = 0x61000000, ++ ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG0 = 0x68000001, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG1 = 0x68000002, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG2 = 0x68000004, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG3 = 0x68000008, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG4 = 0x68000010, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN = 0x68000020, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX = 0x68000040, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN = 0x68000080, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX = 0x68000100, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX = 0x68000200, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2 = 0x68000400, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1 = 0x68000800, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1ID_TX = 0x68001000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1_CONFIG = 0x68002000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG = 0x68004000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A2_CONFIG = 0x68008000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR = 0x68080000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_STBY = 0x68100000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2 = 0x68200000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG_PRI_ADJ = 0x68400000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ0 = 0x68800000, ++ SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ1 = 0x69000000, ++ ++ SSP_PCAP_ADJ_BIT_SYS_RST_CLR = 0x6c000001, ++ SSP_PCAP_ADJ_BIT_SYS_RST_MODE0 = 0x6c000002, ++ SSP_PCAP_ADJ_BIT_SYS_RST_MODE1 = 0x6c000004, ++ SSP_PCAP_ADJ_BIT_SYS_VFLASH_0 = 0x6c000008, ++ SSP_PCAP_ADJ_BIT_SYS_VFLASH_1 = 0x6c000010, ++ SSP_PCAP_ADJ_BIT_SYS_MID_SELECT = 0x6c000020, ++ SSP_PCAP_ADJ_BIT_SYS_MID_FET = 0x6c000040, ++ SSP_PCAP_ADJ_BIT_SYS_MAIN_LOW = 0x6c000080, ++ SSP_PCAP_ADJ_BIT_SYS_BATTFB_DIS = 0x6c000100, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG9 = 0x6c000200, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG10 = 0x6c000400, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG11 = 0x6c000800, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG12 = 0x6c001000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG13 = 0x6c002000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG14 = 0x6c004000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG15 = 0x6c008000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG16 = 0x6c010000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG17 = 0x6c020000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG18 = 0x6c040000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG19 = 0x6c080000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG20 = 0x6c100000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG21 = 0x6c200000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG22 = 0x6c400000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG23 = 0x6c800000, ++ SSP_PCAP_ADJ_BIT_SYS_GP_REG24 = 0x6d000000 ++ ++}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE; ++ ++/************************ FUNCTION PROTOTYPES **************************************/ ++extern void ssp_pcap_init(void); ++extern void ssp_pcap_release(void); ++ ++extern void ssp_pcap_open(SSP_PCAP_INIT_DRIVER_TYPE portType); ++extern void ssp_pcap_close(void); ++ ++extern void ssp_pcap_intoSleep_callBack(void); ++extern void ssp_pcap_wakeUp_callBack(void); ++ ++ ++extern SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,U32 ssp_pcap_register_value); ++extern SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,P_U32 p_ssp_pcap_register_value); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; ++extern U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register ) ; ++ ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_mode_set(TOUCH_SCREEN_DETECT_TYPE mode_Type ); ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_start_XY_read(void); ++extern SSP_PCAP_STATUS SSP_PCAP_TSI_get_XY_value(P_U16 p_x,P_U16 p_y); ++extern SSP_PCAP_STATUS SSP_PCAP_CDC_CLK_set(PHONE_CDC_CLOCK_TYPE clkType); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_CDC_SR_set(ST_SAMPLE_RATE_TYPE srType); ++extern SSP_PCAP_STATUS SSP_PCAP_BCLK_set(ST_BCLK_TIME_SLOT_TYPE bclkType); ++extern SSP_PCAP_STATUS SSP_PCAP_STCLK_set(ST_CLK_TYPE stClkType); ++extern SSP_PCAP_STATUS SSP_PCAP_DIG_AUD_FS_set(DIG_AUD_MODE_TYPE fsType); ++extern SSP_PCAP_STATUS SSP_PCAP_AUDIG_set(U32 audioInGain); ++extern SSP_PCAP_STATUS SSP_PCAP_MONO_set(MONO_TYPE monoType); ++extern SSP_PCAP_STATUS SSP_PCAP_AUDOG_set(U32 audioOutGain); ++ ++extern SSP_PCAP_STATUS SSP_PCAP_V_VIB_level_set(VibratorVoltageLevel_TYPE VIBLevelType); ++extern SSP_PCAP_STATUS SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_PORT_TYPE portType); ++extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_audio_in_status(void); ++ ++/* for log */ ++extern void pcap_log_add_pure_data(u8* pData,u32 len); ++extern void pcap_log_add_data(u8* pData,u32 len); ++ ++/* screen lock on/off handler */ ++extern void ssp_pcap_screenlock_lock(u32 data); ++extern void ssp_pcap_screenlock_unlock(u32 data); ++ ++#endif +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/hardware.h linux-2.6.16/include/asm-arm/arch-pxa/hardware.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/hardware.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/hardware.h 2006-06-03 11:14:56.256336992 +0200 +@@ -62,6 +62,7 @@ + + #ifndef __ASSEMBLY__ + ++#include <asm/arch-pxa/ezx-compat.h> + /* + * Handy routine to set GPIO alternate functions + */ +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/irqs.h linux-2.6.16/include/asm-arm/arch-pxa/irqs.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/irqs.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/irqs.h 2006-06-03 11:14:57.127204600 +0200 +@@ -176,7 +176,8 @@ + #elif defined(CONFIG_SHARP_LOCOMO) + #define NR_IRQS (IRQ_LOCOMO_SPI_TEND + 1) + #elif defined(CONFIG_ARCH_LUBBOCK) || \ +- defined(CONFIG_MACH_MAINSTONE) ++ defined(CONFIG_MACH_MAINSTONE) || \ ++ defined(CONFIG_PXA_EZX) + #define NR_IRQS (IRQ_BOARD_END) + #else + #define NR_IRQS (IRQ_BOARD_START) +@@ -217,3 +218,13 @@ + #define IRQ_LOCOMO_GPIO_BASE (IRQ_BOARD_START + 1) + #define IRQ_LOCOMO_LT_BASE (IRQ_BOARD_START + 2) + #define IRQ_LOCOMO_SPI_BASE (IRQ_BOARD_START + 3) ++ ++/* EZX Interrupts (CONFIG_EZX) */ ++#define EZX_IRQ(x) (IRQ_BOARD_START + (x)) ++#define EZX_IRQ_ADCDONE EZX_IRQ(0) /* PCAP */ ++#define EZX_IRQ_TS EZX_IRQ(1) /* PCAP */ ++#define EZX_IRQ_USB4V EZX_IRQ(2) /* PCAP */ ++#define EZX_IRQ_USB1V EZX_IRQ(3) /* PCAP */ ++#define EZX_IRQ_HEADJACK EZX_IRQ(4) /* PCAP */ ++#define EZX_IRQ_MIC EZX_IRQ(5) /* PCAP */ ++#define EZX_IRQ_ADCDONE2 EZX_IRQ(6) /* PCAP */ +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/kbd.h linux-2.6.16/include/asm-arm/arch-pxa/kbd.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/kbd.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/kbd.h 2006-06-03 11:14:56.977227400 +0200 +@@ -0,0 +1,28 @@ ++/* ++ * kbd_pxa.h ++ * ++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#ifndef _KBD_PXA_H_ ++#define _KBD_PXA_H_ ++ ++struct pxakbd_platform_data { ++ int (*init)(void); /* init gpio, etc. */ ++ unsigned int scan_interval; ++ struct { ++ unsigned int rows; ++ unsigned int cols; ++ unsigned char *keycode; ++ } matrix; ++ struct { ++ unsigned int num; ++ unsigned char *keycode; ++ } direct; ++}; ++ ++#endif +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/pxa-regs.h linux-2.6.16/include/asm-arm/arch-pxa/pxa-regs.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/pxa-regs.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/pxa-regs.h 2006-06-03 11:14:57.129204296 +0200 +@@ -856,6 +856,8 @@ + #define UP2OCR_HXOE (1 << 17) /* Host Port 2 Transceiver Output Enable */ + #define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ + ++#define UP3OCR __REG(0x40600024) /* USB Port 3 Output Control register */ ++ + #define UDCCSN(x) __REG2(0x40600100, (x) << 2) + #define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ + #define UDCCSR0_SA (1 << 7) /* Setup Active */ +@@ -1259,6 +1261,7 @@ + #define GPIO33_nCS_5 33 /* chip select 5 */ + #define GPIO34_FFRXD 34 /* FFUART receive */ + #define GPIO34_MMCCS0 34 /* MMC Chip Select 0 */ ++#define GPIO34_USB_P2_2 34 /* USB Port2 Pin 2 */ + #define GPIO35_FFCTS 35 /* FFUART Clear to send */ + #define GPIO36_FFDCD 36 /* FFUART Data carrier detect */ + #define GPIO37_FFDSR 37 /* FFUART data set ready */ +@@ -1371,6 +1374,7 @@ + #define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN) + #define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN) + #define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN) ++#define GPIO22_SCLK2_MD (22 | GPIO_ALT_FN_3_IN) + #define GPIO23_SCLK_MD (23 | GPIO_ALT_FN_2_OUT) + #define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT) + #define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT) +@@ -1381,23 +1385,33 @@ + #define GPIO28_BITCLK_OUT_I2S_MD (28 | GPIO_ALT_FN_1_OUT) + #define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN) + #define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN) ++#define GPIO29_SCLK_MD (29 | GPIO_ALT_FN_3_IN) + #define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT) ++#define GPIO30_USB_P3_2 (30 | GPIO_ALT_FN_3_OUT) + #define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT) + #define GPIO31_SYNC_I2S_MD (31 | GPIO_ALT_FN_1_OUT) + #define GPIO31_SYNC_AC97_MD (31 | GPIO_ALT_FN_2_OUT) ++#define GPIO31_USB_P3_6 (31 | GPIO_ALT_FN_3_OUT) + #define GPIO32_SDATA_IN1_AC97_MD (32 | GPIO_ALT_FN_1_IN) + #define GPIO32_SYSCLK_I2S_MD (32 | GPIO_ALT_FN_1_OUT) + #define GPIO32_MMCCLK_MD ( 32 | GPIO_ALT_FN_2_OUT) + #define GPIO33_nCS_5_MD (33 | GPIO_ALT_FN_2_OUT) + #define GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) ++#define GPIO34_USB_P2_2_MD (34 | GPIO_ALT_FN_1_OUT) + #define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT) + #define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO35_USB_P2_1_MD (35 | GPIO_ALT_FN_2_IN) + #define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN) ++#define GPIO36_USB_P2_4_MD (36 | GPIO_ALT_FN_1_OUT) + #define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN) ++#define GPIO37_SFRM2_MD (37 | GPIO_ALT_FN_2_IN) + #define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN) ++#define GPIO38_STXD2_MD (38 | GPIO_ALT_FN_2_OUT) + #define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT) + #define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO39_USB_P2_6_MD (39 | GPIO_ALT_FN_1_OUT) + #define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT) ++#define GPIO40_USB_P2_5_MD (40 | GPIO_ALT_FN_3_IN) + #define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) + #define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN) + #define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN) +@@ -1422,13 +1436,17 @@ + #define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT) + #define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) + #define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) +-#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) ++#define GPIO52_SCLK3_MD (52 | GPIO_ALT_FN_2_OUT) + #define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT) ++#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) ++#define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) ++#define GPIO53_USB_P2_3_MD (53 | GPIO_ALT_FN_2_IN) + #define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT) + #define GPIO54_nPCE_2_MD (54 | GPIO_ALT_FN_2_OUT) + #define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT) + #define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT) + #define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN) ++#define GPIO56_USB_P3_4 (56 | GPIO_ALT_FN_1_OUT) + #define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN) + #define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT) + #define GPIO59_LDD_1_MD (59 | GPIO_ALT_FN_2_OUT) +@@ -1464,13 +1482,19 @@ + #define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT) + #define GPIO81_NSSP_CLK_OUT (81 | GPIO_ALT_FN_1_OUT) + #define GPIO81_NSSP_CLK_IN (81 | GPIO_ALT_FN_1_IN) ++#define GPIO81_STXD3_MD (81 | GPIO_ALT_FN_1_OUT) + #define GPIO82_NSSP_FRM_OUT (82 | GPIO_ALT_FN_1_OUT) + #define GPIO82_NSSP_FRM_IN (82 | GPIO_ALT_FN_1_IN) + #define GPIO83_NSSP_TX (83 | GPIO_ALT_FN_1_OUT) + #define GPIO83_NSSP_RX (83 | GPIO_ALT_FN_2_IN) ++#define GPIO83_SFRM3_MD (83 | GPIO_ALT_FN_1_IN) + #define GPIO84_NSSP_TX (84 | GPIO_ALT_FN_1_OUT) + #define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN) + #define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT) ++#define GPIO88_SRXD2_MD (88 | GPIO_ALT_FN_2_IN) ++#define GPIO89_SRXD3_MD (89 | GPIO_ALT_FN_1_IN) ++#define GPIO90_USB_P3_5 (90 | GPIO_ALT_FN_2_IN) ++#define GPIO91_USB_P3_1 (91 | GPIO_ALT_FN_2_IN) + #define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT) + #define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT) + #define GPIO109_MMCDAT1_MD (109 | GPIO_ALT_FN_1_OUT) +@@ -1481,6 +1505,7 @@ + #define GPIO112_MMCCMD_MD (112 | GPIO_ALT_FN_1_OUT) + #define GPIO113_I2S_SYSCLK_MD (113 | GPIO_ALT_FN_1_OUT) + #define GPIO113_AC97_RESET_N_MD (113 | GPIO_ALT_FN_2_OUT) ++#define GPIO113_USB_P3_3 (113 | GPIO_ALT_FN_3_IN) + #define GPIO117_I2CSCL_MD (117 | GPIO_ALT_FN_1_OUT) + #define GPIO118_I2CSDA_MD (118 | GPIO_ALT_FN_1_IN) + +@@ -1496,6 +1521,7 @@ + #define PFER __REG(0x40F00014) /* Power Manager GPIO Falling-Edge Detect Enable Register */ + #define PEDR __REG(0x40F00018) /* Power Manager GPIO Edge Detect Status Register */ + #define PCFR __REG(0x40F0001C) /* Power Manager General Configuration Register */ ++#define PGSR(x) (__REG(0x40F00020 + ((unsigned long)(x)/32 * 4))) + #define PGSR0 __REG(0x40F00020) /* Power Manager GPIO Sleep State Register for GP[31-0] */ + #define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */ + #define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */ +@@ -1670,6 +1696,7 @@ + #define SSCR1_RSRE (1 << 20) /* Receive Service Request Enable */ + #define SSCR1_TINTE (1 << 19) /* Receiver Time-out Interrupt enable */ + #define SSCR1_PINTE (1 << 18) /* Peripheral Trailing Byte Interupt Enable */ ++#define SSCR1_IFS (1 << 16) /* Invert Frame Signal */ + #define SSCR1_STRF (1 << 15) /* Select FIFO or EFWR */ + #define SSCR1_EFWR (1 << 14) /* Enable FIFO Write/Read */ + +@@ -2123,6 +2150,11 @@ + #define KPMK_MKP (0x1 << 31) + #define KPAS_SO (0x1 << 31) + #define KPASMKPx_SO (0x1 << 31) ++#define KPAS_RP (0x000000f0) ++#define KPAS_CP (0x0000000f) ++#define KPAS_MUKP (0x7c000000) ++#define KPAS_MUKP_ONE (0x04000000) ++#define KPAS_MUKP_NONE (0x00000000) + + /* + * UHC: USB Host Controller (OHCI-like) register definitions +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/spi.h linux-2.6.16/include/asm-arm/arch-pxa/spi.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/spi.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/spi.h 2006-06-03 11:14:57.144202016 +0200 +@@ -0,0 +1,11 @@ ++#ifndef _PXA_SPI_H ++#define _PXA_SPI_H ++ ++/* board-specific data for one SPI controller */ ++struct pxa_spi_data { ++ int (*init)(unsigned int n); ++}; ++ ++extern void pxa_register_spi(unsigned int n, struct pxa_spi_data *pdata); ++ ++#endif +diff -Nurd linux-2.6.16.orig/include/asm-arm/arch-pxa/uncompress.h linux-2.6.16/include/asm-arm/arch-pxa/uncompress.h +--- linux-2.6.16.orig/include/asm-arm/arch-pxa/uncompress.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/arch-pxa/uncompress.h 2006-06-03 11:14:56.259336536 +0200 +@@ -14,12 +14,12 @@ + #define STUART ((volatile unsigned long *)0x40700000) + #define HWUART ((volatile unsigned long *)0x41600000) + +-#define UART FFUART ++#define UART STUART + + + static __inline__ void putc(char c) + { +- while (!(UART[5] & 0x20)); ++ while (!(UART[5] & 0x40)); + UART[0] = c; + } + +diff -Nurd linux-2.6.16.orig/include/asm-arm/dpm.h linux-2.6.16/include/asm-arm/dpm.h +--- linux-2.6.16.orig/include/asm-arm/dpm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/dpm.h 2006-06-03 11:14:55.903390648 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * include/asm-arm/dpm.h Arch-dependent DPM defines for ARM ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, MontaVista Software <source@mvista.com> ++ * ++ * Based on include/asm-ppc/dpm.h by Robert Paulsen. Copyright (C) ++ * 2002, International Business Machines Corporation, All Rights ++ * Reserved. ++ * */ ++ ++#ifndef __ASM_DPM_H__ ++#define __ASM_DPM_H__ ++ ++#include <asm/arch/dpm.h> ++ ++#endif /* __ASM_DPM_H__ */ +diff -Nurd linux-2.6.16.orig/include/asm-arm/system.h linux-2.6.16/include/asm-arm/system.h +--- linux-2.6.16.orig/include/asm-arm/system.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-arm/system.h 2006-06-03 11:14:55.903390648 +0200 +@@ -169,6 +169,7 @@ + #define switch_to(prev,next,last) \ + do { \ + last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \ ++ dpm_set_os(current->dpm_state); \ + } while (0) + + /* +diff -Nurd linux-2.6.16.orig/include/asm-i386/cpufeature.h linux-2.6.16/include/asm-i386/cpufeature.h +--- linux-2.6.16.orig/include/asm-i386/cpufeature.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/cpufeature.h 2006-06-03 11:14:55.351474552 +0200 +@@ -70,6 +70,7 @@ + #define X86_FEATURE_P3 (3*32+ 6) /* P3 */ + #define X86_FEATURE_P4 (3*32+ 7) /* P4 */ + #define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */ ++#define X86_FEATURE_FXSAVE_LEAK (3*32+10) /* FXSAVE leaks FOP/FIP/FOP */ + + /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ + #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ +diff -Nurd linux-2.6.16.orig/include/asm-i386/dpm-centrino.h linux-2.6.16/include/asm-i386/dpm-centrino.h +--- linux-2.6.16.orig/include/asm-i386/dpm-centrino.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/dpm-centrino.h 2006-06-03 11:14:55.904390496 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * include/asm-i386/dpm-centrino.h DPM defines for Intel Centrino ++ * ++ * 2003 (c) MontaVista Software, Inc. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ */ ++ ++#ifndef __ASM_DPM_CENTRINO_H__ ++#define __ASM_DPM_CENTRINO_H__ ++ ++/* MD operating point parameters */ ++#define DPM_MD_CPU_FREQ 0 /* CPU freq */ ++#define DPM_MD_V 1 /* core voltage */ ++ ++#define DPM_PP_NBR 2 ++ ++#define DPM_PARAM_NAMES \ ++{ "cpu", "v" } ++ ++/* Instances of this structure define valid Innovator operating points for DPM. ++ Voltages are represented in mV, and frequencies are represented in KHz. */ ++ ++struct dpm_md_opt { ++ unsigned int v; /* Target voltage in mV */ ++ unsigned int cpu; /* CPU frequency in KHz */ ++}; ++ ++#endif /* __ASM_DPM_CENTRINO_H__ */ +diff -Nurd linux-2.6.16.orig/include/asm-i386/dpm.h linux-2.6.16/include/asm-i386/dpm.h +--- linux-2.6.16.orig/include/asm-i386/dpm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/dpm.h 2006-06-03 11:14:55.904390496 +0200 +@@ -0,0 +1,86 @@ ++/* ++ * include/asm-i386/dpm.h Platform-dependent DPM defines for x86 ++ * ++ * 2003 (c) MontaVista Software, Inc. This file is licensed under the ++ * terms of the GNU General Public License version 2. This program is ++ * licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ */ ++ ++#ifndef __ASM_DPM_H__ ++#define __ASM_DPM_H__ ++ ++/* ++ * machine dependent operating state ++ * ++ * An operating state is a cpu execution state that has implications for power ++ * management. The DPM will select operating points based largely on the ++ * current operating state. ++ * ++ * DPM_STATES is the number of supported operating states. Valid operating ++ * states are from 0 to DPM_STATES-1 but when setting an operating state the ++ * kernel should only specify a state from the set of "base states" and should ++ * do so by name. During the context switch the new operating state is simply ++ * extracted from current->dpm_state. ++ * ++ * task states: ++ * ++ * APIs that reference task states use the range -(DPM_TASK_STATE_LIMIT + 1) ++ * through +DPM_TASK_STATE_LIMIT. This value is added to DPM_TASK_STATE to ++ * obtain the downward or upward adjusted task state value. The ++ * -(DPM_TASK_STATE_LIMIT + 1) value is interpreted specially, and equates to ++ * DPM_NO_STATE. ++ * ++ * Tasks inherit their task operating states across calls to ++ * fork(). DPM_TASK_STATE is the default operating state for all tasks, and is ++ * inherited from init. Tasks can change (or have changed) their tasks states ++ * using the DPM_SET_TASK_STATE variant of the sys_dpm() system call. */ ++ ++#define DPM_IDLE_TASK_STATE 0 ++#define DPM_IDLE_STATE 1 ++#define DPM_BASE_STATES 2 ++ ++#define DPM_TASK_STATE_LIMIT 4 ++#define DPM_TASK_STATE (DPM_BASE_STATES + DPM_TASK_STATE_LIMIT) ++#define DPM_STATES (DPM_TASK_STATE + DPM_TASK_STATE_LIMIT + 1) ++#define DPM_TASK_STATES (DPM_STATES - DPM_BASE_STATES) ++ ++#define DPM_STATE_NAMES \ ++{ "idle-task", "idle",\ ++ "task-4", "task-3", "task-2", "task-1",\ ++ "task", \ ++ "task+1", "task+2", "task+3", "task+4" \ ++} ++ ++#ifdef CONFIG_DPM_CENTRINO ++#include <asm/dpm-centrino.h> ++#endif ++ ++#ifndef __ASSEMBLER__ ++ ++#include <linux/types.h> ++#include <asm/timex.h> ++ ++#define dpm_time() get_cycles() ++ ++#define dpm_time_to_usec(ticks) ({ \ ++ unsigned long long quot = (unsigned long long) ticks * 10; \ ++ do_div(quot, (unsigned long) (cpu_khz / 100)); \ ++ quot; }) ++ ++/* Board-dependent routines. */ ++ ++struct dpm_opt; ++ ++struct dpm_bd { ++ int (*startup)(void); /* startup */ ++ void (*cleanup)(void); /* terminate */ ++ int (*init_opt)(struct dpm_opt *opt); /* init an opt */ ++ int (*get_opt)(struct dpm_opt *opt); /* get current opt */ ++ int (*set_opt)(struct dpm_md_opt *md_opt); /* set opt */ ++}; ++ ++extern struct dpm_bd dpm_bd; ++ ++#endif /* __ASSEMBLER__ */ ++#endif /* __ASM_DPM_H__ */ +diff -Nurd linux-2.6.16.orig/include/asm-i386/i387.h linux-2.6.16/include/asm-i386/i387.h +--- linux-2.6.16.orig/include/asm-i386/i387.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/i387.h 2006-06-03 11:14:55.351474552 +0200 +@@ -13,6 +13,7 @@ + + #include <linux/sched.h> + #include <linux/init.h> ++#include <linux/kernel_stat.h> + #include <asm/processor.h> + #include <asm/sigcontext.h> + #include <asm/user.h> +@@ -38,17 +39,38 @@ + extern void kernel_fpu_begin(void); + #define kernel_fpu_end() do { stts(); preempt_enable(); } while(0) + ++/* We need a safe address that is cheap to find and that is already ++ in L1 during context switch. The best choices are unfortunately ++ different for UP and SMP */ ++#ifdef CONFIG_SMP ++#define safe_address (__per_cpu_offset[0]) ++#else ++#define safe_address (kstat_cpu(0).cpustat.user) ++#endif ++ + /* + * These must be called with preempt disabled + */ + static inline void __save_init_fpu( struct task_struct *tsk ) + { ++ /* Use more nops than strictly needed in case the compiler ++ varies code */ + alternative_input( +- "fnsave %1 ; fwait ;" GENERIC_NOP2, +- "fxsave %1 ; fnclex", ++ "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4, ++ "fxsave %[fx]\n" ++ "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:", + X86_FEATURE_FXSR, +- "m" (tsk->thread.i387.fxsave) +- :"memory"); ++ [fx] "m" (tsk->thread.i387.fxsave), ++ [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory"); ++ /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception ++ is pending. Clear the x87 state here by setting it to fixed ++ values. safe_address is a random variable that should be in L1 */ ++ alternative_input( ++ GENERIC_NOP8 GENERIC_NOP2, ++ "emms\n\t" /* clear stack tags */ ++ "fildl %[addr]", /* set F?P to defined value */ ++ X86_FEATURE_FXSAVE_LEAK, ++ [addr] "m" (safe_address)); + task_thread_info(tsk)->status &= ~TS_USEDFPU; + } + +diff -Nurd linux-2.6.16.orig/include/asm-i386/pgtable-2level.h linux-2.6.16/include/asm-i386/pgtable-2level.h +--- linux-2.6.16.orig/include/asm-i386/pgtable-2level.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/pgtable-2level.h 2006-06-03 11:14:55.352474400 +0200 +@@ -18,6 +18,9 @@ + #define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval) + #define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) + ++#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) ++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) ++ + #define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte_low, 0)) + #define pte_same(a, b) ((a).pte_low == (b).pte_low) + #define pte_page(x) pfn_to_page(pte_pfn(x)) +diff -Nurd linux-2.6.16.orig/include/asm-i386/pgtable-3level.h linux-2.6.16/include/asm-i386/pgtable-3level.h +--- linux-2.6.16.orig/include/asm-i386/pgtable-3level.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/pgtable-3level.h 2006-06-03 11:14:55.352474400 +0200 +@@ -85,6 +85,26 @@ + #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \ + pmd_index(address)) + ++/* ++ * For PTEs and PDEs, we must clear the P-bit first when clearing a page table ++ * entry, so clear the bottom half first and enforce ordering with a compiler ++ * barrier. ++ */ ++static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ ptep->pte_low = 0; ++ smp_wmb(); ++ ptep->pte_high = 0; ++} ++ ++static inline void pmd_clear(pmd_t *pmd) ++{ ++ u32 *tmp = (u32 *)pmd; ++ *tmp = 0; ++ smp_wmb(); ++ *(tmp + 1) = 0; ++} ++ + static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + pte_t res; +diff -Nurd linux-2.6.16.orig/include/asm-i386/pgtable.h linux-2.6.16/include/asm-i386/pgtable.h +--- linux-2.6.16.orig/include/asm-i386/pgtable.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-i386/pgtable.h 2006-06-03 11:14:55.352474400 +0200 +@@ -204,12 +204,10 @@ + extern unsigned long pg0[]; + + #define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) +-#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) + + /* To avoid harmful races, pmd_none(x) should check only the lower when PAE */ + #define pmd_none(x) (!(unsigned long)pmd_val(x)) + #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +-#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) + #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) + + +@@ -269,7 +267,7 @@ + pte_t pte; + if (full) { + pte = *ptep; +- *ptep = __pte(0); ++ pte_clear(mm, addr, ptep); + } else { + pte = ptep_get_and_clear(mm, addr, ptep); + } +diff -Nurd linux-2.6.16.orig/include/asm-m32r/smp.h linux-2.6.16/include/asm-m32r/smp.h +--- linux-2.6.16.orig/include/asm-m32r/smp.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-m32r/smp.h 2006-06-03 11:14:55.353474248 +0200 +@@ -67,7 +67,8 @@ + #define raw_smp_processor_id() (current_thread_info()->cpu) + + extern cpumask_t cpu_callout_map; +-#define cpu_possible_map cpu_callout_map ++extern cpumask_t cpu_possible_map; ++extern cpumask_t cpu_present_map; + + static __inline__ int hard_smp_processor_id(void) + { +diff -Nurd linux-2.6.16.orig/include/asm-m32r/uaccess.h linux-2.6.16/include/asm-m32r/uaccess.h +--- linux-2.6.16.orig/include/asm-m32r/uaccess.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-m32r/uaccess.h 2006-06-03 11:14:55.354474096 +0200 +@@ -5,17 +5,9 @@ + * linux/include/asm-m32r/uaccess.h + * + * M32R version. +- * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> ++ * Copyright (C) 2004, 2006 Hirokazu Takata <takata at linux-m32r.org> + */ + +-#undef UACCESS_DEBUG +- +-#ifdef UACCESS_DEBUG +-#define UAPRINTK(args...) printk(args) +-#else +-#define UAPRINTK(args...) +-#endif /* UACCESS_DEBUG */ +- + /* + * User space memory access functions + */ +@@ -38,27 +30,29 @@ + #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + + #ifdef CONFIG_MMU ++ + #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) + #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) +-#else +-#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +-#define USER_DS MAKE_MM_SEG(0xFFFFFFFF) +-#endif /* CONFIG_MMU */ +- + #define get_ds() (KERNEL_DS) +-#ifdef CONFIG_MMU + #define get_fs() (current_thread_info()->addr_limit) + #define set_fs(x) (current_thread_info()->addr_limit = (x)) +-#else ++ ++#else /* not CONFIG_MMU */ ++ ++#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) ++#define USER_DS MAKE_MM_SEG(0xFFFFFFFF) ++#define get_ds() (KERNEL_DS) ++ + static inline mm_segment_t get_fs(void) + { +- return USER_DS; ++ return USER_DS; + } + + static inline void set_fs(mm_segment_t s) + { + } +-#endif /* CONFIG_MMU */ ++ ++#endif /* not CONFIG_MMU */ + + #define segment_eq(a,b) ((a).seg == (b).seg) + +@@ -83,9 +77,9 @@ + " subx %0, %0\n" \ + " cmpu %4, %1\n" \ + " subx %0, %5\n" \ +- : "=&r"(flag), "=r"(sum) \ +- : "1"(addr), "r"((int)(size)), \ +- "r"(current_thread_info()->addr_limit.seg), "r"(0) \ ++ : "=&r" (flag), "=r" (sum) \ ++ : "1" (addr), "r" ((int)(size)), \ ++ "r" (current_thread_info()->addr_limit.seg), "r" (0) \ + : "cbit" ); \ + flag; }) + +@@ -113,10 +107,10 @@ + #else + static inline int access_ok(int type, const void *addr, unsigned long size) + { +- extern unsigned long memory_start, memory_end; +- unsigned long val = (unsigned long)addr; ++ extern unsigned long memory_start, memory_end; ++ unsigned long val = (unsigned long)addr; + +- return ((val >= memory_start) && ((val + size) < memory_end)); ++ return ((val >= memory_start) && ((val + size) < memory_end)); + } + #endif /* CONFIG_MMU */ + +@@ -155,39 +149,6 @@ + * accesses to the same area of user memory). + */ + +-extern void __get_user_1(void); +-extern void __get_user_2(void); +-extern void __get_user_4(void); +- +-#ifndef MODULE +-#define __get_user_x(size,ret,x,ptr) \ +- __asm__ __volatile__( \ +- " mv r0, %0\n" \ +- " mv r1, %1\n" \ +- " bl __get_user_" #size "\n" \ +- " mv %0, r0\n" \ +- " mv %1, r1\n" \ +- : "=r"(ret), "=r"(x) \ +- : "0"(ptr) \ +- : "r0", "r1", "r14" ) +-#else /* MODULE */ +-/* +- * Use "jl" instead of "bl" for MODULE +- */ +-#define __get_user_x(size,ret,x,ptr) \ +- __asm__ __volatile__( \ +- " mv r0, %0\n" \ +- " mv r1, %1\n" \ +- " seth lr, #high(__get_user_" #size ")\n" \ +- " or3 lr, lr, #low(__get_user_" #size ")\n" \ +- " jl lr\n" \ +- " mv %0, r0\n" \ +- " mv %1, r1\n" \ +- : "=r"(ret), "=r"(x) \ +- : "0"(ptr) \ +- : "r0", "r1", "r14" ) +-#endif +- + /* Careful: we have to cast the result to the type of the pointer for sign + reasons */ + /** +@@ -208,20 +169,7 @@ + * On error, the variable @x is set to zero. + */ + #define get_user(x,ptr) \ +-({ int __ret_gu; \ +- unsigned long __val_gu; \ +- __chk_user_ptr(ptr); \ +- switch(sizeof (*(ptr))) { \ +- case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ +- case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \ +- case 4: __get_user_x(4,__ret_gu,__val_gu,ptr); break; \ +- default: __get_user_x(X,__ret_gu,__val_gu,ptr); break; \ +- } \ +- (x) = (__typeof__(*(ptr)))__val_gu; \ +- __ret_gu; \ +-}) +- +-extern void __put_user_bad(void); ++ __get_user_check((x),(ptr),sizeof(*(ptr))) + + /** + * put_user: - Write a simple value into user space. +@@ -240,8 +188,7 @@ + * Returns zero on success, or -EFAULT on error. + */ + #define put_user(x,ptr) \ +- __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +- ++ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) + + /** + * __get_user: - Get a simple variable from user space, with less checking. +@@ -264,8 +211,64 @@ + * On error, the variable @x is set to zero. + */ + #define __get_user(x,ptr) \ +- __get_user_nocheck((x),(ptr),sizeof(*(ptr))) ++ __get_user_nocheck((x),(ptr),sizeof(*(ptr))) ++ ++#define __get_user_nocheck(x,ptr,size) \ ++({ \ ++ long __gu_err = 0; \ ++ unsigned long __gu_val; \ ++ might_sleep(); \ ++ __get_user_size(__gu_val,(ptr),(size),__gu_err); \ ++ (x) = (__typeof__(*(ptr)))__gu_val; \ ++ __gu_err; \ ++}) ++ ++#define __get_user_check(x,ptr,size) \ ++({ \ ++ long __gu_err = -EFAULT; \ ++ unsigned long __gu_val = 0; \ ++ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ ++ might_sleep(); \ ++ if (access_ok(VERIFY_READ,__gu_addr,size)) \ ++ __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ ++ (x) = (__typeof__(*(ptr)))__gu_val; \ ++ __gu_err; \ ++}) + ++extern long __get_user_bad(void); ++ ++#define __get_user_size(x,ptr,size,retval) \ ++do { \ ++ retval = 0; \ ++ __chk_user_ptr(ptr); \ ++ switch (size) { \ ++ case 1: __get_user_asm(x,ptr,retval,"ub"); break; \ ++ case 2: __get_user_asm(x,ptr,retval,"uh"); break; \ ++ case 4: __get_user_asm(x,ptr,retval,""); break; \ ++ default: (x) = __get_user_bad(); \ ++ } \ ++} while (0) ++ ++#define __get_user_asm(x, addr, err, itype) \ ++ __asm__ __volatile__( \ ++ " .fillinsn\n" \ ++ "1: ld"itype" %1,@%2\n" \ ++ " .fillinsn\n" \ ++ "2:\n" \ ++ ".section .fixup,\"ax\"\n" \ ++ " .balign 4\n" \ ++ "3: ldi %0,%3\n" \ ++ " seth r14,#high(2b)\n" \ ++ " or3 r14,r14,#low(2b)\n" \ ++ " jmp r14\n" \ ++ ".previous\n" \ ++ ".section __ex_table,\"a\"\n" \ ++ " .balign 4\n" \ ++ " .long 1b,3b\n" \ ++ ".previous" \ ++ : "=&r" (err), "=&r" (x) \ ++ : "r" (addr), "i" (-EFAULT), "0" (err) \ ++ : "r14", "memory") + + /** + * __put_user: - Write a simple value into user space, with less checking. +@@ -287,11 +290,13 @@ + * Returns zero on success, or -EFAULT on error. + */ + #define __put_user(x,ptr) \ +- __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) ++ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) ++ + + #define __put_user_nocheck(x,ptr,size) \ + ({ \ + long __pu_err; \ ++ might_sleep(); \ + __put_user_size((x),(ptr),(size),__pu_err); \ + __pu_err; \ + }) +@@ -308,28 +313,28 @@ + }) + + #if defined(__LITTLE_ENDIAN__) +-#define __put_user_u64(x, addr, err) \ +- __asm__ __volatile__( \ +- " .fillinsn\n" \ +- "1: st %L1,@%2\n" \ +- " .fillinsn\n" \ +- "2: st %H1,@(4,%2)\n" \ +- " .fillinsn\n" \ +- "3:\n" \ +- ".section .fixup,\"ax\"\n" \ +- " .balign 4\n" \ +- "4: ldi %0,%3\n" \ +- " seth r14,#high(3b)\n" \ +- " or3 r14,r14,#low(3b)\n" \ +- " jmp r14\n" \ +- ".previous\n" \ +- ".section __ex_table,\"a\"\n" \ +- " .balign 4\n" \ +- " .long 1b,4b\n" \ +- " .long 2b,4b\n" \ +- ".previous" \ +- : "=&r"(err) \ +- : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ ++#define __put_user_u64(x, addr, err) \ ++ __asm__ __volatile__( \ ++ " .fillinsn\n" \ ++ "1: st %L1,@%2\n" \ ++ " .fillinsn\n" \ ++ "2: st %H1,@(4,%2)\n" \ ++ " .fillinsn\n" \ ++ "3:\n" \ ++ ".section .fixup,\"ax\"\n" \ ++ " .balign 4\n" \ ++ "4: ldi %0,%3\n" \ ++ " seth r14,#high(3b)\n" \ ++ " or3 r14,r14,#low(3b)\n" \ ++ " jmp r14\n" \ ++ ".previous\n" \ ++ ".section __ex_table,\"a\"\n" \ ++ " .balign 4\n" \ ++ " .long 1b,4b\n" \ ++ " .long 2b,4b\n" \ ++ ".previous" \ ++ : "=&r" (err) \ ++ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err) \ + : "r14", "memory") + + #elif defined(__BIG_ENDIAN__) +@@ -353,13 +358,15 @@ + " .long 1b,4b\n" \ + " .long 2b,4b\n" \ + ".previous" \ +- : "=&r"(err) \ +- : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ ++ : "=&r" (err) \ ++ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err) \ + : "r14", "memory") + #else + #error no endian defined + #endif + ++extern void __put_user_bad(void); ++ + #define __put_user_size(x,ptr,size,retval) \ + do { \ + retval = 0; \ +@@ -398,52 +405,8 @@ + " .balign 4\n" \ + " .long 1b,3b\n" \ + ".previous" \ +- : "=&r"(err) \ +- : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ +- : "r14", "memory") +- +-#define __get_user_nocheck(x,ptr,size) \ +-({ \ +- long __gu_err; \ +- unsigned long __gu_val; \ +- __get_user_size(__gu_val,(ptr),(size),__gu_err); \ +- (x) = (__typeof__(*(ptr)))__gu_val; \ +- __gu_err; \ +-}) +- +-extern long __get_user_bad(void); +- +-#define __get_user_size(x,ptr,size,retval) \ +-do { \ +- retval = 0; \ +- __chk_user_ptr(ptr); \ +- switch (size) { \ +- case 1: __get_user_asm(x,ptr,retval,"ub"); break; \ +- case 2: __get_user_asm(x,ptr,retval,"uh"); break; \ +- case 4: __get_user_asm(x,ptr,retval,""); break; \ +- default: (x) = __get_user_bad(); \ +- } \ +-} while (0) +- +-#define __get_user_asm(x, addr, err, itype) \ +- __asm__ __volatile__( \ +- " .fillinsn\n" \ +- "1: ld"itype" %1,@%2\n" \ +- " .fillinsn\n" \ +- "2:\n" \ +- ".section .fixup,\"ax\"\n" \ +- " .balign 4\n" \ +- "3: ldi %0,%3\n" \ +- " seth r14,#high(2b)\n" \ +- " or3 r14,r14,#low(2b)\n" \ +- " jmp r14\n" \ +- ".previous\n" \ +- ".section __ex_table,\"a\"\n" \ +- " .balign 4\n" \ +- " .long 1b,3b\n" \ +- ".previous" \ +- : "=&r"(err), "=&r"(x) \ +- : "r"(addr), "i"(-EFAULT), "0"(err) \ ++ : "=&r" (err) \ ++ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err) \ + : "r14", "memory") + + /* +@@ -453,7 +416,6 @@ + * anything, so this is accurate. + */ + +- + /* + * Copy To/From Userspace + */ +@@ -511,8 +473,9 @@ + " .long 2b,9b\n" \ + " .long 3b,9b\n" \ + ".previous\n" \ +- : "=&r"(__dst), "=&r"(__src), "=&r"(size), "=&r"(__c) \ +- : "0"(to), "1"(from), "2"(size), "3"(size / 4) \ ++ : "=&r" (__dst), "=&r" (__src), "=&r" (size), \ ++ "=&r" (__c) \ ++ : "0" (to), "1" (from), "2" (size), "3" (size / 4) \ + : "r14", "memory"); \ + } while (0) + +@@ -573,8 +536,9 @@ + " .long 2b,7b\n" \ + " .long 3b,7b\n" \ + ".previous\n" \ +- : "=&r"(__dst), "=&r"(__src), "=&r"(size), "=&r"(__c) \ +- : "0"(to), "1"(from), "2"(size), "3"(size / 4) \ ++ : "=&r" (__dst), "=&r" (__src), "=&r" (size), \ ++ "=&r" (__c) \ ++ : "0" (to), "1" (from), "2" (size), "3" (size / 4) \ + : "r14", "memory"); \ + } while (0) + +@@ -676,7 +640,7 @@ + #define copy_from_user(to,from,n) \ + ({ \ + might_sleep(); \ +-__generic_copy_from_user((to),(from),(n)); \ ++ __generic_copy_from_user((to),(from),(n)); \ + }) + + long __must_check strncpy_from_user(char *dst, const char __user *src, +diff -Nurd linux-2.6.16.orig/include/asm-mips/bitops.h linux-2.6.16/include/asm-mips/bitops.h +--- linux-2.6.16.orig/include/asm-mips/bitops.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-mips/bitops.h 2006-06-03 11:14:55.355473944 +0200 +@@ -654,7 +654,12 @@ + { + #ifdef CONFIG_32BIT + #ifdef CONFIG_CPU_MIPS32 +- __asm__ ("clz %0, %1" : "=r" (word) : "r" (word)); ++ __asm__ ( ++ " .set mips32 \n" ++ " clz %0, %1 \n" ++ " .set mips0 \n" ++ : "=r" (word) ++ : "r" (word)); + + return 32 - word; + #else +@@ -678,7 +683,12 @@ + #ifdef CONFIG_64BIT + #ifdef CONFIG_CPU_MIPS64 + +- __asm__ ("dclz %0, %1" : "=r" (word) : "r" (word)); ++ __asm__ ( ++ " .set mips64 \n" ++ " dclz %0, %1 \n" ++ " .set mips0 \n" ++ : "=r" (word) ++ : "r" (word)); + + return 64 - word; + #else +diff -Nurd linux-2.6.16.orig/include/asm-mips/byteorder.h linux-2.6.16/include/asm-mips/byteorder.h +--- linux-2.6.16.orig/include/asm-mips/byteorder.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-mips/byteorder.h 2006-06-03 11:14:55.355473944 +0200 +@@ -19,7 +19,9 @@ + static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) + { + __asm__( ++ " .set mips32r2 \n" + " wsbh %0, %1 \n" ++ " .set mips0 \n" + : "=r" (x) + : "r" (x)); + +@@ -30,8 +32,10 @@ + static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) + { + __asm__( ++ " .set mips32r2 \n" + " wsbh %0, %1 \n" + " rotr %0, %0, 16 \n" ++ " .set mips0 \n" + : "=r" (x) + : "r" (x)); + +diff -Nurd linux-2.6.16.orig/include/asm-mips/interrupt.h linux-2.6.16/include/asm-mips/interrupt.h +--- linux-2.6.16.orig/include/asm-mips/interrupt.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-mips/interrupt.h 2006-06-03 11:14:55.355473944 +0200 +@@ -20,7 +20,9 @@ + " .set reorder \n" + " .set noat \n" + #ifdef CONFIG_CPU_MIPSR2 ++ " .set mips32r2 \n" + " ei \n" ++ " .set mips0 \n" + #else + " mfc0 $1,$12 \n" + " ori $1,0x1f \n" +@@ -63,7 +65,9 @@ + " .set push \n" + " .set noat \n" + #ifdef CONFIG_CPU_MIPSR2 ++ " .set mips32r2 \n" + " di \n" ++ " .set mips0 \n" + #else + " mfc0 $1,$12 \n" + " ori $1,0x1f \n" +@@ -103,8 +107,10 @@ + " .set reorder \n" + " .set noat \n" + #ifdef CONFIG_CPU_MIPSR2 ++ " .set mips32r2 \n" + " di \\result \n" + " andi \\result, 1 \n" ++ " .set mips0 \n" + #else + " mfc0 \\result, $12 \n" + " ori $1, \\result, 0x1f \n" +@@ -133,9 +139,11 @@ + * Slow, but doesn't suffer from a relativly unlikely race + * condition we're having since days 1. + */ ++ " .set mips32r2 \n" + " beqz \\flags, 1f \n" + " di \n" + " ei \n" ++ " .set mips0 \n" + "1: \n" + #elif defined(CONFIG_CPU_MIPSR2) + /* +diff -Nurd linux-2.6.16.orig/include/asm-mips/r4kcache.h linux-2.6.16/include/asm-mips/r4kcache.h +--- linux-2.6.16.orig/include/asm-mips/r4kcache.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-mips/r4kcache.h 2006-06-03 11:14:55.356473792 +0200 +@@ -37,7 +37,7 @@ + " cache %0, %1 \n" \ + " .set pop \n" \ + : \ +- : "i" (op), "m" (*(unsigned char *)(addr))) ++ : "i" (op), "R" (*(unsigned char *)(addr))) + + static inline void flush_icache_line_indexed(unsigned long addr) + { +diff -Nurd linux-2.6.16.orig/include/asm-powerpc/floppy.h linux-2.6.16/include/asm-powerpc/floppy.h +--- linux-2.6.16.orig/include/asm-powerpc/floppy.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-powerpc/floppy.h 2006-06-03 11:14:55.356473792 +0200 +@@ -35,6 +35,7 @@ + #ifdef CONFIG_PCI + + #include <linux/pci.h> ++#include <asm/ppc-pci.h> /* for ppc64_isabridge_dev */ + + #define fd_dma_setup(addr,size,mode,io) powerpc_fd_dma_setup(addr,size,mode,io) + +@@ -52,12 +53,12 @@ + if (bus_addr + && (addr != prev_addr || size != prev_size || dir != prev_dir)) { + /* different from last time -- unmap prev */ +- pci_unmap_single(NULL, bus_addr, prev_size, prev_dir); ++ pci_unmap_single(ppc64_isabridge_dev, bus_addr, prev_size, prev_dir); + bus_addr = 0; + } + + if (!bus_addr) /* need to map it */ +- bus_addr = pci_map_single(NULL, addr, size, dir); ++ bus_addr = pci_map_single(ppc64_isabridge_dev, addr, size, dir); + + /* remember this one as prev */ + prev_addr = addr; +diff -Nurd linux-2.6.16.orig/include/asm-x86_64/cpufeature.h linux-2.6.16/include/asm-x86_64/cpufeature.h +--- linux-2.6.16.orig/include/asm-x86_64/cpufeature.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-x86_64/cpufeature.h 2006-06-03 11:14:55.357473640 +0200 +@@ -64,6 +64,7 @@ + #define X86_FEATURE_REP_GOOD (3*32+ 4) /* rep microcode works well on this CPU */ + #define X86_FEATURE_CONSTANT_TSC (3*32+5) /* TSC runs at constant rate */ + #define X86_FEATURE_SYNC_RDTSC (3*32+6) /* RDTSC syncs CPU core */ ++#define X86_FEATURE_FXSAVE_LEAK (3*32+7) /* FIP/FOP/FDP leaks through FXSAVE */ + + /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ + #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ +diff -Nurd linux-2.6.16.orig/include/asm-x86_64/i387.h linux-2.6.16/include/asm-x86_64/i387.h +--- linux-2.6.16.orig/include/asm-x86_64/i387.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/asm-x86_64/i387.h 2006-06-03 11:14:55.364472576 +0200 +@@ -72,6 +72,23 @@ + #define set_fpu_swd(t,val) ((t)->thread.i387.fxsave.swd = (val)) + #define set_fpu_fxsr_twd(t,val) ((t)->thread.i387.fxsave.twd = (val)) + ++#define X87_FSW_ES (1 << 7) /* Exception Summary */ ++ ++/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception ++ is pending. Clear the x87 state here by setting it to fixed ++ values. The kernel data segment can be sometimes 0 and sometimes ++ new user value. Both should be ok. ++ Use the PDA as safe address because it should be already in L1. */ ++static inline void clear_fpu_state(struct i387_fxsave_struct *fx) ++{ ++ if (unlikely(fx->swd & X87_FSW_ES)) ++ asm volatile("fnclex"); ++ alternative_input(ASM_NOP8 ASM_NOP2, ++ " emms\n" /* clear stack tags */ ++ " fildl %%gs:0", /* load to clear state */ ++ X86_FEATURE_FXSAVE_LEAK); ++} ++ + static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) + { + int err; +@@ -119,6 +136,7 @@ + #endif + if (unlikely(err)) + __clear_user(fx, sizeof(struct i387_fxsave_struct)); ++ /* No need to clear here because the caller clears USED_MATH */ + return err; + } + +@@ -149,7 +167,7 @@ + "i" (offsetof(__typeof__(*tsk), + thread.i387.fxsave))); + #endif +- __asm__ __volatile__("fnclex"); ++ clear_fpu_state(&tsk->thread.i387.fxsave); + } + + static inline void kernel_fpu_begin(void) +diff -Nurd linux-2.6.16.orig/include/linux/apm_bios.h linux-2.6.16/include/linux/apm_bios.h +--- linux-2.6.16.orig/include/linux/apm_bios.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/apm_bios.h 2006-06-03 11:14:56.344323616 +0200 +@@ -208,6 +208,31 @@ + #define APM_CAP_RESUME_SUSPEND_PCMCIA 0x0080 /* Resume on PCMCIA Ring */ + + /* ++ * kernel event definitions for our ezx platform ++ */ ++enum ++{ ++ KRNL_ACCS_ATTACH, ++ KRNL_ACCS_DETACH, ++ KRNL_BLUETOOTH, ++ KRNL_TOUCHSCREEN, ++ KRNL_KEYPAD, ++ KRNL_RTC, ++ KRNL_FLIP_ON, ++ KRNL_FLIP_OFF, ++ KRNL_VOICE_REC, ++ KRNL_ICL, ++ KRNL_BP, ++ KRNL_BP_WDI, ++ KRNL_PROC_INACT, ++ KRNL_IDLE_TIMEOUT, ++ KRNL_SCREEN_LOCK, ++ KRNL_SCREEN_UNLOCK ++}; ++ ++ ++ ++/* + * ioctl operations + */ + #include <linux/ioctl.h> +diff -Nurd linux-2.6.16.orig/include/linux/cpu.h linux-2.6.16/include/linux/cpu.h +--- linux-2.6.16.orig/include/linux/cpu.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/cpu.h 2006-06-03 11:14:55.365472424 +0200 +@@ -32,7 +32,7 @@ + }; + + extern int register_cpu(struct cpu *, int, struct node *); +-extern struct sys_device *get_cpu_sysdev(int cpu); ++extern struct sys_device *get_cpu_sysdev(unsigned cpu); + #ifdef CONFIG_HOTPLUG_CPU + extern void unregister_cpu(struct cpu *, struct node *); + #endif +diff -Nurd linux-2.6.16.orig/include/linux/cpumask.h linux-2.6.16/include/linux/cpumask.h +--- linux-2.6.16.orig/include/linux/cpumask.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/cpumask.h 2006-06-03 11:14:55.365472424 +0200 +@@ -408,6 +408,7 @@ + }) + + #define for_each_cpu(cpu) for_each_cpu_mask((cpu), cpu_possible_map) ++#define for_each_possible_cpu(cpu) for_each_cpu_mask((cpu), cpu_possible_map) + #define for_each_online_cpu(cpu) for_each_cpu_mask((cpu), cpu_online_map) + #define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map) + +diff -Nurd linux-2.6.16.orig/include/linux/device.h linux-2.6.16/include/linux/device.h +--- linux-2.6.16.orig/include/linux/device.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/device.h 2006-06-03 11:14:55.905390344 +0200 +@@ -336,6 +336,8 @@ + + struct list_head dma_pools; /* dma pools (if dma'ble) */ + ++ struct constraints *constraints; ++ + struct dma_coherent_mem *dma_mem; /* internal for coherent mem + override */ + +diff -Nurd linux-2.6.16.orig/include/linux/dpm.h linux-2.6.16/include/linux/dpm.h +--- linux-2.6.16.orig/include/linux/dpm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/linux/dpm.h 2006-06-03 11:14:55.906390192 +0200 +@@ -0,0 +1,409 @@ ++/* ++ * include/linux/dpm.h DPM policy management ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, International Business Machines Corporation ++ * All Rights Reserved ++ * ++ * Robert Paulsen ++ * IBM Linux Technology Center ++ * rpaulsen@us.ibm.com ++ * August, 2002 ++ * ++ */ ++ ++#ifndef __DPM_H__ ++#define __DPM_H__ ++ ++#include <linux/config.h> ++#include <linux/device.h> ++ ++#define DPM_NO_STATE -1 ++ ++#ifndef CONFIG_DPM ++ ++/* The above and following constants must always be defined for the ++ benefit of the init task and system tasks, although they are ++ otherwise ignored if DPM is not configured. */ ++ ++#define DPM_TASK_STATE 0 ++#define dpm_set_os(task_state) do {} while (0); ++ ++#else /* CONFIG_DPM */ ++ ++#include <asm/dpm.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/unistd.h> ++#include <linux/notifier.h> ++ ++/* max size of DPM names */ ++enum {DPM_NAME_SIZE=256}; ++ ++#include <linux/dpm-trace.h> ++#include <linux/list.h> ++#include <asm/semaphore.h> ++#include <asm/atomic.h> ++ ++/* statistics */ ++struct dpm_stats { ++ unsigned long count; ++ unsigned long long total_time; ++ unsigned long long start_time; ++}; ++ ++extern struct dpm_stats dpm_state_stats[DPM_STATES]; ++ ++/* update statistics structures */ ++extern unsigned long long dpm_update_stats(struct dpm_stats *new, ++ struct dpm_stats *old); ++ ++typedef int dpm_state_t; ++typedef int dpm_md_pp_t; ++ ++/* A table of processor-dependent routines, must be initialized by ++ platform-dependent boot code. None of the entries (that will actually be ++ called) are allowed to be NULL if DPM is enabled. */ ++ ++struct dpm_opt; ++ ++struct dpm_md { ++ int (*init_opt)(struct dpm_opt *opt); ++ int (*set_opt)(struct dpm_opt *cur, struct dpm_opt *new); ++ int (*get_opt)(struct dpm_opt *opt); ++ int (*check_constraint)(struct constraint_param *param, ++ struct dpm_opt *opt); ++ void (*idle)(void); ++ void (*startup)(void); ++ void (*cleanup)(void); ++}; ++ ++ ++/***************************************************************************** ++ * Search a list looking for a named entity. ++ * A pointer to the found element is put in the variable named by the ++ * "answer" argument (or it is set to zero if not found). ++ * The structure's type name is given by the "element_type" argument. ++ * The name being looked for is given by the "find_me" argument. ++ * The name of the stand-alone list_head is given by the "list_name" argument. ++ * Assumes the proper semaphore is held. ++ * Assumes the structure's list_head is named "list". ++ * Assumes the structure's name is in a field called "name" ++ *****************************************************************************/ ++#define list_find(answer,find_me,list_name,element_type) \ ++ do { \ ++ element_type *elm; \ ++ struct list_head *scan; \ ++ (answer)=0; \ ++ for(scan=list_name.next;scan!=&list_name; \ ++ scan=scan->next) { \ ++ elm=list_entry(scan,element_type,list); \ ++ if (strncmp((find_me),elm->name, \ ++ DPM_NAME_SIZE)==0) { \ ++ (answer)=elm; \ ++ break; \ ++ } \ ++ } \ ++ } while(0) ++ ++/* internal representation of an operating point */ ++ ++#define DPM_OP_FORCE 0x0001 ++#define DPM_OP_NOP 0x0002 ++ ++struct dpm_opt { ++ char *name; /* name */ ++ struct list_head list; /* all installed op points */ ++ dpm_md_pp_t pp[DPM_PP_NBR]; /* initialization params */ ++ struct dpm_md_opt md_opt; /* machine dependent part */ ++ int constrained; /* is this opt constrained? */ ++ struct kobject kobj; /* kobject */ ++ struct dpm_stats stats; /* statistics */ ++ int flags; ++}; ++ ++/* internal representation of a class of op points (to be mapped to an ++ * operating state */ ++struct dpm_class { ++ char *name; /* name */ ++ struct list_head list; /* all installed classes */ ++ unsigned nops; /* nbr ops in this class */ ++ struct dpm_opt **ops; /* the ops in this class */ ++ struct kobject kobj; /* kobject */ ++ struct dpm_stats stats; /* statistics */ ++}; ++ ++/* ++ * temporary support for policies to map operating points to either ++ * operating pts or classes. Only one field allowed to be set. ++ */ ++ ++struct dpm_classopt { ++ struct dpm_opt *opt; ++ struct dpm_class *class; ++}; ++ ++/* internal representation of an installed power policy */ ++struct dpm_policy { ++ char *name; /* name */ ++ struct list_head list; /* all installed policies */ ++ struct dpm_classopt classopt[DPM_STATES]; /* classes/op pts */ ++ struct kobject kobj; /* kobject */ ++ struct dpm_stats stats; /* statistics */ ++}; ++ ++/* ++ * internal use utility functions for use by DPM ++ */ ++ ++/* DPM semaphore locking. To simplify future expansion, don't 'down' _dpm_lock ++ directly. Also, _dpm_lock must be 'up'ed only by dpm_unlock(). */ ++ ++extern struct semaphore _dpm_lock; ++ ++static inline void ++dpm_lock(void) ++{ ++ down(&_dpm_lock); ++} ++ ++static inline int ++dpm_lock_interruptible(void) ++{ ++ if (down_interruptible(&_dpm_lock)) ++ return -ERESTARTSYS; ++ return 0; ++} ++ ++static inline int ++dpm_trylock(void) ++{ ++ if (down_trylock(&_dpm_lock)) ++ return -EBUSY; ++ return 0; ++} ++ ++void dpm_unlock(void); ++void dpm_idle(void); ++ ++/* set operating state */ ++void dpm_set_os(dpm_state_t state); ++ ++/* ++ * names of DPM stuff for userspace interfaces ++ */ ++ ++extern char *dpm_state_names[DPM_STATES]; ++extern char *dpm_param_names[DPM_PP_NBR]; ++ ++/* initialize/terminate the DPM */ ++int dynamicpower_init(void); ++int dynamicpower_terminate(void); ++ ++/* (temporarily) disable the DPM */ ++int dynamicpower_disable(void); ++ ++/* re-enable the DPM */ ++int dynamicpower_enable(void); ++ ++/* suspend/resume DPM across a system shutdown */ ++int dynamicpm_suspend(void); ++void dynamicpm_resume(void); ++ ++/* create operating point */ ++int dpm_create_opt(const char *name, const dpm_md_pp_t *pp, int npp); ++ ++/* create class of operating points */ ++int dpm_create_class(const char *name, char **op_names, unsigned nops); ++ ++/* create policy */ ++int dpm_create_policy(const char *name, char **opt_names, int nopts); ++int dpm_map_policy_state(struct dpm_policy *policy, int state, char *classopt); ++ ++/* destroy policy */ ++int dpm_destroy_policy(const char *name); ++ ++/* activate a power policy */ ++int dpm_set_policy(const char *name); ++ ++/* get name of active power policy */ ++int dpm_get_policy(char *name); ++ ++/* set a raw operating state */ ++int dpm_set_op_state(const char *name); ++int dpm_set_opt(struct dpm_opt *opt, unsigned flags); ++ ++/* choose unconstrained operating point from policy */ ++extern struct dpm_opt *dpm_choose_opt(struct dpm_policy *policy, int state); ++ ++ ++/* constraints */ ++int dpm_check_constraints(struct dpm_opt *opt); ++int dpm_default_check_constraint(struct constraint_param *param, ++ struct dpm_opt *opt); ++int dpm_show_opconstraints(struct dpm_opt *opt, char * buf); ++ ++/* driver scale callbacks */ ++void dpm_driver_scale(int level, struct dpm_opt *newop); ++void dpm_register_scale(struct notifier_block *nb, int level); ++void dpm_unregister_scale(struct notifier_block *nb, int level); ++ ++/* utils */ ++extern void dpm_udelay(unsigned uS); ++extern void dpm_udelay_from(u64 start, unsigned uS); ++extern unsigned long dpm_compute_lpj(unsigned long ref, u_int div, u_int mult); ++ ++/* ++ * sysfs interface ++ */ ++ ++extern void dpm_sysfs_new_policy(struct dpm_policy *policy); ++extern void dpm_sysfs_destroy_policy(struct dpm_policy *policy); ++extern void dpm_sysfs_new_class(struct dpm_class *class); ++extern void dpm_sysfs_destroy_class(struct dpm_class *class); ++extern void dpm_sysfs_new_op(struct dpm_opt *opt); ++extern void dpm_sysfs_destroy_op(struct dpm_opt *opt); ++ ++extern int proc_pid_dpm_read(struct task_struct*,char*); ++ ++ ++/* ++ * global data for power management system ++ */ ++ ++/* curently installed policies, classes and operating points */ ++extern struct list_head dpm_policies; ++extern struct list_head dpm_classes; ++extern struct list_head dpm_opts; ++extern struct semaphore dpm_policy_sem; ++extern spinlock_t dpm_policy_lock; ++ ++/* the currently active policy, class, state, point */ ++extern struct dpm_policy *dpm_active_policy; ++extern struct dpm_class *dpm_active_class; ++extern dpm_state_t dpm_active_state; ++extern struct dpm_opt *dpm_active_opt; ++ ++/* is DPM initialized and enabled? */ ++extern int dpm_initialized; ++extern int dpm_enabled; ++ ++extern inline void ++dpm_quick_enter_state(int new_state) ++{ ++#ifdef CONFIG_DPM_STATS ++ dpm_update_stats(new_state != DPM_NO_STATE ? ++ &dpm_state_stats[new_state] : NULL, ++ dpm_active_state != DPM_NO_STATE ? ++ &dpm_state_stats[dpm_active_state] : NULL); ++#endif ++ ++ dpm_active_state = new_state; ++} ++ ++/* Flags for dpm_set_opt(). By default, dpm_set_op() is guaranteed not ++ to block the caller, and will arrange to complete asynchronously if ++ necessary. ++ ++ DPM_SYNC The operating point is guaranteed to be set when the call ++ returns. The call may block. ++ ++ DPM_UNLOCK The caller requires dpm_md_set_opt() to unlock the DPM system ++ once the operating point is set. ++*/ ++ ++#define DPM_SYNC 0x01 ++#define DPM_UNLOCK 0x02 ++ ++/* ++ * Common machine-dependent and board-dependent function wrappers. ++ */ ++ ++extern struct dpm_md dpm_md; ++ ++static inline void ++dpm_md_startup(void) ++{ ++ if (dpm_md.startup) ++ dpm_md.startup(); ++} ++ ++ ++static inline void ++dpm_md_cleanup(void) ++{ ++ if (dpm_md.cleanup) ++ dpm_md.cleanup(); ++} ++ ++ ++static inline void ++dpm_md_idle(void) ++{ ++ if (dpm_md.idle) ++ dpm_md.idle(); ++} ++ ++ ++/* Machine-dependent operating point creating/query/setting */ ++ ++ ++static inline int ++dpm_md_init_opt(struct dpm_opt *opt) ++{ ++ if (dpm_md.init_opt) ++ return dpm_md.init_opt(opt); ++ return 0; ++} ++ ++static inline int ++dpm_md_set_opt(struct dpm_opt *cur, struct dpm_opt *new) ++{ ++ if (dpm_md.set_opt) { ++ return dpm_md.set_opt(cur, new); ++ } ++ return 0; ++} ++ ++static inline int ++dpm_md_get_opt(struct dpm_opt *opt) ++{ ++ if (dpm_md.get_opt) ++ return dpm_md.get_opt(opt); ++ return 0; ++} ++ ++static inline int ++dpm_md_check_constraint(struct constraint_param *param, struct dpm_opt *opt) ++{ ++ return dpm_md.check_constraint ? ++ dpm_md.check_constraint(param, opt) : 1; ++} ++ ++/* ++ * Helper functions ++ */ ++ ++static inline char * ++dpm_classopt_name(struct dpm_policy *policy, int state) ++{ ++ return policy->classopt[state].opt ? ++ policy->classopt[state].opt->name : ++ policy->classopt[state].class->name; ++} ++ ++#endif /* CONFIG_DPM */ ++#endif /*__DPM_H__*/ +diff -Nurd linux-2.6.16.orig/include/linux/dpm-trace.h linux-2.6.16/include/linux/dpm-trace.h +--- linux-2.6.16.orig/include/linux/dpm-trace.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/linux/dpm-trace.h 2006-06-03 11:14:55.905390344 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * include/linux/dpm.h DPM policy management ++ * ++ * 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 ++ * ++ * Copyright (C) 2002, International Business Machines Corporation ++ * All Rights Reserved ++ * ++ * Robert Paulsen ++ * IBM Linux Technology Center ++ * rpaulsen@us.ibm.com ++ * August, 2002 ++ * ++ */ ++ ++#ifndef __DPM_TRACE_H_ ++#define __DPM_TRACE_H_ ++ ++#include <linux/config.h> ++ ++#ifdef CONFIG_DPM_TRACE ++ ++#define DPM_TRACE_SET_OPT_ASYNC 0x00000001 ++#define DPM_TRACE_SET_OPT_SYNC 0x00000002 ++#define DPM_TRACE_RESYNC 0x00000004 ++#define DPM_TRACE_UNLOCK 0x00000008 ++#define DPM_TRACE_SET_OS 0x00000010 ++#define DPM_TRACE_SET_POLICY 0x00000020 ++#define DPM_TRACE_START 0x00000040 ++#define DPM_TRACE_STOP 0x00000080 ++#define DPM_TRACE_SET_TASK_STATE 0x00000100 ++ ++#define DPM_TRACE_ALL 0x000001ff ++ ++void dpm_trace(unsigned event, ...); ++void dpm_trace_start(unsigned events); ++void dpm_trace_stop(void); ++void dpm_trace_reset(void); ++ ++int ++read_proc_dpm_trace(char *page, char **start, off_t offset, ++ int count, int *eof, void *data); ++int ++write_proc_dpm_trace(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++ ++#else ++ ++#define dpm_trace(args...) do {} while (0) ++ ++#endif /* CONFIG_DPM_TRACE */ ++ ++#endif /*__DPM_TRACE_H_*/ +diff -Nurd linux-2.6.16.orig/include/linux/ezx_roflash.h linux-2.6.16/include/linux/ezx_roflash.h +--- linux-2.6.16.orig/include/linux/ezx_roflash.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/linux/ezx_roflash.h 2006-06-03 11:14:56.385317384 +0200 +@@ -0,0 +1,41 @@ ++/* ++ * linux/include/linux/ezx_roflash.h ++ * ++ * Created by Susan Gu 0ct, 22 2002 ++ * ++ * For multiple cramfs partitions in ezx project ++ * At repsent, there are three cramfs partitions in ezx project, they are: ++ * 1. root file system ++ * 2. Language package ++ * 3. setup package ++*/ ++ ++#ifndef EZX_ROFLASH_FS_H ++#define EZX_ROFLASH_FS_H ++ ++#include <asm/ioctl.h> ++ ++#define ROFLASH_MAJOR 62 ++ ++#define ROFLASH_LINEAR 0x0010 ++#define ROFLASH_LINEAR_XIP 0x0011 ++#define ROFLASH_BLOCK 0x1000 ++#define ROFLASH_CHAR 0x1100 ++#define MAX_ROFLASH 4 ++ ++typedef struct ++{ ++ char name[16]; /* This length should be enough for DC stuff */ ++ unsigned long offset; ++ unsigned long size; ++ int (*roflash_read)(void *, unsigned long, size_t, size_t *, u_char *); ++ /* Added by Susan for multiple Linear or block cramfs */ ++ void *priv_map; ++ unsigned long phys_addr; ++ unsigned short l_x_b; ++}roflash_area; ++ ++extern roflash_area *roflash_get_dev(unsigned char minor); ++extern roflash_area **roflash_table_pptr; ++ ++#endif +diff -Nurd linux-2.6.16.orig/include/linux/fb.h linux-2.6.16/include/linux/fb.h +--- linux-2.6.16.orig/include/linux/fb.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/fb.h 2006-06-03 11:14:55.366472272 +0200 +@@ -839,12 +839,10 @@ + #define FB_LEFT_POS(bpp) (32 - bpp) + #define FB_SHIFT_HIGH(val, bits) ((val) >> (bits)) + #define FB_SHIFT_LOW(val, bits) ((val) << (bits)) +-#define FB_BIT_NR(b) (7 - (b)) + #else + #define FB_LEFT_POS(bpp) (0) + #define FB_SHIFT_HIGH(val, bits) ((val) << (bits)) + #define FB_SHIFT_LOW(val, bits) ((val) >> (bits)) +-#define FB_BIT_NR(b) (b) + #endif + + /* +diff -Nurd linux-2.6.16.orig/include/linux/fs.h linux-2.6.16/include/linux/fs.h +--- linux-2.6.16.orig/include/linux/fs.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/fs.h 2006-06-03 11:14:55.367472120 +0200 +@@ -1383,6 +1383,7 @@ + extern void bd_release(struct block_device *); + + /* fs/char_dev.c */ ++#define CHRDEV_MAJOR_HASH_SIZE 255 + extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); + extern int register_chrdev_region(dev_t, unsigned, const char *); + extern int register_chrdev(unsigned int, const char *, +@@ -1390,25 +1391,17 @@ + extern int unregister_chrdev(unsigned int, const char *); + extern void unregister_chrdev_region(dev_t, unsigned); + extern int chrdev_open(struct inode *, struct file *); +-extern int get_chrdev_list(char *); +-extern void *acquire_chrdev_list(void); +-extern int count_chrdev_list(void); +-extern void *get_next_chrdev(void *); +-extern int get_chrdev_info(void *, int *, char **); +-extern void release_chrdev_list(void *); ++extern void chrdev_show(struct seq_file *,off_t); + + /* fs/block_dev.c */ ++#define BLKDEV_MAJOR_HASH_SIZE 255 + #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ + extern const char *__bdevname(dev_t, char *buffer); + extern const char *bdevname(struct block_device *bdev, char *buffer); + extern struct block_device *lookup_bdev(const char *); + extern struct block_device *open_bdev_excl(const char *, int, void *); + extern void close_bdev_excl(struct block_device *); +-extern void *acquire_blkdev_list(void); +-extern int count_blkdev_list(void); +-extern void *get_next_blkdev(void *); +-extern int get_blkdev_info(void *, int *, char **); +-extern void release_blkdev_list(void *); ++extern void blkdev_show(struct seq_file *,off_t); + + extern void init_special_inode(struct inode *, umode_t, dev_t); + +diff -Nurd linux-2.6.16.orig/include/linux/init_task.h linux-2.6.16/include/linux/init_task.h +--- linux-2.6.16.orig/include/linux/init_task.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/init_task.h 2006-06-03 11:14:55.906390192 +0200 +@@ -1,6 +1,7 @@ + #ifndef _LINUX__INIT_TASK_H + #define _LINUX__INIT_TASK_H + ++#include <linux/dpm.h> + #include <linux/file.h> + #include <linux/rcupdate.h> + +@@ -116,6 +117,7 @@ + .list = LIST_HEAD_INIT(tsk.pending.list), \ + .signal = {{0}}}, \ + .blocked = {{0}}, \ ++ .dpm_state = DPM_TASK_STATE, \ + .alloc_lock = SPIN_LOCK_UNLOCKED, \ + .proc_lock = SPIN_LOCK_UNLOCKED, \ + .journal_info = NULL, \ +diff -Nurd linux-2.6.16.orig/include/linux/keypad.h linux-2.6.16/include/linux/keypad.h +--- linux-2.6.16.orig/include/linux/keypad.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/linux/keypad.h 2006-06-03 11:14:56.344323616 +0200 +@@ -0,0 +1,137 @@ ++#ifndef __LINUX_KEYPAD_H ++#define __LINUX_KEYPAD_H ++ ++/* ++ * include/linux/keypad.h ++ * ++ * (c) Copyright Motorola 2003, All rights reserved. ++ */ ++ ++#include <linux/ioctl.h> ++ ++#define KEYDOWN 0x8000 ++#define KEYUP 0x0000 ++ ++#define EVENTSIZE sizeof(short) ++#define KEY_IS_DOWN(x) ((x) & KEYDOWN) ++#define KEYCODE(x) ((x) & 0x7fff) ++ ++struct autorepeatinfo { ++ int r_repeat; /* 1 to do autorepeat, 0 to not do it */ ++ int r_time_to_first_repeat; /* time to first repeat in milliseconds */ ++ int r_time_between_repeats; /* time between repeats in milliseconds */ ++}; ++ ++#define KEYPAD_IOCTL_BASE 'k' ++ ++/* ++ * return the bitmap of keys currently down. ++ * The bitmap is an array of NUM_WORDS_IN_BITMAP unsigned long words. ++ * We count the bits starting with 1 in the rightmost position in ++ * the rightmost (highest-indexed) word. If NUM_WORDS_IN_BITMAP is two, ++ * the bitmap looks like this: ++ * 0 1 ++ * ---------------------------------------------------- ++ * | 64 63 ........... 34 33 | 32 31 ............. 2 1 | ++ * ---------------------------------------------------- ++ * Bit n corresponds to key code n. ++ */ ++ ++#define KEYPAD_IOC_GETBITMAP _IOR(KEYPAD_IOCTL_BASE,1,unsigned long *) ++#define NUM_WORDS_IN_BITMAP 2 ++ ++/** ++ * put the specified event on the keypad's input queue and update the bitmap. ++ * The exact event as specified will be returned by read() when it ++ * reaches the front of the queue. A key press event consists of ++ * the key code or'd with KEYDOWN. A key release event consists of ++ * just the key code. ++ */ ++#define KEYPAD_IOC_INSERT_EVENT _IOW(KEYPAD_IOCTL_BASE,2,unsigned short) ++ ++/** ++ * have the driver interpret the specified scan register values as ++ * if it had gotten an interrupt. The passed-in argument is a pointer ++ * to three consecutive 32-bit words in this order: KPAS, KPASMKP0, KPASMKP1. ++ */ ++#define KEYPAD_IOC_INSERTKEYSCAN _IOW(KEYPAD_IOCTL_BASE,3,unsigned long *) ++ ++/* get the hardware debounce interval (in milliseconds) */ ++#define KEYPAD_IOC_GET_DEBOUNCE_INTERVAL \ ++ _IOR(KEYPAD_IOCTL_BASE,4,unsigned short *) ++ ++/* set the hardware debounce interval (in milliseconds) */ ++#define KEYPAD_IOC_SET_DEBOUNCE_INTERVAL \ ++ _IOW(KEYPAD_IOCTL_BASE,4,unsigned short) ++ ++/* get "Ignore Multiple Key Press" bit; 1 means they are ignored */ ++#define KEYPAD_IOC_GET_IMKP_SETTING _IOR(KEYPAD_IOCTL_BASE,5,unsigned char *) ++ ++/* set "Ignore Multiple Key Press" bit; 1 means they will be ignored */ ++#define KEYPAD_IOC_SET_IMKP_SETTING _IOW(KEYPAD_IOCTL_BASE,5,unsigned char) ++ ++/* ++ * specify what to do about autorepeat on held keys ++ * the 3rd argument is a pointer to a struct autorepeat ++ */ ++#define KEYPAD_IOC_SET_AUTOREPEAT _IOW(KEYPAD_IOCTL_BASE,6,unsigned long *) ++ ++#define KEYPADI_TURN_ON_LED 1 ++#define KEYPADI_TURN_OFF_LED 0 ++/* ++ * the constant KEY_k is both the code for key k in an event returned by ++ * read() and the bit position for key k in the bitmap returned by ++ * ioctl(KEYPAD_IOC_GETBITMAP). ++ */ ++#define KEYPAD_NONE 0 ++ ++#define KEYPAD_0 1 ++#define KEYPAD_1 2 ++#define KEYPAD_2 3 ++#define KEYPAD_3 4 ++#define KEYPAD_4 5 ++#define KEYPAD_5 6 ++#define KEYPAD_6 7 ++#define KEYPAD_7 8 ++#define KEYPAD_8 9 ++#define KEYPAD_9 10 ++ ++#define KEYPAD_UP 11 ++#define KEYPAD_DOWN 12 ++#define KEYPAD_LEFT 13 ++#define KEYPAD_RIGHT 14 ++#define KEYPAD_POUND 15 ++#define KEYPAD_STAR 16 ++#define KEYPAD_MENU 17 ++#define KEYPAD_SLEFT 18 ++#define KEYPAD_SRIGHT 19 ++#define KEYPAD_VOLUP 20 ++#define KEYPAD_VOLDOWN 21 ++#define KEYPAD_CAMERA 22 ++#define KEYPAD_CLEAR 23 ++#define KEYPAD_CARRIER 24 ++#define KEYPAD_ACTIVATE 25 ++#define KEYPAD_SEND 26 ++#define KEYPAD_SMART 27 ++#define KEYPAD_VAVR 28 ++ ++#define KEYPAD_CENTER 29 ++#define KEYPAD_HOME 30 ++#define KEYPAD_A 31 ++#define KEYPAD_B 32 ++#define KEYPAD_GAME_R 33 ++#define KEYPAD_GAME_L 34 ++#define KEYPAD_CAMERA_VOICE 35 ++//#define KEYPAD_SCREEN_LOCK 36 ++#define KEYPAD_POWER 37 ++ ++#define KEYPAD_OK 38 ++#define KEYPAD_CANCEL 39 ++#define KEYPAD_PTT 40 ++#define KEYPAD_JOG_UP 41 ++#define KEYPAD_JOG_MIDDLE 42 ++#define KEYPAD_JOG_DOWN 43 ++ ++#define KEYPAD_MAXCODE 43 ++ ++#endif /* __LINUX_KEYPAD_H */ +diff -Nurd linux-2.6.16.orig/include/linux/mm.h linux-2.6.16/include/linux/mm.h +--- linux-2.6.16.orig/include/linux/mm.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/mm.h 2006-06-03 11:14:55.368471968 +0200 +@@ -229,10 +229,9 @@ + unsigned long private; /* Mapping-private opaque data: + * usually used for buffer_heads + * if PagePrivate set; used for +- * swp_entry_t if PageSwapCache. +- * When page is free, this ++ * swp_entry_t if PageSwapCache; + * indicates order in the buddy +- * system. ++ * system if PG_buddy is set. + */ + struct address_space *mapping; /* If low bit clear, points to + * inode address_space, or NULL. +diff -Nurd linux-2.6.16.orig/include/linux/page-flags.h linux-2.6.16/include/linux/page-flags.h +--- linux-2.6.16.orig/include/linux/page-flags.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/page-flags.h 2006-06-03 11:14:55.368471968 +0200 +@@ -74,7 +74,9 @@ + #define PG_mappedtodisk 16 /* Has blocks allocated on-disk */ + #define PG_reclaim 17 /* To be reclaimed asap */ + #define PG_nosave_free 18 /* Free, should not be written */ +-#define PG_uncached 19 /* Page has been mapped as uncached */ ++#define PG_buddy 19 /* Page is free, on buddy lists */ ++ ++#define PG_uncached 20 /* Page has been mapped as uncached */ + + /* + * Global page accounting. One instance per CPU. Only unsigned longs are +@@ -319,6 +321,10 @@ + #define SetPageNosaveFree(page) set_bit(PG_nosave_free, &(page)->flags) + #define ClearPageNosaveFree(page) clear_bit(PG_nosave_free, &(page)->flags) + ++#define PageBuddy(page) test_bit(PG_buddy, &(page)->flags) ++#define __SetPageBuddy(page) __set_bit(PG_buddy, &(page)->flags) ++#define __ClearPageBuddy(page) __clear_bit(PG_buddy, &(page)->flags) ++ + #define PageMappedToDisk(page) test_bit(PG_mappedtodisk, &(page)->flags) + #define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags) + #define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags) +diff -Nurd linux-2.6.16.orig/include/linux/pm.h linux-2.6.16/include/linux/pm.h +--- linux-2.6.16.orig/include/linux/pm.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/pm.h 2006-06-03 11:14:55.907390040 +0200 +@@ -131,6 +131,34 @@ + extern struct pm_ops *pm_ops; + extern int pm_suspend(suspend_state_t state); + ++struct device; ++ ++struct constraint_param { ++ int id; ++ int min; ++ int max; ++}; ++ ++#define DPM_CONSTRAINT_PARAMS_MAX 20 ++ ++struct constraints { ++ int asserted; ++ int count; ++ int violations; ++ struct constraint_param param[DPM_CONSTRAINT_PARAMS_MAX]; ++ struct list_head entry; ++}; ++ ++enum { ++ SCALE_PRECHANGE, ++ SCALE_POSTCHANGE, ++ SCALE_MAX ++}; ++ ++extern void assert_constraints(struct constraints *); ++extern void deassert_constraints(struct constraints *); ++extern void power_event(char *eventstr); ++extern void device_power_event(struct device * dev, char *eventstr); + + /* + * Device power management +diff -Nurd linux-2.6.16.orig/include/linux/proc_fs.h linux-2.6.16/include/linux/proc_fs.h +--- linux-2.6.16.orig/include/linux/proc_fs.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/proc_fs.h 2006-06-03 11:14:55.369471816 +0200 +@@ -78,7 +78,7 @@ + struct vmcore { + struct list_head list; + unsigned long long paddr; +- unsigned long size; ++ unsigned long long size; + loff_t offset; + }; + +diff -Nurd linux-2.6.16.orig/include/linux/pxa_camera.h linux-2.6.16/include/linux/pxa_camera.h +--- linux-2.6.16.orig/include/linux/pxa_camera.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/linux/pxa_camera.h 2006-06-03 11:14:56.728265248 +0200 +@@ -0,0 +1,445 @@ ++/*================================================================================ ++ ++ Module Name: pxa-camera.h ++ ++General Description: E680/A780 camera driver header ++ ++================================================================================== ++ Motorola Confidential Proprietary ++ Advanced Technology and Software Operations ++ (c) Copyright Motorola 1999, All Rights Reserved ++ ++Revision History: ++ Modification Tracking ++Author Date Number Description of Changes ++---------------- ------------ ---------- ------------------------- ++Wang Fei/w20239 12/19/2003 LIBdd35749 Created ++Wang Fei/w20239 02/05/2004 LIBdd74309 Set frame rate in video mode ++Wang Fei/w20239 03/08/2004 LIBdd84578 Photo effects setting ++Wang Fei/w20239 11/01/2004 LIBxxxxxxx Change to SDK style ++ ++================================================================================== ++ INCLUDE FILES ++================================================================================*/ ++#ifndef __PXA_CAMERA_H__ ++#define __PXA_CAMERA_H__ ++ ++/*! ++ * General description of the Motorola A780/E680 video device driver: ++ * ++ * The Motorola A780/E680 video device is based on V4L (video for linux) 1.0, however not ++ * all V4L features are supported. ++ * There are also some additional extensions included for specific requirements beyond V4L. ++ * ++ * The video device driver has a "character special" file named /dev/video0. Developers can ++ * access the video device via the file operator interfaces. ++ * Six file operator interfaces are supported: ++ * open ++ * ioctl ++ * mmap ++ * poll/select ++ * read ++ * close ++ * For information on using these fuctions, please refer to the standard linux ++ * development documents. ++ * ++ * These four ioctl interfaces are important for getting the video device to work properly: ++ * VIDIOCGCAP Gets the video device capability ++ * VIDIOCCAPTURE Starts/stops the video capture ++ * VIDIOCGMBUF Gets the image frame buffer map info ++ * VIDIOCSWIN Sets the picture size ++ * These interfaces are compatible with V4L 1.0. Please refer to V4L documents for more details. ++ * sample.c demonstrates their use. ++ * ++ * The following ioctl interfaces are Motorola-specific extensions. These are not compatible with V4L 1.0. ++ * WCAM_VIDIOCSCAMREG ++ * WCAM_VIDIOCGCAMREG ++ * WCAM_VIDIOCSCIREG ++ * WCAM_VIDIOCGCIREG ++ * WCAM_VIDIOCSINFOR ++ * WCAM_VIDIOCGINFOR ++ * WCAM_VIDIOCSSSIZE ++ * WCAM_VIDIOCSOSIZE ++ * WCAM_VIDIOCGSSIZE ++ * WCAM_VIDIOCGOSIZE ++ * WCAM_VIDIOCSFPS ++ * WCAM_VIDIOCSNIGHTMODE ++ * WCAM_VIDIOCSSTYLE ++ * WCAM_VIDIOCSLIGHT ++ * WCAM_VIDIOCSBRIGHT ++ * WCAM_VIDIOCSBUFCOUNT ++ * WCAM_VIDIOCGCURFRMS ++ * WCAM_VIDIOCGSTYPE ++ * WCAM_VIDIOCSCONTRAST ++ * WCAM_VIDIOCSFLICKER ++ * Detailed information about these constants are described below. ++ * ++ * sample.c demonstrates most features of the Motorola A780/E680 video device driver. ++ * - Opening/closing the video device ++ * - Initializing the video device driver ++ * - Displaying the video image on a A780/E680 LCD screen ++ * - Changing the image size ++ * - Changing the style ++ * - Changing the light mode ++ * - Changing the brightness ++ * - Capturing and saving a still picture ++ */ ++ ++/*! ++ * These are the registers for the read/write camera module and the CIF ++ * (Intel PXA27x processer quick capture interface) ++ * The following 4 ioctl interfaces are used for debugging and are not open to developers ++ */ ++#define WCAM_VIDIOCSCAMREG 211 ++#define WCAM_VIDIOCGCAMREG 212 ++#define WCAM_VIDIOCSCIREG 213 ++#define WCAM_VIDIOCGCIREG 214 ++ ++/*! ++ * WCAM_VIDIOCSINFOR Sets the image data format ++ * ++ * The following code sets the image format to YCbCr422_planar ++ * ++ * struct {int val1, val2;}format; ++ * format.val1 = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ * format.val2 = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR; ++ * //dev is the video device handle ++ * ioctl(dev, WCAM_VIDIOCSINFOR, &format); ++ * ++ * Remarks: ++ * val1 is the output format of the camera module, val2 is the output format of the CIF (capture ++ * interface). Image data from the camera module can be converted to other formats through ++ * the CIF. val2 specifies the final output format of the video device. ++ * ++ * For more description on CIF please refer to the Intel PXA27x processor family developer's manual. ++ * http://www.intel.com/design/pca/prodbref/253820.html ++ */ ++#define WCAM_VIDIOCSINFOR 215 ++ ++/* ++ * WCAM_VIDIOCGINFOR Gets the image data format ++ * ++ * struct {int val1, val2;}format; ++ * ioctl(dev, WCAM_VIDIOCGINFOR, &format); ++ */ ++#define WCAM_VIDIOCGINFOR 216 ++ ++/*! ++ * WCAM_VIDIOCSSSIZE Sets the sensor window size ++ * ++ * The following code sets the sensor size to 640 X 480: ++ * ++ * struct {unsigned short w, h;}sensor_size; ++ * sensor_size.w = 640; ++ * sensor_size.h = 480; ++ * //dev is the video device handle ++ * ioctl(dev, WCAM_VIDIOCSSSIZE, &sensor_size); ++ * ++ * Remarks: ++ * The sensor size is restricted by the video device capability. ++ * VIDIOCGCAP can get the video device capability. ++ * The sensor size must be an even of multiple of 8. If not, the driver changes the sensor size to a multiple of 8. ++ */ ++#define WCAM_VIDIOCSSSIZE 217 ++ ++/*! ++ * WCAM_VIDIOCSOSIZE Sets output size of the video device ++ * ++ * The following code segment shows how to set the output size to 240 X 320: ++ * ++ * struct {unsigned short w, h;}out_size; ++ * out_size.w = 240; ++ * out_size.h = 320; ++ * //dev is the video device handle ++ * ioctl(dev, WCAM_VIDIOCSSSIZE, &out_size); ++ * ++ * Remarks: ++ * In video mode, the output size must be less than 240X320. However, in still mode, the output ++ * size is restricted by the video device capability and the sensor size. ++ * The output size must always be less than the sensor size, so if the developer changes the output size ++ * to be greater than the sensor size, the video device driver may work abnormally. ++ * The width and height must also be a multiple of 8. If it is not, the driver changes the width and height size to a multiple of 8. ++ * The developer can modify the sensor size and the output size to create a digital zoom. ++ */ ++#define WCAM_VIDIOCSOSIZE 218 ++ ++/*! ++ * WCAM_VIDIOCGSSIZE Gets the current sensor size. ++ * ++ * The following code segment shows how to use this function: ++ * ++ * struct {unsigned short w, h;}sensor_size; ++ * //dev is the video device handle ++ * ioctl(dev, WCAM_VIDIOCGSSIZE, &sensor_size); ++ * printf("sensor width is %d, sensor_height is %d\n", sensor_size.w, sensor_size.h); ++ * ++ */ ++#define WCAM_VIDIOCGSSIZE 219 ++ ++/*! ++ * WCAM_VIDIOCGOSIZE Gets the current output size. ++ * ++ * The following code segment shows how to use this function: ++ * ++ * struct {unsigned short w, h;}out_size; ++ * //dev is the video device handle ++ * ioctl(dev, WCAM_VIDIOCGOSIZE, &out_size); ++ * printf("output width is %d, output height is %d\n", out_size.w, out_size.h); ++ * ++ */ ++#define WCAM_VIDIOCGOSIZE 220 ++ ++/*! ++ * WCAM_VIDIOCSFPS Sets the output frame rate (fps- frames per second) of the video device ++ * ++ * The following code segment shows how to use this function: ++ * ++ * struct {int maxfps, minfps;}fps; ++ * fps.maxfps = 15; ++ * fps.minfps = 12; ++ * ioctl(dev, WCAM_VIDIOCSFPS, &fps); ++ * ++ * Remarks: ++ * The minimum value of maxfps is 1; the maximum value is 15. minfps must not exceed maxfps. ++ * The default value of fps is [15, 10]. ++ * minfps and maxfps only suggest a fps range. The video device driver will select ++ * an appropriate value automatically. The actual fps depends on environmental circumstances ++ * such as brightness, illumination, etc. ++ * sample.c illustrates how to calculate actual frame rate. ++ * ++ */ ++#define WCAM_VIDIOCSFPS 221 ++ ++/*! ++ * WCAM_VIDIOCSNIGHTMODE Sets the video device capture mode. ++ * ++ * The capture mode can use the following values ++ * ++ * V4l_NM_AUTO Auto mode(default value) ++ * V4l_NM_NIGHT Night mode ++ * V4l_NM_ACTION Action mode ++ * ++ * The following code segment shows how to set the video device to night mode: ++ * ++ * ioctl(dev, WCAM_VIDIOCSNIGHTMODE, V4l_NM_NIGHT); ++ * ++ * Remarks: ++ * Different capture modes represent different sensor exposure times. Night mode represents a longer ++ * exposure time. Setting the video device to night mode can capture high quality image data in low light environments. ++ * Action mode represents a shorter exposure time. This is used for capture moving objects. When working in auto mode, the ++ * video device will select an appropriate exposure time automatically. ++ * ++ * Not all camera modules support this interface. Developers can also use WCAM_VIDIOCSFPS to achieve similar results. ++ * Smaller minfps represent longer exposure times. ++ * ++ */ ++#define WCAM_VIDIOCSNIGHTMODE 222 ++ ++/*! ++ * WCAM_VIDIOCSSTYLE Sets the image style. ++ * ++ * The following styles are supported: ++ * ++ * V4l_STYLE_NORMAL Normal (default value) ++ * V4l_STYLE_BLACK_WHITE Black and white ++ * V4l_STYLE_SEPIA Sepia ++ * V4l_STYLE_SOLARIZE Solarized (not supported by all camera modules) ++ * V4l_STYLE_NEG_ART Negative (not supported by all camera modules) ++ * ++ * The following code segment demonstrates how to set the image style to black and white: ++ * ++ * ioctl(dev, WCAM_VIDIOCSSTYLE, V4l_STYLE_BLACK_WHITE); ++ * ++ */ ++#define WCAM_VIDIOCSSTYLE 250 ++ ++/*! ++ * WCAM_VIDIOCSLIGHT Sets the image light mode ++ * ++ * The following light modes are supported: ++ * V4l_WB_AUTO Auto mode(default) ++ * V4l_WB_DIRECT_SUN Direct sun ++ * V4l_WB_INCANDESCENT Incandescent ++ * V4l_WB_FLUORESCENT Fluorescent ++ * ++ * The following code sets the image light mode to incandescent: ++ * ioctl(dev, WCAM_VIDIOCSLIGHT, V4l_WB_INCANDESCENT); ++ */ ++#define WCAM_VIDIOCSLIGHT 251 ++ ++/*! ++ * WCAM_VIDIOCSBRIGHT Sets the brightness of the image (exposure compensation value) ++ * ++ * parameter value exposure value ++ * -4 -2.0 EV ++ * -3 -1.5 EV ++ * -2 -1.0 EV ++ * -1 -0.5 EV ++ * 0 0.0 EV(default value) ++ * 1 +0.5 EV ++ * 2 +1.0 EV ++ * 3 +1.5 EV ++ * 4 +2.0 EV ++ * ++ * The following code segment sets the brightness to 2.0 EV ++ * ioctl(dev, WCAM_VIDIOCSBRIGHT, 4); ++ */ ++#define WCAM_VIDIOCSBRIGHT 252 ++ ++/*! ++ * Sets the frame buffer count for video mode. The default value is 3. ++ * ++ * Remarks: ++ * The video device driver maintains some memory for buffering image data in the kernel space. When working in video mode, ++ * there are at least 3 frame buffers in the driver. In still mode, there is only 1 frame buffer. ++ * This interface is not open to SDK developers. ++ * ++ */ ++#define WCAM_VIDIOCSBUFCOUNT 253 ++ ++/*! ++ * Gets the current available frames ++ * ++ * The following code demonstrates getting the current available frames: ++ * ++ * struct {int first, last;}cur_frms; ++ * ioctl(dev, WCAM_VIDIOCGCURFRMS, &cur_frms); ++ * ++ * Remarks: ++ * cur_frms.first represents the earliest frame in frame buffer ++ * cur_frms.last represents the latest or most recent frame in frame buffer. ++ */ ++#define WCAM_VIDIOCGCURFRMS 254 ++ ++/*! ++ * Gets the camera sensor type ++ * ++ * unsigned int sensor_type ++ * ioctl(dev, WCAM_VIDIOCGSTYPE, &sensor_type); ++ * if(sensor_type == CAMERA_TYPE_ADCM_2700) ++ * { ++ * printf("Agilent ADCM2700"); ++ * } ++ * ++ * Remarks: ++ * For all possible values of sensor_type please refer to the sensor definitions below. ++ */ ++#define WCAM_VIDIOCGSTYPE 255 ++ ++/*! ++ * Sets the image contrast ++ * Not open to SDK developers ++ */ ++#define WCAM_VIDIOCSCONTRAST 256 ++ ++/*! ++ * Sets the flicker frequency(50hz/60hz) ++ * Not open to SDK developers ++ */ ++#define WCAM_VIDIOCSFLICKER 257 ++ ++ ++ ++typedef enum V4l_NIGHT_MODE ++{ ++ V4l_NM_AUTO, ++ V4l_NM_NIGHT, ++ V4l_NM_ACTION ++}V4l_NM; ++ ++typedef enum V4l_PIC_STYLE ++{ ++ V4l_STYLE_NORMAL, ++ V4l_STYLE_BLACK_WHITE, ++ V4l_STYLE_SEPIA, ++ V4l_STYLE_SOLARIZE, ++ V4l_STYLE_NEG_ART ++}V4l_PIC_STYLE; ++ ++typedef enum V4l_PIC_WB ++{ ++ V4l_WB_AUTO, ++ V4l_WB_DIRECT_SUN, ++ V4l_WB_INCANDESCENT, ++ V4l_WB_FLUORESCENT ++}V4l_PIC_WB; ++ ++ ++ ++/*! ++ *Image format definitions ++ *Remarks: ++ * Although not all formats are supported by all camera modules, YCBCR422_PLANAR is widely supported. ++ * For detailed information on each format please refer to the Intel PXA27x processor family developer's manual. ++ * http://www.intel.com/design/pca/prodbref/253820.html ++ * ++ */ ++#define CAMERA_IMAGE_FORMAT_RAW8 0 ++#define CAMERA_IMAGE_FORMAT_RAW9 1 ++#define CAMERA_IMAGE_FORMAT_RAW10 2 ++ ++#define CAMERA_IMAGE_FORMAT_RGB444 3 ++#define CAMERA_IMAGE_FORMAT_RGB555 4 ++#define CAMERA_IMAGE_FORMAT_RGB565 5 ++#define CAMERA_IMAGE_FORMAT_RGB666_PACKED 6 ++#define CAMERA_IMAGE_FORMAT_RGB666_PLANAR 7 ++#define CAMERA_IMAGE_FORMAT_RGB888_PACKED 8 ++#define CAMERA_IMAGE_FORMAT_RGB888_PLANAR 9 ++#define CAMERA_IMAGE_FORMAT_RGBT555_0 10 //RGB+Transparent bit 0 ++#define CAMERA_IMAGE_FORMAT_RGBT888_0 11 ++#define CAMERA_IMAGE_FORMAT_RGBT555_1 12 //RGB+Transparent bit 1 ++#define CAMERA_IMAGE_FORMAT_RGBT888_1 13 ++ ++#define CAMERA_IMAGE_FORMAT_YCBCR400 14 ++#define CAMERA_IMAGE_FORMAT_YCBCR422_PACKED 15 ++#define CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR 16 ++#define CAMERA_IMAGE_FORMAT_YCBCR444_PACKED 17 ++#define CAMERA_IMAGE_FORMAT_YCBCR444_PLANAR 18 ++ ++/*! ++ *VIDIOCCAPTURE arguments ++ */ ++#define STILL_IMAGE 1 ++#define VIDEO_START 0 ++#define VIDEO_STOP -1 ++ ++/*! ++ *Sensor type definitions ++ */ ++#define CAMERA_TYPE_ADCM_2650 1 ++#define CAMERA_TYPE_ADCM_2670 2 ++#define CAMERA_TYPE_ADCM_2700 3 ++#define CAMERA_TYPE_OMNIVISION_9640 4 ++#define CAMERA_TYPE_MT9M111 5 ++#define CAMERA_TYPE_MT9V111 6 ++#define CAMERA_TYPE_ADCM3800 7 ++#define CAMERA_TYPE_OV9650 8 ++#define CAMERA_TYPE_MAX CAMERA_TYPE_OV9650 ++ ++ ++/* ++ * Definitions of the camera's i2c device ++ */ ++#define CAMERA_I2C_WRITEW 101 ++#define CAMERA_I2C_WRITEB 102 ++#define CAMERA_I2C_READW 103 ++#define CAMERA_I2C_READB 104 ++#define CAMERA_I2C_DETECTID 105 ++ ++struct camera_i2c_register { ++ unsigned short addr; ++ union { ++ unsigned short w; ++ unsigned char b; ++ } value; ++}; ++ ++struct camera_i2c_detectid { ++ int buflen; ++ char data[256]; ++}; ++ ++//End of the camera's i2c device ++ ++#endif // __PXA_CAMERA_H__ ++ +diff -Nurd linux-2.6.16.orig/include/linux/raid/raid1.h linux-2.6.16/include/linux/raid/raid1.h +--- linux-2.6.16.orig/include/linux/raid/raid1.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/raid/raid1.h 2006-06-03 11:14:55.369471816 +0200 +@@ -130,6 +130,6 @@ + * with failure when last write completes (and all failed). + * Record that bi_end_io was called with this flag... + */ +-#define R1BIO_Returned 4 ++#define R1BIO_Returned 6 + + #endif +diff -Nurd linux-2.6.16.orig/include/linux/rtc.h linux-2.6.16/include/linux/rtc.h +--- linux-2.6.16.orig/include/linux/rtc.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/rtc.h 2006-06-03 11:14:55.370471664 +0200 +@@ -11,8 +11,6 @@ + #ifndef _LINUX_RTC_H_ + #define _LINUX_RTC_H_ + +-#include <linux/interrupt.h> +- + /* + * The struct used to pass data via the following ioctl. Similar to the + * struct tm in <time.h>, but it needs to be here so that the kernel +@@ -95,6 +93,8 @@ + + #ifdef __KERNEL__ + ++#include <linux/interrupt.h> ++ + typedef struct rtc_task { + void (*func)(void *private_data); + void *private_data; +diff -Nurd linux-2.6.16.orig/include/linux/sched.h linux-2.6.16/include/linux/sched.h +--- linux-2.6.16.orig/include/linux/sched.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/sched.h 2006-06-03 11:14:55.908389888 +0200 +@@ -860,6 +860,7 @@ + u64 acct_vm_mem1; /* accumulated virtual memory usage */ + clock_t acct_stimexpd; /* clock_t-converted stime since last update */ + #endif ++ int dpm_state; /* DPM operating state to use for this task */ + #ifdef CONFIG_NUMA + struct mempolicy *mempolicy; + short il_next; +diff -Nurd linux-2.6.16.orig/include/linux/spi/spi.h linux-2.6.16/include/linux/spi/spi.h +--- linux-2.6.16.orig/include/linux/spi/spi.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/linux/spi/spi.h 2006-06-03 11:14:57.130204144 +0200 +@@ -19,6 +19,8 @@ + #ifndef __LINUX_SPI_H + #define __LINUX_SPI_H + ++#include <linux/device.h> ++ + /* + * INTERFACES between SPI master-side drivers and SPI infrastructure. + * (There's no SPI slave support for Linux yet...) +@@ -205,6 +207,9 @@ + int (*transfer)(struct spi_device *spi, + struct spi_message *mesg); + ++ /* bidirectional bulk transfer, synchronous, non-sleeping */ ++ int (*transfer_nosleep)(struct spi_device *spi, ++ struct spi_message *mesg); + /* called on release() to free memory provided by spi_master */ + void (*cleanup)(const struct spi_device *spi); + }; +@@ -485,6 +490,16 @@ + return spi->master->transfer(spi, message); + } + ++static inline int ++spi_sync_nosleep(struct spi_device *spi, struct spi_message *msg) ++{ ++ if (!spi->master->transfer_nosleep) ++ return -EIO; ++ ++ msg->spi = spi; ++ return spi->master->transfer_nosleep(spi, msg); ++} ++ + /*---------------------------------------------------------------------------*/ + + /* All these synchronous SPI transfer routines are utilities layered +diff -Nurd linux-2.6.16.orig/include/linux/wrapper.h linux-2.6.16/include/linux/wrapper.h +--- linux-2.6.16.orig/include/linux/wrapper.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/include/linux/wrapper.h 2006-06-03 11:14:56.344323616 +0200 +@@ -0,0 +1,7 @@ ++#ifndef _WRAPPER_H_ ++#define _WRAPPER_H_ ++ ++#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags)) ++#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags)) ++ ++#endif /* _WRAPPER_H_ */ +diff -Nurd linux-2.6.16.orig/include/net/ip.h linux-2.6.16/include/net/ip.h +--- linux-2.6.16.orig/include/net/ip.h 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/include/net/ip.h 2006-06-03 11:14:55.370471664 +0200 +@@ -95,6 +95,7 @@ + extern int ip_mr_input(struct sk_buff *skb); + extern int ip_output(struct sk_buff *skb); + extern int ip_mc_output(struct sk_buff *skb); ++extern int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); + extern int ip_do_nat(struct sk_buff *skb); + extern void ip_send_check(struct iphdr *ip); + extern int ip_queue_xmit(struct sk_buff *skb, int ipfragok); +diff -Nurd linux-2.6.16.orig/ipc/shm.c linux-2.6.16/ipc/shm.c +--- linux-2.6.16.orig/ipc/shm.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/ipc/shm.c 2006-06-03 11:14:55.371471512 +0200 +@@ -161,6 +161,8 @@ + ret = shmem_mmap(file, vma); + if (ret == 0) { + vma->vm_ops = &shm_vm_ops; ++ if (!(vma->vm_flags & VM_WRITE)) ++ vma->vm_flags &= ~VM_MAYWRITE; + shm_inc(file->f_dentry->d_inode->i_ino); + } + +diff -Nurd linux-2.6.16.orig/ipc/util.c linux-2.6.16/ipc/util.c +--- linux-2.6.16.orig/ipc/util.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/ipc/util.c 2006-06-03 11:14:55.371471512 +0200 +@@ -182,8 +182,7 @@ + if(new == NULL) + return size; + new->size = newsize; +- memcpy(new->p, ids->entries->p, sizeof(struct kern_ipc_perm *)*size + +- sizeof(struct ipc_id_ary)); ++ memcpy(new->p, ids->entries->p, sizeof(struct kern_ipc_perm *)*size); + for(i=size;i<newsize;i++) { + new->p[i] = NULL; + } +diff -Nurd linux-2.6.16.orig/kernel/auditsc.c linux-2.6.16/kernel/auditsc.c +--- linux-2.6.16.orig/kernel/auditsc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/auditsc.c 2006-06-03 11:14:55.372471360 +0200 +@@ -966,11 +966,6 @@ + if (context->in_syscall) { + struct audit_context *newctx; + +-#if defined(__NR_vm86) && defined(__NR_vm86old) +- /* vm86 mode should only be entered once */ +- if (major == __NR_vm86 || major == __NR_vm86old) +- return; +-#endif + #if AUDIT_DEBUG + printk(KERN_ERR + "audit(:%d) pid=%d in syscall=%d;" +diff -Nurd linux-2.6.16.orig/kernel/exec_domain.c linux-2.6.16/kernel/exec_domain.c +--- linux-2.6.16.orig/kernel/exec_domain.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/exec_domain.c 2006-06-03 11:14:55.373471208 +0200 +@@ -140,6 +140,7 @@ + ep = lookup_exec_domain(personality); + if (ep == current_thread_info()->exec_domain) { + current->personality = personality; ++ module_put(ep->module); + return 0; + } + +diff -Nurd linux-2.6.16.orig/kernel/fork.c linux-2.6.16/kernel/fork.c +--- linux-2.6.16.orig/kernel/fork.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/fork.c 2006-06-03 11:14:55.373471208 +0200 +@@ -720,7 +720,7 @@ + free_fdset (new_fdt->open_fds, new_fdt->max_fdset); + free_fd_array(new_fdt->fd, new_fdt->max_fds); + kmem_cache_free(files_cachep, newf); +- goto out; ++ return NULL; + } + + static int copy_files(unsigned long clone_flags, struct task_struct * tsk) +diff -Nurd linux-2.6.16.orig/kernel/power/process.c linux-2.6.16/kernel/power/process.c +--- linux-2.6.16.orig/kernel/power/process.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/power/process.c 2006-06-03 11:14:55.374471056 +0200 +@@ -25,8 +25,7 @@ + (p->flags & PF_NOFREEZE) || + (p->exit_state == EXIT_ZOMBIE) || + (p->exit_state == EXIT_DEAD) || +- (p->state == TASK_STOPPED) || +- (p->state == TASK_TRACED)) ++ (p->state == TASK_STOPPED)) + return 0; + return 1; + } +diff -Nurd linux-2.6.16.orig/kernel/ptrace.c linux-2.6.16/kernel/ptrace.c +--- linux-2.6.16.orig/kernel/ptrace.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/ptrace.c 2006-06-03 11:14:55.374471056 +0200 +@@ -57,10 +57,6 @@ + signal_wake_up(child, 1); + } + } +- if (child->signal->flags & SIGNAL_GROUP_EXIT) { +- sigaddset(&child->pending.signal, SIGKILL); +- signal_wake_up(child, 1); +- } + spin_unlock(&child->sighand->siglock); + } + +@@ -82,7 +78,8 @@ + SET_LINKS(child); + } + +- ptrace_untrace(child); ++ if (child->state == TASK_TRACED) ++ ptrace_untrace(child); + } + + /* +diff -Nurd linux-2.6.16.orig/kernel/sched.c linux-2.6.16/kernel/sched.c +--- linux-2.6.16.orig/kernel/sched.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/sched.c 2006-06-03 11:14:55.911389432 +0200 +@@ -49,6 +49,8 @@ + #include <linux/syscalls.h> + #include <linux/times.h> + #include <linux/acct.h> ++#include <linux/dpm.h> ++ + #include <asm/tlb.h> + + #include <asm/unistd.h> +@@ -237,6 +239,7 @@ + + task_t *migration_thread; + struct list_head migration_queue; ++ int cpu; + #endif + + #ifdef CONFIG_SCHEDSTATS +@@ -1660,6 +1663,9 @@ + /* + * double_rq_lock - safely lock two runqueues + * ++ * We must take them in cpu order to match code in ++ * dependent_sleeper and wake_dependent_sleeper. ++ * + * Note this does not disable interrupts like task_rq_lock, + * you need to do so manually before calling. + */ +@@ -1671,7 +1677,7 @@ + spin_lock(&rq1->lock); + __acquire(rq2->lock); /* Fake it out ;) */ + } else { +- if (rq1 < rq2) { ++ if (rq1->cpu < rq2->cpu) { + spin_lock(&rq1->lock); + spin_lock(&rq2->lock); + } else { +@@ -1707,7 +1713,7 @@ + __acquires(this_rq->lock) + { + if (unlikely(!spin_trylock(&busiest->lock))) { +- if (busiest < this_rq) { ++ if (busiest->cpu < this_rq->cpu) { + spin_unlock(&this_rq->lock); + spin_lock(&busiest->lock); + spin_lock(&this_rq->lock); +@@ -6035,6 +6041,7 @@ + rq->push_cpu = 0; + rq->migration_thread = NULL; + INIT_LIST_HEAD(&rq->migration_queue); ++ rq->cpu = i; + #endif + atomic_set(&rq->nr_iowait, 0); + +diff -Nurd linux-2.6.16.orig/kernel/signal.c linux-2.6.16/kernel/signal.c +--- linux-2.6.16.orig/kernel/signal.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/signal.c 2006-06-03 11:14:55.379470296 +0200 +@@ -975,7 +975,6 @@ + if (t == NULL) + /* restart balancing at this thread */ + t = p->signal->curr_target = p; +- BUG_ON(t->tgid != p->tgid); + + while (!wants_signal(sig, t)) { + t = next_thread(t); +@@ -1689,6 +1688,7 @@ + /* Let the debugger run. */ + set_current_state(TASK_TRACED); + spin_unlock_irq(¤t->sighand->siglock); ++ try_to_freeze(); + read_lock(&tasklist_lock); + if (likely(current->ptrace & PT_PTRACED) && + likely(current->parent != current->real_parent || +@@ -1942,9 +1942,9 @@ + /* Let the debugger run. */ + ptrace_stop(signr, signr, info); + +- /* We're back. Did the debugger cancel the sig or group_exit? */ ++ /* We're back. Did the debugger cancel the sig? */ + signr = current->exit_code; +- if (signr == 0 || current->signal->flags & SIGNAL_GROUP_EXIT) ++ if (signr == 0) + continue; + + current->exit_code = 0; +diff -Nurd linux-2.6.16.orig/kernel/softirq.c linux-2.6.16/kernel/softirq.c +--- linux-2.6.16.orig/kernel/softirq.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/softirq.c 2006-06-03 11:14:55.912389280 +0200 +@@ -45,6 +45,8 @@ + + static DEFINE_PER_CPU(struct task_struct *, ksoftirqd); + ++#include <linux/dpm.h> ++ + /* + * we cannot loop indefinitely here to avoid userspace starvation, + * but we also don't want to introduce a worst case 1/HZ latency +@@ -352,6 +354,11 @@ + set_user_nice(current, 19); + current->flags |= PF_NOFREEZE; + ++#ifdef CONFIG_DPM ++ /* Identify as a system task for DPM purposes */ ++ current->dpm_state = DPM_NO_STATE; ++#endif ++ + set_current_state(TASK_INTERRUPTIBLE); + + while (!kthread_should_stop()) { +diff -Nurd linux-2.6.16.orig/kernel/sys.c linux-2.6.16/kernel/sys.c +--- linux-2.6.16.orig/kernel/sys.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/sys.c 2006-06-03 11:14:55.380470144 +0200 +@@ -1657,7 +1657,19 @@ + (cputime_eq(current->signal->it_prof_expires, cputime_zero) || + new_rlim.rlim_cur <= cputime_to_secs( + current->signal->it_prof_expires))) { +- cputime_t cputime = secs_to_cputime(new_rlim.rlim_cur); ++ unsigned long rlim_cur = new_rlim.rlim_cur; ++ cputime_t cputime; ++ ++ if (rlim_cur == 0) { ++ /* ++ * The caller is asking for an immediate RLIMIT_CPU ++ * expiry. But we use the zero value to mean "it was ++ * never set". So let's cheat and make it one second ++ * instead ++ */ ++ rlim_cur = 1; ++ } ++ cputime = secs_to_cputime(rlim_cur); + read_lock(&tasklist_lock); + spin_lock_irq(¤t->sighand->siglock); + set_process_cpu_timer(current, CPUCLOCK_PROF, +diff -Nurd linux-2.6.16.orig/kernel/uid16.c linux-2.6.16/kernel/uid16.c +--- linux-2.6.16.orig/kernel/uid16.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/uid16.c 2006-06-03 11:14:55.381469992 +0200 +@@ -20,43 +20,67 @@ + + asmlinkage long sys_chown16(const char __user * filename, old_uid_t user, old_gid_t group) + { +- return sys_chown(filename, low2highuid(user), low2highgid(group)); ++ long ret = sys_chown(filename, low2highuid(user), low2highgid(group)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_lchown16(const char __user * filename, old_uid_t user, old_gid_t group) + { +- return sys_lchown(filename, low2highuid(user), low2highgid(group)); ++ long ret = sys_lchown(filename, low2highuid(user), low2highgid(group)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group) + { +- return sys_fchown(fd, low2highuid(user), low2highgid(group)); ++ long ret = sys_fchown(fd, low2highuid(user), low2highgid(group)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid) + { +- return sys_setregid(low2highgid(rgid), low2highgid(egid)); ++ long ret = sys_setregid(low2highgid(rgid), low2highgid(egid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_setgid16(old_gid_t gid) + { +- return sys_setgid(low2highgid(gid)); ++ long ret = sys_setgid(low2highgid(gid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid) + { +- return sys_setreuid(low2highuid(ruid), low2highuid(euid)); ++ long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_setuid16(old_uid_t uid) + { +- return sys_setuid(low2highuid(uid)); ++ long ret = sys_setuid(low2highuid(uid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid) + { +- return sys_setresuid(low2highuid(ruid), low2highuid(euid), +- low2highuid(suid)); ++ long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid), ++ low2highuid(suid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid) +@@ -72,8 +96,11 @@ + + asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid) + { +- return sys_setresgid(low2highgid(rgid), low2highgid(egid), +- low2highgid(sgid)); ++ long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid), ++ low2highgid(sgid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid) +@@ -89,12 +116,18 @@ + + asmlinkage long sys_setfsuid16(old_uid_t uid) + { +- return sys_setfsuid(low2highuid(uid)); ++ long ret = sys_setfsuid(low2highuid(uid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + asmlinkage long sys_setfsgid16(old_gid_t gid) + { +- return sys_setfsgid(low2highgid(gid)); ++ long ret = sys_setfsgid(low2highgid(gid)); ++ /* avoid REGPARM breakage on x86: */ ++ prevent_tail_call(ret); ++ return ret; + } + + static int groups16_to_user(old_gid_t __user *grouplist, +diff -Nurd linux-2.6.16.orig/kernel/workqueue.c linux-2.6.16/kernel/workqueue.c +--- linux-2.6.16.orig/kernel/workqueue.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/kernel/workqueue.c 2006-06-03 11:14:55.912389280 +0200 +@@ -23,6 +23,7 @@ + #include <linux/signal.h> + #include <linux/completion.h> + #include <linux/workqueue.h> ++#include <linux/dpm.h> + #include <linux/slab.h> + #include <linux/cpu.h> + #include <linux/notifier.h> +@@ -195,6 +196,11 @@ + + set_user_nice(current, -5); + ++#ifdef CONFIG_DPM ++ /* Identify as a system task for DPM purposes */ ++ current->dpm_state = DPM_NO_STATE; ++#endif ++ + /* Block and flush all signals */ + sigfillset(&blocked); + sigprocmask(SIG_BLOCK, &blocked, NULL); +diff -Nurd linux-2.6.16.orig/Makefile linux-2.6.16/Makefile +--- linux-2.6.16.orig/Makefile 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/Makefile 2006-06-03 11:14:55.219494616 +0200 +@@ -1,7 +1,7 @@ + VERSION = 2 + PATCHLEVEL = 6 + SUBLEVEL = 16 +-EXTRAVERSION = ++EXTRAVERSION = .13 + NAME=Sliding Snow Leopard + + # *DOCUMENTATION* +diff -Nurd linux-2.6.16.orig/mm/madvise.c linux-2.6.16/mm/madvise.c +--- linux-2.6.16.orig/mm/madvise.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/mm/madvise.c 2006-06-03 11:14:55.381469992 +0200 +@@ -168,6 +168,9 @@ + return -EINVAL; + } + ++ if ((vma->vm_flags & (VM_SHARED|VM_WRITE)) != (VM_SHARED|VM_WRITE)) ++ return -EACCES; ++ + mapping = vma->vm_file->f_mapping; + + offset = (loff_t)(start - vma->vm_start) +diff -Nurd linux-2.6.16.orig/mm/page_alloc.c linux-2.6.16/mm/page_alloc.c +--- linux-2.6.16.orig/mm/page_alloc.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/mm/page_alloc.c 2006-06-03 11:14:55.383469688 +0200 +@@ -153,7 +153,8 @@ + 1 << PG_reclaim | + 1 << PG_slab | + 1 << PG_swapcache | +- 1 << PG_writeback ); ++ 1 << PG_writeback | ++ 1 << PG_buddy ); + set_page_count(page, 0); + reset_page_mapcount(page); + page->mapping = NULL; +@@ -224,12 +225,12 @@ + + static inline void set_page_order(struct page *page, int order) { + set_page_private(page, order); +- __SetPagePrivate(page); ++ __SetPageBuddy(page); + } + + static inline void rmv_page_order(struct page *page) + { +- __ClearPagePrivate(page); ++ __ClearPageBuddy(page); + set_page_private(page, 0); + } + +@@ -268,11 +269,13 @@ + * This function checks whether a page is free && is the buddy + * we can do coalesce a page and its buddy if + * (a) the buddy is not in a hole && +- * (b) the buddy is free && +- * (c) the buddy is on the buddy system && +- * (d) a page and its buddy have the same order. +- * for recording page's order, we use page_private(page) and PG_private. ++ * (b) the buddy is in the buddy system && ++ * (c) a page and its buddy have the same order. ++ * ++ * For recording whether a page is in the buddy system, we use PG_buddy. ++ * Setting, clearing, and testing PG_buddy is serialized by zone->lock. + * ++ * For recording page's order, we use page_private(page). + */ + static inline int page_is_buddy(struct page *page, int order) + { +@@ -281,10 +284,10 @@ + return 0; + #endif + +- if (PagePrivate(page) && +- (page_order(page) == order) && +- page_count(page) == 0) ++ if (PageBuddy(page) && page_order(page) == order) { ++ BUG_ON(page_count(page) != 0); + return 1; ++ } + return 0; + } + +@@ -301,7 +304,7 @@ + * as necessary, plus some accounting needed to play nicely with other + * parts of the VM system. + * At each level, we keep a list of pages, which are heads of continuous +- * free pages of length of (1 << order) and marked with PG_Private.Page's ++ * free pages of length of (1 << order) and marked with PG_buddy. Page's + * order is recorded in page_private(page) field. + * So when we are allocating or freeing one, we can derive the state of the + * other. That is, if we allocate a small block, and both were +@@ -364,7 +367,8 @@ + 1 << PG_slab | + 1 << PG_swapcache | + 1 << PG_writeback | +- 1 << PG_reserved )))) ++ 1 << PG_reserved | ++ 1 << PG_buddy )))) + bad_page(page); + if (PageDirty(page)) + __ClearPageDirty(page); +@@ -522,7 +526,8 @@ + 1 << PG_slab | + 1 << PG_swapcache | + 1 << PG_writeback | +- 1 << PG_reserved )))) ++ 1 << PG_reserved | ++ 1 << PG_buddy )))) + bad_page(page); + + /* +diff -Nurd linux-2.6.16.orig/net/atm/clip.c linux-2.6.16/net/atm/clip.c +--- linux-2.6.16.orig/net/atm/clip.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/atm/clip.c 2006-06-03 11:14:55.394468016 +0200 +@@ -613,12 +613,19 @@ + + + static int clip_device_event(struct notifier_block *this,unsigned long event, +- void *dev) ++ void *arg) + { ++ struct net_device *dev = arg; ++ ++ if (event == NETDEV_UNREGISTER) { ++ neigh_ifdown(&clip_tbl, dev); ++ return NOTIFY_DONE; ++ } ++ + /* ignore non-CLIP devices */ +- if (((struct net_device *) dev)->type != ARPHRD_ATM || +- ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit) ++ if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit) + return NOTIFY_DONE; ++ + switch (event) { + case NETDEV_UP: + DPRINTK("clip_device_event NETDEV_UP\n"); +@@ -686,14 +693,12 @@ + static void atmarpd_close(struct atm_vcc *vcc) + { + DPRINTK("atmarpd_close\n"); +- atmarpd = NULL; /* assumed to be atomic */ +- barrier(); +- unregister_inetaddr_notifier(&clip_inet_notifier); +- unregister_netdevice_notifier(&clip_dev_notifier); +- if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) +- printk(KERN_ERR "atmarpd_close: closing with requests " +- "pending\n"); ++ ++ rtnl_lock(); ++ atmarpd = NULL; + skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); ++ rtnl_unlock(); ++ + DPRINTK("(done)\n"); + module_put(THIS_MODULE); + } +@@ -714,7 +719,12 @@ + + static int atm_init_atmarp(struct atm_vcc *vcc) + { +- if (atmarpd) return -EADDRINUSE; ++ rtnl_lock(); ++ if (atmarpd) { ++ rtnl_unlock(); ++ return -EADDRINUSE; ++ } ++ + if (start_timer) { + start_timer = 0; + init_timer(&idle_timer); +@@ -731,10 +741,7 @@ + vcc->push = NULL; + vcc->pop = NULL; /* crash */ + vcc->push_oam = NULL; /* crash */ +- if (register_netdevice_notifier(&clip_dev_notifier)) +- printk(KERN_ERR "register_netdevice_notifier failed\n"); +- if (register_inetaddr_notifier(&clip_inet_notifier)) +- printk(KERN_ERR "register_inetaddr_notifier failed\n"); ++ rtnl_unlock(); + return 0; + } + +@@ -992,6 +999,8 @@ + + clip_tbl_hook = &clip_tbl; + register_atm_ioctl(&clip_ioctl_ops); ++ register_netdevice_notifier(&clip_dev_notifier); ++ register_inetaddr_notifier(&clip_inet_notifier); + + #ifdef CONFIG_PROC_FS + { +@@ -1012,6 +1021,9 @@ + + remove_proc_entry("arp", atm_proc_root); + ++ unregister_inetaddr_notifier(&clip_inet_notifier); ++ unregister_netdevice_notifier(&clip_dev_notifier); ++ + deregister_atm_ioctl(&clip_ioctl_ops); + + /* First, stop the idle timer, so it stops banging +diff -Nurd linux-2.6.16.orig/net/bridge/br_netfilter.c linux-2.6.16/net/bridge/br_netfilter.c +--- linux-2.6.16.orig/net/bridge/br_netfilter.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/bridge/br_netfilter.c 2006-06-03 11:14:55.403466648 +0200 +@@ -739,6 +739,15 @@ + return NF_STOLEN; + } + ++static int br_nf_dev_queue_xmit(struct sk_buff *skb) ++{ ++ if (skb->protocol == htons(ETH_P_IP) && ++ skb->len > skb->dev->mtu && ++ !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) ++ return ip_fragment(skb, br_dev_queue_push_xmit); ++ else ++ return br_dev_queue_push_xmit(skb); ++} + + /* PF_BRIDGE/POST_ROUTING ********************************************/ + static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, +@@ -798,7 +807,7 @@ + realoutdev = nf_bridge->netoutdev; + #endif + NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, +- br_dev_queue_push_xmit); ++ br_nf_dev_queue_xmit); + + return NF_STOLEN; + +@@ -843,7 +852,7 @@ + if ((out->hard_start_xmit == br_dev_xmit && + okfn != br_nf_forward_finish && + okfn != br_nf_local_out_finish && +- okfn != br_dev_queue_push_xmit) ++ okfn != br_nf_dev_queue_xmit) + #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + || ((out->priv_flags & IFF_802_1Q_VLAN) && + VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit) +diff -Nurd linux-2.6.16.orig/net/core/dev.c linux-2.6.16/net/core/dev.c +--- linux-2.6.16.orig/net/core/dev.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/core/dev.c 2006-06-03 11:14:55.405466344 +0200 +@@ -2932,11 +2932,11 @@ + + switch(dev->reg_state) { + case NETREG_REGISTERING: ++ dev->reg_state = NETREG_REGISTERED; + err = netdev_register_sysfs(dev); + if (err) + printk(KERN_ERR "%s: failed sysfs registration (%d)\n", + dev->name, err); +- dev->reg_state = NETREG_REGISTERED; + break; + + case NETREG_UNREGISTERING: +diff -Nurd linux-2.6.16.orig/net/core/sock.c linux-2.6.16/net/core/sock.c +--- linux-2.6.16.orig/net/core/sock.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/core/sock.c 2006-06-03 11:14:55.406466192 +0200 +@@ -404,8 +404,9 @@ + if (!valbool) { + sk->sk_bound_dev_if = 0; + } else { +- if (optlen > IFNAMSIZ) +- optlen = IFNAMSIZ; ++ if (optlen > IFNAMSIZ - 1) ++ optlen = IFNAMSIZ - 1; ++ memset(devname, 0, sizeof(devname)); + if (copy_from_user(devname, optval, optlen)) { + ret = -EFAULT; + break; +diff -Nurd linux-2.6.16.orig/net/ipv4/fib_trie.c linux-2.6.16/net/ipv4/fib_trie.c +--- linux-2.6.16.orig/net/ipv4/fib_trie.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv4/fib_trie.c 2006-06-03 11:14:55.407466040 +0200 +@@ -314,11 +314,6 @@ + kfree(container_of(head, struct leaf, rcu)); + } + +-static inline void free_leaf(struct leaf *leaf) +-{ +- call_rcu(&leaf->rcu, __leaf_free_rcu); +-} +- + static void __leaf_info_free_rcu(struct rcu_head *head) + { + kfree(container_of(head, struct leaf_info, rcu)); +@@ -357,7 +352,12 @@ + + static inline void tnode_free(struct tnode *tn) + { +- call_rcu(&tn->rcu, __tnode_free_rcu); ++ if(IS_LEAF(tn)) { ++ struct leaf *l = (struct leaf *) tn; ++ call_rcu_bh(&l->rcu, __leaf_free_rcu); ++ } ++ else ++ call_rcu(&tn->rcu, __tnode_free_rcu); + } + + static struct leaf *leaf_new(void) +diff -Nurd linux-2.6.16.orig/net/ipv4/ip_output.c linux-2.6.16/net/ipv4/ip_output.c +--- linux-2.6.16.orig/net/ipv4/ip_output.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv4/ip_output.c 2006-06-03 11:14:55.408465888 +0200 +@@ -86,8 +86,6 @@ + + int sysctl_ip_default_ttl = IPDEFTTL; + +-static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)); +- + /* Generate a checksum for an outgoing IP datagram. */ + __inline__ void ip_send_check(struct iphdr *iph) + { +@@ -421,7 +419,7 @@ + * single device frame, and queue such a frame for sending. + */ + +-static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) ++int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) + { + struct iphdr *iph; + int raw = 0; +@@ -673,6 +671,8 @@ + return err; + } + ++EXPORT_SYMBOL(ip_fragment); ++ + int + ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) + { +@@ -1249,11 +1249,7 @@ + iph->tos = inet->tos; + iph->tot_len = htons(skb->len); + iph->frag_off = df; +- if (!df) { +- __ip_select_ident(iph, &rt->u.dst, 0); +- } else { +- iph->id = htons(inet->id++); +- } ++ ip_select_ident(iph, &rt->u.dst, sk); + iph->ttl = ttl; + iph->protocol = sk->sk_protocol; + iph->saddr = rt->rt_src; +diff -Nurd linux-2.6.16.orig/net/ipv4/netfilter/ip_conntrack_netlink.c linux-2.6.16/net/ipv4/netfilter/ip_conntrack_netlink.c +--- linux-2.6.16.orig/net/ipv4/netfilter/ip_conntrack_netlink.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv4/netfilter/ip_conntrack_netlink.c 2006-06-03 11:14:55.409465736 +0200 +@@ -1619,7 +1619,7 @@ + printk("ctnetlink: unregistering from nfnetlink.\n"); + + #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS +- ip_conntrack_unregister_notifier(&ctnl_notifier_exp); ++ ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); + ip_conntrack_unregister_notifier(&ctnl_notifier); + #endif + +diff -Nurd linux-2.6.16.orig/net/ipv4/netfilter/ip_conntrack_proto_sctp.c linux-2.6.16/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +--- linux-2.6.16.orig/net/ipv4/netfilter/ip_conntrack_proto_sctp.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv4/netfilter/ip_conntrack_proto_sctp.c 2006-06-03 11:14:55.410465584 +0200 +@@ -235,12 +235,15 @@ + flag = 1; + } + +- /* Cookie Ack/Echo chunks not the first OR +- Init / Init Ack / Shutdown compl chunks not the only chunks */ +- if ((sch->type == SCTP_CID_COOKIE_ACK ++ /* ++ * Cookie Ack/Echo chunks not the first OR ++ * Init / Init Ack / Shutdown compl chunks not the only chunks ++ * OR zero-length. ++ */ ++ if (((sch->type == SCTP_CID_COOKIE_ACK + || sch->type == SCTP_CID_COOKIE_ECHO + || flag) +- && count !=0 ) { ++ && count !=0) || !sch->length) { + DEBUGP("Basic checks failed\n"); + return 1; + } +diff -Nurd linux-2.6.16.orig/net/ipv4/route.c linux-2.6.16/net/ipv4/route.c +--- linux-2.6.16.orig/net/ipv4/route.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv4/route.c 2006-06-03 11:14:55.414464976 +0200 +@@ -2750,7 +2750,10 @@ + /* Reserve room for dummy headers, this skb can pass + through good chunk of routing engine. + */ +- skb->mac.raw = skb->data; ++ skb->mac.raw = skb->nh.raw = skb->data; ++ ++ /* Bugfix: need to give ip_route_input enough of an IP header to not gag. */ ++ skb->nh.iph->protocol = IPPROTO_ICMP; + skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); + + if (rta[RTA_SRC - 1]) +diff -Nurd linux-2.6.16.orig/net/ipv4/tcp_output.c linux-2.6.16/net/ipv4/tcp_output.c +--- linux-2.6.16.orig/net/ipv4/tcp_output.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv4/tcp_output.c 2006-06-03 11:14:55.416464672 +0200 +@@ -537,7 +537,9 @@ + buff = sk_stream_alloc_skb(sk, nsize, GFP_ATOMIC); + if (buff == NULL) + return -ENOMEM; /* We'll just try again later. */ +- sk_charge_skb(sk, buff); ++ ++ buff->truesize = skb->len - len; ++ skb->truesize -= buff->truesize; + + /* Correct the sequence numbers. */ + TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; +diff -Nurd linux-2.6.16.orig/net/ipv6/exthdrs.c linux-2.6.16/net/ipv6/exthdrs.c +--- linux-2.6.16.orig/net/ipv6/exthdrs.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv6/exthdrs.c 2006-06-03 11:14:55.641430472 +0200 +@@ -489,6 +489,18 @@ + { + struct inet6_skb_parm *opt = IP6CB(skb); + ++ /* ++ * skb->nh.raw is equal to skb->data, and ++ * skb->h.raw - skb->nh.raw is always equal to ++ * sizeof(struct ipv6hdr) by definition of ++ * hop-by-hop options. ++ */ ++ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) || ++ !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) { ++ kfree_skb(skb); ++ return -1; ++ } ++ + opt->hop = sizeof(struct ipv6hdr); + if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { + skb->h.raw += (skb->h.raw[1]+1)<<3; +diff -Nurd linux-2.6.16.orig/net/ipv6/xfrm6_policy.c linux-2.6.16/net/ipv6/xfrm6_policy.c +--- linux-2.6.16.orig/net/ipv6/xfrm6_policy.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/ipv6/xfrm6_policy.c 2006-06-03 11:14:55.642430320 +0200 +@@ -191,16 +191,18 @@ + static inline void + _decode_session6(struct sk_buff *skb, struct flowi *fl) + { +- u16 offset = sizeof(struct ipv6hdr); ++ u16 offset = skb->h.raw - skb->nh.raw; + struct ipv6hdr *hdr = skb->nh.ipv6h; +- struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); +- u8 nexthdr = skb->nh.ipv6h->nexthdr; ++ struct ipv6_opt_hdr *exthdr; ++ u8 nexthdr = skb->nh.raw[IP6CB(skb)->nhoff]; + + memset(fl, 0, sizeof(struct flowi)); + ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr); + ipv6_addr_copy(&fl->fl6_src, &hdr->saddr); + + while (pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) { ++ exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); ++ + switch (nexthdr) { + case NEXTHDR_ROUTING: + case NEXTHDR_HOP: +diff -Nurd linux-2.6.16.orig/net/netfilter/nf_conntrack_netlink.c linux-2.6.16/net/netfilter/nf_conntrack_netlink.c +--- linux-2.6.16.orig/net/netfilter/nf_conntrack_netlink.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/netfilter/nf_conntrack_netlink.c 2006-06-03 11:14:55.643430168 +0200 +@@ -1641,7 +1641,7 @@ + printk("ctnetlink: unregistering from nfnetlink.\n"); + + #ifdef CONFIG_NF_CONNTRACK_EVENTS +- nf_conntrack_unregister_notifier(&ctnl_notifier_exp); ++ nf_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); + nf_conntrack_unregister_notifier(&ctnl_notifier); + #endif + +diff -Nurd linux-2.6.16.orig/net/netfilter/nf_conntrack_proto_sctp.c linux-2.6.16/net/netfilter/nf_conntrack_proto_sctp.c +--- linux-2.6.16.orig/net/netfilter/nf_conntrack_proto_sctp.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/net/netfilter/nf_conntrack_proto_sctp.c 2006-06-03 11:14:55.643430168 +0200 +@@ -240,12 +240,15 @@ + flag = 1; + } + +- /* Cookie Ack/Echo chunks not the first OR +- Init / Init Ack / Shutdown compl chunks not the only chunks */ +- if ((sch->type == SCTP_CID_COOKIE_ACK ++ /* ++ * Cookie Ack/Echo chunks not the first OR ++ * Init / Init Ack / Shutdown compl chunks not the only chunks ++ * OR zero-length. ++ */ ++ if (((sch->type == SCTP_CID_COOKIE_ACK + || sch->type == SCTP_CID_COOKIE_ECHO + || flag) +- && count !=0 ) { ++ && count !=0) || !sch->length) { + DEBUGP("Basic checks failed\n"); + return 1; + } +diff -Nurd linux-2.6.16.orig/security/keys/key.c linux-2.6.16/security/keys/key.c +--- linux-2.6.16.orig/security/keys/key.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/security/keys/key.c 2006-06-03 11:14:55.863396728 +0200 +@@ -785,6 +785,10 @@ + + key_check(keyring); + ++ key_ref = ERR_PTR(-ENOTDIR); ++ if (keyring->type != &key_type_keyring) ++ goto error_2; ++ + down_write(&keyring->sem); + + /* if we're going to allocate a new key, we're going to have +diff -Nurd linux-2.6.16.orig/security/keys/keyring.c linux-2.6.16/security/keys/keyring.c +--- linux-2.6.16.orig/security/keys/keyring.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/security/keys/keyring.c 2006-06-03 11:14:55.864396576 +0200 +@@ -437,6 +437,7 @@ + /* + * search the given keyring only (no recursion) + * - keyring must be locked by caller ++ * - caller must guarantee that the keyring is a keyring + */ + key_ref_t __keyring_search_one(key_ref_t keyring_ref, + const struct key_type *ktype, +diff -Nurd linux-2.6.16.orig/security/selinux/ss/mls.c linux-2.6.16/security/selinux/ss/mls.c +--- linux-2.6.16.orig/security/selinux/ss/mls.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/security/selinux/ss/mls.c 2006-06-03 11:14:55.864396576 +0200 +@@ -264,7 +264,7 @@ + + if (!selinux_mls_enabled) { + if (def_sid != SECSID_NULL && oldc) +- *scontext += strlen(*scontext); ++ *scontext += strlen(*scontext)+1; + return 0; + } + +diff -Nurd linux-2.6.16.orig/sound/isa/opti9xx/opti92x-ad1848.c linux-2.6.16/sound/isa/opti9xx/opti92x-ad1848.c +--- linux-2.6.16.orig/sound/isa/opti9xx/opti92x-ad1848.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/sound/isa/opti9xx/opti92x-ad1848.c 2006-06-03 11:14:55.866396272 +0200 +@@ -2088,9 +2088,11 @@ + int error; + struct platform_device *device; + ++#ifdef CONFIG_PNP + pnp_register_card_driver(&opti9xx_pnpc_driver); + if (snd_opti9xx_pnp_is_probed) + return 0; ++#endif + if (! is_isapnp_selected()) { + error = platform_driver_register(&snd_opti9xx_driver); + if (error < 0) +@@ -2102,7 +2104,9 @@ + } + platform_driver_unregister(&snd_opti9xx_driver); + } ++#ifdef CONFIG_PNP + pnp_unregister_card_driver(&opti9xx_pnpc_driver); ++#endif + #ifdef MODULE + printk(KERN_ERR "no OPTi " CHIP_NAME " soundcard found\n"); + #endif +@@ -2115,7 +2119,9 @@ + platform_device_unregister(snd_opti9xx_platform_device); + platform_driver_unregister(&snd_opti9xx_driver); + } ++#ifdef CONFIG_PNP + pnp_unregister_card_driver(&opti9xx_pnpc_driver); ++#endif + } + + module_init(alsa_card_opti9xx_init) +diff -Nurd linux-2.6.16.orig/sound/oss/dmasound/tas_common.c linux-2.6.16/sound/oss/dmasound/tas_common.c +--- linux-2.6.16.orig/sound/oss/dmasound/tas_common.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/sound/oss/dmasound/tas_common.c 2006-06-03 11:14:55.867396120 +0200 +@@ -195,8 +195,8 @@ + + printk(KERN_INFO "tas driver [%s])\n", driver_name); + +-#ifndef CONFIG_I2C_KEYWEST +- request_module("i2c-keywest"); ++#ifndef CONFIG_I2C_POWERMAC ++ request_module("i2c-powermac"); + #endif + tas_node = find_devices("deq"); + if (tas_node == NULL) +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-a780.c linux-2.6.16/sound/oss/ezx-a780.c +--- linux-2.6.16.orig/sound/oss/ezx-a780.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-a780.c 2006-06-03 11:14:56.782257040 +0200 +@@ -0,0 +1,530 @@ ++/* ++ * linux/drivers/sound/ezx-a780.c ++ * ++ * ++ * Description: Motorola a780 phone specific functions implementation for audio drivers ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save ++ * Cheng Xuefeng(a2491c) Jun.24,2004,LIBdd95397 Add EMU PIHF carkit sound path ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-common.h" ++ ++ ++#ifdef CONFIG_ARCH_EZX_A780 ++ ++extern u32 gpio_hw_attenuate_a780_status; ++ ++ ++void close_input_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input carkit. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++ ++ ++#if EMU_PIHF_FEATURE ++void close_input_pihf_carkit(void) ++{ ++ printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++#endif /* EMU_PIHF_FEATURE */ ++ ++ ++void close_input_handset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input handset. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); ++} ++ ++ ++void close_input_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input headset. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); ++} ++ ++ ++void open_input_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input carkit. \n"); ++#endif ++ ++ codec_input_path = CARKIT_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++ ++ ++#if EMU_PIHF_FEATURE ++void open_input_pihf_carkit(void) ++{ ++ printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); ++ codec_input_path = PIHF_CARKIT_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++#endif /* EMU_PIHF_FEATURE */ ++ ++ ++void open_input_handset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input handset. \n"); ++#endif ++ ++ codec_input_path = HANDSET_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); ++} ++ ++ ++void open_input_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input headset. \n"); ++#endif ++ ++ codec_input_path = HEADSET_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); ++} ++ ++ ++void close_output_pcap_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap headset. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++} ++ ++ ++void close_output_pcap_louderspeaker(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap louderspeaker. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN); ++} ++ ++ ++void close_output_pcap_earpiece(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap earpiece. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); ++} ++ ++ ++void close_output_pcap_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap carkit. \n"); ++#endif ++ EIHF_Mute(EIHF_MUTE); //Mute EIHF ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ++ Set_EMU_Mux_Switch(DEFAULT_USB_MODE); ++} ++ ++ ++#if EMU_PIHF_FEATURE ++void close_output_pcap_pihf_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap pihf carkit. \n"); ++ printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++} ++#endif /* EMU_PIHF_FEATURE */ ++ ++ ++void close_output_pcap_headjack(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap headjack. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++} ++ ++ ++void close_output_pcap_bluetooth(void) ++{ ++} ++ ++ ++int open_output_pcap_headset(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap headset. \n"); ++#endif ++ ++ if((audioonflag & DSP_DEVICE)==DSP_DEVICE) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ codec_output_path = val; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_louderspeaker(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap louderspeaker. \n"); ++#endif ++ ++ if((audioonflag & DSP_DEVICE)==DSP_DEVICE) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ codec_output_path = val; ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_earpiece(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap earpiece. \n"); ++#endif ++ ++ if((audioonflag & DSP_DEVICE)==DSP_DEVICE) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ codec_output_path = val; ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_carkit(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap carkit. \n"); ++#endif ++ ++ Set_EMU_Mux_Switch(MONO_AUDIO_MODE); ++ ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ ++ codec_output_path = val; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ++ set_output_gain_hw_reg(); ++ ++ EIHF_Mute(EIHF_UNMUTE); ++ ++ return ret; ++} ++ ++ ++#if EMU_PIHF_FEATURE ++int open_output_pcap_pihf_carkit(long val) ++{ ++ int ret; ++ ++ printk("EMU:%s,%s\n",__FILE__,__FUNCTION__); ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ ++ codec_output_path = val; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++#endif /* EMU_PIHF_FEATURE */ ++ ++ ++int open_output_pcap_headjack(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap headjack. \n"); ++#endif ++ ++ if((audioonflag & DSP_DEVICE)==DSP_DEVICE) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ codec_output_path = val; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_bluetooth(long val) ++{ ++ return 0; ++} ++ ++ ++void set_output_gain_hw_reg(void) ++{ ++ SSP_PCAP_AUDOG_set( PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC ); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "codec_output_gain=%d\n", codec_output_gain); ++ printk(EZXOSS_DEBUG "output gain=%d\n",PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC); ++#endif ++} ++ ++ ++void set_input_gain_hw_reg(void) ++{ ++ SSP_PCAP_AUDIG_set( PCAP_INPUT_AUDIG_REG_VAL_FROM_LOGIC ); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "codec_input_gain=%d\n", codec_input_gain); ++#endif ++} ++ ++ ++void poweron_mixer( audio_dev_type type ) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "A780 No. 0x%X device wants to power on the mixer hardware.\n", type); ++ printk(EZXOSS_DEBUG "A780 No. 0x%X device has already powered on the mixer hardware.\n", audioonflag); ++#endif ++ ++ audioonflag |= type; ++ if( audioonflag == type ) ++ { ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "A780 No. 0x%X device is powering on the mixer hardware.\n", type); ++#endif ++ ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++ ++ /* (1) set pcap audio power V2_EN_2(OR WITH V2_EN) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); ++ ++ /* (6) enable output_path and set gain */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); /* disable codec bypass */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW); /* open telephone codec path into right PGA */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); /* close PGA_INR into PGA */ ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); /* enable right PGA */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* enable left PGA */ ++ } ++} ++ ++ ++void shutdown_mixer( audio_dev_type type ) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "A780 No. 0x%X device wants to shut down the mixer hardware.\n", type); ++#endif ++ ++ audioonflag &= ~type; ++ ++ if( audioonflag == 0 ) ++ { ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "A780 No. 0x%X device is shutting down the mixer hardware.\n", type); ++#endif ++ /* close pcap output path */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ } ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "A780 No. 0x%X device is still using the mixer hardware.\n", audioonflag); ++#endif ++} ++ ++ ++void mixer_not_in_use(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " A780 mixer not in use.\n"); ++#endif ++ ++ (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(); ++ (*mixer_close_input_path[codec_input_path])(); ++ ++ if( micinflag == 0 ) /* close pcap output path */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++} ++ ++ ++u32 gpio_hw_attenuate_a780_status; ++void use_hw_noise_attenuate(void) ++{ ++ set_GPIO_mode(GPIO_HW_ATTENUATE_A780 | GPIO_OUT); ++ clr_GPIO(GPIO_HW_ATTENUATE_A780); ++ PGSR(GPIO_HW_ATTENUATE_A780) &= ~GPIO_bit(GPIO_HW_ATTENUATE_A780); ++ gpio_hw_attenuate_a780_status = 0; ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "set a780 hw noise attenuation gpio low. \n"); ++#endif ++} ++ ++ ++void bypass_hw_noise_attenuate(void) ++{ ++ set_GPIO_mode(GPIO_HW_ATTENUATE_A780 | GPIO_OUT); ++ set_GPIO(GPIO_HW_ATTENUATE_A780); ++ PGSR(GPIO_HW_ATTENUATE_A780) |= GPIO_bit(GPIO_HW_ATTENUATE_A780); ++ gpio_hw_attenuate_a780_status = 1; ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "set a780 hw noise attenuation gpio high. \n"); ++#endif ++} ++ ++ ++void pcap_use_ap_13m_clock(void) ++{ ++ OSCC |= 0x00000008; ++ set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_ALT_FN_3_OUT); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); ++} ++ ++ ++void pcap_use_bp_13m_clock(void) ++{ ++ OSCC &= ~0x00000008; ++ set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_IN); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); ++} ++ ++ ++#ifdef CONFIG_PM ++int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req){ ++ case PM_SUSPEND: ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " A780 before AP sleep.\n"); ++#endif ++ if( (audioonflag & PHONE_DEVICE) == 0 ) ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); ++ break; ++ case PM_RESUME: ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " A780 after AP sleep.\n"); ++#endif ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); ++ set_output_gain_hw_reg(); ++ ++ if(gpio_hw_attenuate_a780_status) ++ bypass_hw_noise_attenuate(); ++ else ++ use_hw_noise_attenuate(); ++ if(audioonflag) ++ (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); ++ ++ break; ++ } ++ return 0; ++} ++#endif ++ ++ ++void mute_output_to_avoid_pcap_noise(void) ++{ ++} ++ ++ ++void undo_mute_output_to_avoid_pcap_noise(void) ++{ ++} ++ ++ ++#endif ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-a780.h linux-2.6.16/sound/oss/ezx-a780.h +--- linux-2.6.16.orig/sound/oss/ezx-a780.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-a780.h 2006-06-03 11:14:56.790255824 +0200 +@@ -0,0 +1,117 @@ ++/* ++ * linux/drivers/sound/ezx-a780.h ++ * ++ * ++ * Description: header file for ezx-a780.c ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save ++ * Cheng Xuefeng(a2491c) Jun.24,2004,LIBdd95397 Add EMU PIHF carkit sound path ++ * ++ */ ++ ++#ifndef EZX_A780_H ++#define EZX_A780_H ++ ++#include <linux/config.h> ++ ++#ifdef CONFIG_ARCH_EZX_A780 ++ ++//#define EZX_OSS_DEBUG /* debug switch for all ezx oss src files excluding ezx-audio.c */ ++#undef EZX_OSS_DEBUG ++//#define EZX_OSS_AUDIO_DEBUG /* debug switch for src file ezx-audio.c */ ++#undef EZX_OSS_AUDIO_DEBUG ++ ++/* ++#ifdef EZX_OSS_DBG ++#define OSSPRINTF(fmt,args...) printf(fmt,##args) ++#else ++#define OSSPRINTF(fmt,args...) { } ++#endif ++*/ ++ ++ ++typedef enum{ ++ PHONE_DEVICE = 0x01, ++ DSP_DEVICE = 0x02, ++ DSP16_DEVICE = 0x04, ++ AUDIO_DEVICE = 0x08 ++}audio_dev_type; ++ ++typedef enum{ ++ HW_ATTENUATION_USED, ++ HW_ATTENUATION_BYPASSED ++}hw_noise_attenuation; ++ ++ ++void close_input_carkit(void); ++void close_input_handset(void); ++void close_input_headset(void); ++#if EMU_PIHF_FEATURE ++void close_input_pihf_carkit(void); ++#endif ++ ++void open_input_carkit(void); ++void open_input_handset(void); ++void open_input_headset(void); ++#if EMU_PIHF_FEATURE ++void open_input_pihf_carkit(void); ++#endif ++ ++void close_output_pcap_headset(void); ++void close_output_pcap_louderspeaker(void); ++void close_output_pcap_earpiece(void); ++void close_output_pcap_carkit(void); ++void close_output_pcap_headjack(void); ++void close_output_pcap_bluetooth(void); ++#if EMU_PIHF_FEATURE ++void close_output_pcap_pihf_carkit(void); ++#endif ++ ++int open_output_pcap_headset(long val); ++int open_output_pcap_louderspeaker(long val); ++int open_output_pcap_earpiece(long val); ++int open_output_pcap_carkit(long val); ++int open_output_pcap_headjack(long val); ++int open_output_pcap_bluetooth(long val); ++#if EMU_PIHF_FEATURE ++int open_output_pcap_pihf_carkit(long val); ++#endif ++ ++void set_output_gain_hw_reg(void); ++void set_input_gain_hw_reg(void); ++ ++void poweron_mixer( audio_dev_type type ); ++void shutdown_mixer( audio_dev_type type ); ++void mixer_not_in_use(void); ++ ++void use_hw_noise_attenuate(void); ++void bypass_hw_noise_attenuate(void); ++ ++void pcap_use_ap_13m_clock(void); ++void pcap_use_bp_13m_clock(void); ++ ++void mute_output_to_avoid_pcap_noise(void); ++void undo_mute_output_to_avoid_pcap_noise(void); ++ ++int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data); ++ ++#endif ++ ++ ++#endif ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-asspm.c linux-2.6.16/sound/oss/ezx-asspm.c +--- linux-2.6.16.orig/sound/oss/ezx-asspm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-asspm.c 2006-06-03 11:14:56.792255520 +0200 +@@ -0,0 +1,550 @@ ++/* ++ * linux/drivers/sound/ezx-asspm.c ++ * ++ * ++ * Description: assp interface for the ezx platform ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * zhouqiong Jun 20,2002 created ++ * zhouqiong Sep 19,2002 according code review meeting minutes. ++ * zhouqiong Oct 30,2002 according new requirement for VA.ASSP interface split to ++ * /dev/dsp (support stereo playback) and /dev/dsp16 (support ++ * mono playback and record).this file is for mono playback and record ++ * zhouqiong Nov 05,2002 according code review meeting minutes. ++ * zhouqiong Mar 04,2003 (1) don't close headset interrupt; ++ * (2) when headset in, output gain decrease 6db ++ * zhouqiong Apr 24,2003 no switch for headset insert and remove ++ * LiYong Sep 23,2003 Port from EZX ++ * Jin Lihong(w20076) Jan 02,2004,LIBdd66088 (1) Port from UDC e680 kernel of jem vob. ++ * (2) Move audio driver DEBUG macro definition to ezx-audio.h ++ * header file,and redefine DEBUG to EZX_OSS_DEBUG ++ * (3) reorganize file header ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * lin weiqiang Jun.08,2004,LIBee14656 record noise bug fix. ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/poll.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-audio.h" ++#include "ezx-common.h" ++ ++ ++static DECLARE_MUTEX(cotulla_assp_mono_mutex); ++ ++EXPORT_SYMBOL(set_pcap_telephone_codec); ++EXPORT_SYMBOL(set_pcap_input_path); ++EXPORT_SYMBOL(set_pcap_output_path); ++ ++static int assp_mono_init(void); ++static void assp_mono_shutdown(void); ++ ++void set_pcap_telephone_codec(int port) ++{ ++ unsigned long ssp_pcap_register_val; ++ SSP_PCAP_BIT_STATUS phoneClkBit; ++ /* set pcap register, telephone codec */ ++ /* (1) set pcap audio power V2_EN_2(OR WITH V2_EN) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); ++ ++ /* disable PCAP stereo DAC */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, 0); ++ /* (2) set codec sample rate(FS_8K_16K=0) */ ++ /* CDC_CLK(000=13MHZ) bitclk output(SMB=0) audio IO1(DIG_AUD_IN=1) */ ++ ssp_pcap_register_val = PCAP_CDC_CLK_IN_13M0; ++ phoneClkBit = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, ssp_pcap_register_val); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); /* master */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); /* 8K sample rate */ ++/* ++ if( SSP_PCAP_BIT_ONE == phoneClkBit) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ } ++ else ++ { ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ } ++*/ ++ if(port) ++ { ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI1 */ ++ } ++ else ++ { ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI0 */ ++ } ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV); ++ ++ /*(3) reset digital filter(DF_RESET=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH); ++ /* (4) enable pcap clk(CDC_CLK_EN=1),enable CODEC(CDC_EN=1) */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ mdelay(1); /* specified enable time */ ++} ++ ++ ++void set_pcap_output_path(void) ++{ ++ int ret; ++ ++ /* enable output_path */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); /* close PGA_INR into PGA */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW); /* open telephone switch */ ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); /* enable right PGA */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* disable left PGA */ ++ ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); /* right+left output */ ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "codec_output_path = %d\n", codec_output_path); ++ printk(EZXOSS_DEBUG "codec_output_base = %d\n", codec_output_base); ++#endif ++ ret = (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); ++} ++ ++ ++void set_pcap_input_path(void) ++{ ++ unsigned long ssp_pcap_register_val; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "codec_input_path=%d\n", codec_input_path); ++#endif ++ ++ (*mixer_open_input_path[codec_input_path])(); ++ set_input_gain_hw_reg(); ++ ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); ++ printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val); ++#endif ++} ++ ++ ++/*initialize hardware, assp controller and pcap register*/ ++static int assp_mono_init(void) ++{ ++ unsigned long flags; ++ unsigned long ssp_pcap_register_val; ++ unsigned int audiostatus; ++ unsigned long timeout; ++ ++/* ++#ifdef CONFIG_ARCH_EZX_E680 ++ if( audioonflag & FM_DEVICE ){ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 open dsp16 EBUSY because 0x%X device is using the sound hardware.\n",audioonflag ); ++#endif ++ return -EBUSY; ++ } ++#endif ++*/ ++ ++ audioonflag |= DSP16_DEVICE; ++ ++ down(&cotulla_assp_mono_mutex); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "setup assp controller register \n"); ++#endif ++ local_irq_save(flags); ++ CKEN |= CKEN4_ASSP; /* need enable cken4 */ ++ ++ set_GPIO_mode(GPIO_SYNC_IN_ASSP_MD); ++ set_GPIO_mode(GPIO_SDATA_OUT_ASSP_MD); ++ set_GPIO_mode(GPIO_BITCLK_IN_ASSP_MD); ++ set_GPIO_mode(GPIO_SDATA_IN_ASSP_MD); ++ ++ /* setup assp port */ ++ ASSCR0 = ASSCR0_FRF_PSP | ASSCR0_DSS_16bit; /* psp mode, 16bit */ ++ ASSCR1 = ASSCR1_TTE | ASSCR1_EBCEI | ASSCR1_SCLKDIR | ASSCR1_SFRMDIR | ASSCR1_RFTH_14 | ASSCR1_TFTH_4; ++ ASSPSP = ASSPSP_SFRMWDTH_1 | ASSPSP_STRTDLY_1 | ASSPSP_SFRMP_HIGH | ASSPSP_SCMODE; ++ ASSCR1 |= ASSCR1_RSRE | ASSCR1_TSRE; /* enable transmit and receive dma request */ ++ ASSCR0 |= ASSCR0_SSE; /* enable assp controller */ ++ local_irq_restore(flags); ++ ++#ifdef EZX_OSS_DEBUG ++ audiostatus = ASSCR0; ++ printk(EZXOSS_DEBUG "ASSCR0 = 0x%lx\n", audiostatus); ++ audiostatus = ASSCR1; ++ printk(EZXOSS_DEBUG "ASSCR1 = 0x%lx\n", audiostatus); ++ audiostatus = ASSPSP; ++ printk(EZXOSS_DEBUG "ASSPSP = 0x%lx\n", audiostatus); ++#endif ++ ++ mute_output_to_avoid_pcap_noise(); ++ ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++ if( MONODEVOPENED == DSP16_DEVICE ) ++ pcap_use_ap_13m_clock(); ++ ++/* not in phone call, PCAP telephone */ ++ if((audioonflag & PHONE_DEVICE)==0){ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "setup pcap audio register\n"); ++#endif ++ set_pcap_telephone_codec(1); ++ set_pcap_output_path(); ++ set_pcap_input_path(); ++ } ++ else{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "there is phone call\n"); ++#endif ++ /* set pcap register, stereo DAC */ ++ //SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, &ssp_pcap_register_val); ++ //ssp_pcap_register_val |= PCAP_ST_SAMPLE_RATE_8K | PCAP_ST_BCLK_SLOT_4 | PCAP_ST_CLK_PLL_CLK_IN_BITCLK | PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK; //NETWORK mode ++ //SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, ssp_pcap_register_val); ++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_8K); ++ SSP_PCAP_BCLK_set(PCAP_ST_BCLK_SLOT_4); ++ SSP_PCAP_STCLK_set(PCAP_ST_CLK_PLL_CLK_IN_FSYNC); ++ SSP_PCAP_DIG_AUD_FS_set(PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV); ++ ++ /* (3) reset digital filter(DF_RESET_ST_DAC=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC); ++ ++ /* (4)set bitclk output(SMB_ST_DAC=0), audio IO=part1(DIG_AUD_IN_ST_DAC=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC); /* input, slave mode */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC); ++ ++ /* (5) enable pcap clk(ST_CLK_EN=1),enable dac(ST_DAC_EN=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); ++ mdelay(1); /* specified enable time according spec */ ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* enable left PGA */ ++ } ++ ++ undo_mute_output_to_avoid_pcap_noise(); ++ ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); ++ printk(EZXOSS_DEBUG "pcap register 13 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); ++ printk(EZXOSS_DEBUG "pcap register 12 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); ++ printk(EZXOSS_DEBUG "pcap register 11 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); ++ printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val); ++#endif ++ timeout = 0; ++ /* check if ssp is ready for slave operation */ ++ while(((audiostatus = ASSSR) & ASSSR_CSS) !=0){ ++ if((timeout++) > 10000000) ++ goto err; ++ } ++ ++ up(&cotulla_assp_mono_mutex); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " complete all hardware init \n"); ++#endif ++ return 0; ++ ++err: ++ up(&cotulla_assp_mono_mutex); ++ printk(EZXOSS_DEBUG "audio panic2: ssp don't ready for slave operation!!! "); ++ return -ENODEV; ++} ++ ++ ++static void assp_mono_shutdown(void) ++{ ++ unsigned long ssp_pcap_register_val; ++ ++ down(&cotulla_assp_mono_mutex); ++ ++ /* clear ASSP port */ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close assp port\n"); ++#endif ++ ASSCR0 = 0; ++ ASSCR1 = 0; ++ ASSPSP = 0; ++ CKEN &= ~CKEN4_ASSP; ++ ++ set_GPIO_mode(GPIO_ASSP_SCLK3 | GPIO_IN); /* Assp Frame sync */ ++ set_GPIO_mode(GPIO_ASSP_TXD3 | GPIO_IN); ++ set_GPIO_mode(GPIO_ASSP_RXD3 | GPIO_IN); /* ASSP BitCLK */ ++ set_GPIO_mode(GPIO_ASSP_SFRM3 | GPIO_IN); /* ASsp RX */ ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close pcap register\n"); ++#endif ++ ++ mute_output_to_avoid_pcap_noise(); /* mute hw noise and save power */ ++ ++ if( MONODEVOPENED == DSP16_DEVICE ) ++ pcap_use_bp_13m_clock(); ++ ++ if((audioonflag & PHONE_DEVICE) == 0){ ++ /* close pcap output path */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ /* close pcap input path */ ++ if(micinflag) ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); ++ else ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER, 0); ++ /* disable PCAP mono codec */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI0 */ ++ /* set fsync, tx, bitclk are tri-stated */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS); ++ } ++ else{ ++ /* disable PCAP stereo DAC */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC); ++ } ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ e680_boomer_path_mono_lineout(); /* mute hw noise and save power for e680 */ ++#endif ++ ++ audioonflag &= ~DSP16_DEVICE; ++ ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); ++ printk("pcap register 13 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); ++ printk("pcap register 12 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); ++ printk("pcap register 11 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); ++ printk("pcap register 26 = 0x%lx\n", ssp_pcap_register_val); ++#endif ++ up(&cotulla_assp_mono_mutex); ++} ++ ++ ++/* ++ * ASSP codec ioctls ++ */ ++static int codec_adc_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ ++static int codec_dac_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ ++ ++static int assp_mono_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val; ++ int audiostatus, timeout; ++ ++ switch(cmd) { ++ case SNDCTL_DSP_STEREO: ++#ifdef EZX_OSS_DEBUG ++ printk(" check if support stereo\n"); ++#endif ++ ret = get_user(val, (int *) arg); ++ if (ret) ++ return ret; ++ ++ if(val) ++ ret = -EINVAL; /* not support stereo */ ++ else ++ ret = 1; ++ return put_user(ret, (int *) arg); ++ ++ case SNDCTL_DSP_CHANNELS: ++ case SOUND_PCM_READ_CHANNELS: ++#ifdef EZX_OSS_DEBUG ++ printk(" check if 2 channels \n"); ++#endif ++ return put_user(1, (long *) arg); ++ ++ case SNDCTL_DSP_SPEED: ++#ifdef EZX_OSS_DEBUG ++ printk(" set sample frequency \n"); ++#endif ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ down(&cotulla_assp_mono_mutex); ++ ASSCR0 &= ~ASSCR0_SSE; ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ switch(val) ++ { ++ case PHONE_CODEC_16K_RATE: ++ ret= SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); ++ codec_adc_rate = val; ++ codec_dac_rate = val; ++ break; ++ case PHONE_CODEC_DEFAULT_RATE: ++ ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); ++ codec_adc_rate = val; ++ codec_dac_rate = val; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ /* reset digital filter(DF_RESET=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ ++ ASSCR0 |= ASSCR0_SSE; /* enable assp controller */ ++ timeout = 0; ++ /* check if ssp is ready for slave operation */ ++ while(((audiostatus = ASSSR) & ASSSR_CSS) !=0) ++ { ++ if((timeout++) > 10000000) ++ { ++ printk("audio panic3: can't be slave mode!!!"); ++ ret = -ENODEV; ++ break; ++ } ++ } ++#ifdef EZX_OSS_DEBUG ++ printk("AD sample freq = %d\n", codec_adc_rate); ++ printk("DA sample freq = %d\n", codec_dac_rate); ++#endif ++ up(&cotulla_assp_mono_mutex); ++ return put_user(codec_adc_rate, (long *) arg); ++ ++ case SOUND_PCM_READ_RATE: ++ if (file->f_mode & FMODE_WRITE) ++ { ++#ifdef EZX_OSS_DEBUG ++ printk("read DA sample freq\n"); ++#endif ++ val = codec_dac_rate; ++ } ++ if (file->f_mode & FMODE_READ) ++ { ++#ifdef EZX_OSS_DEBUG ++ printk("read AD sample freq\n"); ++#endif ++ val = codec_adc_rate; ++ } ++ return put_user(val, (long *) arg); ++ ++ case SNDCTL_DSP_SETFMT: ++ case SNDCTL_DSP_GETFMTS: ++ /* SUPPORT little endian signed 16 */ ++#ifdef EZX_OSS_DEBUG ++ printk("data format is AFMT_S16_LEd\n"); ++#endif ++ return put_user(AFMT_S16_LE, (long *) arg); ++ ++ default: ++ return mixer_ioctl(inode, file, cmd, arg); ++ } ++ return 0; ++} ++ ++ ++/* ++ * Audio stuff ++ */ ++static audio_stream_t assp_mono_audio_out = { ++ name: "assp mono audio out", ++ dcmd: DCMD_TXASSDRM, ++ drcmr: &DRCMRTXASSDR, /* ASSP dma map register */ ++ dev_addr: __PREG(ASSDR), ++}; ++ ++static audio_stream_t assp_mono_audio_in = { ++ name: "assp mono audio in", ++ dcmd: DCMD_RXASSDR, ++ drcmr: &DRCMRRXASSDR, /* ASSP dma map register */ ++ dev_addr: __PREG(ASSDR), ++}; ++ ++static audio_state_t assp_mono_audio_state = { ++ output_stream: &assp_mono_audio_out, ++ input_stream: &assp_mono_audio_in, ++ client_ioctl: assp_mono_ioctl, ++ hw_init: assp_mono_init, ++ hw_shutdown: assp_mono_shutdown, ++ sem: __MUTEX_INITIALIZER(assp_mono_audio_state.sem), ++}; ++ ++static int assp_mono_audio_open(struct inode *inode, struct file *file) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk("assp mono audio open \n"); ++#endif ++ ++ return cotulla_audio_attach(inode, file, &assp_mono_audio_state); ++} ++ ++/* ++ * Missing fields of this structure will be patched with the call ++ * to cotulla_audio_attach(). ++ */ ++ ++static struct file_operations assp_mono_audio_fops = { ++ open: assp_mono_audio_open, ++ owner: THIS_MODULE ++}; ++ ++static int __init cotulla_assp_mono_init(void) ++{ ++ assp_mono_audio_state.dev_dsp = register_sound_dsp16(&assp_mono_audio_fops, -1); ++ ++#ifdef EZX_OSS_DEBUG ++ printk("/dev/dsp16 init ok\n"); ++#endif ++ return 0; ++} ++ ++static void __exit cotulla_assp_mono_exit(void) ++{ ++ unregister_sound_dsp16(assp_mono_audio_state.dev_dsp); ++#ifdef EZX_OSS_DEBUG ++ printk("/dev/dsp16 exit ok\n"); ++#endif ++} ++ ++module_init(cotulla_assp_mono_init); ++module_exit(cotulla_assp_mono_exit); ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-assps.c linux-2.6.16/sound/oss/ezx-assps.c +--- linux-2.6.16.orig/sound/oss/ezx-assps.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-assps.c 2006-06-03 11:14:56.794255216 +0200 +@@ -0,0 +1,1168 @@ ++/*
++ * linux/drivers/sound/ezx-assps.c
++ *
++ *
++ * Description: assp interface for the ezx platform
++ *
++ *
++ * Copyright: BJDC motorola.
++ *
++ * 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.
++ *
++ *
++ * History:
++ * zhouqiong Jun 20,2002 created
++ * zhouqiong Sep 19,2002 according code review meeting minutes.
++ * zhouqiong Oct 30,2002 according new requirement for VA.ASSP interface split to
++ * /dev/dsp (support stereo playback) and /dev/dsp16 (support
++ * mono playback and record) this file is for stereo playback.
++ * zhouqiong Nov 05,2002 according code review meeting minutes.
++ * zhouqiong Jan 13,2003 (1) add audio panic return value
++ * (2) modify sample frequency to standard
++ * zhouqiong Mar 03,2003 (1) open headset interrupt
++ * (2) change gain when headset is in
++ * (3) add ioctl to get headset status
++ * zhouqiong Apr 17,2003 (1) according codec_dac_rate init pcap
++ * zhouqiong Apr 18,2003 (1) change output gain according output path
++ * zhouqiong Apr 24,2003 (1) no switch when headset insert and remove
++ * zhouqiong May 21,2003 (1) modify loudspk gain max 0db, for audio-shaping
++ * LiYong Sep 23,2003 (1)Port from EZX; (2)Modify the ASSP port inital
++ * Jin Lihong(w20076) Jan 02,2004,Libdd66088 (1) Port from UDC e680 kernel of jem vob.
++ * (2) Move audio driver DEBUG macro definition to ezx-audio.h
++ * header file,and redefine DEBUG to EZX_OSS_DEBUG
++ * (3) reorganize file header
++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work.
++ * Jia Tong(w19836) Feb 04,2004,LIBdd67717 haptics feature added
++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs
++ * Jia Tong(w19836) Feb 23,2004,LIBdd79841 haptics GPIO initialization change
++ * Li Yong(w19946) Feb 26,2004 LIBdd80614 Add DAI test
++ * Add control to switch PCAP CODEC mode from master to slave mode
++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix
++ * Jia Tong(w19836) Mar 17,2004,LIBdd87621 GPIO change for haptics filter & boomer mute while setting haptics.
++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface
++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app
++ * Li Yong(w19946) Apr.23.2004.LIBee02702 Add EMU Carkit
++ * Li Yong(w19946) May.23.2004.LIBee12065 Add the EMU audio test
++ * lin weiqiang Jun.08,2004,LIBee14656 record noise bug fix.
++ * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save ++ * Jin Lihong(w20076) Aug.11,2004,LIBff01482 audio pcap LOW_POWER bit initialize ++ * ++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/poll.h>
++#include <linux/pm.h> ++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include <asm/dma.h>
++
++#include "ezx-audio.h"
++#include "ezx-common.h"
++
++
++static DECLARE_MUTEX(cotulla_assp_mutex);
++
++static int codec_dac_rate = STEREO_CODEC_44K_RATE; /* default 44k sample rate */
++static struct timer_list audio_timer,mic_timer;
++ ++#ifdef CONFIG_PM ++static struct pm_dev *mixer_hw_pm_dev; ++#endif
++ ++ ++EXPORT_SYMBOL(headjack_change_interrupt_routine);
++EXPORT_SYMBOL(mic_change_interrupt_routine);
++EXPORT_SYMBOL(mixer_ioctl);
++
++static int assp_init(void);
++static void assp_shutdown(void);
++static void change_input_output(void);
++static void open_mic_interrupt(void);
++
++void Set_EMU_Mux_Switch(int mode);
++void EIHF_Mute(int Flag);
++
++static int EMU_AUD_test_flag = 0;
++
++static struct timer_list EMU_timer;
++
++/*initialize hardware, assp controller and pcap register*/
++static int assp_init(void)
++{
++ unsigned long flags;
++ unsigned long ssp_pcap_register_val;
++ unsigned long audiostatus;
++ unsigned long timeout;
++ int ret;
++
++ down(&cotulla_assp_mutex);
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "setup assp controller register \n");
++#endif
++ local_irq_save(flags);
++ CKEN |= CKEN4_ASSP; /* need enable cken4 */
++
++ set_GPIO_mode(GPIO_SYNC_IN_ASSP_MD); /* Assp Frame sync */
++ set_GPIO_mode(GPIO_SDATA_OUT_ASSP_MD); /* Assp TX */
++ set_GPIO_mode(GPIO_BITCLK_IN_ASSP_MD); /* ASSP BitCLK */
++ set_GPIO_mode(GPIO_SDATA_IN_ASSP_MD); /* ASsp RX */
++
++ /* setup assp port */
++ ASSCR0 = ASSCR0_FRF_PSP | ASSCR0_EDSS | ASSCR0_DSS_16bit; /* PSP mode, 32bit */
++ ASSCR1 = ASSCR1_EBCEI | ASSCR1_SCLKDIR | ASSCR1_SFRMDIR | ASSCR1_TFTH_4;
++ ASSPSP = ASSPSP_SFRMWDTH_16 | ASSPSP_SCMODE;
++ ASSCR1 |= ASSCR1_TSRE; /* enable transmit dma request */
++ ASSCR0 |= ASSCR0_SSE; /* enable assp controller */
++ local_irq_restore(flags);
++
++#ifdef EZX_OSS_DEBUG
++ audiostatus = ASSCR0;
++ printk(EZXOSS_DEBUG "ASSCR0 = 0x%lx\n", audiostatus);
++ audiostatus = ASSCR1;
++ printk(EZXOSS_DEBUG "ASSCR1 = 0x%lx\n", audiostatus);
++ audiostatus = ASSPSP;
++ printk(EZXOSS_DEBUG "ASSPSP = 0x%lx\n", audiostatus);
++#endif
++
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "setup pcap audio register\n");
++#endif
++ ++ mute_output_to_avoid_pcap_noise(); ++ poweron_mixer(DSP_DEVICE);
++
++ /* (1) set bitclk(BCK=3, two_time_slot) pll clock(ST_CLK=0, 13M) NORMAL mode(DIG_AUD_FS =00) */
++ ssp_pcap_register_val = PCAP_ST_BCLK_SLOT_2 | PCAP_ST_CLK_PLL_CLK_IN_13M0 | PCAP_DIGITAL_AUDIO_INTERFACE_NORMAL; //NORMAL mode
++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER, ssp_pcap_register_val);
++ /* here dsp device must use AP 13Mhz clock */
++ pcap_use_ap_13m_clock();
++
++ /* set stereo sample rate */
++ switch(codec_dac_rate)
++ {
++ case STEREO_CODEC_48K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_48K);
++ break;
++
++ case STEREO_CODEC_44K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_44K);
++ break;
++
++ case STEREO_CODEC_32K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_32K);
++ break;
++
++ case STEREO_CODEC_24K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_24K);
++ break;
++
++ case STEREO_CODEC_22K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_22K);
++ break;
++
++ case STEREO_CODEC_16K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_16K);
++ break;
++
++ case STEREO_CODEC_12K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_12K);
++ break;
++
++ case STEREO_CODEC_11K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_11K);
++ break;
++
++ case STEREO_CODEC_8K_RATE:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_8K);
++ break;
++ default:
++ SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_44K);
++ break;
++ }
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "codec_dac_rate=%d\n", codec_dac_rate);
++#endif
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV);
++
++ /* (3) reset digital filter(DF_RESET_ST_DAC=1) */
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC);
++
++ /* (4)set bitclk output(SMB_ST_DAC=0), audio IO=part1(DIG_AUD_IN_ST_DAC=1) */
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC);
++
++ /* (5) enable pcap clk(ST_CLK_EN=1),enable dac(ST_DAC_EN=1) */
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN);
++ mdelay(1); /* specified enable time according spec */
++ ++#ifdef CONFIG_ARCH_EZX_A780 ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "codec_output_path=%d\n", codec_output_path);
++ printk(EZXOSS_DEBUG "codec_output_base=%d\n", codec_output_base);
++#endif
++ ret = (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); ++#endif ++ ++ undo_mute_output_to_avoid_pcap_noise(); ++
++#ifdef EZX_OSS_DEBUG
++ SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val);
++ printk(EZXOSS_DEBUG "pcap register 13 = 0x%lx\n", ssp_pcap_register_val);
++ SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val);
++ printk(EZXOSS_DEBUG "pcap register 12 = 0x%lx\n", ssp_pcap_register_val);
++ SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val);
++ printk(EZXOSS_DEBUG "pcap register 11 = 0x%lx\n", ssp_pcap_register_val);
++ SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val);
++ printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val);
++#endif
++ timeout = 0;
++ /* check if ssp is ready for slave operation */
++ while(((audiostatus = ASSSR) & ASSSR_CSS) !=0)
{ ++ if((timeout++) > 10000000)
++ goto err;
++ }
++
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " complete all hardware init \n");
++#endif
++ up(&cotulla_assp_mutex);
++
++ return 0;
++err:
++ up(&cotulla_assp_mutex);
++ printk(EZXOSS_DEBUG "audio panic: ssp don't ready for slave operation!!! ");
++ return -ENODEV;
++}
++
++
++static void assp_shutdown(void)
++{
++ down(&cotulla_assp_mutex);
++
++ /* clear ASSP port */
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "close assp port\n");
++#endif
++ ASSCR0 = 0;
++ ASSCR1 = 0;
++ ASSPSP = 0;
++ CKEN &= ~CKEN4_ASSP;
++
++ set_GPIO_mode(GPIO_ASSP_SCLK3 | GPIO_IN); /* Assp Frame sync */
++ set_GPIO_mode(GPIO_ASSP_TXD3 | GPIO_IN);
++ set_GPIO_mode(GPIO_ASSP_RXD3 | GPIO_IN); /* ASSP BitCLK */
++ set_GPIO_mode(GPIO_ASSP_SFRM3 | GPIO_IN); /* ASsp RX */
++ ++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "close pcap register\n");
++#endif
++ ++ shutdown_mixer(DSP_DEVICE);
++
++ /* disable PCAP stereo DAC */
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC);
++ pcap_use_bp_13m_clock();
++ ++ up(&cotulla_assp_mutex);
++} ++
++
++/*
++ * for stereo headset and mono headset insert, it will take A1I interrupt
++ * in A1I interrupt handler, open MB_ON2 to check if mic connect
++ */
++void headjack_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs)
++{
++ int bdelay = 20;
++
++ del_timer(&audio_timer);
++ init_timer(&audio_timer);
++ audio_timer.function = change_input_output;
++ audio_timer.expires = (jiffies + bdelay);
++ add_timer(&audio_timer);
++}
++
++
++static void open_mic_interrupt(void)
++{
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "Open mic interrupt\n");
++#endif
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I );
++ udelay(10);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_MB2M);
++}
++
++
++void Set_EMU_Mux_Switch(int mode)
++{
++ set_GPIO_mode(GPIO_EMU_MUX1 | GPIO_OUT);
++ set_GPIO_mode(GPIO_EMU_MUX2 | GPIO_OUT);
++
++ switch(mode)
++ {
++ case DEFAULT_USB_MODE:
++ clr_GPIO(GPIO_EMU_MUX1);
++ clr_GPIO(GPIO_EMU_MUX2); //default mode
++ break;
++
++ case MONO_AUDIO_MODE:
++ set_GPIO(GPIO_EMU_MUX1);
++ clr_GPIO(GPIO_EMU_MUX2); //Mono audio mode
++ break;
++
++ case SETERO_AUDIO_MODE:
++ set_GPIO(GPIO_EMU_MUX1);
++ set_GPIO(GPIO_EMU_MUX2); //Setero audio mode
++ break;
++
++ default:
++ break;
++ }
++
++ printk("::set EMU Mux GPIO.\n");
++}
++
++void EIHF_Mute(int Flag)
++{
++
++ set_GPIO_mode(GPIO_SNP_INT_CTL | GPIO_OUT);
++ if(EMU_AUD_test_flag) //At the audio EMU test mode
++ {
++ clr_GPIO(GPIO_SNP_INT_CTL);
++ return;
++ }
++
++ if(!Flag)
++ {
++ clr_GPIO(GPIO_SNP_INT_CTL);
++ }
++ else
++ {
++ set_GPIO(GPIO_SNP_INT_CTL); // high is active
++ }
++
++}
++
++void Switch_Audio_To_USB()
++{
++ set_GPIO_mode(GPIO_SNP_INT_IN | GPIO_IN);
++
++ while(1) //If the EMU ID short to GND
++ {
++ if(!(GPLR(GPIO_SNP_INT_IN) & GPIO_bit(GPIO_SNP_INT_IN)))
++ break;
++ }
++ EIHF_Mute(EIHF_MUTE);
++ Set_EMU_Mux_Switch(DEFAULT_USB_MODE); // Switch the MUX to USB mode
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); // Disable the PCAP loopback
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); //Pull up the D+
++
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB4VM);
++
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB1VM);
++
++ EMU_AUD_test_flag = 0; // Restore the default value
++}
++
++void Switch_USB_To_Audio()
++{
++ EMU_AUD_test_flag = 0xff; // Enter the EMU audio test mode
++ set_GPIO_mode(GPIO_SNP_INT_IN | GPIO_IN);
++
++
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM);
++
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM);
++
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU);
++
++
++ del_timer(&EMU_timer); //Start one timer
++ init_timer(&EMU_timer);
++ EMU_timer.function = Switch_Audio_To_USB;
++ EMU_timer.expires = (jiffies+500);
++ add_timer(&EMU_timer);
++}
++
++
++
++static void change_input_output(void)
++{
++ unsigned long ssp_pcap_bit_status;
++
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "enter headjack change interrupt routine \n");
++#endif
++ /* read pcap register to check if headjack is in */
++ ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS);
++ if(ssp_pcap_bit_status) /* headset is in */
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "headset insert\n");
++#endif
++ headset_in_handler(0, NULL, NULL);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2);
++ micinflag = 1;
++ del_timer(&mic_timer);
++ init_timer(&mic_timer);
++ mic_timer.function = open_mic_interrupt;
++ mic_timer.expires = (jiffies+100);
++ add_timer(&mic_timer);
++ }
++ else /* headset is out */
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "headset remove\n");
++#endif
++ headset_out_handler(0, NULL, NULL);
++ micinflag = 0;
++ del_timer(&mic_timer);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M);
++ }
++}
++
++
++void mic_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs)
++{
++ int ssp_pcap_bit_status;
++
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "enter mic change interrupt routine \n");
++#endif
++
++ /* read pcap register to check if headjack is in */
++ ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS);
++ if( ssp_pcap_bit_status ) /* headjack is in */
++ {
++ answer_button_handler(0, NULL, NULL);
++ }
++}
++
++
++/*
++ * Audio Mixer stuff
++ */
++int mixer_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ int ret;
++ int i,j;
++ long val;
++ unsigned long ssp_pcap_register_val;
++
++ switch(cmd)
++ {
++#ifdef MAKE_FTR_HAPTICS ++ case SOUND_MIXER_WRITE_HAPTICS_ON:
++ Set_Haptics_GPIO();
++ break;
++ case SOUND_MIXER_WRITE_HAPTICS_OFF:
++ Clear_Haptics_GPIO();
++ break;
++ case SOUND_MIXER_READ_HAPTICS_FIL: ++ if( (GPDR(GPIO_FLT_SEL_BUL) & GPIO_bit(GPIO_FLT_SEL_BUL))==0 ) ++ val = 0; ++ else ++ val = 1; ++ return put_user(val, (long *)arg); ++#endif
++ ++ case SOUND_MIXER_READ_IGAIN:
++ val = codec_input_gain;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " read input gain=%d\n", val);
++#endif
++ return put_user(val, (long *)arg);
++
++ case SOUND_MIXER_WRITE_IGAIN:
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++
++ if( (val<EZX_OSS_MIN_LOGICAL_GAIN) || (val>EZX_OSS_MAX_LOGICAL_GAIN) )
++ ret = -EINVAL;
++ else{
++ codec_input_gain = val;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " write input gain=%d\n", codec_input_gain);
++#endif
++ set_input_gain_hw_reg();
++ }
++
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_READ_OGAIN:
++ /* read pcap ogain register */
++ val = codec_output_gain;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " read output gain=%d\n", val);
++#endif
++ return put_user(val, (long *)arg);
++
++ case SOUND_MIXER_WRITE_VOLUME:
++ case SOUND_MIXER_WRITE_OGAIN:
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " write output gain=%d\n", val);
++#endif
++
++ if((val >= EZX_OSS_MIN_LOGICAL_GAIN)&&(val <=EZX_OSS_MAX_LOGICAL_GAIN))
++ {
++ codec_output_gain = val;
++ /* write pcap ogain register */
++ set_output_gain_hw_reg();
++ }
++ else
++ {
++ ret = -EINVAL;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "value is invalid\n");
++#endif
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_READ_RECSRC:
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " read input path\n");
++#endif
++ /* read pcap input status, 0-extmic, 1-A5, 2-A3 */
++ val = codec_input_path;
++ return put_user(val, (long *)arg);
++
++ case SOUND_MIXER_WRITE_RECSRC:
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " force write input path=%d\n", val);
++#endif
++ /* close old input path */
++ (*mixer_close_input_path[codec_input_path])();
++ /* open input path */
++ if( (val>INPUT_PATH_MAX) || (val<INPUT_PATH_MIN) )
++ ret = -EINVAL;
++ else
++ (*mixer_open_input_path[val])();
++ ++ if( audioonflag == 0 ) ++ mixer_not_in_use(); /* for power save */ ++ ++#ifdef EZX_OSS_DEBUG
++ SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val);
++ printk(EZXOSS_DEBUG "pcap register 26 = 0x%lx\n", ssp_pcap_register_val);
++#endif
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_READ_OUTSRC:
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " read output path\n");
++#endif
++ val = codec_output_path | codec_output_base;
++ return put_user(val, (long *)arg);
++
++ case SOUND_MIXER_WRITE_OUTSRC:
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "force write output path=0x%03X\n", val);
++#endif
++ /* close old output path */
++ (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])();
++
++ /* set pcap output register */
++ if( (GET_OUTPUT_BASE(val)>OUTPUT_BASE_MAX) || (GET_OUTPUT_PATH(val)>OUTPUT_PATH_MAX) )
++ ret = -EINVAL;
++ else
++ ret = (*mixer_open_output_path[OUTPUT_BASE_TYPE(GET_OUTPUT_BASE(val))][GET_OUTPUT_PATH(val)])(val);
++
++ if( audioonflag == 0 ) ++ mixer_not_in_use(); /* for power save */ ++ ++#ifdef EZX_OSS_DEBUG
++ SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val);
++ printk(EZXOSS_DEBUG "pcap register 12 = 0x%lx\n", ssp_pcap_register_val);
++#endif
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_MUTE: /* mute output path */
++ /* 0-unmute, 1-mute */
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++ if(val == 1) /* if mute */
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " mute PGA\n");
++#endif
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN);
++ }
++ else if(val == 0) /* unmute */
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "unmute PGA\n");
++#endif
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN);
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_INPUTMUTE: /* mute input path for DAI test */
++ /* 0-unmute, 1-mute */
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++ if(val == 1) /* if mute */
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " mute input\n");
++#endif
++ (*mixer_close_input_path[codec_input_path])();
++ }
++ else if(val == 0) /* unmute */
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "unmute input\n");
++#endif
++ (*mixer_open_input_path[codec_input_path])();
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_LOOPBACK: /* set loopback mode for DAI test */
++ /* 0-unloopback, 1-loopback */
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++ if(val == 1)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "loopback\n");
++#endif
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP);
++
++
++ }
++ else if(val ==0)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "unloopback\n");
++#endif
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP);
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_AUDOHPF: /* set audio output High Pass filter for test command */
++ /* 0-disable filter, 1-enable filter */
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++ if(val == 1)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "enable audio output High Pass filter\n");
++#endif
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET);
++
++ }
++ else if(val ==0)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "disable audio output High Pass filter\n");
++#endif
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET);
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_AUDIHPF: /* set audio input High Pass filter for test command */
++ /* 0-disable filter, 1-enable filter */
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++ if(val == 1)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk("enable audio input High Pass filter\n");
++#endif
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET);
++
++ }
++ else if(val ==0)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk("disable audio input High Pass filter\n");
++#endif
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET);
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_CODEC_SLAVE:
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET);
++ return put_user(ret, (int *) arg);
++ case SOUND_MIXER_READ_HEADSET_STATUS: /* read if headset is in */
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "read headset status, jiffies=%d\n", jiffies);
++#endif
++
++ j=0;
++ for(i=0;i<3;i++)
++ {
++ val = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS);
++ if(val)
++ j++;
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(50*HZ/1000);
++ }
++ if(j>=2)
++ {
++ ret = STEREO_HEADSET;
++ micinflag=1;
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_MB2M);
++ }
++ else
++ {
++ ret = NO_HEADSET;
++ micinflag=0;
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M);
++ }
++ return put_user(ret, (long *)arg);
++
++ case SOUND_MIXER_WRITE_EIHF_MUX:
++ ret = get_user(val, (long *) arg);
++ if(ret)
++ return ret;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " \n user space is writing MUX status =%d\n", val);
++#endif
++ switch(val)
++ {
++ case DEFAULT_USB_MODE:
++ Set_EMU_Mux_Switch(DEFAULT_USB_MODE);
++ break;
++ case MONO_AUDIO_MODE:
++ Set_EMU_Mux_Switch(MONO_AUDIO_MODE);
++ break;
++ case SETERO_AUDIO_MODE:
++ Set_EMU_Mux_Switch(SETERO_AUDIO_MODE);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SOUND_MIXER_WRITE_EIHF_MUTE:
++ ret = get_user(val, (long *) arg);
++ if(ret)
++ return ret;
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " \n user space is writing MUTE status =%d\n", val);
++#endif
++ if(val)
++ EIHF_Mute(EIHF_UNMUTE);
++ else
++ EIHF_Mute(EIHF_MUTE);
++
++ return put_user(ret, (int *) arg);
++ case SOUND_MIXER_WRITE_EMU_TEST:
++ ret = get_user(val, (long *) arg);
++ if(ret)
++ return ret;
++ Switch_USB_To_Audio();
++ return put_user(ret, (int *) arg);
++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ case SOUND_MIXER_READ_3D_STATUS: ++ val = get_boomer_3d_status(); ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " read e680 3d status =%d\n", val); ++#endif ++ return put_user(val, (long *)arg); ++ ++ case SOUND_MIXER_WRITE_3D_STATUS: ++ ret = get_user(val, (long *) arg); ++ if(ret) ++ return ret; ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " user space is writing 3d status =%d\n", val); ++#endif ++ ++ if( (val<LOUDERSPEAKER_ON_HEADSET_ON_3D) || (val>LOUDERSPEAKER_OFF_HEADSET_OFF_3D) ) ++ ret = -EINVAL; ++ else ++ set_boomer_3d_status((boomer_3d_status)val); ++ ++ return put_user(ret, (int *) arg); ++#endif ++ ++#ifdef CONFIG_ARCH_EZX_A780 ++ case SOUND_MIXER_WRITE_HW_ATTENU: ++ ret = get_user(val, (long *) arg); ++ if(ret) ++ return ret; ++ ++ if(val == HW_ATTENUATION_USED){ ++ use_hw_noise_attenuate(); ++ ret = HW_ATTENUATION_USED; ++ } ++ else if(val == HW_ATTENUATION_BYPASSED){ ++ bypass_hw_noise_attenuate(); ++ ret = HW_ATTENUATION_BYPASSED; ++ } ++ else ++ ret = -EINVAL; ++ ++ return put_user(ret, (int *) arg); ++#endif ++ ++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++
++static struct file_operations mixer_fops = {
++ ioctl: mixer_ioctl,
++ owner: THIS_MODULE
++};
++
++/*
++ * ASSP codec ioctls
++ */
++
++static int assp_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int ret;
++ long val;
++ int audiostatus, timeout;
++
++ switch(cmd) {
++ case SNDCTL_DSP_STEREO:
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " check if support stereo\n");
++#endif
++ ret = get_user(val, (int *) arg);
++ if (ret)
++ return ret;
++ if(file->f_mode & FMODE_WRITE)
++ {
++ if(val) /* write only support stereo mode */
++ ret = 1;
++ else /* not support mono mode */
++ ret = -EINVAL;
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(ret, (int *) arg);
++
++ case SNDCTL_DSP_CHANNELS:
++ case SOUND_PCM_READ_CHANNELS:
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " check if 2 channels \n");
++#endif
++ if(file->f_mode & FMODE_WRITE)
++ {
++ return put_user(2, (long *) arg);
++ }
++ else
++ {
++ ret = -EINVAL;
++ return put_user(ret, (long *) arg);
++ }
++
++ case SNDCTL_DSP_SPEED:
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG " set sample frequency \n");
++#endif
++ ret = get_user(val, (long *) arg);
++ if (ret)
++ return ret;
++
++ if(file->f_mode & FMODE_WRITE)
++ {
++ down(&cotulla_assp_mutex);
++ ASSCR0 &= ~ASSCR0_SSE;
++
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN);
++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN);
++ switch(val)
++ {
++ case STEREO_CODEC_48K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_48K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_44K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_44K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_32K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_32K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_24K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_24K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_22K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_22K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_16K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_16K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_12K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_12K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_11K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_11K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++
++ case STEREO_CODEC_8K_RATE:
++ ret = SSP_PCAP_CDC_SR_set(PCAP_ST_SAMPLE_RATE_8K);
++ /* set pcap dac sample rate */
++ codec_dac_rate = val;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ /* reset digital filter(DF_RESET_ST_DAC=1) */
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC);
++
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN);
++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN);
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "DA sample freq = %d\n", codec_dac_rate);
++#endif
++ ASSCR0 |= ASSCR0_SSE; /* enable assp controller */
++ timeout = 0;
++ /* check if ssp is ready for slave operation */
++ while(((audiostatus = ASSSR) & ASSSR_CSS) !=0)
++ {
++ if((timeout++) > 10000000)
++ {
++ printk(EZXOSS_DEBUG "audio panic: can't be slave mode!!!");
++ ret = -ENODEV;
++ break;
++ }
++ }
++ up(&cotulla_assp_mutex);
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ return put_user(codec_dac_rate, (long *) arg);
++
++ case SOUND_PCM_READ_RATE:
++ if (file->f_mode & FMODE_WRITE)
++ {
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "read DA sample freq\n");
++#endif
++ val = codec_dac_rate;
++ }
++ else
++ {
++ val = -EINVAL;
++ }
++ return put_user(val, (long *) arg);
++
++ case SNDCTL_DSP_SETFMT:
++ case SNDCTL_DSP_GETFMTS:
++ /* SUPPORT little endian signed 16 */
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "data format is AFMT_S16_LEd\n");
++#endif
++ return put_user(AFMT_S16_LE, (long *) arg);
++
++ default:
++ return mixer_ioctl(inode, file, cmd, arg);
++ }
++ return 0;
++}
++
++
++/*
++ * Audio stuff
++ */
++static audio_stream_t assp_audio_out = {
++ name: "assp audio out",
++ dcmd: DCMD_TXASSDR,
++ drcmr: &DRCMRTXASSDR, /* ASSP dma map register */
++ dev_addr: __PREG(ASSDR),
++};
++
++
++static audio_stream_t assp_audio_in = {
++ name: "assp audio in",
++ dcmd: DCMD_RXASSDR,
++ drcmr: &DRCMRRXASSDR, /* ASSP dma map register */
++ dev_addr: __PREG(ASSDR),
++};
++
++
++static audio_state_t assp_audio_state = {
++ output_stream: &assp_audio_out,
++ input_stream: &assp_audio_in,
++ client_ioctl: assp_ioctl,
++ hw_init: assp_init,
++ hw_shutdown: assp_shutdown,
++ sem: __MUTEX_INITIALIZER(assp_audio_state.sem),
++};
++
++
++static int assp_audio_open(struct inode *inode, struct file *file)
++{
++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "assp audio open \n");
++#endif
++
++ return cotulla_audio_attach(inode, file, &assp_audio_state);
++}
++
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to cotulla_audio_attach().
++ */
++static struct file_operations assp_audio_fops = {
++ open: assp_audio_open,
++ owner: THIS_MODULE
++};
++
++
++static int mixer_dev_id;
++
++static int __init cotulla_assp_init(void)
++{
++ assp_audio_state.dev_dsp = register_sound_dsp(&assp_audio_fops, -1);
++ mixer_dev_id = register_sound_mixer(&mixer_fops, -1);
++
++ set_GPIO_mode(GPIO_ASSP_SCLK3 | GPIO_IN); /* Assp Frame sync */
++ set_GPIO_mode(GPIO_ASSP_TXD3 | GPIO_IN);
++ set_GPIO_mode(GPIO_ASSP_RXD3 | GPIO_IN); /* ASSP BitCLK */
++ set_GPIO_mode(GPIO_ASSP_SFRM3 | GPIO_IN); /* ASsp RX */
++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ Clear_Haptics_GPIO(); ++ e680_boomer_init(); ++#endif ++ ++#ifdef CONFIG_PM ++ mixer_hw_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mixer_hw_pm_callback); ++#endif ++ ++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "cotulla-assp-init ok\n");
++#endif
++ return 0;
++}
++
++
++static void __exit cotulla_assp_exit(void)
++{
++ unregister_sound_dsp(assp_audio_state.dev_dsp);
++ unregister_sound_mixer(mixer_dev_id);
++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ e680_boomer_shutdown(); ++#endif ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); ++ ++#ifdef CONFIG_PM ++ pm_unregister(mixer_hw_pm_dev); ++#endif ++ ++#ifdef EZX_OSS_DEBUG
++ printk(EZXOSS_DEBUG "cotulla-assp-exit ok\n");
++#endif
++}
++
++
++module_init(cotulla_assp_init);
++module_exit(cotulla_assp_exit);
++
++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-audio.c linux-2.6.16/sound/oss/ezx-audio.c +--- linux-2.6.16.orig/sound/oss/ezx-audio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-audio.c 2006-06-03 11:14:56.795255064 +0200 +@@ -0,0 +1,1122 @@ ++/* ++ * linux/drivers/sound/ezx-audio.c ++ * ++ * ++ * Description: audio interface for ezx ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * zhouqiong Jun 20,2002 created ++ * LiYong Sep 23,2003 (1)Port from EZX ++ * Jin Lihong(w20076) Jan 02,2004,Libdd66088 (1) Port from UDC e680 kernel of jem vob. ++ * (2) Move audio driver DEBUG macro definition to ezx-audio.h ++ * header file,and redefine DEBUG to EZX_OSS_AUDIO_DEBUG ++ * (3) reorganize file header ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * Jin Lihong(w20076) Jun.15,2004,LIBee21625 boomer's power management ++ * Jin Lihong(w20076) Aug.11,2004,LIBff01482 DMA channel release bug fix ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-common.h" ++#include "ezx-audio.h" ++ ++ ++#define AUDIO_NBFRAGS_DEFAULT 8 ++#define AUDIO_FRAGSIZE_DEFAULT 8192 ++ ++#define MAX_DMA_SIZE 4096 ++#define DMA_DESC_SIZE sizeof(pxa_dma_desc) ++ ++#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref) ++ ++ ++/* ++ * This function frees all buffers ++ */ ++static void audio_clear_buf(audio_stream_t *s) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int frag; ++ ++ if (!s->buffers) ++ return; ++ ++ /* Ensure DMA isn't running */ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("ensure dma isn't running\n"); ++#endif ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&s->stop_wq, &wait); ++ DCSR(s->dma_ch) = DCSR_STOPIRQEN; ++ schedule(); ++ remove_wait_queue(&s->stop_wq, &wait); ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("free dma buffers\n"); ++#endif ++ /* free DMA buffers */ ++ for (frag = 0; frag < s->nbfrags; frag++) { ++ audio_buf_t *b = &s->buffers[frag]; ++ if (!b->master) ++ continue; ++ consistent_free(b->data, b->master, b->dma_desc->dsadr); ++ } ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("free descriptor buffers\n"); ++#endif ++ /* free descriptor ring */ ++ if (s->buffers->dma_desc) ++ consistent_free(s->buffers->dma_desc, ++ s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE, ++ s->dma_desc_phys); ++ ++ /* free buffer structure array */ ++ kfree(s->buffers); ++ s->buffers = NULL; ++} ++ ++/* ++ * This function allocates the DMA descriptor array and buffer data space ++ * according to the current number of fragments and fragment size. ++ */ ++static int audio_setup_buf(audio_stream_t *s) ++{ ++ pxa_dma_desc *dma_desc; ++ dma_addr_t dma_desc_phys; ++ int nb_desc, frag, i, buf_size = 0; ++ char *dma_buf = NULL; ++ dma_addr_t dma_buf_phys = 0; ++ ++ if (s->buffers) ++ return -EBUSY; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("audio setup buffer \n"); ++#endif ++ /* Our buffer structure array */ ++ s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); ++ if (!s->buffers) ++ goto err; ++ memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags); ++ ++ /* ++ * Our DMA descriptor array: ++ * for Each fragment we have one checkpoint descriptor plus one ++ * descriptor per MAX_DMA_SIZE byte data blocks. ++ */ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("malloc descriptor memory\n"); ++#endif ++ nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags; ++ dma_desc = consistent_alloc(GFP_KERNEL, ++ nb_desc * DMA_DESC_SIZE, ++ &dma_desc_phys); ++ if (!dma_desc) ++ goto err; ++ s->descs_per_frag = nb_desc / s->nbfrags; ++ s->buffers->dma_desc = dma_desc; ++ s->dma_desc_phys = dma_desc_phys; ++ for (i = 0; i < nb_desc - 1; i++) ++ dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE; ++ dma_desc[i].ddadr = dma_desc_phys; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("malloc dma memory\n"); ++#endif ++ /* Our actual DMA buffers */ ++ for (frag = 0; frag < s->nbfrags; frag++) { ++ audio_buf_t *b = &s->buffers[frag]; ++ ++ /* ++ * Let's allocate non-cached memory for DMA buffers. ++ * We try to allocate all memory at once. ++ * If this fails (a common reason is memory fragmentation), ++ * then we'll try allocating smaller buffers. ++ */ ++ if (!buf_size) { ++ buf_size = (s->nbfrags - frag) * s->fragsize; ++ do { ++ dma_buf = consistent_alloc(GFP_KERNEL, ++ buf_size, ++ &dma_buf_phys); ++ if (!dma_buf) ++ buf_size -= s->fragsize; ++ } while (!dma_buf && buf_size); ++ if (!dma_buf) ++ goto err; ++ b->master = buf_size; ++ memzero(dma_buf, buf_size); ++ } ++ ++ /* ++ * Set up our checkpoint descriptor. Since the count ++ * is always zero, we'll abuse the dsadr and dtadr fields ++ * just in case this one is picked up by the hardware ++ * while processing SOUND_DSP_GETPTR. ++ */ ++ dma_desc->dsadr = dma_buf_phys; ++ dma_desc->dtadr = dma_buf_phys; ++ dma_desc->dcmd = DCMD_ENDIRQEN; ++ if (s->output && !s->mapped) ++ dma_desc->ddadr |= DDADR_STOP; ++ b->dma_desc = dma_desc++; ++ ++ /* set up the actual data descriptors */ ++ for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) { ++ dma_desc[i].dsadr = (s->output) ? ++ (dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr; ++ dma_desc[i].dtadr = (s->output) ? ++ s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE); ++ dma_desc[i].dcmd = s->dcmd | ++ ((s->fragsize < MAX_DMA_SIZE) ? ++ s->fragsize : MAX_DMA_SIZE); ++ } ++ dma_desc += i; ++ ++ /* handle buffer pointers */ ++ b->data = dma_buf; ++ dma_buf += s->fragsize; ++ dma_buf_phys += s->fragsize; ++ buf_size -= s->fragsize; ++ } ++ ++ s->usr_frag = s->dma_frag = 0; ++ s->bytecount = 0; ++ s->getptrCount = 0; ++ s->fragcount = 0; ++ sema_init(&s->sem, (s->output) ? s->nbfrags : 0); ++ return 0; ++ ++err: ++ printk("cotulla-audio: unable to allocate audio memory\n "); ++ audio_clear_buf(s); ++ return -ENOMEM; ++} ++ ++/* ++ * Our DMA interrupt handler ++ */ ++static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs) ++{ ++ audio_stream_t *s = dev_id; ++ u_int dcsr; ++ ++ dcsr = DCSR(ch); ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("dcsr=0x%lx\n", dcsr); ++#endif ++ DCSR(ch) = dcsr & ~DCSR_STOPIRQEN; ++ ++ if (!s->buffers) { ++ printk("SSP DMA: wow... received IRQ for channel %d but no buffer exists\n", ch); ++ return; ++ } ++ ++ if (dcsr & DCSR_BUSERR) ++ printk("SSP DMA: bus error interrupt on channel %d\n", ch); ++ ++ if (dcsr & DCSR_ENDINTR) ++ { ++ u_long cur_dma_desc; ++ u_int cur_dma_frag; ++ ++ /* ++ * Find out which DMA desc is current. Note that DDADR ++ * points to the next desc, not the current one. ++ */ ++ cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE; ++ /* ++ * Let the compiler nicely optimize constant divisors into ++ * multiplications for the common cases which is much faster. ++ * Common cases: x = 1 + (1 << y) for y = [0..3] ++ */ ++ switch (s->descs_per_frag) { ++ case 2: cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break; ++ case 3: cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break; ++ case 5: cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break; ++ case 9: cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break; ++ default: cur_dma_frag = ++ cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE); ++ } ++ ++ /* Account for possible wrap back of cur_dma_desc above */ ++ if (cur_dma_frag >= s->nbfrags) ++ cur_dma_frag = s->nbfrags - 1; ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("cur_dma_frag=0x%lx\n", cur_dma_frag); ++ printk("s->dma_frag=0x%lx\n", s->dma_frag); ++#endif ++ while (s->dma_frag != cur_dma_frag) { ++ if (!s->mapped) { ++ /* ++ * This fragment is done - set the checkpoint ++ * descriptor to STOP until it is gets ++ * processed by the read or write function. ++ */ ++ s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP; ++ up(&s->sem); ++ } ++ if (++s->dma_frag >= s->nbfrags) ++ s->dma_frag = 0; ++ ++ /* Accounting */ ++ s->bytecount += s->fragsize; ++ s->fragcount++; ++ } ++ ++ /* ... and for polling processes */ ++ wake_up(&s->frag_wq); ++ } ++ ++ if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE)) ++ wake_up(&s->stop_wq); ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("audio dma irq complete\n"); ++#endif ++} ++ ++/* ++ * Validate and sets up buffer fragments, etc. ++ */ ++static int audio_set_fragments(audio_stream_t *s, int val) ++{ ++ if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN) ++ return -EBUSY; ++ if (s->buffers) ++ audio_clear_buf(s); ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("audio set fragments\n"); ++#endif ++ s->nbfrags = (val >> 16) & 0x7FFF; ++ val &= 0xffff; ++ if (val < 5) ++ val = 5; ++ if (val > 15) ++ val = 15; ++ s->fragsize = 1 << val; ++ if (s->nbfrags < 2) ++ s->nbfrags = 2; ++ if (s->nbfrags * s->fragsize > 256 * 1024) ++ s->nbfrags = 256 * 1024 / s->fragsize; ++ if (audio_setup_buf(s)) ++ return -ENOMEM; ++ return val|(s->nbfrags << 16); ++} ++ ++ ++/* ++ * The fops functions ++ */ ++ ++static int audio_write(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ const char *buffer0 = buffer; ++ audio_state_t *state = (audio_state_t *)file->private_data; ++ audio_stream_t *s = state->output_stream; ++ int chunksize, ret = 0; ++ unsigned int audiostatus; ++ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ if (s->mapped) ++ return -ENXIO; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enter audio write \n"); ++ printk("buffer0=0x%lx\n", buffer0); ++ printk("count=%d\n", count); ++#endif ++ while (count > 0) { ++ audio_buf_t *b = &s->buffers[s->usr_frag]; ++ ++ /* Grab a fragment */ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ if (down_trylock(&s->sem)) ++ break; ++ } else { ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&s->sem)) ++ break; ++ } ++ ++ /* Feed the current buffer */ ++ chunksize = s->fragsize - b->offset; ++ if (chunksize > count) ++ chunksize = count; ++ if (copy_from_user(b->data + b->offset, buffer, chunksize)) { ++ up(&s->sem); ++ return -EFAULT; ++ } ++ b->offset += chunksize; ++ buffer += chunksize; ++ ++ count -= chunksize; ++ if (b->offset < s->fragsize) { ++ up(&s->sem); ++ break; ++ } ++ ++ /* ++ * Activate DMA on current buffer. ++ * We unlock this fragment's checkpoint descriptor and ++ * kick DMA if it is idle. Using checkpoint descriptors ++ * allows for control operations without the need for ++ * stopping the DMA channel if it is already running. ++ */ ++ b->offset = 0; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enable dma run\n"); ++#endif ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = b->dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ ++ /* move the index to the next fragment */ ++ if (++s->usr_frag >= s->nbfrags) ++ s->usr_frag = 0; ++ } ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("write bytes=0x%x \n", ret); ++#endif ++ return ret; ++} ++ ++ ++static int audio_read(struct file *file, char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ char *buffer0 = buffer; ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s = state->input_stream; ++ int chunksize, ret = 0; ++ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ if (s->mapped) ++ return -ENXIO; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enter audio read \n"); ++ printk("buffer0=0x%lx\n", buffer0); ++ printk("count=%d\n", count); ++#endif ++ while (count > 0) { ++ audio_buf_t *b = &s->buffers[s->usr_frag]; ++ ++ /* prime DMA */ ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = ++ s->buffers[s->dma_frag].dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ ++ /* Wait for a buffer to become full */ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ if (down_trylock(&s->sem)) ++ break; ++ } else { ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&s->sem)) ++ break; ++ } ++ ++ /* Grab data from current buffer */ ++ chunksize = s->fragsize - b->offset; ++ if (chunksize > count) ++ chunksize = count; ++ if (copy_to_user(buffer, b->data + b->offset, chunksize)) { ++ up(&s->sem); ++ return -EFAULT; ++ } ++ b->offset += chunksize; ++ buffer += chunksize; ++ count -= chunksize; ++ if (b->offset < s->fragsize) { ++ up(&s->sem); ++ break; ++ } ++ ++ /* ++ * Make this buffer available for DMA again. ++ * We unlock this fragment's checkpoint descriptor and ++ * kick DMA if it is idle. Using checkpoint descriptors ++ * allows for control operations without the need for ++ * stopping the DMA channel if it is already running. ++ */ ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ ++ /* move the index to the next fragment */ ++ if (++s->usr_frag >= s->nbfrags) ++ s->usr_frag = 0; ++ } ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("read bytes=0x%x \n", ret); ++#endif ++ return ret; ++} ++ ++ ++static int audio_sync(struct file *file) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s = state->output_stream; ++ audio_buf_t *b; ++ pxa_dma_desc *final_desc; ++ u_long dcmd_save = 0; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) ++ return 0; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enter audio sync \n"); ++#endif ++ /* ++ * Send current buffer if it contains data. Be sure to send ++ * a full sample count. ++ */ ++ final_desc = NULL; ++ b = &s->buffers[s->usr_frag]; ++ if (b->offset &= ~3) ++ { ++ final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE]; ++ b->offset &= (MAX_DMA_SIZE-1); ++ dcmd_save = final_desc->dcmd; ++ final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; ++ final_desc->ddadr |= DDADR_STOP; ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = b->dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ } ++ ++ /* Wait for DMA to complete. */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ add_wait_queue(&s->frag_wq, &wait); ++ while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) { ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&s->frag_wq, &wait); ++ ++ /* Restore the descriptor chain. */ ++ if (final_desc) { ++ final_desc->dcmd = dcmd_save; ++ final_desc->ddadr &= ~DDADR_STOP; ++ b->dma_desc->ddadr |= DDADR_STOP; ++ } ++ return 0; ++} ++ ++ ++static unsigned int audio_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ unsigned int mask = 0; ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enter audio poll \n"); ++#endif ++ if (file->f_mode & FMODE_READ) { ++ /* Start audio input if not already active */ ++ if (!is->buffers && audio_setup_buf(is)) ++ return -ENOMEM; ++ if (DCSR(is->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(is->dma_ch) = ++ is->buffers[is->dma_frag].dma_desc->ddadr; ++ DCSR(is->dma_ch) = DCSR_RUN; ++ } ++ poll_wait(file, &is->frag_wq, wait); ++ } ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ poll_wait(file, &os->frag_wq, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) ++ if (( is->mapped && (is->bytecount != is->getptrCount)) || ++ (!is->mapped && atomic_read(&is->sem.count) > 0)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ if (file->f_mode & FMODE_WRITE) ++ if (( os->mapped && (os->bytecount != os->getptrCount)) || ++ (!os->mapped && atomic_read(&os->sem.count) > 0)) ++ mask |= POLLOUT | POLLWRNORM; ++ ++ return mask; ++} ++ ++ ++static int audio_ioctl( struct inode *inode, struct file *file, ++ uint cmd, ulong arg) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *os = state->output_stream; ++ audio_stream_t *is = state->input_stream; ++ long val; ++ ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ ++ case SNDCTL_DSP_GETBLKSIZE: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("get block size\n"); ++#endif ++ if (file->f_mode & FMODE_WRITE) ++ return put_user(os->fragsize, (int *)arg); ++ else ++ return put_user(is->fragsize, (int *)arg); ++ ++ case SNDCTL_DSP_GETCAPS: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("get audio capability \n"); ++#endif ++ val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP; ++ if (is && os) ++ val |= DSP_CAP_DUPLEX; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETFRAGMENT: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("set fragment no\n"); ++#endif ++ if (get_user(val, (long *) arg)) ++ return -EFAULT; ++ ++ if (file->f_mode & FMODE_READ) ++ { ++ int ret = audio_set_fragments(is, val); ++ if (ret < 0) ++ return ret; ++ ret = put_user(ret, (int *)arg); ++ if (ret) ++ return ret; ++ } ++ if (file->f_mode & FMODE_WRITE) ++ { ++ int ret = audio_set_fragments(os, val); ++ if (ret < 0) ++ return ret; ++ ret = put_user(ret, (int *)arg); ++ if (ret) ++ return ret; ++ } ++ return 0; ++ ++ case SNDCTL_DSP_SYNC: ++ return audio_sync(file); ++ ++ case SNDCTL_DSP_SETDUPLEX: ++ return 0; ++ ++ case SNDCTL_DSP_POST: ++ return 0; ++ ++ case SNDCTL_DSP_GETTRIGGER: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("get trigger\n"); ++#endif ++ val = 0; ++ if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN) ++ val |= PCM_ENABLE_OUTPUT; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETTRIGGER: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("set trigger\n"); ++#endif ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (file->f_mode & FMODE_READ) ++ { ++ if (val & PCM_ENABLE_INPUT) ++ { ++ if (!is->buffers && audio_setup_buf(is)) ++ return -ENOMEM; ++ if (!(DCSR(is->dma_ch) & DCSR_RUN)) ++ { ++ audio_buf_t *b = &is->buffers[is->dma_frag]; ++ DDADR(is->dma_ch) = b->dma_desc->ddadr; ++ DCSR(is->dma_ch) = DCSR_RUN; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("start read dma channel\n"); ++#endif ++ } ++ } else{ ++ DCSR(is->dma_ch) = 0; ++ } ++ } ++ if (file->f_mode & FMODE_WRITE) ++ { ++ if (val & PCM_ENABLE_OUTPUT) ++ { ++ if (!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ if (!(DCSR(os->dma_ch) & DCSR_RUN)) { ++ audio_buf_t *b = &os->buffers[os->dma_frag]; ++ DDADR(os->dma_ch) = b->dma_desc->ddadr; ++ DCSR(os->dma_ch) = DCSR_RUN; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("start write dma channel\n"); ++#endif ++ } ++ } else{ ++ DCSR(os->dma_ch) = 0; ++ } ++ } ++ return 0; ++ ++ case SNDCTL_DSP_GETOSPACE: ++ case SNDCTL_DSP_GETISPACE: ++ { ++ audio_buf_info inf = { 0, }; ++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("get input and output space size\n"); ++#endif ++ if ((s == is && !(file->f_mode & FMODE_READ)) || ++ (s == os && !(file->f_mode & FMODE_WRITE))) ++ return -EINVAL; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ ++ inf.bytes = atomic_read(&s->sem.count) * s->fragsize; ++ inf.bytes -= s->buffers[s->usr_frag].offset; ++ inf.fragments = inf.bytes / s->fragsize; ++ inf.fragsize = s->fragsize; ++ inf.fragstotal = s->nbfrags; ++ ++ return copy_to_user((void *)arg, &inf, sizeof(inf)); ++ } ++ ++ case SNDCTL_DSP_GETOPTR: ++ case SNDCTL_DSP_GETIPTR: ++ { ++ count_info inf = { 0, }; ++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; ++ dma_addr_t ptr; ++ int bytecount, offset, flags; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("get input and output pointer\n"); ++#endif ++ if ((s == is && !(file->f_mode & FMODE_READ)) || ++ (s == os && !(file->f_mode & FMODE_WRITE))) ++ return -EINVAL; ++ ++ if (DCSR(s->dma_ch) & DCSR_RUN) ++ { ++ audio_buf_t *b; ++ save_flags_cli(flags); ++ ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch); ++ b = &s->buffers[s->dma_frag]; ++ offset = ptr - b->dma_desc->dsadr; ++ if (offset >= s->fragsize) ++ offset = s->fragsize - 4; ++ } else ++ { ++ save_flags(flags); ++ offset = 0; ++ } ++ inf.ptr = s->dma_frag * s->fragsize + offset; ++ bytecount = s->bytecount + offset; ++ s->getptrCount = s->bytecount; /* so poll can tell if it changes */ ++ inf.blocks = s->fragcount; ++ s->fragcount = 0; ++ restore_flags(flags); ++ if (bytecount < 0) ++ bytecount = 0; ++ inf.bytes = bytecount; ++ return copy_to_user((void *)arg, &inf, sizeof(inf)); ++ } ++ ++ case SNDCTL_DSP_NONBLOCK: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("set device none block mode\n"); ++#endif ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ ++ case SNDCTL_DSP_GETODELAY: ++ { ++ int count = 0, offset; ++ int i; ++ int flags; ++ audio_buf_t *b; ++ dma_addr_t ptr; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("get output delay\n "); ++#endif ++ if(!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ if(!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ ++ save_flags_cli(flags); ++ for(i = 0; i < os->nbfrags; i++){ ++ /* if contain data */ ++ if(atomic_read(&os->sem.count) <= 0){ ++ count += os->fragsize; ++ } ++ } ++ if (DCSR(os->dma_ch) & DCSR_RUN) ++ { ++ ptr = DSADR(os->dma_ch); ++ b = &os->buffers[os->dma_frag]; ++ offset = ptr - b->dma_desc->dsadr; ++ if (offset >= os->fragsize) ++ offset = os->fragsize - 4; ++ } else ++ { ++ offset = 0; ++ } ++ count -= offset; ++ restore_flags(flags); ++ return put_user(count,(int *)arg); ++ } ++ ++ case SNDCTL_DSP_RESET: ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("reset audio data buffer\n"); ++#endif ++ if (file->f_mode & FMODE_WRITE) ++ audio_clear_buf(os); ++ if (file->f_mode & FMODE_READ) ++ audio_clear_buf(is); ++ return 0; ++ ++ default: ++ return state->client_ioctl(inode, file, cmd, arg); ++ } ++ ++ return 0; ++} ++ ++ ++static int audio_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s; ++ unsigned long size, vma_addr; ++ int i, ret; ++ ++ if (vma->vm_pgoff != 0) ++ return -EINVAL; ++ ++ if (vma->vm_flags & VM_WRITE) { ++ if (!state->wr_ref) ++ return -EINVAL; ++ s = state->output_stream; ++ } else if (vma->vm_flags & VM_READ) { ++ if (!state->rd_ref) ++ return -EINVAL; ++ s = state->input_stream; ++ } else return -EINVAL; ++ ++ if (s->mapped) ++ return -EINVAL; ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enter audio mmap \n"); ++#endif ++ size = vma->vm_end - vma->vm_start; ++ if (size != s->fragsize * s->nbfrags) ++ return -EINVAL; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ ++ vma_addr = vma->vm_start; ++ for (i = 0; i < s->nbfrags; i++) { ++ audio_buf_t *buf = &s->buffers[i]; ++ if (!buf->master) ++ continue; ++ ret = remap_page_range(vma_addr, buf->dma_desc->dsadr, ++ buf->master, vma->vm_page_prot); ++ if (ret) ++ return ret; ++ vma_addr += buf->master; ++ } ++ for (i = 0; i < s->nbfrags; i++) ++ s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP; ++ ++ s->mapped = 1; ++ return 0; ++} ++ ++ ++static int audio_release(struct inode *inode, struct file *file) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ ++ down(&state->sem); ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("enter audio release \n"); ++#endif ++ if (file->f_mode & FMODE_READ) ++ { ++ audio_clear_buf(state->input_stream); ++ *is->drcmr = 0; ++ pxa_free_dma(is->dma_ch); ++ state->rd_ref = 0; ++ } ++ ++ if (file->f_mode & FMODE_WRITE) ++ { ++ audio_sync(file); ++ audio_clear_buf(state->output_stream); ++ *os->drcmr = 0; ++ pxa_free_dma(os->dma_ch); ++ state->wr_ref = 0; ++ } ++ ++ if (!AUDIO_ACTIVE(state)) { ++ if (state->hw_shutdown) ++ state->hw_shutdown(); ++#ifdef CONFIG_PM ++ pm_unregister(state->pm_dev); ++#endif ++ } ++ ++ up(&state->sem); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int audio_dma_sleep(audio_stream_t *s) ++{ ++ dmach_t channel; ++ ++ channel = s->dma_ch; ++ DCSR(channel)=DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("DINT=0x%lx\n", DINT); ++ printk("DCSR(%d)=0x%lx\n", channel, DCSR(channel)); ++ printk("s->dcmd=0x%lx\n", s->dcmd); ++ printk("*s->drcmr=0x%lx\n", *s->drcmr); ++ printk("DDADR(%d)=0x%lx\n", channel, DDADR(channel)); ++#endif ++ return 0; ++} ++ ++static int audio_dma_wakeup(audio_stream_t *s) ++{ ++ dmach_t channel; ++ ++ channel = s->dma_ch; ++ DCSR(channel)=DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ *s->drcmr = s->dma_ch | DRCMR_MAPVLD; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("DINT=0x%lx\n", DINT); ++ printk("DCSR(%d)=0x%lx\n", channel, DCSR(channel)); ++ printk("s->dcmd=0x%lx\n", s->dcmd); ++ printk("*s->drcmr=0x%lx\n", *s->drcmr); ++ printk("DDADR(%d)=0x%lx\n", channel, DDADR(channel)); ++#endif ++ return 0; ++} ++ ++static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ audio_state_t *state = (audio_state_t *)pm_dev->data; ++ ++ switch (req) { ++ case PM_SUSPEND: /* enter D1-D3 */ ++ if (state->output_stream) ++ audio_dma_sleep(state->output_stream); ++ if (state->input_stream) ++ audio_dma_sleep(state->input_stream); ++ if (AUDIO_ACTIVE(state) && state->hw_shutdown) ++ state->hw_shutdown(); ++ break; ++ case PM_RESUME: /* enter D0 */ ++ if (AUDIO_ACTIVE(state) && state->hw_init) ++ state->hw_init(); ++ if (state->output_stream) ++ audio_dma_wakeup(state->output_stream); ++ if (state->input_stream) ++ audio_dma_wakeup(state->input_stream); ++ break; ++ } ++ return 0; ++} ++#endif ++ ++ ++int cotulla_audio_attach(struct inode *inode, struct file *file, ++ audio_state_t *state) ++{ ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ int err; ++ ++ down(&state->sem); ++ ++ /* access control */ ++ err = -ENODEV; ++ if ((file->f_mode & FMODE_WRITE) && !os) ++ goto out; ++ if ((file->f_mode & FMODE_READ) && !is) ++ goto out; ++ ++ err = -EBUSY; ++ if ((file->f_mode & FMODE_WRITE) && state->wr_ref) ++ goto out; ++ if ((file->f_mode & FMODE_READ) && state->rd_ref) ++ goto out; ++ ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("request dma channels \n"); ++#endif ++ /* request DMA channels */ ++ if (file->f_mode & FMODE_WRITE) ++ { ++ err = pxa_request_dma(os->name, DMA_PRIO_LOW, audio_dma_irq, os); ++ if (err < 0) ++ goto out; ++ os->dma_ch = err; ++ } ++ ++ if (file->f_mode & FMODE_READ) ++ { ++ err = pxa_request_dma(is->name, DMA_PRIO_LOW, audio_dma_irq, is); ++ if (err < 0){ ++ if(file->f_mode & FMODE_WRITE){ ++ *os->drcmr = 0; ++ pxa_free_dma(os->dma_ch); ++ } ++ goto out; ++ } ++ is->dma_ch = err; ++ } ++ ++ err = -ENODEV; ++ /* now complete initialisation */ ++ if(!AUDIO_ACTIVE(state)){ ++ if(state->hw_init){ ++ err = state->hw_init(); ++ if(err<0){ ++ if(file->f_mode & FMODE_WRITE){ ++ *os->drcmr = 0; ++ pxa_free_dma(os->dma_ch); ++ } ++ if(file->f_mode & FMODE_READ){ ++ *is->drcmr = 0; ++ pxa_free_dma(is->dma_ch); ++ } ++ goto out; ++ } ++ } ++ ++#ifdef CONFIG_PM ++ state->pm_dev = pm_register(PM_SYS_DEV, 0, audio_pm_callback); ++ if (state->pm_dev) ++ state->pm_dev->data = state; ++#endif ++ } ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("init data structure \n"); ++#endif ++ file->private_data = state; ++ file->f_op->release = audio_release; ++ file->f_op->write = audio_write; ++ file->f_op->read = audio_read; ++ file->f_op->mmap = audio_mmap; ++ file->f_op->poll = audio_poll; ++ file->f_op->ioctl = audio_ioctl; ++ file->f_op->llseek = no_llseek; ++ ++ if ((file->f_mode & FMODE_WRITE)) ++ { ++ state->wr_ref = 1; ++ os->fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ os->nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ os->output = 1; ++ os->mapped = 0; ++ init_waitqueue_head(&os->frag_wq); ++ init_waitqueue_head(&os->stop_wq); ++ *os->drcmr = os->dma_ch | DRCMR_MAPVLD; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("*os->drcmr=0x%lx\n", *os->drcmr); ++#endif ++ } ++ if (file->f_mode & FMODE_READ) ++ { ++ state->rd_ref = 1; ++ is->fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ is->nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ is->output = 0; ++ is->mapped = 0; ++ init_waitqueue_head(&is->frag_wq); ++ init_waitqueue_head(&is->stop_wq); ++ *is->drcmr = is->dma_ch | DRCMR_MAPVLD; ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("*is->drcmr=0x%lx\n", *is->drcmr); ++#endif ++ } ++ err = 0; ++ up(&state->sem); ++#ifdef EZX_OSS_AUDIO_DEBUG ++ printk("audio device open success\n"); ++#endif ++ return err; ++out: ++ up(&state->sem); ++ printk("audio device is busy or there is no audio device\n"); ++ return err; ++} ++ ++EXPORT_SYMBOL(cotulla_audio_attach); ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-audio.h linux-2.6.16/sound/oss/ezx-audio.h +--- linux-2.6.16.orig/sound/oss/ezx-audio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-audio.h 2006-06-03 11:14:56.796254912 +0200 +@@ -0,0 +1,120 @@ ++/* ++ * linux/drivers/sound/ezx-audio.h ++ * ++ * ++ * Description: audio interface for ezx ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * zhou qiong June,2002 Created ++ * LiYong Sep 23,2003 Port from EZX ++ * Jin Lihong(w20076) Jan 02,2004,Libdd66088 (1) Port from UDC e680 kernel of jem vob. ++ * (2) Move all audio driver DEBUG macro definition to ezx-audio.h ++ * header file,and redefine DEBUG to EZX_OSS_DEBUG/EZX_OSS_AUDIO_DEBUG ++ * (3) reorganize file header ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * ++ */ ++ ++#ifndef EZX_AUDIO_H ++#define EZX_AUDIO_H ++ ++ ++#define NO_HEADSET 0 ++#define MONO_HEADSET 1 ++#define STEREO_HEADSET 2 ++ ++#define OUT_ADJUST_GAIN 2 ++#define IN_ADJUST_GAIN 12 ++ ++#define ASSP_CLK (1<<20) ++#define ASSP_PINS (7<<17) ++ ++ ++#define PHONE_CODEC_DEFAULT_RATE 8000 ++#define PHONE_CODEC_16K_RATE 16000 ++ ++ ++#define STEREO_CODEC_8K_RATE 8000 ++#define STEREO_CODEC_11K_RATE 11025 ++#define STEREO_CODEC_12K_RATE 12000 ++#define STEREO_CODEC_16K_RATE 16000 ++#define STEREO_CODEC_22K_RATE 22050 ++#define STEREO_CODEC_24K_RATE 24000 ++#define STEREO_CODEC_32K_RATE 32000 ++#define STEREO_CODEC_44K_RATE 44100 ++#define STEREO_CODEC_48K_RATE 48000 ++ ++ ++typedef struct { ++ int offset; /* current buffer position */ ++ char *data; /* actual buffer */ ++ pxa_dma_desc *dma_desc; /* pointer to the starting desc */ ++ int master; /* owner for buffer allocation, contain size whn true */ ++}audio_buf_t; ++ ++typedef struct { ++ char *name; /* stream identifier */ ++ audio_buf_t *buffers; /* pointer to audio buffer array */ ++ u_int usr_frag; /* user fragment index */ ++ u_int dma_frag; /* DMA fragment index */ ++ u_int fragsize; /* fragment size */ ++ u_int nbfrags; /* number of fragments */ ++ u_int dma_ch; /* DMA channel number */ ++ dma_addr_t dma_desc_phys; /* phys addr of descriptor ring */ ++ u_int descs_per_frag; /* nbr descriptors per fragment */ ++ int bytecount; /* nbr of processed bytes */ ++ int getptrCount; /* value of bytecount last time anyone asked via GETxPTR*/ ++ int fragcount; /* nbr of fragment transitions */ ++ struct semaphore sem; /* account for fragment usage */ ++ wait_queue_head_t frag_wq; /* for poll(), etc. */ ++ wait_queue_head_t stop_wq; /* for users of DCSR_STOPIRQEN */ ++ u_long dcmd; /* DMA descriptor dcmd field */ ++ volatile u32 *drcmr; /* the DMA request channel to use */ ++ u_long dev_addr; /* device physical address for DMA */ ++ int mapped:1; /* mmap()'ed buffers */ ++ int output:1; /* 0 for input, 1 for output */ ++}audio_stream_t; ++ ++typedef struct { ++ audio_stream_t *output_stream; ++ audio_stream_t *input_stream; ++ int dev_dsp; /* audio device handle */ ++ int rd_ref:1; /* open reference for recording */ ++ int wr_ref:1; /* open reference for playback */ ++ int (*hw_init)(void); ++ void (*hw_shutdown)(void); ++ int (*client_ioctl)(struct inode *, struct file *, uint, ulong); ++ struct pm_dev *pm_dev; ++ struct semaphore sem; /* prevent races in attach/release */ ++}audio_state_t; ++ ++ ++extern int cotulla_audio_attach(struct inode *inode, struct file *file, audio_state_t *state); ++ ++/* for headset and mic interrupt routine*/ ++extern void headjack_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs); ++extern void mic_change_interrupt_routine(int ch, void *dev_id, struct pt_regs *regs); ++extern int mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++ ++extern void set_pcap_telephone_codec(int port); ++extern void set_pcap_output_path(void); ++extern void set_pcap_input_path(void); ++ ++ ++extern void bluetoothaudio_open(void); ++extern void bluetoothaudio_close(void); ++ ++ ++#endif ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-common.c linux-2.6.16/sound/oss/ezx-common.c +--- linux-2.6.16.orig/sound/oss/ezx-common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-common.c 2006-06-03 11:14:56.796254912 +0200 +@@ -0,0 +1,216 @@ ++/* ++ * linux/drivers/sound/ezx-common.c ++ * ++ * ++ * Description: common functions implementation for ezx audio drivers ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface ++ * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics ++ * Cheng Xuefeng(a2491c) June.24,2004,LIBdd95397 Add sound path for EMU PIHF ++ * ++ */ ++ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-common.h" ++ ++ ++int codec_output_gain = EZX_OSS_DEFAULT_OUTPUT_LOGICAL_GAIN; /* A2,loudspeaker, gain level */ ++output_enum codec_output_path = LOUDERSPEAKER_OUT; ++output_base_enum codec_output_base = PCAP_BASE; ++ ++int codec_input_gain = EZX_OSS_DEFAULT_AUDIG_LOGICAL_GAIN; /* A5,mic,gain=+17db */ ++input_enum codec_input_path = HANDSET_INPUT; ++int audioonflag = 0; ++int micinflag = 0; ++ ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ ++void (*mixer_close_input_path[INPUT_TOTAL_TYPES])(void) = ++{ ++ close_input_carkit, ++ close_input_handset, ++ close_input_headset, ++ close_input_funlight ++}; ++ ++void (*mixer_open_input_path[INPUT_TOTAL_TYPES])(void) = ++{ ++ open_input_carkit, ++ open_input_handset, ++ open_input_headset, ++ open_input_funlight ++}; ++ ++void (*mixer_close_output_path[][OUTPUT_TOTAL_TYPES])(void) = ++{ ++ { ++ close_output_pcap_headset, ++ close_output_pcap_louderspeaker, ++ close_output_pcap_earpiece, ++ close_output_pcap_carkit, ++ close_output_pcap_headjack, ++ close_output_pcap_bluetooth, ++ close_output_pcap_louderspeaker_mixed ++ }, ++ { ++ close_output_ma3_headset, ++ close_output_ma3_louderspeaker, ++ close_output_ma3_earpiece, ++ close_output_ma3_carkit, ++ close_output_ma3_headjack, ++ close_output_ma3_bluetooth, ++ close_output_ma3_louderspeaker_mixed ++ }, ++ { ++ close_output_fm_headset, ++ close_output_fm_louderspeaker, ++ close_output_fm_earpiece, ++ close_output_fm_carkit, ++ close_output_fm_headjack, ++ close_output_fm_bluetooth, ++ close_output_fm_louderspeaker_mixed ++ }, ++ { ++ close_output_mixed_headset, ++ close_output_mixed_louderspeaker, ++ close_output_mixed_earpiece, ++ close_output_mixed_carkit, ++ close_output_mixed_headjack, ++ close_output_mixed_bluetooth, ++ close_output_mixed_louderspeaker_mixed ++ } ++}; ++ ++int (*mixer_open_output_path[][OUTPUT_TOTAL_TYPES])(long val) = ++{ ++ { ++ open_output_pcap_headset, ++ open_output_pcap_louderspeaker, ++ open_output_pcap_earpiece, ++ open_output_pcap_carkit, ++ open_output_pcap_headjack, ++ open_output_pcap_bluetooth, ++ open_output_pcap_louderspeaker_mixed ++ }, ++ { ++ open_output_ma3_headset, ++ open_output_ma3_louderspeaker, ++ open_output_ma3_earpiece, ++ open_output_ma3_carkit, ++ open_output_ma3_headjack, ++ open_output_ma3_bluetooth, ++ open_output_ma3_louderspeaker_mixed ++ }, ++ { ++ open_output_fm_headset, ++ open_output_fm_louderspeaker, ++ open_output_fm_earpiece, ++ open_output_fm_carkit, ++ open_output_fm_headjack, ++ open_output_fm_bluetooth, ++ open_output_fm_louderspeaker_mixed ++ }, ++ { ++ open_output_mixed_headset, ++ open_output_mixed_louderspeaker, ++ open_output_mixed_earpiece, ++ open_output_mixed_carkit, ++ open_output_mixed_headjack, ++ open_output_mixed_bluetooth, ++ open_output_mixed_louderspeaker_mixed ++ } ++}; ++#endif /* CONFIG_ARCH_EZX_E680 */ ++ ++ ++#ifdef CONFIG_ARCH_EZX_A780 ++void (*mixer_close_input_path[INPUT_TOTAL_TYPES])(void) = ++{ ++ close_input_carkit, ++ close_input_handset, ++#if EMU_PIHF_FEATURE ++ close_input_headset, ++ close_input_pihf_carkit ++#else ++ close_input_headset ++#endif ++ ++}; ++ ++void (*mixer_open_input_path[INPUT_TOTAL_TYPES])(void) = ++{ ++ open_input_carkit, ++ open_input_handset, ++#if EMU_PIHF_FEATURE ++ open_input_headset, ++ open_input_pihf_carkit ++#else ++ open_input_headset ++#endif ++}; ++ ++void (*mixer_close_output_path[][OUTPUT_TOTAL_TYPES])(void) = ++{ ++ { ++ close_output_pcap_headset, ++ close_output_pcap_louderspeaker, ++ close_output_pcap_earpiece, ++ close_output_pcap_carkit, ++ close_output_pcap_headjack, ++#if EMU_PIHF_FEATURE ++ close_output_pcap_bluetooth, ++ close_output_pcap_pihf_carkit ++#else ++ close_output_pcap_bluetooth ++#endif ++ } ++}; ++ ++int (*mixer_open_output_path[][OUTPUT_TOTAL_TYPES])(long val) = ++{ ++ { ++ open_output_pcap_headset, ++ open_output_pcap_louderspeaker, ++ open_output_pcap_earpiece, ++ open_output_pcap_carkit, ++ open_output_pcap_headjack, ++#if EMU_PIHF_FEATURE ++ open_output_pcap_bluetooth, ++ open_output_pcap_pihf_carkit ++#else ++ open_output_pcap_bluetooth ++#endif ++ } ++}; ++#endif ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-common.h linux-2.6.16/sound/oss/ezx-common.h +--- linux-2.6.16.orig/sound/oss/ezx-common.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-common.h 2006-06-03 11:14:56.797254760 +0200 +@@ -0,0 +1,161 @@ ++/* ++ * linux/drivers/sound/ezx-common.h ++ * ++ * ++ * Description: header file for ezx-common.c ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jin Lihong(w20076) Jan 12,2004,LIBdd68327 Created,Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface ++ * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics ++ * Li Yong(w19946) Apr.22.2004.LIBee02702 Add EMU carKit ++ * Cheng Xuefeng(a2491c) Jun.15.2004,LIBdd95397 Support EMU PIHF feature ++ * ++ */ ++ ++#ifndef EZX_COMMON_H ++#define EZX_COMMON_H ++ ++#include "ezx-e680.h" ++#include "ezx-a780.h" ++#include "../../drivers/misc/ezx/ssp_pcap.h" ++ ++#define EZXOSS_EMERG "Snd driver w20076 <0 EMERG>: " /* system is unusable */ ++#define EZXOSS_ALERT "Snd driver w20076 <1 ALERT>: " /* action must be taken immediately */ ++#define EZXOSS_CRIT "Snd driver w20076 <2 CRIT>: " /* critical conditions */ ++#define EZXOSS_ERR "Snd driver w20076 <3 ERR>: " /* error conditions */ ++#define EZXOSS_WARNING "Snd driver w20076 <4 WARNING>: " /* warning conditions */ ++#define EZXOSS_NOTICE "Snd driver w20076 <5 NOTICE>: " /* normal but significant condition */ ++#define EZXOSS_INFO "Snd driver w20076 <6 INFO>: " /* informational */ ++#define EZXOSS_DEBUG "Snd driver w20076 <7 DEBUG>: " /* debug-level messages */ ++ ++#define MONODEVOPENED ( audioonflag & (PHONE_DEVICE|DSP16_DEVICE|AUDIO_DEVICE) ) ++#define PHONEDEVOPENED ( audioonflag & PHONE_DEVICE ) ++ ++#define EZX_OSS_MIN_LOGICAL_GAIN 0 ++#define EZX_OSS_MAX_LOGICAL_GAIN 100 ++#define EZX_OSS_DEFAULT_OUTPUT_LOGICAL_GAIN 74 /* +9db, same as a760 */ ++#define EZX_OSS_DEFAULT_AUDIG_LOGICAL_GAIN 55 /* +17db, same as a760 */ ++#define EZX_OSS_DEFAULT_MIC2IG_LOGICAL_GAIN 55 /* +17db, same as a760 */ ++ ++#define PCAP_OUTPUT_GAIN_MIN_REG_VAL 0 ++#define PCAP_OUTPUT_GAIN_MAX_REG_VAL 15 ++#define PCAP_INPUT_GAIN_MIN_REG_VAL 0 ++#define PCAP_INPUT_GAIN_MAX_REG_VAL 31 ++/*EMU CarKit Mute control signal */ ++#define EIHF_UNMUTE 0x01 ++#define EIHF_MUTE 0x00 ++ ++#define DEFAULT_USB_MODE 0x00 ++#define MONO_AUDIO_MODE 0x02 ++#define SETERO_AUDIO_MODE 0x03 ++ ++#define PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC (codec_output_gain*PCAP_OUTPUT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) ++#define PCAP_INPUT_AUDIG_REG_VAL_FROM_LOGIC (codec_input_gain*PCAP_INPUT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) ++#define PCAP_INPUT_MIC2IG_REG_VAL_FROM_LOGIC (codec_input_gain*PCAP_INPUT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) ++ ++#ifdef EMU_PIHF_FEATURE ++typedef enum{ ++ HEADSET_OUT, /* ear-phone : stereo headset */ ++ LOUDERSPEAKER_OUT, /* A2_OUTPUT in a760 */ ++ EARPIECE_OUT, /* A1_OUTPUT in a760 */ ++ CARKIT_OUT, /* A4_OUTPUT in a760 */ ++ HEADJACK_OUT, /* mono headjack, HEADJACK_OUTPUT in a760 */ ++ BLUETOOTH_OUT, /* bluetooth headset */ ++ PIHF_CARKIT_OUT /* A4_OUTPUT in a760 */ ++}output_enum; ++#else /* EMU_PIHF_FEATURE */ ++typedef enum{ ++ HEADSET_OUT, /* ear-phone : stereo headset */ ++ LOUDERSPEAKER_OUT, /* A2_OUTPUT in a760 */ ++ EARPIECE_OUT, /* A1_OUTPUT in a760 */ ++ CARKIT_OUT, /* A4_OUTPUT in a760 */ ++ HEADJACK_OUT, /* mono headjack, HEADJACK_OUTPUT in a760 */ ++ BLUETOOTH_OUT, /* bluetooth headset */ ++ LOUDERSPEAKER_MIXED_OUT /* e680 louderspeaker out, boomer input is stereo+mono, mono is aimed for haptics signals */ ++}output_enum; ++#endif /* EMU_PIHF_FEAURE */ ++ ++typedef enum{ ++ PCAP_BASE = 0x0000 , /* used to tell that we are setting the PCAP */ ++ MA3_BASE = 0x0100 , /* MA3 Midi device */ ++ FM_BASE = 0x0200 , /* FM radio device */ ++ MIXED_BASE = 0x0300 /* Both MA3 device and PCAP device are used */ ++}output_base_enum; ++ ++#ifdef EMU_PIHF_FEATURE ++typedef enum{ ++ CARKIT_INPUT, /* EXT_MIC */ ++ HANDSET_INPUT , /* A5 */ ++ HEADSET_INPUT , /* A3 */ ++ PIHF_CARKIT_INPUT /* EXT_MIC */ ++}input_enum; ++#else /* EMU_PIHF_FEATURE */ ++typedef enum{ ++ CARKIT_INPUT, /* EXT_MIC */ ++ HANDSET_INPUT , /* A5 */ ++ HEADSET_INPUT , /* A3 */ ++ FUNLIGHT_INPUT /* E680 funlight */ ++}input_enum; ++#endif /* EMU_PIHF_FEATURE */ ++ ++ ++#define INPUT_PATH_MIN CARKIT_INPUT ++ ++#ifdef CONFIG_PXA_EZX_A780 ++#ifdef EMU_PIHF_FEATURE ++#define INPUT_PATH_MAX PIHF_CARKIT_INPUT ++#define INPUT_TOTAL_TYPES 4 /* = HEADSET_INPUT+1 */ ++#define OUTPUT_PATH_MAX PIHF_CARKIT_OUT ++#define OUTPUT_BASE_MAX PCAP_BASE ++#define OUTPUT_TOTAL_TYPES 7 /* = BLUETOOTH_OUT+1 */ ++#else /* EMU_PIHF_FEATURE */ ++#define INPUT_PATH_MAX HEADSET_INPUT ++#define INPUT_TOTAL_TYPES 3 /* = HEADSET_INPUT+1 */ ++#define OUTPUT_PATH_MAX BLUETOOTH_OUT ++#define OUTPUT_BASE_MAX PCAP_BASE ++#define OUTPUT_TOTAL_TYPES 6 /* = BLUETOOTH_OUT+1 */ ++#endif /* EMU_PIHF_FEATURE */ ++#endif ++ ++#ifdef CONFIG_PXA_EZX_E680 ++#define INPUT_PATH_MAX FUNLIGHT_INPUT ++#define INPUT_TOTAL_TYPES 4 /* = FUNLIGHT_INPUT + 1 */ ++#define OUTPUT_PATH_MAX LOUDERSPEAKER_MIXED_OUT ++#define OUTPUT_BASE_MAX MIXED_BASE ++#define OUTPUT_TOTAL_TYPES 7 /* = LOUDERSPEAKER_MIXED_OUT+1 */ ++#endif ++ ++#define OUTPUT_BASE_MEANINGFUL_START_BIT 8 ++#define OUTPUT_BASE_TYPE(x) (x >>OUTPUT_BASE_MEANINGFUL_START_BIT) ++#define OUTPUT_BASE_TOTAL_TYPES (OUTPUT_BASE_MAX>>OUTPUT_BASE_MEANINGFUL_START_BIT +1) ++#define GET_OUTPUT_BASE(x) (x&0xFF00) ++#define GET_OUTPUT_PATH(x) (x&0x00FF) ++ ++ ++extern int codec_output_gain, codec_input_gain; ++extern output_enum codec_output_path; ++extern input_enum codec_input_path; ++extern output_base_enum codec_output_base; ++extern int audioonflag; ++extern int micinflag; ++ ++extern void (*mixer_close_output_path[][OUTPUT_TOTAL_TYPES])(void); ++extern int (*mixer_open_output_path[][OUTPUT_TOTAL_TYPES])(long val); ++extern void (*mixer_close_input_path[INPUT_TOTAL_TYPES])(void); ++extern void (*mixer_open_input_path[INPUT_TOTAL_TYPES])(void); ++ ++ ++#endif ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-e680.c linux-2.6.16/sound/oss/ezx-e680.c +--- linux-2.6.16.orig/sound/oss/ezx-e680.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-e680.c 2006-06-03 11:14:56.799254456 +0200 +@@ -0,0 +1,1733 @@ ++/* ++ * linux/drivers/sound/ezx-e680.c ++ * ++ * ++ * Description: Motorola e680 phone specific functions implementation for audio drivers ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Created, Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90336 play music noise tmp solution ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * Jin Lihong(w20076) Apr.20,2004,LIBee01165 reduce noise ++ * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics ++ * Li Yong(w19946) Apr.23.2004.LIBee02702 Add EMU Carkit ++ * Jin Lihong(w20076) Jun.08,2004,libee14656 change boomer input path for mono sound ++ * Jin Lihong(w20076) Jun.15,2004,LIBee21625 boomer's power management ++ * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save ++ * Wu Hongxing(w20691)Jul.07,2004 LIBee29664 ap 13m clock usage. ++ * Jin Lihong(w20076) Aug.11,2004,LIBff01482 mixer power on/off sequence optimize ++ * ++ */ ++ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/delay.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-common.h" ++ ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ ++EXPORT_SYMBOL(poweron_mixer); ++EXPORT_SYMBOL(shutdown_mixer); ++EXPORT_SYMBOL(kernel_clr_oscc_13m_clock); ++EXPORT_SYMBOL(kernel_set_oscc_13m_clock); ++ ++static DECLARE_MUTEX(ezx_mixer_mutex); ++ ++ ++ ++#define BOOMER_MONO_VOL_REG_PREFIX 0x00 ++#define BOOMER_STEREO_LEFT_VOL_REG_PREFIX 0x40 ++#define BOOMER_STEREO_RIGHT_VOL_REG_PREFIX 0x80 ++#define BOOMER_MODE_CONTROL_REG_PREFIX 0xC0 ++ ++#define BOOMER_MONO_GAIN_MIN_REG_VAL 0 ++#define BOOMER_MONO_GAIN_MAX_REG_VAL 31 ++#define BOOMER_MONO_GAIN_DEFAULT_REG_VAL 15 ++#define BOOMER_MONO_GAIN_DEFAULT_FIXED_REG_VAL 23 ++#define BOOMER_MONO_GAIN_MIXED_INPUT_CASE_REG_VAL 15 /* when in a special use case: mono input for haptics, ++ stereo input for audio signals */ ++ ++#define BOOMER_STEREO_LEFT_GAIN_MIN_REG_VAL 0 ++#define BOOMER_STEREO_LEFT_GAIN_MAX_REG_VAL 31 ++#define BOOMER_STEREO_LEFT_GAIN_DEFAULT_REG_VAL 15 ++#define BOOMER_STEREO_LEFT_GAIN_DEFAULT_FIXED_REG_VAL 27 ++#define BOOMER_STEREO_LEFT_GAIN_MIXED_INPUT_CASE_REG_VAL 27 /* when in a special use case: mono input for haptics, ++ stereo input for audio signals */ ++ ++#define BOOMER_STEREO_RIGHT_GAIN_MIN_REG_VAL 0 ++#define BOOMER_STEREO_RIGHT_GAIN_MAX_REG_VAL 31 ++#define BOOMER_STEREO_RIGHT_GAIN_DEFAULT_REG_VAL 15 ++#define BOOMER_STEREO_RIGHT_GAIN_DEFAULT_FIXED_REG_VAL 27 ++#define BOOMER_STEREO_RIGHT_GAIN_MIXED_INPUT_CASE_REG_VAL 27 /* when in a special use case: mono input for haptics, ++ stereo input for audio signals */ ++ ++#define BOOMER_OUTPUT_GAIN_MONO_REG_VAL_FROM_LOGIC (codec_output_gain*BOOMER_MONO_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) ++#define BOOMER_OUTPUT_GAIN_STEREO_LEFT_REG_VAL_FROM_LOGIC (codec_output_gain*BOOMER_STEREO_LEFT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) ++#define BOOMER_OUTPUT_GAIN_STEREO_RIGHT_REG_VAL_FROM_LOGIC (codec_output_gain*BOOMER_STEREO_RIGHT_GAIN_MAX_REG_VAL/EZX_OSS_MAX_LOGICAL_GAIN) ++ ++#define BOOMER_LOUDER_SPEAKER_3D_OFF 0X00 /* bit LD5 */ ++#define BOOMER_LOUDER_SPEAKER_3D_ON 0X20 ++#define BOOMER_HEADPHONE_3D_OFF 0X00 /* bit RD5 */ ++#define BOOMER_HEADPHONE_3D_ON 0X20 ++ ++#define BOOMER_SHUTDOWN 0X00 /* bit CD3 ~ CD0 */ ++#define BOOMER_IN_MONO_OUT_MONO_EARPIECE 0X01 ++#define BOOMER_IN_MONO_OUT_LOUDER_SPEAKER 0X02 ++#define BOOMER_IN_MONO_OUT_LOUDER_SPEAKER_AND_HEADPHONE 0X03 ++#define BOOMER_IN_MONO_OUT_HEADPHONE 0X04 ++#define BOOMER_IN_MONO_OUT_MONO_LINEOUT 0X05 ++#define BOOMER_IN_STEREO_OUT_MONO_EARPIECE 0X06 ++#define BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER 0X07 ++#define BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER_AND_HEADPHONE 0X08 ++#define BOOMER_IN_STEREO_OUT_HEADPHONE 0X09 ++#define BOOMER_IN_STEREO_OUT_MONO_LINEOUT 0X0a ++#define BOOMER_IN_MONO_AND_STEREO_OUT_MONO_EARPIECE 0X0b ++#define BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER 0X0c ++#define BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER_AND_HEADPHONE 0X0d ++#define BOOMER_IN_MONO_AND_STEREO_OUT_HEADPHONE 0X0e ++#define BOOMER_IN_MONO_AND_STEREO_OUT_MONO_LINEOUT 0X0f ++ ++#define BOOMER_FAST_WAKEUP 0X00 /* bit CD5 */ ++#define BOOMER_SLOW_WAKEUP 0X20 ++ ++#define BOOMER_EARPIECE_GAIN_SMALL_OPTION 0X00 /* bit CD4 */ ++#define BOOMER_EARPIECE_GAIN_LARGE_OPTION 0X10 ++ ++ ++typedef struct { ++ u8 monovol; /* mono volume */ ++ u8 leftvol; /* stereo left volume */ ++ u8 rightvol; /* stereo right volume */ ++ u8 path; /* boomer path setup */ ++ u8 speaker3d; ++ u8 headphone3d; ++ u8 wakeuptime; /* fast or slow wakeup setting */ ++ u8 earpiecegaintable; /* earpiece gain table select */ ++} e680_boomer; ++ ++ ++static e680_boomer e680boomer; ++static u32 gpio_flt_sel_status; ++u32 gpio_va_sel_status; ++ ++static void set_boomer_mono_vol_reg( void ); ++static void set_boomer_stereo_left_vol_reg(void); ++static void set_boomer_stereo_right_vol_reg(void); ++static void set_boomer_mode_control_reg(void); ++ ++static void write_boomer(const char *buf, size_t count); ++extern int mixer_write(const char *buf, size_t count); ++ ++ ++void e680_boomer_init(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "e680 boomer init\n"); ++#endif ++ ++ e680boomer.monovol = BOOMER_MONO_GAIN_DEFAULT_REG_VAL; ++ e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_DEFAULT_REG_VAL; ++ e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_DEFAULT_REG_VAL; ++ e680boomer.path = BOOMER_IN_MONO_OUT_MONO_LINEOUT; ++ e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_ON; ++ e680boomer.headphone3d = BOOMER_HEADPHONE_3D_ON; ++ e680boomer.wakeuptime = BOOMER_FAST_WAKEUP; ++ e680boomer.earpiecegaintable = BOOMER_EARPIECE_GAIN_LARGE_OPTION; ++ ++ set_boomer_mode_control_reg(); ++ set_boomer_mono_vol_reg(); ++ set_boomer_stereo_left_vol_reg(); ++ set_boomer_stereo_right_vol_reg(); ++} ++ ++ ++void e680_boomer_shutdown(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "e680 boomer shutdown.\n"); ++#endif ++ ++ e680boomer.path = BOOMER_SHUTDOWN; ++ set_boomer_mode_control_reg(); ++} ++ ++ ++void e680_boomer_path_mono_lineout(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " set E680 boomer path to mono input mono lineout.\n"); ++#endif ++ ++ e680boomer.path = BOOMER_IN_MONO_OUT_MONO_LINEOUT; ++ set_boomer_mode_control_reg(); ++} ++ ++ ++void e680_boomer_path_tmp_mono_lineout(void) ++{ ++ u8 mode; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " mute E680 boomer.\n"); ++#endif ++ ++ mode = BOOMER_MODE_CONTROL_REG_PREFIX | BOOMER_IN_MONO_OUT_MONO_LINEOUT ++ | e680boomer.wakeuptime | e680boomer.earpiecegaintable; ++ ++ write_boomer(&mode, 1); ++} ++ ++ ++void e680_boomer_path_tmp_shutdown(void) ++{ ++ u8 mode; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " E680 boomer path set to tmp shutdown..\n"); ++#endif ++ ++ mode = BOOMER_MODE_CONTROL_REG_PREFIX | BOOMER_SHUTDOWN ++ | e680boomer.wakeuptime | e680boomer.earpiecegaintable; ++ ++ write_boomer(&mode, 1); ++} ++ ++ ++void e680_boomer_path_restore(void) ++{ ++ u8 mode; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " E680 boomer path restore: path = 0X%X \n", e680boomer.path); ++#endif ++ mode = BOOMER_MODE_CONTROL_REG_PREFIX | e680boomer.path | e680boomer.wakeuptime | e680boomer.earpiecegaintable; ++ write_boomer(&mode, 1); ++} ++ ++ ++static void set_boomer_mono_vol_reg( void ) ++{ ++ u8 vol; ++ ++ vol = BOOMER_MONO_VOL_REG_PREFIX | e680boomer.monovol; ++ write_boomer(&vol, 1); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "set e680 boomer mono volume register,vol=0x%2X \n", vol); ++#endif ++} ++ ++ ++static void set_boomer_stereo_left_vol_reg(void) ++{ ++ u8 vol; ++ ++ vol = BOOMER_STEREO_LEFT_VOL_REG_PREFIX | e680boomer.leftvol | e680boomer.speaker3d; ++ write_boomer(&vol, 1); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "set e680 boomer stereo left volume register,vol=0x%2X \n", vol); ++#endif ++} ++ ++ ++static void set_boomer_stereo_right_vol_reg(void) ++{ ++ u8 vol; ++ ++ vol = BOOMER_STEREO_RIGHT_VOL_REG_PREFIX | e680boomer.rightvol | e680boomer.headphone3d; ++ write_boomer(&vol, 1); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "set e680 boomer stereo right volume register,vol=0x%2X \n", vol); ++#endif ++} ++ ++ ++static void set_boomer_mode_control_reg(void) ++{ ++ u8 mode; ++ ++ mode = BOOMER_MODE_CONTROL_REG_PREFIX | e680boomer.path | e680boomer.wakeuptime | e680boomer.earpiecegaintable; ++ write_boomer(&mode, 1); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "set e680 boomer mode control register,mode=0x%2X \n", mode); ++#endif ++} ++ ++ ++static void write_boomer(const char *buf, size_t count) ++{ ++ int ret, i = 0; ++ size_t written = 0; ++ ++ while(written<count) ++ { ++ ret = mixer_write(buf+written, count-written); ++ written+=ret; ++ i++; ++ if( i>2 ) ++ break; ++ } ++ if( written < count ) ++ printk(EZXOSS_ERR "write boomer failed.\n"); ++} ++ ++ ++void poweron_mixer( audio_dev_type type ) ++{ ++ down(&ezx_mixer_mutex); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 No. 0x%X device wants to power on the mixer hardware.\n", type); ++ printk(EZXOSS_DEBUG "E680 No. 0x%X device has already powered on the mixer hardware.\n", audioonflag); ++#endif ++ ++ audioonflag |= type; ++ ++ if( MIXERISSTEREO == type ){ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 No. 0x%X device is powering on the mixer hardware.\n", type); ++#endif ++ ++ if( (type==MIDI_DEVICE) || (type==FM_DEVICE) ) ++ mute_output_to_avoid_pcap_noise(); ++ ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++ ++ /* (1) set pcap audio power V2_EN_2(OR WITH V2_EN) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2); ++ ++ /* (6) enable output_path and set gain */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); /* disable codec bypass */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW); /* close stereo switch */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW); /* open telephone codec path into right PGA */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); /* close PGA_INR into PGA */ ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); /* enable right PGA */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); /* enable left PGA */ ++ ++ if( (type==MIDI_DEVICE) || (type==FM_DEVICE) ) ++ undo_mute_output_to_avoid_pcap_noise(); ++ } ++ ++ up(&ezx_mixer_mutex); ++} ++ ++ ++void shutdown_mixer( audio_dev_type type ) ++{ ++ down(&ezx_mixer_mutex); ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 No. 0x%X device wants to shut down the mixer hardware.\n", type); ++#endif ++ ++ if( audioonflag == type ){ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 No. 0x%X device is shutting down the mixer hardware.\n", type); ++#endif ++ ++ e680_boomer_path_mono_lineout(); /* mute hw noise and save power for e680 */ ++ ++ /* close pcap output path */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ } ++ ++ audioonflag &= ~type; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 No. 0x%X device is still using the mixer hardware.\n", audioonflag); ++#endif ++ ++ up(&ezx_mixer_mutex); ++} ++ ++ ++void mixer_not_in_use(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " E680 mixer not in use.\n"); ++#endif ++ ++ (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(); ++ (*mixer_close_input_path[codec_input_path])(); ++ ++ if( micinflag == 0 ) /* close pcap output path */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ ++ e680_boomer_path_mono_lineout(); ++} ++ ++ ++void set_output_gain_hw_reg(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "set output gain hw register. \n"); ++#endif ++ ++ SSP_PCAP_AUDOG_set( PCAP_OUTPUT_GAIN_REG_VAL_FROM_LOGIC ); ++ ++ if( e680boomer.path == BOOMER_SHUTDOWN ){ ++ ; ++ } ++ else if( e680boomer.path <= BOOMER_IN_MONO_OUT_MONO_LINEOUT ){ ++ e680boomer.monovol = BOOMER_MONO_GAIN_DEFAULT_FIXED_REG_VAL; ++ set_boomer_mono_vol_reg(); ++ } ++ else if( e680boomer.path <= BOOMER_IN_STEREO_OUT_MONO_LINEOUT ){ ++ e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_DEFAULT_FIXED_REG_VAL; ++ e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_DEFAULT_FIXED_REG_VAL; ++ set_boomer_stereo_left_vol_reg(); ++ set_boomer_stereo_right_vol_reg(); ++ } ++ else{ ++ if( e680boomer.path == BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER ){ ++ e680boomer.monovol = BOOMER_MONO_GAIN_MIXED_INPUT_CASE_REG_VAL; ++ e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_MIXED_INPUT_CASE_REG_VAL; ++ e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_MIXED_INPUT_CASE_REG_VAL; ++ } ++ else{ ++ e680boomer.monovol = BOOMER_MONO_GAIN_DEFAULT_FIXED_REG_VAL; ++ e680boomer.leftvol = BOOMER_STEREO_LEFT_GAIN_DEFAULT_FIXED_REG_VAL; ++ e680boomer.rightvol = BOOMER_STEREO_RIGHT_GAIN_DEFAULT_FIXED_REG_VAL; ++ } ++ set_boomer_mono_vol_reg(); ++ set_boomer_stereo_left_vol_reg(); ++ set_boomer_stereo_right_vol_reg(); ++ } ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "codec_output_gain=%d\n", codec_output_gain); ++#endif ++} ++ ++ ++void set_input_gain_hw_reg(void) ++{ ++ SSP_PCAP_AUDIG_set( PCAP_INPUT_AUDIG_REG_VAL_FROM_LOGIC ); ++ ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "codec_input_gain=%d\n", codec_input_gain ); ++#endif ++} ++ ++ ++void set_boomer_3d_status(boomer_3d_status status) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "set boomer 3d status.\n"); ++#endif ++ ++ switch(status) ++ { ++ case LOUDERSPEAKER_ON_HEADSET_OFF_3D: ++ e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_ON; ++ e680boomer.headphone3d = BOOMER_HEADPHONE_3D_OFF; ++ break; ++ ++ case LOUDERSPEAKER_OFF_HEADSET_ON_3D: ++ e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_OFF; ++ e680boomer.headphone3d = BOOMER_HEADPHONE_3D_ON; ++ break; ++ ++ case LOUDERSPEAKER_OFF_HEADSET_OFF_3D: ++ e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_OFF; ++ e680boomer.headphone3d = BOOMER_HEADPHONE_3D_OFF; ++ break; ++ ++ case LOUDERSPEAKER_ON_HEADSET_ON_3D: ++ default: ++ e680boomer.speaker3d = BOOMER_LOUDER_SPEAKER_3D_ON; ++ e680boomer.headphone3d = BOOMER_HEADPHONE_3D_ON; ++ } ++ ++ set_boomer_stereo_left_vol_reg(); ++ set_boomer_stereo_right_vol_reg(); ++} ++ ++ ++boomer_3d_status get_boomer_3d_status(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "get boomer 3d status.\n"); ++#endif ++ ++ if(e680boomer.speaker3d == BOOMER_LOUDER_SPEAKER_3D_ON){ ++ if(e680boomer.headphone3d == BOOMER_HEADPHONE_3D_ON) ++ return LOUDERSPEAKER_ON_HEADSET_ON_3D; ++ else ++ return LOUDERSPEAKER_ON_HEADSET_OFF_3D; ++ } ++ else{ ++ if(e680boomer.headphone3d == BOOMER_HEADPHONE_3D_ON) ++ return LOUDERSPEAKER_OFF_HEADSET_ON_3D; ++ else ++ return LOUDERSPEAKER_OFF_HEADSET_OFF_3D; ++ } ++} ++ ++ ++void set_gpio_va_sel_out_high(void) ++{ ++ set_GPIO_mode(GPIO_VA_SEL_BUL | GPIO_OUT); ++ set_GPIO(GPIO_VA_SEL_BUL); ++ PGSR(GPIO_VA_SEL_BUL) |= GPIO_bit(GPIO_VA_SEL_BUL); ++ gpio_va_sel_status = 1; ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "set VA_SEL high. \n"); ++#endif ++} ++ ++ ++void set_gpio_va_sel_out_low(void) ++{ ++ set_GPIO_mode(GPIO_VA_SEL_BUL | GPIO_OUT); ++ clr_GPIO(GPIO_VA_SEL_BUL); ++ PGSR(GPIO_VA_SEL_BUL) &= ~GPIO_bit(GPIO_VA_SEL_BUL); ++ gpio_va_sel_status = 0; ++#ifdef EZX_OSS_DEBUG ++ printk( EZXOSS_DEBUG "set VA_SEL low. \n"); ++#endif ++} ++ ++ ++void close_input_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input carkit. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++ ++ ++void close_input_handset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input handset. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); ++} ++ ++ ++void close_input_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input headset. \n"); ++#endif ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); ++} ++ ++ ++void close_input_funlight(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close input funlight. \n"); ++#endif ++ ++ /* disable PCAP codec */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); ++ /* set fsync, tx, bitclk are tri-stated */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++ ++ ++void open_input_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input carkit. \n"); ++#endif ++ codec_input_path = CARKIT_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++ ++ ++void open_input_handset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input handset. \n"); ++#endif ++ ++ codec_input_path = HANDSET_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX); ++} ++ ++ ++void open_input_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input headset. \n"); ++#endif ++ ++ codec_input_path = HEADSET_INPUT; ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX); ++} ++ ++ ++void open_input_funlight(void) ++{ ++ unsigned long ssp_pcap_register_val; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open input funlight. \n"); ++#endif ++ ++ codec_input_path = FUNLIGHT_INPUT; ++ ++ set_gpio_va_sel_out_high(); ++ ++ /* (2) set codec sample rate(FS_8K_16K=0) */ ++ /* CDC_CLK(000=13MHZ) bitclk output(SMB=0) audio IO1(DIG_AUD_IN=1) */ ++ ssp_pcap_register_val = PCAP_CDC_CLK_IN_13M0; ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, ssp_pcap_register_val); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); /* codec master */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); /* 8K sample rate */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN); /* DAI0 */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV); ++ ++ /*(3) reset digital filter(DF_RESET=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH); ++ /* (4) enable pcap clk(CDC_CLK_EN=1),enable CODEC(CDC_EN=1) */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ mdelay(1); /* specified enable time */ ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX); ++} ++ ++ ++void close_output_pcap_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap headset. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++} ++ ++ ++void close_output_pcap_louderspeaker(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap louderspeaker. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++} ++ ++ ++void close_output_pcap_earpiece(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap earpiece. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); ++} ++ ++ ++void close_output_pcap_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap carkit. \n"); ++#endif ++ e680_boomer_path_mono_lineout(); ++ EIHF_Mute(EIHF_MUTE); //Mute EIHF ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ++ Set_EMU_Mux_Switch(DEFAULT_USB_MODE); ++} ++ ++ ++void close_output_pcap_headjack(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap headjack. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++} ++ ++ ++void close_output_pcap_bluetooth(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap bluetooth. \n"); ++#endif ++ ++} ++ ++ ++void close_output_pcap_louderspeaker_mixed(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output pcap louderspeaker mixed. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++} ++ ++ ++void close_output_ma3_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 headset. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_ma3_louderspeaker(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 louderspeaker. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_ma3_earpiece(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 earpiece. \n"); ++#endif ++ ++} ++ ++ ++void close_output_ma3_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 carkit. \n"); ++#endif ++ ++} ++ ++ ++void close_output_ma3_headjack(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 headjack. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_ma3_bluetooth(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 bluetooth. \n"); ++#endif ++ ++} ++ ++ ++void close_output_ma3_louderspeaker_mixed(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output ma3 louderspeaker mixed. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_fm_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm headset. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_fm_louderspeaker(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm louderspeaker. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_fm_earpiece(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm earpiece. \n"); ++#endif ++ ++} ++ ++ ++void close_output_fm_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm carkit. \n"); ++#endif ++ ++} ++ ++ ++void close_output_fm_headjack(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm headjack. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_fm_bluetooth(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm bluetooth. \n"); ++#endif ++ ++} ++ ++ ++void close_output_fm_louderspeaker_mixed(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output fm louderspeaker mixed. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_mixed_headset(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed headset. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_mixed_louderspeaker(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed louderspeaker. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_mixed_earpiece(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed earpiece. \n"); ++#endif ++ ++} ++ ++ ++void close_output_mixed_carkit(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed carkit. \n"); ++#endif ++ ++} ++ ++ ++void close_output_mixed_headjack(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed headjack. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++void close_output_mixed_bluetooth(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed bluetooth. \n"); ++#endif ++ ++} ++ ++ ++void close_output_mixed_louderspeaker_mixed(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "close output mixed louderspeaker mixed. \n"); ++#endif ++ ++ e680_boomer_path_mono_lineout(); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++} ++ ++ ++int open_output_pcap_headset(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap headset. \n"); ++#endif ++ ++ /* set pcap output path register AR_EN=1, AL_EN=1 */ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ set_boomer_mode_control_reg(); ++ ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_louderspeaker(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap louderspeaker. \n"); ++#endif ++ ++ /* set pcap output path register AR_EN=1, AL_EN=1 */ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ set_boomer_mode_control_reg(); ++ ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_earpiece(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap earpiece. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_MONO_OUT_MONO_LINEOUT; ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN); ++ set_boomer_mode_control_reg(); ++ ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_carkit(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap carkit. \n"); ++#endif ++ ++ Set_EMU_Mux_Switch(MONO_AUDIO_MODE); ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path=BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ++ set_boomer_mode_control_reg(); ++ ++ set_output_gain_hw_reg(); ++ ++ EIHF_Mute(EIHF_UNMUTE); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_headjack(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap headjack. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ set_boomer_mode_control_reg(); ++ ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_pcap_bluetooth(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap bluetooth. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_pcap_louderspeaker_mixed(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output pcap louderspeaker mixed. \n"); ++#endif ++ ++ /* set pcap output path register AR_EN=1, AL_EN=1 */ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ set_boomer_mode_control_reg(); ++ ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_ma3_headset(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 headset. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_ma3_louderspeaker(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 louderspeaker. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_ma3_earpiece(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 earpiece. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_ma3_carkit(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 carkit. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_ma3_headjack(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 headjack. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_ma3_bluetooth(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 bluetooth. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_ma3_louderspeaker_mixed(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output ma3 louderspeaker mixed. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_fm_headset(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm headset. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_fm_louderspeaker(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm louderspeaker. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_fm_earpiece(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm earpiece. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_fm_carkit(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm carkit. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_fm_headjack(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm headjack. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_fm_bluetooth(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm bluetooth. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_fm_louderspeaker_mixed(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output fm louderspeaker mixed. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_mixed_headset(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed headset. \n"); ++#endif ++ ++ /* set pcap output path register AR_EN=1, AL_EN=1 */ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_mixed_louderspeaker(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed louderspeaker. \n"); ++#endif ++ ++ /* set pcap output path register AR_EN=1, AL_EN=1 */ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_mixed_earpiece(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed earpiece. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_mixed_carkit(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed carkit. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_mixed_headjack(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed headjack. \n"); ++#endif ++ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL_6DB); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_STEREO_OUT_HEADPHONE; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++int open_output_mixed_bluetooth(long val) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed bluetooth. \n"); ++#endif ++ ++ return 0; ++} ++ ++ ++int open_output_mixed_louderspeaker_mixed(long val) ++{ ++ int ret; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open output mixed louderspeaker mixed. \n"); ++#endif ++ ++ /* set pcap output path register AR_EN=1, AL_EN=1 */ ++ if(MIXERISSTEREO) ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_R_L_STEREO); ++ else ++ SSP_PCAP_MONO_set(PCAP_MONO_PGA_RL); ++ e680boomer.path = BOOMER_IN_MONO_AND_STEREO_OUT_LOUDER_SPEAKER; ++ ++ codec_output_path = GET_OUTPUT_PATH(val); ++ codec_output_base = GET_OUTPUT_BASE(val); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN); ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); ++ ++ set_boomer_mode_control_reg(); ++ set_output_gain_hw_reg(); ++ ++ return ret; ++} ++ ++ ++void kernel_set_oscc_13m_clock(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "midi set oscc 13m clock \n" ); ++#endif ++ ++ if( DSPUSE13MCLK == 0 ) ++ OSCC |= 0x00000008; ++} ++ ++ ++void kernel_clr_oscc_13m_clock(void) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "midi clr oscc 13m clock \n"); ++#endif ++ ++ if( (DSPUSE13MCLK == 0 ) && (DSP16USE13MCLK == 0) ) /* for app will close midi after dsp16 opened under some cases */ ++ OSCC &= ~0x00000008; ++} ++ ++ ++void pcap_use_ap_13m_clock(void) ++{ ++ if( MIDIUSE13MCLK == 0 ) ++ OSCC |= 0x00000008; ++ set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_ALT_FN_3_OUT); ++ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); ++} ++ ++ ++void pcap_use_bp_13m_clock(void) ++{ ++ if( MIDIUSE13MCLK == 0 ) ++ OSCC &= ~0x00000008; ++ set_GPIO_mode(AP_13MHZ_OUTPUT_PIN | GPIO_IN); ++ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL); ++} ++ ++ ++#ifdef CONFIG_PM ++int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req){ ++ case PM_SUSPEND: ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " E680 boomer path = 0X%X before AP sleep. \n", e680boomer.path); ++#endif ++ if( (audioonflag & (PHONE_DEVICE|FM_DEVICE)) == 0 ){ ++ e680_boomer_path_tmp_shutdown(); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); ++ } ++ break; ++ case PM_RESUME: ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " E680 after AP sleep.\n"); ++#endif ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR); ++ set_output_gain_hw_reg(); ++ if( gpio_flt_sel_status ) ++ Clear_Haptics_GPIO(); ++ else ++ Set_Haptics_GPIO(); ++ if(audioonflag) ++ (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path); ++ e680_boomer_path_restore(); ++ break; ++ } ++ return 0; ++} ++#endif ++ ++ ++void mute_output_to_avoid_pcap_noise(void) ++{ ++ e680_boomer_path_tmp_mono_lineout(); ++} ++ ++ ++void undo_mute_output_to_avoid_pcap_noise(void) ++{ ++ e680_boomer_path_restore(); ++} ++ ++ ++void Set_Haptics_GPIO(void) ++{ ++ e680_boomer_path_tmp_mono_lineout(); ++ ++ set_GPIO_mode(GPIO_FLT_SEL_BUL | GPIO_OUT); ++ clr_GPIO(GPIO_FLT_SEL_BUL); ++ PGSR(GPIO_FLT_SEL_BUL) &= ~GPIO_bit(GPIO_FLT_SEL_BUL); ++ gpio_flt_sel_status = 0; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " set haptics GPIO \n"); ++#endif ++ ++ e680_boomer_path_restore(); ++} ++ ++ ++void Clear_Haptics_GPIO(void) ++{ ++ e680_boomer_path_tmp_mono_lineout(); ++ ++ set_GPIO_mode(GPIO_FLT_SEL_BUL | GPIO_OUT); ++ set_GPIO(GPIO_FLT_SEL_BUL); ++ PGSR(GPIO_FLT_SEL_BUL) |= GPIO_bit(GPIO_FLT_SEL_BUL); ++ gpio_flt_sel_status = 1; ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG " clear haptics GPIO \n"); ++#endif ++ ++ e680_boomer_path_restore(); ++} ++ ++ ++#endif /* CONFIG_ARCH_EZX_E680 */ ++ ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-e680.h linux-2.6.16/sound/oss/ezx-e680.h +--- linux-2.6.16.orig/sound/oss/ezx-e680.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-e680.h 2006-06-03 11:14:56.799254456 +0200 +@@ -0,0 +1,183 @@ ++/* ++ * linux/drivers/sound/ezx-e680.h ++ * ++ * ++ * Description: header file for ezx-e680.c ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * Jin Lihong(w20076) Jan 12,2004,LIBdd68327 Created,Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 close dsp protection,and add 3d control interface for app ++ * Jin Lihong(w20076) Apr.24,2004,LIBee03164 reduce music noise, add new pathes for haptics ++ * Jin Lihong(w20076) Jun.15,2004,LIBee21625 boomer's power management ++ * Jin Lihong(w20076) Jun.22,2004,LIBee24284 mixer power save ++ * Wu Hongxing(w20691)Jul.07,2004 LIBee29664 ap 13m clock usage. ++ * ++ */ ++ ++#ifndef EZX_E680_H ++#define EZX_E680_H ++ ++#include <linux/config.h> ++#include <linux/pm.h> ++ ++#ifdef CONFIG_PXA_EZX_E680 ++ ++//#define EZX_OSS_DEBUG /* debug switch for all ezx oss src files excluding ezx-audio.c */ ++#undef EZX_OSS_DEBUG ++//#define EZX_OSS_AUDIO_DEBUG /* debug switch for src file ezx-audio.c */ ++#undef EZX_OSS_AUDIO_DEBUG ++ ++/* ++#ifdef EZX_OSS_DBG ++#define OSSPRINTF(fmt,args...) printf(fmt,##args) ++#else ++#define OSSPRINTF(fmt,args...) { } ++#endif ++*/ ++ ++ ++#define MIXERISSTEREO ( audioonflag & (DSP_DEVICE|MIDI_DEVICE|FM_DEVICE) ) ++#define MIDIUSE13MCLK ( audioonflag & MIDI_DEVICE ) ++#define DSPUSE13MCLK ( audioonflag & DSP_DEVICE ) ++#define DSP16USE13MCLK ( audioonflag & DSP16_DEVICE ) ++ ++ ++typedef enum{ ++ PHONE_DEVICE = 0x01, ++ DSP_DEVICE = 0x02, ++ DSP16_DEVICE = 0x04, ++ AUDIO_DEVICE = 0x08, ++ MIDI_DEVICE = 0x10, ++ FM_DEVICE = 0x20 ++}audio_dev_type; ++ ++typedef enum{ ++ LOUDERSPEAKER_ON_HEADSET_ON_3D, ++ LOUDERSPEAKER_ON_HEADSET_OFF_3D, ++ LOUDERSPEAKER_OFF_HEADSET_ON_3D, ++ LOUDERSPEAKER_OFF_HEADSET_OFF_3D ++}boomer_3d_status; ++ ++ ++void e680_boomer_init(void); ++void e680_boomer_shutdown(void); ++void e680_boomer_path_mono_lineout(void); ++void e680_boomer_path_tmp_mono_lineout(void); ++void e680_boomer_path_tmp_shutdown(void); ++void e680_boomer_path_restore(void); ++ ++void poweron_mixer( audio_dev_type type ); ++void shutdown_mixer( audio_dev_type type ); ++void mixer_not_in_use(void); ++ ++void set_output_gain_hw_reg(void); ++void set_input_gain_hw_reg(void); ++ ++void set_boomer_3d_status(boomer_3d_status status); ++boomer_3d_status get_boomer_3d_status(void); ++ ++void set_gpio_va_sel_out_high(void); ++void set_gpio_va_sel_out_low(void); ++ ++void close_input_carkit(void); ++void close_input_handset(void); ++void close_input_headset(void); ++void close_input_funlight(void); ++ ++void open_input_carkit(void); ++void open_input_handset(void); ++void open_input_headset(void); ++void open_input_funlight(void); ++ ++void close_output_pcap_headset(void); ++void close_output_pcap_louderspeaker(void); ++void close_output_pcap_earpiece(void); ++void close_output_pcap_carkit(void); ++void close_output_pcap_headjack(void); ++void close_output_pcap_bluetooth(void); ++void close_output_pcap_louderspeaker_mixed(void); ++ ++void close_output_ma3_headset(void); ++void close_output_ma3_louderspeaker(void); ++void close_output_ma3_earpiece(void); ++void close_output_ma3_carkit(void); ++void close_output_ma3_headjack(void); ++void close_output_ma3_bluetooth(void); ++void close_output_ma3_louderspeaker_mixed(void); ++ ++void close_output_fm_headset(void); ++void close_output_fm_louderspeaker(void); ++void close_output_fm_earpiece(void); ++void close_output_fm_carkit(void); ++void close_output_fm_headjack(void); ++void close_output_fm_bluetooth(void); ++void close_output_fm_louderspeaker_mixed(void); ++ ++void close_output_mixed_headset(void); ++void close_output_mixed_louderspeaker(void); ++void close_output_mixed_earpiece(void); ++void close_output_mixed_carkit(void); ++void close_output_mixed_headjack(void); ++void close_output_mixed_bluetooth(void); ++void close_output_mixed_louderspeaker_mixed(void); ++ ++int open_output_pcap_headset(long val); ++int open_output_pcap_louderspeaker(long val); ++int open_output_pcap_earpiece(long val); ++int open_output_pcap_carkit(long val); ++int open_output_pcap_headjack(long val); ++int open_output_pcap_bluetooth(long val); ++int open_output_pcap_louderspeaker_mixed(long val); ++ ++int open_output_ma3_headset(long val); ++int open_output_ma3_louderspeaker(long val); ++int open_output_ma3_earpiece(long val); ++int open_output_ma3_carkit(long val); ++int open_output_ma3_headjack(long val); ++int open_output_ma3_bluetooth(long val); ++int open_output_ma3_louderspeaker_mixed(long val); ++ ++int open_output_fm_headset(long val); ++int open_output_fm_louderspeaker(long val); ++int open_output_fm_earpiece(long val); ++int open_output_fm_carkit(long val); ++int open_output_fm_headjack(long val); ++int open_output_fm_bluetooth(long val); ++int open_output_fm_louderspeaker_mixed(long val); ++ ++int open_output_mixed_headset(long val); ++int open_output_mixed_louderspeaker(long val); ++int open_output_mixed_earpiece(long val); ++int open_output_mixed_carkit(long val); ++int open_output_mixed_headjack(long val); ++int open_output_mixed_bluetooth(long val); ++int open_output_mixed_louderspeaker_mixed(long val); ++ ++void kernel_set_oscc_13m_clock(void); ++void kernel_clr_oscc_13m_clock(void); ++void pcap_use_ap_13m_clock(void); ++void pcap_use_bp_13m_clock(void); ++ ++int mixer_hw_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data); ++void mute_output_to_avoid_pcap_noise(void); ++void undo_mute_output_to_avoid_pcap_noise(void); ++ ++void Set_Haptics_GPIO(void); ++void Clear_Haptics_GPIO(void); ++ ++ ++#endif /* CONFIG_ARCH_EZX_E680 */ ++ ++ ++#endif ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-nssp.c linux-2.6.16/sound/oss/ezx-nssp.c +--- linux-2.6.16.orig/sound/oss/ezx-nssp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-nssp.c 2006-06-03 11:14:56.800254304 +0200 +@@ -0,0 +1,358 @@ ++/* ++ * linux/drivers/sound/ezx-nssp.c ++ * ++ * ++ * Description: nssp interface for the ezx platform ++ * ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * zhouqiong, Motorola Jun 20,2002 created ++ * zhouqiong, Motorola Sep 19,2002 according code review meeting minutes. ++ * zhouqiong, Motorola Oct 30,2002 according new requirement for VA. ++ * zhouqiong, Motorola Nov 05,2002 according code review meeting minutes. ++ * zhouqiong, Motorola Mar 04,2003 (1) don't close headset interrupt; ++ * (2) when headset in, output gain decrease 6db ++ * LiYong, Motorola Sep 23,2003 (1)Port from EZX; (2)Modify the NSSP port inital ++ * Jin Lihong(w20076), Motorola Jan 02,2004 (1) Port from UDC e680 kernel of jem vob. ++ * (2) Move audio driver DEBUG macro definition to ezx-audio.h ++ * header file,and redefine DEBUG to EZX_OSS_DEBUG ++ * (3) reorganize file header ++ * Jin Lihong(w20076),Motorola Feb.23,2004,LIBdd79747 add e680 audio path switch and gain setting funcs ++ * Jin Lihong(w20076),Motorola Mar.15,2004,LIBdd86574 mixer bug fix ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/poll.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-audio.h" ++#include "ezx-common.h" ++ ++ ++static DECLARE_MUTEX(cotulla_nssp_mutex); ++ ++static int nssp_init(void); ++static void nssp_shutdown(void); ++ ++ ++/*initialize hardware, nssp controller and pcap register*/ ++static int nssp_init(void) ++{ ++ unsigned long flags; ++ unsigned long ssp_pcap_register_val; ++ unsigned int ssp_pcap_bit_status; ++ volatile unsigned long audiostatus; ++ unsigned long timeout; ++ ++ down(&cotulla_nssp_mutex); ++ ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++ if( MONODEVOPENED == 0 ) ++ pcap_use_ap_13m_clock(); ++ audioonflag |= AUDIO_DEVICE; ++ ++#ifdef EZX_OSS_DEBUG ++ printk("setup nssp controller register \n"); ++#endif ++ local_irq_save(flags); ++ CKEN |= CKEN3_NSSP; /* need enable cken3 */ ++ ++ set_GPIO_mode(GPIO_BITCLK_IN_NSSP_MD); /* BitCLK */ ++ set_GPIO_mode(GPIO_SYNC_IN_NSSP_MD); /* FS */ ++ /*At E680,the NSSP TX and RX pins are single direction */ ++// set_GPIO_mode(GPIO_SDATA_OUT_NSSP_MD); /* TXD ssp2 ALF out 2 */ ++ set_GPIO_mode(GPIO_SDATA_IN_NSSP_MD); /* RXD ssp2 ALF in 1*/ ++ /* setup nssp port */ ++ NSSCR0 = NSSCR0_FRF_PSP | NSSCR0_DSS_16bit; /* PSP mode, 16bit */ ++ NSSCR1 = NSSCR1_TTE | NSSCR1_EBCEI | NSSCR1_SCLKDIR | NSSCR1_SFRMDIR | NSSCR1_TFTH_4 | NSSCR1_RFTH_14; ++ NSSPSP = NSSPSP_SFRMWDTH_1 | NSSPSP_STRTDLY_1 | NSSPSP_SFRMP_HIGH | NSSPSP_SCMODE; ++ NSSCR1 |= NSSCR1_TSRE | NSSCR1_RSRE; /* enable dma request */ ++ NSSCR0 |= NSSCR0_SSE; /* enable nssp controller */ ++ local_irq_restore(flags); ++ ++#ifdef EZX_OSS_DEBUG ++ audiostatus = NSSCR0; ++ printk("NSSCR0 = 0x%lx\n", audiostatus); ++ audiostatus = NSSCR1; ++ printk("NSSCR1 = 0x%lx\n", audiostatus); ++ audiostatus = NSSPSP; ++ printk("NSSPSP = 0x%lx\n", audiostatus); ++#endif ++ ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(0x0d,&ssp_pcap_register_val); ++ printk("pcap register 13 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0c,&ssp_pcap_register_val); ++ printk("pcap register 12 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0b,&ssp_pcap_register_val); ++ printk("pcap register 11 = 0x%lx\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x1a,&ssp_pcap_register_val); ++ printk("pcap register 26 = 0x%lx\n", ssp_pcap_register_val); ++#endif ++ ++ timeout = 0; ++ /* check if ssp is ready for slave operation */ ++ while(((audiostatus = NSSSR) & NSSSR_CSS) !=0){ ++ if((timeout++) > 10000000) ++ goto err; ++ } ++#ifdef EZX_OSS_DEBUG ++ printk(" complete all hardware init \n"); ++#endif ++ up(&cotulla_nssp_mutex); ++ return 0; ++ ++err: ++ up(&cotulla_nssp_mutex); ++ printk("audio panic: ssp don't ready for slave operation!!! "); ++ return -ENODEV; ++} ++ ++ ++static void nssp_shutdown(void) ++{ ++ down(&cotulla_nssp_mutex); ++ ++ audioonflag &= ~AUDIO_DEVICE; ++ if( MONODEVOPENED == 0 ) ++ pcap_use_bp_13m_clock(); ++ ++#ifdef EZX_OSS_DEBUG ++ printk("close nssp port\n"); ++#endif ++ NSSCR0 = 0; ++ NSSCR1 = 0; ++ NSSPSP = 0; ++ CKEN &= ~CKEN3_NSSP; /* SSP2 need control the CKEN3 */ ++ ++ set_GPIO_mode(GPIO_NSSP_SCLK2 | GPIO_IN); /* BitCLK */ ++ set_GPIO_mode(GPIO_NSSP_SFRM2 | GPIO_IN); /* FS */ ++ set_GPIO_mode(GPIO_NSSP_TXD2 | GPIO_IN); ++ set_GPIO_mode(GPIO_NSSP_RXD2 | GPIO_IN); ++ ++#ifdef EZX_OSS_DEBUG ++ printk("close pcap register\n"); ++#endif ++ ++ up(&cotulla_nssp_mutex); ++} ++ ++ ++/* ++ * nssp codec ioctls ++ */ ++static int codec_adc_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ ++static int codec_dac_rate = PHONE_CODEC_DEFAULT_RATE; /* default 8k sample rate */ ++ ++static int nssp_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val; ++ int audiostatus, timeout; ++ ++ switch(cmd) { ++ case SNDCTL_DSP_STEREO: ++#ifdef EZX_OSS_DEBUG ++ printk(" check if support stereo\n"); ++#endif ++ ret = get_user(val, (int *) arg); ++ if (ret) ++ return ret; ++ if(val) /* not support stereo mode */ ++ ret = -EINVAL; ++ else ++ ret = 1; ++ return put_user(ret, (int *) arg); ++ ++ case SNDCTL_DSP_CHANNELS: ++ case SOUND_PCM_READ_CHANNELS: ++#ifdef EZX_OSS_DEBUG ++ printk(" check if 2 channels \n"); ++#endif ++ return put_user(1, (long *) arg); ++ ++ case SNDCTL_DSP_SPEED: ++#ifdef EZX_OSS_DEBUG ++ printk(" set sample frequency \n"); ++#endif ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ down(&cotulla_nssp_mutex); ++ NSSCR0 &= ~NSSCR0_SSE; ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ switch(val) ++ { ++ case PHONE_CODEC_16K_RATE: /*16K sample rate */ ++ ret = SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); ++ codec_adc_rate = val; ++ codec_dac_rate = val; ++ break; ++ case PHONE_CODEC_DEFAULT_RATE: /*8K sample rate */ ++ ret = SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K); ++ codec_adc_rate = val; ++ codec_dac_rate = val; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ /* reset digital filter(DF_RESET=1) */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ ++ NSSCR0 |= NSSCR0_SSE; /* enable nssp controller */ ++ timeout = 0; ++ /* check if ssp is ready for slave operation */ ++ while(((audiostatus = NSSSR) & NSSSR_CSS) !=0) ++ { ++ if((timeout++) > 10000000) ++ { ++ printk("audio panic: can't be slave mode!!!"); ++ ret =-ENODEV; ++ break; ++ } ++ } ++ up(&cotulla_nssp_mutex); ++#ifdef EZX_OSS_DEBUG ++ printk("AD sample freq = %d\n", codec_adc_rate); ++ printk("DA sample freq = %d\n", codec_dac_rate); ++#endif ++ return put_user(codec_adc_rate, (long *) arg); ++ ++ case SOUND_PCM_READ_RATE: ++ if (file->f_mode & FMODE_WRITE) ++ { ++#ifdef EZX_OSS_DEBUG ++ printk("read DA sample freq\n"); ++#endif ++ val = codec_dac_rate; ++ } ++ if (file->f_mode & FMODE_READ) ++ { ++#ifdef EZX_OSS_DEBUG ++ printk("read AD sample freq\n"); ++#endif ++ val = codec_adc_rate; ++ } ++ return put_user(val, (long *) arg); ++ ++ case SNDCTL_DSP_SETFMT: ++ case SNDCTL_DSP_GETFMTS: ++ /* SUPPORT little endian signed 16 */ ++#ifdef EZX_OSS_DEBUG ++ printk("data format is AFMT_S16_LEd\n"); ++#endif ++ return put_user(AFMT_S16_LE, (long *) arg); ++ ++ default: ++ return mixer_ioctl(inode, file, cmd, arg); ++ } ++ return 0; ++} ++ ++ ++/* ++ * Audio stuff ++ */ ++ ++static audio_stream_t nssp_audio_out = { ++ name: "nssp audio out", ++ dcmd: DCMD_TXNSSDR, ++ drcmr: &DRCMRTXNSSDR, /* nssp dma map register */ ++ dev_addr: __PREG(NSSDR), ++}; ++ ++static audio_stream_t nssp_audio_in = { ++ name: "nssp audio in", ++ dcmd: DCMD_RXNSSDR, ++ drcmr: &DRCMRRXNSSDR, /* nssp dma map register */ ++ dev_addr: __PREG(NSSDR), ++}; ++ ++static audio_state_t nssp_audio_state = { ++ output_stream: &nssp_audio_out, ++ input_stream: &nssp_audio_in, ++ client_ioctl: nssp_ioctl, ++ hw_init: nssp_init, ++ hw_shutdown: nssp_shutdown, ++ sem: __MUTEX_INITIALIZER(nssp_audio_state.sem), ++}; ++ ++ ++static int nssp_audio_open(struct inode *inode, struct file *file) ++{ ++#ifdef EZX_OSS_DEBUG ++ printk("nssp audio open \n"); ++#endif ++ return cotulla_audio_attach(inode, file, &nssp_audio_state); ++} ++ ++ ++/* ++ * Missing fields of this structure will be patched with the call ++ * to cotulla_audio_attach(). ++ */ ++ ++ ++static struct file_operations nssp_audio_fops = { ++ open: nssp_audio_open, ++ owner: THIS_MODULE ++}; ++ ++ ++static int __init cotulla_nssp_init(void) ++{ ++ nssp_audio_state.dev_dsp = register_sound_audio(&nssp_audio_fops, -1); ++ ++ set_GPIO_mode(GPIO_NSSP_SCLK2 | GPIO_IN); /* BitCLK */ ++ set_GPIO_mode(GPIO_NSSP_SFRM2 | GPIO_IN); /* FS */ ++ set_GPIO_mode(GPIO_NSSP_TXD2 | GPIO_IN); ++ set_GPIO_mode(GPIO_NSSP_RXD2 | GPIO_IN); /* RXD ssp2 ALF in 1*/ ++ ++#ifdef EZX_OSS_DEBUG ++ printk("cotulla-nssp-init ok\n"); ++#endif ++ return 0; ++} ++ ++ ++static void __exit cotulla_nssp_exit(void) ++{ ++ unregister_sound_audio(nssp_audio_state.dev_dsp); ++#ifdef EZX_OSS_DEBUG ++ printk("cotulla-nssp-exit ok\n"); ++#endif ++} ++ ++ ++module_init(cotulla_nssp_init); ++module_exit(cotulla_nssp_exit); ++ ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-phone.c linux-2.6.16/sound/oss/ezx-phone.c +--- linux-2.6.16.orig/sound/oss/ezx-phone.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-phone.c 2006-06-03 11:14:56.801254152 +0200 +@@ -0,0 +1,280 @@ ++/* ++ * linux/drivers/sound/ezx-phone ++ * ++ * ++ * Description: phone interface for EZX. for application can't direct call interface in kernel space from ++ * user space.so phone controll realize a char device. ++ * ++ * ++ * copyright: Motorola ++ * ++ * 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. ++ * ++ * ++ * History: ++ * zhouqiong Aug 02,2002 created ++ * zhouqiong Mar 03,2003 (1) don't close headset interrupt; ++ * (2) move bluetooth to phone device ioctl ++ * LiYong Sep 23,2003 Port from EZX ++ * Jin Lihong(w20076) Jan 02,2004,LIBdd66088 (1) Port from UDC e680 kernel of jem vob. ++ * (2) Move audio driver DEBUG macro definition to ezx-audio.h ++ * header file,and redefine DEBUG to EZX_OSS_DEBUG ++ * (3) reorganize file header ++ * Jin Lihong(w20076) Jan 13,2004,LIBdd68327 Make the e680 louder speaker work. ++ * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 mixer bug fix ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90336 play music noise tmp solution ++ * Jin Lihong(w20076) Mar.25,2004,LIBdd90846 a780 new gain setting interface ++ * Jin Lihong(w20076) Apr.20,2004,LIBee01165 va of a phone call for e680 ++ * Jin Lihong(w20076) Apr.24,2004,LIBee03164 a780 bitclock restore to normal because pcap2 upgraded ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/fs.h> ++#include <linux/major.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "ezx-common.h" ++ ++ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++#endif ++ ++static DECLARE_MUTEX(phone_mutex); ++ ++#ifdef CONFIG_PM ++#ifdef CONFIG_ARCH_EZX_E680 ++extern u32 gpio_va_sel_status; ++#endif ++ ++ ++static int phone_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ break; ++ case PM_RESUME: ++#ifdef CONFIG_ARCH_EZX_E680 ++ set_GPIO_mode(GPIO_VA_SEL_BUL | GPIO_OUT); ++ if(gpio_va_sel_status) ++ { ++ set_GPIO(GPIO_VA_SEL_BUL); ++ } ++ else ++ { ++ clr_GPIO(GPIO_VA_SEL_BUL); ++ } ++#endif ++ break; ++ } ++ return 0; ++} ++#endif ++ ++ ++void bluetoothaudio_open(void) ++{} ++void bluetoothaudio_close(void) ++{} ++ ++static int phone_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned long ssp_pcap_register_val; ++ ++ switch(cmd) { ++ case BLUETOOTH_AUDIO_ON: ++#ifdef EZX_OSS_DEBUG ++ printk("bluetooth audio on\n"); ++#endif ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, &ssp_pcap_register_val); ++ printk("AUD_CODEC=0x%x\n", ssp_pcap_register_val); ++#endif ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); ++ (*mixer_close_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(); ++ break; ++ ++ case BLUETOOTH_AUDIO_OFF: ++#ifdef EZX_OSS_DEBUG ++ printk("bluetooth audio off\n"); ++#endif ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER, &ssp_pcap_register_val); ++ printk("AUD_CODEC=0x%x\n", ssp_pcap_register_val); ++#endif ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN); ++ (*mixer_open_output_path[OUTPUT_BASE_TYPE(codec_output_base)][codec_output_path])(codec_output_base|codec_output_path ); ++ break; ++ ++ default: ++ return mixer_ioctl(inode, file, cmd, arg); ++ } ++ return 0; ++} ++ ++ ++/* ++ * there is a supposition: ++ * when run phone_open, other audio device is stopped, pcap is free ++ */ ++static int count = 0; ++static int phone_open(struct inode *inode, struct file *file) ++{ ++ unsigned int ssp_pcap_register_val; ++ ++/* ++#ifdef CONFIG_ARCH_EZX_E680 ++ if( audioonflag & FM_DEVICE ){ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "E680 open phone EBUSY because 0x%X device is using the sound hardware.\n",audioonflag ); ++#endif ++ return -EBUSY; ++ } ++#endif ++*/ ++ ++ if(!count){ ++ count ++; ++ ++ down(&phone_mutex); ++ ++ mute_output_to_avoid_pcap_noise(); ++ audioonflag |= PHONE_DEVICE; ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++ pcap_use_bp_13m_clock(); ++ ++ ++#ifdef EZX_OSS_DEBUG ++ printk(EZXOSS_DEBUG "open phone device, init pcap register\n"); ++#endif ++ set_pcap_telephone_codec(0); ++ set_pcap_output_path(); ++ set_pcap_input_path(); ++ ++ undo_mute_output_to_avoid_pcap_noise(); ++ ++#ifdef EZX_OSS_DEBUG ++ SSP_PCAP_read_data_from_PCAP(0x0b, &ssp_pcap_register_val); ++ printk("reg 11=0x%x\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0d, &ssp_pcap_register_val); ++ printk("reg 13=0x%x\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x0c, &ssp_pcap_register_val); ++ printk("reg 12=0x%x\n", ssp_pcap_register_val); ++ SSP_PCAP_read_data_from_PCAP(0x1a, &ssp_pcap_register_val); ++ printk("reg 26=0x%x\n", ssp_pcap_register_val); ++#endif ++ up(&phone_mutex); ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ set_gpio_va_sel_out_low(); ++#endif ++ ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, phone_pm_callback); ++#endif ++ return 0; ++ } ++ else ++ return -EBUSY; ++} ++ ++ ++static int phone_release(struct inode *inode, struct file *file) ++{ ++ count --; ++ if(!count){ ++ down(&phone_mutex); ++ ++ mute_output_to_avoid_pcap_noise(); ++ ++ /* close pcap input path */ ++ if(micinflag) ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2); ++ else ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER, 0); ++ /* close pcap output path */ ++ SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER,SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL); ++ /* disable PCAP mono codec */ ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN); ++ SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN); ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB); ++ ++ /* set fsync, tx, bitclk are tri-stated */ ++ SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS); ++ ++ up(&phone_mutex); ++ ++#ifdef CONFIG_ARCH_EZX_E680 ++ set_gpio_va_sel_out_high(); ++ e680_boomer_path_mono_lineout(); /* mute hw noise and save power for e680 */ ++#endif ++ ++ pcap_use_bp_13m_clock(); ++ audioonflag &= ~PHONE_DEVICE; ++ ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++ } ++ ++ return 0; ++} ++ ++ ++static struct file_operations device_fops = { ++ owner: THIS_MODULE, ++ open: phone_open, ++ release: phone_release, ++ ioctl: phone_ioctl, ++}; ++ ++static int __init phone_init(void) ++{ ++ int ret; ++ ret = register_chrdev(MYPHONE_MAJOR,"phone", &device_fops); ++ if(ret) ++ { ++ printk("can't register phone device with kernel"); ++ } ++#ifdef EZX_OSS_DEBUG ++ printk("register phone device with kernel ok \n"); ++#endif ++ return 0; ++} ++ ++static void __exit phone_exit(void) ++{ ++ unregister_chrdev(MYPHONE_MAJOR, "phone"); ++#ifdef EZX_OSS_DEBUG ++ printk("unregister phone device \n"); ++#endif ++} ++ ++ ++module_init(phone_init); ++module_exit(phone_exit); ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-vibrator.c linux-2.6.16/sound/oss/ezx-vibrator.c +--- linux-2.6.16.orig/sound/oss/ezx-vibrator.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-vibrator.c 2006-06-03 11:14:56.801254152 +0200 +@@ -0,0 +1,245 @@ ++/* ++ * linux/drivers/sound/vibrator.c ++ * ++ * ++ * Description: vibrator interface for EZX. for application can't direct call interface in kernel space from ++ * user space.so vibrator still realize a char device. ++ * ++ * ++ * (c) Copyright Motorola 2003, All rights reserved. ++ * ++ * ++ * History: ++ * zhouqiong Jun 20,2002 created ++ * Kin Wong Nov 05,2003 Renamed ezx-vibrator.h to vibrator.h ++ * Jin Lihong(w20076) Jan 02,2004 (1) Port from UDC e680 kernel of jem vob. ++ * (2) Move audio driver DEBUG macro definition to ezx-audio.h ++ * header file,and redefine DEBUG to EZX_OSS_DEBUG ++ * (3) reorganize file header ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 reorganise file header ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/fs.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "../misc/ssp_pcap.h" ++#include "ezx-vibrator.h" ++ ++ ++#ifdef CONFIG_PM ++static struct pm_dev *pm_dev; ++#endif ++ ++static int active=0; ++static int voltage=0; ++ ++static int vibrator_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val; ++ ++ switch(cmd) ++ { ++ case VIBRATOR_ENABLE: ++#ifdef EZX_OSS_DEBUG ++ printk("enable vibrator \n"); ++#endif ++ ret = get_user(val, (int *) arg); ++ if (ret) ++ return ret; ++ switch(val) ++ { ++ case 0: ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator level 0 \n"); ++#endif ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); ++ active = 1; ++ voltage = 0; ++ SSP_vibrate_start_command(); ++ break; ++ case 1: ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator level 1 \n"); ++#endif ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); ++ active = 1; ++ voltage = 1; ++ SSP_vibrate_start_command(); ++ break; ++ case 2: ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator level 2 \n"); ++#endif ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); ++ active = 1; ++ voltage = 2; ++ SSP_vibrate_start_command(); ++ break; ++ case 3: ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator level 3 \n"); ++#endif ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ ret = SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ active = 1; ++ voltage = 3; ++ SSP_vibrate_start_command(); ++ break; ++ default: ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator level error \n"); ++#endif ++ return -EINVAL; ++ } ++ return put_user(ret, (int *) arg); ++ ++ case VIBRATOR_DISABLE: ++#ifdef EZX_OSS_DEBUG ++ printk("disable vibrator \n"); ++#endif ++ ret = 0; ++ active = 0; ++ SSP_vibrate_stop_command(); ++ return put_user(ret, (int *) arg); ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int vibrator_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ switch(req) ++ { ++ case PM_SUSPEND: ++ if(active) ++ { ++ SSP_vibrate_stop_command(); ++ } ++ break; ++ case PM_RESUME: ++ if(active) ++ { ++ switch(voltage) ++ { ++ case 0: ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL0); ++ break; ++ case 1: ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL1); ++ break; ++ case 2: ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL2); ++ break; ++ case 3: ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ SSP_PCAP_V_VIB_level_set(PCAP_VIBRATOR_VOLTAGE_LEVEL3); ++ break; ++ default: ++ break; ++ } ++ SSP_vibrate_start_command(); ++ } ++ break; ++ } ++ return 0; ++} ++#endif ++ ++static int count=0; ++static int vibrator_open(struct inode *inode, struct file *file) ++{ ++ if(!count) ++ { ++ count ++; ++ //ssp_pcap_init(); ++ ssp_pcap_open(SSP_PCAP_AUDIO_OPEN); ++#ifdef CONFIG_PM ++ pm_dev = pm_register(PM_SYS_DEV, 0, vibrator_pm_callback); ++#endif ++#ifdef EZX_OSS_DEBUG ++ printk("open vibrator \n"); ++#endif ++ return 0; ++ } ++ else ++ return -EBUSY; ++} ++ ++static int vibrator_release(struct inode *inode, struct file *file) ++{ ++ count --; ++ if(!count) ++ { ++#ifdef CONFIG_PM ++ pm_unregister(pm_dev); ++#endif ++#ifdef EZX_OSS_DEBUG ++ printk("close vibrator \n"); ++#endif ++ } ++ return 0; ++} ++ ++ ++static struct file_operations device_fops = { ++ owner: THIS_MODULE, ++ open: vibrator_open, ++ release: vibrator_release, ++ ioctl: vibrator_ioctl, ++}; ++ ++static int __init vibrator_init(void) ++{ ++ int ret; ++#ifdef EZX_OSS_DEBUG ++ printk("enter vibrator init...\n"); ++#endif ++ ret = register_chrdev(VIBRATOR_MAJOR,"vibrator", &device_fops); ++ if(ret){ ++ printk("can't register vibrator device with kernel"); ++ } ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator init ok\n"); ++#endif ++ return 0; ++} ++ ++static void __exit vibrator_exit(void) ++{ ++ unregister_chrdev(VIBRATOR_MAJOR, "vibrator"); ++#ifdef EZX_OSS_DEBUG ++ printk("vibrator exit ok\n"); ++#endif ++ return; ++} ++ ++ ++module_init(vibrator_init); ++module_exit(vibrator_exit); ++ ++ +diff -Nurd linux-2.6.16.orig/sound/oss/ezx-vibrator.h linux-2.6.16/sound/oss/ezx-vibrator.h +--- linux-2.6.16.orig/sound/oss/ezx-vibrator.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16/sound/oss/ezx-vibrator.h 2006-06-03 11:14:56.802254000 +0200 +@@ -0,0 +1,33 @@ ++/* ++ * linux/drivers/sound/ezx-vibrator.h ++ * ++ * Copyright: BJDC motorola. ++ * ++ * 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. ++ * ++ * ++ * History: ++ * zhouqiong Jun 20,2002 created ++ * Jin Lihong(w20076) Jan 02,2004 (1) Port from UDC e680 kernel of jem vob. ++ * (2) reorganize file header ++ * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 reorganise file header ++ * ++ */ ++ ++#ifndef EZX_VIBRATOR_H ++#define EZX_VIBRATOR_H ++ ++#include <linux/ioctl.h> ++ ++ ++#define VIBRATOR_MAJOR 108 ++#define VIBRATOR_IOCTL_BASE 0xbb ++#define VIBRATOR_ENABLE _IOW (VIBRATOR_IOCTL_BASE,1,int) ++#define VIBRATOR_DISABLE _IO (VIBRATOR_IOCTL_BASE,2) ++ ++ ++#endif ++ ++ +diff -Nurd linux-2.6.16.orig/sound/pci/hda/patch_realtek.c linux-2.6.16/sound/pci/hda/patch_realtek.c +--- linux-2.6.16.orig/sound/pci/hda/patch_realtek.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/sound/pci/hda/patch_realtek.c 2006-06-03 11:14:55.870395664 +0200 +@@ -2948,6 +2948,8 @@ + { .modelname = "basic", .config = ALC260_BASIC }, + { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, + .config = ALC260_BASIC }, /* Sony VAIO */ ++ { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, ++ .config = ALC260_BASIC }, /* CTL Travel Master U553W */ + { .modelname = "hp", .config = ALC260_HP }, + { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, + { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, +diff -Nurd linux-2.6.16.orig/sound/ppc/daca.c linux-2.6.16/sound/ppc/daca.c +--- linux-2.6.16.orig/sound/ppc/daca.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/sound/ppc/daca.c 2006-06-03 11:14:55.871395512 +0200 +@@ -256,7 +256,7 @@ + + #ifdef CONFIG_KMOD + if (current->fs->root) +- request_module("i2c-keywest"); ++ request_module("i2c-powermac"); + #endif /* CONFIG_KMOD */ + + mix = kmalloc(sizeof(*mix), GFP_KERNEL); +diff -Nurd linux-2.6.16.orig/sound/ppc/tumbler.c linux-2.6.16/sound/ppc/tumbler.c +--- linux-2.6.16.orig/sound/ppc/tumbler.c 2006-03-20 06:53:29.000000000 +0100 ++++ linux-2.6.16/sound/ppc/tumbler.c 2006-06-03 11:14:55.872395360 +0200 +@@ -1314,7 +1314,7 @@ + + #ifdef CONFIG_KMOD + if (current->fs->root) +- request_module("i2c-keywest"); ++ request_module("i2c-powermac"); + #endif /* CONFIG_KMOD */ + + mix = kmalloc(sizeof(*mix), GFP_KERNEL); diff --git a/packages/linux/linux-ezx_2.6.16.13.bb b/packages/linux/linux-ezx_2.6.16.13.bb index d80ceb9134..21be475894 100644 --- a/packages/linux/linux-ezx_2.6.16.13.bb +++ b/packages/linux/linux-ezx_2.6.16.13.bb @@ -17,8 +17,7 @@ RPSRC = "http://www.rpsys.net/openzaurus/patches/archive" # source and patches # SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.16.tar.bz2 \ - http://people.openezx.org/stefan/patches/patches-2.6.16-2.6.16.13-exz6-symlink-fix.tar.bz2 \ - file://touchscreen-fix-r0.patch;patch=1 \ + file://ezx6-jumbo.patch;patch=1 \ \ ${RPSRC}/led_core-r15.patch;patch=1 \ ${RPSRC}/led_triggers-r14.patch;patch=1 \ @@ -32,6 +31,7 @@ SRC_URI = "http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.16.tar.bz2 \ ${RPSRC}/led_nand-r3.patch;patch=1 \ \ file://led_ezx-r0.patch;patch=1 \ + file://touchscreen-fix-r0.patch;patch=1 \ \ file://e680-keypad-compile-HACK.patch;patch=1 \ file://e680-disable-boomer-HACK.patch;patch=1 \ @@ -118,4 +118,4 @@ do_deploy() { do_deploy[dirs] = "${S}" addtask deploy before do_package after do_install -addtask ezxpatch before do_patch after do_unpack +#addtask ezxpatch before do_patch after do_unpack |