From 0fff0494048f449e38f7391c0622cedfbd5df7e1 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Fri, 18 Feb 2011 15:25:04 -0800 Subject: linux-2.6.23: remove the linux-2.6.23 recipe The machines supported by this recipe were either recently removed or simply not defined. Signed-off-by: Darren Hart --- .../linux/linux-2.6.23/em-x270/em-x270.patch | 12063 ------------------- 1 file changed, 12063 deletions(-) delete mode 100644 meta/recipes-kernel/linux/linux-2.6.23/em-x270/em-x270.patch (limited to 'meta/recipes-kernel/linux/linux-2.6.23/em-x270/em-x270.patch') diff --git a/meta/recipes-kernel/linux/linux-2.6.23/em-x270/em-x270.patch b/meta/recipes-kernel/linux/linux-2.6.23/em-x270/em-x270.patch deleted file mode 100644 index 3c28be83c7..0000000000 --- a/meta/recipes-kernel/linux/linux-2.6.23/em-x270/em-x270.patch +++ /dev/null @@ -1,12063 +0,0 @@ - arch/arm/Kconfig | 13 +- - arch/arm/configs/em_x270_defconfig | 367 +++-- - arch/arm/mach-pxa/Kconfig | 8 + - arch/arm/mach-pxa/Makefile | 9 +- - arch/arm/mach-pxa/cpu-pxa.c | 442 ++++++ - arch/arm/mach-pxa/em-x270-devices.c | 331 +++++ - arch/arm/mach-pxa/em-x270-lcd.c | 223 +++ - arch/arm/mach-pxa/em-x270-pm.c | 892 ++++++++++++ - arch/arm/mach-pxa/em-x270.c | 127 ++- - arch/arm/mach-pxa/pwr-i2c.c | 539 +++++++ - arch/arm/mach-pxa/pxa27x.c | 6 +- - arch/arm/mach-pxa/spitz.c | 27 + - drivers/i2c/chips/Kconfig | 13 + - drivers/i2c/chips/Makefile | 1 + - drivers/i2c/chips/da9030.c | 1213 ++++++++++++++++ - drivers/i2c/chips/da9030.h | 282 ++++ - drivers/input/touchscreen/Kconfig | 43 + - drivers/input/touchscreen/Makefile | 14 + - drivers/input/touchscreen/wm9705.c | 360 +++++ - drivers/input/touchscreen/wm9712.c | 464 ++++++ - drivers/input/touchscreen/wm9713.c | 461 ++++++ - drivers/input/touchscreen/wm97xx-core.c | 859 +++++++++++ - drivers/leds/Kconfig | 6 + - drivers/leds/Makefile | 1 + - drivers/leds/leds-em-x270.c | 99 ++ - drivers/mtd/chips/jedec_probe.c | 58 +- - drivers/net/dm9000.c | 1 + - drivers/power/Kconfig | 6 + - drivers/power/Makefile | 1 + - drivers/power/em_x270_battery.c | 579 ++++++++ - drivers/usb/gadget/Kconfig | 20 + - drivers/usb/gadget/Makefile | 1 + - drivers/usb/gadget/epautoconf.c | 9 +- - drivers/usb/gadget/ether.c | 63 +- - drivers/usb/gadget/file_storage.c | 11 +- - drivers/usb/gadget/pxa27x_udc.c | 2387 +++++++++++++++++++++++++++++++ - drivers/usb/gadget/pxa27x_udc.h | 298 ++++ - drivers/usb/gadget/pxa2xx_udc.h | 7 +- - drivers/usb/gadget/serial.c | 18 +- - drivers/usb/gadget/zero.c | 13 +- - drivers/video/backlight/Kconfig | 2 +- - include/asm-arm/arch-pxa/pwr-i2c.h | 61 + - include/linux/da9030.h | 118 ++ - include/linux/usb_gadget.h | 23 +- - include/linux/wm97xx.h | 291 ++++ - sound/soc/pxa/Kconfig | 9 + - sound/soc/pxa/Makefile | 2 + - sound/soc/pxa/em-x270.c | 137 ++ - 48 files changed, 10742 insertions(+), 173 deletions(-) - -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 691aae3..cf1dbc2 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -858,7 +858,7 @@ config KEXEC - - endmenu - --if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX ) -+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA) - - menu "CPU Frequency scaling" - -@@ -894,6 +894,15 @@ config CPU_FREQ_IMX - - If in doubt, say N. - -+config CPU_FREQ_PXA -+ tristate "CPUfreq driver for PXA2xx CPUs" -+ depends on CPU_FREQ && ARCH_PXA -+ default y -+ help -+ Thes enables the CPUfreq driver for PXA2xx CPUs. -+ -+ If in doubt, say Y. -+ - endmenu - - endif -@@ -1029,6 +1038,8 @@ source "drivers/spi/Kconfig" - - source "drivers/w1/Kconfig" - -+source "drivers/power/Kconfig" -+ - source "drivers/hwmon/Kconfig" - - #source "drivers/l3/Kconfig" -diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig -index 6bea090..3246136 100644 ---- a/arch/arm/configs/em_x270_defconfig -+++ b/arch/arm/configs/em_x270_defconfig -@@ -1,13 +1,13 @@ - # - # Automatically generated make config: don't edit --# Linux kernel version: 2.6.22 --# Mon Jul 9 15:18:20 2007 -+# Linux kernel version: 2.6.23-rc9 -+# Tue Oct 9 11:19:21 2007 - # - CONFIG_ARM=y - CONFIG_SYS_SUPPORTS_APM_EMULATION=y - CONFIG_GENERIC_GPIO=y - CONFIG_GENERIC_TIME=y --# CONFIG_GENERIC_CLOCKEVENTS is not set -+CONFIG_GENERIC_CLOCKEVENTS=y - CONFIG_MMU=y - # CONFIG_NO_IOPORT is not set - CONFIG_GENERIC_HARDIRQS=y -@@ -27,25 +27,20 @@ CONFIG_VECTORS_BASE=0xffff0000 - CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - - # --# Code maturity level options -+# General setup - # - CONFIG_EXPERIMENTAL=y - CONFIG_BROKEN_ON_SMP=y - CONFIG_INIT_ENV_ARG_LIMIT=32 -- --# --# General setup --# - CONFIG_LOCALVERSION="-em-x270" - # CONFIG_LOCALVERSION_AUTO is not set - CONFIG_SWAP=y - CONFIG_SYSVIPC=y --# CONFIG_IPC_NS is not set - CONFIG_SYSVIPC_SYSCTL=y - # CONFIG_POSIX_MQUEUE is not set - # CONFIG_BSD_PROCESS_ACCT is not set - # CONFIG_TASKSTATS is not set --# CONFIG_UTS_NS is not set -+# CONFIG_USER_NS is not set - # CONFIG_AUDIT is not set - CONFIG_IKCONFIG=y - CONFIG_IKCONFIG_PROC=y -@@ -71,34 +66,27 @@ CONFIG_FUTEX=y - CONFIG_ANON_INODES=y - CONFIG_EPOLL=y - CONFIG_SIGNALFD=y --CONFIG_TIMERFD=y - CONFIG_EVENTFD=y - CONFIG_SHMEM=y - CONFIG_VM_EVENT_COUNTERS=y --CONFIG_SLAB=y --# CONFIG_SLUB is not set -+CONFIG_SLUB_DEBUG=y -+# CONFIG_SLAB is not set -+CONFIG_SLUB=y - # CONFIG_SLOB is not set - CONFIG_RT_MUTEXES=y - # CONFIG_TINY_SHMEM is not set - CONFIG_BASE_SMALL=0 -- --# --# Loadable module support --# - CONFIG_MODULES=y - CONFIG_MODULE_UNLOAD=y - CONFIG_MODULE_FORCE_UNLOAD=y - # CONFIG_MODVERSIONS is not set - # CONFIG_MODULE_SRCVERSION_ALL is not set - CONFIG_KMOD=y -- --# --# Block layer --# - CONFIG_BLOCK=y - # CONFIG_LBD is not set - # CONFIG_BLK_DEV_IO_TRACE is not set - # CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set - - # - # IO Schedulers -@@ -139,6 +127,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" - # CONFIG_ARCH_L7200 is not set - # CONFIG_ARCH_KS8695 is not set - # CONFIG_ARCH_NS9XXX is not set -+# CONFIG_ARCH_MXC is not set - # CONFIG_ARCH_PNX4008 is not set - CONFIG_ARCH_PXA=y - # CONFIG_ARCH_RPC is not set -@@ -160,6 +149,15 @@ CONFIG_ARCH_PXA=y - # CONFIG_MACH_TRIZEPS4 is not set - CONFIG_MACH_EM_X270=y - CONFIG_PXA27x=y -+CONFIG_PXA_PWR_I2C=y -+ -+# -+# Boot options -+# -+ -+# -+# Power management -+# - - # - # Processor Type -@@ -185,6 +183,7 @@ CONFIG_XSCALE_PMU=y - # - # Bus support - # -+# CONFIG_PCI_SYSCALL is not set - # CONFIG_ARCH_SUPPORTS_MSI is not set - - # -@@ -196,8 +195,9 @@ CONFIG_XSCALE_PMU=y - # Kernel Features - # - # CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set - # CONFIG_PREEMPT is not set --# CONFIG_NO_IDLE_HZ is not set - CONFIG_HZ=100 - CONFIG_AEABI=y - CONFIG_OABI_COMPAT=y -@@ -212,6 +212,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y - CONFIG_SPLIT_PTLOCK_CPUS=4096 - # CONFIG_RESOURCES_64BIT is not set - CONFIG_ZONE_DMA_FLAG=1 -+CONFIG_BOUNCE=y -+CONFIG_VIRT_TO_BUS=y - CONFIG_ALIGNMENT_TRAP=y - - # -@@ -219,11 +221,28 @@ CONFIG_ALIGNMENT_TRAP=y - # - CONFIG_ZBOOT_ROM_TEXT=0x0 - CONFIG_ZBOOT_ROM_BSS=0x0 --CONFIG_CMDLINE="" -+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=jffs2 console=ttyS0,115200" - # CONFIG_XIP_KERNEL is not set - # CONFIG_KEXEC is not set - - # -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+CONFIG_CPU_FREQ_GOV_POWERSAVE=m -+CONFIG_CPU_FREQ_GOV_USERSPACE=m -+CONFIG_CPU_FREQ_GOV_ONDEMAND=m -+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -+CONFIG_CPU_FREQ_PXA=y -+ -+# - # Floating point emulation - # - -@@ -238,8 +257,8 @@ CONFIG_FPE_NWFPE=y - # Userspace binary formats - # - CONFIG_BINFMT_ELF=y --# CONFIG_BINFMT_AOUT is not set --# CONFIG_BINFMT_MISC is not set -+CONFIG_BINFMT_AOUT=m -+CONFIG_BINFMT_MISC=m - - # - # Power management options -@@ -247,8 +266,10 @@ CONFIG_BINFMT_ELF=y - CONFIG_PM=y - CONFIG_PM_LEGACY=y - # CONFIG_PM_DEBUG is not set --# CONFIG_PM_SYSFS_DEPRECATED is not set --CONFIG_APM_EMULATION=m -+CONFIG_PM_SLEEP=y -+CONFIG_SUSPEND_UP_POSSIBLE=y -+CONFIG_SUSPEND=y -+CONFIG_APM_EMULATION=y - - # - # Networking -@@ -316,6 +337,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" - # QoS and/or fair queueing - # - # CONFIG_NET_SCHED is not set -+CONFIG_NET_SCH_FIFO=y - - # - # Network testing -@@ -350,9 +372,12 @@ CONFIG_BT_HCIBFUSB=m - # - # Wireless - # --# CONFIG_CFG80211 is not set --# CONFIG_WIRELESS_EXT is not set --# CONFIG_MAC80211 is not set -+CONFIG_CFG80211=m -+CONFIG_WIRELESS_EXT=y -+CONFIG_MAC80211=m -+# CONFIG_MAC80211_LEDS is not set -+CONFIG_MAC80211_DEBUGFS=y -+# CONFIG_MAC80211_DEBUG is not set - CONFIG_IEEE80211=m - # CONFIG_IEEE80211_DEBUG is not set - CONFIG_IEEE80211_CRYPT_WEP=m -@@ -360,6 +385,7 @@ CONFIG_IEEE80211_CRYPT_CCMP=m - # CONFIG_IEEE80211_CRYPT_TKIP is not set - # CONFIG_IEEE80211_SOFTMAC is not set - # CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set - - # - # Device Drivers -@@ -374,10 +400,6 @@ CONFIG_FW_LOADER=y - # CONFIG_DEBUG_DRIVER is not set - # CONFIG_DEBUG_DEVRES is not set - # CONFIG_SYS_HYPERVISOR is not set -- --# --# Connector - unified userspace <-> kernelspace linker --# - # CONFIG_CONNECTOR is not set - CONFIG_MTD=y - # CONFIG_MTD_DEBUG is not set -@@ -402,11 +424,10 @@ CONFIG_MTD_BLOCK=y - # - # RAM/ROM/Flash chip drivers - # --# CONFIG_MTD_CFI is not set --# CONFIG_MTD_JEDECPROBE is not set --# CONFIG_MTD_CFI_NOSWAP is not set --# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set --# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set -+CONFIG_MTD_CFI=y -+CONFIG_MTD_JEDECPROBE=y -+CONFIG_MTD_GEN_PROBE=y -+# CONFIG_MTD_CFI_ADV_OPTIONS is not set - CONFIG_MTD_MAP_BANK_WIDTH_1=y - CONFIG_MTD_MAP_BANK_WIDTH_2=y - CONFIG_MTD_MAP_BANK_WIDTH_4=y -@@ -417,14 +438,25 @@ CONFIG_MTD_CFI_I1=y - CONFIG_MTD_CFI_I2=y - # CONFIG_MTD_CFI_I4 is not set - # CONFIG_MTD_CFI_I8 is not set -+CONFIG_MTD_CFI_INTELEXT=y -+CONFIG_MTD_CFI_AMDSTD=y -+CONFIG_MTD_CFI_STAA=y -+CONFIG_MTD_CFI_UTIL=y - # CONFIG_MTD_RAM is not set - # CONFIG_MTD_ROM is not set - # CONFIG_MTD_ABSENT is not set -+# CONFIG_MTD_XIP is not set - - # - # Mapping drivers for chip access - # - # CONFIG_MTD_COMPLEX_MAPPINGS is not set -+CONFIG_MTD_PHYSMAP=y -+CONFIG_MTD_PHYSMAP_START=0x0 -+CONFIG_MTD_PHYSMAP_LEN=0x100000 -+CONFIG_MTD_PHYSMAP_BANKWIDTH=2 -+# CONFIG_MTD_ARM_INTEGRATOR is not set -+# CONFIG_MTD_IMPA7 is not set - # CONFIG_MTD_SHARP_SL is not set - # CONFIG_MTD_PLATRAM is not set - -@@ -457,21 +489,17 @@ CONFIG_MTD_NAND_PLATFORM=y - # - # UBI - Unsorted block images - # --# CONFIG_MTD_UBI is not set -+CONFIG_MTD_UBI=m -+CONFIG_MTD_UBI_WL_THRESHOLD=4096 -+CONFIG_MTD_UBI_BEB_RESERVE=1 -+CONFIG_MTD_UBI_GLUEBI=y - - # --# Parallel port support -+# UBI debugging options - # -+# CONFIG_MTD_UBI_DEBUG is not set - # CONFIG_PARPORT is not set -- --# --# Plug and Play support --# --# CONFIG_PNPACPI is not set -- --# --# Block devices --# -+CONFIG_BLK_DEV=y - # CONFIG_BLK_DEV_COW_COMMON is not set - CONFIG_BLK_DEV_LOOP=y - # CONFIG_BLK_DEV_CRYPTOLOOP is not set -@@ -490,6 +518,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 - # - # CONFIG_RAID_ATTRS is not set - CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y - # CONFIG_SCSI_TGT is not set - # CONFIG_SCSI_NETLINK is not set - # CONFIG_SCSI_PROC_FS is not set -@@ -519,36 +548,23 @@ CONFIG_SCSI_WAIT_SCAN=m - # CONFIG_SCSI_SPI_ATTRS is not set - # CONFIG_SCSI_FC_ATTRS is not set - # CONFIG_SCSI_ISCSI_ATTRS is not set --# CONFIG_SCSI_SAS_ATTRS is not set - # CONFIG_SCSI_SAS_LIBSAS is not set -- --# --# SCSI low-level drivers --# -+CONFIG_SCSI_LOWLEVEL=y - # CONFIG_ISCSI_TCP is not set - # CONFIG_SCSI_DEBUG is not set - # CONFIG_ATA is not set -- --# --# Multi-device support (RAID and LVM) --# - # CONFIG_MD is not set -- --# --# Network device support --# - CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set - # CONFIG_DUMMY is not set - # CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set - # CONFIG_EQUALIZER is not set - # CONFIG_TUN is not set - # CONFIG_PHYLIB is not set -- --# --# Ethernet (10 or 100Mbit) --# - CONFIG_NET_ETHERNET=y - CONFIG_MII=y -+# CONFIG_AX88796 is not set - # CONFIG_SMC91X is not set - CONFIG_DM9000=y - # CONFIG_SMC911X is not set -@@ -571,16 +587,22 @@ CONFIG_DM9000=y - # CONFIG_USB_USBNET_MII is not set - # CONFIG_USB_USBNET is not set - # CONFIG_WAN is not set --# CONFIG_PPP is not set -+CONFIG_PPP=m -+# CONFIG_PPP_MULTILINK is not set -+# CONFIG_PPP_FILTER is not set -+CONFIG_PPP_ASYNC=m -+CONFIG_PPP_SYNC_TTY=m -+CONFIG_PPP_DEFLATE=m -+CONFIG_PPP_BSDCOMP=m -+CONFIG_PPP_MPPE=m -+# CONFIG_PPPOE is not set -+CONFIG_PPPOL2TP=m - # CONFIG_SLIP is not set -+CONFIG_SLHC=m - # 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 - - # -@@ -612,16 +634,21 @@ CONFIG_INPUT_KEYBOARD=y - # CONFIG_KEYBOARD_XTKBD is not set - # CONFIG_KEYBOARD_NEWTON is not set - # CONFIG_KEYBOARD_STOWAWAY is not set --CONFIG_KEYBOARD_PXA27x=m -+CONFIG_KEYBOARD_PXA27x=y - # CONFIG_KEYBOARD_GPIO is not set - # CONFIG_INPUT_MOUSE is not set - # CONFIG_INPUT_JOYSTICK is not set - # CONFIG_INPUT_TABLET is not set - CONFIG_INPUT_TOUCHSCREEN=y -+# CONFIG_TOUCHSCREEN_FUJITSU 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_WM97XX=y -+# CONFIG_TOUCHSCREEN_WM9705 is not set -+CONFIG_TOUCHSCREEN_WM9712=y -+# CONFIG_TOUCHSCREEN_WM9713 is not set - # CONFIG_TOUCHSCREEN_PENMOUNT is not set - # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set - # CONFIG_TOUCHSCREEN_TOUCHWIN is not set -@@ -660,58 +687,91 @@ 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_LEGACY_PTYS is not set - # CONFIG_IPMI_HANDLER is not set - # CONFIG_WATCHDOG is not set - CONFIG_HW_RANDOM=m - # CONFIG_NVRAM is not set - # CONFIG_R3964 is not set - # CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+CONFIG_I2C=y -+CONFIG_I2C_BOARDINFO=y -+# CONFIG_I2C_CHARDEV is not set - - # --# TPM devices -+# I2C Algorithms - # --# CONFIG_TCG_TPM is not set --# CONFIG_I2C is not set -+# CONFIG_I2C_ALGOBIT is not set -+# CONFIG_I2C_ALGOPCF is not set -+# CONFIG_I2C_ALGOPCA is not set - - # --# SPI support -+# I2C Hardware Bus support - # --# CONFIG_SPI is not set --# CONFIG_SPI_MASTER is not set -+# CONFIG_I2C_GPIO is not set -+CONFIG_I2C_PXA=y -+# CONFIG_I2C_PXA_SLAVE is not set -+# CONFIG_I2C_OCORES is not set -+# CONFIG_I2C_PARPORT_LIGHT is not set -+# CONFIG_I2C_SIMTEC is not set -+# CONFIG_I2C_TAOS_EVM is not set -+# CONFIG_I2C_STUB is not set -+# CONFIG_I2C_TINY_USB is not set - - # --# Dallas's 1-wire bus -+# Miscellaneous I2C Chip support - # --# CONFIG_W1 is not set --# CONFIG_HWMON is not set -+# CONFIG_SENSORS_DS1337 is not set -+# CONFIG_SENSORS_DS1374 is not set -+# CONFIG_DS1682 is not set -+# CONFIG_SENSORS_EEPROM is not set -+# CONFIG_SENSORS_PCF8574 is not set -+# CONFIG_SENSORS_PCA9539 is not set -+# CONFIG_SENSORS_PCF8591 is not set -+# CONFIG_SENSORS_MAX6875 is not set -+# CONFIG_SENSORS_TSL2550 is not set -+CONFIG_DA9030=y -+# 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 - - # --# Misc devices -+# SPI support - # -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+CONFIG_POWER_SUPPLY=y -+# CONFIG_POWER_SUPPLY_DEBUG is not set -+# CONFIG_PDA_POWER is not set -+CONFIG_APM_POWER=y -+# CONFIG_BATTERY_DS2760 is not set -+# CONFIG_BATTERY_EM_X270 is not set -+# CONFIG_HWMON is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set - - # - # Multifunction device drivers - # - # CONFIG_MFD_SM501 is not set -- --# --# LED devices --# --# CONFIG_NEW_LEDS is not set -+CONFIG_NEW_LEDS=y -+CONFIG_LEDS_CLASS=m - - # - # LED drivers - # -+CONFIG_LEDS_GPIO=m -+CONFIG_LEDS_EM_X270=m - - # - # LED Triggers - # -+CONFIG_LEDS_TRIGGERS=y -+CONFIG_LEDS_TRIGGER_TIMER=m -+CONFIG_LEDS_TRIGGER_HEARTBEAT=m - - # - # Multimedia devices -@@ -723,13 +783,17 @@ CONFIG_HW_RANDOM=m - # - # Graphics support - # --# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+CONFIG_BACKLIGHT_LCD_SUPPORT=y -+CONFIG_LCD_CLASS_DEVICE=y -+CONFIG_BACKLIGHT_CLASS_DEVICE=y -+CONFIG_BACKLIGHT_CORGI=y - - # - # Display device support - # - # CONFIG_DISPLAY_SUPPORT is not set - # CONFIG_VGASTATE is not set -+CONFIG_VIDEO_OUTPUT_CONTROL=m - CONFIG_FB=y - # CONFIG_FIRMWARE_EDID is not set - # CONFIG_FB_DDC is not set -@@ -752,7 +816,7 @@ CONFIG_FB_DEFERRED_IO=y - # - # CONFIG_FB_S1D13XXX is not set - CONFIG_FB_PXA=y --# CONFIG_FB_PXA_PARAMETERS is not set -+CONFIG_FB_PXA_PARAMETERS=y - # CONFIG_FB_MBX is not set - # CONFIG_FB_VIRTUAL is not set - -@@ -762,6 +826,7 @@ CONFIG_FB_PXA=y - # CONFIG_VGA_CONSOLE is not set - CONFIG_DUMMY_CONSOLE=y - CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set - # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set - # CONFIG_FONTS is not set - CONFIG_FONT_8x8=y -@@ -774,18 +839,18 @@ CONFIG_LOGO_LINUX_CLUT224=y - # - # Sound - # --CONFIG_SOUND=m -+CONFIG_SOUND=y - - # - # Advanced Linux Sound Architecture - # --CONFIG_SND=m --CONFIG_SND_TIMER=m --CONFIG_SND_PCM=m -+CONFIG_SND=y -+CONFIG_SND_TIMER=y -+CONFIG_SND_PCM=y - # CONFIG_SND_SEQUENCER is not set - CONFIG_SND_OSSEMUL=y --CONFIG_SND_MIXER_OSS=m --CONFIG_SND_PCM_OSS=m -+CONFIG_SND_MIXER_OSS=y -+CONFIG_SND_PCM_OSS=y - CONFIG_SND_PCM_OSS_PLUGINS=y - # CONFIG_SND_DYNAMIC_MINORS is not set - CONFIG_SND_SUPPORT_OLD_API=y -@@ -817,17 +882,23 @@ CONFIG_SND_PXA2XX_AC97=m - # - # System on Chip audio support - # --# CONFIG_SND_SOC is not set -+CONFIG_SND_SOC_AC97_BUS=y -+CONFIG_SND_SOC=y -+CONFIG_SND_PXA2XX_SOC=y -+CONFIG_SND_PXA2XX_SOC_AC97=y -+CONFIG_SND_PXA2XX_SOC_EM_X270=y - - # --# Open Sound System -+# SoC Audio support for SuperH - # --# CONFIG_SOUND_PRIME is not set --CONFIG_AC97_BUS=m -+CONFIG_SND_SOC_WM9712=y - - # --# HID Devices -+# Open Sound System - # -+# CONFIG_SOUND_PRIME is not set -+CONFIG_AC97_BUS=y -+CONFIG_HID_SUPPORT=y - CONFIG_HID=y - # CONFIG_HID_DEBUG is not set - -@@ -838,10 +909,7 @@ CONFIG_USB_HID=y - # CONFIG_USB_HIDINPUT_POWERBOOK is not set - # CONFIG_HID_FF is not set - # CONFIG_USB_HIDDEV is not set -- --# --# USB support --# -+CONFIG_USB_SUPPORT=y - CONFIG_USB_ARCH_HAS_HCD=y - CONFIG_USB_ARCH_HAS_OHCI=y - # CONFIG_USB_ARCH_HAS_EHCI is not set -@@ -855,6 +923,7 @@ CONFIG_USB_DEVICEFS=y - # CONFIG_USB_DEVICE_CLASS is not set - # CONFIG_USB_DYNAMIC_MINORS is not set - # CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set - # CONFIG_USB_OTG is not set - - # -@@ -866,12 +935,13 @@ CONFIG_USB_OHCI_HCD=y - # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set - CONFIG_USB_OHCI_LITTLE_ENDIAN=y - # CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set - - # - # USB Device Class drivers - # --# CONFIG_USB_ACM is not set --# CONFIG_USB_PRINTER is not set -+CONFIG_USB_ACM=m -+CONFIG_USB_PRINTER=m - - # - # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -@@ -896,8 +966,8 @@ CONFIG_USB_STORAGE=y - # - # USB Imaging devices - # --# CONFIG_USB_MDC800 is not set --# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MDC800=m -+CONFIG_USB_MICROTEK=m - # CONFIG_USB_MON is not set - - # -@@ -940,25 +1010,25 @@ CONFIG_USB_STORAGE=y - # USB Gadget Support - # - # CONFIG_USB_GADGET is not set --CONFIG_MMC=m -+CONFIG_MMC=y - # CONFIG_MMC_DEBUG is not set --# CONFIG_MMC_UNSAFE_RESUME is not set -+CONFIG_MMC_UNSAFE_RESUME=y - - # - # MMC/SD Card Drivers - # --CONFIG_MMC_BLOCK=m -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y - - # - # MMC/SD Host Controller Drivers - # --CONFIG_MMC_PXA=m -- --# --# Real Time Clock --# -+CONFIG_MMC_PXA=y - CONFIG_RTC_LIB=y --CONFIG_RTC_CLASS=m -+CONFIG_RTC_CLASS=y -+CONFIG_RTC_HCTOSYS=y -+CONFIG_RTC_HCTOSYS_DEVICE="rtc1" -+# CONFIG_RTC_DEBUG is not set - - # - # RTC interfaces -@@ -972,6 +1042,15 @@ CONFIG_RTC_INTF_DEV=y - # - # I2C RTC drivers - # -+# CONFIG_RTC_DRV_DS1307 is not set -+# CONFIG_RTC_DRV_DS1672 is not set -+# CONFIG_RTC_DRV_MAX6900 is not set -+# CONFIG_RTC_DRV_RS5C372 is not set -+# CONFIG_RTC_DRV_ISL1208 is not set -+# CONFIG_RTC_DRV_X1205 is not set -+# CONFIG_RTC_DRV_PCF8563 is not set -+# CONFIG_RTC_DRV_PCF8583 is not set -+# CONFIG_RTC_DRV_M41T80 is not set - - # - # SPI RTC drivers -@@ -982,14 +1061,29 @@ CONFIG_RTC_INTF_DEV=y - # - # CONFIG_RTC_DRV_CMOS is not set - # CONFIG_RTC_DRV_DS1553 is not set -+# CONFIG_RTC_DRV_STK17TA8 is not set - # CONFIG_RTC_DRV_DS1742 is not set - # CONFIG_RTC_DRV_M48T86 is not set --CONFIG_RTC_DRV_V3020=m -+# CONFIG_RTC_DRV_M48T59 is not set -+CONFIG_RTC_DRV_V3020=y - - # - # on-CPU RTC drivers - # --CONFIG_RTC_DRV_SA1100=m -+CONFIG_RTC_DRV_SA1100=y -+ -+# -+# DMA Engine support -+# -+# CONFIG_DMA_ENGINE is not set -+ -+# -+# DMA Clients -+# -+ -+# -+# DMA Devices -+# - - # - # File systems -@@ -1098,7 +1192,6 @@ CONFIG_SMB_FS=y - # 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 -@@ -1167,20 +1260,22 @@ CONFIG_NLS_UTF8=y - CONFIG_ENABLE_MUST_CHECK=y - CONFIG_MAGIC_SYSRQ=y - # CONFIG_UNUSED_SYMBOLS is not set --# CONFIG_DEBUG_FS is not set -+CONFIG_DEBUG_FS=y - # CONFIG_HEADERS_CHECK is not set - CONFIG_DEBUG_KERNEL=y - # CONFIG_DEBUG_SHIRQ is not set - # CONFIG_DETECT_SOFTLOCKUP is not set -+CONFIG_SCHED_DEBUG=y - # CONFIG_SCHEDSTATS is not set - # CONFIG_TIMER_STATS is not set --# CONFIG_DEBUG_SLAB is not set -+# CONFIG_SLUB_DEBUG_ON is not set - # CONFIG_DEBUG_RT_MUTEXES is not set - # CONFIG_RT_MUTEX_TESTER is not set - # CONFIG_DEBUG_SPINLOCK is not set - # CONFIG_DEBUG_MUTEXES is not set - # CONFIG_DEBUG_LOCK_ALLOC is not set - # CONFIG_PROVE_LOCKING is not set -+# CONFIG_LOCK_STAT is not set - # CONFIG_DEBUG_SPINLOCK_SLEEP is not set - # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set - # CONFIG_DEBUG_KOBJECT is not set -@@ -1202,10 +1297,6 @@ CONFIG_DEBUG_LL=y - # - # CONFIG_KEYS is not set - # CONFIG_SECURITY is not set -- --# --# Cryptographic options --# - CONFIG_CRYPTO=y - CONFIG_CRYPTO_ALGAPI=m - CONFIG_CRYPTO_BLKCIPHER=m -@@ -1215,7 +1306,7 @@ CONFIG_CRYPTO_MANAGER=m - # CONFIG_CRYPTO_NULL is not set - # CONFIG_CRYPTO_MD4 is not set - # CONFIG_CRYPTO_MD5 is not set --# CONFIG_CRYPTO_SHA1 is not set -+CONFIG_CRYPTO_SHA1=m - # CONFIG_CRYPTO_SHA256 is not set - # CONFIG_CRYPTO_SHA512 is not set - # CONFIG_CRYPTO_WP512 is not set -@@ -1243,19 +1334,17 @@ CONFIG_CRYPTO_ARC4=m - # CONFIG_CRYPTO_CRC32C is not set - # CONFIG_CRYPTO_CAMELLIA is not set - # CONFIG_CRYPTO_TEST is not set -- --# --# Hardware crypto devices --# -+CONFIG_CRYPTO_HW=y - - # - # Library routines - # - CONFIG_BITREVERSE=y --# CONFIG_CRC_CCITT is not set -+CONFIG_CRC_CCITT=m - # CONFIG_CRC16 is not set - # CONFIG_CRC_ITU_T is not set - CONFIG_CRC32=y -+# CONFIG_CRC7 is not set - # CONFIG_LIBCRC32C is not set - CONFIG_ZLIB_INFLATE=y - CONFIG_ZLIB_DEFLATE=y -diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig -index 5ebec6d..2957cb9 100644 ---- a/arch/arm/mach-pxa/Kconfig -+++ b/arch/arm/mach-pxa/Kconfig -@@ -148,4 +148,12 @@ config PXA_SSP - tristate - help - Enable support for PXA2xx SSP ports -+ -+config PXA_PWR_I2C -+ bool "Simple Power I2C interface" -+ depends on PXA27x -+ help -+ Enable support for PXA27x Power I2C interface. This driver -+ enables very simple blocking access to Power I2C, which -+ might be useful for early access to Power Management ICs. - endif -diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile -index 7d6ab5c..2d7a431 100644 ---- a/arch/arm/mach-pxa/Makefile -+++ b/arch/arm/mach-pxa/Makefile -@@ -18,7 +18,7 @@ obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o sp - obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o - obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o - obj-$(CONFIG_MACH_TOSA) += tosa.o --obj-$(CONFIG_MACH_EM_X270) += em-x270.o -+obj-$(CONFIG_MACH_EM_X270) += em-x270.o em-x270-pm.o em-x270-lcd.o em-x270-devices.o - - # Support for blinky lights - led-y := leds.o -@@ -29,9 +29,16 @@ led-$(CONFIG_MACH_TRIZEPS4) += leds-trizeps4.o - - obj-$(CONFIG_LEDS) += $(led-y) - -+# CPU Frequency scaling -+obj-$(CONFIG_CPU_FREQ_PXA) += cpu-pxa.o -+ - # Misc features - obj-$(CONFIG_PM) += pm.o sleep.o - obj-$(CONFIG_PXA_SSP) += ssp.o -+obj-$(CONFIG_PXA_PWR_I2C) += pwr-i2c.o -+ -+#obj-m += da9030_asm.o -+#da9030_asm-y += da9030.o da9030_c.o - - ifeq ($(CONFIG_PXA27x),y) - obj-$(CONFIG_PM) += standby.o -diff --git a/arch/arm/mach-pxa/cpu-pxa.c b/arch/arm/mach-pxa/cpu-pxa.c -new file mode 100644 -index 0000000..7fa9703 ---- /dev/null -+++ b/arch/arm/mach-pxa/cpu-pxa.c -@@ -0,0 +1,442 @@ -+/* -+ * linux/arch/arm/mach-pxa/cpu-pxa.c -+ * -+ * Copyright (C) 2002,2003 Intrinsyc Software -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; 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 -+ * -+ * History: -+ * 31-Jul-2002 : Initial version [FB] -+ * 29-Jan-2003 : added PXA255 support [FB] -+ * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) -+ * 11-Jan-2006 : v2.6, support for PXA27x processor up to 624MHz (Bill Reese, Hewlett Packard) -+ * -+ * Note: -+ * This driver may change the memory bus clock rate, but will not do any -+ * platform specific access timing changes... for example if you have flash -+ * memory connected to CS0, you will need to register a platform specific -+ * notifier which will adjust the memory access strobes to maintain a -+ * minimum strobe width. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+/* -+ * This comes from generic.h in this directory. -+ */ -+extern unsigned int get_clk_frequency_khz(int info); -+ -+#define DEBUG 0 -+ -+#ifdef DEBUG -+ static unsigned int freq_debug = DEBUG; -+ module_param(freq_debug, int, 0644); -+ MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0"); -+#else -+ #define freq_debug 0 -+#endif -+ -+typedef struct -+{ -+ unsigned int khz; /* CPU frequency */ -+ unsigned int membus; /* memory bus frequency */ -+ unsigned int cccr; /* new CCLKCFG setting */ -+ unsigned int div2; /* alter memory controller settings to divide by 2 */ -+ unsigned int cclkcfg; /* new CCLKCFG setting */ -+} pxa_freqs_t; -+ -+/* Define the refresh period in mSec for the SDRAM and the number of rows */ -+#define SDRAM_TREF 64 /* standard 64ms SDRAM */ -+#if defined(CONFIG_MACH_H4700) || defined(CONFIG_ARCH_H2200) || defined(CONFIG_MACH_MAGICIAN) -+#define SDRAM_ROWS 8192 /* hx4700 uses 2 64Mb DRAMs, 8912 rows */ -+#else -+#define SDRAM_ROWS 4096 /* 64MB=8192 32MB=4096 */ -+#endif -+#define MDREFR_DRI(x) (((x*SDRAM_TREF/SDRAM_ROWS - 31)/32)) -+ -+#define CCLKCFG_TURBO 0x1 -+#define CCLKCFG_FCS 0x2 -+#define CCLKCFG_HALFTURBO 0x4 -+#define CCLKCFG_FASTBUS 0x8 -+#ifdef CONFIG_ARCH_H5400 -+/* H5400's SAMCOP chip does not like when K2DB2 touched */ -+#define MDREFR_DB2_MASK (MDREFR_K1DB2) -+#else -+#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2) -+#endif -+#define MDREFR_DRI_MASK 0xFFF -+#define PXA25x_CCLKCFG CCLKCFG_TURBO | CCLKCFG_FCS -+ -+/* -+ * For the PXA27x: -+ * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG. -+ * -+ * A = 0 => memory controller clock from table 3-7, -+ * A = 1 => memory controller clock = system bus clock -+ * Run mode frequency = 13 MHz * L -+ * Turbo mode frequency = 13 MHz * L * N -+ * System bus frequency = 13 MHz * L / (B + 1) -+ * System initialized by bootldr to: -+ * -+ * In CCCR: -+ * A = 1 -+ * L = 16 oscillator to run mode ratio -+ * 2N = 6 2 * (turbo mode to run mode ratio) -+ * -+ * In CCLKCFG: -+ * B = 1 Fast bus mode -+ * HT = 0 Half-Turbo mode -+ * T = 1 Turbo mode -+ * -+ * For now, just support some of the combinations in table 3-7 of -+ * PXA27x Processor Family Developer's Manual to simplify frequency -+ * change sequences. -+ * -+ * Specify 2N in the PXA27x_CCCR macro, not N! -+ */ -+#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L) -+#define PXA27x_CCLKCFG(B, HT, T) (B << 3 | HT << 2 | CCLKCFG_FCS | T) -+ -+#define PXA25x_CCCR(L, M, N) (L << 0 | M << 5 | N << 7) -+ -+/* -+ * Valid frequency assignments -+ */ -+static pxa_freqs_t pxa2xx_freqs[] = -+{ -+ /* CPU MEMBUS CCCR DIV2 */ -+#if defined(CONFIG_PXA25x) -+#if defined(CONFIG_PXA25x_ALTERNATE_FREQS) -+ { 99500, 99500, PXA25x_CCCR(1, 1, 2), 1, PXA25x_CCLKCFG}, /* run=99, turbo= 99, PXbus=50, SDRAM=50 */ -+ {199100, 99500, PXA25x_CCCR(1, 1, 4), 0, PXA25x_CCLKCFG}, /* run=99, turbo=199, PXbus=50, SDRAM=99 */ -+ {298500, 99500, PXA25x_CCCR(1, 1, 6), 0, PXA25x_CCLKCFG}, /* run=99, turbo=287, PXbus=50, SDRAM=99 */ -+ {298600, 99500, PXA25x_CCCR(1, 2, 3), 0, PXA25x_CCLKCFG}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */ -+ {398100, 99500, PXA25x_CCCR(1, 2, 4), 0, PXA25x_CCLKCFG} /* run=199, turbo=398, PXbus=99, SDRAM=99 */ -+#else -+ { 99500, 99500, PXA25x_CCCR(1, 1, 2), 1, PXA25x_CCLKCFG}, /* run= 99, turbo= 99, PXbus=50, SDRAM=50 */ -+ {132700, 132700, PXA25x_CCCR(3, 1, 2), 1, PXA25x_CCLKCFG}, /* run=133, turbo=133, PXbus=66, SDRAM=66 */ -+ {199100, 99500, PXA25x_CCCR(1, 2, 2), 0, PXA25x_CCLKCFG}, /* run=199, turbo=199, PXbus=99, SDRAM=99 */ -+ {265400, 132700, PXA25x_CCCR(3, 2, 2), 1, PXA25x_CCLKCFG}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */ -+ {331800, 165900, PXA25x_CCCR(5, 2, 2), 1, PXA25x_CCLKCFG}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */ -+ {398100, 99500, PXA25x_CCCR(1, 3, 2), 0, PXA25x_CCLKCFG} /* run=398, turbo=398, PXbus=196, SDRAM=99 */ -+#endif -+#elif defined(CONFIG_PXA27x) -+ {104000, 104000, PXA27x_CCCR(1, 8, 2), 0, PXA27x_CCLKCFG(1, 0, 1)}, -+ {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, PXA27x_CCLKCFG(1, 1, 1)}, -+ {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, PXA27x_CCLKCFG(0, 0, 1)}, -+ {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, PXA27x_CCLKCFG(1, 0, 1)}, -+ {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, PXA27x_CCLKCFG(1, 0, 1)}, -+ {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, PXA27x_CCLKCFG(1, 0, 1)}, -+/* {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, PXA27x_CCLKCFG(1, 0, 1)} */ -+#endif -+}; -+#define NUM_FREQS (sizeof(pxa2xx_freqs)/sizeof(pxa_freqs_t)) -+ -+static struct cpufreq_frequency_table pxa2xx_freq_table[NUM_FREQS+1]; -+ -+/* Return the memory clock rate for a given cpu frequency. */ -+int pxa_cpufreq_memclk(int cpu_khz) -+{ -+ int i; -+ int freq_mem = 0; -+ -+ for (i = 0; i < NUM_FREQS; i++) { -+ if (pxa2xx_freqs[i].khz == cpu_khz) { -+ freq_mem = pxa2xx_freqs[i].membus; -+ break; -+ } -+ } -+ -+ return freq_mem; -+} -+EXPORT_SYMBOL(pxa_cpufreq_memclk); -+ -+ -+/* find a valid frequency point */ -+static int pxa_verify_policy(struct cpufreq_policy *policy) -+{ -+ int ret; -+ -+ ret=cpufreq_frequency_table_verify(policy, pxa2xx_freq_table); -+ -+ if(freq_debug) { -+ printk("Verified CPU policy: %dKhz min to %dKhz max\n", -+ policy->min, policy->max); -+ } -+ -+ return ret; -+} -+ -+static int pxa_set_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ int idx; -+ cpumask_t cpus_allowed, allowedcpuset; -+ int cpu = policy->cpu; -+ struct cpufreq_freqs freqs; -+ unsigned long flags; -+ unsigned int unused; -+ unsigned int preset_mdrefr, postset_mdrefr, cclkcfg; -+ -+ if(freq_debug) { -+ printk ("CPU PXA: target freq %d\n", target_freq); -+ printk ("CPU PXA: relation %d\n", relation); -+ } -+ -+ /* -+ * Save this threads cpus_allowed mask. -+ */ -+ cpus_allowed = current->cpus_allowed; -+ -+ /* -+ * Bind to the specified CPU. When this call returns, -+ * we should be running on the right CPU. -+ */ -+ cpus_clear (allowedcpuset); -+ cpu_set (cpu, allowedcpuset); -+ set_cpus_allowed(current, allowedcpuset); -+ BUG_ON(cpu != smp_processor_id()); -+ -+ /* Lookup the next frequency */ -+ if (cpufreq_frequency_table_target(policy, pxa2xx_freq_table, -+ target_freq, relation, &idx)) { -+ return -EINVAL; -+ } -+ -+ freqs.old = policy->cur; -+ freqs.new = pxa2xx_freqs[idx].khz; -+ freqs.cpu = policy->cpu; -+ if(freq_debug) { -+ printk(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", -+ freqs.new/1000, (pxa2xx_freqs[idx].div2) ? -+ (pxa2xx_freqs[idx].membus/2000) : -+ (pxa2xx_freqs[idx].membus/1000)); -+ } -+ -+ /* -+ * Tell everyone what we're about to do... -+ * you should add a notify client with any platform specific -+ * Vcc changing capability -+ */ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ -+ /* Calculate the next MDREFR. If we're slowing down the SDRAM clock -+ * we need to preset the smaller DRI before the change. If we're speeding -+ * up we need to set the larger DRI value after the change. -+ */ -+ preset_mdrefr = postset_mdrefr = MDREFR; -+ if((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa2xx_freqs[idx].membus)) { -+ preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) | -+ MDREFR_DRI(pxa2xx_freqs[idx].membus); -+ } -+ postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) | -+ MDREFR_DRI(pxa2xx_freqs[idx].membus); -+ -+ /* If we're dividing the memory clock by two for the SDRAM clock, this -+ * must be set prior to the change. Clearing the divide must be done -+ * after the change. -+ */ -+ if(pxa2xx_freqs[idx].div2) { -+ /* -+ * Potentially speeding up memory clock, so slow down the memory -+ * before speeding up the clock. -+ */ -+ preset_mdrefr |= MDREFR_DB2_MASK | MDREFR_K0DB4; -+ preset_mdrefr &= ~MDREFR_K0DB2; -+ -+ postset_mdrefr |= MDREFR_DB2_MASK | MDREFR_K0DB4; -+ postset_mdrefr &= ~MDREFR_K0DB2; -+ } else { -+ /* -+ * Potentially slowing down memory clock. Wait until after the change -+ * to speed up the memory. -+ */ -+ postset_mdrefr &= ~MDREFR_DB2_MASK; -+ postset_mdrefr &= ~MDREFR_K0DB4; -+ postset_mdrefr |= MDREFR_K0DB2; -+ } -+ -+ cclkcfg = pxa2xx_freqs[idx].cclkcfg; -+ -+ if (freq_debug) { -+ printk (KERN_INFO "CPU PXA writing 0x%08x to CCCR\n", -+ pxa2xx_freqs[idx].cccr); -+ printk (KERN_INFO "CPU PXA writing 0x%08x to CCLKCFG\n", -+ pxa2xx_freqs[idx].cclkcfg); -+ printk (KERN_INFO "CPU PXA writing 0x%08x to MDREFR before change\n", -+ preset_mdrefr); -+ printk (KERN_INFO "CPU PXA writing 0x%08x to MDREFR after change\n", -+ postset_mdrefr); -+ } -+ -+ local_irq_save(flags); -+ -+ /* Set new the CCCR */ -+ CCCR = pxa2xx_freqs[idx].cccr; -+ -+ /* -+ * Should really set both of PMCR[xIDAE] while changing the core frequency -+ */ -+ -+ /* -+ * TODO: On the PXA27x: If we're setting half-turbo mode and changing the -+ * core frequency at the same time we must split it up into two operations. -+ * The current values in the pxa2xx_freqs table don't do this, so the code -+ * is unimplemented. -+ */ -+ -+ __asm__ __volatile__(" \ -+ ldr r4, [%1] ; /* load MDREFR */ \ -+ b 2f ; \ -+ .align 5 ; \ -+1: \ -+ str %3, [%1] ; /* preset the MDREFR */ \ -+ mcr p14, 0, %2, c6, c0, 0 ; /* set CCLKCFG[FCS] */ \ -+ str %4, [%1] ; /* postset the MDREFR */ \ -+ \ -+ b 3f ; \ -+2: b 1b ; \ -+3: nop ; \ -+ " -+ : "=&r" (unused) -+ : "r" (&MDREFR), "r" (cclkcfg), \ -+ "r" (preset_mdrefr), "r" (postset_mdrefr) -+ : "r4", "r5"); -+ local_irq_restore(flags); -+ -+ if (freq_debug) { -+ printk (KERN_INFO "CPU PXA Frequency change successful\n"); -+ printk (KERN_INFO "CPU PXA new CCSR 0x%08x\n", CCSR); -+ } -+ -+ /* -+ * Restore the CPUs allowed mask. -+ */ -+ set_cpus_allowed(current, cpus_allowed); -+ -+ /* -+ * Tell everyone what we've just done... -+ * you should add a notify client with any platform specific -+ * SDRAM refresh timer adjustments -+ */ -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+ -+ return 0; -+} -+ -+static int pxa_cpufreq_init(struct cpufreq_policy *policy) -+{ -+ cpumask_t cpus_allowed, allowedcpuset; -+ unsigned int cpu = policy->cpu; -+ int i; -+ unsigned int cclkcfg; -+ -+ cpus_allowed = current->cpus_allowed; -+ -+ cpus_clear (allowedcpuset); -+ cpu_set (cpu, allowedcpuset); -+ set_cpus_allowed(current, allowedcpuset); -+ BUG_ON(cpu != smp_processor_id()); -+ -+ /* set default governor and cpuinfo */ -+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; -+ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ -+ policy->cur = get_clk_frequency_khz(0); /* current freq */ -+ -+ /* Generate the cpufreq_frequency_table struct */ -+ for(i=0;icpus_allowed; -+ set_cpus_allowed(current, cpumask_of_cpu(cpu)); -+ BUG_ON(cpu != smp_processor_id()); -+ -+ cur_freq = get_clk_frequency_khz(0); -+ -+ set_cpus_allowed(current, cpumask_saved); -+ -+ return cur_freq; -+} -+ -+static struct cpufreq_driver pxa_cpufreq_driver = { -+ .verify = pxa_verify_policy, -+ .target = pxa_set_target, -+ .init = pxa_cpufreq_init, -+ .get = pxa_cpufreq_get, -+#if defined(CONFIG_PXA25x) -+ .name = "PXA25x", -+#elif defined(CONFIG_PXA27x) -+ .name = "PXA27x", -+#endif -+}; -+ -+static int __init pxa_cpu_init(void) -+{ -+ return cpufreq_register_driver(&pxa_cpufreq_driver); -+} -+ -+static void __exit pxa_cpu_exit(void) -+{ -+ cpufreq_unregister_driver(&pxa_cpufreq_driver); -+} -+ -+ -+MODULE_AUTHOR ("Intrinsyc Software Inc."); -+MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture"); -+MODULE_LICENSE("GPL"); -+module_init(pxa_cpu_init); -+module_exit(pxa_cpu_exit); -+ -diff --git a/arch/arm/mach-pxa/em-x270-devices.c b/arch/arm/mach-pxa/em-x270-devices.c -new file mode 100644 -index 0000000..d142930 ---- /dev/null -+++ b/arch/arm/mach-pxa/em-x270-devices.c -@@ -0,0 +1,331 @@ -+/* -+ * Support for CompuLab EM-X270 platfrom specific device -+ * initialization, and per-device power management functions. -+ * -+ * Copyright (C) 2007 CompuLab, Ltd. -+ * Author: Mike Rapoport -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../../../drivers/i2c/chips/da9030.h" -+ -+#include -+#include -+ -+struct em_x270_dev_data { -+ int (*is_on)(struct device *dev); -+ int (*set_on)(struct device *dev, int on); -+ int (*get_opts)(struct device *dev, -+ struct device_attribute *attr, -+ char *buf); -+ int (*set_opts)(struct device *dev, int opts); -+}; -+ -+static void em_x270_dev_release(struct device * dev) -+{ -+ -+} -+ -+static ssize_t em_x270_dev_pm_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct em_x270_dev_data *pm_data = dev->platform_data; -+ int is_on = pm_data->is_on(dev); -+ -+ return sprintf(buf, "%d\n", is_on); -+} -+ -+static ssize_t em_x270_dev_pm_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char *endp; -+ int on = simple_strtoul(buf, &endp, 0); -+ size_t size = endp - buf; -+ struct em_x270_dev_data *pm_data = dev->platform_data; -+ -+ pr_info("%s: %s\n", __FUNCTION__, buf); -+ -+ if (*endp && isspace(*endp)) -+ size++; -+ if (size != count) -+ return -EINVAL; -+ -+ pm_data->set_on(dev, on); -+ -+ return count; -+} -+ -+static DEVICE_ATTR(pwr_on, S_IWUSR | S_IRUGO, -+ em_x270_dev_pm_show, em_x270_dev_pm_store); -+ -+static int gprs_is_on(struct device *dev) -+{ -+ return !!(pxa_gpio_get_value(20)); -+} -+ -+static int gprs_set_on(struct device *dev, int on) -+{ -+ pr_info("%s: on = %d\n", __FUNCTION__, on); -+ if (on) { -+ pxa_gpio_mode(20 | GPIO_OUT | GPIO_DFLT_HIGH); -+ mdelay(500); -+ pxa_gpio_set_value(82, 0); -+ mdelay(500); -+ pxa_gpio_mode(82 | GPIO_OUT | GPIO_DFLT_HIGH); -+ mdelay(1000); -+ pxa_gpio_set_value(82, 0); -+ } -+ else { -+ pxa_gpio_set_value(20, 0); -+ pxa_gpio_mode(20 | GPIO_OUT); -+ } -+ -+ return 0; -+} -+ -+static struct em_x270_dev_data em_x270_gprs_data = { -+ .is_on = gprs_is_on, -+ .set_on = gprs_set_on, -+}; -+ -+static struct platform_device em_x270_gprs = { -+ .name = "gprs", -+ .id = -1, -+ .dev = { -+ .platform_data = &em_x270_gprs_data, -+ .release = em_x270_dev_release, -+ }, -+}; -+ -+static int is_wlan_on; -+ -+static int wlan_is_on(struct device *dev) -+{ -+ return is_wlan_on; -+} -+ -+static int wlan_set_on(struct device *dev, int on) -+{ -+ if (on) { -+ /* WLAN power-up sequence */ -+ /* Mask LDO17 and LDO19 tolerance events */ -+ da9030_set_reg(IRQ_MASK_C, -+ IRQ_MASK_C_LDO19 | IRQ_MASK_C_LDO17); -+ -+ /* Force I2C control over LDO17, LDO19 */ -+ da9030_set_reg(SLEEP_CONTROL, -+ APP_SLEEP_CTL_BYPASS_LDO19 | -+ APP_SLEEP_CTL_BYPASS_LDO17); -+ -+ /* Turn off LDO17 and LDO19 */ -+ da9030_set_reg(REG_CONTROL_1_17, -+ RC1_LDO16_EN | RC1_LDO15_EN | -+ RC1_LDO11_EN | RC1_LDO10_EN | RC1_BUCK2_EN); -+ da9030_set_reg(REG_CONTROL_2_18, RC2_SIMCP_EN | RC2_LDO18_EN); -+ -+ /* Set LDO17 voltage to 3V (VCC_WLAN_IO) */ -+ da9030_set_reg(LDO_17_SIMCP0, LDO_17_SIMCP0_LDO17_3V); -+ mdelay(200); -+ -+ /* Turn WLAN RF power on */ -+ pxa_gpio_mode(115 | GPIO_OUT | GPIO_DFLT_HIGH); -+ -+ /* Turn LDO17 on */ -+ da9030_set_reg(REG_CONTROL_1_17, -+ RC1_LDO17_EN| RC1_LDO16_EN | RC1_LDO15_EN | -+ RC1_LDO11_EN | RC1_LDO10_EN | RC1_BUCK2_EN); -+ mdelay(200); -+ -+ /* Turn on LDO19 */ -+ da9030_set_reg(REG_CONTROL_2_18, -+ RC2_SIMCP_EN | RC2_LDO18_EN | RC2_LDO19_EN); -+ -+ } -+ else { -+ /* FIXME: implement BGW shutdown */ -+ } -+ is_wlan_on = on; -+ -+ return 0; -+} -+ -+static struct em_x270_dev_data em_x270_wlan_data = { -+ .is_on = wlan_is_on, -+ .set_on = wlan_set_on, -+}; -+ -+static struct platform_device em_x270_wlan = { -+ .name = "wlan", -+ .id = -1, -+ .dev = { -+ .platform_data = &em_x270_wlan_data, -+ .release = em_x270_dev_release, -+ }, -+}; -+ -+static int gps_is_on(struct device *dev) -+{ -+ int val = da9030_get_reg(REG_CONTROL_1_97); -+ return !!(val & RC3_LDO3_EN); -+} -+ -+static int gps_set_on(struct device *dev, int on) -+{ -+ int val = da9030_get_reg(REG_CONTROL_1_97); -+ -+ if (on) -+ val |= RC3_LDO3_EN; -+ else -+ val &= ~RC3_LDO3_EN; -+ da9030_set_reg(REG_CONTROL_1_97, val); -+ -+ return 0; -+} -+ -+static struct em_x270_dev_data em_x270_gps_data = { -+ .is_on = gps_is_on, -+ .set_on = gps_set_on, -+}; -+ -+static struct platform_device em_x270_gps = { -+ .name = "gps", -+ .id = -1, -+ .dev = { -+ .platform_data = &em_x270_gps_data, -+ .release = em_x270_dev_release, -+ }, -+}; -+ -+static int usb_mode; -+static int usb_host_is_on(struct device *dev) -+{ -+ return usb_mode; -+} -+ -+static int usb_host_set_on(struct device *dev, int on) -+{ -+ if (on) { -+ da9030_set_reg(MISC_CONTROLB, MISCB_SESSION_VALID_ENABLE); -+ da9030_set_reg(USBPUMP, -+ USB_PUMP_EN_USBVEP | -+ USB_PUMP_EN_USBVE | -+ USB_PUMP_USBVE); -+ -+ /* enable port 2 transiever */ -+ UP2OCR = UP2OCR_HXS | UP2OCR_HXOE; -+ usb_mode = 1; -+ } -+ else { -+ UP2OCR = UP2OCR_DPPUE | UP2OCR_DPPUBE | UP2OCR_HXOE; -+ da9030_set_reg(USBPUMP, -+ USB_PUMP_EN_USBVEP | USB_PUMP_EN_USBVE); -+ usb_mode = 0; -+ } -+ -+ return 0; -+} -+ -+static struct em_x270_dev_data em_x270_usb_host_data = { -+ .is_on = usb_host_is_on, -+ .set_on = usb_host_set_on, -+}; -+ -+static struct platform_device em_x270_usb_host = { -+ .name = "usb_host", -+ .id = -1, -+ .dev = { -+ .platform_data = &em_x270_usb_host_data, -+ .release = em_x270_dev_release, -+ }, -+}; -+ -+static struct platform_device *em_x270_devices[] = { -+ &em_x270_gprs, -+ &em_x270_wlan, -+ &em_x270_gps, -+ &em_x270_usb_host, -+}; -+ -+static struct work_struct usb_work; -+static void usb_worker(struct work_struct *work) -+{ -+ usb_host_set_on(NULL, !pxa_gpio_get_value(21)); -+} -+ -+static irqreturn_t usb_irq_handler(int irq, void *regs) -+{ -+ schedule_work(&usb_work); -+ -+ pr_info("%s\n", __FUNCTION__); -+ return IRQ_HANDLED; -+} -+ -+static int em_x270_devices_init(void) -+{ -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(em_x270_devices); i++ ) { -+ ret = platform_device_register(em_x270_devices[i]); -+ if (ret) { -+ dev_dbg(&em_x270_devices[i]->dev, -+ "Registration failed: %d\n", ret); -+ continue; -+ } -+ -+ ret = device_create_file(&em_x270_devices[i]->dev, -+ &dev_attr_pwr_on); -+ if (ret) { -+ dev_dbg(&em_x270_devices[i]->dev, -+ "PWR_ON attribute failed: %d\n", ret); -+ } -+ -+ dev_dbg(&em_x270_devices[i]->dev, -+ "Registered PWR ON attribute\n"); -+ } -+ -+ /* setup USB detection irq */ -+ INIT_WORK(&usb_work, usb_worker); -+ set_irq_type(IRQ_GPIO(21), IRQT_BOTHEDGE); -+ ret = request_irq(IRQ_GPIO(21), usb_irq_handler, IRQF_DISABLED, -+ "usb detect", 0); -+ if (ret) { -+ pr_info("USB device detection disabled\n"); -+ } -+ else { -+ schedule_work(&usb_work); -+ } -+ -+ return 0; -+} -+ -+static void em_x270_devices_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(em_x270_devices); i++ ) { -+ device_remove_file(&em_x270_devices[i]->dev, -+ &dev_attr_pwr_on); -+ platform_device_unregister(em_x270_devices[i]); -+ } -+} -+ -+late_initcall(em_x270_devices_init); -+module_exit(em_x270_devices_exit); -+ -+MODULE_AUTHOR("Mike Rapoport"); -+MODULE_DESCRIPTION("Support for platfrom specific device attributes for EM-X270"); -+MODULE_LICENSE("GPL"); -diff --git a/arch/arm/mach-pxa/em-x270-lcd.c b/arch/arm/mach-pxa/em-x270-lcd.c -new file mode 100644 -index 0000000..437efe1 ---- /dev/null -+++ b/arch/arm/mach-pxa/em-x270-lcd.c -@@ -0,0 +1,223 @@ -+/* -+ * LCD initialization and backlight managemnet for EM-X270 -+ * -+ * Copyright (C) 2007 CompuLab, Ltd. -+ * Author: Igor Vaisbein -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "devices.h" -+ -+#define GPIO87_nPCE_2 87 /* Card Enable for Card Space (PXA27x) */ -+#define GPIO87_nPCE_2_MD (87 | GPIO_ALT_FN_1_IN) -+#define GPIO87_USB3_1_MD (87 | GPIO_ALT_FN_3_IN) -+#define GPIO87_SSPTXD2_MD (87 | GPIO_ALT_FN_1_OUT) -+#define GPIO87_SSFRM2_MD (87 | GPIO_ALT_FN_3_OUT) -+ -+#define LCCR4 __REG(0x44000010) -+ -+#define TD035STEE1_LCD_ID 0x2008 -+ -+static void em_x270_set_bl_intensity(int intensity) -+{ -+ da9030_set_wled((intensity != 0), intensity); -+} -+ -+struct corgibl_machinfo em_x270_bl_machinfo = { -+ .max_intensity = 0x7, -+ .default_intensity = 0x3, -+ .limit_mask = 0x1, -+ .set_bl_intensity = em_x270_set_bl_intensity, -+}; -+ -+static void em_x270_bl_release(struct device * dev) -+{ -+ -+} -+ -+static struct platform_device em_x270_bl = { -+ .name = "corgi-bl", -+ .dev = { -+ .release = em_x270_bl_release, -+ .parent = &pxa_device_fb.dev, -+ .platform_data = &em_x270_bl_machinfo, -+ }, -+ .id = -1, -+}; -+ -+/* -+ * Helper functions to access LCD throuhg SPI interface -+ */ -+static void set_ssp_9bit(void) -+{ -+ int temp; -+ SSCR0 = 0xFF208; -+ SSCR0 = 0xFF288; -+ SSCR1 = 0x40000018; -+ -+ while (SSSR & 0x8) -+ temp = SSDR; -+} -+ -+static void set_ssp_18bit(void) -+{ -+ int temp; -+ SSCR0 = 0x1FF201; -+ SSCR0 = 0x1FF281; -+ SSCR1 = 0x40000018; -+ while (SSSR & 0x8) -+ temp = SSDR; -+} -+ -+static void set_ssp_rcv(void) -+{ -+ int temp; -+ SSCR0 = 0x1FF20F; -+ SSCR0 = 0x1FF28F; -+ SSCR1 = 0x40000018; -+ while (SSSR & 0x8) -+ temp = SSDR; -+} -+ -+static void send_ssp_9bit(unsigned int value) -+{ -+ int temp; -+ SSDR = (value); -+ -+ asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); -+ -+ if (!(SSSR & 0x4)) -+ while ((SSSR & 0xf00) == 0) -+ ; -+ -+ while ((SSSR & 0xf00) != 0) -+ ; -+ while (SSSR & 0x10) -+ ; -+ while (SSSR & 0x8) -+ temp = SSDR; -+} -+ -+static void send_ssp_18bit(unsigned int value) -+{ -+ int temp; -+ SSDR = (value); -+ -+ asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); -+ -+ if (!(SSSR & 0x4)) -+ while ((SSSR & 0xf00) == 0) -+ ; -+ -+ while ((SSSR & 0xf00) != 0) -+ ; -+ while (SSSR & 0x10) -+ ; -+ while (SSSR & 0x8) -+ temp = SSDR; -+} -+ -+static unsigned int rcv_ssp_18bit(void) -+{ -+ SSDR = ((0x04) << 23); -+ asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); -+ if (!(SSSR & 0x4)) -+ while ((SSSR & 0xf00) == 0) -+ ; -+ while ((SSSR & 0xf00) != 0) -+ ; -+ while (SSSR & 0x10) -+ ; -+ return SSDR; -+} -+ -+/* LCD init sequence */ -+int em_x270_lcd_detect(void) -+{ -+ unsigned int data; -+ -+ /* Reset the LCD module */ -+ pxa_gpio_mode(GPIO87_nPCE_2 | GPIO_OUT); -+ GPCR(GPIO87_nPCE_2) |= GPIO_bit(GPIO87_nPCE_2); -+ mdelay(75); -+ GPSR(GPIO87_nPCE_2) |= GPIO_bit(GPIO87_nPCE_2); -+ mdelay(70); -+ -+ /* TD035STEE1 LCD_SSP initialization commands */ -+ set_ssp_9bit(); -+ send_ssp_9bit(0x000); -+ mdelay(5); -+ -+ send_ssp_9bit(0x000); -+ mdelay(5); -+ -+ send_ssp_9bit(0x000); -+ mdelay(5); -+ -+ set_ssp_18bit(); -+ send_ssp_18bit(0x17980); -+ mdelay(5); -+ -+ send_ssp_18bit(0x17F10); -+ mdelay(5); -+ -+ set_ssp_9bit(); -+ send_ssp_9bit(0x011); -+ mdelay(50); -+ -+ send_ssp_9bit(0x029); -+ mdelay(10); -+ -+ set_ssp_rcv(); -+ -+ /* Check for LCD ID, to enable the back-light */ -+ data = rcv_ssp_18bit(); -+ -+ if ((data & 0xFFFF) != TD035STEE1_LCD_ID) -+ return -ENODEV; -+ -+ /* enable backlight */ -+ da9030_set_wled(1, 2); -+ return 0; -+} -+ -+static int em_x270_lcd_init(void) -+{ -+ int ret; -+ pr_debug("%s\n", __FUNCTION__); -+ ret = em_x270_lcd_detect(); -+ if (ret) -+ return ret; -+ -+ /* make sure we keep LCCR4 with PCD=0 */ -+ LCCR4 = 0x0; -+ -+ return platform_device_register(&em_x270_bl); -+} -+ -+static void em_x270_lcd_exit(void) -+{ -+ pr_debug("%s\n", __FUNCTION__); -+ platform_device_unregister(&em_x270_bl); -+} -+ -+late_initcall(em_x270_lcd_init); -+module_exit(em_x270_lcd_exit); -+ -+MODULE_DESCRIPTION("EM-X270 backlight and LCD initialization driver"); -+MODULE_AUTHOR("Mike Rapoport"); -+MODULE_LICENSE("GPL"); -diff --git a/arch/arm/mach-pxa/em-x270-pm.c b/arch/arm/mach-pxa/em-x270-pm.c -new file mode 100644 -index 0000000..55ba4cd ---- /dev/null -+++ b/arch/arm/mach-pxa/em-x270-pm.c -@@ -0,0 +1,892 @@ -+/* -+ * Support for CompuLab EM-X270 platform power management -+ * -+ * Copyright (C) 2007 CompuLab, Ltd. -+ * Author: Mike Rapoport -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "../../../drivers/i2c/chips/da9030.h" -+ -+#include -+#include -+#include -+#include -+ -+#define DA9030_ADDR 0x92 -+ -+#define EM_X270_BATCHK_TIME_SUSPEND (10*60) /* 10 min */ -+ -+#define VOLTAGE_MAX_DESIGN 4200000 /* 4.2V in uV */ -+#define VOLTAGE_MIN_DESIGN 3000000 /* 3V in uV */ -+ -+#define REG2VOLT(x) ((((x) * 2650) >> 8) + 2650) -+#define VOLT2REG(x) ((((x) - 2650) << 8) / 2650) -+ -+#define REG2CURR(x) ((((x) * 24000) >> 8) / 15) -+ -+#define VCHARGE_MIN_THRESHOLD VOLT2REG(3200) -+#define VCHARGE_MAX_THRESHOLD VOLT2REG(5500) -+ -+#define VBAT_LOW_THRESHOLD VOLT2REG(3600) -+#define VBAT_CRIT_THRESHOLD VOLT2REG(3400) -+ -+#define VBAT_CHARGE_START VOLT2REG(4100) -+#define VBAT_CHARGE_STOP VOLT2REG(4200) -+#define VBAT_CHARGE_RESTART VOLT2REG(4000) -+ -+#define TBAT_LOW_THRESHOLD 197 /* 0oC */ -+#define TBAT_HIGH_THRESHOLD 78 /* 45oC */ -+#define TBAT_RESUME_THRESHOLD 100 /* 35oC */ -+ -+struct em_x270_charger; -+ -+struct em_x270_charger_ops { -+ void (*get_status)(struct em_x270_charger *charger); -+ void (*set_charge)(struct em_x270_charger *charger, int on); -+ -+ s32 (*da9030_get_reg)(u32 reg); -+ s32 (*da9030_set_reg)(u32 reg, u8 val); -+}; -+ -+struct em_x270_charger { -+ struct device *dev; -+ -+ struct power_supply bat; -+ struct da9030_adc_res adc; -+ struct delayed_work work; -+ -+ int interval; -+ -+ int da9030_status; -+ int da9030_fault; -+ int mA; -+ int mV; -+ int is_on; -+ -+ struct em_x270_charger_ops *ops; -+ -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *debug_file; -+#endif -+}; -+ -+static struct em_x270_charger *the_charger; -+ -+static unsigned short tbat_readings[] = { -+ 300, 244, 200, 178, 163, 152, 144, 137, 131, -+ 126, 122, 118, 114, 111, 108, 105, 103, 101, -+ 98, 96, 94, 93, 91, 89, 88, 86, 85, -+ 83, 82, 81, 79, 78, 77, 76, 75, 74, -+ 73, 72, 71, 70, 69, 68, 67, 67, 66, -+ 65, 64, 63, 63, 62, 61, 60, 60, 59, -+ 58, 58, 57, 57, 56, 55, 55, 54, 53, -+ 53, 52, 52, 51, 51, 50, 50, 49, 49, -+ 48, 48, 47, 47, 46, 46, 45, 45, 44, -+ 44, 43, 43, 42, 42, 41, 41, 41, 40, -+ 40, 39, 39, 38, 38, 38, 37, 37, 36, -+ 36, 35, 35, 35, 34, 34, 34, 33, 33, -+ 32, 32, 32, 31, 31, 30, 30, 30, 29, -+ 29, 29, 28, 28, 28, 27, 27, 26, 26, -+ 26, 25, 25, 25, 24, 24, 24, 23, 23, -+ 23, 22, 22, 21, 21, 21, 20, 20, 20, -+ 19, 19, 19, 18, 18, 18, 17, 17, 17, -+ 16, 16, 16, 15, 15, 14, 14, 14, 13, -+ 13, 13, 12, 12, 12, 11, 11, 11, 10, -+ 10, 10, 9, 9, 8, 8, 8, 7, 7, -+ 7, 6, 6, 5, 5, 5, 4, 4, 3, -+ 3, 3, 2, 2, 1, 1, 1, 0, 0, -+ -1, -1, -1, -2, -2, -3, -3, -4, -4, -+ -5, -5, -6, -6, -6, -7, -7, -8, -9, -+ -9, -10, -10, -11, -11, -12, -12, -13, -14, -+ -14, -15, -16, -16, -17, -18, -18, -19, -20, -+ -21, -21, -22, -23, -24, -25, -26, -27, -28, -+ -30, -31, -32, -34, -35, -37, -39, -41, -44, -+ -47, -50, -56, -64, -+}; -+ -+static inline int usb_host_on(void) -+{ -+ return !pxa_gpio_get_value(21); -+} -+ -+#ifdef CONFIG_DEBUG_FS -+ -+static int debug_show(struct seq_file *s, void *data) -+{ -+ struct em_x270_charger *charger = s->private; -+ -+ seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off"); -+ if (charger->da9030_status & CHRG_CHARGER_ENABLE) { -+ seq_printf(s, "iset = %dmA, vset = %dmV\n", -+ charger->mA, charger->mV); -+ } -+ -+ seq_printf(s, "vbat_res = %d (%dmV)\n", -+ charger->adc.vbat_res, REG2VOLT(charger->adc.vbat_res)); -+ seq_printf(s, "vbatmin_res = %d (%dmV)\n", -+ charger->adc.vbatmin_res, -+ REG2VOLT(charger->adc.vbatmin_res)); -+ seq_printf(s, "vbatmintxon = %d (%dmV)\n", -+ charger->adc.vbatmintxon, -+ REG2VOLT(charger->adc.vbatmintxon)); -+ seq_printf(s, "ichmax_res = %d (%dmA)\n", -+ charger->adc.ichmax_res, -+ REG2CURR(charger->adc.ichmax_res)); -+ seq_printf(s, "ichmin_res = %d (%dmA)\n", -+ charger->adc.ichmin_res, -+ REG2CURR(charger->adc.ichmin_res)); -+ seq_printf(s, "ichaverage_res = %d (%dmA)\n", -+ charger->adc.ichaverage_res, -+ REG2CURR(charger->adc.ichaverage_res)); -+ seq_printf(s, "vchmax_res = %d (%dmV)\n", -+ charger->adc.vchmax_res, -+ REG2VOLT(charger->adc.vchmax_res)); -+ seq_printf(s, "vchmin_res = %d (%dmV)\n", -+ charger->adc.vchmin_res, -+ REG2VOLT(charger->adc.vchmin_res)); -+ seq_printf(s, "tbat_res = %d (%doC)\n", charger->adc.tbat_res, -+ tbat_readings[charger->adc.tbat_res]); -+ seq_printf(s, "adc_in4_res = %d\n", charger->adc.adc_in4_res); -+ seq_printf(s, "adc_in5_res = %d\n", charger->adc.adc_in5_res); -+ -+ return 0; -+} -+ -+static int debug_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, debug_show, inode->i_private); -+} -+ -+static const struct file_operations debug_fops = { -+ .open = debug_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static struct dentry* em_x270_create_debugfs(struct em_x270_charger *charger) -+{ -+ charger->debug_file = debugfs_create_file("charger", 0666, 0, charger, -+ &debug_fops); -+ return charger->debug_file; -+} -+ -+static void em_x270_remove_debugfs(struct em_x270_charger *charger) -+{ -+ debugfs_remove(charger->debug_file); -+} -+#else -+#define em_x270_create_debugfs(x) NULL -+#define em_x270_remove_debugfs(x) do {} while(0) -+#endif -+ -+/*********************************************************************/ -+/* DA9030 access functions for suspend/resume */ -+#define DA_ADDR 0x49 -+static inline s32 __da9030_get_reg(u32 reg) -+{ -+ pr_info("%s: reg = %d\n", __FUNCTION__, reg); -+ return pxa_pwr_i2c_reg_read(DA_ADDR, reg); -+} -+ -+static inline s32 __da9030_set_reg(u32 reg, u8 val) -+{ -+ pr_info("%s: reg = %d, val = %d\n", __FUNCTION__, reg, val); -+ return pxa_pwr_i2c_reg_write(DA_ADDR, reg, val); -+} -+ -+/*********************************************************************/ -+/* helpers for charger state monnitor. Different version for stready -+ * state and suspended system -+ */ -+static void em_x270_get_charger_status(struct em_x270_charger *charger) -+{ -+ da9030_get_charger(&charger->is_on, &charger->mA, &charger->mV); -+ da9030_read_adc(&charger->adc); -+ charger->da9030_status = da9030_get_status(); -+ charger->da9030_fault = da9030_get_fault_log(); -+} -+ -+static void em_x270_set_charge(struct em_x270_charger *charger, int on) -+{ -+ if (on) { -+ pr_debug("%s: enabling charger\n", __FUNCTION__); -+ da9030_set_thresholds(TBAT_HIGH_THRESHOLD, -+ TBAT_RESUME_THRESHOLD, -+ TBAT_LOW_THRESHOLD, -+ VBAT_LOW_THRESHOLD); -+ da9030_set_reg(CCTR_CONTROL, CCTR_SET_8MIN); -+ da9030_set_charger(1, 1000, 4200); -+ da9030_set_led(3, 1, 0, 0, 0); -+ charger->is_on = 1; -+ } -+ else { -+ /* disable charger */ -+ pr_debug("%s: disabling charger\n", __FUNCTION__); -+ da9030_set_charger(0, 0, 0); -+ da9030_set_led(3, 0, 0, 0, 0); -+ charger->is_on = 0; -+ } -+} -+ -+static void em_x270_get_charger_status_suspend(struct em_x270_charger *charger) -+{ -+ s32 val; -+ -+ val = __da9030_get_reg(CHARGE_CONTROL); -+ charger->is_on = (val & CHRG_CHARGER_ENABLE) ? 1 : 0; -+ charger->mA = ((val >> 3) & 0xf) * 100; -+ charger->mV = (val & 0x7) * 50 + 4000; -+ -+ charger->adc.vbat_res = __da9030_get_reg(VBAT_RES); -+ charger->adc.vchmax_res = __da9030_get_reg(VCHMAX_RES); -+ charger->adc.vchmin_res = __da9030_get_reg(VCHMIN_RES); -+ charger->adc.tbat_res = __da9030_get_reg(TBAT_RES); -+ -+ charger->da9030_status = __da9030_get_reg(STATUS); -+ charger->da9030_fault = __da9030_get_reg(FAULT_LOG); -+} -+ -+static void em_x270_set_charge_suspend(struct em_x270_charger *charger, int on) -+{ -+ if (on) { -+ u8 val = 0; -+ int mA = 1000; -+ int mV = 4200; -+ -+ pr_debug("%s: enabling charger\n", __FUNCTION__); -+ val = CHRG_CHARGER_ENABLE; -+ val |= (mA / 100) << 3; -+ val |= (mV - 4000) / 50; -+ -+ __da9030_set_reg(CCTR_CONTROL, CCTR_SET_8MIN); -+ __da9030_set_reg(VBATMON, VBAT_LOW_THRESHOLD); -+ __da9030_set_reg(CHARGE_CONTROL, val); -+ charger->is_on = 1; -+ } -+ else { -+ /* disable charger */ -+ pr_debug("%s: disabling charger\n", __FUNCTION__); -+ __da9030_set_reg(CHARGE_CONTROL, 0); -+ charger->is_on = 0; -+ } -+} -+ -+static struct em_x270_charger_ops em_x270_charger_ops = { -+ .get_status = em_x270_get_charger_status, -+ .set_charge = em_x270_set_charge, -+ .da9030_get_reg = da9030_get_reg, -+ .da9030_set_reg = da9030_set_reg, -+}; -+ -+static struct em_x270_charger_ops em_x270_charger_ops_suspend = { -+ .get_status = em_x270_get_charger_status_suspend, -+ .set_charge = em_x270_set_charge_suspend, -+ .da9030_get_reg = __da9030_get_reg, -+ .da9030_set_reg = __da9030_set_reg, -+}; -+ -+/*********************************************************************/ -+/* charging state machine */ -+static void em_x270_check_charger_state(struct em_x270_charger *charger) -+{ -+ charger->ops->get_status(charger); -+ -+/* we wake or boot with external power on */ -+ if (!charger->is_on) { -+ if ((charger->da9030_status & STATUS_CHDET) && -+ (!usb_host_on()) && -+ (charger->adc.vbat_res < VBAT_CHARGE_START)) { -+ pr_debug("%s: vbat_res <= 4100\n", __FUNCTION__); -+ charger->ops->set_charge(charger, 1); -+ } -+ } -+ else { -+ if (charger->adc.vbat_res >= VBAT_CHARGE_STOP) { -+ pr_debug("%s: vbat_res >= 4200\n", __FUNCTION__); -+ charger->ops->set_charge(charger, 0); -+ charger->ops->da9030_set_reg(VBATMON, -+ VBAT_CHARGE_RESTART); -+ } -+ else if (charger->adc.vbat_res > VBAT_LOW_THRESHOLD) { -+ /* we are charging and passed LOW_THRESH, -+ so upate DA9030 VBAT threshold -+ */ -+ pr_debug("%s: vbat_res >= %d\n", __FUNCTION__, -+ REG2VOLT(VBAT_LOW_THRESHOLD)); -+ charger->ops->da9030_set_reg(VBATMON, -+ VBAT_LOW_THRESHOLD); -+ } -+ if (charger->adc.vchmax_res > VCHARGE_MAX_THRESHOLD || -+ charger->adc.vchmin_res < VCHARGE_MIN_THRESHOLD || -+ /* Tempreture readings are negative */ -+ charger->adc.tbat_res < TBAT_HIGH_THRESHOLD || -+ charger->adc.tbat_res > TBAT_LOW_THRESHOLD ) { -+ /* disable charger */ -+ pr_info("%s: thresholds fail\n", __FUNCTION__); -+ charger->ops->set_charge(charger, 0); -+ } -+ } -+} -+ -+static void em_x270_charging_monitor(struct work_struct *work) -+{ -+ struct em_x270_charger *charger; -+ -+ charger = container_of(work, struct em_x270_charger, work.work); -+ -+ em_x270_check_charger_state(charger); -+ -+ /* reschedule for the next time */ -+ schedule_delayed_work(&charger->work, charger->interval); -+} -+ -+void em_x270_battery_release(struct device * dev) -+{ -+} -+ -+struct em_x270_battery_thresh { -+ int voltage; -+ int percentage; -+}; -+ -+static struct em_x270_battery_thresh vbat_ranges[] = { -+ { 150, 100}, -+ { 149, 99}, -+ { 148, 98}, -+ { 147, 98}, -+ { 146, 97}, -+ { 145, 96}, -+ { 144, 96}, -+ { 143, 95}, -+ { 142, 94}, -+ { 141, 93}, -+ { 140, 92}, -+ { 139, 91}, -+ { 138, 90}, -+ { 137, 90}, -+ { 136, 89}, -+ { 135, 88}, -+ { 134, 88}, -+ { 133, 87}, -+ { 132, 86}, -+ { 131, 85}, -+ { 130, 83}, -+ { 129, 82}, -+ { 128, 81}, -+ { 127, 81}, -+ { 126, 80}, -+ { 125, 75}, -+ { 124, 74}, -+ { 123, 73}, -+ { 122, 70}, -+ { 121, 66}, -+ { 120, 65}, -+ { 119, 64}, -+ { 118, 64}, -+ { 117, 63}, -+ { 116, 59}, -+ { 115, 58}, -+ { 114, 57}, -+ { 113, 57}, -+ { 112, 56}, -+ { 111, 50}, -+ { 110, 49}, -+ { 109, 49}, -+ { 108, 48}, -+ { 107, 48}, -+ { 106, 33}, -+ { 105, 32}, -+ { 104, 32}, -+ { 103, 32}, -+ { 102, 31}, -+ { 101, 16}, -+ { 100, 15}, -+ { 99, 15}, -+ { 98, 15}, -+ { 97, 10}, -+ { 96, 9}, -+ { 95, 7}, -+ { 94, 3}, -+ { 93, 0}, -+}; -+ -+static enum power_supply_property em_x270_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_TECHNOLOGY, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_AVG, -+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_MANUFACTURER, -+ POWER_SUPPLY_PROP_MODEL_NAME, -+}; -+ -+static void em_x270_bat_check_status(struct em_x270_charger *charger, -+ union power_supply_propval *val) -+{ -+ /* FIXME: below code is very crude approximation of actual -+ states, we need to take into account voltage and current -+ measurements to determine actual charger state */ -+ if (charger->da9030_status & STATUS_CHDET) { -+ if (!usb_host_on()) { -+ if (charger->is_on) { -+ val->intval = POWER_SUPPLY_STATUS_CHARGING; -+ } -+ else { -+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ } -+ } -+ } -+ else { -+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING; -+ } -+} -+ -+static void em_x270_bat_check_health(struct em_x270_charger *charger, -+ union power_supply_propval *val) -+{ -+ if (charger->da9030_fault & FAULT_LOG_OVER_TEMP) { -+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; -+ } -+ else if (charger->da9030_fault & FAULT_LOG_VBAT_OVER) { -+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; -+ } -+ else { -+ val->intval = POWER_SUPPLY_HEALTH_GOOD; -+ } -+} -+ -+static int vbat_interpolate(int reg) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(vbat_ranges); i++ ) -+ if (vbat_ranges[i].voltage == reg) { -+ pr_debug("%s: voltage = %d, percentage = %d\n", -+ __FUNCTION__, vbat_ranges[i].voltage, -+ vbat_ranges[i].percentage); -+ return vbat_ranges[i].percentage; -+ } -+ -+ return 0; -+} -+ -+static int em_x270_bat_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ u32 reg; -+ struct em_x270_charger *charger; -+ charger = container_of(psy, struct em_x270_charger, bat); -+ -+ switch(psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ em_x270_bat_check_status(charger, val); -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ em_x270_bat_check_health(charger, val); -+ break; -+ case POWER_SUPPLY_PROP_TECHNOLOGY: -+ val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ val->intval = VOLTAGE_MAX_DESIGN; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ val->intval = VOLTAGE_MIN_DESIGN; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ reg = charger->adc.vbat_res; -+ /* V = (reg / 256) * 2.65 + 2.65 (V) */ -+ val->intval = ((reg * 2650000) >> 8) + 2650000; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_AVG: -+ reg = charger->adc.ichaverage_res; -+ val->intval = reg; /* reg */ -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ reg = charger->adc.vbat_res; -+ val->intval = vbat_interpolate(reg); -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ reg = charger->adc.tbat_res; -+ val->intval = tbat_readings[reg]; -+ break; -+ case POWER_SUPPLY_PROP_MANUFACTURER: -+ val->strval = "MaxPower"; -+ pr_debug("%s: MFG = %s\n", __FUNCTION__, val->strval); -+ break; -+ case POWER_SUPPLY_PROP_MODEL_NAME: -+ val->strval = "LP555597P6H-FPS"; -+ pr_debug("%s: MODEL = %s\n", __FUNCTION__, val->strval); -+ break; -+ default: break; -+ } -+ -+ return 0; -+} -+ -+static void em_x270_setup_battery(struct power_supply *bat) -+{ -+ bat->name = "em-x270-battery"; -+ bat->type = POWER_SUPPLY_TYPE_BATTERY; -+ bat->properties = em_x270_bat_props; -+ bat->num_properties = ARRAY_SIZE(em_x270_bat_props); -+ bat->get_property = em_x270_bat_get_property; -+ bat->use_for_apm = 1; -+}; -+ -+static void em_x270_chiover_callback(int event, void *_charger) -+{ -+ /* disable charger */ -+ struct em_x270_charger *charger = _charger; -+/* pr_info("%s\n", __FUNCTION__); */ -+ em_x270_set_charge(charger, 0); -+} -+ -+static void em_x270_tbat_callback(int event, void *_charger) -+{ -+ /* disable charger */ -+ struct em_x270_charger *charger = _charger; -+/* pr_info("%s\n", __FUNCTION__); */ -+ em_x270_set_charge(charger, 0); -+} -+ -+static void em_x270_vbat_callback(int event, void *_charger) -+{ -+ struct em_x270_charger *charger = _charger; -+ da9030_read_adc(&charger->adc); -+ -+ if (!charger->is_on) { -+ if (charger->adc.vbat_res < VBAT_LOW_THRESHOLD) { -+ /* set VBAT threshold for critical */ -+ da9030_set_reg(VBATMON, VBAT_CRIT_THRESHOLD); -+ da9030_set_reg(VBATMON_1, VBAT_CRIT_THRESHOLD); -+ apm_queue_event(APM_LOW_BATTERY); -+ } -+ else if (charger->adc.vbat_res < VBAT_CRIT_THRESHOLD) { -+ /* notify the system of battery critical */ -+ apm_queue_event(APM_CRITICAL_SUSPEND); -+ } -+ } -+} -+ -+static void em_x270_chdet_callback(int event, void *_charger) -+{ -+ struct em_x270_charger *charger = _charger; -+ int status = da9030_get_status(); -+ pr_info("%s\n", __FUNCTION__); -+ -+/* em_x270_check_charger_state(charger); */ -+ -+ /* check if we have "real" charger or our own USB pump */ -+ if (!usb_host_on()) -+ em_x270_set_charge(charger, !!(status & CHRG_CHARGER_ENABLE)); -+} -+ -+static int em_x270_battery_probe(struct platform_device *pdev) -+{ -+ struct em_x270_charger *charger; -+ -+ pr_debug("%s\n", __FUNCTION__); -+ charger = kzalloc(sizeof(*charger), GFP_KERNEL); -+ if (charger == NULL) { -+ return -ENOMEM; -+ } -+ -+ the_charger = charger; -+ -+ charger->dev = &pdev->dev; -+ -+ charger->ops = &em_x270_charger_ops; -+ -+ charger->interval = 10 * HZ; /* 10 seconds between monotor runs */ -+ em_x270_setup_battery(&charger->bat); -+ -+ platform_set_drvdata(pdev, charger); -+ -+ da9030_enable_adc(); -+ -+ INIT_DELAYED_WORK(&charger->work, em_x270_charging_monitor); -+ schedule_delayed_work(&charger->work, charger->interval); -+ -+ charger->debug_file = em_x270_create_debugfs(charger); -+ -+ em_x270_setup_battery(&charger->bat); -+ -+ da9030_register_callback(DA9030_IRQ_CHDET, -+ em_x270_chdet_callback, -+ charger); -+ da9030_register_callback(DA9030_IRQ_VBATMON, -+ em_x270_vbat_callback, -+ charger); -+ -+ /* critical condition events */ -+ da9030_register_callback(DA9030_IRQ_CHIOVER, -+ em_x270_chiover_callback, -+ charger); -+ da9030_register_callback(DA9030_IRQ_TBAT, -+ em_x270_tbat_callback, -+ charger); -+ -+ da9030_set_thresholds(TBAT_HIGH_THRESHOLD, -+ TBAT_RESUME_THRESHOLD, -+ TBAT_LOW_THRESHOLD, -+ VBAT_LOW_THRESHOLD); -+ -+ power_supply_register(&pdev->dev, &charger->bat); -+ -+ return 0; -+} -+ -+static int em_x270_battery_remove(struct platform_device *dev) -+{ -+ struct em_x270_charger *charger = platform_get_drvdata(dev); -+ -+ pr_debug("%s\n", __FUNCTION__); -+ em_x270_remove_debugfs(charger); -+ cancel_delayed_work(&charger->work); -+ power_supply_unregister(&charger->bat); -+ -+ kfree(charger); -+ the_charger = NULL; -+ -+ return 0; -+} -+ -+static int em_x270_battery_suspend(struct platform_device *pdev, -+ pm_message_t state) -+{ -+ pr_info("%s\n", __FUNCTION__); -+ da9030_set_reg(REG_CONTROL_1_97, RC3_BUCK_EN | RC3_LDO6_EN); -+ da9030_set_reg(REG_CONTROL_2_98, 0); -+ da9030_set_reg(REG_CONTROL_2_18,RC2_LDO18_EN); -+ da9030_set_reg(REG_CONTROL_1_17, -+ RC1_LDO16_EN | RC1_LDO15_EN | RC1_BUCK2_EN); -+ da9030_set_reg(WLED_CONTROL, 0); -+ -+ da9030_set_reg(LED_1_CONTROL, 0); -+ da9030_set_reg(LED_4_CONTROL, 0); -+ -+ return 0; -+} -+ -+extern int em_x270_lcd_detect(void); -+static int em_x270_battery_resume(struct platform_device *pdev) -+{ -+ pr_info("%s\n", __FUNCTION__); -+ -+ da9030_set_reg(LED_1_CONTROL, 0xff); -+ da9030_set_reg(LED_4_CONTROL, 0xff); -+ -+ da9030_set_reg(REG_CONTROL_1_97, -+ RC3_BUCK_EN | RC3_LDO1_EN | RC3_LDO2_EN | -+ RC3_LDO3_EN | RC3_LDO6_EN | RC3_LDO7_EN); -+ da9030_set_reg(REG_CONTROL_2_98, -+ RC4_SIMCP_ENABLE | RC4_LDO11_EN | -+ RC4_LDO9_EN | RC4_LDO8_EN); -+ da9030_set_reg(REG_CONTROL_2_18, -+ RC2_SIMCP_EN | RC2_LDO18_EN | RC2_LDO19_EN); -+ da9030_set_reg(REG_CONTROL_1_17, -+ RC1_LDO17_EN| RC1_LDO16_EN | RC1_LDO15_EN | -+ RC1_LDO11_EN | RC1_LDO10_EN | RC1_BUCK2_EN); -+ -+ if (em_x270_lcd_detect() != 0) -+ pr_info("%s: LCD resume failed\n", __FUNCTION__); -+ -+ return 0; -+} -+ -+static struct platform_driver em_x270_battery_driver = { -+ .driver = { -+ .name = "em-x270-battery", -+ .owner = THIS_MODULE, -+ }, -+ .probe = em_x270_battery_probe, -+ .remove = em_x270_battery_remove, -+ -+ .suspend_late = em_x270_battery_suspend, -+ .resume_early = em_x270_battery_resume, -+}; -+ -+/**************************************************************************/ -+/* global patform power management */ -+/**************************************************************************/ -+/* suspend/resume button */ -+static irqreturn_t em_x270_suspend_irq(int irq, void *data) -+{ -+ apm_queue_event(APM_USER_SUSPEND); -+ return IRQ_HANDLED; -+} -+ -+static void em_x270_goto_sleep(suspend_state_t state, -+ unsigned long alarm_time, -+ unsigned int alarm_enable) -+{ -+ pr_info("%s\n", __FUNCTION__); -+ -+ the_charger->ops = &em_x270_charger_ops_suspend; -+ -+ RTSR &= RTSR_ALE; -+ RTAR = RCNR + EM_X270_BATCHK_TIME_SUSPEND; -+ -+ pxa_pm_enter(state); -+} -+ -+static int em_x270_enter_suspend(unsigned long alarm_time, -+ unsigned int alarm_enable) -+{ -+ s32 status = 0; -+ s32 event_a, event_b; -+ int ret; -+ int retry = 10; -+ pr_info("%s\n", __FUNCTION__); -+ -+ /* make sure power I2C state is consistent */ -+ PWRICR &= ~ICR_IUE; -+ -+ if ((PEDR & PWER_GPIO1)) { -+ /* button pressed */ -+ /* clear pending event to avoid interrupt*/ -+ PEDR &= ~PWER_GPIO1; -+ GEDR0 &= ~GPIO_bit(1); -+ -+ ret = 0; -+ } -+ else if ((PEDR & PWER_RTC)) { -+ PEDR &= ~PWER_RTC; -+ pr_debug("%s: timer alarm\n", __FUNCTION__); -+ em_x270_check_charger_state(the_charger); -+ ret = 1; -+ } -+ else if ((PEDR & PWER_GPIO0)) { -+ PEDR &= ~PWER_GPIO0; -+ GEDR0 &= ~GPIO_bit(0); -+ -+ /* we woke up because of DA9030 event */ -+ do { -+ status = the_charger->ops->da9030_get_reg(STATUS); -+ udelay(1000); -+ } while (status < 0 && retry--); -+ -+ the_charger->da9030_status = status; -+ event_a = the_charger->ops->da9030_get_reg(EVENT_A); -+ event_b = the_charger->ops->da9030_get_reg(EVENT_B); -+ -+ pr_info("%s: DA9030 wakeup: status: %x, ev_a: %x, ev_b: %x\n", -+ __FUNCTION__, the_charger->da9030_status, -+ event_a, event_b); -+ -+/* if ((the_charger->da9030_status & STATUS_CHDET)) { */ -+ if (event_a & EVENT_A_CHDET) { -+ pr_info("%s: EVENT_A_CHDET\n", __FUNCTION__); -+ em_x270_check_charger_state(the_charger); -+ } -+ else { -+ pr_info("%s: What the hell?\n", __FUNCTION__); -+ } -+ -+ ret = 1; -+ } -+ else { -+ /* wake up is not DA9030, so continue and let battery -+ driver check the charger state */ -+ ret = 0; -+ } -+ -+ /* get back to sleep */ -+ if (ret) -+ em_x270_goto_sleep(PM_SUSPEND_MEM, alarm_time, alarm_enable); -+ -+ return ret; -+} -+ -+static int em_x270_pm_enter(suspend_state_t state) -+{ -+ unsigned long alarm_time = RTAR; -+ unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0); -+ -+ /* pre-suspend */ -+ pr_info("suspending emma\n"); -+ pxa_gpio_mode(38 | GPIO_OUT | GPIO_DFLT_HIGH); -+ -+ em_x270_goto_sleep(state, alarm_time, alarm_status); -+ -+ /* check if we were resumed because of charger events */ -+ while (em_x270_enter_suspend(alarm_time, alarm_status)) -+ {} -+ -+ /* make sure power I2C state is consistent */ -+ PWRICR &= ~ICR_IUE; -+ -+ /* resume */ -+ pr_info("emma is resumed\n"); -+ the_charger->ops = &em_x270_charger_ops; -+ -+ return 0; -+} -+ -+static struct pm_ops em_x270_pm_ops = { -+ .enter = em_x270_pm_enter, -+ .valid = pm_valid_only_mem, -+}; -+ -+static int em_x270_pm_init(void) -+{ -+ int ret; -+ pm_set_ops(&em_x270_pm_ops); -+ -+ set_irq_type(IRQ_GPIO(1), IRQT_RISING); -+ -+ ret = platform_driver_register(&em_x270_battery_driver); -+ if (ret) -+ return ret; -+ -+ ret = request_irq(IRQ_GPIO(1), em_x270_suspend_irq, IRQF_DISABLED, -+ "suspend button", 0); -+ if (ret) { -+ platform_driver_unregister(&em_x270_battery_driver); -+ } -+ -+ return ret; -+} -+ -+static void em_x270_pm_exit(void) -+{ -+ free_irq(IRQ_GPIO(1), em_x270_suspend_irq); -+ platform_driver_unregister(&em_x270_battery_driver); -+} -+ -+/* make sure I2C is already running */ -+late_initcall(em_x270_pm_init); -+module_exit(em_x270_pm_exit); -+ -+MODULE_DESCRIPTION("EM-X270 power manager"); -+MODULE_AUTHOR("Mike Rapoport"); -+MODULE_LICENSE("GPL"); -diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c -index 3d0ad50..402d792 100644 ---- a/arch/arm/mach-pxa/em-x270.c -+++ b/arch/arm/mach-pxa/em-x270.c -@@ -18,20 +18,26 @@ - #include - #include - --#include -+#include -+#include - -+#include - #include - - #include - #include - #include - #include -+#include - #include - -+#include -+ -+#include -+ - #include "generic.h" - - /* GPIO IRQ usage */ --#define EM_X270_MMC_PD (105) - #define EM_X270_ETHIRQ IRQ_GPIO(41) - #define EM_X270_MMC_IRQ IRQ_GPIO(13) - -@@ -213,6 +219,68 @@ static struct platform_device em_x270_nand = { - } - }; - -+/* DA9030 */ -+static struct i2c_board_info em_x270_pmic_info = { -+ .driver_name = "da9030", -+ .type = "pmic", -+ .addr = 0x49, -+ .irq = IRQ_GPIO(0), -+}; -+ -+/* Keypad */ -+/* The Demo KeyPad has the following mapping: -+ * (0,0) (1,2) (2,1) -+ * (0,2) (1,1) (2,0) -+ * (0,1) (1,0) (2,2) -+ */ -+static struct pxa27x_keyboard_platform_data em_x270_kbd = { -+ .nr_rows = 3, -+ .nr_cols = 3, -+ .keycodes = { -+ { /* row 0 */ -+ -1, -+ -1, -+ KEY_LEFT, -+ }, -+ { /* row 1 */ -+ KEY_UP, -+ KEY_ENTER, -+ KEY_DOWN -+ }, -+ { /* row 2 */ -+ KEY_RIGHT, -+ -1, -+ -1 -+ }, -+ }, -+ .gpio_modes = { -+ (100 | GPIO_ALT_FN_1_IN), -+ (101 | GPIO_ALT_FN_1_IN), -+ (102 | GPIO_ALT_FN_1_IN), -+ (103 | GPIO_ALT_FN_2_OUT), -+ (104 | GPIO_ALT_FN_2_OUT), -+ (105 | GPIO_ALT_FN_2_OUT), -+ }, -+}; -+ -+static struct platform_device em_x270_pxa_keypad = { -+ .name = "pxa27x-keyboard", -+ .id = -1, -+ .dev = { -+ .platform_data = &em_x270_kbd, -+ }, -+}; -+ -+static struct platform_device em_x270_battery_device = { -+ .name = "em-x270-battery", -+ .id = -1, -+}; -+ -+static struct platform_device em_x270_led_device = { -+ .name = "em-x270-led", -+ .id = -1, -+}; -+ - /* platform devices */ - static struct platform_device *platform_devices[] __initdata = { - &em_x270_dm9k, -@@ -220,6 +288,9 @@ static struct platform_device *platform_devices[] __initdata = { - &em_x270_ts, - &em_x270_rtc, - &em_x270_nand, -+ &em_x270_pxa_keypad, -+ &em_x270_battery_device, -+ &em_x270_led_device, - }; - - -@@ -241,6 +312,33 @@ static struct pxaohci_platform_data em_x270_ohci_platform_data = { - .init = em_x270_ohci_init, - }; - -+/* -+ * USB Client (Gadget/UDC) -+ */ -+static void em_x270_udc_command(int cmd) -+{ -+ switch(cmd) { -+ case PXA2XX_UDC_CMD_CONNECT: -+ UP2OCR = UP2OCR_HXOE | UP2OCR_DMPUE | UP2OCR_DMPUBE; -+ break; -+ case PXA2XX_UDC_CMD_DISCONNECT: -+/* UP2OCR = UP2OCR_HXS | UP2OCR_HXOE; */ -+ //UP2OCR = UP2OCR_HXOE | UP2OCR_DMPUE | UP2OCR_DMPUBE; -+ break; -+ } -+} -+ -+static int em_x270_udc_detect(void) -+{ -+ return 1; -+} -+ -+static struct pxa2xx_udc_mach_info em_x270_udc_info __initdata = { -+ .udc_is_connected = em_x270_udc_detect, -+ .udc_command = em_x270_udc_command, -+}; -+ -+ - - static int em_x270_mci_init(struct device *dev, - irq_handler_t em_x270_detect_int, -@@ -256,9 +354,6 @@ static int em_x270_mci_init(struct device *dev, - pxa_gpio_mode(GPIO110_MMCDAT2_MD); - pxa_gpio_mode(GPIO111_MMCDAT3_MD); - -- /* EM-X270 uses GPIO13 as SD power enable */ -- pxa_gpio_mode(EM_X270_MMC_PD | GPIO_OUT); -- - err = request_irq(EM_X270_MMC_IRQ, em_x270_detect_int, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, - "MMC card detect", data); -@@ -313,12 +408,19 @@ static struct pxafb_mach_info em_x270_lcd = { - .num_modes = 1, - .cmap_inverse = 0, - .cmap_static = 0, -- .lccr0 = LCCR0_PAS, -- .lccr3 = LCCR3_PixClkDiv(0x01) | LCCR3_Acb(0xff), -+ -+ .lccr0 = LCCR0_Act, -+ .lccr3 = LCCR3_PixFlEdg, - }; - - static void __init em_x270_init(void) - { -+ /* register PMIC */ -+ i2c_register_board_info(1, &em_x270_pmic_info, 1); -+ -+ /* setup DA9030 irq */ -+ set_irq_type(IRQ_GPIO(0), IRQT_FALLING); -+ - /* setup LCD */ - set_pxa_fb_info(&em_x270_lcd); - -@@ -329,6 +431,8 @@ static void __init em_x270_init(void) - pxa_set_mci_info(&em_x270_mci_platform_data); - pxa_set_ohci_info(&em_x270_ohci_platform_data); - -+ pxa_set_udc_info(&em_x270_udc_info); -+ - /* setup STUART GPIOs */ - pxa_gpio_mode(GPIO46_STRXD_MD); - pxa_gpio_mode(GPIO47_STTXD_MD); -@@ -341,9 +445,16 @@ static void __init em_x270_init(void) - - /* Setup interrupt for dm9000 */ - set_irq_type(EM_X270_ETHIRQ, IRQT_RISING); -+ -+ PCFR = 0x6; -+ PSLR = 0xff400000; -+ PMCR = 0x00000005; -+ PWER = 0x80000003; -+ PFER = 0x00000003; -+ PRER = 0x00000000; - } - --MACHINE_START(EM_X270, "Compulab EM-x270") -+MACHINE_START(EM_X270, "Compulab EM-X270") - .boot_params = 0xa0000100, - .phys_io = 0x40000000, - .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, -diff --git a/arch/arm/mach-pxa/pwr-i2c.c b/arch/arm/mach-pxa/pwr-i2c.c -new file mode 100644 -index 0000000..8a501c4 ---- /dev/null -+++ b/arch/arm/mach-pxa/pwr-i2c.c -@@ -0,0 +1,539 @@ -+/* -+ * (C) Copyrihgt 2007 CompuLab, Ltd. -+ * Mike Rapoport -+ * Adaptation of U-Boot I2C driver for PXA. -+ * -+ * (C) Copyright 2000 -+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it -+ * -+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH -+ * Marius Groeger -+ * -+ * (C) Copyright 2003 Pengutronix e.K. -+ * Robert Schwebel -+ * -+ * See file CREDITS for list of people who contributed to this -+ * project. -+ * -+ * 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 -+ * -+ * Back ported to the 8xx platform (from the 8260 platform) by -+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01. -+ */ -+ -+/* #define DEBUG */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) -+#define I2C_ISR_INIT 0x7FF -+ -+/* Shall the current transfer have a start/stop condition? */ -+#define I2C_COND_NORMAL 0 -+#define I2C_COND_START 1 -+#define I2C_COND_STOP 2 -+ -+/* Shall the current transfer be ack/nacked or being waited for it? */ -+#define I2C_ACKNAK_WAITACK 1 -+#define I2C_ACKNAK_SENDACK 2 -+#define I2C_ACKNAK_SENDNAK 4 -+ -+/* Specify who shall transfer the data (master or slave) */ -+#define I2C_READ 0 -+#define I2C_WRITE 1 -+ -+/* All transfers are described by this data structure */ -+struct i2c_msg { -+ u8 condition; -+ u8 acknack; -+ u8 direction; -+ u8 data; -+}; -+ -+/** -+ * pxa_pwr_i2c_transfer: - reset the host controller -+ * -+ */ -+/* static void pxa_pwr_i2c_reset(void) */ -+/* { */ -+/* int i; */ -+ -+/* /\* CKEN |= CKEN_PWRI2C; *\/ */ -+/* /\* PWRICR |= PCFR_PI2C_EN; *\/ */ -+ -+/* /\* /\\* delay 250ms *\\/ *\/ */ -+/* /\* for (i = 0; i < 250; i++) *\/ */ -+/* /\* udelay(1000); *\/ */ -+ -+/* /\* PWRICR &= ~(ICR_MA | ICR_START | ICR_STOP); *\/ */ -+/* /\* PWRICR |= ICR_UR; *\/ */ -+/* /\* PWRISR = 0x7ff; *\/ */ -+ -+/* /\* PWRICR &= ~ICR_UR; *\/ */ -+/* /\* PWRICR = ICR_GCD | ICR_SCLE; *\/ */ -+/* /\* PWRICR |= ICR_IUE; *\/ */ -+/* /\* PWRICR |= 0x8000; *\/ */ -+ -+/* /\* udelay(1000); *\/ */ -+ -+/* return; */ -+ -+/* PWRICR &= ~ICR_IUE; /\* disable unit *\/ */ -+/* PWRICR |= ICR_UR; /\* reset the unit *\/ */ -+/* udelay(100); */ -+/* PWRICR &= ~ICR_IUE; /\* disable unit *\/ */ -+ -+/* CKEN |= CKEN_PWRI2C; */ -+/* PCFR |= PCFR_PI2C_EN; */ -+ -+/* PWRICR = I2C_ICR_INIT; /\* set control register values *\/ */ -+/* PWRISR = I2C_ISR_INIT; /\* set clear interrupt bits *\/ */ -+/* PWRICR |= ICR_IUE; /\* enable unit *\/ */ -+/* udelay(100); */ -+/* } */ -+ -+static void pwr_i2c_abort() -+{ -+ unsigned long timeout = 250000; -+ unsigned long time = 0; -+ -+ while ((time < timeout) && (PWRIBMR & 0x1) == 0) { -+ unsigned long icr = PWRICR; -+ -+ icr &= ~ICR_START; -+ icr |= ICR_ACKNAK | ICR_STOP | ICR_TB; -+ -+ PWRICR = icr; -+ -+ udelay(1000); -+ time += 1000; -+ } -+ -+ PWRICR &= ~(ICR_MA | ICR_START | ICR_STOP); -+} -+ -+static void pxa_pwr_i2c_reset(void) -+{ -+ pr_debug("Resetting I2C Controller Unit\n"); -+ -+ /* abort any transfer currently under way */ -+ pwr_i2c_abort(); -+ -+ /* reset according to 9.8 */ -+ PWRICR = ICR_UR; -+ PWRISR = I2C_ISR_INIT; -+ PWRISR &= ~ICR_UR; -+ -+ /* set control register values */ -+ PWRICR = I2C_ICR_INIT; -+ -+ /* enable unit */ -+ PWRICR |= ICR_IUE; -+ udelay(100); -+ -+/* CKEN |= CKEN_PWRI2C; */ -+/* PCFR |= PCFR_PI2C_EN; */ -+} -+ -+/** -+ * i2c_isr_set_cleared: - wait until certain bits of the I2C status register -+ * are set and cleared -+ * -+ * @return: 1 in case of success, 0 means timeout (no match within 10 ms). -+ */ -+static int pxa_pwr_i2c_isr_set_cleared(unsigned long set_mask, -+ unsigned long cleared_mask) -+{ -+ int timeout = 10000; -+ -+ while (((PWRISR & set_mask) != set_mask) -+ || ((PWRISR & cleared_mask) != 0)) { -+ udelay(10); -+ if (timeout-- < 0) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/** -+ * pxa_pwr_i2c_transfer: - Transfer one byte over the i2c bus -+ * -+ * This function can tranfer a byte over the i2c bus in both directions. -+ * It is used by the public API functions. -+ * -+ * @return: 0: transfer successful -+ * -EINVAL: message is empty -+ * -ETIMEDOUT: transmit timeout -+ * -E: ACK missing -+ * -ETIMEDOUT: receive timeout -+ * -EINVAL: illegal parameters -+ * -EBUSY: bus is busy and couldn't be aquired -+ */ -+int pxa_pwr_i2c_transfer(struct i2c_msg *msg) -+{ -+ int ret; -+ -+ if (!msg) -+ goto transfer_error_msg_empty; -+ -+ switch (msg->direction) { -+ case I2C_WRITE: -+ /* check if bus is not busy */ -+/* if (!pxa_pwr_i2c_isr_set_cleared(0, (ISR_IBB | ISR_UB))) */ -+/* goto transfer_error_bus_busy; */ -+ -+ /* start transmission */ -+ PWRICR &= ~ICR_START; -+ PWRICR &= ~ICR_STOP; -+ PWRIDBR = msg->data; -+ if (msg->condition == I2C_COND_START) -+ PWRICR |= ICR_START; -+ if (msg->condition == I2C_COND_STOP) -+ PWRICR |= ICR_STOP; -+ if (msg->acknack == I2C_ACKNAK_SENDNAK) -+ PWRICR |= ICR_ACKNAK; -+ if (msg->acknack == I2C_ACKNAK_SENDACK) -+ PWRICR &= ~ICR_ACKNAK; -+ PWRICR &= ~ICR_ALDIE; -+ PWRICR |= ICR_TB; -+ -+ /* transmit register empty? */ -+ if (!pxa_pwr_i2c_isr_set_cleared(ISR_ITE, 0)) -+ goto transfer_error_transmit_timeout; -+ -+ /* clear 'transmit empty' state */ -+ PWRISR |= ISR_ITE; -+ -+ /* wait for ACK from slave */ -+ if (msg->acknack == I2C_ACKNAK_WAITACK) -+ if (!pxa_pwr_i2c_isr_set_cleared(0, ISR_ACKNAK)) -+ goto transfer_error_ack_missing; -+ break; -+ case I2C_READ: -+ /* check if bus is not busy */ -+/* if (!pxa_pwr_i2c_isr_set_cleared(0, ISR_IBB)) */ -+/* goto transfer_error_bus_busy; */ -+ -+ /* start receive */ -+ PWRICR &= ~ICR_START; -+ PWRICR &= ~ICR_STOP; -+ if (msg->condition == I2C_COND_START) -+ PWRICR |= ICR_START; -+ if (msg->condition == I2C_COND_STOP) -+ PWRICR |= ICR_STOP; -+ if (msg->acknack == I2C_ACKNAK_SENDNAK) -+ PWRICR |= ICR_ACKNAK; -+ if (msg->acknack == I2C_ACKNAK_SENDACK) -+ PWRICR &= ~ICR_ACKNAK; -+ PWRICR &= ~ICR_ALDIE; -+ PWRICR |= ICR_TB; -+ -+ /* receive register full? */ -+ if (!pxa_pwr_i2c_isr_set_cleared(ISR_IRF, 0)) -+ goto transfer_error_receive_timeout; -+ -+ msg->data = PWRIDBR; -+ -+ /* clear 'receive empty' state */ -+ PWRISR |= ISR_IRF; -+ -+ break; -+ default: -+ goto transfer_error_illegal_param; -+ -+ } -+ -+ return 0; -+ -+transfer_error_msg_empty: -+ pr_debug("%s: error: 'msg' is empty\n", __FUNCTION__); -+ ret = -1; -+ goto i2c_transfer_finish; -+ -+transfer_error_transmit_timeout: -+ pr_debug("%s: error: transmit timeout\n", __FUNCTION__); -+ ret = -2; -+ goto i2c_transfer_finish; -+ -+transfer_error_ack_missing: -+ pr_debug("%s: error: ACK missing\n", __FUNCTION__); -+ ret = -3; -+ goto i2c_transfer_finish; -+ -+transfer_error_receive_timeout: -+ pr_debug("%s: error: receive timeout\n", __FUNCTION__); -+ ret = -4; -+ goto i2c_transfer_finish; -+ -+transfer_error_illegal_param: -+ pr_debug("%s: error: illegal parameters\n", __FUNCTION__); -+ ret = -5; -+ goto i2c_transfer_finish; -+ -+transfer_error_bus_busy: -+ pr_debug("%s: error: bus is busy\n", __FUNCTION__); -+ ret = -6; -+ goto i2c_transfer_finish; -+ -+i2c_transfer_finish: -+ pr_debug("%s: ISR: 0x%04x\n", __FUNCTION__, ISR); -+ return ret; -+} -+ -+/* ------------------------------------------------------------------------ */ -+/* API Functions */ -+/* ------------------------------------------------------------------------ */ -+/** -+ * i2c_probe: - Test if a chip answers for a given i2c address -+ * -+ * @chip: address of the chip which is searched for -+ * @return: 0 if a chip was found, -1 otherwhise -+ */ -+int pxa_pwr_i2c_probe(u8 chip) -+{ -+ struct i2c_msg msg; -+ int ret; -+ -+ pxa_pwr_i2c_reset(); -+ -+ msg.condition = I2C_COND_START; -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = (chip << 1) + 1; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ -+ msg.condition = I2C_COND_STOP; -+ msg.acknack = I2C_ACKNAK_SENDNAK; -+ msg.direction = I2C_READ; -+ msg.data = 0x00; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ -+ return 0; -+} -+ -+/** -+ * i2c_read: - Read multiple bytes from an i2c device -+ * -+ * The higher level routines take into account that this function is only -+ * called with len < page length of the device (see configuration file) -+ * -+ * @chip: address of the chip which is to be read -+ * @addr: i2c data address within the chip -+ * @alen: length of the i2c data address (1..2 bytes) -+ * @buffer: where to write the data -+ * @len: how much byte do we want to read -+ * @return: 0 in case of success -+ */ -+int pxa_pwr_i2c_read(u8 chip, uint addr, int alen, u8 * buffer, int len) -+{ -+ struct i2c_msg msg; -+ u8 addr_bytes[3]; /* lowest...highest byte of data address */ -+ int ret; -+ -+ pr_debug("%s(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\n", -+ __FUNCTION__, chip, addr, alen, len); -+ -+ pxa_pwr_i2c_reset(); -+ -+ /* dummy chip address write */ -+ pr_debug("%s: dummy chip address write\n", __FUNCTION__); -+ msg.condition = I2C_COND_START; -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = (chip << 1); -+ msg.data &= 0xFE; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ -+ /* -+ * send memory address bytes; -+ * alen defines how much bytes we have to send. -+ */ -+ /*addr &= ((1 << CFG_EEPROM_PAGE_WRITE_BITS)-1); */ -+ addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF); -+ addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF); -+ addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF); -+ -+ while (--alen >= 0) { -+ pr_debug("%s: send memory word address byte %1d\n", -+ __FUNCTION__, alen); -+ msg.condition = I2C_COND_NORMAL; -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = addr_bytes[alen]; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ } -+ -+ /* start read sequence */ -+ pr_debug("%s: start read sequence\n", __FUNCTION__); -+ msg.condition = I2C_COND_START; -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = (chip << 1); -+ msg.data |= 0x01; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ -+ /* read bytes; send NACK at last byte */ -+ while (len--) { -+ if (len == 0) { -+ msg.condition = I2C_COND_STOP; -+ msg.acknack = I2C_ACKNAK_SENDNAK; -+ } else { -+ msg.condition = I2C_COND_NORMAL; -+ msg.acknack = I2C_ACKNAK_SENDACK; -+ } -+ -+ msg.direction = I2C_READ; -+ msg.data = 0x00; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ -+ *buffer = msg.data; -+ pr_debug("%s: reading byte (0x%08x)=0x%02x\n", -+ __FUNCTION__, (unsigned int)buffer, *buffer); -+ buffer++; -+ } -+ -+ pxa_pwr_i2c_reset(); -+ return 0; -+} -+ -+/** -+ * i2c_write: - Write multiple bytes to an i2c device -+ * -+ * The higher level routines take into account that this function is only -+ * called with len < page length of the device (see configuration file) -+ * -+ * @chip: address of the chip which is to be written -+ * @addr: i2c data address within the chip -+ * @alen: length of the i2c data address (1..2 bytes) -+ * @buffer: where to find the data to be written -+ * @len: how much byte do we want to read -+ * @return: 0 in case of success -+ */ -+int pxa_pwr_i2c_write(u8 chip, uint addr, int alen, u8 * buffer, int len) -+{ -+ struct i2c_msg msg; -+ u8 addr_bytes[3]; /* lowest...highest byte of data address */ -+ int ret; -+ -+ pr_debug("%s(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\n", -+ __FUNCTION__, chip, addr, alen, len); -+ -+ pxa_pwr_i2c_reset(); -+ -+ /* chip address write */ -+ pr_debug("%s: chip address write\n", __FUNCTION__); -+ msg.condition = I2C_COND_START; -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = (chip << 1); -+ msg.data &= 0xFE; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ -+ /* -+ * send memory address bytes; -+ * alen defines how much bytes we have to send. -+ */ -+ addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF); -+ addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF); -+ addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF); -+ -+ while (--alen >= 0) { -+ pr_debug("%s: send memory word address\n", __FUNCTION__); -+ msg.condition = I2C_COND_NORMAL; -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = addr_bytes[alen]; -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ } -+ -+ /* write bytes; send NACK at last byte */ -+ while (len--) { -+ pr_debug("%s: writing byte (0x%08x)=0x%02x\n", -+ __FUNCTION__, (unsigned int)buffer, *buffer); -+ -+ if (len == 0) -+ msg.condition = I2C_COND_STOP; -+ else -+ msg.condition = I2C_COND_NORMAL; -+ -+ msg.acknack = I2C_ACKNAK_WAITACK; -+ msg.direction = I2C_WRITE; -+ msg.data = *(buffer++); -+ -+ if ((ret = pxa_pwr_i2c_transfer(&msg))) -+ return ret; -+ } -+ -+ pxa_pwr_i2c_reset(); -+ return 0; -+} -+ -+/** -+ * pxa_pwr_i2c_reg_read: - Read single byte from an i2c device -+ * -+ * @chip: address of the chip which is to be read -+ * @reg: i2c data address within the chip -+ * @return: data in case of success, negative error code otherwise -+ */ -+s32 pxa_pwr_i2c_reg_read(u8 chip, u8 reg) -+{ -+ char buf; -+ int ret; -+ -+ pr_debug("%s(chip=0x%02x, reg=0x%02x)\n", __FUNCTION__, chip, reg); -+ ret = pxa_pwr_i2c_read(chip, reg, 1, &buf, 1); -+ if (ret == 0) -+ ret = buf; -+ -+ return ret; -+} -+ -+/** -+ * pxa_pwr_i2c_reg_write: - Write multiple bytes to an i2c device -+ * -+ * The higher level routines take into account that this function is only -+ * called with len < page length of the device (see configuration file) -+ * -+ * @chip: address of the chip which is to be written -+ * @reg: i2c data address within the chip -+ * @return: 0 in case of success, negative error code otherwise -+ */ -+s32 pxa_pwr_i2c_reg_write(u8 chip, u8 reg, u8 val) -+{ -+ pr_debug("%s(chip=0x%02x, reg=0x%02x, val=0x%02x)\n", -+ __FUNCTION__, chip, reg, val); -+ return pxa_pwr_i2c_write(chip, reg, 1, &val, 1); -+} -+ -+MODULE_DESCRIPTION("PXA Power I2C"); -+MODULE_AUTHOR("Mike Rapoport"); -+MODULE_LICENSE("GPL"); -diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c -index 203371a..36b695f 100644 ---- a/arch/arm/mach-pxa/pxa27x.c -+++ b/arch/arm/mach-pxa/pxa27x.c -@@ -243,7 +243,11 @@ void pxa27x_cpu_pm_enter(suspend_state_t state) - case PM_SUSPEND_MEM: - /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); -- pxa27x_cpu_suspend(PWRMODE_SLEEP); -+#ifdef CONFIG_MACH_EM_X270 -+ pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP); -+#else -+ pxa27x_cpu_suspend(PWRMODE_SLEEP); -+#endif - break; - } - } -diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c -index bae47e1..a16e532 100644 ---- a/arch/arm/mach-pxa/spitz.c -+++ b/arch/arm/mach-pxa/spitz.c -@@ -349,6 +349,32 @@ static struct pxamci_platform_data spitz_mci_platform_data = { - - - /* -+ * USB Client (Gadget/UDC) -+ */ -+static void spitz_udc_command(int cmd) -+{ -+ switch(cmd) { -+ case PXA2XX_UDC_CMD_CONNECT: -+ UP2OCR = UP2OCR_HXOE | UP2OCR_DMPUE | UP2OCR_DMPUBE; -+ break; -+ case PXA2XX_UDC_CMD_DISCONNECT: -+ //UP2OCR = UP2OCR_HXOE | UP2OCR_DMPUE | UP2OCR_DMPUBE; -+ break; -+ } -+} -+ -+static int spitz_udc_detect(void) -+{ -+ return 1; -+} -+ -+static struct pxa2xx_udc_mach_info spitz_udc_info __initdata = { -+ .udc_is_connected = spitz_udc_detect, -+ .udc_command = spitz_udc_command, -+}; -+ -+ -+/* - * USB Host (OHCI) - */ - static int spitz_ohci_init(struct device *dev) -@@ -499,6 +525,7 @@ static void __init common_init(void) - pxa_gpio_mode(SPITZ_GPIO_HSYNC | GPIO_IN); - - platform_add_devices(devices, ARRAY_SIZE(devices)); -+ pxa_set_udc_info(&spitz_udc_info); - pxa_set_mci_info(&spitz_mci_platform_data); - pxa_set_ohci_info(&spitz_ohci_platform_data); - pxa_set_ficp_info(&spitz_ficp_platform_data); -diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig -index 2e1c24f..f80f2b1 100644 ---- a/drivers/i2c/chips/Kconfig -+++ b/drivers/i2c/chips/Kconfig -@@ -163,4 +163,17 @@ config MENELAUS - and other features that are often used in portable devices like - cell phones and PDAs. - -+config DA9030 -+ tristate "Dialog Semiconductor DA9030 power management chip" -+ depends on EXPERIMENTAL && EMBEDDED -+ help -+ If you say yes here you get support for the Dialog -+ Semiconductor DA9030 power management chip. -+ This includes voltage regulators, lithium ion/polymer battery -+ charging, and other features that are often used in portable -+ devices like PDAs, cell phones and cameras. -+ -+ This driver can also be built as a module. If so, the module -+ will be called da9030. -+ - endmenu -diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile -index ca924e1..69f545c 100644 ---- a/drivers/i2c/chips/Makefile -+++ b/drivers/i2c/chips/Makefile -@@ -15,6 +15,7 @@ obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o - obj-$(CONFIG_TPS65010) += tps65010.o - obj-$(CONFIG_MENELAUS) += menelaus.o - obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o -+obj-$(CONFIG_DA9030) += da9030.o - - ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) - EXTRA_CFLAGS += -DDEBUG -diff --git a/drivers/i2c/chips/da9030.c b/drivers/i2c/chips/da9030.c -new file mode 100644 -index 0000000..9791272 ---- /dev/null -+++ b/drivers/i2c/chips/da9030.c -@@ -0,0 +1,1213 @@ -+/* -+ * Dialog Semiconductor DA9030 power management IC driver -+ * -+ * Copyright (C) 2007 Compulab, Ltd. -+ * Mike Rapoport -+ * -+ * Some parts based on menelaus.c: -+ * Copyright (C) 2004 Texas Instruments, Inc. -+ * Copyright (C) 2005, 2006 Nokia Corporation -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "da9030.h" -+ -+#define DRIVER_NAME "da9030" -+ -+static unsigned short normal_i2c[] = { 0x49, I2C_CLIENT_END }; -+ -+I2C_CLIENT_INSMOD; -+ -+struct da9030 { -+ struct mutex lock; -+ struct i2c_client *client; -+ -+ struct work_struct event_work; -+ -+ /* there are 24 interrupts */ -+ void (*callbacks[24])(int event, void *data); -+ void *callbacks_data[24]; -+ -+ struct dentry *debug_file; -+}; -+ -+/* I hardly believe there can be more than 1 such chip in the system, -+ so keeping its global instance won't really hurt */ -+static struct da9030 *the_da9030; -+ -+unsigned char defined_regs[] = { -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, -+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, -+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, -+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, -+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, -+ 0x50, 0x51, -+ 0x60, 0x61, 0x62, 0x63, -+ 0x80, 0x81, -+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, -+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, -+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, -+}; -+ -+static inline int is_reg_valid(u32 reg) -+{ -+ int i; -+ for (i = 0; i < ARRAY_SIZE(defined_regs); i++) -+ if (reg == defined_regs[i]) -+ return 1; -+ -+ return 0; -+} -+ -+s32 da9030_get_reg(u32 reg) -+{ -+ if (!is_reg_valid(reg)) -+ return -EINVAL; -+ -+ return i2c_smbus_read_byte_data(the_da9030->client, reg); -+} -+EXPORT_SYMBOL(da9030_get_reg); -+ -+s32 da9030_set_reg(u32 reg, u8 val) -+{ -+ if (!is_reg_valid(reg)) -+ return -EINVAL; -+ -+ return i2c_smbus_write_byte_data(the_da9030->client, reg, val); -+} -+EXPORT_SYMBOL(da9030_set_reg); -+ -+static s32 da9030_update_reg_bits(u32 reg, int bits, int shift, int val) -+{ -+ int ret; -+ int new_val; -+ -+ mutex_lock(&the_da9030->lock); -+ ret = da9030_get_reg(reg); -+ if (ret < 0) -+ goto out; -+ -+ new_val = reg & ~(((1 << bits) - 1) << shift); -+ new_val |= (val << shift); -+ -+ ret = da9030_set_reg(reg, new_val); -+ mutex_unlock(&the_da9030->lock); -+ -+out: -+ return ret; -+} -+ -+int da9030_get_status(void) -+{ -+ s32 ret; -+ -+ mutex_lock(&the_da9030->lock); -+ ret = da9030_get_reg(STATUS); -+ mutex_unlock(&the_da9030->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(da9030_get_status); -+ -+int da9030_get_fault_log(void) -+{ -+ s32 ret; -+ -+ mutex_lock(&the_da9030->lock); -+ ret = da9030_get_reg(FAULT_LOG); -+ mutex_unlock(&the_da9030->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(da9030_get_fault_log); -+ -+void da9030_read_adc(struct da9030_adc_res *adc) -+{ -+ mutex_lock(&the_da9030->lock); -+ -+ adc->vbat_res = da9030_get_reg(VBAT_RES); -+ adc->vbatmin_res = da9030_get_reg(VBATMIN_RES); -+ adc->vbatmintxon = da9030_get_reg(VBATMINTXON_RES); -+ adc->ichmax_res = da9030_get_reg(ICHMAX_RES); -+ adc->ichmin_res = da9030_get_reg(ICHMIN_RES); -+ adc->ichaverage_res = da9030_get_reg(ICHAVERAGE_RES); -+ adc->vchmax_res = da9030_get_reg(VCHMAX_RES); -+ adc->vchmin_res = da9030_get_reg(VCHMIN_RES); -+ adc->tbat_res = da9030_get_reg(TBAT_RES); -+ adc->adc_in4_res = da9030_get_reg(ADC_IN4_RES); -+ adc->adc_in5_res = da9030_get_reg(ADC_IN5_RES); -+ -+ mutex_unlock(&the_da9030->lock); -+} -+EXPORT_SYMBOL(da9030_read_adc); -+ -+void da9030_enable_adc(void) -+{ -+ /* enable automatic A/D measurements */ -+ mutex_lock(&the_da9030->lock); -+ -+ da9030_set_reg(ADC_MAN_CONTROL, -+ ADC_LDO_INT_ENABLE | ADC_TBATREF_ENABLE); -+ da9030_set_reg(ADC_MAN_CONTROL_1, -+ ADC_LDO_INT_ENABLE | ADC_TBATREF_ENABLE); -+ da9030_set_reg(ADC_AUTO_CONTROL_1, -+ ADC_TBAT_ENABLE | ADC_VBAT_IN_TXON | ADC_VCH_ENABLE | -+ ADC_ICH_ENABLE | ADC_VBAT_ENABLE | -+ ADC_AUTO_SLEEP_ENABLE); -+ da9030_set_reg(ADC_AUTO_CONTROL, -+ ADC_TBAT_ENABLE | ADC_VBAT_IN_TXON | ADC_VCH_ENABLE | -+ ADC_ICH_ENABLE | ADC_VBAT_ENABLE | -+ ADC_AUTO_SLEEP_ENABLE); -+ -+ mutex_unlock(&the_da9030->lock); -+} -+EXPORT_SYMBOL(da9030_enable_adc); -+ -+void da9030_set_wled(int on, unsigned int brightness) -+{ -+ u8 val; -+ -+ mutex_lock(&the_da9030->lock); -+ -+ if (on) -+ val = WLED_CP_ENABLE | (brightness & 0x7); -+ else -+ val = da9030_get_reg(WLED_CONTROL) & ~WLED_CP_ENABLE; -+ -+ da9030_set_reg(WLED_CONTROL, val); -+ -+ mutex_unlock(&the_da9030->lock); -+} -+EXPORT_SYMBOL(da9030_set_wled); -+ -+int da9030_set_charger(int on, unsigned int mA, unsigned int mV) -+{ -+ int ret; -+ u8 val = 0; -+ if (on) { -+ if (mA >= 1500 || mV < 4000 || mV > 4350) -+ return -EINVAL; -+ -+ val = CHRG_CHARGER_ENABLE; -+ val |= (mA / 100) << 3; -+ val |= (mV - 4000) / 50; -+ } -+ -+ mutex_lock(&the_da9030->lock); -+ ret = da9030_set_reg(CHARGE_CONTROL, val); -+ mutex_unlock(&the_da9030->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(da9030_set_charger); -+ -+void da9030_get_charger(int *on, unsigned int *mA, unsigned int *mV) -+{ -+ s32 val; -+ -+ mutex_lock(&the_da9030->lock); -+ -+ val = da9030_get_reg(CHARGE_CONTROL); -+ -+ mutex_unlock(&the_da9030->lock); -+ -+ if (on) -+ *on = (val & CHRG_CHARGER_ENABLE) ? 1 : 0; -+ -+ if (mA) -+ *mA = ((val >> 3) & 0xf) * 100; -+ -+ if (mV) -+ *mV = (val & 0x7) * 50 + 4000; -+} -+EXPORT_SYMBOL(da9030_get_charger); -+ -+int da9030_set_led(int led, int on, -+ enum da9030_led_rate rate, -+ enum da9030_led_duty_cycle duty, -+ enum da9030_led_pwm_chop pwm_chop) -+{ -+ int reg; -+ int ret; -+ -+ u8 val = 0; -+ -+ if (led > 4) -+ return -EINVAL; -+ -+ reg = LED_1_CONTROL + led; -+ if (on) { -+ val = LED_ENABLE; -+ val |= (rate & 0x3) << 5; -+ val |= (duty & 0x3) << 3; -+ val |= (pwm_chop & 0x7); -+ } -+ -+ mutex_lock(&the_da9030->lock); -+ ret = da9030_set_reg(reg, val); -+ mutex_unlock(&the_da9030->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(da9030_set_led); -+ -+void da9030_set_thresholds(unsigned int tbathighp, unsigned int tbathighn, -+ unsigned int tbatlow, unsigned int vbatmon) -+{ -+ mutex_lock(&the_da9030->lock); -+ -+ da9030_set_reg(TBATHIGHP, tbathighp); -+ da9030_set_reg(TBATHIGHN, tbathighn); -+ da9030_set_reg(TBATLOW, tbatlow); -+ da9030_set_reg(VBATMONTXON, vbatmon); -+ da9030_set_reg(VBATMON, vbatmon); -+ -+ da9030_set_reg(TBATHIGHP_1, tbathighp); -+ da9030_set_reg(TBATHIGHN_1, tbathighn); -+ da9030_set_reg(TBATLOW_1, tbatlow); -+ da9030_set_reg(VBATMONTXMON_1, vbatmon); -+ da9030_set_reg(VBATMON_1, vbatmon); -+ -+ mutex_unlock(&the_da9030->lock); -+} -+EXPORT_SYMBOL(da9030_set_thresholds); -+ -+struct da9030_vtg_value { -+ u16 vtg; -+ u16 val; -+}; -+ -+struct da9030_vtg_value da9030_vtg_1V8_3V2[] = { -+ {1800, 0x0}, -+ {1900, 0x1}, -+ {2000, 0x2}, -+ {2100, 0x3}, -+ {2200, 0x4}, -+ {2300, 0x5}, -+ {2400, 0x6}, -+ {2500, 0x7}, -+ {2600, 0x8}, -+ {2700, 0x9}, -+ {2800, 0xa}, -+ {2900, 0xb}, -+ {3000, 0xc}, -+ {3100, 0xd}, -+ {3200, 0xe}, -+ {3200, 0xf}, -+}; -+ -+struct da9030_vtg_value da9030_vtg_1V1_2V65[] = { -+ {1100, 0x0}, -+ {1150, 0x1}, -+ {1200, 0x2}, -+ {1250, 0x3}, -+ {1300, 0x4}, -+ {1350, 0x5}, -+ {1400, 0x6}, -+ {1450, 0x7}, -+ {1500, 0x8}, -+ {1550, 0x9}, -+ {1600, 0xa}, -+ {1650, 0xb}, -+ {1700, 0xc}, -+ {1750, 0xd}, -+ {1800, 0xe}, -+ {1850, 0xf}, -+ {1900, 0x10}, -+ {1950, 0x11}, -+ {2000, 0x12}, -+ {2050, 0x13}, -+ {2100, 0x14}, -+ {2150, 0x15}, -+ {2200, 0x16}, -+ {2250, 0x17}, -+ {2300, 0x18}, -+ {2350, 0x19}, -+ {2400, 0x1a}, -+ {2450, 0x1b}, -+ {2500, 0x1c}, -+ {2550, 0x1d}, -+ {2600, 0x1e}, -+ {2650, 0x1f}, -+}; -+ -+struct da9030_vtg_value da9030_vtg_2V76_2V94[] = { -+ {2760, 0x7}, -+ {2790, 0x6}, -+ {2820, 0x5}, -+ {2850, 0x4}, -+ {2850, 0x3}, -+ {2880, 0x1}, -+ {2910, 0x2}, -+ {2940, 0x3}, -+}; -+ -+struct da9030_vtg_value da9030_vtg_0V85_1V625[] = { -+ {850, 0x0}, -+ {875, 0x1}, -+ {900, 0x2}, -+ {925, 0x3}, -+ {950, 0x4}, -+ {975, 0x5}, -+ {1000, 0x6}, -+ {1025, 0x7}, -+ {1050, 0x8}, -+ {1075, 0x9}, -+ {1100, 0xa}, -+ {1125, 0xb}, -+ {1150, 0xc}, -+ {1175, 0xd}, -+ {1200, 0xe}, -+ {1225, 0xf}, -+ {1250, 0x10}, -+ {1275, 0x11}, -+ {1300, 0x12}, -+ {1325, 0x13}, -+ {1350, 0x14}, -+ {1375, 0x15}, -+ {1400, 0x16}, -+ {1425, 0x17}, -+ {1450, 0x18}, -+ {1475, 0x19}, -+ {1500, 0x1a}, -+ {1525, 0x1b}, -+ {1550, 0x1c}, -+ {1575, 0x1d}, -+ {1600, 0x1e}, -+ {1625, 0x1f}, -+}; -+ -+struct ldo_param { -+ u8 reg; -+ u8 shift; -+ u8 bits; -+}; -+ -+struct da9030_ldo { -+ const char *name; -+ -+ struct ldo_param vtg; -+ struct ldo_param sleep; -+ struct ldo_param lock; -+ -+ /* several LDOs have two enable/disable bits */ -+ struct ldo_param enable[2]; -+ -+ struct da9030_vtg_value *values; -+ int values_count; -+}; -+ -+static struct da9030_ldo da9030_ldos[] = { -+ [0] = { -+ .name = "LDO1", -+ .vtg = { -+ .reg = LDO_1, -+ .shift = 0, -+ .bits = 5, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 1, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = LDO_1, -+ .shift = 5, -+ .bits = 2, -+ }, -+ .lock = { -+ .reg = REG_SLEEP_CONTROL1, -+ .shift = 0, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [1] = { -+ .name = "LDO2", -+ .vtg = { -+ .reg = LDO_2_3, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 2, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL1, -+ .shift = 2, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [2] = { -+ .name = "LDO3", -+ .vtg = { -+ .reg = LDO_2_3, -+ .shift = 4, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 3, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL1, -+ .shift = 4, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [3] = { -+ .name = "LDO4", -+ .vtg = { -+ .reg = LDO_4_5, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 4, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL1, -+ .shift = 6, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [4] = { -+ .name = "LDO5", -+ .vtg = { -+ .reg = LDO_4_5, -+ .shift = 4, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 5, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL2, -+ .shift = 0, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [5] = { -+ .name = "LDO6", -+ .vtg = { -+ .reg = LDO_6_SIMCP, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 6, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [6] = { -+ .name = "LDO7", -+ .vtg = { -+ .reg = LDO_7_8, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_97, -+ .shift = 7, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL2, -+ .shift = 2, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [7] = { -+ .name = "LDO8", -+ .vtg = { -+ .reg = LDO_7_8, -+ .shift = 4, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_2_98, -+ .shift = 0, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL2, -+ .shift = 4, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [8] = { -+ .name = "LDO9", -+ .vtg = { -+ .reg = LDO_9_12, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_2_98, -+ .shift = 1, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL2, -+ .shift = 6, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [9] = { -+ .name = "LDO10", -+ .vtg = { -+ .reg = LDO_10_11, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, -+ .shift = 1, -+ .bits = 1, -+ }, -+ .enable[1] = { -+ .reg = REG_CONTROL_2_98, -+ .shift = 2, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [10] = { -+ .name = "LDO11", -+ .vtg = { -+ .reg = LDO_10_11, -+ .shift = 4, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, -+ .shift = 2, -+ .bits = 1, -+ }, -+ .enable[1] = { -+ .reg = REG_CONTROL_2_98, -+ .shift = 3, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [11] = { -+ .name = "LDO12", -+ .vtg = { -+ .reg = LDO_9_12, -+ .shift = 4, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_2_98, -+ .shift = 4, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = REG_SLEEP_CONTROL3, -+ .shift = 0, -+ .bits = 2, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [12] = { -+ .name = "LDO13", -+ .vtg = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, -+ .shift = 3, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = NULL, -+ .values_count = 0, -+ }, -+ [13] = { -+ .name = "LDO14", -+ .vtg = { -+ .reg = LDO_14_16, -+ .shift = 0, -+ .bits = 3, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, /* FIXME: or 2_98? */ -+ .shift = 4, -+ .bits = 1, -+ }, -+ .enable[1] = { -+ .reg = REG_CONTROL_2_98, /* FIXME: or 2_98? */ -+ .shift = 5, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_2V76_2V94, -+ .values_count = ARRAY_SIZE(da9030_vtg_2V76_2V94), -+ }, -+ [14] = { -+ .name = "LDO15", -+ .vtg = { -+ .reg = LDO_15, -+ .shift = 0, -+ .bits = 5, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, -+ .shift = 5, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .lock = { -+ .reg = LDO_15, -+ .shift = 5, -+ .bits = 3, -+ }, -+ .values = da9030_vtg_1V1_2V65, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V1_2V65), -+ }, -+ [15] = { -+ .name = "LDO16", -+ .vtg = { -+ .reg = LDO_14_16, -+ .shift = 3, -+ .bits = 5, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, -+ .shift = 6, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V1_2V65, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V1_2V65), -+ }, -+ [16] = { -+ .name = "LDO17", -+ .vtg = { -+ .reg = LDO_17_SIMCP0, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_1_17, -+ .shift = 7, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [17] = { -+ .name = "LDO18", -+ .vtg = { -+ .reg = LDO_18_19, -+ .shift = 0, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_2_18, -+ .shift = 2, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+ [18] = { -+ .name = "LDO19", -+ .vtg = { -+ .reg = LDO_18_19, -+ .shift = 4, -+ .bits = 4, -+ }, -+ .enable[0] = { -+ .reg = REG_CONTROL_2_18, -+ .shift = 1, -+ .bits = 1, -+ }, -+ .sleep = { -+ .reg = 0, -+ .shift = 0, -+ .bits = 0, -+ }, -+ .values = da9030_vtg_1V8_3V2, -+ .values_count = ARRAY_SIZE(da9030_vtg_1V8_3V2), -+ }, -+}; -+ -+static int da9030_get_vtg_value(int vtg, const struct da9030_vtg_value *tbl, -+ int n) -+{ -+ int i; -+ -+ for (i = 0; i < n; i++, tbl++) -+ if (tbl->vtg == vtg) -+ return tbl->val; -+ return -EINVAL; -+} -+ -+static int da9030_set_ldo_volt(struct da9030_ldo *ldo, unsigned int mV) -+{ -+ int val; -+ -+ val = da9030_get_vtg_value(mV, ldo->values, ldo->values_count); -+ if (val < 0) -+ return val; -+ -+ return da9030_update_reg_bits(ldo->vtg.reg, ldo->vtg.bits, -+ ldo->vtg.shift, val); -+} -+ -+static int da9030_enable_ldo(struct da9030_ldo *ldo, int enable) -+{ -+ int ret; -+ -+ ret = da9030_update_reg_bits(ldo->enable[0].reg, ldo->enable[1].bits, -+ ldo->enable[0].shift, enable); -+ -+ if (ret < 0) -+ return ret; -+ -+ if (unlikely(ldo->enable[1].reg != 0)) -+ ret = da9030_update_reg_bits(ldo->enable[1].reg, -+ ldo->enable[1].bits, -+ ldo->enable[1].shift, enable); -+ -+ return ret; -+} -+ -+static int da9030_set_ldo_sleep(struct da9030_ldo *ldo, -+ enum da9030_ldo_sleep_mode sleep_mode) -+{ -+ return da9030_update_reg_bits(ldo->sleep.reg, ldo->sleep.bits, -+ ldo->sleep.shift, sleep_mode); -+} -+ -+int da9030_set_ldo(int ldo_num, int on, unsigned int mV, -+ enum da9030_ldo_sleep_mode sleep_mode) -+{ -+ struct da9030_ldo *ldo; -+ int ret; -+ -+ if (ldo_num < 0 || ldo_num > ARRAY_SIZE(da9030_ldos)) -+ return -EINVAL; -+ -+ ldo = &da9030_ldos[ldo_num]; -+ -+ ret = da9030_set_ldo_volt(ldo, mV); -+ if (ret < 0) -+ return ret; -+ -+ ret = da9030_enable_ldo(ldo, on); -+ if (ret < 0) -+ return ret; -+ -+ ret = da9030_set_ldo_sleep(ldo, sleep_mode); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+EXPORT_SYMBOL(da9030_set_ldo); -+ -+int da9030_set_buck(int buck, int on, unsigned int mV, int flags) -+{ -+ /* FIXME: implement */ -+ return 0; -+} -+EXPORT_SYMBOL(da9030_set_buck); -+ -+static void da9030_disable_irq(unsigned int irq) -+{ -+ int reg, val; -+ -+ if (irq < 8) { -+ reg = IRQ_MASK_A; -+ val = 1 << irq; -+ } else if (irq < 16) { -+ reg = IRQ_MASK_B; -+ val = 1 << (irq - 8); -+ } else { -+ reg = IRQ_MASK_C; -+ val = 1 << (irq - 16); -+ } -+ -+ i2c_smbus_write_byte_data( -+ the_da9030->client, reg, -+ i2c_smbus_read_byte_data(the_da9030->client, reg) | val); -+} -+ -+static void da9030_enable_irq(unsigned int irq) -+{ -+ int reg, val; -+ -+ if (irq < 8) { -+ reg = IRQ_MASK_A; -+ val = 1 << irq; -+ } else if (irq < 16) { -+ reg = IRQ_MASK_B; -+ val = 1 << (irq - 8); -+ } else { -+ reg = IRQ_MASK_C; -+ val = 1 << (irq - 16); -+ } -+ -+ i2c_smbus_write_byte_data( -+ the_da9030->client, reg, -+ i2c_smbus_read_byte_data(the_da9030->client, reg) & ~val); -+} -+ -+int da9030_register_callback(int event, -+ void (*callback)(int event, void *data), -+ void *data) -+{ -+ int ret; -+ -+ if (event < 0 || event > 23) -+ return -EINVAL; -+ -+ mutex_lock(&the_da9030->lock); -+ if (the_da9030->callbacks[event]) -+ ret = -EBUSY; -+ else { -+ the_da9030->callbacks[event] = callback; -+ the_da9030->callbacks_data[event] = data; -+ da9030_enable_irq(event); -+ ret = 0; -+ } -+ mutex_unlock(&the_da9030->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(da9030_register_callback); -+ -+void da9030_unregister_callback(int event) -+{ -+ mutex_lock(&the_da9030->lock); -+ -+ da9030_disable_irq(event); -+ the_da9030->callbacks[event] = NULL; -+ the_da9030->callbacks_data[event] = 0; -+ -+ mutex_unlock(&the_da9030->lock); -+} -+EXPORT_SYMBOL(da9030_unregister_callback); -+ -+#ifdef CONFIG_DEBUG_FS -+#define MAX_BUF 256 -+ -+static int da9030_debug_show(struct seq_file *s, void *data) -+{ -+ int i, res = 0; -+ struct da9030 *da9030 = s->private; -+ struct i2c_client *client = da9030->client; -+ -+ seq_printf(s, "DA9030 state: da = %p, cl = %p, s->private = %p\n", -+ da9030, client, s->private); -+ -+ for (i = 0; i < ARRAY_SIZE(defined_regs); i++) { -+ res = i2c_smbus_read_byte_data(client, defined_regs[i]); -+ seq_printf(s, "%02x %x\n", defined_regs[i], res); -+ } -+ return 0; -+} -+ -+static int da9030_debug_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, da9030_debug_show, inode->i_private); -+} -+ -+ssize_t da9030_debug_write(struct file *f, const char __user *buf, size_t len, -+ loff_t *off) -+{ -+ char buffer[MAX_BUF]; -+ int reg, val; -+ char *endp; -+ struct da9030 *da9030 = ((struct seq_file *)f->private_data)->private; -+ struct i2c_client *client = da9030->client; -+ -+ if (len > MAX_BUF) { -+ printk(KERN_INFO "%s: large buffer\n", __FUNCTION__); -+ len = MAX_BUF; -+ } -+ -+ if (copy_from_user(buffer, buf, len)) { -+ printk(KERN_INFO "%s: copy_from_user failed\n", __FUNCTION__); -+ return -EFAULT; -+ } -+ buffer[len] = '\0'; -+ -+ reg = simple_strtoul(buffer, &endp, 0); -+ while (endp && isspace(*endp)) -+ endp++; -+ -+ val = simple_strtoul(endp, 0, 0); -+ -+ i2c_smbus_write_byte_data(client, reg, val); -+ -+ return len; -+} -+ -+static const struct file_operations debug_fops = { -+ .open = da9030_debug_open, -+ .read = seq_read, -+ .write = da9030_debug_write, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static struct dentry *da9030_create_debugfs(struct da9030 *da9030) -+{ -+ da9030->debug_file = debugfs_create_file("da9030", 0666, 0, da9030, -+ &debug_fops); -+ return da9030->debug_file; -+} -+ -+static void da9030_remove_debugfs(struct da9030 *da9030) -+{ -+ debugfs_remove(da9030->debug_file); -+} -+#else -+#define da9030_create_debugfs(x) NULL -+#define da9030_remove_debugfs(x) do {} while (0) -+#endif -+ -+static irqreturn_t da9030_irq(int irq, void *_da9030) -+{ -+ struct da9030 *da9030 = _da9030; -+ -+ (void)schedule_work(&da9030->event_work); -+ -+ return IRQ_HANDLED; -+} -+ -+static void da9030_irq_worker(struct work_struct *work) -+{ -+ struct da9030 *da9030 = container_of(work, struct da9030, event_work); -+ void (*callback)(int event, void *data); -+ u32 pending = 0; -+ u32 mask = 0; -+ int i; -+ -+ while (1) { -+ pending = (i2c_smbus_read_byte_data(da9030->client, -+ EVENT_A)) | -+ ((i2c_smbus_read_byte_data(da9030->client, -+ EVENT_B)) << 8) | -+ ((i2c_smbus_read_byte_data(da9030->client, -+ EVENT_C)) << 16); -+ -+ mask = (i2c_smbus_read_byte_data(da9030->client, -+ IRQ_MASK_A)) | -+ ((i2c_smbus_read_byte_data(da9030->client, -+ IRQ_MASK_B)) << 8) | -+ ((i2c_smbus_read_byte_data(da9030->client, -+ IRQ_MASK_C)) << 16); -+ pending &= ~mask; -+ -+ if (!pending) -+ return; -+ -+ while (pending) { -+ i = __ffs(pending); -+ callback = da9030->callbacks[i]; -+ if (callback) -+ callback(i, da9030->callbacks_data[i]); -+ pending &= ~(1 << i); -+ } -+ } -+} -+ -+static inline void da9030_disable_interrupts(struct da9030 *da9030) -+{ -+ /* clear pending interruts */ -+ (void)i2c_smbus_read_byte_data(da9030->client, EVENT_A); -+ (void)i2c_smbus_read_byte_data(da9030->client, EVENT_B); -+ (void)i2c_smbus_read_byte_data(da9030->client, EVENT_C); -+ -+ /* disable interrupts */ -+ i2c_smbus_write_byte_data(da9030->client, IRQ_MASK_A, 0xff); -+ i2c_smbus_write_byte_data(da9030->client, IRQ_MASK_B, 0xff); -+ i2c_smbus_write_byte_data(da9030->client, IRQ_MASK_C, 0xff); -+} -+ -+static int da9030_probe(struct i2c_client *client) -+{ -+ int ret; -+ struct da9030 *da9030; -+ -+ if (the_da9030) { -+ dev_dbg(&client->dev, "only one %s for now\n", -+ DRIVER_NAME); -+ return -ENODEV; -+ } -+ -+ ret = i2c_smbus_read_byte_data(client, CHIP_ID); -+ -+ dev_info(&client->dev, "initialized chip revision %x\n", ret); -+ -+ da9030 = kzalloc(sizeof(struct da9030), GFP_KERNEL); -+ if (da9030 == NULL) { -+ dev_err(&client->dev, "insufficient memory\n"); -+ return -ENOMEM; -+ } -+ the_da9030 = da9030; -+ da9030->client = client; -+ -+ mutex_init(&the_da9030->lock); -+ -+ da9030_disable_interrupts(da9030); -+ INIT_WORK(&da9030->event_work, da9030_irq_worker); -+ -+ ret = request_irq(client->irq, da9030_irq, -+ IRQF_DISABLED, DRIVER_NAME, da9030); -+ -+ if (ret) { -+ kfree(da9030); -+ dev_err(&client->dev, -+ "failed to allocate irq %d\n", -+ client->irq); -+ return ret; -+ } -+ -+ i2c_set_clientdata(client, da9030); -+ -+ da9030->debug_file = da9030_create_debugfs(da9030); -+ -+ return 0; -+} -+ -+/* static int da9030_detach_adapter(struct i2c_adapter *a) */ -+static int da9030_remove(struct i2c_client *client) -+{ -+ struct da9030 *da9030 = i2c_get_clientdata(client); -+ -+ da9030_remove_debugfs(da9030); -+ -+ free_irq(da9030->client->irq, da9030); -+ kfree(da9030); -+ i2c_set_clientdata(client, NULL); -+ the_da9030 = NULL; -+ -+ return 0; -+} -+ -+static struct i2c_driver da9030_driver = { -+ .driver = { -+ .name = "da9030", -+ .owner = THIS_MODULE, -+ }, -+ -+ .probe = da9030_probe, -+ .remove = da9030_remove, -+}; -+ -+static int da9030_init(void) -+{ -+ i2c_add_driver(&da9030_driver); -+ return 0; -+} -+ -+static void da9030_exit(void) -+{ -+ i2c_del_driver(&da9030_driver); -+} -+ -+/* NOTE: this MUST be initialized before the other parts of the system -+ * that rely on it ... but after the i2c bus on which this relies. -+ * That is, much earlier than on PC-type systems, which don't often use -+ * I2C as a core system bus. -+ */ -+subsys_initcall(da9030_init); -+module_exit(da9030_exit); -+ -+MODULE_DESCRIPTION("DA9030 power manager driver"); -+MODULE_AUTHOR("Mike Rapoport, Compulab"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/i2c/chips/da9030.h b/drivers/i2c/chips/da9030.h -new file mode 100644 -index 0000000..4163156 ---- /dev/null -+++ b/drivers/i2c/chips/da9030.h -@@ -0,0 +1,282 @@ -+/* DA9030 Register definintions */ -+ -+#define CHIP_ID 0x00 -+ -+#define EVENT_A 0x01 -+#define EVENT_A_CHIOVER (1 << 7) -+#define EVENT_A_VBAT_MON_TXON (1 << 6) -+#define EVENT_A_VBAT_MON (1 << 5) -+#define EVENT_A_TBAT (1 << 4) -+#define EVENT_A_CHDET (1 << 3) -+#define EVENT_A_EXTON (1 << 2) -+#define EVENT_A_PWREN1 (1 << 1) -+#define EVENT_A_ONKEY_N (1 << 0) -+ -+#define EVENT_B 0x02 -+#define EVENT_B_WDOG_INT (1 << 7) -+#define EVENT_B_SRP_DETECT (1 << 6) -+#define EVENT_B_SESSION_VALID (1 << 5) -+#define EVENT_B_VBUS_VALID_4_0 (1 << 4) -+#define EVENT_B_VBUS_VALID_4_4 (1 << 3) -+#define EVENT_B_ADC_READY (1 << 2) -+#define EVENT_B_CCTO (1 << 1) -+#define EVENT_B_TCTO (1 << 0) -+ -+#define EVENT_C 0x03 -+#define EVENT_C_ADC_IN5 (1 << 7) -+#define EVENT_C_ADC_IN4 (1 << 6) -+#define EVENT_C_BUCK2 (1 << 5) -+#define EVENT_C_LDO19 (1 << 4) -+#define EVENT_C_LDO18 (1 << 3) -+#define EVENT_C_LDO17 (1 << 2) -+#define EVENT_C_LDO16 (1 << 1) -+#define EVENT_C_LDO15 (1 << 0) -+ -+#define STATUS 0x04 -+#define STATUS_MCLK_DETECT (1 << 7) -+#define STATUS_VBAT_MON_TXON (1 << 6) -+#define STATUS_VBAT_MON (1 << 5) -+#define STATUS_TBAT (1 << 4) -+#define STATUS_CHDET (1 << 3) -+#define STATUS_EXTON (1 << 2) -+#define STATUS_PWREN1 (1 << 1) -+#define STATUS_ONKEY_N (1 << 0) -+ -+#define IRQ_MASK_A 0x05 -+#define IRQ_MASK_A_CHIOVER (1 << 7) -+#define IRQ_MASK_A_VBAT_MON_TXON (1 << 6) -+#define IRQ_MASK_A_VBAT_MON (1 << 5) -+#define IRQ_MASK_A_TBAT (1 << 4) -+#define IRQ_MASK_A_CHDET (1 << 3) -+#define IRQ_MASK_A_EXTON (1 << 2) -+#define IRQ_MASK_A_PWREN1 (1 << 1) -+#define IRQ_MASK_A_ONKEY_N (1 << 0) -+ -+#define IRQ_MASK_B 0x06 -+#define IRQ_MASK_B_WDOG_INT (1 << 7) -+#define IRQ_MASK_B_SRP_DETECT (1 << 6) -+#define IRQ_MASK_B_SESSION_VALID (1 << 5) -+#define IRQ_MASK_B_VBUS_VALID_4_0 (1 << 4) -+#define IRQ_MASK_B_VBUS_VALID_4_4 (1 << 3) -+#define IRQ_MASK_B_ADC_READY (1 << 2) -+#define IRQ_MASK_B_CCTO (1 << 1) -+#define IRQ_MASK_B_TCTO (1 << 0) -+ -+#define IRQ_MASK_C 0x07 -+#define IRQ_MASK_C_ADC_IN5 (1 << 7) -+#define IRQ_MASK_C_ADC_IN4 (1 << 6) -+#define IRQ_MASK_C_BUCK2 (1 << 5) -+#define IRQ_MASK_C_LDO19 (1 << 4) -+#define IRQ_MASK_C_LDO18 (1 << 3) -+#define IRQ_MASK_C_LDO17 (1 << 2) -+#define IRQ_MASK_C_LDO16 (1 << 1) -+#define IRQ_MASK_C_LDO15 (1 << 0) -+ -+#define SYS_CTRL_A 0x08 -+#define SYS_CONTROL_A_SLEEP_N_PIN_ENABLE 0x1 -+#define SYS_CONTROL_A_SHUT_DOWN (1<<1) -+#define SYS_CONTROL_A_HWRES_ENABLE (1<<2) -+#define SYS_CONTROL_A_WDOG_ACTION (1<<3) -+#define SYS_CONTROL_A_WATCHDOG (1<<7) -+ -+#define SYS_CONTROL_B 0x09 -+#define SYS_CLTR_B_SLEEP_13MHZ_EN (1 << 4) -+#define SYS_CLTR_B_AUTO_CLK_SWITCH (1 << 3) -+ -+#define FAULT_LOG 0x0a -+#define FAULT_LOG_OVER_TEMP (1 << 7) -+#define FAULT_LOG_VBAT_OVER (1 << 4) -+ -+#define LDO_10_11 0x10 -+#define LDO_10_11_LDO10_3V (0xc) -+#define LDO_10_11_LDO11_3V2 (0xe << 4) -+ -+#define LDO_15 0x11 -+#define LDO_14_16 0x12 -+#define LDO_18_19 0x13 -+#define LDO_18_19_LDO18_3V2 (0xe) -+ -+#define LDO_17_SIMCP0 0x14 -+#define LDO_17_SIMCP0_LDO17_3V 0x0F -+ -+#define BUCK_2_DVC1 0x15 -+#define BUCK_2_GO (1 << 7) -+#define BUCK_2_SLEEP (1 << 6) -+#define BUCK_2_TRIM_1V5 (0x1a) -+ -+#define BUCK_2_DVC2 0x16 -+ -+#define REG_CONTROL_1_17 0x17 -+#define RC1_LDO17_EN (1 << 7) -+#define RC1_LDO16_EN (1 << 6) -+#define RC1_LDO15_EN (1 << 5) -+#define RC1_LDO14_EN (1 << 4) -+#define RC1_LDO13_EN (1 << 3) -+#define RC1_LDO11_EN (1 << 2) -+#define RC1_LDO10_EN (1 << 1) -+#define RC1_BUCK2_EN (1 << 0) -+ -+#define REG_CONTROL_2_18 0x18 -+#define RC2_SIMCP_EN (1 << 6) -+#define RC2_LDO19_EN (1 << 1) -+#define RC2_LDO18_EN (1 << 0) -+ -+#define REG_CONTROL_3_ -+ -+#define USBPUMP 0x19 -+#define USB_PUMP_EN_USBVEP (1 << 7) -+#define USB_PUMP_EN_USBVE (1 << 6) -+#define USB_PUMP_SPR_DETECT (1 << 5) -+#define USB_PUMP_SESSION_VALID (1 << 4) -+#define USB_PUMP_VBUS_VALID_4_0 (1 << 3) -+#define USB_PUMP_VBUS_VALID_4_4 (1 << 2) -+#define USB_PUMP_USBVEP (1 << 1) -+#define USB_PUMP_USBVE (1 << 0) -+ -+#define SLEEP_CONTROL 0x1a -+#define APP_SLEEP_CTL_PWR_EN (1 << 7) -+#define APP_SLEEP_CTL_SYS_EN (1 << 6) -+#define APP_SLEEP_CTL_BYPASS_LDO19 (1 << 2) -+#define APP_SLEEP_CTL_BYPASS_LDO18 (1 << 1) -+#define APP_SLEEP_CTL_BYPASS_LDO17 (1 << 0) -+ -+#define STARTUP_CONTROL 0x1b -+#define STARTUP_CTL_LDO11_PWR_SYS (1 << 3) -+#define STARTUP_CTL_LDO10_PWR_SYS (1 << 2) -+#define STARTUP_CTL_LDO11_START (1 << 1) -+#define STARTUP_CTL_LDO10_START (1 << 0) -+ -+#define LED_1_CONTROL 0x20 -+#define LED_2_CONTROL 0x21 -+#define LED_3_CONTROL 0x22 -+#define LED_4_CONTROL 0x23 -+#define LEDPC_CONTROL 0x24 -+#define LED_ENABLE (1 << 7) -+ -+#define WLED_CONTROL 0x25 -+#define WLED_CP_ENABLE (1 << 6) -+#define WLED_ISET_10 (3) -+ -+#define MISC_CONTROLA 0x26 -+#define MISC_CONTROLB 0x27 -+#define MISCB_SESSION_VALID_ENABLE (1 << 3) -+#define MISCB_USB_INT_RISING (1 << 2) -+#define MISCB_I2C_ADDRESS (1 << 1) -+#define MISCB_STARTUP_SEQUENCE (1 << 0) -+ -+#define CHARGE_CONTROL 0x28 -+#define CHRG_CHARGER_ENABLE (1 << 7) -+ -+#define CCTR_CONTROL 0x29 -+#define CCTR_SET_8MIN 0x01 -+ -+#define TCTR_CONTROL 0x2a -+#define CHARGE_PULSE 0x2b -+ -+#define ADC_MAN_CONTROL 0x30 -+ -+#define ADC_AUTO_CONTROL 0x31 -+#define ADC_IN5_EN (1 << 7) -+#define ADC_IN4_EN (1 << 6) -+#define ADC_TBAT_ENABLE (1 << 5) -+#define ADC_VBAT_IN_TXON (1 << 4) -+#define ADC_VCH_ENABLE (1 << 3) -+#define ADC_ICH_ENABLE (1 << 2) -+#define ADC_VBAT_ENABLE (1 << 1) -+#define ADC_AUTO_SLEEP_ENABLE (1 << 0) -+ -+#define VBATMON 0x32 -+#define VBATMONTXON 0x33 -+#define TBATHIGHP 0x34 -+#define TBATHIGHN 0x35 -+#define TBATLOW 0x36 -+#define ADC_IN4_MIN 0x37 -+#define ADC_IN4_MAX 0x38 -+#define ADC_IN5_MIN 0x39 -+#define ADC_IN5_MAX 0x3a -+ -+#define VBAT_RES 0x41 -+#define VBATMIN_RES 0x42 -+#define VBATMINTXON 0x43 -+#define ICHMAX_RES 0x44 -+#define ICHMIN_RES 0x45 -+#define ICHAVERAGE_RES 0x46 -+#define VCHMAX_RES 0x47 -+#define VCHMIN_RES 0x48 -+#define TBAT_RES 0x49 -+#define ADC_IN4_RES 0x4a -+#define ADC_IN5_RES 0x4b -+ -+#define LDO_1 0x90 -+#define LDO_1_UNLOCK (0x5 << 5) -+#define LDO_1_TRIM_3V (0x12) -+ -+#define LDO_2_3 0x91 -+#define LDO_2_3_LDO2_3V2 (0xe << 4) -+#define LDO_2_3_LDO3_3V (0xc) -+ -+#define LDO_4_5 0x92 -+#define LDO_6_SIMCP 0x93 -+#define LDO_6_SIMCP_LDO6_3V2 (0xe) -+ -+#define LDO_7_8 0x94 -+#define LDO_9_12 0x95 -+#define BUCK 0x96 -+#define REG_CONTROL_1_97 0x97 -+#define RC3_LDO7_EN (1 << 7) -+#define RC3_LDO6_EN (1 << 6) -+#define RC3_LDO5_EN (1 << 5) -+#define RC3_LDO4_EN (1 << 4) -+#define RC3_LDO3_EN (1 << 3) -+#define RC3_LDO2_EN (1 << 2) -+#define RC3_LDO1_EN (1 << 1) -+#define RC3_BUCK_EN (1 << 0) -+ -+#define REG_CONTROL_2_98 0x98 -+#define RC4_SLEEP (1 << 7) -+#define RC4_SIMCP_ENABLE (1 << 6) -+#define RC4_LDO14_EN (1 << 5) -+#define RC4_LDO12_EN (1 << 4) -+#define RC4_LDO11_EN (1 << 3) -+#define RC4_LDO10_EN (1 << 2) -+#define RC4_LDO9_EN (1 << 1) -+#define RC4_LDO8_EN (1 << 0) -+ -+#define REG_SLEEP_CONTROL1 0x99 -+#define REG_SLEEP_CONTROL2 0x9a -+#define REG_SLEEP_CONTROL3 0x9b -+ -+#define ADC_MAN_CONTROL_1 0xa0 -+#define ADC_DEBOUNCE_VBATMON_TXON (1 << 7) -+#define ADC_DEBOUNCE_VBATMON (1 << 6) -+#define ADC_TBATREF_ENABLE (1 << 5) -+#define ADC_LDO_INT_ENABLE (1 << 4) -+#define ADC_MAN_CONV (1 << 3) -+#define ADC_MUX_VBAT (0) -+ -+#define ADC_AUTO_CONTROL_1 0xa1 -+#define ADC_IN5_EN (1 << 7) -+#define ADC_IN4_EN (1 << 6) -+#define ADC_TBAT_ENABLE (1 << 5) -+#define ADC_VBAT_IN_TXON (1 << 4) -+#define ADC_VCH_ENABLE (1 << 3) -+#define ADC_ICH_ENABLE (1 << 2) -+#define ADC_VBAT_ENABLE (1 << 1) -+#define ADC_AUTO_SLEEP_ENABLE (1 << 0) -+ -+#define VBATMON_1 0xa2 -+#define VBATMONTXMON_1 0xa3 -+#define TBATHIGHP_1 0xa4 -+#define TBATHIGHN_1 0xa5 -+#define TBATLOW_1 0xa6 -+#define MAN_RES 0xb0 -+#define VBAT_RES_1 0xb1 -+#define VBATMIN_RES_1 0xb2 -+#define VBATMINTXON_RES 0xb3 -+#define ICHMAX_RES_1 0xb4 -+#define ICHMIN_RES_1 0xb5 -+#define ICHAVERAGE_RES_1 0xb6 -+#define VCHMAX_RES_1 0xb7 -+#define VCHMIN_RES_1 0xb8 -+#define TBAT_RES_1 0xb9 -+#define ADC_IN4_RES_1 0xba -diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig -index f929fcd..174ea2e 100644 ---- a/drivers/input/touchscreen/Kconfig -+++ b/drivers/input/touchscreen/Kconfig -@@ -126,6 +126,49 @@ config TOUCHSCREEN_HP600 - To compile this driver as a module, choose M here: the - module will be called hp680_ts_input. - -+config TOUCHSCREEN_WM97XX -+ tristate "Support for WM97xx AC97 touchscreen controllers" -+ depends AC97_BUS -+ -+choice -+ prompt "WM97xx codec type" -+ depends TOUCHSCREEN_WM97XX -+ -+config TOUCHSCREEN_WM9705 -+ bool "WM9705 Touchscreen interface support" -+ depends on TOUCHSCREEN_WM97XX -+ help -+ Say Y here if you have the wm9705 touchscreen. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called wm9705. -+ -+config TOUCHSCREEN_WM9712 -+ bool "WM9712 Touchscreen interface support" -+ depends on TOUCHSCREEN_WM97XX -+ help -+ Say Y here if you have the wm9712 touchscreen. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called wm9712. -+ -+config TOUCHSCREEN_WM9713 -+ bool "WM9713 Touchscreen interface support" -+ depends on TOUCHSCREEN_WM97XX -+ help -+ Say Y here if you have the wm9713 touchscreen. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called wm9713. -+ -+endchoice -+ - config TOUCHSCREEN_PENMOUNT - tristate "Penmount serial touchscreen" - select SERIO -diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile -index 5de8933..3a059b1 100644 ---- a/drivers/input/touchscreen/Makefile -+++ b/drivers/input/touchscreen/Makefile -@@ -3,6 +3,7 @@ - # - - # Each configuration option enables a list of files. -+wm97xx-ts-objs := wm97xx-core.o - - obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o - obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o -@@ -18,3 +19,16 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o - obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o -+obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o -+ -+ifeq ($(CONFIG_TOUCHSCREEN_WM9713),y) -+wm97xx-ts-objs += wm9713.o -+endif -+ -+ifeq ($(CONFIG_TOUCHSCREEN_WM9712),y) -+wm97xx-ts-objs += wm9712.o -+endif -+ -+ifeq ($(CONFIG_TOUCHSCREEN_WM9705),y) -+wm97xx-ts-objs += wm9705.o -+endif -diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c -new file mode 100644 -index 0000000..1dae63d ---- /dev/null -+++ b/drivers/input/touchscreen/wm9705.c -@@ -0,0 +1,360 @@ -+/* -+ * wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec. -+ * -+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC. -+ * Author: Liam Girdwood -+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com -+ * Parts Copyright : Ian Molton -+ * Andrew Zabolotny -+ * Russell King -+ * -+ * 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. -+ * -+ * Revision history -+ * 6th Sep 2006 Mike Arthur -+ * Added pre and post sample calls. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TS_NAME "wm97xx" -+#define WM9705_VERSION "0.62" -+#define DEFAULT_PRESSURE 0xb0c0 -+ -+/* -+ * Debug -+ */ -+#if 0 -+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) -+#endif -+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg) -+ -+/* -+ * Module parameters -+ */ -+ -+/* -+ * Set current used for pressure measurement. -+ * -+ * Set pil = 2 to use 400uA -+ * pil = 1 to use 200uA and -+ * pil = 0 to disable pressure measurement. -+ * -+ * This is used to increase the range of values returned by the adc -+ * when measureing touchpanel pressure. -+ */ -+static int pil = 0; -+module_param(pil, int, 0); -+MODULE_PARM_DESC(pil, "Set current used for pressure measurement."); -+ -+/* -+ * Set threshold for pressure measurement. -+ * -+ * Pen down pressure below threshold is ignored. -+ */ -+static int pressure = DEFAULT_PRESSURE & 0xfff; -+module_param(pressure, int, 0); -+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement."); -+ -+/* -+ * Set adc sample delay. -+ * -+ * For accurate touchpanel measurements, some settling time may be -+ * required between the switch matrix applying a voltage across the -+ * touchpanel plate and the ADC sampling the signal. -+ * -+ * This delay can be set by setting delay = n, where n is the array -+ * position of the delay in the array delay_table below. -+ * Long delays > 1ms are supported for completeness, but are not -+ * recommended. -+ */ -+static int delay = 4; -+module_param(delay, int, 0); -+MODULE_PARM_DESC(delay, "Set adc sample delay."); -+ -+/* -+ * Pen detect comparator threshold. -+ * -+ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold -+ * i.e. 1 = Vmid/15 threshold -+ * 15 = Vmid/1 threshold -+ * -+ * Adjust this value if you are having problems with pen detect not -+ * detecting any down events. -+ */ -+static int pdd = 8; -+module_param(pdd, int, 0); -+MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold"); -+ -+/* -+ * Set adc mask function. -+ * -+ * Sources of glitch noise, such as signals driving an LCD display, may feed -+ * through to the touch screen plates and affect measurement accuracy. In -+ * order to minimise this, a signal may be applied to the MASK pin to delay or -+ * synchronise the sampling. -+ * -+ * 0 = No delay or sync -+ * 1 = High on pin stops conversions -+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above) -+ * 3 = Edge triggered, edge on pin starts conversion after delay param -+ */ -+static int mask = 0; -+module_param(mask, int, 0); -+MODULE_PARM_DESC(mask, "Set adc mask function."); -+ -+/* -+ * ADC sample delay times in uS -+ */ -+static const int delay_table[] = { -+ 21, // 1 AC97 Link frames -+ 42, // 2 -+ 84, // 4 -+ 167, // 8 -+ 333, // 16 -+ 667, // 32 -+ 1000, // 48 -+ 1333, // 64 -+ 2000, // 96 -+ 2667, // 128 -+ 3333, // 160 -+ 4000, // 192 -+ 4667, // 224 -+ 5333, // 256 -+ 6000, // 288 -+ 0 // No delay, switch matrix always on -+}; -+ -+/* -+ * Delay after issuing a POLL command. -+ * -+ * The delay is 3 AC97 link frames + the touchpanel settling delay -+ */ -+static inline void poll_delay(int d) -+{ -+ udelay (3 * AC97_LINK_FRAME + delay_table [d]); -+} -+ -+/* -+ * set up the physical settings of the WM9705 -+ */ -+static void init_wm9705_phy(struct wm97xx* wm) -+{ -+ u16 dig1 = 0, dig2 = WM97XX_RPR; -+ -+ /* -+ * mute VIDEO and AUX as they share X and Y touchscreen -+ * inputs on the WM9705 -+ */ -+ wm97xx_reg_write(wm, AC97_AUX, 0x8000); -+ wm97xx_reg_write(wm, AC97_VIDEO, 0x8000); -+ -+ /* touchpanel pressure current*/ -+ if (pil == 2) { -+ dig2 |= WM9705_PIL; -+ dbg("setting pressure measurement current to 400uA."); -+ } else if (pil) -+ dbg("setting pressure measurement current to 200uA."); -+ if(!pil) -+ pressure = 0; -+ -+ /* polling mode sample settling delay */ -+ if (delay!=4) { -+ if (delay < 0 || delay > 15) { -+ dbg("supplied delay out of range."); -+ delay = 4; -+ } -+ } -+ dig1 &= 0xff0f; -+ dig1 |= WM97XX_DELAY(delay); -+ dbg("setting adc sample delay to %d u Secs.", delay_table[delay]); -+ -+ /* WM9705 pdd */ -+ dig2 |= (pdd & 0x000f); -+ dbg("setting pdd to Vmid/%d", 1 - (pdd & 0x000f)); -+ -+ /* mask */ -+ dig2 |= ((mask & 0x3) << 4); -+ -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2); -+} -+ -+static int wm9705_digitiser_ioctl(struct wm97xx* wm, int cmd) -+{ -+ switch(cmd) { -+ case WM97XX_DIG_START: -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig[2] | WM97XX_PRP_DET_DIG); -+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */ -+ break; -+ case WM97XX_DIG_STOP: -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig[2] & ~WM97XX_PRP_DET_DIG); -+ break; -+ case WM97XX_AUX_PREPARE: -+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig)); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG); -+ break; -+ case WM97XX_DIG_RESTORE: -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]); -+ break; -+ case WM97XX_PHY_INIT: -+ init_wm9705_phy(wm); -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static inline int is_pden (struct wm97xx* wm) -+{ -+ return wm->dig[2] & WM9705_PDEN; -+} -+ -+/* -+ * Read a sample from the WM9705 adc in polling mode. -+ */ -+static int wm9705_poll_sample (struct wm97xx* wm, int adcsel, int *sample) -+{ -+ int timeout = 5 * delay; -+ -+ if (!wm->pen_probably_down) { -+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (!(data & WM97XX_PEN_DOWN)) -+ return RC_PENUP; -+ wm->pen_probably_down = 1; -+ } -+ -+ /* set up digitiser */ -+ if (adcsel & 0x8000) -+ adcsel = ((adcsel & 0x7fff) + 3) << 12; -+ -+ if (wm->mach_ops && wm->mach_ops->pre_sample) -+ wm->mach_ops->pre_sample(adcsel); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay)); -+ -+ /* wait 3 AC97 time slots + delay for conversion */ -+ poll_delay (delay); -+ -+ /* wait for POLL to go low */ -+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) { -+ udelay(AC97_LINK_FRAME); -+ timeout--; -+ } -+ -+ if (timeout <= 0) { -+ /* If PDEN is set, we can get a timeout when pen goes up */ -+ if (is_pden(wm)) -+ wm->pen_probably_down = 0; -+ else -+ dbg ("adc sample timeout"); -+ return RC_PENUP; -+ } -+ -+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (wm->mach_ops && wm->mach_ops->post_sample) -+ wm->mach_ops->post_sample(adcsel); -+ -+ /* check we have correct sample */ -+ if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) { -+ dbg ("adc wrong sample, read %x got %x", adcsel, -+ *sample & WM97XX_ADCSEL_MASK); -+ return RC_PENUP; -+ } -+ -+ if (!(*sample & WM97XX_PEN_DOWN)) { -+ wm->pen_probably_down = 0; -+ return RC_PENUP; -+ } -+ -+ return RC_VALID; -+} -+ -+/* -+ * Sample the WM9705 touchscreen in polling mode -+ */ -+static int wm9705_poll_touch(struct wm97xx* wm, struct wm97xx_data *data) -+{ -+ int rc; -+ -+ if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID) -+ return rc; -+ if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID) -+ return rc; -+ if (pil) { -+ if ((rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID) -+ return rc; -+ } else -+ data->p = DEFAULT_PRESSURE; -+ -+ return RC_VALID; -+} -+ -+/* -+ * Enable WM9705 continuous mode, i.e. touch data is streamed across an AC97 slot -+ */ -+static int wm9705_acc_enable (struct wm97xx* wm, int enable) -+{ -+ u16 dig1, dig2; -+ int ret = 0; -+ -+ dig1 = wm->dig[1]; -+ dig2 = wm->dig[2]; -+ -+ if (enable) { -+ /* continous mode */ -+ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0) -+ return ret; -+ dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK | -+ WM97XX_DELAY_MASK | WM97XX_SLT_MASK); -+ dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN | -+ WM97XX_DELAY (delay) | -+ WM97XX_SLT (wm->acc_slot) | -+ WM97XX_RATE (wm->acc_rate); -+ if (pil) -+ dig1 |= WM97XX_ADCSEL_PRES; -+ dig2 |= WM9705_PDEN; -+ } else { -+ dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN); -+ dig2 &= ~WM9705_PDEN; -+ if (wm->mach_ops->acc_shutdown) -+ wm->mach_ops->acc_shutdown(wm); -+ } -+ -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2); -+ return ret; -+} -+ -+struct wm97xx_codec_drv wm97xx_codec = { -+ .id = WM9705_ID2, -+ .name = "wm9705", -+ .poll_sample = wm9705_poll_sample, -+ .poll_touch = wm9705_poll_touch, -+ .acc_enable = wm9705_acc_enable, -+ .digitiser_ioctl = wm9705_digitiser_ioctl, -+}; -+ -+EXPORT_SYMBOL_GPL(wm97xx_codec); -+ -+/* Module information */ -+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); -+MODULE_DESCRIPTION("WM9705 Touch Screen Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c -new file mode 100644 -index 0000000..99433e9 ---- /dev/null -+++ b/drivers/input/touchscreen/wm9712.c -@@ -0,0 +1,464 @@ -+/* -+ * wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs. -+ * -+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC. -+ * Author: Liam Girdwood -+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com -+ * Parts Copyright : Ian Molton -+ * Andrew Zabolotny -+ * Russell King -+ * -+ * 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. -+ * -+ * Revision history -+ * 4th Jul 2005 Initial version. -+ * 6th Sep 2006 Mike Arthur -+ * Added pre and post sample calls. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TS_NAME "wm97xx" -+#define WM9712_VERSION "0.61" -+#define DEFAULT_PRESSURE 0xb0c0 -+ -+/* -+ * Debug -+ */ -+#if 0 -+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) -+#endif -+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg) -+ -+/* -+ * Module parameters -+ */ -+ -+/* -+ * Set internal pull up for pen detect. -+ * -+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive) -+ * i.e. pull up resistance = 64k Ohms / rpu. -+ * -+ * Adjust this value if you are having problems with pen detect not -+ * detecting any down event. -+ */ -+static int rpu = 8; -+module_param(rpu, int, 0); -+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect."); -+ -+/* -+ * Set current used for pressure measurement. -+ * -+ * Set pil = 2 to use 400uA -+ * pil = 1 to use 200uA and -+ * pil = 0 to disable pressure measurement. -+ * -+ * This is used to increase the range of values returned by the adc -+ * when measureing touchpanel pressure. -+ */ -+static int pil = 0; -+module_param(pil, int, 0); -+MODULE_PARM_DESC(pil, "Set current used for pressure measurement."); -+ -+/* -+ * Set threshold for pressure measurement. -+ * -+ * Pen down pressure below threshold is ignored. -+ */ -+static int pressure = DEFAULT_PRESSURE & 0xfff; -+module_param(pressure, int, 0); -+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement."); -+ -+/* -+ * Set adc sample delay. -+ * -+ * For accurate touchpanel measurements, some settling time may be -+ * required between the switch matrix applying a voltage across the -+ * touchpanel plate and the ADC sampling the signal. -+ * -+ * This delay can be set by setting delay = n, where n is the array -+ * position of the delay in the array delay_table below. -+ * Long delays > 1ms are supported for completeness, but are not -+ * recommended. -+ */ -+static int delay = 3; -+module_param(delay, int, 0); -+MODULE_PARM_DESC(delay, "Set adc sample delay."); -+ -+/* -+ * Set five_wire = 1 to use a 5 wire touchscreen. -+ * -+ * NOTE: Five wire mode does not allow for readback of pressure. -+ */ -+static int five_wire; -+module_param(five_wire, int, 0); -+MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen."); -+ -+/* -+ * Set adc mask function. -+ * -+ * Sources of glitch noise, such as signals driving an LCD display, may feed -+ * through to the touch screen plates and affect measurement accuracy. In -+ * order to minimise this, a signal may be applied to the MASK pin to delay or -+ * synchronise the sampling. -+ * -+ * 0 = No delay or sync -+ * 1 = High on pin stops conversions -+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above) -+ * 3 = Edge triggered, edge on pin starts conversion after delay param -+ */ -+static int mask = 0; -+module_param(mask, int, 0); -+MODULE_PARM_DESC(mask, "Set adc mask function."); -+ -+/* -+ * Coordinate Polling Enable. -+ * -+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together -+ * for every poll. -+ */ -+static int coord = 0; -+module_param(coord, int, 0); -+MODULE_PARM_DESC(coord, "Polling coordinate mode"); -+ -+/* -+ * ADC sample delay times in uS -+ */ -+static const int delay_table[] = { -+ 21, // 1 AC97 Link frames -+ 42, // 2 -+ 84, // 4 -+ 167, // 8 -+ 333, // 16 -+ 667, // 32 -+ 1000, // 48 -+ 1333, // 64 -+ 2000, // 96 -+ 2667, // 128 -+ 3333, // 160 -+ 4000, // 192 -+ 4667, // 224 -+ 5333, // 256 -+ 6000, // 288 -+ 0 // No delay, switch matrix always on -+}; -+ -+/* -+ * Delay after issuing a POLL command. -+ * -+ * The delay is 3 AC97 link frames + the touchpanel settling delay -+ */ -+static inline void poll_delay(int d) -+{ -+ udelay (3 * AC97_LINK_FRAME + delay_table [d]); -+} -+ -+/* -+ * set up the physical settings of the WM9712 -+ */ -+static void init_wm9712_phy(struct wm97xx* wm) -+{ -+ u16 dig1 = 0; -+ u16 dig2 = WM97XX_RPR | WM9712_RPU(1); -+ -+ /* WM9712 rpu */ -+ if (rpu) { -+ dig2 &= 0xffc0; -+ dig2 |= WM9712_RPU(rpu); -+ dbg("setting pen detect pull-up to %d Ohms",64000 / rpu); -+ } -+ -+ /* touchpanel pressure current*/ -+ if (pil == 2) { -+ dig2 |= WM9712_PIL; -+ dbg("setting pressure measurement current to 400uA."); -+ } else if (pil) -+ dbg("setting pressure measurement current to 200uA."); -+ if(!pil) -+ pressure = 0; -+ -+ /* WM9712 five wire */ -+ if (five_wire) { -+ dig2 |= WM9712_45W; -+ dbg("setting 5-wire touchscreen mode."); -+ } -+ -+ /* polling mode sample settling delay */ -+ if (delay < 0 || delay > 15) { -+ dbg("supplied delay out of range."); -+ delay = 4; -+ } -+ dig1 &= 0xff0f; -+ dig1 |= WM97XX_DELAY(delay); -+ dbg("setting adc sample delay to %d u Secs.", delay_table[delay]); -+ -+ /* mask */ -+ dig2 |= ((mask & 0x3) << 6); -+ if (mask) { -+ u16 reg; -+ /* Set GPIO4 as Mask Pin*/ -+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE); -+ wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4); -+ reg = wm97xx_reg_read(wm, AC97_GPIO_CFG); -+ wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4); -+ } -+ -+ /* wait - coord mode */ -+ if(coord) -+ dig2 |= WM9712_WAIT; -+ -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2); -+} -+ -+static int wm9712_digitiser_ioctl(struct wm97xx* wm, int cmd) -+{ -+ u16 dig2 = wm->dig[2]; -+ -+ switch(cmd) { -+ case WM97XX_DIG_START: -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2 | WM97XX_PRP_DET_DIG); -+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */ -+ break; -+ case WM97XX_DIG_STOP: -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2 & ~WM97XX_PRP_DET_DIG); -+ break; -+ case WM97XX_AUX_PREPARE: -+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig)); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG); -+ break; -+ case WM97XX_DIG_RESTORE: -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]); -+ break; -+ case WM97XX_PHY_INIT: -+ init_wm9712_phy(wm); -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static inline int is_pden (struct wm97xx* wm) -+{ -+ return wm->dig[2] & WM9712_PDEN; -+} -+ -+/* -+ * Read a sample from the WM9712 adc in polling mode. -+ */ -+static int wm9712_poll_sample (struct wm97xx* wm, int adcsel, int *sample) -+{ -+ int timeout = 5 * delay; -+ -+ if (!wm->pen_probably_down) { -+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (!(data & WM97XX_PEN_DOWN)) -+ return RC_PENUP; -+ wm->pen_probably_down = 1; -+ } -+ -+ /* set up digitiser */ -+ if (adcsel & 0x8000) -+ adcsel = ((adcsel & 0x7fff) + 3) << 12; -+ -+ if (wm->mach_ops && wm->mach_ops->pre_sample) -+ wm->mach_ops->pre_sample(adcsel); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, adcsel | WM97XX_POLL | WM97XX_DELAY(delay)); -+ -+ /* wait 3 AC97 time slots + delay for conversion */ -+ poll_delay (delay); -+ -+ /* wait for POLL to go low */ -+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) { -+ udelay(AC97_LINK_FRAME); -+ timeout--; -+ } -+ -+ if (timeout <= 0) { -+ /* If PDEN is set, we can get a timeout when pen goes up */ -+ if (is_pden(wm)) -+ wm->pen_probably_down = 0; -+ else -+ dbg ("adc sample timeout"); -+ return RC_PENUP; -+ } -+ -+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (wm->mach_ops && wm->mach_ops->post_sample) -+ wm->mach_ops->post_sample(adcsel); -+ -+ /* check we have correct sample */ -+ if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) { -+ dbg ("adc wrong sample, read %x got %x", adcsel, -+ *sample & WM97XX_ADCSEL_MASK); -+ return RC_PENUP; -+ } -+ -+ if (!(*sample & WM97XX_PEN_DOWN)) { -+ wm->pen_probably_down = 0; -+ return RC_PENUP; -+ } -+ -+ return RC_VALID; -+} -+ -+/* -+ * Read a coord from the WM9712 adc in polling mode. -+ */ -+static int wm9712_poll_coord (struct wm97xx* wm, struct wm97xx_data *data) -+{ -+ int timeout = 5 * delay; -+ -+ if (!wm->pen_probably_down) { -+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (!(data & WM97XX_PEN_DOWN)) -+ return RC_PENUP; -+ wm->pen_probably_down = 1; -+ } -+ -+ /* set up digitiser */ -+ if (wm->mach_ops && wm->mach_ops->pre_sample) -+ wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y); -+ -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, -+ WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay)); -+ -+ /* wait 3 AC97 time slots + delay for conversion and read x */ -+ poll_delay(delay); -+ data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ /* wait for POLL to go low */ -+ while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) { -+ udelay(AC97_LINK_FRAME); -+ timeout--; -+ } -+ -+ if (timeout <= 0) { -+ /* If PDEN is set, we can get a timeout when pen goes up */ -+ if (is_pden(wm)) -+ wm->pen_probably_down = 0; -+ else -+ dbg ("adc sample timeout"); -+ return RC_PENUP; -+ } -+ -+ /* read back y data */ -+ data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (pil) -+ data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ else -+ data->p = DEFAULT_PRESSURE; -+ -+ if (wm->mach_ops && wm->mach_ops->post_sample) -+ wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y); -+ -+ /* check we have correct sample */ -+ if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y)) -+ goto err; -+ if(pil && !(data->p & WM97XX_ADCSEL_PRES)) -+ goto err; -+ -+ if (!(data->x & WM97XX_PEN_DOWN)) { -+ wm->pen_probably_down = 0; -+ return RC_PENUP; -+ } -+ return RC_VALID; -+err: -+ return RC_PENUP; -+} -+ -+/* -+ * Sample the WM9712 touchscreen in polling mode -+ */ -+static int wm9712_poll_touch(struct wm97xx* wm, struct wm97xx_data *data) -+{ -+ int rc; -+ -+ if(coord) { -+ if((rc = wm9712_poll_coord(wm, data)) != RC_VALID) -+ return rc; -+ } else { -+ if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x)) != RC_VALID) -+ return rc; -+ -+ if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y)) != RC_VALID) -+ return rc; -+ -+ if (pil && !five_wire) { -+ if ((rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p)) != RC_VALID) -+ return rc; -+ } else -+ data->p = DEFAULT_PRESSURE; -+ } -+ return RC_VALID; -+} -+ -+/* -+ * Enable WM9712 continuous mode, i.e. touch data is streamed across an AC97 slot -+ */ -+static int wm9712_acc_enable (struct wm97xx* wm, int enable) -+{ -+ u16 dig1, dig2; -+ int ret = 0; -+ -+ dig1 = wm->dig[1]; -+ dig2 = wm->dig[2]; -+ -+ if (enable) { -+ /* continous mode */ -+ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0) -+ return ret; -+ dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK | -+ WM97XX_DELAY_MASK | WM97XX_SLT_MASK); -+ dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN | -+ WM97XX_DELAY (delay) | -+ WM97XX_SLT (wm->acc_slot) | -+ WM97XX_RATE (wm->acc_rate); -+ if (pil) -+ dig1 |= WM97XX_ADCSEL_PRES; -+ dig2 |= WM9712_PDEN; -+ } else { -+ dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN); -+ dig2 &= ~WM9712_PDEN; -+ if (wm->mach_ops->acc_shutdown) -+ wm->mach_ops->acc_shutdown(wm); -+ } -+ -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1); -+ wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2); -+ return 0; -+} -+ -+struct wm97xx_codec_drv wm97xx_codec = { -+ .id = WM9712_ID2, -+ .name = "wm9712", -+ .poll_sample = wm9712_poll_sample, -+ .poll_touch = wm9712_poll_touch, -+ .acc_enable = wm9712_acc_enable, -+ .digitiser_ioctl = wm9712_digitiser_ioctl, -+}; -+ -+EXPORT_SYMBOL_GPL(wm97xx_codec); -+ -+/* Module information */ -+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); -+MODULE_DESCRIPTION("WM9712 Touch Screen Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c -new file mode 100644 -index 0000000..42f5f30 ---- /dev/null -+++ b/drivers/input/touchscreen/wm9713.c -@@ -0,0 +1,461 @@ -+/* -+ * wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec. -+ * -+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC. -+ * Author: Liam Girdwood -+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com -+ * Parts Copyright : Ian Molton -+ * Andrew Zabolotny -+ * Russell King -+ * -+ * 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. -+ * -+ * Revision history -+ * 6th Sep 2006 Mike Arthur -+ * Added pre and post sample calls. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TS_NAME "wm97xx" -+#define WM9713_VERSION "0.53" -+#define DEFAULT_PRESSURE 0xb0c0 -+ -+/* -+ * Debug -+ */ -+#if 0 -+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) -+#endif -+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg) -+ -+/* -+ * Module parameters -+ */ -+ -+/* -+ * Set internal pull up for pen detect. -+ * -+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive) -+ * i.e. pull up resistance = 64k Ohms / rpu. -+ * -+ * Adjust this value if you are having problems with pen detect not -+ * detecting any down event. -+ */ -+static int rpu = 8; -+module_param(rpu, int, 0); -+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect."); -+ -+/* -+ * Set current used for pressure measurement. -+ * -+ * Set pil = 2 to use 400uA -+ * pil = 1 to use 200uA and -+ * pil = 0 to disable pressure measurement. -+ * -+ * This is used to increase the range of values returned by the adc -+ * when measureing touchpanel pressure. -+ */ -+static int pil = 0; -+module_param(pil, int, 0); -+MODULE_PARM_DESC(pil, "Set current used for pressure measurement."); -+ -+/* -+ * Set threshold for pressure measurement. -+ * -+ * Pen down pressure below threshold is ignored. -+ */ -+static int pressure = DEFAULT_PRESSURE & 0xfff; -+module_param(pressure, int, 0); -+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement."); -+ -+/* -+ * Set adc sample delay. -+ * -+ * For accurate touchpanel measurements, some settling time may be -+ * required between the switch matrix applying a voltage across the -+ * touchpanel plate and the ADC sampling the signal. -+ * -+ * This delay can be set by setting delay = n, where n is the array -+ * position of the delay in the array delay_table below. -+ * Long delays > 1ms are supported for completeness, but are not -+ * recommended. -+ */ -+static int delay = 4; -+module_param(delay, int, 0); -+MODULE_PARM_DESC(delay, "Set adc sample delay."); -+ -+/* -+ * Set adc mask function. -+ * -+ * Sources of glitch noise, such as signals driving an LCD display, may feed -+ * through to the touch screen plates and affect measurement accuracy. In -+ * order to minimise this, a signal may be applied to the MASK pin to delay or -+ * synchronise the sampling. -+ * -+ * 0 = No delay or sync -+ * 1 = High on pin stops conversions -+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above) -+ * 3 = Edge triggered, edge on pin starts conversion after delay param -+ */ -+static int mask = 0; -+module_param(mask, int, 0); -+MODULE_PARM_DESC(mask, "Set adc mask function."); -+ -+/* -+ * Coordinate Polling Enable. -+ * -+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together -+ * for every poll. -+ */ -+static int coord = 0; -+module_param(coord, int, 0); -+MODULE_PARM_DESC(coord, "Polling coordinate mode"); -+ -+/* -+ * ADC sample delay times in uS -+ */ -+static const int delay_table[] = { -+ 21, // 1 AC97 Link frames -+ 42, // 2 -+ 84, // 4 -+ 167, // 8 -+ 333, // 16 -+ 667, // 32 -+ 1000, // 48 -+ 1333, // 64 -+ 2000, // 96 -+ 2667, // 128 -+ 3333, // 160 -+ 4000, // 192 -+ 4667, // 224 -+ 5333, // 256 -+ 6000, // 288 -+ 0 // No delay, switch matrix always on -+}; -+ -+/* -+ * Delay after issuing a POLL command. -+ * -+ * The delay is 3 AC97 link frames + the touchpanel settling delay -+ */ -+static inline void poll_delay(int d) -+{ -+ udelay (3 * AC97_LINK_FRAME + delay_table [d]); -+} -+ -+/* -+ * set up the physical settings of the WM9713 -+ */ -+static void init_wm9713_phy(struct wm97xx* wm) -+{ -+ u16 dig1 = 0, dig2, dig3; -+ -+ /* default values */ -+ dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5); -+ dig3= WM9712_RPU(1); -+ -+ /* rpu */ -+ if (rpu) { -+ dig3 &= 0xffc0; -+ dig3 |= WM9712_RPU(rpu); -+ info("setting pen detect pull-up to %d Ohms",64000 / rpu); -+ } -+ -+ /* touchpanel pressure */ -+ if (pil == 2) { -+ dig3 |= WM9712_PIL; -+ info("setting pressure measurement current to 400uA."); -+ } else if (pil) -+ info ("setting pressure measurement current to 200uA."); -+ if(!pil) -+ pressure = 0; -+ -+ /* sample settling delay */ -+ if (delay < 0 || delay > 15) { -+ info ("supplied delay out of range."); -+ delay = 4; -+ info("setting adc sample delay to %d u Secs.", delay_table[delay]); -+ } -+ dig2 &= 0xff0f; -+ dig2 |= WM97XX_DELAY(delay); -+ -+ /* mask */ -+ dig3 |= ((mask & 0x3) << 4); -+ if(coord) -+ dig3 |= WM9713_WAIT; -+ -+ wm->misc = wm97xx_reg_read(wm, 0x5a); -+ -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3); -+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0); -+} -+ -+static int wm9713_digitiser_ioctl(struct wm97xx* wm, int cmd) -+{ -+ u16 val = 0; -+ -+ switch(cmd){ -+ case WM97XX_DIG_START: -+ val = wm97xx_reg_read(wm, AC97_EXTENDED_MID); -+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] | WM97XX_PRP_DET_DIG); -+ wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */ -+ break; -+ case WM97XX_DIG_STOP: -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] & ~WM97XX_PRP_DET_DIG); -+ val = wm97xx_reg_read(wm, AC97_EXTENDED_MID); -+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000); -+ break; -+ case WM97XX_AUX_PREPARE: -+ memcpy(wm->dig_save, wm->dig, sizeof(wm->dig)); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG); -+ break; -+ case WM97XX_DIG_RESTORE: -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]); -+ break; -+ case WM97XX_PHY_INIT: -+ init_wm9713_phy(wm); -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static inline int is_pden (struct wm97xx* wm) -+{ -+ return wm->dig[2] & WM9713_PDEN; -+} -+ -+/* -+ * Read a sample from the WM9713 adc in polling mode. -+ */ -+static int wm9713_poll_sample (struct wm97xx* wm, int adcsel, int *sample) -+{ -+ u16 dig1; -+ int timeout = 5 * delay; -+ -+ if (!wm->pen_probably_down) { -+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (!(data & WM97XX_PEN_DOWN)) -+ return RC_PENUP; -+ wm->pen_probably_down = 1; -+ } -+ -+ /* set up digitiser */ -+ if (adcsel & 0x8000) -+ adcsel = 1 << ((adcsel & 0x7fff) + 3); -+ -+ dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1); -+ dig1 &= ~WM9713_ADCSEL_MASK; -+ -+ if (wm->mach_ops && wm->mach_ops->pre_sample) -+ wm->mach_ops->pre_sample(adcsel); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel |WM9713_POLL); -+ -+ /* wait 3 AC97 time slots + delay for conversion */ -+ poll_delay(delay); -+ -+ /* wait for POLL to go low */ -+ while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && timeout) { -+ udelay(AC97_LINK_FRAME); -+ timeout--; -+ } -+ -+ if (timeout <= 0) { -+ /* If PDEN is set, we can get a timeout when pen goes up */ -+ if (is_pden(wm)) -+ wm->pen_probably_down = 0; -+ else -+ dbg ("adc sample timeout"); -+ return RC_PENUP; -+ } -+ -+ *sample =wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (wm->mach_ops && wm->mach_ops->post_sample) -+ wm->mach_ops->post_sample(adcsel); -+ -+ /* check we have correct sample */ -+ if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) { -+ dbg ("adc wrong sample, read %x got %x", adcsel, -+ *sample & WM97XX_ADCSRC_MASK); -+ return RC_PENUP; -+ } -+ -+ if (!(*sample & WM97XX_PEN_DOWN)) { -+ wm->pen_probably_down = 0; -+ return RC_PENUP; -+ } -+ -+ return RC_VALID; -+} -+ -+/* -+ * Read a coordinate from the WM9713 adc in polling mode. -+ */ -+static int wm9713_poll_coord (struct wm97xx* wm, struct wm97xx_data *data) -+{ -+ u16 dig1; -+ int timeout = 5 * delay; -+ -+ if (!wm->pen_probably_down) { -+ u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (!(data & WM97XX_PEN_DOWN)) -+ return RC_PENUP; -+ wm->pen_probably_down = 1; -+ } -+ -+ /* set up digitiser */ -+ dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1); -+ dig1 &= ~WM9713_ADCSEL_MASK; -+ if(pil) -+ dig1 |= WM97XX_ADCSEL_PRES; -+ -+ if (wm->mach_ops && wm->mach_ops->pre_sample) -+ wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL | WM9713_COO); -+ -+ /* wait 3 AC97 time slots + delay for conversion */ -+ poll_delay(delay); -+ data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ /* wait for POLL to go low */ -+ while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) && timeout) { -+ udelay(AC97_LINK_FRAME); -+ timeout--; -+ } -+ -+ if (timeout <= 0) { -+ /* If PDEN is set, we can get a timeout when pen goes up */ -+ if (is_pden(wm)) -+ wm->pen_probably_down = 0; -+ else -+ dbg ("adc sample timeout"); -+ return RC_PENUP; -+ } -+ -+ /* read back data */ -+ data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ if (pil) -+ data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); -+ else -+ data->p = DEFAULT_PRESSURE; -+ -+ if (wm->mach_ops && wm->mach_ops->post_sample) -+ wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y); -+ -+ /* check we have correct sample */ -+ if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y)) -+ goto err; -+ if(pil && !(data->p & WM97XX_ADCSEL_PRES)) -+ goto err; -+ -+ if (!(data->x & WM97XX_PEN_DOWN)) { -+ wm->pen_probably_down = 0; -+ return RC_PENUP; -+ } -+ return RC_VALID; -+err: -+ return RC_PENUP; -+} -+ -+/* -+ * Sample the WM9713 touchscreen in polling mode -+ */ -+static int wm9713_poll_touch(struct wm97xx* wm, struct wm97xx_data *data) -+{ -+ int rc; -+ -+ if(coord) { -+ if((rc = wm9713_poll_coord(wm, data)) != RC_VALID) -+ return rc; -+ } else { -+ if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x)) != RC_VALID) -+ return rc; -+ if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y)) != RC_VALID) -+ return rc; -+ if (pil) { -+ if ((rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES, &data->p)) != RC_VALID) -+ return rc; -+ } else -+ data->p = DEFAULT_PRESSURE; -+ } -+ return RC_VALID; -+} -+ -+/* -+ * Enable WM9713 continuous mode, i.e. touch data is streamed across an AC97 slot -+ */ -+static int wm9713_acc_enable (struct wm97xx* wm, int enable) -+{ -+ u16 dig1, dig2, dig3; -+ int ret = 0; -+ -+ dig1 = wm->dig[0]; -+ dig2 = wm->dig[1]; -+ dig3 = wm->dig[2]; -+ -+ if (enable) { -+ /* continous mode */ -+ if (wm->mach_ops->acc_startup && -+ (ret = wm->mach_ops->acc_startup(wm)) < 0) -+ return ret; -+ -+ dig1 &= ~WM9713_ADCSEL_MASK; -+ dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X | WM9713_ADCSEL_Y; -+ if (pil) -+ dig1 |= WM9713_ADCSEL_PRES; -+ dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK | WM97XX_CM_RATE_MASK); -+ dig2 |= WM97XX_SLEN | WM97XX_DELAY (delay) | -+ WM97XX_SLT (wm->acc_slot) | WM97XX_RATE (wm->acc_rate); -+ dig3 |= WM9713_PDEN; -+ } else { -+ dig1 &= ~(WM9713_CTC | WM9713_COO); -+ dig2 &= ~WM97XX_SLEN; -+ dig3 &= ~WM9713_PDEN; -+ if (wm->mach_ops->acc_shutdown) -+ wm->mach_ops->acc_shutdown(wm); -+ } -+ -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3); -+ return ret; -+} -+ -+struct wm97xx_codec_drv wm97xx_codec = { -+ .id = WM9713_ID2, -+ .name = "wm9713", -+ .poll_sample = wm9713_poll_sample, -+ .poll_touch = wm9713_poll_touch, -+ .acc_enable = wm9713_acc_enable, -+ .digitiser_ioctl = wm9713_digitiser_ioctl, -+}; -+ -+EXPORT_SYMBOL_GPL(wm97xx_codec); -+ -+/* Module information */ -+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); -+MODULE_DESCRIPTION("WM9713 Touch Screen Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c -new file mode 100644 -index 0000000..87179d2 ---- /dev/null -+++ b/drivers/input/touchscreen/wm97xx-core.c -@@ -0,0 +1,859 @@ -+/* -+ * wm97xx-core.c -- Touch screen driver core for Wolfson WM9705, WM9712 -+ * and WM9713 AC97 Codecs. -+ * -+ * Copyright 2003, 2004, 2005, 2006 Wolfson Microelectronics PLC. -+ * Author: Liam Girdwood -+ * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com -+ * Parts Copyright : Ian Molton -+ * Andrew Zabolotny -+ * Russell King -+ * -+ * 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. -+ * -+ * Notes: -+ * -+ * Features: -+ * - supports WM9705, WM9712, WM9713 -+ * - polling mode -+ * - continuous mode (arch-dependent) -+ * - adjustable rpu/dpp settings -+ * - adjustable pressure current -+ * - adjustable sample settle delay -+ * - 4 and 5 wire touchscreens (5 wire is WM9712 only) -+ * - pen down detection -+ * - battery monitor -+ * - sample AUX adc's -+ * - power management -+ * - codec GPIO -+ * - codec event notification -+ * Todo -+ * - Support for async sampling control for noisy LCD's. -+ * -+ * Revision history -+ * 7th May 2003 Initial version. -+ * 6th June 2003 Added non module support and AC97 registration. -+ * 18th June 2003 Added AUX adc sampling. -+ * 23rd June 2003 Did some minimal reformatting, fixed a couple of -+ * codec_mutexing bugs and noted a race to fix. -+ * 24th June 2003 Added power management and fixed race condition. -+ * 10th July 2003 Changed to a misc device. -+ * 31st July 2003 Moved TS_EVENT and TS_CAL to wm97xx.h -+ * 8th Aug 2003 Added option for read() calling wm97xx_sample_touch() -+ * because some ac97_read/ac_97_write call schedule() -+ * 7th Nov 2003 Added Input touch event interface, stanley.cai@intel.com -+ * 13th Nov 2003 Removed h3600 touch interface, added interrupt based -+ * pen down notification and implemented continous mode -+ * on XScale arch. -+ * 16th Nov 2003 Ian Molton -+ * Modified so that it suits the new 2.6 driver model. -+ * 25th Jan 2004 Andrew Zabolotny -+ * Implemented IRQ-driven pen down detection, implemented -+ * the private API meant to be exposed to platform-specific -+ * drivers, reorganized the driver so that it supports -+ * an arbitrary number of devices. -+ * 1st Feb 2004 Moved continuous mode handling to a separate -+ * architecture-dependent file. For now only PXA -+ * built-in AC97 controller is supported (pxa-ac97-wm97xx.c). -+ * 11th Feb 2004 Reduced CPU usage by keeping a cached copy of both -+ * digitizer registers instead of reading them every time. -+ * A reorganization of the whole code for better -+ * error handling. -+ * 17th Apr 2004 Added BMON support. -+ * 17th Nov 2004 Added codec GPIO, codec event handling (real and virtual -+ * GPIOs) and 2.6 power management. -+ * 29th Nov 2004 Added WM9713 support. -+ * 4th Jul 2005 Moved codec specific code out to seperate files. -+ * 6th Sep 2006 Mike Arthur -+ * Added bus interface. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define TS_NAME "wm97xx" -+#define WM_CORE_VERSION "0.64" -+#define DEFAULT_PRESSURE 0xb0c0 -+ -+ -+/* -+ * Touchscreen absolute values -+ * -+ * These parameters are used to help the input layer discard out of -+ * range readings and reduce jitter etc. -+ * -+ * o min, max:- indicate the min and max values your touch screen returns -+ * o fuzz:- use a higher number to reduce jitter -+ * -+ * The default values correspond to Mainstone II in QVGA mode -+ * -+ * Please read -+ * Documentation/input/input-programming.txt for more details. -+ */ -+ -+static int abs_x[3] = {350,3900,5}; -+module_param_array(abs_x, int, NULL, 0); -+MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz"); -+ -+static int abs_y[3] = {320,3750,40}; -+module_param_array(abs_y, int, NULL, 0); -+MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz"); -+ -+static int abs_p[3] = {0,150,4}; -+module_param_array(abs_p, int, NULL, 0); -+MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz"); -+ -+/* -+ * Debug -+ */ -+#if 0 -+#define dbg(format, arg...) printk(KERN_DEBUG TS_NAME ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) -+#endif -+#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg) -+ -+/* -+ * wm97xx IO access, all IO locking done by AC97 layer -+ */ -+int wm97xx_reg_read(struct wm97xx *wm, u16 reg) -+{ -+ if (wm->ac97) -+ return wm->ac97->bus->ops->read(wm->ac97, reg); -+ else -+ return -1; -+} -+EXPORT_SYMBOL_GPL(wm97xx_reg_read); -+ -+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val) -+{ -+ /* cache digitiser registers */ -+ if(reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3) -+ wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val; -+ -+ /* cache gpio regs */ -+ if(reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE) -+ wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val; -+ -+ /* wm9713 irq reg */ -+ if(reg == 0x5a) -+ wm->misc = val; -+ -+ if (wm->ac97) -+ wm->ac97->bus->ops->write(wm->ac97, reg, val); -+} -+EXPORT_SYMBOL_GPL(wm97xx_reg_write); -+ -+/** -+ * wm97xx_read_aux_adc - Read the aux adc. -+ * @wm: wm97xx device. -+ * @adcsel: codec ADC to be read -+ * -+ * Reads the selected AUX ADC. -+ */ -+ -+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) -+{ -+ int power_adc = 0, auxval; -+ u16 power = 0; -+ -+ /* get codec */ -+ mutex_lock(&wm->codec_mutex); -+ -+ /* When the touchscreen is not in use, we may have to power up the AUX ADC -+ * before we can use sample the AUX inputs-> -+ */ -+ if (wm->id == WM9713_ID2 && -+ (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) { -+ power_adc = 1; -+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff); -+ } -+ -+ /* Prepare the codec for AUX reading */ -+ wm->codec->digitiser_ioctl(wm, WM97XX_AUX_PREPARE); -+ -+ /* Turn polling mode on to read AUX ADC */ -+ wm->pen_probably_down = 1; -+ wm->codec->poll_sample(wm, adcsel, &auxval); -+ -+ if (power_adc) -+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000); -+ -+ wm->codec->digitiser_ioctl(wm, WM97XX_DIG_RESTORE); -+ -+ wm->pen_probably_down = 0; -+ -+ mutex_unlock(&wm->codec_mutex); -+ return auxval & 0xfff; -+} -+EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc); -+ -+/** -+ * wm97xx_get_gpio - Get the status of a codec GPIO. -+ * @wm: wm97xx device. -+ * @gpio: gpio -+ * -+ * Get the status of a codec GPIO pin -+ */ -+ -+wm97xx_gpio_status_t wm97xx_get_gpio(struct wm97xx *wm, u32 gpio) -+{ -+ u16 status; -+ wm97xx_gpio_status_t ret; -+ -+ mutex_lock(&wm->codec_mutex); -+ status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); -+ -+ if (status & gpio) -+ ret = WM97XX_GPIO_HIGH; -+ else -+ ret = WM97XX_GPIO_LOW; -+ -+ mutex_unlock(&wm->codec_mutex); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(wm97xx_get_gpio); -+ -+/** -+ * wm97xx_set_gpio - Set the status of a codec GPIO. -+ * @wm: wm97xx device. -+ * @gpio: gpio -+ * -+ * -+ * Set the status of a codec GPIO pin -+ */ -+ -+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, -+ wm97xx_gpio_status_t status) -+{ -+ u16 reg; -+ -+ mutex_lock(&wm->codec_mutex); -+ reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); -+ -+ if (status & WM97XX_GPIO_HIGH) -+ reg |= gpio; -+ else -+ reg &= ~gpio; -+ -+ if (wm->id == WM9712_ID2) -+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1); -+ else -+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg); -+ mutex_unlock(&wm->codec_mutex); -+} -+EXPORT_SYMBOL_GPL(wm97xx_set_gpio); -+ -+/* -+ * Codec GPIO pin configuration, this set's pin direction, polarity, -+ * stickyness and wake up. -+ */ -+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, wm97xx_gpio_dir_t dir, -+ wm97xx_gpio_pol_t pol, wm97xx_gpio_sticky_t sticky, -+ wm97xx_gpio_wake_t wake) -+{ -+ u16 reg; -+ -+ mutex_lock(&wm->codec_mutex); -+ reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); -+ -+ if (pol == WM97XX_GPIO_POL_HIGH) -+ reg |= gpio; -+ else -+ reg &= ~gpio; -+ -+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg); -+ reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY); -+ -+ if (sticky == WM97XX_GPIO_STICKY) -+ reg |= gpio; -+ else -+ reg &= ~gpio; -+ -+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg); -+ reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP); -+ -+ if (wake == WM97XX_GPIO_WAKE) -+ reg |= gpio; -+ else -+ reg &= ~gpio; -+ -+ wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg); -+ reg = wm97xx_reg_read(wm, AC97_GPIO_CFG); -+ -+ if (dir == WM97XX_GPIO_IN) -+ reg |= gpio; -+ else -+ reg &= ~gpio; -+ -+ wm97xx_reg_write(wm, AC97_GPIO_CFG, reg); -+ mutex_unlock(&wm->codec_mutex); -+} -+EXPORT_SYMBOL_GPL(wm97xx_config_gpio); -+ -+/* -+ * Handle a pen down interrupt. -+ */ -+static void wm97xx_pen_irq_worker(struct work_struct *w) -+{ -+/* struct wm97xx *wm = (struct wm97xx *) ptr; */ -+ struct wm97xx *wm = container_of(w, struct wm97xx, pen_event_work); -+ -+ /* do we need to enable the touch panel reader */ -+ if (wm->id == WM9705_ID2) { -+ if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN) -+ wm->pen_is_down = 1; -+ else -+ wm->pen_is_down = 0; -+ wake_up_interruptible(&wm->pen_irq_wait); -+ } else { -+ u16 status, pol; -+ mutex_lock(&wm->codec_mutex); -+ status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); -+ pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); -+ -+ if (WM97XX_GPIO_13 & pol & status) { -+ wm->pen_is_down = 1; -+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol & ~WM97XX_GPIO_13); -+ } else { -+ wm->pen_is_down = 0; -+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol | WM97XX_GPIO_13); -+ } -+ -+ if (wm->id == WM9712_ID2) -+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & ~WM97XX_GPIO_13) << 1); -+ else -+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, status & ~WM97XX_GPIO_13); -+ mutex_unlock(&wm->codec_mutex); -+ wake_up_interruptible(&wm->pen_irq_wait); -+ } -+ -+ if (!wm->pen_is_down && wm->mach_ops && wm->mach_ops->acc_enabled) -+ wm->mach_ops->acc_pen_up(wm); -+ enable_irq(wm->pen_irq); -+} -+ -+/* -+ * Codec PENDOWN irq handler -+ * -+ * We have to disable the codec interrupt in the handler because it can -+ * take upto 1ms to clear the interrupt source. The interrupt is then enabled -+ * again in the slow handler when the source has been cleared. -+ */ -+static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id) -+{ -+ struct wm97xx *wm = (struct wm97xx *) dev_id; -+ disable_irq(wm->pen_irq); -+ queue_work(wm->pen_irq_workq, &wm->pen_event_work); -+ return IRQ_HANDLED; -+} -+ -+/* -+ * initialise pen IRQ handler and workqueue -+ */ -+static int wm97xx_init_pen_irq(struct wm97xx *wm) -+{ -+ u16 reg; -+ -+ INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker/* , wm */); -+ if ((wm->pen_irq_workq = -+ create_singlethread_workqueue("kwm97pen")) == NULL) { -+ err("could not create pen irq work queue"); -+ wm->pen_irq = 0; -+ return -EINVAL; -+ } -+ -+ -+ wm->pen_irq = IRQ_GPIO(90); -+ if (request_irq (wm->pen_irq, wm97xx_pen_interrupt, SA_SHIRQ, "wm97xx-pen", wm)) { -+ err("could not register codec pen down interrupt, will poll for pen down"); -+ destroy_workqueue(wm->pen_irq_workq); -+ wm->pen_irq = 0; -+ return -EINVAL; -+ } -+ -+ /* enable PEN down on wm9712/13 */ -+ if (wm->id != WM9705_ID2) { -+ reg = wm97xx_reg_read(wm, AC97_MISC_AFE); -+ wm97xx_reg_write(wm, AC97_MISC_AFE, reg & 0xfffb); -+ reg = wm97xx_reg_read(wm, 0x5a); -+ wm97xx_reg_write(wm, 0x5a, reg & ~0x0001); -+ } -+ -+ return 0; -+} -+ -+/* Private struct for communication between struct wm97xx_tshread -+ * and wm97xx_read_samples */ -+struct ts_state { -+ int sleep_time; -+ int min_sleep_time; -+}; -+ -+static int wm97xx_read_samples(struct wm97xx *wm, struct ts_state *state) -+{ -+ struct wm97xx_data data; -+ int rc; -+ -+ mutex_lock(&wm->codec_mutex); -+ -+ if (wm->mach_ops && wm->mach_ops->acc_enabled) -+ rc = wm->mach_ops->acc_pen_down(wm); -+ else -+ rc = wm->codec->poll_touch(wm, &data); -+ -+ if (rc & RC_PENUP) { -+ if (wm->pen_is_down) { -+ wm->pen_is_down = 0; -+ dbg("pen up"); -+ input_report_abs(wm->input_dev, ABS_PRESSURE, 0); -+ input_sync(wm->input_dev); -+ } else if (!(rc & RC_AGAIN)) { -+ /* We need high frequency updates only while pen is down, -+ * the user never will be able to touch screen faster than -+ * a few times per second... On the other hand, when the -+ * user is actively working with the touchscreen we don't -+ * want to lose the quick response. So we will slowly -+ * increase sleep time after the pen is up and quicky -+ * restore it to ~one task switch when pen is down again. -+ */ -+ if (state->sleep_time < HZ / 10) -+ state->sleep_time++; -+ } -+ -+ } else if (rc & RC_VALID) { -+ dbg("pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n", -+ data.x >> 12, data.x & 0xfff, data.y >> 12, -+ data.y & 0xfff, data.p >> 12, data.p & 0xfff); -+ input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff); -+ input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff); -+ input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff); -+ input_sync(wm->input_dev); -+ wm->pen_is_down = 1; -+ state->sleep_time = state->min_sleep_time; -+ } else if (rc & RC_PENDOWN) { -+ dbg("pen down"); -+ wm->pen_is_down = 1; -+ state->sleep_time = state->min_sleep_time; -+ } -+ -+ mutex_unlock(&wm->codec_mutex); -+ return rc; -+} -+ -+/* -+* The touchscreen sample reader thread. -+*/ -+static int wm97xx_ts_read(void *data) -+{ -+ int rc; -+ struct ts_state state; -+ struct wm97xx *wm = (struct wm97xx *) data; -+ -+ /* set up thread context */ -+ wm->ts_task = current; -+ daemonize("kwm97xxts"); -+ -+ if (wm->codec == NULL) { -+ wm->ts_task = NULL; -+ printk(KERN_ERR "codec is NULL, bailing\n"); -+ } -+ -+ complete(&wm->ts_init); -+ wm->pen_is_down = 0; -+ state.min_sleep_time = HZ >= 100 ? HZ / 100 : 1; -+ if (state.min_sleep_time < 1) -+ state.min_sleep_time = 1; -+ state.sleep_time = state.min_sleep_time; -+ -+ /* touch reader loop */ -+ while (wm->ts_task) { -+ do { -+ try_to_freeze(); -+ rc = wm97xx_read_samples(wm, &state); -+ } while (rc & RC_AGAIN); -+ if (!wm->pen_is_down && wm->pen_irq) { -+ /* Nice, we don't have to poll for pen down event */ -+ wait_event_interruptible(wm->pen_irq_wait, wm->pen_is_down); -+ } else { -+ set_task_state(current, TASK_INTERRUPTIBLE); -+ schedule_timeout(state.sleep_time); -+ } -+ } -+ complete_and_exit(&wm->ts_exit, 0); -+} -+ -+/** -+ * wm97xx_ts_input_open - Open the touch screen input device. -+ * @idev: Input device to be opened. -+ * -+ * Called by the input sub system to open a wm97xx touchscreen device. -+ * Starts the touchscreen thread and touch digitiser. -+ */ -+static int wm97xx_ts_input_open(struct input_dev *idev) -+{ -+ int ret = 0; -+ struct wm97xx *wm = (struct wm97xx *) idev->private; -+ -+ mutex_lock(&wm->codec_mutex); -+ /* first time opened ? */ -+ if (wm->ts_use_count++ == 0) { -+ /* start touchscreen thread */ -+ init_completion(&wm->ts_init); -+ init_completion(&wm->ts_exit); -+ ret = kernel_thread(wm97xx_ts_read, wm, CLONE_KERNEL); -+ -+ if (ret >= 0) { -+ wait_for_completion(&wm->ts_init); -+ if (wm->ts_task == NULL) -+ ret = -EINVAL; -+ } else { -+ mutex_unlock(&wm->codec_mutex); -+ return ret; -+ } -+ -+ /* start digitiser */ -+ if (wm->mach_ops && wm->mach_ops->acc_enabled) -+ wm->codec->acc_enable(wm, 1); -+ wm->codec->digitiser_ioctl(wm, WM97XX_DIG_START); -+ -+ /* init pen down/up irq handling */ -+ if (wm->pen_irq) { -+ wm97xx_init_pen_irq(wm); -+ -+ if (wm->pen_irq == 0) { -+ /* we failed to get an irq for pen down events, -+ * so we resort to polling. kickstart the reader */ -+ wm->pen_is_down = 1; -+ wake_up_interruptible(&wm->pen_irq_wait); -+ } -+ } -+ } -+ -+ mutex_unlock(&wm->codec_mutex); -+ return 0; -+} -+ -+/** -+ * wm97xx_ts_input_close - Close the touch screen input device. -+ * @idev: Input device to be closed. -+ * -+ * Called by the input sub system to close a wm97xx touchscreen device. -+ * Kills the touchscreen thread and stops the touch digitiser. -+ */ -+ -+static void wm97xx_ts_input_close(struct input_dev *idev) -+{ -+ struct wm97xx *wm = (struct wm97xx *) idev->private; -+ -+ mutex_lock(&wm->codec_mutex); -+ if (--wm->ts_use_count == 0) { -+ /* destroy workqueues and free irqs */ -+ if (wm->pen_irq) { -+ free_irq(wm->pen_irq, wm); -+ destroy_workqueue(wm->pen_irq_workq); -+ } -+ -+ /* kill thread */ -+ if (wm->ts_task) { -+ wm->ts_task = NULL; -+ wm->pen_is_down = 1; -+ mutex_unlock(&wm->codec_mutex); -+ wake_up_interruptible(&wm->pen_irq_wait); -+ wait_for_completion(&wm->ts_exit); -+ wm->pen_is_down = 0; -+ mutex_lock(&wm->codec_mutex); -+ } -+ -+ /* stop digitiser */ -+ wm->codec->digitiser_ioctl(wm, WM97XX_DIG_STOP); -+ if (wm->mach_ops && wm->mach_ops->acc_enabled) -+ wm->codec->acc_enable(wm, 0); -+ } -+ mutex_unlock(&wm->codec_mutex); -+} -+ -+/* -+ * Bus interface to allow for client drivers codec access -+ * e.g. battery monitor -+ */ -+static int wm97xx_bus_match(struct device *dev, struct device_driver *drv) -+{ -+ return !(strcmp(dev->bus_id,drv->name)); -+} -+ -+/* -+ * The AC97 audio driver will do all the Codec suspend and resume -+ * tasks. This is just for anything machine specific or extra. -+ */ -+static int wm97xx_bus_suspend(struct device *dev, pm_message_t state) -+{ -+ int ret = 0; -+ -+ if (dev->driver && dev->driver->suspend) -+ ret = dev->driver->suspend(dev, state); -+ -+ return ret; -+} -+ -+static int wm97xx_bus_resume(struct device *dev) -+{ -+ int ret = 0; -+ -+ if (dev->driver && dev->driver->resume) -+ ret = dev->driver->resume(dev); -+ -+ return ret; -+} -+ -+struct bus_type wm97xx_bus_type = { -+ .name = "wm97xx", -+ .match = wm97xx_bus_match, -+ .suspend = wm97xx_bus_suspend, -+ .resume = wm97xx_bus_resume, -+}; -+EXPORT_SYMBOL_GPL(wm97xx_bus_type); -+ -+static void wm97xx_release(struct device *dev) -+{ -+ kfree(dev); -+} -+ -+static int wm97xx_probe(struct device *dev) -+{ -+ struct wm97xx* wm; -+ int ret = 0, id = 0; -+ -+ if (!(wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL))) -+ return -ENOMEM; -+ mutex_init(&wm->codec_mutex); -+ -+ init_waitqueue_head(&wm->pen_irq_wait); -+ wm->dev = dev; -+ dev->driver_data = wm; -+ wm->ac97 = to_ac97_t(dev); -+ -+ /* check that we have a supported codec */ -+ if ((id = wm97xx_reg_read(wm, AC97_VENDOR_ID1)) != WM97XX_ID1) { -+ err("could not find a wm97xx, found a %x instead\n", id); -+ kfree(wm); -+ return -ENODEV; -+ } -+ -+ wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2); -+ if(wm->id != wm97xx_codec.id) { -+ err("could not find a the selected codec, please build for wm97%2x", wm->id & 0xff); -+ kfree(wm); -+ return -ENODEV; -+ } -+ -+ if((wm->input_dev = input_allocate_device()) == NULL) { -+ kfree(wm); -+ return -ENOMEM; -+ } -+ -+ /* set up touch configuration */ -+ info("detected a wm97%2x codec", wm->id & 0xff); -+ wm->input_dev->name = "wm97xx touchscreen"; -+ wm->input_dev->open = wm97xx_ts_input_open; -+ wm->input_dev->close = wm97xx_ts_input_close; -+ set_bit(EV_ABS, wm->input_dev->evbit); -+ set_bit(ABS_X, wm->input_dev->absbit); -+ set_bit(ABS_Y, wm->input_dev->absbit); -+ set_bit(ABS_PRESSURE, wm->input_dev->absbit); -+ wm->input_dev->absmax[ABS_X] = abs_x[1]; -+ wm->input_dev->absmax[ABS_Y] = abs_y[1]; -+ wm->input_dev->absmax[ABS_PRESSURE] = abs_p[1]; -+ wm->input_dev->absmin[ABS_X] = abs_x[0]; -+ wm->input_dev->absmin[ABS_Y] = abs_y[0]; -+ wm->input_dev->absmin[ABS_PRESSURE] = abs_p[0]; -+ wm->input_dev->absfuzz[ABS_X] = abs_x[2]; -+ wm->input_dev->absfuzz[ABS_Y] = abs_y[2]; -+ wm->input_dev->absfuzz[ABS_PRESSURE] = abs_p[2]; -+ wm->input_dev->private = wm; -+ wm->codec = &wm97xx_codec; -+ if((ret = input_register_device(wm->input_dev)) < 0) { -+ kfree(wm); -+ return -ENOMEM; -+ } -+ -+ /* set up physical characteristics */ -+ wm->codec->digitiser_ioctl(wm, WM97XX_PHY_INIT); -+ -+ /* load gpio cache */ -+ wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG); -+ wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); -+ wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY); -+ wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP); -+ wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS); -+ wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE); -+ -+ /* register our battery device */ -+ if (!(wm->battery_dev = kzalloc(sizeof(struct device), GFP_KERNEL))) { -+ ret = -ENOMEM; -+ goto batt_err; -+ } -+ wm->battery_dev->bus = &wm97xx_bus_type; -+ strcpy(wm->battery_dev->bus_id,"wm97xx-battery"); -+ wm->battery_dev->driver_data = wm; -+ wm->battery_dev->parent = dev; -+ wm->battery_dev->release = wm97xx_release; -+ if((ret = device_register(wm->battery_dev)) < 0) -+ goto batt_reg_err; -+ -+ /* register our extended touch device (for machine specific extensions) */ -+ if (!(wm->touch_dev = kzalloc(sizeof(struct device), GFP_KERNEL))) { -+ ret = -ENOMEM; -+ goto touch_err; -+ } -+ wm->touch_dev->bus = &wm97xx_bus_type; -+ strcpy(wm->touch_dev->bus_id,"wm97xx-touchscreen"); -+ wm->touch_dev->driver_data = wm; -+ wm->touch_dev->parent = dev; -+ wm->touch_dev->release = wm97xx_release; -+ if((ret = device_register(wm->touch_dev)) < 0) -+ goto touch_reg_err; -+ -+ return ret; -+ -+touch_reg_err: -+ kfree(wm->touch_dev); -+touch_err: -+ device_unregister(wm->battery_dev); -+batt_reg_err: -+ kfree(wm->battery_dev); -+batt_err: -+ input_unregister_device(wm->input_dev); -+ kfree(wm); -+ return ret; -+} -+ -+static int wm97xx_remove(struct device *dev) -+{ -+ struct wm97xx *wm = dev_get_drvdata(dev); -+ -+ /* Stop touch reader thread */ -+ if (wm->ts_task) { -+ wm->ts_task = NULL; -+ wm->pen_is_down = 1; -+ wake_up_interruptible(&wm->pen_irq_wait); -+ wait_for_completion(&wm->ts_exit); -+ } -+ device_unregister(wm->battery_dev); -+ device_unregister(wm->touch_dev); -+ input_unregister_device(wm->input_dev); -+ -+ kfree(wm); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+int wm97xx_resume(struct device* dev) -+{ -+ struct wm97xx *wm = dev_get_drvdata(dev); -+ -+ /* restore digitiser and gpio's */ -+ if(wm->id == WM9713_ID2) { -+ wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]); -+ wm97xx_reg_write(wm, 0x5a, wm->misc); -+ if(wm->ts_use_count) { -+ u16 reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff; -+ wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg); -+ } -+ } -+ -+ wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]); -+ wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]); -+ -+ wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]); -+ wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]); -+ wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]); -+ wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]); -+ wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]); -+ wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]); -+ -+ return 0; -+} -+ -+#else -+#define wm97xx_resume NULL -+#endif -+ -+/* -+ * Machine specific operations -+ */ -+int wm97xx_register_mach_ops(struct wm97xx *wm, struct wm97xx_mach_ops *mach_ops) -+{ -+ mutex_lock(&wm->codec_mutex); -+ if(wm->mach_ops) { -+ mutex_unlock(&wm->codec_mutex); -+ return -EINVAL; -+ } -+ wm->mach_ops = mach_ops; -+ mutex_unlock(&wm->codec_mutex); -+ return 0; -+} -+EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops); -+ -+void wm97xx_unregister_mach_ops(struct wm97xx *wm) -+{ -+ mutex_lock(&wm->codec_mutex); -+ wm->mach_ops = NULL; -+ mutex_unlock(&wm->codec_mutex); -+} -+EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops); -+ -+static struct device_driver wm97xx_driver = { -+ .name = "ac97", -+ .bus = &ac97_bus_type, -+ .owner = THIS_MODULE, -+ .probe = wm97xx_probe, -+ .remove = wm97xx_remove, -+ .resume = wm97xx_resume, -+}; -+ -+static int __init wm97xx_init(void) -+{ -+ int ret; -+ -+ info("version %s liam.girdwood@wolfsonmicro.com", WM_CORE_VERSION); -+ if((ret = bus_register(&wm97xx_bus_type)) < 0) -+ return ret; -+ return driver_register(&wm97xx_driver); -+} -+ -+static void __exit wm97xx_exit(void) -+{ -+ driver_unregister(&wm97xx_driver); -+ bus_unregister(&wm97xx_bus_type); -+} -+ -+module_init(wm97xx_init); -+module_exit(wm97xx_exit); -+ -+/* Module information */ -+MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com"); -+MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 4468cb3..01b4828 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -101,6 +101,12 @@ config LEDS_GPIO - outputs. To be useful the particular board must have LEDs - and they must be connected to the GPIO lines. - -+config LEDS_EM_X270 -+ tristate "LED Support for the CompuLab EM-X270" -+ depends on LEDS_CLASS && MACH_EM_X270 -+ help -+ This option enables support for the LEDs on CompuLab EM-X270. -+ - comment "LED Triggers" - - config LEDS_TRIGGERS -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index f8995c9..6d3941e 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -17,6 +17,7 @@ obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o - obj-$(CONFIG_LEDS_H1940) += leds-h1940.o - obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o - obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o -+obj-$(CONFIG_LEDS_EM_X270) += leds-em-x270.o - - # LED Triggers - obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o -diff --git a/drivers/leds/leds-em-x270.c b/drivers/leds/leds-em-x270.c -new file mode 100644 -index 0000000..485e7da ---- /dev/null -+++ b/drivers/leds/leds-em-x270.c -@@ -0,0 +1,99 @@ -+/* -+ * LED Triggers Core -+ * -+ * Copyright 2007 CompuLab, Ltd. -+ * Author: Mike Rapoport -+ * -+ * Based on Corgi leds driver: -+ * Copyright 2005-2006 Openedhand Ltd. -+ * Author: Richard Purdie -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static void em_x270_led_orange_set(struct led_classdev *led_cdev, -+ enum led_brightness value) -+{ -+ int on = 1; -+ int pwm_chop = 0; -+ -+ pr_info("%s: value = %d\n", __FUNCTION__, value); -+ if (value == LED_OFF) -+ on = 0; -+ else if (value == LED_HALF) -+ pwm_chop = 4; -+ -+ da9030_set_led(3, on, 0, 0, pwm_chop); -+} -+ -+static struct led_classdev em_x270_orange_led = { -+ .name = "em_x270:orange", -+ .default_trigger = "em-x270-battery.0-charging-or-full", -+ .brightness_set = em_x270_led_orange_set, -+}; -+ -+#ifdef CONFIG_PM -+static int em_x270_led_suspend(struct platform_device *dev, pm_message_t state) -+{ -+#ifdef CONFIG_LEDS_TRIGGERS -+ if (em_x270_orange_led.trigger && strcmp(em_x270_orange_led.trigger->name, "em-x270-battery-charging-or-full")) -+#endif -+ led_classdev_suspend(&em_x270_orange_led); -+ return 0; -+} -+ -+static int em_x270_led_resume(struct platform_device *dev) -+{ -+ led_classdev_resume(&em_x270_orange_led); -+ return 0; -+} -+#endif -+ -+static int em_x270_led_probe(struct platform_device *pdev) -+{ -+ return led_classdev_register(&pdev->dev, &em_x270_orange_led); -+} -+ -+static int em_x270_led_remove(struct platform_device *pdev) -+{ -+ led_classdev_unregister(&em_x270_orange_led); -+ return 0; -+} -+ -+static struct platform_driver em_x270_led_driver = { -+ .probe = em_x270_led_probe, -+ .remove = em_x270_led_remove, -+#ifdef CONFIG_PM -+ .suspend = em_x270_led_suspend, -+ .resume = em_x270_led_resume, -+#endif -+ .driver = { -+ .name = "em-x270-led", -+ }, -+}; -+ -+static int __init em_x270_led_init(void) -+{ -+ return platform_driver_register(&em_x270_led_driver); -+} -+ -+static void __exit em_x270_led_exit(void) -+{ -+ platform_driver_unregister(&em_x270_led_driver); -+} -+ -+module_init(em_x270_led_init); -+module_exit(em_x270_led_exit); -+ -+MODULE_AUTHOR("Mike Rapoport "); -+MODULE_DESCRIPTION("EX-X270 LED driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c -index 58e561e..7050e71 100644 ---- a/drivers/mtd/chips/jedec_probe.c -+++ b/drivers/mtd/chips/jedec_probe.c -@@ -38,7 +38,7 @@ - #define MANUFACTURER_ST 0x0020 - #define MANUFACTURER_TOSHIBA 0x0098 - #define MANUFACTURER_WINBOND 0x00da -- -+#define CONTINUATION_CODE 0x007f - - /* AMD */ - #define AM29DL800BB 0x22C8 -@@ -68,6 +68,10 @@ - #define AT49BV32X 0x00C8 - #define AT49BV32XT 0x00C9 - -+/* Eon */ -+#define EN29SL800BB 0x226B -+#define EN29SL800BT 0x22EA -+ - /* Fujitsu */ - #define MBM29F040C 0x00A4 - #define MBM29LV650UE 0x22D7 -@@ -632,6 +636,40 @@ static const struct amd_flash_info jedec_table[] = { - ERASEINFO(0x02000,8) - } - }, { -+ .mfr_id = 0x1c, -+ .dev_id = EN29SL800BT, -+ .name = "Eon EN29SL800BT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000, 15), -+ ERASEINFO(0x08000, 1), -+ ERASEINFO(0x02000, 2), -+ ERASEINFO(0x04000, 1), -+ } -+ }, { -+ .mfr_id = 0x1c, -+ .dev_id = EN29SL800BB, -+ .name = "Eon EN29SL800BB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000, 1), -+ ERASEINFO(0x02000, 2), -+ ERASEINFO(0x08000, 1), -+ ERASEINFO(0x10000, 15), -+ } -+ }, { - .mfr_id = MANUFACTURER_FUJITSU, - .dev_id = MBM29F040C, - .name = "Fujitsu MBM29F040C", -@@ -1769,9 +1807,21 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, - { - map_word result; - unsigned long mask; -- u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type); -- mask = (1 << (cfi->device_type * 8)) -1; -- result = map_read(map, base + ofs); -+ int bank = 0; -+ -+ /* According to JEDEC "Standard Manufacturer's Identification Code" -+ * (http://www.jedec.org/download/search/jep106W.pdf) -+ * several first banks can contain 0x7f instead of actual ID -+ */ -+ do { -+ u32 ofs = cfi_build_cmd_addr(0 + (bank << 8), -+ cfi_interleave(cfi), -+ cfi->device_type); -+ mask = (1 << (cfi->device_type * 8)) -1; -+ result = map_read(map, base + ofs); -+ bank++; -+ } while ((result.x[0] & mask) == CONTINUATION_CODE); -+ - return result.x[0] & mask; - } - -diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c -index 738aa59..88dbbdf 100644 ---- a/drivers/net/dm9000.c -+++ b/drivers/net/dm9000.c -@@ -546,6 +546,7 @@ dm9000_probe(struct platform_device *pdev) - - if (id_val != DM9000_ID) { - printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val); -+ ret = -ENODEV; - goto release; - } - -diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig -index 58c806e..3a16d9c 100644 ---- a/drivers/power/Kconfig -+++ b/drivers/power/Kconfig -@@ -49,4 +49,10 @@ config BATTERY_OLPC - help - Say Y to enable support for the battery on the OLPC laptop. - -+config BATTERY_EM_X270 -+ tristate "EM-X270 battery" -+ depends on DA9030 && MACH_EM_X270 -+ help -+ Say Y here to enable support for battery on EM-X270. -+ - endif # POWER_SUPPLY -diff --git a/drivers/power/Makefile b/drivers/power/Makefile -index 6413ded..dc9585e 100644 ---- a/drivers/power/Makefile -+++ b/drivers/power/Makefile -@@ -20,3 +20,4 @@ obj-$(CONFIG_APM_POWER) += apm_power.o - obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o - obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o - obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o -+obj-$(CONFIG_BATTERY_EM_X270) += em_x270_battery.o -diff --git a/drivers/power/em_x270_battery.c b/drivers/power/em_x270_battery.c -new file mode 100644 -index 0000000..2630c68 ---- /dev/null -+++ b/drivers/power/em_x270_battery.c -@@ -0,0 +1,579 @@ -+/* -+ * Power managemnet implementation for EM-X270 -+ * -+ * Copyright (C) 2007 CompuLab, Ltd. -+ * Author: Mike Rapoport -+ * -+ * 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. -+ * -+ */ -+ -+#define DEBUG -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "../i2c/chips/da9030.h" -+ -+#define VOLTAGE_MAX_DESIGN 4200000 /* 4.2V in uV */ -+#define VOLTAGE_MIN_DESIGN 3000000 /* 3V in uV */ -+ -+/* #define VCHARGE_MIN_THRESHOLD 72 /\* 4.5V *\/ */ -+ -+#define VCHARGE_MIN_THRESHOLD 60 /* ?.?V */ -+#define VCHARGE_MAX_THRESHOLD 89 /* 5.5V */ -+#define TBAT_LOW_THRESHOLD 197 /* 0oC */ -+#define TBAT_HIGH_THRESHOLD 78 /* 45oC */ -+#define TBAT_RESUME_THRESHOLD 100 /* 35oC */ -+#define VBAT_LOW_THRESHOLD 82 /* 3.498V */ -+#define VBAT_CRIT_THRESHOLD 62 /* 3.291V */ -+ -+struct da9030_charger { -+ struct device *dev; -+ -+ struct power_supply bat; -+ struct da9030_adc_res adc; -+ struct delayed_work work; -+ -+ int interval; -+ int status; -+ int mA; -+ int mV; -+ -+ int is_charging:1; -+ -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *debug_file; -+#endif -+}; -+ -+static unsigned short tbat_readings[] = { -+ 300, 244, 200, 178, 163, 152, 144, 137, 131, -+ 126, 122, 118, 114, 111, 108, 105, 103, 101, -+ 98, 96, 94, 93, 91, 89, 88, 86, 85, -+ 83, 82, 81, 79, 78, 77, 76, 75, 74, -+ 73, 72, 71, 70, 69, 68, 67, 67, 66, -+ 65, 64, 63, 63, 62, 61, 60, 60, 59, -+ 58, 58, 57, 57, 56, 55, 55, 54, 53, -+ 53, 52, 52, 51, 51, 50, 50, 49, 49, -+ 48, 48, 47, 47, 46, 46, 45, 45, 44, -+ 44, 43, 43, 42, 42, 41, 41, 41, 40, -+ 40, 39, 39, 38, 38, 38, 37, 37, 36, -+ 36, 35, 35, 35, 34, 34, 34, 33, 33, -+ 32, 32, 32, 31, 31, 30, 30, 30, 29, -+ 29, 29, 28, 28, 28, 27, 27, 26, 26, -+ 26, 25, 25, 25, 24, 24, 24, 23, 23, -+ 23, 22, 22, 21, 21, 21, 20, 20, 20, -+ 19, 19, 19, 18, 18, 18, 17, 17, 17, -+ 16, 16, 16, 15, 15, 14, 14, 14, 13, -+ 13, 13, 12, 12, 12, 11, 11, 11, 10, -+ 10, 10, 9, 9, 8, 8, 8, 7, 7, -+ 7, 6, 6, 5, 5, 5, 4, 4, 3, -+ 3, 3, 2, 2, 1, 1, 1, 0, 0, -+ -1, -1, -1, -2, -2, -3, -3, -4, -4, -+ -5, -5, -6, -6, -6, -7, -7, -8, -9, -+ -9, -10, -10, -11, -11, -12, -12, -13, -14, -+ -14, -15, -16, -16, -17, -18, -18, -19, -20, -+ -21, -21, -22, -23, -24, -25, -26, -27, -28, -+ -30, -31, -32, -34, -35, -37, -39, -41, -44, -+ -47, -50, -56, -64, -+}; -+ -+#ifdef CONFIG_DEBUG_FS -+ -+#define REG2VOLT(x) ((((x) * 2650) >> 8) + 2650) -+ -+static int debug_show(struct seq_file *s, void *data) -+{ -+ struct da9030_charger *charger = s->private; -+ -+ seq_printf(s, "charger is %s\n", -+ charger->status & CHRG_CHARGER_ENABLE ? "on" : "off"); -+ if (charger->status & CHRG_CHARGER_ENABLE) { -+ seq_printf(s, "iset = %dmA, vset = %dmV\n", -+ charger->mA, charger->mV); -+ } -+ -+ seq_printf(s, "vbat_res = %d (%dmV)\n", -+ charger->adc.vbat_res, REG2VOLT(charger->adc.vbat_res)); -+ seq_printf(s, "vbatmin_res = %d (%dmV)\n", -+ charger->adc.vbatmin_res, -+ REG2VOLT(charger->adc.vbatmin_res)); -+ seq_printf(s, "vbatmintxon = %d (%dmV)\n", -+ charger->adc.vbatmintxon, -+ REG2VOLT(charger->adc.vbatmintxon)); -+ seq_printf(s, "ichmax_res = %d\n", charger->adc.ichmax_res); -+ seq_printf(s, "ichmin_res = %d\n", charger->adc.ichmin_res); -+ seq_printf(s, "ichaverage_res = %d\n", charger->adc.ichaverage_res); -+ seq_printf(s, "vchmax_res = %d (%dmV)\n", -+ charger->adc.vchmax_res, -+ REG2VOLT(charger->adc.vchmax_res)); -+ seq_printf(s, "vchmin_res = %d (%dmV)\n", -+ charger->adc.vchmin_res, -+ REG2VOLT(charger->adc.vchmin_res)); -+ seq_printf(s, "tbat_res = %d (%doC\n", charger->adc.tbat_res, -+ tbat_readings[charger->adc.tbat_res]); -+ seq_printf(s, "adc_in4_res = %d\n", charger->adc.adc_in4_res); -+ seq_printf(s, "adc_in5_res = %d\n", charger->adc.adc_in5_res); -+ -+ return 0; -+} -+ -+static int debug_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, debug_show, inode->i_private); -+} -+ -+static const struct file_operations debug_fops = { -+ .open = debug_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static struct dentry* da9030_create_debugfs(struct da9030_charger *charger) -+{ -+ charger->debug_file = debugfs_create_file("charger", 0666, 0, charger, -+ &debug_fops); -+ return charger->debug_file; -+} -+ -+static void da9030_remove_debugfs(struct da9030_charger *charger) -+{ -+ debugfs_remove(charger->debug_file); -+} -+#else -+#define da9030_create_debugfs(x) NULL -+#define da9030_remove_debugfs(x) do {} while(0) -+#endif -+ -+static void da9030_set_charge(struct da9030_charger *charger, int on) -+{ -+/* int status = da9030_get_status(); */ -+ if (on) { -+ pr_debug("%s: enabling charger\n", __FUNCTION__); -+ da9030_set_thresholds(TBAT_HIGH_THRESHOLD, -+ TBAT_RESUME_THRESHOLD, -+ TBAT_LOW_THRESHOLD); -+ da9030_set_charger(1, 1000, 4200); -+ charger->is_charging = 1; -+ } -+ else { -+ /* disable charger */ -+ pr_debug("%s: disabling charger\n", __FUNCTION__); -+ da9030_set_charger(0, 0, 0); -+ charger->is_charging = 0; -+ } -+} -+ -+static void da9030_charging_monitor(struct work_struct *work) -+{ -+ struct da9030_charger *charger; -+ int is_on; -+ unsigned int mA, mV; -+ -+ charger = container_of(work, struct da9030_charger, work.work); -+ -+ da9030_get_charger(&is_on, &mA, &mV); -+ da9030_read_adc(&charger->adc); -+ -+ charger->status = da9030_get_status(); -+ charger->mA = mA; -+ charger->mV = mV; -+ -+ /* we wake or boot with external power on */ -+ if (!is_on && (charger->status & STATUS_CHDET)) { -+ da9030_set_charge(charger, 1); -+ return; -+ } -+ -+ if (is_on) { -+/* pr_info("%s: mA = %d, mV = %d\n", __FUNCTION__, mA, mV); */ -+/* pr_info("%s: vchmin_res = %d, vchmax_res = %d\n", */ -+/* __FUNCTION__, charger->adc.vchmin_res, */ -+/* charger->adc.vchmax_res); */ -+/* pr_info("%s: tbat_res = %d\n", */ -+/* __FUNCTION__, charger->adc.tbat_res); */ -+ if (charger->adc.vbat_res > VBAT_LOW_THRESHOLD) { -+ /* update VBAT threshlods ? */ -+ da9030_set_reg(VBATMON, VBAT_LOW_THRESHOLD); -+ } -+ if (charger->adc.vchmax_res > VCHARGE_MAX_THRESHOLD || -+ charger->adc.vchmin_res < VCHARGE_MIN_THRESHOLD || -+ /* Tempreture readings are negative */ -+ charger->adc.tbat_res < TBAT_HIGH_THRESHOLD || -+ charger->adc.tbat_res > TBAT_LOW_THRESHOLD) { -+ /* disable charger */ -+ da9030_set_charge(charger, 0); -+ } -+ } -+ -+ /* reschedule for the next time */ -+ schedule_delayed_work(&charger->work, charger->interval); -+} -+ -+void da9030_battery_release(struct device * dev) -+{ -+} -+ -+static void da9030_external_power_changed(struct power_supply *psy) -+{ -+/* struct da9030_charger *charger; */ -+ -+/* charger = container_of(psy, struct da9030_charger, bat); */ -+/* pr_info("%s:\n", __FUNCTION__); */ -+/* da9030_set_charge(charger); */ -+} -+ -+struct da9030_battery_thresh { -+ int voltage; -+ int percentage; -+}; -+ -+static struct da9030_battery_thresh vbat_ranges[] = { -+ { 150, 100}, -+ { 149, 99}, -+ { 148, 98}, -+ { 147, 98}, -+ { 146, 97}, -+ { 145, 96}, -+ { 144, 96}, -+ { 143, 95}, -+ { 142, 94}, -+ { 141, 93}, -+ { 140, 92}, -+ { 139, 91}, -+ { 138, 90}, -+ { 137, 90}, -+ { 136, 89}, -+ { 135, 88}, -+ { 134, 88}, -+ { 133, 87}, -+ { 132, 86}, -+ { 131, 85}, -+ { 130, 83}, -+ { 129, 82}, -+ { 128, 81}, -+ { 127, 81}, -+ { 126, 80}, -+ { 125, 75}, -+ { 124, 74}, -+ { 123, 73}, -+ { 122, 70}, -+ { 121, 66}, -+ { 120, 65}, -+ { 119, 64}, -+ { 118, 64}, -+ { 117, 63}, -+ { 116, 59}, -+ { 115, 58}, -+ { 114, 57}, -+ { 113, 57}, -+ { 112, 56}, -+ { 111, 50}, -+ { 110, 49}, -+ { 109, 49}, -+ { 108, 48}, -+ { 107, 48}, -+ { 106, 33}, -+ { 105, 32}, -+ { 104, 32}, -+ { 103, 32}, -+ { 102, 31}, -+ { 101, 16}, -+ { 100, 15}, -+ { 99, 15}, -+ { 98, 15}, -+ { 97, 10}, -+ { 96, 9}, -+ { 95, 7}, -+ { 94, 3}, -+ { 93, 0}, -+}; -+ -+static enum power_supply_property da9030_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_TECHNOLOGY, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_AVG, -+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_MANUFACTURER, -+ POWER_SUPPLY_PROP_MODEL_NAME, -+}; -+ -+static void da9030_bat_check_status(union power_supply_propval *val) -+{ -+ int charger_on; -+ int status = da9030_get_status(); -+ -+ da9030_get_charger(&charger_on, 0, 0); -+ -+ /* FIXME: below code is very crude approximation of actual -+ states, we need to take into account voltage and current -+ measurements to determine actual charger state */ -+ if (status & STATUS_CHDET) { -+ if (charger_on) { -+ val->intval = POWER_SUPPLY_STATUS_CHARGING; -+ } -+ else { -+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ } -+ } -+ else { -+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING; -+ } -+} -+ -+static void da9030_bat_check_health(union power_supply_propval *val) -+{ -+ int fault_log = da9030_get_fault_log(); -+ -+ if (fault_log & FAULT_LOG_OVER_TEMP) { -+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; -+ } -+ else if (fault_log & FAULT_LOG_VBAT_OVER) { -+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; -+ } -+ else { -+ val->intval = POWER_SUPPLY_HEALTH_GOOD; -+ } -+} -+ -+static int vbat_interpolate(int reg) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(vbat_ranges); i++ ) -+ if (vbat_ranges[i].voltage == reg) { -+ pr_debug("%s: voltage = %d, percentage = %d\n", -+ __FUNCTION__, vbat_ranges[i].voltage, -+ vbat_ranges[i].percentage); -+ return vbat_ranges[i].percentage; -+ } -+ -+ return 0; -+} -+ -+static int da9030_bat_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ u32 reg; -+ struct da9030_charger *charger; -+ charger = container_of(psy, struct da9030_charger, bat); -+ -+ switch(psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ da9030_bat_check_status(val); -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ da9030_bat_check_health(val); -+ break; -+ case POWER_SUPPLY_PROP_TECHNOLOGY: -+ val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ val->intval = VOLTAGE_MAX_DESIGN; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ val->intval = VOLTAGE_MIN_DESIGN; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ reg = charger->adc.vbat_res; -+ /* V = (reg / 256) * 2.65 + 2.65 (V) */ -+ val->intval = ((reg * 2650000) >> 8) + 2650000; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_AVG: -+ reg = charger->adc.ichaverage_res; -+ val->intval = reg; /* reg */ -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ reg = charger->adc.vbat_res; -+ val->intval = vbat_interpolate(reg); -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ reg = charger->adc.tbat_res; -+ val->intval = tbat_readings[reg]; -+ break; -+ case POWER_SUPPLY_PROP_MANUFACTURER: -+ val->strval = "MaxPower"; -+ pr_debug("%s: MFG = %s\n", __FUNCTION__, val->strval); -+ break; -+ case POWER_SUPPLY_PROP_MODEL_NAME: -+ val->strval = "LP555597P6H-FPS"; -+ pr_debug("%s: MODEL = %s\n", __FUNCTION__, val->strval); -+ break; -+ default: break; -+ } -+ -+ return 0; -+} -+ -+static void da9030_setup_battery(struct power_supply *bat) -+{ -+ bat->name = "em-x270-battery"; -+ bat->type = POWER_SUPPLY_TYPE_BATTERY; -+ bat->properties = da9030_bat_props; -+ bat->num_properties = ARRAY_SIZE(da9030_bat_props); -+ bat->get_property = da9030_bat_get_property; -+ bat->use_for_apm = 1; -+ bat->external_power_changed = da9030_external_power_changed; -+}; -+ -+static void da9030_chiover_callback(int event, void *_charger) -+{ -+ /* disable charger */ -+ struct da9030_charger *charger = _charger; -+ da9030_set_charge(charger, 0); -+} -+ -+static void da9030_tbat_callback(int event, void *_charger) -+{ -+ /* disable charger */ -+ struct da9030_charger *charger = _charger; -+ da9030_set_charge(charger, 0); -+} -+ -+static void da9030_vbat_callback(int event, void *_charger) -+{ -+ struct da9030_charger *charger = _charger; -+ da9030_read_adc(&charger->adc); -+ -+ if (charger->is_charging) { -+ if (charger->adc.vbat_res < VBAT_LOW_THRESHOLD) { -+ /* set VBAT threshold for critical */ -+ da9030_set_reg(VBATMON, VBAT_CRIT_THRESHOLD); -+ } -+ else if (charger->adc.vbat_res < VBAT_CRIT_THRESHOLD) { -+ /* notify the system of battery critical */ -+ apm_queue_event(APM_CRITICAL_SUSPEND); -+ } -+ } -+} -+ -+static void da9030_ccto_callback(int event, void *_charger) -+{ -+ /* x3 */ -+} -+ -+static void da9030_tcto_callback(int event, void *_charger) -+{ -+ /* x3 */ -+} -+ -+static void da9030_chdet_callback(int event, void *_charger) -+{ -+ struct da9030_charger *charger = _charger; -+ int status = da9030_get_status(); -+ da9030_set_charge(charger, !!(status & CHRG_CHARGER_ENABLE)); -+} -+ -+static int da9030_battery_probe(struct platform_device *pdev) -+{ -+ struct da9030_charger *charger; -+ -+ pr_debug("%s\n", __FUNCTION__); -+ charger = kzalloc(sizeof(*charger), GFP_KERNEL); -+ if (charger == NULL) { -+ return -ENOMEM; -+ } -+ -+ charger->dev = &pdev->dev; -+ -+ charger->interval = 10 * HZ; /* 10 seconds between monotor runs */ -+ da9030_setup_battery(&charger->bat); -+ -+ platform_set_drvdata(pdev, charger); -+ -+ da9030_enable_adc(); -+ -+ INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor); -+ schedule_delayed_work(&charger->work, charger->interval); -+ -+ charger->debug_file = da9030_create_debugfs(charger); -+ -+ da9030_setup_battery(&charger->bat); -+ -+ da9030_register_callback(DA9030_IRQ_CHDET, -+ da9030_chdet_callback, -+ charger); -+ da9030_register_callback(DA9030_IRQ_VBATMON, -+ da9030_vbat_callback, -+ charger); -+ -+ /* critical condition events */ -+ da9030_register_callback(DA9030_IRQ_CHIOVER, -+ da9030_chiover_callback, -+ charger); -+ da9030_register_callback(DA9030_IRQ_TBAT, -+ da9030_tbat_callback, -+ charger); -+ -+ /* timer events */ -+ da9030_register_callback(DA9030_IRQ_TCTO, -+ da9030_tcto_callback, -+ charger); -+ da9030_register_callback(DA9030_IRQ_CCTO, -+ da9030_ccto_callback, -+ charger); -+ -+ power_supply_register(&pdev->dev, &charger->bat); -+ -+ return 0; -+} -+ -+static int da9030_battery_remove(struct platform_device *dev) -+{ -+ struct da9030_charger *charger = platform_get_drvdata(dev); -+ -+ pr_debug("%s\n", __FUNCTION__); -+ da9030_remove_debugfs(charger); -+ cancel_delayed_work(&charger->work); -+ power_supply_unregister(&charger->bat); -+ kfree(charger); -+ return 0; -+} -+ -+static struct platform_driver da9030_battery_driver = { -+ .driver = { -+ .name = "da9030-battery", -+ .owner = THIS_MODULE, -+ }, -+ .probe = da9030_battery_probe, -+ .remove = da9030_battery_remove, -+}; -+ -+static int da9030_battery_init(void) -+{ -+ pr_debug("%s\n", __FUNCTION__); -+ -+ return platform_driver_register(&da9030_battery_driver); -+} -+ -+static void da9030_battery_exit(void) -+{ -+ pr_debug("%s\n", __FUNCTION__); -+ -+ platform_driver_unregister(&da9030_battery_driver); -+} -+ -+module_init(da9030_battery_init); -+module_exit(da9030_battery_exit); -+ -+MODULE_DESCRIPTION("DA9030 charger driver"); -+MODULE_AUTHOR("Mike Rapoport"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig -index 767aed5..4c44a7a 100644 ---- a/drivers/usb/gadget/Kconfig -+++ b/drivers/usb/gadget/Kconfig -@@ -195,6 +195,26 @@ config USB_M66592 - default USB_GADGET - select USB_GADGET_SELECTED - -+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. -+ -+ It has 23 endpoints, as well as endpoint zero (for control -+ transfers). -+ -+ 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_GADGET_GOKU - boolean "Toshiba TC86C001 'Goku-S'" - depends on PCI -diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile -index 1bc0f03..b8743bf 100644 ---- a/drivers/usb/gadget/Makefile -+++ b/drivers/usb/gadget/Makefile -@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o - obj-$(CONFIG_USB_NET2280) += net2280.o - obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o - obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o -+obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o - obj-$(CONFIG_USB_GOKU) += goku_udc.o - obj-$(CONFIG_USB_OMAP) += omap_udc.o - obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o -diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c -index 3aa46cf..d7d5550 100644 ---- a/drivers/usb/gadget/epautoconf.c -+++ b/drivers/usb/gadget/epautoconf.c -@@ -228,14 +228,19 @@ find_ep (struct usb_gadget *gadget, const char *name) - * - * On failure, this returns a null endpoint descriptor. - */ --struct usb_ep * __devinit usb_ep_autoconfig ( -+struct usb_ep * usb_ep_autoconfig ( - struct usb_gadget *gadget, -- struct usb_endpoint_descriptor *desc -+ struct usb_endpoint_descriptor *desc, -+ struct usb_endpoint_config *epconfig, int numconfigs - ) - { - struct usb_ep *ep; - u8 type; - -+ /* Use device specific ep allocation code if provided */ -+ if (gadget->ops->ep_alloc) -+ return gadget->ops->ep_alloc(gadget, desc, epconfig, numconfigs); -+ - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - /* First, apply chip-specific "best usage" knowledge. -diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c -index 593e235..87aa9fb 100644 ---- a/drivers/usb/gadget/ether.c -+++ b/drivers/usb/gadget/ether.c -@@ -1350,6 +1350,10 @@ static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req) - /* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */ - } - -+#ifdef CONFIG_USB_GADGET_PXA27X -+int write_ep0_zlp(void); -+#endif -+ - static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) - { - struct eth_dev *dev = ep->driver_data; -@@ -1360,6 +1364,10 @@ static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) - status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf); - if (status < 0) - ERROR(dev, "%s: rndis parse error %d\n", __FUNCTION__, status); -+ -+#ifdef CONFIG_USB_GADGET_PXA27X -+ write_ep0_zlp(); -+#endif - spin_unlock(&dev->lock); - } - -@@ -2287,7 +2295,8 @@ eth_bind (struct usb_gadget *gadget) - struct eth_dev *dev; - struct net_device *net; - u8 cdc = 1, zlp = 1, rndis = 1; -- struct usb_ep *in_ep, *out_ep, *status_ep = NULL; -+ struct usb_ep *in_ep = NULL , *out_ep = NULL, *status_ep = NULL; -+ struct usb_endpoint_config ep_config[2]; - int status = -ENOMEM; - int gcnum; - -@@ -2386,7 +2395,30 @@ eth_bind (struct usb_gadget *gadget) - - /* all we really need is bulk IN/OUT */ - usb_ep_autoconfig_reset (gadget); -- in_ep = usb_ep_autoconfig (gadget, &fs_source_desc); -+ -+ ep_config[0].config = DEV_CONFIG_VALUE; -+#if defined(DEV_CONFIG_CDC) -+ ep_config[0].interface = data_intf.bInterfaceNumber; -+ ep_config[0].altinterface = data_intf.bAlternateSetting; -+#else /* DEV_CONFIG_SUBSET */ -+ ep_config[0].interface = subset_data_intf.bInterfaceNumber; -+ ep_config[0].altinterface = subset_data_intf.bAlternateSetting; -+#endif -+ -+#ifdef CONFIG_USB_ETH_RNDIS -+ ep_config[1].config = DEV_RNDIS_CONFIG_VALUE; -+#ifdef CONFIG_USB_GADGET_PXA27X -+ ep_config[1].interface = 0; -+#else -+ ep_config[1].interface = rndis_data_intf.bInterfaceNumber; -+#endif -+ ep_config[1].altinterface = rndis_data_intf.bAlternateSetting; -+ -+ in_ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 2); -+#else -+ in_ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 1); -+#endif -+ - if (!in_ep) { - autoconf_fail: - dev_err (&gadget->dev, -@@ -2396,7 +2428,12 @@ autoconf_fail: - } - in_ep->driver_data = in_ep; /* claim */ - -- out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); -+#ifdef CONFIG_USB_ETH_RNDIS -+ out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 2); -+#else -+ out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 1); -+#endif -+ - if (!out_ep) - goto autoconf_fail; - out_ep->driver_data = out_ep; /* claim */ -@@ -2406,7 +2443,25 @@ autoconf_fail: - * Since some hosts expect one, try to allocate one anyway. - */ - if (cdc || rndis) { -- status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); -+#ifdef DEV_CONFIG_CDC -+ ep_config[0].config = DEV_CONFIG_VALUE; -+ ep_config[0].interface = control_intf.bInterfaceNumber; -+ ep_config[0].altinterface = control_intf.bAlternateSetting; -+#endif -+#ifdef CONFIG_USB_ETH_RNDIS -+ ep_config[1].config = DEV_RNDIS_CONFIG_VALUE; -+ ep_config[1].interface = rndis_control_intf.bInterfaceNumber; -+ ep_config[1].altinterface = rndis_control_intf.bAlternateSetting; -+#endif -+ -+#if defined(DEV_CONFIG_CDC) && defined(CONFIG_USB_ETH_RNDIS) -+ status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[0], 2); -+#elif defined(CONFIG_USB_ETH_RNDIS) -+ status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[1], 1); -+#else -+ status_ep = usb_ep_autoconfig(gadget, &fs_status_desc, &ep_config[0], 1); -+#endif -+ - if (status_ep) { - status_ep->driver_data = status_ep; /* claim */ - } else if (rndis) { -diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c -index 965ad7b..b9cd8c9 100644 ---- a/drivers/usb/gadget/file_storage.c -+++ b/drivers/usb/gadget/file_storage.c -@@ -3841,6 +3841,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) - struct usb_ep *ep; - struct usb_request *req; - char *pathbuf, *p; -+ struct usb_endpoint_config ep_config; - - fsg->gadget = gadget; - set_gadget_data(gadget, fsg); -@@ -3911,21 +3912,25 @@ static int __init fsg_bind(struct usb_gadget *gadget) - } - - /* Find all the endpoints we will use */ -+ ep_config.config = CONFIG_VALUE; -+ ep_config.interface = intf_desc.bInterfaceNumber; -+ ep_config.altinterface = intf_desc.bAlternateSetting; -+ - usb_ep_autoconfig_reset(gadget); -- ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc); -+ ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc, &ep_config, 1); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_in = ep; - -- ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc); -+ ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc, &ep_config, 1); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_out = ep; - - if (transport_is_cbi()) { -- ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc); -+ ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc, &ep_config, 1); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint -diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c -new file mode 100644 -index 0000000..d4270d4 ---- /dev/null -+++ b/drivers/usb/gadget/pxa27x_udc.c -@@ -0,0 +1,2387 @@ -+/* -+ * Handles the Intel 27x USB Device Controller (UDC) -+ * -+ * 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) -+ * Copyright (C) 2005-2006 Openedhand Ltd. (Richard Purdie) -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+/* -+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x -+ * 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. The -+ * biggest issue is that the endpoints have to be setup before the controller -+ * can be enabled and each endpoint can only have one configuration, interface -+ * and alternative interface number. Once enabled, these cannot be changed -+ * without a controller reset. -+ * -+ * Intel Errata #22 mentions issues when changing alternate interface. -+ * The exact meaning of this remains uncertain as gadget drivers using alternate -+ * interfaces such as CDC-Ethernet appear to work... -+ */ -+ -+#define DRIVER_VERSION "01-01-2006" -+#define DRIVER_DESC "PXA 27x USB Device Controller driver" -+ -+static const char driver_name [] = "pxa27x_udc"; -+ -+static const char ep0name [] = "ep0"; -+ -+ -+#define USE_DMA -+//#undef USE_DMA -+ -+#ifdef CONFIG_PROC_FS -+#define UDC_PROC_FILE -+#endif -+ -+#include "pxa27x_udc.h" -+ -+#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); -+static void kick_dma(struct pxa27x_ep *ep, struct pxa27x_request *req); -+ -+#define DMASTR " (dma support)" -+ -+#else /* !USE_DMA */ -+#define DMASTR " (pio only)" -+#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) -+ -+static void pxa27x_ep_fifo_flush(struct usb_ep *ep); -+static void nuke(struct pxa27x_ep *, int status); -+static void udc_init_ep(struct pxa27x_udc *dev); -+ -+ -+/* -+ * Endpoint Functions -+ */ -+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 -+ * -+ * Not much to do here as the ep_alloc function sets up most things. Once -+ * enabled, not much of the pxa27x configuration can be changed. -+ * -+ */ -+static int pxa27x_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -+{ -+ struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ struct pxa27x_ep *ep = virt_ep->pxa_ep; -+ struct pxa27x_udc *dev; -+ -+ if (!_ep || !desc || _ep->name == ep0name -+ || desc->bDescriptorType != USB_DT_ENDPOINT -+ || ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { -+ dev_err(ep->dev->dev, "%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) { -+ dev_err(ep->dev->dev, "%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) { -+ dev_err(ep->dev->dev, "%s, bad %s maxpacket\n", __FUNCTION__, _ep->name); -+ return -ERANGE; -+ } -+ -+ dev = ep->dev; -+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { -+ dev_err(ep->dev->dev, "%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->usb_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. -+ */ -+ dev_dbg(ep->dev->dev, "%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 : DMA_PRIO_LOW, dma_nodesc_handler, ep); -+ if (ep->dma >= 0) { -+ *ep->reg_drcmr = DRCMR_MAPVLD | ep->dma; -+ dev_dbg(ep->dev->dev, "%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_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ struct pxa27x_ep *ep = virt_ep->pxa_ep; -+ unsigned long flags; -+ -+ if (!_ep || !ep->desc) { -+ dev_err(ep->dev->dev, "%s, %s not enabled\n", __FUNCTION__, -+ _ep ? _ep->name : NULL); -+ return -EINVAL; -+ } -+ local_irq_save(flags); -+ 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; -+ -+ local_irq_restore(flags); -+ 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 = kzalloc(sizeof *req, gfp_flags); -+ if (!req) -+ return 0; -+ -+ 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); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * 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->usb_ep->name, &req->req, status, -+ req->req.actual, req->req.length); -+ -+ /* don't modify queue heads during completion callback */ -+ req->req.complete(ep->usb_ep, &req->req); -+} -+ -+ -+static inline void ep0_idle(struct pxa27x_udc *dev) -+{ -+ dev->ep0state = EP0_IDLE; -+} -+ -+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); -+ -+ //dev_dbg(ep->dev->dev, "Length %d, Remain %d, Count %d\n",length, remain, count); -+ -+ while (likely(count)) { -+ //dev_dbg(ep->dev->dev, "Sending:0x%x\n", *buf); -+ *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, is_last, is_short; -+ -+ //dev_dbg(ep->dev->dev, "write_fifo7 %x\n", *ep->reg_udccsr); -+ -+ if (*ep->reg_udccsr & UDCCSR_PC) { -+ //dev_dbg(ep->dev->dev, "Transmit Complete\n"); -+ *ep->reg_udccsr = UDCCSR_PC | (*ep->reg_udccsr & UDCCSR_MASK); -+ } -+ -+ if (*ep->reg_udccsr & UDCCSR_TRN) { -+ //dev_dbg(ep->dev->dev, "Clearing Underrun\n"); -+ *ep->reg_udccsr = UDCCSR_TRN | (*ep->reg_udccsr & UDCCSR_MASK); -+ } -+ //dev_dbg(ep->dev->dev, "write_fifo8 %x\n", *ep->reg_udccsr); -+ -+ 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); -+ } -+ -+ //dev_dbg(ep->dev->dev, "write_fifo0 %x\n", *ep->reg_udccsr); -+ -+ dev_dbg(ep->dev->dev, "wrote %s count:%d bytes%s%s %d left %p\n", -+ ep->usb_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. -+ */ -+ -+ if (is_short) -+ *ep->reg_udccsr = UDCCSR_SP | (*ep->reg_udccsr & UDCCSR_MASK); -+ -+ dev_dbg(ep->dev->dev, "write_fifo0.5 %x\n", *ep->reg_udccsr); -+ -+ /* 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->pxa_ep_num); -+ //dev_dbg(ep->dev->dev, "write_fifo1 %x\n", *ep->reg_udccsr); -+#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 -+ } -+ //dev_dbg(ep->dev->dev, "write_fifo2 %x\n", *ep->reg_udccsr); -+ 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); -+ //dev_dbg(ep->dev->dev, "write_fifo2 %x\n", *ep->reg_udccsr); -+ 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->usb_ep->maxpacket); -+ dev_dbg(ep->dev->dev, "read %s udccsr:%02x, count:%d bytes%s req %p %d/%d\n", -+ ep->usb_ep->name, *ep->reg_udccsr, count, -+ is_short ? "/S" : "", -+ &req->req, req->req.actual, req->req.length); -+ -+ count = min(count, bufferspace); -+ while (likely (count > 0)) { -+ *buf++ = *ep->reg_udcdr; -+ count -= 4; -+ } -+ dev_dbg(ep->dev->dev, "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->pxa_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) -+ dev_info(ep->dev->dev, "%s overflow\n", ep->usb_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->usb_ep->maxpacket) { -+ if ((ep->dma_con = (len % ep->usb_ep->maxpacket) != 0)) -+ len = ep->usb_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 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++; -+ -+ completed = 0; -+ -+ dcsr = DCSR(dmach); -+ DCSR(ep->dma) &= ~DCSR_RUN; -+ -+ if (dcsr & DCSR_BUSERR) { -+ DCSR(dmach) = DCSR_BUSERR; -+ dev_err(ep->dev->dev, "DMA Bus 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->usb_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->usb_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_EORINTR) { //Only happened in OUT DMA -+ int remain,udccsr ; -+ -+ DCSR(dmach) = DCSR_EORINTR; -+ 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_virt_ep *virt_ep; -+ struct pxa27x_ep *ep; -+ struct pxa27x_request *req; -+ struct pxa27x_udc *dev; -+ unsigned long flags; -+ -+ virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ ep = virt_ep->pxa_ep; -+ -+ 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; -+ } -+ -+ if (unlikely (!_ep || (!ep->desc && _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->pxa_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->pxa_ep_num); -+} -+ -+ -+/* dequeue JUST ONE request */ -+static int pxa27x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct pxa27x_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ struct pxa27x_ep *ep = virt_ep->pxa_ep; -+ struct pxa27x_request *req; -+ unsigned long flags; -+ -+ if (!_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_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ struct pxa27x_ep *ep = virt_ep->pxa_ep; -+ unsigned long flags; -+ -+ DMSG("%s is called\n", __FUNCTION__); -+ if (unlikely (!_ep || (!ep->desc && _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; -+ -+ /* 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_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ struct pxa27x_ep *ep = virt_ep->pxa_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_virt_ep *virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ struct pxa27x_ep *ep = virt_ep->pxa_ep; -+ -+ DMSG("pxa27x_ep_fifo_flush\n"); -+ -+ if (!_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, -+ -+ .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 inline unsigned int validate_fifo_size(u8 bmAttributes) -+{ -+ switch (bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_CONTROL: -+ return EP0_FIFO_SIZE; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ return ISO_FIFO_SIZE; -+ break; -+ case USB_ENDPOINT_XFER_BULK: -+ return BULK_FIFO_SIZE; -+ break; -+ case USB_ENDPOINT_XFER_INT: -+ return INT_FIFO_SIZE; -+ break; -+ default: -+ break; -+ } -+} -+ -+static void pxa27x_ep_free(struct usb_gadget *gadget, struct usb_ep *_ep) -+{ -+ struct pxa27x_udc *dev = the_controller; -+ struct pxa27x_virt_ep *virt_ep; -+ int i; -+ -+ virt_ep = container_of(_ep, struct pxa27x_virt_ep, usb_ep); -+ -+ for (i = 1; i < UDC_EP_NUM; i++) { -+ if (dev->ep[i].usb_ep == &virt_ep->usb_ep) { -+ if (dev->ep[i].desc) { -+ virt_ep->pxa_ep = &dev->ep[i]; -+ pxa27x_ep_disable(&virt_ep->usb_ep); -+ } -+ dev->ep[i].usb_ep = NULL; -+ } -+ } -+ -+ if (!list_empty(&virt_ep->usb_ep.ep_list)) -+ list_del_init(&virt_ep->usb_ep.ep_list); -+ -+ kfree(virt_ep->usb_ep.name); -+ kfree(virt_ep); -+} -+ -+static void pxa27x_ep_freeall(struct usb_gadget *gadget) -+{ -+ struct pxa27x_udc *dev = the_controller; -+ int i; -+ -+ for (i = 1; i < UDC_EP_NUM; i++) { -+ if(dev->ep[i].usb_ep) -+ pxa27x_ep_free(gadget, dev->ep[i].usb_ep); -+ } -+} -+ -+#define NAME_SIZE 18 -+ -+static int pxa27x_find_free_ep(struct pxa27x_udc *dev) -+{ -+ int i; -+ for (i = 1; i < UDC_EP_NUM; i++) { -+ if(!dev->ep[i].assigned) -+ return i; -+ } -+ return -1; -+} -+ -+/* -+ * Endpoint Allocation/Configuration -+ * -+ * pxa27x endpoint configuration is fixed when the device is enabled. Any pxa -+ * endpoint is only active in one configuration, interface and alternate -+ * interface combination so to support gadget drivers, we map one usb_ep to -+ * one of several pxa ep's. One pxa endpoint is assigned per configuration -+ * combination. -+ */ -+static struct usb_ep* pxa27x_ep_alloc(struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc, -+ struct usb_endpoint_config *epconfig, int configs) -+{ -+ struct pxa27x_udc *dev = the_controller; -+ struct pxa27x_virt_ep *virt_ep; -+ unsigned int i, fifo_size; -+ char *name; -+ -+ if (unlikely(configs < 1)) { -+ dev_err(dev->dev, "%s: Error in config data\n", __FUNCTION__); -+ return NULL; -+ } -+ -+ virt_ep = kmalloc(sizeof(struct pxa27x_virt_ep), GFP_KERNEL); -+ name = kmalloc(NAME_SIZE, GFP_KERNEL); -+ if (!virt_ep || !name) { -+ dev_err(dev->dev, "%s: -ENOMEM\n", __FUNCTION__); -+ kfree(name); -+ kfree(virt_ep); -+ return NULL; -+ } -+ -+ if (!(desc->wMaxPacketSize)) { -+ fifo_size = validate_fifo_size(desc->bmAttributes); -+ desc->wMaxPacketSize = fifo_size; -+ } else { -+ fifo_size = desc->wMaxPacketSize; -+ } -+ -+ DMSG("pxa27x_ep_alloc: bLength: %d, bDescriptorType: %x, bEndpointAddress: %x,\n" -+ " bmAttributes: %x, wMaxPacketSize: %d\n", desc->bLength, -+ desc->bDescriptorType, desc->bEndpointAddress, desc->bmAttributes, -+ desc->wMaxPacketSize); -+ -+ if (!(desc->bEndpointAddress & 0xF)) -+ desc->bEndpointAddress |= dev->ep_num; -+ -+ for (i = 0; i < configs; i++) -+ { -+ struct pxa27x_ep *pxa_ep; -+ int j; -+ -+ DMSG("pxa27x_ep_alloc: config: %d, interface: %d, altinterface: %x,\n", -+ epconfig->config, epconfig->interface, epconfig->altinterface); -+ -+ j = pxa27x_find_free_ep(dev); -+ -+ if (unlikely(j < 0)) { -+ dev_err(dev->dev, "pxa27x_ep_alloc: Failed to find a spare endpoint\n"); -+ pxa27x_ep_free(gadget, &virt_ep->usb_ep); -+ return NULL; -+ } -+ -+ pxa_ep = &dev->ep[j]; -+ -+ if (i == 0) -+ virt_ep->pxa_ep = pxa_ep; -+ -+ pxa_ep->assigned = 1; -+ pxa_ep->ep_num = dev->ep_num; -+ pxa_ep->pxa_ep_num = j; -+ pxa_ep->usb_ep = &virt_ep->usb_ep; -+ pxa_ep->dev = dev; -+ pxa_ep->desc = desc; -+ pxa_ep->pio_irqs = pxa_ep->dma_irqs = 0; -+ pxa_ep->dma = -1; -+ -+ pxa_ep->fifo_size = fifo_size; -+ 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 = epconfig->config; -+ pxa_ep->interface = epconfig->interface; -+ pxa_ep->aisn = epconfig->altinterface; -+ -+ pxa_ep->reg_udccsr = &UDCCSR0 + j; -+ pxa_ep->reg_udcbcr = &UDCBCR0 + j; -+ pxa_ep->reg_udcdr = &UDCDR0 + j ; -+ pxa_ep->reg_udccr = &UDCCRA - 1 + j; -+#ifdef USE_DMA -+ pxa_ep->reg_drcmr = &DRCMR24 + j; -+#endif -+ -+ /* Configure UDCCR */ -+ *pxa_ep->reg_udccr = ((pxa_ep->config << UDCCONR_CN_S) & UDCCONR_CN) -+ | ((pxa_ep->interface << UDCCONR_IN_S) & UDCCONR_IN) -+ | ((pxa_ep->aisn << UDCCONR_AISN_S) & UDCCONR_AISN) -+ | ((dev->ep_num << UDCCONR_EN_S) & UDCCONR_EN) -+ | ((pxa_ep->ep_type << UDCCONR_ET_S) & UDCCONR_ET) -+ | ((pxa_ep->dir_in) ? UDCCONR_ED : 0) -+ | ((min(pxa_ep->fifo_size, (unsigned)desc->wMaxPacketSize) << UDCCONR_MPS_S ) & UDCCONR_MPS) -+ | UDCCONR_EE; -+// | UDCCONR_DE | UDCCONR_EE; -+ -+ -+ -+#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); -+ -+ epconfig++; -+ } -+ -+ /* Fill ep name*/ -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ sprintf(name, "ep%d%s-bulk", dev->ep_num, -+ ((desc->bEndpointAddress & USB_DIR_IN) ? "in":"out")); -+ break; -+ case USB_ENDPOINT_XFER_INT: -+ sprintf(name, "ep%d%s-intr", dev->ep_num, -+ ((desc->bEndpointAddress & USB_DIR_IN) ? "in":"out")); -+ break; -+ default: -+ sprintf(name, "ep%d%s", dev->ep_num, -+ ((desc->bEndpointAddress & USB_DIR_IN) ? "in":"out")); -+ break; -+ } -+ -+ virt_ep->desc = desc; -+ virt_ep->usb_ep.name = name; -+ virt_ep->usb_ep.ops = &pxa27x_ep_ops; -+ virt_ep->usb_ep.maxpacket = min((ushort)fifo_size, desc->wMaxPacketSize); -+ -+ list_add_tail(&virt_ep->usb_ep.ep_list, &gadget->ep_list); -+ -+ dev->ep_num++; -+ return &virt_ep->usb_ep; -+} -+ -+static int pxa27x_udc_get_frame(struct usb_gadget *_gadget) -+{ -+ return (UDCFNR & 0x7FF); -+} -+ -+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 = { -+ .ep_alloc = pxa27x_ep_alloc, -+ .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 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, -+ "%d max %d %s udccs %02x udccr:0x%x\n", -+ i, 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(CKEN_USB, 0); -+ -+ ep0_idle(dev); -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ 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); -+ -+ /* Enable clock for USB device */ -+ pxa_set_cken(CKEN_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) -+ dev_err(dev->dev, "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); -+ -+ DMSG("Connecting\n"); -+ /* RPFIXME */ -+ UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE; -+ //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 (!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; -+ -+ udc_disable(dev); -+ udc_init_ep(dev); -+ udc_reinit(dev); -+ -+ /* first hook up the driver ... */ -+ dev->driver = driver; -+ dev->gadget.dev.driver = &driver->driver; -+ dev->ep_num = 1; -+ -+ retval = device_add(&dev->gadget.dev); -+ if (retval) { -+ DMSG("device_add error %d\n", retval); -+ goto add_fail; -+ } -+ retval = driver->bind(&dev->gadget); -+ if (retval) { -+ DMSG("bind to driver %s --> error %d\n", -+ driver->driver.name, retval); -+ goto bind_fail; -+ } -+ retval = device_create_file(dev->dev, &dev_attr_function); -+ if (retval) { -+ DMSG("device_create_file failed: %d\n", retval); -+ goto create_file_fail; -+ } -+ -+ /* ... 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; -+ -+create_file_fail: -+ driver->unbind(&dev->gadget); -+bind_fail: -+ device_del(&dev->gadget.dev); -+add_fail: -+ dev->driver = 0; -+ dev->gadget.dev.driver = 0; -+ return retval; -+} -+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); -+ pxa27x_ep_freeall(&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); -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+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: -+ dev_info(dev->dev, "%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); -+ -+ 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: -+ dev_err(dev->dev, "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; -+ -+ /* 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->pxa_ep_num); -+ //*ep->reg_udccsr = UDCCSR_FEF; -+ DMSG("%s: no req for out data\n", -+ __FUNCTION__); -+ } -+ } -+ ep->pio_irqs++; -+ } while (completed); -+} -+ -+static void pxa27x_update_eps(struct pxa27x_udc *dev) -+{ -+ struct pxa27x_virt_ep *virt_ep; -+ int i; -+ -+ for (i = 1; i < UDC_EP_NUM; i++) { -+ if(!dev->ep[i].assigned || !dev->ep[i].usb_ep) -+ continue; -+ virt_ep = container_of(dev->ep[i].usb_ep, struct pxa27x_virt_ep, usb_ep); -+ -+ DMSG("%s, Updating eps %d:%d, %d:%d, %d:%d, %p,%p\n", __FUNCTION__, dev->ep[i].config, dev->configuration -+ ,dev->ep[i].interface, dev->interface, dev->ep[i].aisn, dev->alternate, virt_ep->pxa_ep, &dev->ep[i]); -+ -+ if(dev->ep[i].config == dev->configuration && virt_ep->pxa_ep != &dev->ep[i]) { -+ if ((dev->ep[i].interface == dev->interface && -+ dev->ep[i].aisn == dev->alternate) || virt_ep->pxa_ep->config != dev->configuration) { -+ -+ if (virt_ep->pxa_ep->desc) { -+ DMSG("%s, Changing end point to %d (en/dis)\n", __FUNCTION__, i); -+ pxa27x_ep_disable(&virt_ep->usb_ep); -+ virt_ep->pxa_ep = &dev->ep[i]; -+ pxa27x_ep_enable(&virt_ep->usb_ep, virt_ep->desc); -+ } else { -+ DMSG("%s, Changing end point to %d (no en/dis)\n", __FUNCTION__, i); -+ virt_ep->pxa_ep = &dev->ep[i]; -+ } -+ } -+ } -+ } -+} -+ -+static void pxa27x_change_configuration(struct pxa27x_udc *dev) -+{ -+ struct usb_ctrlrequest req ; -+ -+ pxa27x_update_eps(dev); -+ -+ 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; -+ -+ pxa27x_update_eps(dev); -+ -+ 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 pxa27x_udc *dev = _dev; -+ int handled; -+ -+ dev->stats.irqs++; -+ -+ 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_IRSU)) { -+ UDCISR1 = UDCISR1_IRSU; -+ 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_IRRU)) { -+ UDCISR1 = UDCISR1_IRRU; -+ 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_IRCC)) { -+ unsigned config, interface, alternate; -+ -+ handled = 1; -+ DBG(DBG_VERBOSE, "USB SET_CONFIGURATION or " -+ "SET_INTERFACE command received\n"); -+ -+ 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->interface != interface) || (dev->alternate != alternate)) { -+ dev->interface = interface; -+ dev->alternate = alternate; -+ pxa27x_change_interface(dev); -+ } -+ -+ UDCCR |= UDCCR_SMAC; -+ -+ UDCISR1 = UDCISR1_IRCC; -+ DMSG("%s: con:%d,inter:%d,alt:%d\n", -+ __FUNCTION__, config,interface, alternate); -+ } -+ -+ /* ReSeT Interrupt Request - USB reset */ -+ if (unlikely(udcir & UDCISR1_IRRS)) { -+ UDCISR1 = UDCISR1_IRRS; -+ 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) -+ dev_err(dev->dev, " 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) { -+ dev_err(dev->dev, "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; -+} -+ -+int write_ep0_zlp(void) -+{ -+ UDCCSR0 = UDCCSR0_IPR; -+ return 0; -+} -+EXPORT_SYMBOL(write_ep0_zlp); -+ -+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); -+ } -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+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.virt_ep0.usb_ep, -+ .name = driver_name, -+ .dev = { -+ .bus_id = "gadget", -+ .release = nop_release, -+ }, -+ }, -+ -+ /* control endpoint */ -+ .virt_ep0 = { -+ .pxa_ep = &memory.ep[0], -+ .usb_ep = { -+ .name = ep0name, -+ .ops = &pxa27x_ep_ops, -+ .maxpacket = EP0_FIFO_SIZE, -+ }, -+ }, -+ -+ .ep[0] = { -+ .usb_ep = &memory.virt_ep0.usb_ep, -+ .dev = &memory, -+ .reg_udccsr = &UDCCSR0, -+ .reg_udcdr = &UDCDR0, -+ }, -+}; -+ -+static int __init pxa27x_udc_probe(struct platform_device *_dev) -+{ -+ struct pxa27x_udc *dev = &memory; -+ int retval; -+ -+ /* other non-static parts of init */ -+ dev->dev = &_dev->dev; -+ dev->mach = _dev->dev.platform_data; -+ -+ /* RPFIXME */ -+ UP2OCR = UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE; -+ -+ 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; -+ dev->gadget.dev.dma_mask = _dev->dev.dma_mask; -+ -+ the_controller = dev; -+ platform_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) { -+ dev_err(dev->dev, "%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 pxa27x_udc_remove(struct platform_device *_dev) -+{ -+ struct pxa27x_udc *dev = platform_get_drvdata(_dev); -+ -+ udc_disable(dev); -+ remove_proc_files(); -+ usb_gadget_unregister_driver(dev->driver); -+ -+ pxa27x_ep_freeall(&dev->gadget); -+ -+ if (dev->got_irq) { -+ free_irq(IRQ_USB, dev); -+ dev->got_irq = 0; -+ } -+ platform_set_drvdata(_dev, 0); -+ the_controller = 0; -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static void pxa27x_udc_shutdown(struct platform_device *_dev) -+{ -+ struct pxa27x_udc *dev = platform_get_drvdata(_dev); -+ -+ udc_disable(dev); -+} -+ -+static int pxa27x_udc_suspend(struct platform_device *_dev, pm_message_t state) -+{ -+ int i; -+ struct pxa27x_udc *dev = platform_get_drvdata(_dev); -+ -+ DMSG("%s is called\n", __FUNCTION__); -+ -+ dev->udccsr0 = UDCCSR0; -+ for(i=1; (iep[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(CKEN_USB, 0); -+ -+ return 0; -+} -+ -+static int pxa27x_udc_resume(struct platform_device *_dev) -+{ -+ int i; -+ struct pxa27x_udc *dev = platform_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 platform_driver udc_driver = { -+ .driver = { -+ .name = "pxa2xx-udc", -+ }, -+ .probe = pxa27x_udc_probe, -+ .remove = pxa27x_udc_remove, -+#ifdef CONFIG_PM -+ .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 platform_driver_register(&udc_driver); -+} -+module_init(udc_init); -+ -+static void __exit udc_exit(void) -+{ -+ platform_driver_unregister(&udc_driver); -+} -+module_exit(udc_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h -new file mode 100644 -index 0000000..d4377cf ---- /dev/null -+++ b/drivers/usb/gadget/pxa27x_udc.h -@@ -0,0 +1,298 @@ -+/* -+ * linux/drivers/usb/gadget/pxa27x_udc.h -+ * Intel PXA27x on-chip full speed USB device controller -+ * -+ * Copyright (C) 2003 Robert Schwebel , 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 -+ -+struct pxa27x_udc; -+ -+struct pxa27x_ep { -+ struct pxa27x_udc *dev; -+ struct usb_ep *usb_ep; -+ const struct usb_endpoint_descriptor *desc; -+ -+ struct list_head queue; -+ unsigned long pio_irqs; -+ unsigned long dma_irqs; -+ -+ unsigned pxa_ep_num; -+ int dma; -+ unsigned fifo_size; -+ unsigned ep_type; -+ -+ unsigned stopped : 1; -+ unsigned dma_con : 1; -+ unsigned dir_in : 1; -+ unsigned assigned : 1; -+ -+ unsigned ep_num; -+ 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_virt_ep { -+ struct usb_ep usb_ep; -+ const struct usb_endpoint_descriptor *desc; -+ struct pxa27x_ep *pxa_ep; -+}; -+ -+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; -+}; -+ -+#define UDC_EP_NUM 24 -+ -+ -+struct pxa27x_udc { -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ -+ enum ep0_state ep0state; -+ struct udc_stats stats; -+ unsigned got_irq : 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_virt_ep virt_ep0; -+ struct pxa27x_ep ep[UDC_EP_NUM]; -+ unsigned int ep_num; -+ -+ unsigned configuration, -+ interface, -+ alternate; -+#ifdef CONFIG_PM -+ unsigned udccsr0; -+#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].assigned) -+ 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)4) -+ -+#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 --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h -index 0e5d0e6..9483a49 100644 ---- a/drivers/usb/gadget/pxa2xx_udc.h -+++ b/drivers/usb/gadget/pxa2xx_udc.h -@@ -206,7 +206,8 @@ dump_state(struct pxa2xx_udc *dev) - unsigned i; - - DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", -- is_usb_connected() ? "host " : "disconnected", -+ //is_usb_connected() ? "host " : "disconnected", -+ "host ", - state_name[dev->ep0state], - UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); - dump_udccr("udccr"); -@@ -223,8 +224,8 @@ dump_state(struct pxa2xx_udc *dev) - } else - DMSG("ep0 driver '%s'\n", dev->driver->driver.name); - -- if (!is_usb_connected()) -- return; -+ //if (!is_usb_connected()) -+ // return; - - dump_udccs0 ("udccs0"); - DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n", -diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c -index ce4d2e0..5dac23f 100644 ---- a/drivers/usb/gadget/serial.c -+++ b/drivers/usb/gadget/serial.c -@@ -1356,6 +1356,7 @@ static int __init gs_bind(struct usb_gadget *gadget) - struct usb_ep *ep; - struct gs_dev *dev; - int gcnum; -+ struct usb_endpoint_config ep_config[2]; - - /* Some controllers can't support CDC ACM: - * - sh doesn't support multiple interfaces or configs; -@@ -1376,22 +1377,33 @@ static int __init gs_bind(struct usb_gadget *gadget) - __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); - } - -+ ep_config[0].config = GS_BULK_CONFIG_ID; -+ ep_config[0].interface = gs_bulk_interface_desc.bInterfaceNumber; -+ ep_config[0].altinterface = gs_bulk_interface_desc.bAlternateSetting; -+ ep_config[1].config = GS_ACM_CONFIG_ID; -+ ep_config[1].interface = gs_data_interface_desc.bInterfaceNumber; -+ ep_config[1].altinterface = gs_data_interface_desc.bAlternateSetting; -+ - usb_ep_autoconfig_reset(gadget); - -- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); -+ ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc, &ep_config[0], 2); - if (!ep) - goto autoconf_fail; - EP_IN_NAME = ep->name; - ep->driver_data = ep; /* claim the endpoint */ - -- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); -+ ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc, &ep_config[0], 2); - if (!ep) - goto autoconf_fail; - EP_OUT_NAME = ep->name; - ep->driver_data = ep; /* claim the endpoint */ - - if (use_acm) { -- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc); -+ ep_config[0].config = GS_ACM_CONFIG_ID; -+ ep_config[0].interface = gs_control_interface_desc.bInterfaceNumber; -+ ep_config[0].altinterface = gs_control_interface_desc.bAlternateSetting; -+ -+ ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc, &ep_config[0], 1); - if (!ep) { - printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name); - goto autoconf_fail; -diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c -index fcfe869..1e40d46 100644 ---- a/drivers/usb/gadget/zero.c -+++ b/drivers/usb/gadget/zero.c -@@ -1142,6 +1142,7 @@ zero_bind (struct usb_gadget *gadget) - struct zero_dev *dev; - struct usb_ep *ep; - int gcnum; -+ struct usb_endpoint_config ep_config[2]; - - /* FIXME this can't yet work right with SH ... it has only - * one configuration, numbered one. -@@ -1154,7 +1155,15 @@ zero_bind (struct usb_gadget *gadget) - * but there may also be important quirks to address. - */ - usb_ep_autoconfig_reset (gadget); -- ep = usb_ep_autoconfig (gadget, &fs_source_desc); -+ -+ ep_config[0].config = CONFIG_SOURCE_SINK; -+ ep_config[0].interface = source_sink_intf.bInterfaceNumber; -+ ep_config[0].altinterface = source_sink_intf.bAlternateSetting; -+ ep_config[1].config = CONFIG_LOOPBACK; -+ ep_config[1].interface = loopback_intf.bInterfaceNumber; -+ ep_config[1].altinterface = loopback_intf.bAlternateSetting; -+ -+ ep = usb_ep_autoconfig(gadget, &fs_source_desc, &ep_config[0], 2); - if (!ep) { - autoconf_fail: - printk (KERN_ERR "%s: can't autoconfigure on %s\n", -@@ -1164,7 +1173,7 @@ autoconf_fail: - EP_IN_NAME = ep->name; - ep->driver_data = ep; /* claim */ - -- ep = usb_ep_autoconfig (gadget, &fs_sink_desc); -+ ep = usb_ep_autoconfig(gadget, &fs_sink_desc, &ep_config[0], 2); - if (!ep) - goto autoconf_fail; - EP_OUT_NAME = ep->name; -diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig -index 2580f5f..12e4b91 100644 ---- a/drivers/video/backlight/Kconfig -+++ b/drivers/video/backlight/Kconfig -@@ -40,7 +40,7 @@ config BACKLIGHT_CLASS_DEVICE - - config BACKLIGHT_CORGI - tristate "Sharp Corgi Backlight Driver (SL Series)" -- depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL -+ depends on BACKLIGHT_CLASS_DEVICE && (PXA_SHARPSL || MACH_EM_X270) - default y - help - If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the -diff --git a/include/asm-arm/arch-pxa/pwr-i2c.h b/include/asm-arm/arch-pxa/pwr-i2c.h -new file mode 100644 -index 0000000..6bad486 ---- /dev/null -+++ b/include/asm-arm/arch-pxa/pwr-i2c.h -@@ -0,0 +1,61 @@ -+/* -+ * (C) Copyright 2007 CompuLab, Ltd -+ * Mike Rapoport -+ * -+ * Simple Power I2C interface for PXA processors. -+ * Based on U-Boot PXA I2C driver. -+ * -+ * 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 __PXA_PWR_I2C_H__ -+#define __PXA_PWR_I2C_H__ -+ -+/* -+ * Configuration items. -+ */ -+#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */ -+ -+/* -+ * Probe the given I2C chip address. Returns 0 if a chip responded, -+ * not 0 on failure. -+ */ -+extern int pxa_pwr_i2c_probe(u8 chip); -+ -+/* -+ * Read/Write interface: -+ * chip: I2C chip address, range 0..127 -+ * addr: Memory (register) address within the chip -+ * alen: Number of bytes to use for addr (typically 1, 2 for larger -+ * memories, 0 for register type devices with only one -+ * register) -+ * buffer: Where to read/write the data -+ * len: How many bytes to read/write -+ * -+ * Returns: 0 on success, not 0 on failure -+ */ -+extern int pxa_pwr_i2c_read(u8 chip, uint addr, int alen, u8 *buffer, int len); -+extern int pxa_pwr_i2c_write(u8 chip, uint addr, int alen, -+ u8 *buffer, int len); -+ -+/* -+ * Utility routines to read/write registers. -+ */ -+extern s32 pxa_pwr_i2c_reg_read (u8 chip, u8 reg); -+extern s32 pxa_pwr_i2c_reg_write(u8 chip, u8 reg, u8 val); -+ -+#endif /* __PXA_PWR_I2C_H___ */ -diff --git a/include/linux/da9030.h b/include/linux/da9030.h -new file mode 100644 -index 0000000..6eb89e2 ---- /dev/null -+++ b/include/linux/da9030.h -@@ -0,0 +1,118 @@ -+#ifndef _DA9030_H -+#define _DA9030_H -+ -+/* DA9030 has 24 possible interrupts */ -+#define DA9030_IRQ_COUNT 24 -+ -+/* EVENT A */ -+#define DA9030_IRQ_ONKEY_EN 0 -+#define DA9030_IRQ_PWREN1 1 -+#define DA9030_IRQ_EXTON 2 -+#define DA9030_IRQ_CHDET 3 -+#define DA9030_IRQ_TBAT 4 -+#define DA9030_IRQ_VBATMON 5 -+#define DA9030_IRQ_VBATMONTXON 6 -+#define DA9030_IRQ_CHIOVER 7 -+ -+/* EVENT B */ -+#define DA9030_IRQ_TCTO 8 -+#define DA9030_IRQ_CCTO 9 -+#define DA9030_IRQ_ADC_READY 10 -+#define DA9030_IRQ_VBUS_4_4 11 -+#define DA9030_IRQ_VBUS_4_0 12 -+#define DA9030_IRQ_SESSION_VALID 13 -+#define DA9030_IRQ_SRP_DETECT 14 -+#define DA9030_IRQ_WDOG_INTR 15 -+ -+/* EVENT C */ -+#define DA9030_IRQ_LDO15 16 -+#define DA9030_IRQ_LDO16 17 -+#define DA9030_IRQ_LDO17 18 -+#define DA9030_IRQ_LDO18 19 -+#define DA9030_IRQ_LDO19 20 -+#define DA9030_IRQ_BUCK2 21 -+#define DA9030_IRQ_ADC_IN4 22 -+#define DA9030_IRQ_ADC_IN5 23 -+ -+enum da9030_ldo_sleep_mode { -+ DA9030_LDO_SLEEP_KEEP = 0x0, -+ DA9030_LDO_SLEEP_SHUT_DOWN = 0x1, -+ DA9030_LDO_SLEEP_POWER_UP = 0x2, -+ DA9030_LDO_SLEEP_HIGH_Z = 0x3, -+}; -+ -+enum da9030_led_rate { -+ DA9030_LED_RATE_ON = 0x0, -+ DA9030_LED_RATE_0_52 = 0x1, -+ DA9030_LED_RATE_1_05 = 0x2, -+ DA9030_LED_RATE_2_1 = 0x3, -+}; -+ -+enum da9030_led_duty_cycle { -+ DA9030_LED_DUTY_1_16 = 0x0, -+ DA9030_LED_DUTY_1_8 = 0x1, -+ DA9030_LED_DUTY_1_4 = 0x2, -+ DA9030_LED_DUTY_1_2 = 0x3, -+}; -+ -+enum da9030_led_pwm_chop { -+ DA9030_LED_PWM_8_8 = 0x0, -+ DA9030_LED_PWM_7_8 = 0x1, -+ DA9030_LED_PWM_6_8 = 0x2, -+ DA9030_LED_PWM_5_8 = 0x3, -+ DA9030_LED_PWM_4_8 = 0x4, -+ DA9030_LED_PWM_3_8 = 0x5, -+ DA9030_LED_PWM_2_8 = 0x6, -+ DA9030_LED_PWM_1_8 = 0x7, -+}; -+ -+struct da9030_adc_res { -+ int vbat_res; -+ int vbatmin_res; -+ int vbatmintxon; -+ int ichmax_res; -+ int ichmin_res; -+ int ichaverage_res; -+ int vchmax_res; -+ int vchmin_res; -+ int tbat_res; -+ int adc_in4_res; -+ int adc_in5_res; -+}; -+ -+extern int da9030_get_status(void); -+extern int da9030_get_fault_log(void); -+ -+extern void da9030_enable_adc(void); -+extern void da9030_read_adc(struct da9030_adc_res *adc); -+ -+extern void da9030_set_wled(int on, unsigned int brightness); -+ -+extern int da9030_set_led(int led, int on, -+ enum da9030_led_rate rate, -+ enum da9030_led_duty_cycle duty, -+ enum da9030_led_pwm_chop pwm_chop); -+ -+extern int da9030_set_charger(int on, unsigned int mA, unsigned int mV); -+extern void da9030_get_charger(int *on, unsigned int *mA, unsigned int *mV); -+ -+extern int da9030_set_ldo(int ldo, int on, unsigned int mV, -+ enum da9030_ldo_sleep_mode sleep_mode); -+extern int da9030_set_buck(int buck, int on, unsigned int mV, int flags); -+ -+extern void da9030_set_thresholds(unsigned int tbathighp, -+ unsigned int tbathighn, -+ unsigned int tbatlow, -+ unsigned int vbatmon); -+ -+extern int da9030_register_callback(int event, -+ void (*callback)(int event, void *data), -+ void *data); -+extern void da9030_unregister_callback(int event); -+ -+/* Keep these for now, although they are unsafe. When I'll see what -+ other methods are needed from DA9030, I'll remove these */ -+extern s32 da9030_get_reg(u32 reg); -+extern s32 da9030_set_reg(u32 reg, u8 val); -+ -+#endif -diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h -index 4f59b2a..792c568 100644 ---- a/include/linux/usb_gadget.h -+++ b/include/linux/usb_gadget.h -@@ -397,10 +397,28 @@ usb_ep_fifo_flush (struct usb_ep *ep) - - struct usb_gadget; - -+/** -+ * struct usb_endpoint_config - possible configurations of a given endpoint -+ * @config: the configuration number -+ * @interface: the interface number -+ * @altinterface: the altinterface number -+ * -+ * Used as an array to pass information about the possible configurations -+ * of a given endpoint to the bus controller. -+ */ -+struct usb_endpoint_config { -+ u8 config; -+ u8 interface; -+ u8 altinterface; -+}; -+ - /* the rest of the api to the controller hardware: device operations, - * which don't involve endpoints (or i/o). - */ - struct usb_gadget_ops { -+ struct usb_ep* (*ep_alloc)(struct usb_gadget *, -+ struct usb_endpoint_descriptor *, -+ struct usb_endpoint_config *, int); - int (*get_frame)(struct usb_gadget *); - int (*wakeup)(struct usb_gadget *); - int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); -@@ -824,7 +842,10 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config, - /* utility wrapping a simple endpoint selection policy */ - - extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, -- struct usb_endpoint_descriptor *) __devinit; -+ struct usb_endpoint_descriptor *, -+ struct usb_endpoint_config *, -+ int numconfigs -+); - - extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit; - -diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h -new file mode 100644 -index 0000000..354e533 ---- /dev/null -+++ b/include/linux/wm97xx.h -@@ -0,0 +1,291 @@ -+ -+/* -+ * Register bits and API for Wolfson WM97xx series of codecs -+ */ -+ -+#ifndef _LINUX_WM97XX_H -+#define _LINUX_WM97XX_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* Input device layer */ -+ -+/* -+ * WM97xx AC97 Touchscreen registers -+ */ -+#define AC97_WM97XX_DIGITISER1 0x76 -+#define AC97_WM97XX_DIGITISER2 0x78 -+#define AC97_WM97XX_DIGITISER_RD 0x7a -+#define AC97_WM9713_DIG1 0x74 -+#define AC97_WM9713_DIG2 AC97_WM97XX_DIGITISER1 -+#define AC97_WM9713_DIG3 AC97_WM97XX_DIGITISER2 -+ -+/* -+ * WM97xx register bits -+ */ -+#define WM97XX_POLL 0x8000 /* initiate a polling measurement */ -+#define WM97XX_ADCSEL_X 0x1000 /* x coord measurement */ -+#define WM97XX_ADCSEL_Y 0x2000 /* y coord measurement */ -+#define WM97XX_ADCSEL_PRES 0x3000 /* pressure measurement */ -+#define WM97XX_ADCSEL_MASK 0x7000 -+#define WM97XX_COO 0x0800 /* enable coordinate mode */ -+#define WM97XX_CTC 0x0400 /* enable continuous mode */ -+#define WM97XX_CM_RATE_93 0x0000 /* 93.75Hz continuous rate */ -+#define WM97XX_CM_RATE_187 0x0100 /* 187.5Hz continuous rate */ -+#define WM97XX_CM_RATE_375 0x0200 /* 375Hz continuous rate */ -+#define WM97XX_CM_RATE_750 0x0300 /* 750Hz continuous rate */ -+#define WM97XX_CM_RATE_8K 0x00f0 /* 8kHz continuous rate */ -+#define WM97XX_CM_RATE_12K 0x01f0 /* 12kHz continuous rate */ -+#define WM97XX_CM_RATE_24K 0x02f0 /* 24kHz continuous rate */ -+#define WM97XX_CM_RATE_48K 0x03f0 /* 48kHz continuous rate */ -+#define WM97XX_CM_RATE_MASK 0x03f0 -+#define WM97XX_RATE(i) (((i & 3) << 8) | ((i & 4) ? 0xf0 : 0)) -+#define WM97XX_DELAY(i) ((i << 4) & 0x00f0) /* sample delay times */ -+#define WM97XX_DELAY_MASK 0x00f0 -+#define WM97XX_SLEN 0x0008 /* slot read back enable */ -+#define WM97XX_SLT(i) ((i - 5) & 0x7) /* touchpanel slot selection (5-11) */ -+#define WM97XX_SLT_MASK 0x0007 -+#define WM97XX_PRP_DETW 0x4000 /* pen detect on, digitiser off, wake up */ -+#define WM97XX_PRP_DET 0x8000 /* pen detect on, digitiser off, no wake up */ -+#define WM97XX_PRP_DET_DIG 0xc000 /* pen detect on, digitiser on */ -+#define WM97XX_RPR 0x2000 /* wake up on pen down */ -+#define WM97XX_PEN_DOWN 0x8000 /* pen is down */ -+#define WM97XX_ADCSRC_MASK 0x7000 /* ADC source mask */ -+ -+#define WM97XX_AUX_ID1 0x8001 -+#define WM97XX_AUX_ID2 0x8002 -+#define WM97XX_AUX_ID3 0x8003 -+#define WM97XX_AUX_ID4 0x8004 -+ -+ -+/* WM9712 Bits */ -+#define WM9712_45W 0x1000 /* set for 5-wire touchscreen */ -+#define WM9712_PDEN 0x0800 /* measure only when pen down */ -+#define WM9712_WAIT 0x0200 /* wait until adc is read before next sample */ -+#define WM9712_PIL 0x0100 /* current used for pressure measurement. set 400uA else 200uA */ -+#define WM9712_MASK_HI 0x0040 /* hi on mask pin (47) stops conversions */ -+#define WM9712_MASK_EDGE 0x0080 /* rising/falling edge on pin delays sample */ -+#define WM9712_MASK_SYNC 0x00c0 /* rising/falling edge on mask initiates sample */ -+#define WM9712_RPU(i) (i&0x3f) /* internal pull up on pen detect (64k / rpu) */ -+#define WM9712_PD(i) (0x1 << i) /* power management */ -+ -+/* WM9712 Registers */ -+#define AC97_WM9712_POWER 0x24 -+#define AC97_WM9712_REV 0x58 -+ -+/* WM9705 Bits */ -+#define WM9705_PDEN 0x1000 /* measure only when pen is down */ -+#define WM9705_PINV 0x0800 /* inverts sense of pen down output */ -+#define WM9705_BSEN 0x0400 /* BUSY flag enable, pin47 is 1 when busy */ -+#define WM9705_BINV 0x0200 /* invert BUSY (pin47) output */ -+#define WM9705_WAIT 0x0100 /* wait until adc is read before next sample */ -+#define WM9705_PIL 0x0080 /* current used for pressure measurement. set 400uA else 200uA */ -+#define WM9705_PHIZ 0x0040 /* set PHONE and PCBEEP inputs to high impedance */ -+#define WM9705_MASK_HI 0x0010 /* hi on mask stops conversions */ -+#define WM9705_MASK_EDGE 0x0020 /* rising/falling edge on pin delays sample */ -+#define WM9705_MASK_SYNC 0x0030 /* rising/falling edge on mask initiates sample */ -+#define WM9705_PDD(i) (i & 0x000f) /* pen detect comparator threshold */ -+ -+ -+/* WM9713 Bits */ -+#define WM9713_PDPOL 0x0400 /* Pen down polarity */ -+#define WM9713_POLL 0x0200 /* initiate a polling measurement */ -+#define WM9713_CTC 0x0100 /* enable continuous mode */ -+#define WM9713_ADCSEL_X 0x0002 /* X measurement */ -+#define WM9713_ADCSEL_Y 0x0004 /* Y measurement */ -+#define WM9713_ADCSEL_PRES 0x0008 /* Pressure measurement */ -+#define WM9713_COO 0x0001 /* enable coordinate mode */ -+#define WM9713_PDEN 0x0800 /* measure only when pen down */ -+#define WM9713_ADCSEL_MASK 0x00fe /* ADC selection mask */ -+#define WM9713_WAIT 0x0200 /* coordinate wait */ -+ -+/* AUX ADC ID's */ -+#define TS_COMP1 0x0 -+#define TS_COMP2 0x1 -+#define TS_BMON 0x2 -+#define TS_WIPER 0x3 -+ -+/* ID numbers */ -+#define WM97XX_ID1 0x574d -+#define WM9712_ID2 0x4c12 -+#define WM9705_ID2 0x4c05 -+#define WM9713_ID2 0x4c13 -+ -+/* Codec GPIO's */ -+#define WM97XX_MAX_GPIO 16 -+#define WM97XX_GPIO_1 (1 << 1) -+#define WM97XX_GPIO_2 (1 << 2) -+#define WM97XX_GPIO_3 (1 << 3) -+#define WM97XX_GPIO_4 (1 << 4) -+#define WM97XX_GPIO_5 (1 << 5) -+#define WM97XX_GPIO_6 (1 << 6) -+#define WM97XX_GPIO_7 (1 << 7) -+#define WM97XX_GPIO_8 (1 << 8) -+#define WM97XX_GPIO_9 (1 << 9) -+#define WM97XX_GPIO_10 (1 << 10) -+#define WM97XX_GPIO_11 (1 << 11) -+#define WM97XX_GPIO_12 (1 << 12) -+#define WM97XX_GPIO_13 (1 << 13) -+#define WM97XX_GPIO_14 (1 << 14) -+#define WM97XX_GPIO_15 (1 << 15) -+ -+ -+#define AC97_LINK_FRAME 21 /* time in uS for AC97 link frame */ -+ -+ -+/*---------------- Return codes from sample reading functions ---------------*/ -+ -+/* More data is available; call the sample gathering function again */ -+#define RC_AGAIN 0x00000001 -+/* The returned sample is valid */ -+#define RC_VALID 0x00000002 -+/* The pen is up (the first RC_VALID without RC_PENUP means pen is down) */ -+#define RC_PENUP 0x00000004 -+/* The pen is down (RC_VALID implies RC_PENDOWN, but sometimes it is helpful -+ to tell the handler that the pen is down but we don't know yet his coords, -+ so the handler should not sleep or wait for pendown irq) */ -+#define RC_PENDOWN 0x00000008 -+ -+/* The wm97xx driver provides a private API for writing platform-specific -+ * drivers. -+ */ -+ -+/* The structure used to return arch specific sampled data into */ -+struct wm97xx_data { -+ int x; -+ int y; -+ int p; -+}; -+ -+/* Codec GPIO status -+ */ -+typedef enum { -+ WM97XX_GPIO_HIGH, -+ WM97XX_GPIO_LOW -+} wm97xx_gpio_status_t; -+ -+/* Codec GPIO direction -+ */ -+typedef enum { -+ WM97XX_GPIO_IN, -+ WM97XX_GPIO_OUT -+} wm97xx_gpio_dir_t; -+ -+/* Codec GPIO polarity -+ */ -+typedef enum { -+ WM97XX_GPIO_POL_HIGH, -+ WM97XX_GPIO_POL_LOW -+} wm97xx_gpio_pol_t; -+ -+/* Codec GPIO sticky -+ */ -+typedef enum { -+ WM97XX_GPIO_STICKY, -+ WM97XX_GPIO_NOTSTICKY -+} wm97xx_gpio_sticky_t; -+ -+/* Codec GPIO wake -+ */ -+typedef enum { -+ WM97XX_GPIO_WAKE, -+ WM97XX_GPIO_NOWAKE -+} wm97xx_gpio_wake_t; -+ -+ -+/* -+ * Digitiser ioctl commands -+ */ -+#define WM97XX_DIG_START 0x1 -+#define WM97XX_DIG_STOP 0x2 -+#define WM97XX_PHY_INIT 0x3 -+#define WM97XX_AUX_PREPARE 0x4 -+#define WM97XX_DIG_RESTORE 0x5 -+ -+struct wm97xx; -+extern struct wm97xx_codec_drv wm97xx_codec; -+ -+/* -+ * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs -+ */ -+struct wm97xx_codec_drv { -+ u16 id; -+ char *name; -+ int (*poll_sample) (struct wm97xx *, int adcsel, int *sample); /* read 1 sample */ -+ int (*poll_touch) (struct wm97xx *, struct wm97xx_data *); /* read X,Y,[P] in poll */ -+ int (*digitiser_ioctl) (struct wm97xx *, int cmd); -+ int (*acc_enable) (struct wm97xx *, int enable); -+}; -+ -+ -+/* Machine specific and accelerated touch operations */ -+struct wm97xx_mach_ops { -+ -+ /* accelerated touch readback - coords are transmited on AC97 link */ -+ int acc_enabled; -+ void (*acc_pen_up) (struct wm97xx *); -+ int (*acc_pen_down) (struct wm97xx *); -+ int (*acc_startup) (struct wm97xx *); -+ void (*acc_shutdown) (struct wm97xx *); -+ -+ /* pre and post sample - can be used to minimise any analog noise */ -+ void (*pre_sample) (int); /* function to run before sampling */ -+ void (*post_sample) (int); /* function to run after sampling */ -+}; -+ -+struct wm97xx { -+ u16 dig[3], id, gpio[6], misc; /* Cached codec registers */ -+ u16 dig_save[3]; /* saved during aux reading */ -+ struct wm97xx_codec_drv *codec; /* attached codec driver*/ -+ struct input_dev* input_dev; /* touchscreen input device */ -+ struct snd_ac97 *ac97; /* ALSA codec access */ -+ struct device *dev; /* ALSA device */ -+ struct device *battery_dev; -+ struct device *touch_dev; -+ struct wm97xx_mach_ops *mach_ops; -+ struct mutex codec_mutex; -+ struct completion ts_init; -+ struct completion ts_exit; -+ struct task_struct *ts_task; -+ unsigned int pen_irq; /* Pen IRQ number in use */ -+ wait_queue_head_t pen_irq_wait; /* Pen IRQ wait queue */ -+ struct workqueue_struct *pen_irq_workq; -+ struct work_struct pen_event_work; -+ u16 acc_slot; /* AC97 slot used for acc touch data */ -+ u16 acc_rate; /* acc touch data rate */ -+ unsigned int ts_use_count; -+ unsigned pen_is_down:1; /* Pen is down */ -+ unsigned aux_waiting:1; /* aux measurement waiting */ -+ unsigned pen_probably_down:1; /* used in polling mode */ -+}; -+ -+/* Codec GPIO access (not supported on WM9705) -+ * This can be used to set/get codec GPIO and Virtual GPIO status. -+ */ -+wm97xx_gpio_status_t wm97xx_get_gpio(struct wm97xx *wm, u32 gpio); -+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, -+ wm97xx_gpio_status_t status); -+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, -+ wm97xx_gpio_dir_t dir, -+ wm97xx_gpio_pol_t pol, -+ wm97xx_gpio_sticky_t sticky, -+ wm97xx_gpio_wake_t wake); -+ -+/* codec AC97 IO access */ -+int wm97xx_reg_read(struct wm97xx *wm, u16 reg); -+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val); -+ -+/* aux adc readback */ -+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel); -+ -+/* machine ops */ -+int wm97xx_register_mach_ops(struct wm97xx *, struct wm97xx_mach_ops *); -+void wm97xx_unregister_mach_ops(struct wm97xx *); -+ -+extern struct bus_type wm97xx_bus_type; -+#endif -diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig -index a83e229..89b5730 100644 ---- a/sound/soc/pxa/Kconfig -+++ b/sound/soc/pxa/Kconfig -@@ -53,3 +53,12 @@ config SND_PXA2XX_SOC_TOSA - help - Say Y if you want to add support for SoC audio on Sharp - Zaurus SL-C6000x models (Tosa). -+ -+config SND_PXA2XX_SOC_EM_X270 -+ tristate "SoC Audio support for CompuLab EM-x270" -+ depends on SND_PXA2XX_SOC && MACH_EM_X270 -+ select SND_PXA2XX_SOC_AC97 -+ select SND_SOC_WM9712 -+ help -+ Say Y if you want to add support for SoC audio on -+ CompuLab EM-x270. -diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile -index 78e0d6b..32375ac 100644 ---- a/sound/soc/pxa/Makefile -+++ b/sound/soc/pxa/Makefile -@@ -12,9 +12,11 @@ snd-soc-corgi-objs := corgi.o - snd-soc-poodle-objs := poodle.o - snd-soc-tosa-objs := tosa.o - snd-soc-spitz-objs := spitz.o -+snd-soc-em-x270-objs := em-x270.o - - obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o - obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o - obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o - obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o -+obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o - -diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c -new file mode 100644 -index 0000000..9e891d0 ---- /dev/null -+++ b/sound/soc/pxa/em-x270.c -@@ -0,0 +1,137 @@ -+/* -+ * em-x270.c -- SoC audio for EM-X270 -+ * -+ * Copyright 2007 CompuLab, Ltd. -+ * -+ * Author: Mike Rapoport -+ * -+ * Copied from tosa.c: -+ * Copyright 2005 Wolfson Microelectronics PLC. -+ * Copyright 2005 Openedhand Ltd. -+ * -+ * Authors: Liam Girdwood -+ * Richard Purdie -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "../codecs/wm9712.h" -+#include "pxa2xx-pcm.h" -+#include "pxa2xx-ac97.h" -+ -+static struct snd_soc_machine em_x270; -+ -+#define EM_X270_HP 0 -+#define EM_X270_MIC_INT 1 -+#define EM_X270_HEADSET 2 -+#define EM_X270_HP_OFF 3 -+#define EM_X270_SPK_ON 0 -+#define EM_X270_SPK_OFF 1 -+ -+ -+static struct snd_soc_ops em_x270_ops = { -+}; -+ -+static const struct snd_kcontrol_new em_x270_controls[] = { -+}; -+ -+static int em_x270_ac97_init(struct snd_soc_codec *codec) -+{ -+ int i, err; -+ -+ /* add em_x270 specific controls */ -+ for (i = 0; i < ARRAY_SIZE(em_x270_controls); i++) { -+ err = snd_ctl_add(codec->card, -+ snd_soc_cnew(&em_x270_controls[i],codec, NULL)); -+ if (err < 0) -+ return err; -+ } -+ -+ snd_soc_dapm_sync_endpoints(codec); -+ return 0; -+} -+ -+static struct snd_soc_dai_link em_x270_dai[] = { -+ { -+ .name = "AC97", -+ .stream_name = "AC97 HiFi", -+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], -+ .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], -+ .init = em_x270_ac97_init, -+ .ops = &em_x270_ops, -+ }, -+ { -+ .name = "AC97 Aux", -+ .stream_name = "AC97 Aux", -+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], -+ .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], -+ .ops = &em_x270_ops, -+ }, -+}; -+ -+static struct snd_soc_machine em_x270 = { -+ .name = "EM-X270", -+ .dai_link = em_x270_dai, -+ .num_links = ARRAY_SIZE(em_x270_dai), -+}; -+ -+static struct snd_soc_device em_x270_snd_devdata = { -+ .machine = &em_x270, -+ .platform = &pxa2xx_soc_platform, -+ .codec_dev = &soc_codec_dev_wm9712, -+}; -+ -+static struct platform_device *em_x270_snd_device; -+ -+static int __init em_x270_init(void) -+{ -+ int ret; -+ -+ if (!machine_is_em_x270()) -+ return -ENODEV; -+ -+ em_x270_snd_device = platform_device_alloc("soc-audio", -1); -+ if (!em_x270_snd_device) -+ return -ENOMEM; -+ -+ platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata); -+ em_x270_snd_devdata.dev = &em_x270_snd_device->dev; -+ ret = platform_device_add(em_x270_snd_device); -+ -+ if (ret) -+ platform_device_put(em_x270_snd_device); -+ -+ return ret; -+} -+ -+static void __exit em_x270_exit(void) -+{ -+ platform_device_unregister(em_x270_snd_device); -+} -+ -+module_init(em_x270_init); -+module_exit(em_x270_exit); -+ -+/* Module information */ -+MODULE_AUTHOR("Mike Rapoport"); -+MODULE_DESCRIPTION("ALSA SoC EM-X270"); -+MODULE_LICENSE("GPL"); -- cgit v1.2.3-54-g00ecf