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 (charg