diff options
author | Rob Herring <r.herring@freescale.com> | 2009-05-05 14:25:13 -0500 |
---|---|---|
committer | Rob Herring <r.herring@freescale.com> | 2009-05-05 18:17:51 -0500 |
commit | c096fc73812248072b8c62a071dfe565fa359983 (patch) | |
tree | 1b67d3591a8e9d009ca5fcf37d8de654f9cdf33f | |
parent | 4e9da5716840fa8458211b98191ccdebcec74a67 (diff) |
ENGR00112199 Import EA 3780 release 4
This is from EA P4 release with the following changes:
Ported to 2.6.28
UBI support is stock 2.6.28.
USB is not integrated
Regulator code is not yet ported.
Removed 3700 specific files
Fix copyrights
Signed-off-by: Rob Herring <r.herring@freescale.com>
230 files changed, 58047 insertions, 17 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 45e154332d8b..f9079d634bf5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -550,6 +550,16 @@ config ARCH_MSM interface to the ARM9 modem processor which runs the baseband stack and controls some vital subsystems (clock and power control, etc). +config ARCH_STMP3XXX + bool "SigmaTel STMP3xxx" + select ISA + select GENERIC_TIME + select GENERIC_CLOCKEVENTS + select GENERIC_GPIO + select USB_ARCH_HAS_EHCI + help + Support for systems based on the SigmaTel 3xxx CPUs. + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -628,6 +638,8 @@ source "arch/arm/mach-ks8695/Kconfig" source "arch/arm/mach-msm/Kconfig" +source "arch/arm/mach-stmp3xxx/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool @@ -1061,7 +1073,7 @@ endmenu menu "CPU Power Management" -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA || ARCH_MXC) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA || ARCH_MXC || ARCH_STMP3XXX) source "drivers/cpufreq/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 2d56f7fa8007..d970b620aed5 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -145,6 +145,9 @@ endif machine-$(CONFIG_ARCH_MX27) := mx27 machine-$(CONFIG_ARCH_MX25) := mx25 machine-$(CONFIG_ARCH_MX21) := mx21 + machine-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx + incdir-$(CONFIG_ARCH_STMP37XX) := stmp37xx + incdir-$(CONFIG_ARCH_STMP378X) := stmp378x machine-$(CONFIG_ARCH_ORION5X) := orion5x plat-$(CONFIG_PLAT_ORION) := orion machine-$(CONFIG_ARCH_MSM) := msm diff --git a/arch/arm/configs/imx233_defconfig b/arch/arm/configs/imx233_defconfig new file mode 100644 index 000000000000..0704f2c3902d --- /dev/null +++ b/arch/arm/configs/imx233_defconfig @@ -0,0 +1,1468 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.28 +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_MMU=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +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 +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_AS is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_CLASSIC_RCU=y +CONFIG_FREEZER=y + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set +CONFIG_ARCH_STMP3XXX=y + +# +# Boot options +# + +# +# Power management +# + +# +# SigmaTel STMP3xxx implementations +# +# CONFIG_ARCH_STMP37XX is not set +CONFIG_ARCH_STMP378X=y +# CONFIG_MACH_STMP37XX is not set +CONFIG_MACH_STMP378X=y +CONFIG_FB_STMP37XX_LMS350=y +CONFIG_FB_STMP37XX_LMS430=y +CONFIG_FB_STMP378X_TVENC=y +CONFIG_STMP3XXX_UNIQUE_ID=y +CONFIG_STMP3XXX_UNIQUE_ID_OTP=y +CONFIG_STMP378X_RAM_FREQ_SCALING=y +# CONFIG_STMP378X_RAM_MDDR is not set +CONFIG_STMP378X_RAM_DDR=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_NOIFAR=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +# CONFIG_OUTER_CACHE is not set + +# +# Bus support +# +CONFIG_ISA=y +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyAM0,115200 root=/dev/mmcblk0p2 rootwait lcd_panel=lms350" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +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 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set + +# +# Classification +# +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_PHONET is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_OLD_REGULATORY=y +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_MAC80211 is not set +CONFIG_IEEE80211=y +# CONFIG_IEEE80211_DEBUG is not set +# CONFIG_IEEE80211_CRYPT_WEP is not set +# CONFIG_IEEE80211_CRYPT_CCMP is not set +# CONFIG_IEEE80211_CRYPT_TKIP is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +CONFIG_MTD_NAND_GPMI_LBA=m +CONFIG_MTD_NAND_GPMI=m +CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES=y +CONFIG_MTD_NAND_GPMI_BCH=y +CONFIG_MTD_NAND_GPMI_TA1=y +CONFIG_MTD_NAND_GPMI_TA3=y +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ONENAND is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=128 +CONFIG_MTD_UBI_BEB_RESERVE=2 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +# CONFIG_PNP is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MISC_DEVICES is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# 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=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_DH is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# 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_VETH is not set +# CONFIG_ARCNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_AX88796 is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +CONFIG_ENC28J60=y +# CONFIG_ENC28J60_WRITEVERIFY is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_NET_PCI is not set +# CONFIG_B44 is not set +# CONFIG_CS89x0 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_TR is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_IWLWIFI_LEDS is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +CONFIG_INPUT_POLLDEV=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=320 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_GPIO is not set +CONFIG_KEYBOARD_STMP3XXX=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# 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_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +CONFIG_TOUCHSCREEN_STMP3XXX=y +# CONFIG_TOUCHSCREEN_HTCPEN is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_STMP3XXX_ROTDEC=y +# CONFIG_INPUT_UINPUT is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_STMP_DBG=y +CONFIG_SERIAL_STMP_DBG_CONSOLE=y +CONFIG_SERIAL_STMP_APP=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_NVRAM is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_STMP378X=m +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_SIMTEC is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_STUB is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_DS1682 is not set +# CONFIG_AT24 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 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_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 +# CONFIG_I2C_SLAVE is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_STMP3XXX=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=m +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_STMP3XXX=m +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_STMP3XXX_WATCHDOG=y + +# +# ISA-based Watchdog Cards +# +# CONFIG_PCWATCHDOG is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_WDT is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8350_I2C is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_VIDEO_ALLOW_V4L1 is not set +CONFIG_VIDEO_V4L1_COMPAT=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF_GEN=y +CONFIG_VIDEOBUF_DMA_CONTIG=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TDA9875 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# Video decoders +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_TVP5150 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_VIVI is not set +CONFIG_VIDEO_PXP=y +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_SOC_CAMERA is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +CONFIG_RADIO_STFM1000=m +CONFIG_RADIO_STFM1000_ALSA=m +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_STMP37XX=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CORGI is not set +CONFIG_BACKLIGHT_STMP37XX=y + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_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 +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +CONFIG_SND_SOC=y +CONFIG_SND_STMP3XXX_SOC=y +CONFIG_SND_STMP3XXX_SOC_DAI=y +CONFIG_SND_STMP3XXX_SOC_SPDIF_DAI=y +CONFIG_SND_STMP3XXX_SOC_STMP3780_DEVB=y +CONFIG_SND_STMP3XXX_SOC_STMP3780_DEVB_SPDIF=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_STMP378X_CODEC=y +CONFIG_SND_SOC_STMP3XXX_SPDIF=y +# CONFIG_SOUND_PRIME is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_IMX_ESDHCI_PIO_MODE is not set +CONFIG_MMC_STMP3XXX=y +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_NEW_LEDS=y +# CONFIG_LEDS_CLASS is not set + +# +# LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 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 +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_STMP3XXX=y +# CONFIG_DMADEVICES is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_REGISTER_V4 is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_FRAME_POINTER=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_HAVE_FUNCTION_TRACER=y + +# +# Tracers +# +# CONFIG_DYNAMIC_PRINTK_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_NETWORK is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0 +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CRYPTODEV=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=m +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_STMP3XXX_DCP=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF 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 +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/arm/mach-stmp3xxx/Kconfig b/arch/arm/mach-stmp3xxx/Kconfig new file mode 100644 index 000000000000..b1d4dd60ce47 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/Kconfig @@ -0,0 +1,84 @@ +if ARCH_STMP3XXX + +menu "SigmaTel STMP3xxx implementations" + +choice + prompt "Select STMP3xxx chip family" + +config ARCH_STMP37XX + bool "SigmaTel SMTP37xx" + ---help--- + STMP37xx refers to 3700 through 3769 chips + +config ARCH_STMP378X + bool "SigmaTel STMP378x" + ---help--- + STMP378x refers to 3780 through 3789 chips + +endchoice + +choice + prompt "Select STMP3xxx board type" + +config MACH_STMP37XX + depends on ARCH_STMP37XX + bool "SigmaTel STMP37xx development board" + +config MACH_STMP378X + depends on ARCH_STMP378X + bool "SigmaTel STMP378x development board" + +endchoice + +endmenu + +config FB_STMP37XX_HX8238A + depends on ARCH_STMP37XX + bool "HX8238A" + ---help--- + Use HX8238A dotclock LCD panel for STMP37XX + +config FB_STMP37XX_LMS350 + depends on ARCH_STMP378X + bool "LMS350" + ---help--- + Use LMS350 dotclock LCD panel for STMP378X + +config FB_STMP37XX_LMS430 + depends on ARCH_STMP378X + bool "LMS430" + ---help--- + Use LMS430 dotclock LCD panel for STMP378X + +config FB_STMP378X_TVENC + depends on ARCH_STMP378X + bool "TVENC" + ---help--- + Use TVOUT encoder for STMP378X + +config STMP3XXX_UNIQUE_ID + bool "Support for UniqueID on boot media" + default y + +config STMP3XXX_UNIQUE_ID_OTP + bool "UniqueID on OTP" + depends on STMP3XXX_UNIQUE_ID + default y + +config STMP378X_RAM_FREQ_SCALING + bool "RAM frequency scaling support" + depends on ARCH_STMP378X + default y + +choice + prompt "Select STMP378x RAM chip" + depends on STMP378X_RAM_FREQ_SCALING + +config STMP378X_RAM_MDDR + bool "mDDR SDRAM" +config STMP378X_RAM_DDR + bool "DDR SDRAM" + +endchoice + +endif diff --git a/arch/arm/mach-stmp3xxx/Makefile b/arch/arm/mach-stmp3xxx/Makefile new file mode 100644 index 000000000000..acbccb236492 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/Makefile @@ -0,0 +1,43 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. +obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o \ + gpio.o lradc.o devices.o gpmi.o spi.o mmc.o \ + power.o \ + persistent.o power-test.o + +# charging/current limitation testing +obj-m += power-test.o + +obj-$(CONFIG_ARCH_STMP378X) += dcp-bootstream.o + +# Chip family select +obj-$(CONFIG_ARCH_STMP37XX) += stmp37xx.o stmp37xx_lcdif.o +obj-$(CONFIG_ARCH_STMP378X) += stmp378x.o stmp378x_lcdif.o + +obj-$(CONFIG_MACH_STMP37XX) += stmp37xx_devb.o +obj-$(CONFIG_MACH_STMP378X) += stmp378x_devb.o stmp378x_i2c.o stmp378x_pwm_led.o + +# Power Management +obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o + +# LCD panels support +obj-$(CONFIG_FB_STMP37XX_HX8238A) += lcd_hx8238a.o +obj-$(CONFIG_FB_STMP37XX_LMS350) += lcd_lms350.o +obj-$(CONFIG_FB_STMP37XX_LMS430) += lcd_lms430.o + +# TVOUT support +obj-$(CONFIG_FB_STMP378X_TVENC) += tvenc.o + +obj-$(CONFIG_STMP3XXX_UNIQUE_ID) += unique-id.o +obj-$(CONFIG_STMP3XXX_UNIQUE_ID_OTP) += otp.o +obj-$(CONFIG_STMP3XXX_UNIQUE_ID_FILE) += unique-id-file.o + +obj-$(CONFIG_INPUT_STMP3XXX_ROTDEC) += stmp378x_devb_rotdec.o +obj-$(CONFIG_STMP378X_RAM_FREQ_SCALING) += emi.o + +# SPDIF transmitter +obj-$(CONFIG_SND_SOC_STMP3XXX_SPDIF) += spdif.o diff --git a/arch/arm/mach-stmp3xxx/Makefile.boot b/arch/arm/mach-stmp3xxx/Makefile.boot new file mode 100644 index 000000000000..1568ad404d59 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x40008000 +params_phys-y := 0x40000100 +initrd_phys-y := 0x40800000 diff --git a/arch/arm/mach-stmp3xxx/clock.c b/arch/arm/mach-stmp3xxx/clock.c new file mode 100644 index 000000000000..dd21105abbb7 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/clock.c @@ -0,0 +1,1358 @@ +/* + * Clock manipulation routines for Freescale STMP37XX/STMP378X + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <mach/cpu.h> +#include <mach/regs-clkctrl.h> + +#include "clock.h" + +static DEFINE_SPINLOCK(clocks_lock); + +static struct clk osc_24M; +static struct clk pll_clk; +static struct clk cpu_clk; +static struct clk hclk; + +static int std_propagate_rate(struct clk *); + +static inline int clk_is_busy(struct clk *clk) +{ + return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit); +} + +static int std_clk_enable(struct clk *clk) +{ + if (clk->enable_reg) { + u32 clk_reg = __raw_readl(clk->enable_reg); + pr_debug("%s: clock '%s'\n", __func__, clk->name); + if (clk->enable_negate) + clk_reg &= ~(1 << clk->enable_shift); + else + clk_reg |= (1 << clk->enable_shift); + __raw_writel(clk_reg, clk->enable_reg); + if (clk->enable_wait) + udelay(clk->enable_wait); + return 0; + } else + return -EINVAL; +} + +static int std_clk_disable(struct clk *clk) +{ + if (clk->enable_reg) { + u32 clk_reg = __raw_readl(clk->enable_reg); + pr_debug("%s: clock '%s'\n", __func__, clk->name); + if (clk->enable_negate) + clk_reg |= (1 << clk->enable_shift); + else + clk_reg &= ~(1 << clk->enable_shift); + __raw_writel(clk_reg, clk->enable_reg); + return 0; + } else + return -EINVAL; +} + +static int io_set_rate(struct clk *clk, u32 rate) +{ + u32 reg_frac, clkctrl_frac; + int i, ret = 0, mask = 0x1f; + + clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate; + + if (clkctrl_frac < 18 || clkctrl_frac > 35) { + ret = -EINVAL; + goto out; + } + + reg_frac = __raw_readl(clk->scale_reg); + reg_frac &= ~(mask << clk->scale_shift); + __raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift), + clk->scale_reg); + if (clk->busy_reg) { + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) + ret = -ETIMEDOUT; + else + ret = 0; + } +out: + return ret; +} + +static long io_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate * 18; + int mask = 0x1f; + + rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask; + pr_debug("rate now %ld\n", rate); + clk->rate = rate; + + return rate; +} + +static long per_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate; + long div; + const int mask = 0xff; + + pr_debug("%s: clock name %s\n", __func__, clk->name); + if (clk->enable_reg && + !(__raw_readl(clk->enable_reg) & clk->enable_shift)) + clk->rate = 0; + else { + div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask; + if (div) + rate /= div; + else + printk(KERN_WARNING "clock '%s' has divisor 0!\n", + clk->name); + clk->rate = rate; + } + + return 0; +} + +static int per_set_rate(struct clk *clk, u32 rate) +{ + int ret = -EINVAL; + int div = (clk->parent->rate + rate - 1) / rate; + u32 reg_frac; + const int mask = 0xff; + int try = 10; + int i = -1; + + if (div == 0 || div > mask) + goto out; + + reg_frac = __raw_readl(clk->scale_reg); + reg_frac &= ~(mask << clk->scale_shift); + + while (try--) { + __raw_writel(reg_frac | (div << clk->scale_shift), + clk->scale_reg); + + if (clk->busy_reg) { + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + } + if (i) + break; + } + + if (!i) + ret = -ETIMEDOUT; + else + ret = 0; + +out: + BUG_ON(ret != 0); + return ret; +} + +static long lcdif_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate; + long div; + const int mask = 0xff; + + pr_debug("%s: clock name %s\n", __func__, clk->name); + div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask; + if (div) { + rate /= div; + div = (HW_CLKCTRL_FRAC_RD() & BM_CLKCTRL_FRAC_PIXFRAC) >> + BP_CLKCTRL_FRAC_PIXFRAC; + rate /= div; + } else + printk(KERN_WARNING "clock '%s' has divisor 0!\n", clk->name); + clk->rate = rate; + + return 0; +} + +static int lcdif_set_rate(struct clk *clk, u32 rate) +{ + int ret = 0; + /* + * On 3700, we can get most timings exact by modifying ref_pix + * and the divider, but keeping the phase timings at 1 (2 + * phases per cycle). + * + * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz, + * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns. + * + * ns_cycle >= 2*18e3/(18*480) = 25/6 + * ns_cycle <= 2*35e3/(18*480) = 875/108 + * + * Multiply the ns_cycle by 'div' to lengthen it until it fits the + * bounds. This is the divider we'll use after ref_pix. + * + * 6 * ns_cycle >= 25 * div + * 108 * ns_cycle <= 875 * div + */ + u32 ns_cycle = 1000000 / rate; + u32 div, reg_val; + u32 lowest_result = (u32) -1; + u32 lowest_div = 0, lowest_fracdiv = 0; + + for (div = 1; div < 256; ++div) { + u32 fracdiv; + u32 ps_result; + int lower_bound = 6 * ns_cycle >= 25 * div; + int upper_bound = 108 * ns_cycle <= 875 * div; + if (!lower_bound) + break; + if (!upper_bound) + continue; + /* + * Found a matching div. Calculate fractional divider needed, + * rounded up. + */ + fracdiv = ((clk->parent->rate / 1000 * 18 / 2) * + ns_cycle + 1000 * div - 1) / + (1000 * div); + if (fracdiv < 18 || fracdiv > 35) { + ret = -EINVAL; + goto out; + } + /* Calculate the actual cycle time this results in */ + ps_result = 6250 * div * fracdiv / 27; + + /* Use the fastest result that doesn't break ns_cycle */ + if (ps_result <= lowest_result) { + lowest_result = ps_result; + lowest_div = div; + lowest_fracdiv = fracdiv; + } + } + + if (div >= 256 || lowest_result == (u32) -1) { + ret = -EINVAL; + goto out; + } + pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz " + "PIXCLK=%uMHz cycle=%u.%03uns\n", + lowest_fracdiv, lowest_div, + 480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div, + lowest_result / 1000, lowest_result % 1000); + + /* Program ref_pix phase fractional divider */ + HW_CLKCTRL_FRAC_WR((HW_CLKCTRL_FRAC_RD() & ~BM_CLKCTRL_FRAC_PIXFRAC) | + BF_CLKCTRL_FRAC_PIXFRAC(lowest_fracdiv)); + /* Ungate PFD */ + HW_CLKCTRL_FRAC_CLR(BM_CLKCTRL_FRAC_CLKGATEPIX); + + /* Program pix divider */ + reg_val = __raw_readl(clk->scale_reg); + reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE); + reg_val |= BF_CLKCTRL_PIX_DIV(lowest_div); + __raw_writel(reg_val, clk->scale_reg); + + /* Wait for divider update */ + if (clk->busy_reg) { + int i; + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) { + ret = -ETIMEDOUT; + goto out; + } + } + + /* Switch to ref_pix source */ + HW_CLKCTRL_CLKSEQ_CLR(BM_CLKCTRL_CLKSEQ_BYPASS_PIX); + +out: + return ret; +} + + +static int cpu_set_rate(struct clk *clk, u32 rate) +{ + if (rate < 24000) + return -EINVAL; + else if (rate == 24000) { + /* switch to the 24M source */ + clk_set_parent(clk, &osc_24M); + } else { + int i; + u32 clkctrl_cpu = 1; + u32 c = clkctrl_cpu; + u32 clkctrl_frac = 1; + u32 val; + for ( ; c < 0x40; c++) { + u32 f = (pll_clk.rate*18/c + rate/2) / rate; + int s1, s2; + + if (f < 18 || f > 35) + continue; + s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate; + s2 = pll_clk.rate*18/c/f - rate; + pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2); + if (abs(s1) > abs(s2)) { + clkctrl_cpu = c; + clkctrl_frac = f; + } + if (s2 == 0) + break; + }; + pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__, + clkctrl_cpu, clkctrl_frac); + if (c == 0x40) { + int d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - + rate; + if (abs(d) > 100 || + clkctrl_frac < 18 || clkctrl_frac > 35) + return -EINVAL; + } + + /* 4.6.2 */ + val = __raw_readl(clk->scale_reg); + val &= ~(0x3f << clk->scale_shift); + val |= clkctrl_frac; + clk_set_parent(clk, &osc_24M); + udelay(10); + __raw_writel(val, clk->scale_reg); + /* ungate */ + __raw_writel(1<<7, clk->scale_reg + 8); + /* write clkctrl_cpu */ + clk->saved_div = clkctrl_cpu; + HW_CLKCTRL_CPU_WR((HW_CLKCTRL_CPU_RD() & ~0x3f) | clkctrl_cpu); + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) { + printk(KERN_ERR "couldn't set up CPU divisor\n"); + return -ETIMEDOUT; + } + clk_set_parent(clk, &pll_clk); + clk->saved_div = 0; + udelay(10); + } + return 0; +} + +static long cpu_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate * 18; + + rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f; + rate /= HW_CLKCTRL_CPU_RD() & 0x3f; + rate = ((rate + 9) / 10) * 10; + clk->rate = rate; + + return rate; +} + +static long cpu_round_rate(struct clk *clk, u32 rate) +{ + unsigned long r = 0; + + if (rate <= 24000) + r = 24000; + else { + u32 clkctrl_cpu = 1; + u32 clkctrl_frac; + do { + clkctrl_frac = + (pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate; + if (clkctrl_frac > 35) + continue; + if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 == + rate / 10) + break; + } while (pll_clk.rate / 2 >= clkctrl_cpu++ * rate); + if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate) + clkctrl_cpu--; + pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__, + clkctrl_cpu, clkctrl_frac); + if (clkctrl_frac < 18) + clkctrl_frac = 18; + if (clkctrl_frac > 35) + clkctrl_frac = 35; + + r = pll_clk.rate * 18; + r /= clkctrl_frac; + r /= clkctrl_cpu; + r = 10 * ((r + 9) / 10); + } + return r; +} + +static int emi_set_rate(struct clk *clk, u32 rate) +{ + int ret = 0; + + if (rate < 24000) + return -EINVAL; + else { + int i; + struct stmp3xxx_emi_scaling_data sc_data; + int (*scale)(struct stmp3xxx_emi_scaling_data *) = + (void *)STMP3XXX_OCRAM_VA_BASE; + void *saved_ocram; + u32 clkctrl_emi; + u32 clkctrl_frac; + int div = 1; + /* + * We've been setting div to HW_CLKCTRL_CPU_RD() & 0x3f so far. + * TODO: verify 1 is still valid. + */ + + if (!stmp3xxx_ram_funcs_sz) + goto out; + + for (clkctrl_emi = div; clkctrl_emi < 0x3f; + clkctrl_emi += div) { + clkctrl_frac = + (pll_clk.rate * 18 + rate * clkctrl_emi / 2) / + (rate * clkctrl_emi); + if (clkctrl_frac >= 18 && clkctrl_frac <= 35) { + pr_debug("%s: clkctrl_frac found %d for %d\n", + __func__, clkctrl_frac, clkctrl_emi); + if (pll_clk.rate * 18 / + clkctrl_frac / clkctrl_emi / 100 == + rate / 100) + break; + } + } + if (clkctrl_emi >= 0x3f) + return -EINVAL; + pr_debug("%s: clkctrl_emi %d, clkctrl_frac %d\n", + __func__, clkctrl_emi, clkctrl_frac); + + saved_ocram = kmalloc(stmp3xxx_ram_funcs_sz, GFP_KERNEL); + if (!saved_ocram) + return -ENOMEM; + memcpy(saved_ocram, scale, stmp3xxx_ram_funcs_sz); + memcpy(scale, stmp3xxx_ram_freq_scale, stmp3xxx_ram_funcs_sz); + + sc_data.emi_div = clkctrl_emi; + sc_data.frac_div = clkctrl_frac; + sc_data.cur_freq = clk->rate / 1000; + sc_data.new_freq = rate / 1000; + + local_irq_disable(); + local_fiq_disable(); + + scale(&sc_data); + + local_fiq_enable(); + local_irq_enable(); + + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + memcpy(scale, saved_ocram, stmp3xxx_ram_funcs_sz); + kfree(saved_ocram); + + if (!i) { + printk(KERN_ERR "couldn't set up EMI divisor\n"); + ret = -ETIMEDOUT; + goto out; + } + } +out: + return ret; +} + +static long emi_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate * 18; + + rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f; + rate /= HW_CLKCTRL_EMI_RD() & 0x3f; + clk->rate = rate; + + return rate; +} + +static int clkseq_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -EINVAL; + int shift = 8; + + /* bypass? */ + if (parent == &osc_24M) + shift = 4; + + if (clk->bypass_reg) { + u32 hbus_mask = BM_CLKCTRL_HBUS_DIV_FRAC_EN | + BM_CLKCTRL_HBUS_DIV; + + if (clk == &cpu_clk && shift == 4) { + u32 hbus_val = HW_CLKCTRL_HBUS_RD(); + u32 cpu_val = HW_CLKCTRL_CPU_RD(); + hbus_val &= ~hbus_mask; + hbus_val |= 1; + clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU; + cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; + cpu_val |= 1; + __raw_writel(1 << clk->bypass_shift, + clk->bypass_reg + shift); + if (machine_is_stmp378x()) { + HW_CLKCTRL_HBUS_WR(hbus_val); + HW_CLKCTRL_CPU_WR(cpu_val); + hclk.rate = 0; + } + } else if (clk == &cpu_clk && shift == 8) { + u32 hbus_val = HW_CLKCTRL_HBUS_RD(); + u32 cpu_val = HW_CLKCTRL_CPU_RD(); + hbus_val &= ~hbus_mask; + hbus_val |= 2; + cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; + if (clk->saved_div) + cpu_val |= clk->saved_div; + else + cpu_val |= 2; + if (machine_is_stmp378x()) { + HW_CLKCTRL_HBUS_WR(hbus_val); + HW_CLKCTRL_CPU_WR(cpu_val); + hclk.rate = 0; + } + __raw_writel(1 << clk->bypass_shift, + clk->bypass_reg + shift); + } else + __raw_writel(1 << clk->bypass_shift, + clk->bypass_reg + shift); + + ret = 0; + } + + return ret; +} + +static int hbus_set_rate(struct clk *clk, u32 rate) +{ + u8 div = 0; + int is_frac = 0; + u32 clkctrl_hbus; + struct clk *parent = clk->parent; + + pr_debug("%s: rate %d, parent rate %d\n", __func__, rate, + parent->rate); + + if (rate > parent->rate) + return -EINVAL; + + if (((parent->rate + rate/2) / rate) * rate != parent->rate && + parent->rate / rate < 32) { + pr_debug("%s: switching to fractional mode\n", __func__); + is_frac = 1; + } + + if (is_frac) + div = (32 * rate + parent->rate / 2) / parent->rate; + else + div = (parent->rate + rate - 1) / rate; + pr_debug("%s: div calculated is %d\n", __func__, div); + if (!div || div > 0x1f) + return -EINVAL; + + clk_set_parent(&cpu_clk, &osc_24M); + udelay(10); + clkctrl_hbus = __raw_readl(clk->scale_reg); + clkctrl_hbus &= ~0x3f; + clkctrl_hbus |= div; + clkctrl_hbus |= (is_frac << 5); + + __raw_writel(clkctrl_hbus, clk->scale_reg); + if (clk->busy_reg) { + int i; + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) { + printk(KERN_ERR "couldn't set up CPU divisor\n"); + return -ETIMEDOUT; + } + } + clk_set_parent(&cpu_clk, &pll_clk); + __raw_writel(clkctrl_hbus, clk->scale_reg); + udelay(10); + return 0; +} + +static long hbus_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate; + + if (__raw_readl(clk->scale_reg) & 0x20) { + rate *= __raw_readl(clk->scale_reg) & 0x1f; + rate /= 32; + } else + rate /= __raw_readl(clk->scale_reg) & 0x1f; + clk->rate = rate; + + return rate; +} + +static int xbus_set_rate(struct clk *clk, u32 rate) +{ + u16 div = 0; + u32 clkctrl_xbus; + + pr_debug("%s: rate %d, parent rate %d\n", __func__, rate, + clk->parent->rate); + + div = (clk->parent->rate + rate - 1) / rate; + pr_debug("%s: div calculated is %d\n", __func__, div); + if (!div || div > 0x3ff) + return -EINVAL; + + clkctrl_xbus = __raw_readl(clk->scale_reg); + clkctrl_xbus &= ~0x3ff; + clkctrl_xbus |= div; + __raw_writel(clkctrl_xbus, clk->scale_reg); + if (clk->busy_reg) { + int i; + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) { + printk(KERN_ERR "couldn't set up xbus divisor\n"); + return -ETIMEDOUT; + } + } + return 0; +} + +static long xbus_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate; + + rate /= __raw_readl(clk->scale_reg) & 0x3ff; + clk->rate = rate; + + return rate; +} + + +static int etm_set_rate(struct clk *clk, u32 rate) +{ + u16 div = 0; + u32 clkctrl_etm; + + pr_debug("%s: rate %d, parent rate %d\n", __func__, rate, + clk->parent->rate); + + div = (clk->parent->rate + rate - 1) / rate; + pr_debug("%s: div calculated is %d\n", __func__, div); + if (!div || div > 0x3f) + return -EINVAL; + + clkctrl_etm = __raw_readl(clk->scale_reg); + clkctrl_etm &= ~0x3f; + clkctrl_etm |= div; + __raw_writel(clkctrl_etm, clk->scale_reg); + if (clk->busy_reg) { + int i; + for (i = 10000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) { + printk(KERN_ERR "couldn't set up ETM clock divisor\n"); + return -ETIMEDOUT; + } + } + return 0; +} + +static long etm_get_rate(struct clk *clk) +{ + long rate = clk->parent->rate; + rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f; + clk->rate = rate; + + return rate; +} + +/* List of on-chip clocks */ + +static struct clk osc_24M = { + .name = "osc_24M", + .flags = FIXED_RATE | ENABLED | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, + .rate = 24000, + .propagate_rate = std_propagate_rate, +}; + +static struct clk pll_clk = { + .name = "pll", + .parent = &osc_24M, + .enable_reg = HW_CLKCTRL_PLLCTRL0_ADDR, + .enable_shift = 16, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_wait = 10, + .flags = FIXED_RATE | ENABLED | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, + .rate = 480000, + .propagate_rate = std_propagate_rate, +}; + +static struct clk cpu_clk = { + .name = "cpu", + .parent = &pll_clk, + .get_rate = cpu_get_rate, + .set_rate = cpu_set_rate, + .round_rate = cpu_round_rate, + .scale_reg = HW_CLKCTRL_FRAC_ADDR, + .scale_shift = 0, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 7, + .busy_reg = HW_CLKCTRL_CPU_ADDR, + .busy_bit = 28, + .set_parent = clkseq_set_parent, + .flags = RATE_PROPAGATES | ENABLED | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, + .propagate_rate = std_propagate_rate, +}; + +static struct clk io_clk = { + .name = "io", + .parent = &pll_clk, + .enable_reg = HW_CLKCTRL_FRAC_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .get_rate = io_get_rate, + .set_rate = io_set_rate, + .scale_reg = HW_CLKCTRL_FRAC_ADDR, + .scale_shift = 24, + .flags = RATE_PROPAGATES | ENABLED | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, + .propagate_rate = std_propagate_rate, +}; + +static struct clk hclk = { + .name = "hclk", + .parent = &cpu_clk, + .get_rate = hbus_get_rate, + .set_rate = hbus_set_rate, + .scale_reg = HW_CLKCTRL_HBUS_ADDR, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 7, + .busy_reg = HW_CLKCTRL_HBUS_ADDR, + .busy_bit = 29, + .flags = RATE_PROPAGATES | ENABLED | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, + .propagate_rate = std_propagate_rate, +}; + +static struct clk xclk = { + .name = "xclk", + .parent = &osc_24M, + .get_rate = xbus_get_rate, + .set_rate = xbus_set_rate, + .scale_reg = HW_CLKCTRL_XBUS_ADDR, + .busy_reg = HW_CLKCTRL_XBUS_ADDR, + .busy_bit = 31, + .flags = RATE_PROPAGATES | ENABLED | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, + .propagate_rate = std_propagate_rate, +}; + +static struct clk uart_clk = { + .name = "uart", + .parent = &xclk, + .enable_reg = HW_CLKCTRL_XTAL_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = ENABLED | PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk audio_clk = { + .name = "audio", + .parent = &xclk, + .enable_reg = HW_CLKCTRL_XTAL_ADDR, + .enable_shift = 30, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk pwm_clk = { + .name = "pwm", + .parent = &xclk, + .enable_reg = HW_CLKCTRL_XTAL_ADDR, + .enable_shift = 29, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk dri_clk = { + .name = "dri", + .parent = &xclk, + .enable_reg = HW_CLKCTRL_XTAL_ADDR, + .enable_shift = 28, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk digctl_clk = { + .name = "digctl", + .parent = &xclk, /* XXX? */ + .enable_reg = HW_CLKCTRL_XTAL_ADDR, + .enable_shift = 27, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk timer_clk = { + .name = "timer", + .parent = &xclk, /* XXX? */ + .enable_reg = HW_CLKCTRL_XTAL_ADDR, + .enable_shift = 26, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = ENABLED | PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk lcdif_clk = { + .name = "lcdif", + .parent = &pll_clk, + .get_rate = lcdif_get_rate, + .set_rate = lcdif_set_rate, + .scale_reg = HW_CLKCTRL_PIX_ADDR, + .busy_reg = HW_CLKCTRL_PIX_ADDR, + .busy_bit = 29, + .enable_reg = HW_CLKCTRL_PIX_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 1, + .set_parent = clkseq_set_parent, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X | + NEEDS_SET_PARENT, +}; + +static struct clk ssp_clk = { + .name = "ssp", + .parent = &io_clk, + .get_rate = per_get_rate, + .set_rate = per_set_rate, + .scale_reg = HW_CLKCTRL_SSP_ADDR, + .busy_reg = HW_CLKCTRL_SSP_ADDR, + .busy_bit = 29, + .enable_reg = HW_CLKCTRL_SSP_ADDR, + .enable_shift = 31, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 5, + .set_parent = clkseq_set_parent, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = NEEDS_SET_PARENT | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk gpmi_clk = { + .name = "gpmi", + .parent = &io_clk, + .get_rate = per_get_rate, + .set_rate = per_set_rate, + .scale_reg = HW_CLKCTRL_GPMI_ADDR, + .busy_reg = HW_CLKCTRL_GPMI_ADDR, + .busy_bit = 29, + .enable_reg = HW_CLKCTRL_GPMI_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 4, + .set_parent = clkseq_set_parent, + .flags = NEEDS_SET_PARENT | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk spdif_clk = { + .name = "spdif", + .parent = &pll_clk, + .enable_reg = HW_CLKCTRL_SPDIF_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk emi_clk = { + .name = "emi", + .parent = &pll_clk, + .enable_reg = HW_CLKCTRL_EMI_ADDR, + .enable_shift = 31, + .enable_negate = 1, + .scale_reg = HW_CLKCTRL_FRAC_ADDR, + .scale_shift = 8, + .get_rate = emi_get_rate, + .set_rate = emi_set_rate, + .busy_reg = HW_CLKCTRL_EMI_ADDR, + .busy_bit = 28, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 6, + .set_parent = clkseq_set_parent, + .flags = ENABLED | PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk ir_clk = { + .name = "ir", + .parent = &io_clk, + .enable_reg = HW_CLKCTRL_IR_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 3, + .set_parent = clkseq_set_parent, + .flags = NEEDS_SET_PARENT | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk saif_clk = { + .name = "saif", + .parent = &pll_clk, + .get_rate = per_get_rate, + .set_rate = per_set_rate, + .scale_reg = HW_CLKCTRL_SAIF_ADDR, + .busy_reg = HW_CLKCTRL_SAIF_ADDR, + .busy_bit = 29, + .enable_reg = HW_CLKCTRL_SAIF_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 0, + .set_parent = clkseq_set_parent, + .flags = NEEDS_SET_PARENT | + PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk usb_clk = { + .name = "usb", + .parent = &pll_clk, + .enable_reg = HW_CLKCTRL_PLLCTRL0_ADDR, + .enable_shift = 18, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .flags = PRESENT_ON_STMP37XX | PRESENT_ON_STMP378X, +}; + +static struct clk vid_clk = { + .name = "ref_vid", + .parent = &osc_24M, +#ifdef CONFIG_MACH_STMP378X + .enable_reg = HW_CLKCTRL_FRAC1_ADDR, + .enable_shift = 31, + .enable_negate = 1, +#endif + .enable = std_clk_enable, + .disable = std_clk_disable, + .rate = 432000, + .flags = FIXED_RATE | PRESENT_ON_STMP378X, +}; + +static struct clk clk_tv108M_ng = { + .name = "tv108M_ng", + .parent = &vid_clk, +#ifdef CONFIG_MACH_STMP378X + .enable_reg = HW_CLKCTRL_TV_ADDR, + .enable_shift = 31, + .enable_negate = 1, +#endif + .enable = std_clk_enable, + .disable = std_clk_disable, + .rate = 108000, + .flags = FIXED_RATE | PRESENT_ON_STMP378X, +}; + +static struct clk clk_tv54M = { + .name = "tv54M", + .parent = &vid_clk, +#ifdef CONFIG_MACH_STMP378X + .enable_reg = HW_CLKCTRL_TV_ADDR, + .enable_shift = 30, + .enable_negate = 1, +#endif + .enable = std_clk_enable, + .disable = std_clk_disable, + .rate = 54000, + .flags = FIXED_RATE | PRESENT_ON_STMP378X, +}; + +static struct clk clk_tv27M = { + .name = "tv27M", + .parent = &vid_clk, +#ifdef CONFIG_MACH_STMP378X + .enable_reg = HW_CLKCTRL_TV_ADDR, + .enable_shift = 30, + .enable_negate = 1, +#endif + .enable = std_clk_enable, + .disable = std_clk_disable, + .rate = 27000, + .flags = FIXED_RATE | PRESENT_ON_STMP378X, +}; + +static struct clk clk_tvenc_fifo = { + .name = "tvenc_fifo", + .parent = &vid_clk, + .flags = PRESENT_ON_STMP378X, +}; + +static struct clk clk_etm = { + .name = "etm", + .parent = &pll_clk, +#ifdef CONFIG_MACH_STMP378X + .enable_reg = HW_CLKCTRL_ETM_ADDR, + .enable_shift = 31, + .enable = std_clk_enable, + .disable = std_clk_disable, + .enable_negate = 1, + .scale_reg = HW_CLKCTRL_ETM_ADDR, + .scale_shift = 0, + .get_rate = etm_get_rate, + .set_rate = etm_set_rate, + .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR, + .bypass_shift = 8, + .busy_reg = HW_CLKCTRL_ETM_ADDR, + .busy_bit = 29, +#endif + .set_parent = clkseq_set_parent, + .flags = PRESENT_ON_STMP378X, +}; + + +/* list of all the clocks */ +static struct clk *onchip_clks[] = { + &osc_24M, + &pll_clk, + &cpu_clk, + &hclk, + &xclk, + &io_clk, + &uart_clk, + &audio_clk, + &pwm_clk, + &dri_clk, + &digctl_clk, + &timer_clk, + &lcdif_clk, + &ssp_clk, + &gpmi_clk, + &spdif_clk, + &emi_clk, + &ir_clk, + &saif_clk, + &usb_clk, + &vid_clk, + &clk_tv108M_ng, + &clk_tv54M, + &clk_tv27M, + &clk_etm, +}; + +static int std_propagate_rate(struct clk *clk) +{ + struct clk **clkp = onchip_clks; + + for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); + clkp++) { + if (!((*clkp)->flags & PRESENT_ON_STMP37XX && + cpu_is_stmp37xx()) && + !((*clkp)->flags & PRESENT_ON_STMP378X && + cpu_is_stmp378x())) + continue; + + if ((*clkp)->parent == clk && (*clkp)->get_rate) { + ((*clkp)->get_rate)(*clkp); + if ((*clkp)->flags & RATE_PROPAGATES) + ((*clkp)->propagate_rate)(*clkp); + } + } + + return 0; +} + +/* Exported API */ +unsigned long clk_get_rate(struct clk *clk) +{ + if (IS_ERR(clk)) + return 0; + + if (clk->rate != 0) + return clk->rate; + + if (clk->get_rate != NULL) + return clk->get_rate(clk); + + return clk->parent ? clk->parent->rate : 0; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (!IS_ERR(clk) && clk->round_rate) + return clk->round_rate(clk, rate); + + return 0; +} +EXPORT_SYMBOL(clk_round_rate); + +static inline int close_enough(long rate1, long rate2) +{ + return rate1 && !((rate2 - rate1) * 1000 / rate1); +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + + pr_debug("%s: clock %s rate %ld:%ld\n", __func__, clk->name, + (unsigned long)clk->rate, rate); + if (clk->flags & FIXED_RATE || !clk->set_rate) + goto out; + else if (!close_enough(clk->rate, rate)) { + ret = clk->set_rate(clk, rate); + if (ret < 0) { + printk(KERN_ERR "couldn't set rate for clock '%s': " + "error %d\n", clk->name, ret); + goto out; + } + clk->rate = rate; + if (clk->flags & RATE_PROPAGATES) + clk->propagate_rate(clk); + } else + ret = 0; + +out: + return ret; +} +EXPORT_SYMBOL(clk_set_rate); + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk **p; + struct clk *clk = ERR_PTR(-ENOENT); + int idno; + unsigned long clocks_flags; + + if (dev == NULL || dev->bus != &platform_bus_type) + idno = -1; + else + idno = to_platform_device(dev)->id; + + spin_lock_irqsave(&clocks_lock, clocks_flags); + for (p = onchip_clks; p < onchip_clks + ARRAY_SIZE(onchip_clks); p++) { + if (!((*p)->flags & PRESENT_ON_STMP37XX && + cpu_is_stmp37xx()) && + !((*p)->flags & PRESENT_ON_STMP378X && + cpu_is_stmp378x())) + continue; + + if (strcmp(id, (*p)->name) == 0 && + try_module_get((*p)->owner)) { + clk = *p; + break; + } + } + spin_unlock_irqrestore(&clocks_lock, clocks_flags); + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + if (clk->owner) + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + unsigned long clocks_flags; + + if (IS_ERR(clk) || clk == NULL) + return -EINVAL; + pr_debug("%s: clock '%s'\n", __func__, clk->name); + + if (clk->parent) + clk_enable(clk->parent); + + spin_lock_irqsave(&clocks_lock, clocks_flags); + + clk->usage++; + pr_debug("clock '%s': use count increased to %d\n", + clk->name, clk->usage); + if (clk->enable) + (clk->enable)(clk); + + spin_unlock_irqrestore(&clocks_lock, clocks_flags); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void local_clk_disable(struct clk *clk) +{ + unsigned long clocks_flags; + + if (IS_ERR(clk) || clk == NULL) + return; + + spin_lock_irqsave(&clocks_lock, clocks_flags); + + if (clk->usage == 0 && clk->disable) { + pr_debug("%s: disabling clock '%s'\n", __func__, clk->name); + (clk->disable)(clk); + } + + spin_unlock_irqrestore(&clocks_lock, clocks_flags); +} + +void clk_disable(struct clk *clk) +{ + unsigned long clocks_flags; + + if (IS_ERR(clk) || clk == NULL) + return; + pr_debug("%s: clock '%s'\n", __func__, clk->name); + + spin_lock_irqsave(&clocks_lock, clocks_flags); + + if ((--clk->usage) == 0 && clk->disable) + (clk->disable)(clk); + pr_debug("clock '%s': use count decreased to %d\n", + clk->name, clk->usage); + + spin_unlock_irqrestore(&clocks_lock, clocks_flags); + if (clk->parent) + clk_disable(clk->parent); +} +EXPORT_SYMBOL(clk_disable); + +/* Some additional API */ +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -ENODEV; + unsigned long clocks_flags; + + if (!clk->set_parent) + goto out; + + spin_lock_irqsave(&clocks_lock, clocks_flags); + + if (clk->set_parent) + ret = clk->set_parent(clk, parent); + if (!ret) { + pr_debug("%s: '%s': parent usage %d, clk->parent usage %d, " + "clk usage %d\n", __func__, clk->name, + parent->usage, clk->parent->usage, clk->usage); + if (parent->usage == 0 && parent->disable) + (parent->disable)(parent); + parent->usage += clk->usage; + clk->parent->usage -= clk->usage; + if (clk->parent->usage == 0 && clk->parent->disable) + (clk->parent->disable)(clk->parent); + clk->parent = parent; + } + spin_unlock_irqrestore(&clocks_lock, clocks_flags); + +out: + return ret; +} +EXPORT_SYMBOL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +static int __init clk_init(void) +{ + struct clk **clkp; + + spin_lock_init(&clocks_lock); + pr_debug("%s!\n", __func__); + for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks); + clkp++) { + if (!((*clkp)->flags & PRESENT_ON_STMP37XX && + cpu_is_stmp37xx()) && + !((*clkp)->flags & PRESENT_ON_STMP378X && + cpu_is_stmp378x())) + continue; + + (*clkp)->owner = THIS_MODULE; + if ((*clkp)->flags & ENABLED) + clk_enable(*clkp); + else + local_clk_disable(*clkp); + if (((*clkp)->flags & NEEDS_INITIALIZATION) && + (*clkp)->set_rate) + (*clkp)->set_rate((*clkp), (*clkp)->rate); + if (!((*clkp)->flags & FIXED_RATE) && ((*clkp)->get_rate)) + (*clkp)->get_rate(*clkp); + if (((*clkp)->flags & FIXED_RATE) && + ((*clkp)->flags & RATE_PROPAGATES)) + (*clkp)->propagate_rate(*clkp); + if ((*clkp)->flags & NEEDS_SET_PARENT) + (*clkp)->set_parent(*clkp, (*clkp)->parent); + pr_debug("%s: clock %s, rate %d\n", + __func__, (*clkp)->name, (*clkp)->rate); + } + + return 0; +} + +arch_initcall(clk_init); diff --git a/arch/arm/mach-stmp3xxx/clock.h b/arch/arm/mach-stmp3xxx/clock.h new file mode 100644 index 000000000000..08fc733357b4 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/clock.h @@ -0,0 +1,86 @@ +/* + * Clock control driver for Freescale STMP37XX/STMP378X - internal header file + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ARCH_ARM_STMX3XXX_CLOCK_H__ +#define __ARCH_ARM_STMX3XXX_CLOCK_H__ + +#ifndef __ASSEMBLER__ +#include <linux/list.h> + +struct clk { + struct list_head node; + struct module *owner; + const char *name; + struct clk *parent; + u32 rate; + s8 usage; + u32 flags; + u32 scale_reg; + u8 scale_shift; + u8 enable_shift; + u32 enable_reg; + int enable_wait; + int enable_negate; + u8 bypass_shift; + u32 bypass_reg; + u8 busy_bit; + u32 busy_reg; + u32 saved_div; + int (*enable) (struct clk *); + int (*disable) (struct clk *); + long (*get_rate) (struct clk *); + long (*round_rate) (struct clk *, u32); + int (*set_rate) (struct clk *, u32); + int (*set_parent) (struct clk *, struct clk *); + int (*propagate_rate) (struct clk *); +}; + +struct stmp3xxx_emi_scaling_data { + u32 emi_div; + u32 frac_div; + u32 cur_freq; + u32 new_freq; +}; + +#ifdef CONFIG_STMP378X_RAM_FREQ_SCALING +extern void stmp3xxx_ram_freq_scale(struct stmp3xxx_emi_scaling_data *); +extern u32 stmp3xxx_ram_funcs_sz; +#else +static inline void stmp3xxx_ram_freq_scale(struct stmp3xxx_emi_scaling_data *p) +{ +} +static u32 stmp3xxx_ram_funcs_sz; +#endif + +#endif /* __ASSEMBLER__ */ + +/* Flags */ +#define RATE_PROPAGATES (1<<0) +#define NEEDS_INITIALIZATION (1<<1) +#define PARENT_SET_RATE (1<<2) +#define FIXED_RATE (1<<3) +#define ENABLED (1<<4) +#define NEEDS_SET_PARENT (1<<5) +#define PRESENT_ON_STMP37XX (1<<8) +#define PRESENT_ON_STMP378X (1<<9) + +#define SCALING_DATA_EMI_DIV_OFFSET 0 +#define SCALING_DATA_FRAC_DIV_OFFSET 4 +#define SCALING_DATA_CUR_FREQ_OFFSET 8 +#define SCALING_DATA_NEW_FREQ_OFFSET 12 + +#endif diff --git a/arch/arm/mach-stmp3xxx/common.h b/arch/arm/mach-stmp3xxx/common.h new file mode 100644 index 000000000000..1d662dbc5376 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/common.h @@ -0,0 +1,65 @@ +/* + * Freescale STMP37XX/STMP378X internal functions and data declarations + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MACH_STMP3XXX_COMMON_H +#define __ASM_ARCH_MACH_STMP3XXX_COMMON_H + +#include <linux/irq.h> +#include <asm/mach/time.h> +#include "pinmux.h" + +extern struct sys_timer stmp3xxx_timer; +int stmp3xxx_add_devices(void); +void stmp3xxx_init_irq(struct irq_chip *chip1, + struct irq_chip *chip2, + int (*is2)(int)); +void stmp3xxx_init(void); +void stmp3xxx_set_mmc_data(struct device *dev); + +void stmp37xx_map_io(void); +void stmp37xx_init_irq(void); +int stmp37xx_add_devices(void); + +void stmp378x_map_io(void); +void stmp378x_init_irq(void); +void stmp378x_set_mmc_data(struct device *dev); + +extern struct pin_group i2c_pins; +extern struct pin_group appuart_pins[]; +extern struct pin_group dbguart_pins[]; +extern struct pin_group gpmi_pins; +extern struct pin_group stmp37xx_lcd_pins; +extern struct pin_group stmp378x_lcd_pins; +extern unsigned stmp37xx_lcd_spi_pins[]; +extern unsigned stmp378x_lcd_spi_pins[]; +extern struct pin_group usb_mux_pins; +extern struct pin_group spdif_pins; + +/* pm.c */ +extern int stmp_s2ram_alloc_sz; +void stmp37xx_cpu_suspend(void); +extern int stmp_standby_alloc_sz; +void stmp37xx_cpu_standby(void); +void stmp3xxx_suspend_timer(void); +void stmp3xxx_resume_timer(void); + +/* SPI */ +extern int stmp37xx_spi_enc_init(void *); +extern int stmp37xx_spi_enc_release(void *); + + +#endif /* __ASM_ARCH_MACH_STMP3XXXL_COMMON_H */ diff --git a/arch/arm/mach-stmp3xxx/core.c b/arch/arm/mach-stmp3xxx/core.c new file mode 100644 index 000000000000..3c92cd10e54c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/core.c @@ -0,0 +1,153 @@ +/* + * Freescale STMP37XX/STMP378X core routines + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/irq.h> + +#include <mach/hardware.h> +#include <asm/dma.h> +#include <asm/system.h> +#include <asm/mach/irq.h> +#include <asm/mach/time.h> +#include <mach/system.h> + +#include <mach/regs-clkctrl.h> +#include <mach/regs-rtc.h> + +#include "common.h" + +int __stmp3xxx_reset_block(u32 hwreg, int just_enable) +{ + u32 c; + int timeout; + + /* the process of software reset of IP block is done + in several steps: + + - clear SFTRST and wait for block is enabled; + - clear clock gating (CLKGATE bit); + - set the SFTRST again and wait for block is in reset; + - clear SFTRST and wait for reset completion. + */ + c = __raw_readl(hwreg); + c &= ~(1<<31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1<<31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR"%s(%x): timeout when enabling\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1<<30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + + if (!just_enable) { + c = __raw_readl(hwreg); + c |= (1<<31); /* now again set SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* poll until CLKGATE set */ + if (__raw_readl(hwreg) & (1<<30)) + break; + if (timeout <= 0) { + printk(KERN_ERR"%s(%x): timeout when resetting\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1<<31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1<<31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR"%s(%x): timeout when enabling " + "after reset\n", __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1<<30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + } + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1<<30)) == 0) + break; + + if (timeout <= 0) { + printk(KERN_ERR"%s(%x): timeout when unclockgating\n", + __func__, hwreg); + return -ETIME; + } + + return 0; +} +int stmp3xxx_reset_block(u32 hwreg, int just_enable) +{ + int try = 10; + int r; + + while (try--) { + r = __stmp3xxx_reset_block(hwreg, just_enable); + if (!r) + break; + pr_debug("%s: try %d failed\n", __func__, 10 - try); + } + return r; +} +EXPORT_SYMBOL(stmp3xxx_reset_block); + +static void stmp3xxx_machine_restart(char mode) +{ + arch_reset(mode); + printk(KERN_ERR"stmp3xxx_machine_restart failed -- System halted\n"); + for (;;) + continue; +} + +void __init stmp3xxx_init(void) +{ + /* Turn off auto-slow and other tricks */ + HW_CLKCTRL_HBUS_CLR(0x07f00000U); + + /* Re-route machine restart to our own handler */ + arm_pm_restart = stmp3xxx_machine_restart; + + stmp3xxx_dma_init(); + + HW_RTC_PERSISTENT0_SET(BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP | + BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP); +} diff --git a/arch/arm/mach-stmp3xxx/cpufreq.c b/arch/arm/mach-stmp3xxx/cpufreq.c new file mode 100644 index 000000000000..860807d6671e --- /dev/null +++ b/arch/arm/mach-stmp3xxx/cpufreq.c @@ -0,0 +1,406 @@ +/* + * CPU frequency scaling for Freescale STMP37XX/STMP378X + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +//#include <linux/regulator/regulator-drv.h> +#include <linux/notifier.h> + +#include <mach/hardware.h> +#include <linux/io.h> +#include <asm/system.h> +#include <mach/regulator.h> +#include <mach/power.h> +#include <mach/regs-digctl.h> + +#define VERY_HI_RATE 2000000000 + +static struct profile { + int cpu; + int ahb; + int emi; + int ss; + int vddd; + int vddd_bo; + int cur; +} profiles[] = { + { 64000, 64000, 48000, 3, 1000000, 925000, 150000 }, + { 261820, 130910, 130910, 0, 1225000, 1125000, 173000 }, + { 360000, 120000, 120000, 0, 1350000, 1250000, 200000 }, + { 392730, 130910, 130910, 0, 1400000, 1300000, 225000 }, + { 454740, 151580, 151580, 0, 1550000, 1450000, 355000 }, +}; + +static struct stmp3xxx_cpufreq { + struct cpufreq_policy policy; + struct regulator *regulator; + struct notifier_block nb; + struct notifier_block init_nb; + int freq_id; + int next_freq_id; + spinlock_t lock; +} cpufreq_bdata; + +static int reg_callback(struct notifier_block *, unsigned long, void *); +static int init_reg_callback(struct notifier_block *, unsigned long, void *); + +static inline void __set_new_policy(struct cpufreq_policy *policy) +{ + spin_lock(&cpufreq_bdata.lock); + + if (policy) + cpufreq_bdata.policy = *policy; + else + memzero(&cpufreq_bdata.policy, sizeof(cpufreq_bdata.policy)); + + if (cpufreq_bdata.regulator) + goto out; + + cpufreq_bdata.regulator = regulator_get(NULL, "cpufreq-1"); + if (!cpufreq_bdata.regulator || IS_ERR(cpufreq_bdata.regulator)) + cpufreq_bdata.regulator = NULL; + else { + regulator_set_mode(cpufreq_bdata.regulator, + REGULATOR_MODE_FAST); + if (cpufreq_bdata.regulator) + regulator_register_notifier( + cpufreq_bdata.regulator, + &cpufreq_bdata.nb); + } + +out: + spin_unlock(&cpufreq_bdata.lock); +} + +static int stmp3xxx_verify_speed(struct cpufreq_policy *policy) +{ + struct clk *cpu_clk; + + pr_debug("%s: entered, policy %p\n", __func__, policy); + + __set_new_policy(policy); + + if (policy->cpu) + return -EINVAL; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + cpu_clk = clk_get(NULL, "cpu"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + pr_debug("%s: policy->min %d, policy->max %d\n", + __func__, policy->min, policy->max); + policy->min = clk_round_rate(cpu_clk, policy->min); + policy->max = clk_round_rate(cpu_clk, policy->max); + pr_debug("%s: after rounding rate: policy->min %d, policy->max %d\n", + __func__, policy->min, policy->max); + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + clk_put(cpu_clk); + + return 0; +} + +static unsigned int stmp3xxx_getspeed(unsigned int cpu) +{ + struct clk *cpu_clk; + unsigned long rate; + + pr_debug("%s: entered\n", __func__); + if (cpu) + return 0; + + cpu_clk = clk_get(NULL, "cpu"); + if (IS_ERR(cpu_clk)) + return 0; + rate = clk_get_rate(cpu_clk); + pr_debug("%s: got cpu speed %ld\n", __func__, rate); + clk_put(cpu_clk); + + return rate; +} + +static int set_op(unsigned int target_freq) +{ + struct clk *cpu_clk, *ahb_clk, *emi_clk; + struct regulator *vddd, *vdddbo, *cur_limit; + struct cpufreq_freqs freqs; + int ret = 0, i; + + cur_limit = cpufreq_bdata.regulator; + pr_debug("%s: entered\n", __func__); + cpu_clk = clk_get(NULL, "cpu"); + if (IS_ERR(cpu_clk)) { + ret = PTR_ERR(cpu_clk); + goto out_cpu; + } + ahb_clk = clk_get(NULL, "hclk"); + if (IS_ERR(ahb_clk)) { + ret = PTR_ERR(ahb_clk); + goto out_ahb; + } + emi_clk = clk_get(NULL, "emi"); + if (IS_ERR(emi_clk)) { + ret = PTR_ERR(emi_clk); + goto out_emi; + } + + vddd = regulator_get(NULL, "vddd"); + vdddbo = regulator_get(NULL, "vddd_bo"); + if (IS_ERR(vdddbo)) + vdddbo = NULL; + + freqs.old = clk_get_rate(cpu_clk); + freqs.cpu = 0; + for (i = 0; i < ARRAY_SIZE(profiles) - 1; i++) { + if (profiles[i].cpu <= target_freq && + target_freq < profiles[i + 1].cpu) { + freqs.new = profiles[i].cpu; + cpufreq_bdata.next_freq_id = i; + break; + } + if (!vddd && profiles[i].cpu > freqs.old) { + /* can't safely set more than now */ + freqs.new = profiles[i - 1].cpu; + break; + } + } + + pr_debug("target_freq %d, new %d\n", target_freq, freqs.new); + if (i == ARRAY_SIZE(profiles) - 1) { + freqs.new = profiles[i].cpu; + cpufreq_bdata.next_freq_id = i; + } + + if (IS_ERR(vddd)) { + ret = PTR_ERR(vddd); + if (!cpufreq_bdata.init_nb.notifier_call) { + /* we only register once */ + cpufreq_bdata.init_nb.notifier_call = init_reg_callback; + bus_register_notifier(&platform_bus_type, + &cpufreq_bdata.init_nb); + } + goto out_vddd; + } + + pr_debug("i %d: freqs.old %d, freqs.new %d\n", + i, freqs.old, freqs.new); + + spin_lock(&cpufreq_bdata.lock); + if (cur_limit && (freqs.old < freqs.new)) { + ret = regulator_set_current_limit(cur_limit, profiles[i].cur, profiles[i].cur); + if (ret) + goto out_cur; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (freqs.old > freqs.new) { + int ss = profiles[i].ss; + clk_set_rate(cpu_clk, profiles[i].cpu); + clk_set_rate(ahb_clk, profiles[i].ahb); + clk_set_rate(emi_clk, profiles[i].emi); + HW_DIGCTL_ARMCACHE_WR(BF_DIGCTL_ARMCACHE_VALID_SS(ss) | + BF_DIGCTL_ARMCACHE_DRTY_SS(ss) | + BF_DIGCTL_ARMCACHE_CACHE_SS(ss) | + BF_DIGCTL_ARMCACHE_DTAG_SS(ss) | + BF_DIGCTL_ARMCACHE_ITAG_SS(ss)); + if (vddd && vdddbo) { + ret = regulator_set_voltage(vddd, profiles[i].vddd, profiles[i].vddd); + if (ret) + ret = regulator_set_voltage(vddd, + profiles[i].vddd, + profiles[i].vddd); + regulator_set_voltage(vdddbo, profiles[i].vddd_bo, profiles[i].vddd_bo); + } + } else { + int ss = profiles[i].ss; + if (vddd && vdddbo) { + ret = regulator_set_voltage(vddd, profiles[i].vddd, profiles[i].vddd); + if (ret) + ret = regulator_set_voltage(vddd, + profiles[i].vddd, + profiles[i].vddd); + regulator_set_voltage(vdddbo, profiles[i].vddd_bo, profiles[i].vddd_bo); + } + HW_DIGCTL_ARMCACHE_WR(BF_DIGCTL_ARMCACHE_VALID_SS(ss) | + BF_DIGCTL_ARMCACHE_DRTY_SS(ss) | + BF_DIGCTL_ARMCACHE_CACHE_SS(ss) | + BF_DIGCTL_ARMCACHE_DTAG_SS(ss) | + BF_DIGCTL_ARMCACHE_ITAG_SS(ss)); + clk_set_rate(cpu_clk, profiles[i].cpu); + clk_set_rate(ahb_clk, profiles[i].ahb); + clk_set_rate(emi_clk, profiles[i].emi); + } + udelay(100); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + if (cur_limit && (freqs.old > freqs.new)) /* will not fail */ + regulator_set_current_limit(cur_limit, profiles[i].cur, profiles[i].cur); + + cpufreq_bdata.freq_id = i; + +out_cur: + spin_unlock(&cpufreq_bdata.lock); + if (vddd) + regulator_put(vddd); +out_vddd: + clk_put(emi_clk); +out_emi: + clk_put(ahb_clk); +out_ahb: + clk_put(cpu_clk); +out_cpu: + + return ret; +} + +static int stmp3xxx_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + return set_op(target_freq); +} + +static int reg_callback(struct notifier_block *self, unsigned long event, + void *data) +{ + struct stmp3xxx_cpufreq *_temp = + container_of(self, struct stmp3xxx_cpufreq, nb); + struct cpufreq_policy *policy = &_temp->policy; + int max_prof = ARRAY_SIZE(profiles) - 1; + int ret = -EINVAL; + + pr_debug("%s: entered, _temp %p, policy %p, cpu %d, freq_id %d\n", + __func__, _temp, policy, policy->cpu, _temp->freq_id); + + if (policy) + policy = cpufreq_cpu_get(policy->cpu); + if (!policy) { + printk(KERN_ERR "%s: couldn't get cpufreq policy\n", __func__); + goto out; + } + + /* FIXME: Need a lock: set policy by user VS async USB event */ + switch (event) { + case STMP3XXX_REG5V_IS_USB: + pr_debug("%s: limiting max_freq to %d\n", __func__, + profiles[max_prof - 1].cpu); + policy->user_policy.min = profiles[0].cpu; + policy->user_policy.max = profiles[max_prof - 1].cpu; + if (_temp->freq_id > max_prof - 1) + set_op(profiles[max_prof - 1].cpu); + break; + + case STMP3XXX_REG5V_NOT_USB: + pr_debug("%s: undo limiting max_freq to %d\n", __func__, + profiles[max_prof - 1].cpu); + policy->user_policy.min = profiles[0].cpu; + policy->user_policy.max = profiles[max_prof].cpu; + break; + + default: + pr_info("%s: unknown event %ld\n", __func__, event); + break; + } + cpufreq_cpu_put(policy); + ret = cpufreq_update_policy(policy->cpu); +out: + return ret; +} + +static int init_reg_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + int ret; + struct stmp3xxx_cpufreq *_temp = + container_of(self, struct stmp3xxx_cpufreq, init_nb); + + ret = set_op(profiles[_temp->next_freq_id].cpu); + if (ret == 0) + bus_unregister_notifier(&platform_bus_type, + &cpufreq_bdata.init_nb); + return ret; +} + +static int __init stmp3xxx_cpu_init(struct cpufreq_policy *policy) +{ + struct clk *cpu_clk = clk_get(NULL, "cpu"); + + pr_debug("%s: entered\n", __func__); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + if (policy->cpu != 0) + return -EINVAL; + + policy->cur = policy->min = policy->max = clk_get_rate(cpu_clk); + + pr_debug("got CPU clock rate %d\n", policy->cur); + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.min_freq = profiles[0].cpu; + policy->cpuinfo.max_freq = profiles[ARRAY_SIZE(profiles) - 1].cpu; + policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */ + clk_put(cpu_clk); +// stmp3xxx_platform_add_regulator("cpufreq", 1); + + return 0; +} + +static struct cpufreq_driver stmp3xxx_driver = { + .flags = CPUFREQ_STICKY, + .verify = stmp3xxx_verify_speed, + .target = stmp3xxx_target, + .get = stmp3xxx_getspeed, + .init = stmp3xxx_cpu_init, + .name = "stmp3xxx", +}; + +static int __init stmp3xxx_cpufreq_init(void) +{ + spin_lock_init(&cpufreq_bdata.lock); + cpufreq_bdata.nb.notifier_call = reg_callback; + return cpufreq_register_driver(&stmp3xxx_driver); +} + +static int __init stmp3xxx_reg_init(void) +{ + pr_debug("%s: enter\n", __func__); + if (!cpufreq_bdata.regulator) + __set_new_policy(&cpufreq_bdata.policy); + + if (cpufreq_bdata.regulator) + regulator_set_current_limit(cpufreq_bdata.regulator, + profiles[cpufreq_bdata.freq_id].cur, + profiles[cpufreq_bdata.freq_id].cur); + return 0 ; +} + +arch_initcall(stmp3xxx_cpufreq_init); +late_initcall(stmp3xxx_reg_init); diff --git a/arch/arm/mach-stmp3xxx/dcp-bootstream.c b/arch/arm/mach-stmp3xxx/dcp-bootstream.c new file mode 100644 index 000000000000..08776ad0e2d9 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/dcp-bootstream.c @@ -0,0 +1,298 @@ +/* + * Freescale STMP378X DCP driver for bootstream update. Only handles the OTP KEY + * case and can only encrypt/decrypt. + * + * Author: Pantelis Antoniou <pantelis@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sysdev.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/uaccess.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <mach/stmp3xxx_regs.h> +#include <mach/stmp3xxx.h> +#include <mach/regs-dcp.h> +#include <mach/dcp_bootstream_ioctl.h> + +/* use this channel (same as the ROM) */ +#define ROM_DCP_CHAN 3 + +/* Defines the channel mask for the rom dcp channel */ +#define ROM_DCP_CHAN_MASK (1 << ROM_DCP_CHAN) + +/* Defines the initialization value for the dcp control register */ +#define DCP_CTRL_INIT \ + (BM_DCP_CTRL_GATHER_RESIDUAL_WRITES | \ + BM_DCP_CTRL_ENABLE_CONTEXT_CACHING) + +/* Defines the initialization value for the dcp channel control register */ +#define DCP_CHANNELCTRL_INIT \ + BF_DCP_CHANNELCTRL_ENABLE_CHANNEL(ROM_DCP_CHAN_MASK) + +/* DCP work packet 1 value used to calculate CBC-MAC over the image header */ +#define DCP_PKT1_ENCRYPT \ + (BM_DCP_PACKET1_DECR_SEMAPHORE | \ + BM_DCP_PACKET1_ENABLE_CIPHER | \ + BM_DCP_PACKET1_CIPHER_ENCRYPT | \ + BM_DCP_PACKET1_CIPHER_INIT | \ + BM_DCP_PACKET1_OTP_KEY) + +/* DCP work packet 1 value used to decrypt DEK in key dictionary */ +#define DCP_PKT1_DECRYPT \ + (BM_DCP_PACKET1_DECR_SEMAPHORE | \ + BM_DCP_PACKET1_ENABLE_CIPHER | \ + BM_DCP_PACKET1_CIPHER_INIT | \ + BM_DCP_PACKET1_OTP_KEY) + +/* DCP (decryption) work packet definition */ +struct hw_dcp_packet { + uint32_t pNext; /* next dcp work packet address */ + uint32_t pkt1; /* dcp work packet 1 (control 0) */ + uint32_t pkt2; /* dcp work packet 2 (control 1) */ + uint32_t pSrc; /* source buffer address */ + uint32_t pDst; /* destination buffer address */ + uint32_t size; /* buffer size in bytes */ + uint32_t pPayload; /* payload buffer address */ + uint32_t stat; /* dcp status (written by dcp) */ +}; + +struct dma_area { + struct hw_dcp_packet hw_packet; + uint16_t block[16]; +}; + +struct stmp3xxx_dcp_bootstream_data { + struct device *dev; + struct dma_area *dma_area; + dma_addr_t dma_area_phys; +}; + +/* Only one instance allowed, so this is OK */ +static struct stmp3xxx_dcp_bootstream_data *global_dbd; + +static int stmp3xxx_dcp_bootstream_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct stmp3xxx_dcp_bootstream_data *dbd = global_dbd; + struct dma_area *da = dbd->dma_area; + void __user *argp = (void __user *)arg; + unsigned long timeout; + + /* be paranoid */ + if (dbd == NULL) + return -EBADF; + + if (cmd != DBS_ENC && cmd != DBS_DEC) + return -EINVAL; + + /* copy to (aligned) block */ + if (copy_from_user(da->block, argp, 16)) + return -EFAULT; + + /* Soft reset and remove the clock gate */ + HW_DCP_CTRL_SET(BM_DCP_CTRL_SFTRST); + + /* At 24Mhz, it takes no more than 4 clocks (160 ns) Maximum for + * the part to reset, reading the register twice should + * be sufficient to get 4 clks delay. + */ + HW_DCP_CTRL_RD(); + HW_DCP_CTRL_RD(); + + HW_DCP_CTRL_CLR(BM_DCP_CTRL_SFTRST | BM_DCP_CTRL_CLKGATE); + + /* Initialize control registers */ + HW_DCP_CTRL_WR(DCP_CTRL_INIT); + HW_DCP_CHANNELCTRL_WR(DCP_CHANNELCTRL_INIT); + + /* The loader does not enable context switching. Give the context + * buffer pointer an illegal address so if context switching is + * inadvertantly enabled, the dcp will return an error instead of + * trashing good memory. The dcp dma cannot access rom, so any rom + * address will do. + */ + HW_DCP_CONTEXT_WR(0xFFFF0000); + + HW_DCP_CHnSTAT_CLR(ROM_DCP_CHAN, -1); + HW_DCP_STAT_CLR(-1); + + da->hw_packet.pNext = 0; + da->hw_packet.pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE | + BM_DCP_PACKET1_ENABLE_CIPHER | BM_DCP_PACKET1_OTP_KEY | + BM_DCP_PACKET1_INTERRUPT | + (cmd == DBS_ENC ? BM_DCP_PACKET1_CIPHER_ENCRYPT : 0); + da->hw_packet.pkt2 = BF_DCP_PACKET2_CIPHER_CFG(0) | + BF_DCP_PACKET2_KEY_SELECT(0) | + BF_DCP_PACKET2_CIPHER_MODE(BV_DCP_PACKET2_CIPHER_MODE__ECB) | + BF_DCP_PACKET2_CIPHER_SELECT( + BV_DCP_PACKET2_CIPHER_SELECT__AES128); + da->hw_packet.pSrc = dbd->dma_area_phys + + offsetof(struct dma_area, block); + da->hw_packet.pDst = da->hw_packet.pSrc; /* in-place */ + da->hw_packet.size = 16; + da->hw_packet.pPayload = 0; + da->hw_packet.stat = 0; + + /* Load the work packet pointer and bump the channel semaphore */ + HW_DCP_CHnCMDPTR_WR(ROM_DCP_CHAN, dbd->dma_area_phys + + offsetof(struct dma_area, hw_packet)); + HW_DCP_CHnSEMA_WR(ROM_DCP_CHAN, BF_DCP_CHnSEMA_INCREMENT(1)); + + timeout = jiffies + msecs_to_jiffies(100); + + while (time_before(jiffies, timeout) && + (HW_DCP_STAT_RD() & BF_DCP_STAT_IRQ(ROM_DCP_CHAN_MASK)) == 0) + cpu_relax(); + + if (!time_before(jiffies, timeout)) { + dev_err(dbd->dev, "Timeout while waiting STAT\n"); + return -ETIMEDOUT; + } + + if ((HW_DCP_CHnSTAT_RD(ROM_DCP_CHAN) & 0xff) != 0) { + dev_err(dbd->dev, "Channel stat error 0x%02x\n", + HW_DCP_CHnSTAT_RD(ROM_DCP_CHAN) & 0xff); + return -EFAULT; + } + + if (copy_to_user(argp, da->block, 16)) + return -EFAULT; + + return 0; +} + +static struct file_operations stmp3xxx_dcp_bootstream_fops = { + .owner = THIS_MODULE, + .ioctl = stmp3xxx_dcp_bootstream_ioctl, +}; + +static struct miscdevice stmp3xxx_dcp_bootstream_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dcpboot", + .fops = &stmp3xxx_dcp_bootstream_fops, +}; + +static int __devinit stmp3xxx_dcp_bootstream_probe(struct platform_device *pdev) +{ + struct stmp3xxx_dcp_bootstream_data *dbd; + int err; + + /* we only allow a single device */ + if (global_dbd != NULL) + return -ENODEV; + + dbd = kzalloc(sizeof(*dbd), GFP_KERNEL); + if (dbd == NULL) + return -ENOMEM; + memset(dbd, 0, sizeof(*dbd)); + + dbd->dev = &pdev->dev; + platform_set_drvdata(pdev, dbd); + + err = misc_register(&stmp3xxx_dcp_bootstream_misc); + if (err != 0) { + dev_err(&pdev->dev, "Unable to register misc device\n"); + goto err_done; + } + + dbd->dma_area = dma_alloc_coherent(&pdev->dev, sizeof(*dbd->dma_area), + &dbd->dma_area_phys, GFP_KERNEL); + if (dbd->dma_area == NULL) { + dev_err(&pdev->dev, "Unable to allocate DMAable memory\n"); + goto err_dereg; + } + + global_dbd = dbd; + + return 0; + +err_dereg: + misc_deregister(&stmp3xxx_dcp_bootstream_misc); +err_done: + kfree(dbd); + return err; +} + +static int stmp3xxx_dcp_bootstream_remove(struct platform_device *pdev) +{ + struct stmp3xxx_dcp_bootstream_data *dbd; + + dbd = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + dma_free_coherent(&pdev->dev, sizeof(*dbd->dma_area), + dbd->dma_area, dbd->dma_area_phys); + misc_deregister(&stmp3xxx_dcp_bootstream_misc); + + kfree(dbd); + + global_dbd = NULL; + + return 0; +} + +#ifdef CONFIG_PM +static int stmp3xxx_dcp_bootstream_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} + +static int stmp3xxx_dcp_bootstream_resume(struct platform_device *pdev) +{ + return 0; +} +#else +#define stmp3xxx_dcp_bootstream_suspend NULL +#define stmp3xxx_dcp_bootstream_resume NULL +#endif + +static struct platform_driver stmp3xxx_dcp_bootstream_driver = { + .probe = stmp3xxx_dcp_bootstream_probe, + .remove = stmp3xxx_dcp_bootstream_remove, + .suspend = stmp3xxx_dcp_bootstream_suspend, + .resume = stmp3xxx_dcp_bootstream_resume, + .driver = { + .name = "stmp3xxx-dcpboot", + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxx_dcp_bootstream_init(void) +{ + return platform_driver_register(&stmp3xxx_dcp_bootstream_driver); +} + +static void __exit stmp3xxx_dcp_bootstream_exit(void) +{ + platform_driver_unregister(&stmp3xxx_dcp_bootstream_driver); +} + +MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>"); +MODULE_DESCRIPTION("DCP bootstream driver"); +MODULE_LICENSE("GPL"); + +module_init(stmp3xxx_dcp_bootstream_init); +module_exit(stmp3xxx_dcp_bootstream_exit); diff --git a/arch/arm/mach-stmp3xxx/devices.c b/arch/arm/mach-stmp3xxx/devices.c new file mode 100644 index 000000000000..fc4d37653de9 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/devices.c @@ -0,0 +1,570 @@ +/* + * Freescale STMP37XX/STMP378X platform devices + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/mtd/partitions.h> +#include <linux/fsl_devices.h> +#include <asm/setup.h> +#include <asm/dma.h> + +#include <mach/gpio.h> +#include <mach/regs-uartapp.h> +#include <mach/regs-gpmi.h> +#include <mach/regs-i2c.h> +#include <mach/regs-ssp.h> +#include <mach/regs-power.h> +#include <mach/regs-pxp.h> +#include <mach/regs-usbctrl.h> +#include <mach/ddi_bc.h> + +#include <mach/stmp3xxx.h> +#include <mach/gpmi.h> +#include <mach/lcdif.h> + +#include "common.h" + +static u64 common_dmamask = ~(u32)0; +#define COMMON_COHERENT_DMAMASK (u32)0xffffffffU + +static struct resource appuart_resources[] = { + { + .start = IRQ_UARTAPP_INTERNAL, + .end = IRQ_UARTAPP_INTERNAL, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_UARTAPP_RX_DMA, + .end = IRQ_UARTAPP_RX_DMA, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_UARTAPP_TX_DMA, + .end = IRQ_UARTAPP_TX_DMA, + .flags = IORESOURCE_IRQ, + }, + { + .start = REGS_UARTAPP_BASE, + .end = REGS_UARTAPP_BASE + 0xA0, + .flags = IORESOURCE_MEM, + }, + { + /* Rx DMA channel */ + .start = STMP3xxx_DMA(6, STMP3XXX_BUS_APBX), + .end = STMP3xxx_DMA(6, STMP3XXX_BUS_APBX), + .flags = IORESOURCE_DMA, + }, + { + /* Tx DMA channel */ + .start = STMP3xxx_DMA(7, STMP3XXX_BUS_APBX), + .end = STMP3xxx_DMA(7, STMP3XXX_BUS_APBX), + .flags = IORESOURCE_DMA, + }, +}; + +static int appuart_pinmux(int req, int id) +{ + if (req) + return stmp3xxx_request_pin_group(&appuart_pins[id], "appuart"); + else + stmp3xxx_release_pin_group(&appuart_pins[id], "appuart"); + return 0; +} + +struct platform_device stmp3xxx_appuart = { + .name = "stmp37xx-appuart", + .id = 0, + .resource = appuart_resources, + .num_resources = ARRAY_SIZE(appuart_resources), + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + .platform_data = appuart_pinmux, + }, +}; + +static void dbguart_pinmux(int req, int id) +{ + if (req) + stmp3xxx_request_pin_group(&dbguart_pins[id], "dbguart"); + else + stmp3xxx_release_pin_group(&dbguart_pins[id], "dbguart"); +} + +struct platform_device stmp3xxx_dbguart = { + .name = "stmp37xx-dbguart", + .dev = { + .platform_data = dbguart_pinmux, + }, +}; + +struct platform_device stmp3xxx_watchdog = { + .name = "stmp3xxx_wdt", + .id = -1, +}; + +static struct resource ts_resource[] = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_TOUCH_DETECT, + .end = IRQ_TOUCH_DETECT, + }, + { + .flags = IORESOURCE_IRQ, + .start = IRQ_LRADC_CH5, + .end = IRQ_LRADC_CH5, + }, +}; + +struct platform_device stmp3xxx_touchscreen = { + .name = "stmp3xxx_ts", + .id = -1, + .resource = ts_resource, + .num_resources = ARRAY_SIZE(ts_resource), +}; + +/* + * Keypad device + */ +static struct resource keyboard_resource[] = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_LRADC_CH0, + .end = IRQ_LRADC_CH0, + }, +}; + +struct platform_device stmp3xxx_keyboard = { + .name = "stmp3xxx-keyboard", + .id = -1, + .num_resources = ARRAY_SIZE(keyboard_resource), + .resource = keyboard_resource, +}; + +static struct resource gpmi_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + .start = REGS_GPMI_BASE, + .end = REGS_GPMI_BASE + 0x100, + }, + [1] = { + .flags = IORESOURCE_IRQ, + .start = IRQ_GPMI_DMA, + .end = IRQ_GPMI_DMA, + }, + [2] = { + .flags = IORESOURCE_DMA, + .start = STMP3xxx_DMA(4, STMP3XXX_BUS_APBH), + .end = STMP3xxx_DMA(8, STMP3XXX_BUS_APBH), + }, +}; + +struct platform_device stmp3xxx_gpmi = { + .name = "gpmi", + .id = -1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, + .resource = gpmi_resources, + .num_resources = ARRAY_SIZE(gpmi_resources), +}; + +static struct resource i2c_resources[] = { + [0] = { + .flags = IORESOURCE_IRQ, + .start = IRQ_I2C_ERROR, + .end = IRQ_I2C_ERROR, + }, + [1] = { + .flags = IORESOURCE_IRQ, + .start = IRQ_I2C_DMA, + .end = IRQ_I2C_DMA, + }, + +}; + +struct platform_device stmp378x_i2c = { + .name = "i2c_stmp", + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, + .resource = i2c_resources, + .num_resources = ARRAY_SIZE(i2c_resources), +}; + +struct resource mmc1_resource[] = { + [0] = { + .flags = IORESOURCE_MEM, + .start = REGS_SSP_BASE, + .end = REGS_SSP_BASE + 0x4000, + }, + [1] = { + .flags = IORESOURCE_DMA, + .start = STMP3xxx_DMA(1, STMP3XXX_BUS_APBH), + .end = STMP3xxx_DMA(1, STMP3XXX_BUS_APBH), + }, + [2] = { + .flags = IORESOURCE_IRQ, + .start = IRQ_SSP1_DMA, + .end = IRQ_SSP1_DMA, + }, + [3] = { + .flags = IORESOURCE_IRQ, + .start = IRQ_SSP_ERROR, + .end = IRQ_SSP_ERROR, + }, +}; + +struct platform_device stmp3xxx_mmc = { + .name = "stmp3xxx-mmc", + .id = 1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, + .resource = mmc1_resource, + .num_resources = ARRAY_SIZE(mmc1_resource), +}; + +struct platform_device stmp3xxx_rtc = { + .name = "stmp3xxx-rtc", + .id = -1, +}; + +static struct resource fb_resource[] = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_LCDIF_DMA, + .end = IRQ_LCDIF_DMA, + }, + { + .flags = IORESOURCE_IRQ, + .start = IRQ_LCDIF_ERROR, + .end = IRQ_LCDIF_ERROR, + }, +}; + +static struct stmp3xxx_platform_fb_data stmp3xxx_framebuffer_pdata = { + .list = LIST_HEAD_INIT(stmp3xxx_framebuffer_pdata.list), +}; + +struct platform_device stmp3xxx_framebuffer = { + .name = "stmp3xxx-fb", + .id = -1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + .platform_data = &stmp3xxx_framebuffer_pdata, + }, + .num_resources = ARRAY_SIZE(fb_resource), + .resource = fb_resource, +}; + +/* PxP */ +static struct resource pxp_resource[] = { + { + .flags = IORESOURCE_MEM, + .start = REGS_PXP_BASE, + .end = REGS_PXP_BASE + 0x400, + }, + { + .flags = IORESOURCE_IRQ, + .start = IRQ_PXP, + .end = IRQ_PXP, + }, +}; + +struct platform_device stmp3xxx_pxp = { + .name = "stmp3xxx-pxp", + .id = -1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, + .num_resources = ARRAY_SIZE(pxp_resource), + .resource = pxp_resource, +}; + +/* SSP 1&2 */ + +struct resource ssp1_resources[] = { + [0] = { + .start = REGS_SSP_BASE, + .end = REGS_SSP_BASE + 0x200, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP1_DMA, + .end = IRQ_SSP1_DMA, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = STMP3xxx_DMA(1, STMP3XXX_BUS_APBH), + .end = STMP3xxx_DMA(1, STMP3XXX_BUS_APBH), + .flags = IORESOURCE_DMA, + }, +}; + +struct resource ssp2_resources[] = { + [0] = { + .start = REGS_SSP_BASE + 0x800000, + .end = REGS_SSP_BASE + 0x200 + 0x800000, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SSP2_DMA, + .end = IRQ_SSP2_DMA, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = STMP3xxx_DMA(2, STMP3XXX_BUS_APBH), + .end = STMP3xxx_DMA(2, STMP3XXX_BUS_APBH), + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device stmp3xxx_spi1 = { + .name = "stmp37xx_ssp", + .id = 1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, + .resource = ssp1_resources, + .num_resources = ARRAY_SIZE(ssp1_resources), +}; + +struct platform_device stmp3xxx_spi2 = { + .name = "stmp37xx_ssp", + .id = 2, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, + .resource = ssp2_resources, + .num_resources = ARRAY_SIZE(ssp2_resources), +}; + +#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2) \ + static char *cmdline_device_##name; \ + static int cmdline_device_##name##_setup(char *dev) \ + { \ + cmdline_device_##name = dev + 1; \ + return 0; \ + } \ + __setup(#name, cmdline_device_##name##_setup); \ + int stmp3xxx_##name##_device_register(void) \ + { \ + struct platform_device *d = NULL; \ + if (!cmdline_device_##name || \ + !strcmp(cmdline_device_##name, #dev1)) \ + d = &stmp3xxx_##dev1; \ + else if (!strcmp(cmdline_device_##name, #dev2)) \ + d = &stmp3xxx_##dev2; \ + else \ + printk(KERN_ERR"Unknown %s assignment '%s'.\n", \ + #name, cmdline_device_##name); \ + return d ? platform_device_register(d) : -ENOENT; \ + } + +CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1) +CMDLINE_DEVICE_CHOOSE(ssp2, gpmi, spi2) + +struct platform_device stmp3xxx_backlight = { + .name = "stmp3xxx-bl", + .id = -1, +}; + +static const struct stmp3xxx_persistent_bit_config +stmp3xxx_persistent_bit_tab[] = { + { .reg = 0, .start = 0, .width = 1, + .name = "CLOCKSOURCE" }, + { .reg = 0, .start = 1, .width = 1, + .name = "ALARM_WAKE_EN" }, + { .reg = 0, .start = 2, .width = 1, + .name = "ALARM_EN" }, + { .reg = 0, .start = 3, .width = 1, + .name = "CLK_SECS" }, + { .reg = 0, .start = 4, .width = 1, + .name = "XTAL24MHZ_PWRUP" }, + { .reg = 0, .start = 5, .width = 1, + .name = "XTAL32MHZ_PWRUP" }, + { .reg = 0, .start = 6, .width = 1, + .name = "XTAL32_FREQ" }, + { .reg = 0, .start = 7, .width = 1, + .name = "ALARM_WAKE" }, + { .reg = 0, .start = 8, .width = 5, + .name = "MSEC_RES" }, + { .reg = 0, .start = 13, .width = 1, + .name = "DISABLE_XTALOK" }, + { .reg = 0, .start = 14, .width = 2, + .name = "LOWERBIAS" }, + { .reg = 0, .start = 16, .width = 1, + .name = "DISABLE_PSWITCH" }, + { .reg = 0, .start = 17, .width = 1, + .name = "AUTO_RESTART" }, + { .reg = 0, .start = 18, .width = 14, + .name = "SPARE_ANALOG" }, + + { .reg = 1, .start = 0, .width = 1, + .name = "FORCE_RECOVERY" }, + { .reg = 1, .start = 1, .width = 1, + .name = "NAND_SECONDARY_BOOT" }, + { .reg = 1, .start = 2, .width = 1, + .name = "NAND_SDK_BLOCK_REWRITE" }, + { .reg = 1, .start = 3, .width = 1, + .name = "SD_SPEED_ENABLE" }, + { .reg = 1, .start = 4, .width = 1, + .name = "SD_INIT_SEQ_1_DISABLE" }, + { .reg = 1, .start = 5, .width = 1, + .name = "SD_CMD0_DISABLE" }, + { .reg = 1, .start = 6, .width = 1, + .name = "SD_INIT_SEQ_2_ENABLE" }, + { .reg = 1, .start = 7, .width = 1, + .name = "OTG_ATL_ROLE_BIT" }, + { .reg = 1, .start = 8, .width = 1, + .name = "OTG_HNP_BIT" }, + { .reg = 1, .start = 9, .width = 1, + .name = "USB_LOW_POWER_MODE" }, + { .reg = 1, .start = 10, .width = 1, + .name = "SKIP_CHECKDISK" }, + { .reg = 1, .start = 11, .width = 1, + .name = "USB_BOOT_PLAYER_MODE" }, + { .reg = 1, .start = 12, .width = 1, + .name = "ENUMERATE_500MA_TWICE" }, + { .reg = 1, .start = 13, .width = 19, + .name = "SPARE_GENERAL" }, + + { .reg = 2, .start = 0, .width = 32, + .name = "SPARE_2" }, + { .reg = 3, .start = 0, .width = 32, + .name = "SPARE_3" }, + { .reg = 4, .start = 0, .width = 32, + .name = "SPARE_4" }, + { .reg = 5, .start = 0, .width = 32, + .name = "SPARE_5" }, +}; + +static struct stmp3xxx_platform_persistent_data stmp3xxx_persistent_data = { + .bit_config_tab = stmp3xxx_persistent_bit_tab, + .bit_config_cnt = ARRAY_SIZE(stmp3xxx_persistent_bit_tab), +}; + +struct platform_device stmp3xxx_persistent = { + .name = "stmp3xxx-persistent", + .id = -1, + .dev.platform_data = &stmp3xxx_persistent_data, +}; + +struct platform_device stmp3xxx_dcp_bootstream = { + .name = "stmp3xxx-dcpboot", + .id = -1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, +}; + +static struct resource dcp_resources[] = { + { + .start = IRQ_DCP_VMI, + .end = IRQ_DCP_VMI, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_DCP, + .end = IRQ_DCP, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device stmp3xxx_dcp = { + .name = "stmp3xxx-dcp", + .id = -1, + .resource = dcp_resources, + .num_resources = ARRAY_SIZE(dcp_resources), + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, +}; + +struct platform_device stmp3xxx_mtest = { + .name = "stmp3xxx-mtest", + .id = -1, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = COMMON_COHERENT_DMAMASK, + }, +}; + +struct platform_device stmp3xxx_rotdec = { + .name = "stmp3xxx-rotdec", + .id = -1, +}; + +static struct resource battery_resource[] = { + [0] = { + .flags = IORESOURCE_IRQ, + .start = IRQ_VDD5V, + .end = IRQ_VDD5V, + }, +}; + +static ddi_bc_Cfg_t battery_data = { + .u32StateMachinePeriod = 100, /* ms */ + .u16CurrentRampSlope = 75, /* mA/s */ + .u16ConditioningThresholdVoltage = 2900, /* mV */ + .u16ConditioningMaxVoltage = 3000, /* mV */ + .u16ConditioningCurrent = 60, /* mA */ + .u32ConditioningTimeout = 4*60*60*1000, /* ms (4 hours) */ + .u16ChargingVoltage = 4200, /* mV */ + /* FIXME: the current comparator could have h/w bugs in current + * detection through POWER_STS.CHRGSTS bit */ + .u16ChargingCurrent = 600, /* mA 600 */ + .u16ChargingThresholdCurrent = 60, /* mA 60 */ + .u32ChargingTimeout = 4*60*60*1000,/* ms (4 hours) */ + .u32TopOffPeriod = 30*60*1000, /* ms (30 minutes) */ + .useInternalBias = 0, /* ext bias current */ + .monitorDieTemp = 1, /* Monitor the die */ + .u8DieTempHigh = 115, /* deg centigrade */ + .u8DieTempLow = 96, /* deg centigrade */ + .u16DieTempSafeCurrent = 400, /* mA */ + .monitorBatteryTemp = 0, /* Monitor the battery*/ + .u8BatteryTempChannel = 1, /* LRADC 1 */ + .u16BatteryTempHigh = 642, /* Unknown units */ + .u16BatteryTempLow = 497, /* Unknown units */ + .u16BatteryTempSafeCurrent = 0, /* mA */ +}; + +struct platform_device stmp3xxx_battery = { + .name = "stmp3xxx-battery", + .resource = battery_resource, + .num_resources = ARRAY_SIZE(battery_resource), + .dev = { + .platform_data = &battery_data, + } +}; diff --git a/arch/arm/mach-stmp3xxx/dma.c b/arch/arm/mach-stmp3xxx/dma.c new file mode 100644 index 000000000000..49ed790b92d3 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/dma.c @@ -0,0 +1,509 @@ +/* + * DMA helper routines for Freescale STMP37XX/STMP378X + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/sysdev.h> +#include <linux/cpufreq.h> +#include <asm/page.h> +#include <mach/dma.h> +#include <mach/regs-apbx.h> +#include <mach/regs-apbh.h> + +static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command); +static const size_t pool_alignment = 8; +static struct stmp3xxx_dma_user { + void *pool; + int inuse; + char *name; +} channels[MAX_DMA_CHANNELS]; + +static inline int dmach(int ch) +{ + return ch % 16; +} + +static inline int dmabus(int ch) +{ + return ch / 16; +} + +#define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS) +#define IS_USED(ch) (channels[ch].inuse) + +int stmp3xxx_dma_request(int ch, struct device *dev, char *name) +{ + struct stmp3xxx_dma_user *user; + int err = 0; + + user = channels + ch; + if (!IS_VALID_CHANNEL(ch)) { + err = -ENODEV; + goto out; + } + if (IS_USED(ch)) { + err = -EBUSY; + goto out; + } + /* Create a pool to allocate dma commands from */ + user->pool = dma_pool_create(name, dev, pool_item_size, + pool_alignment, PAGE_SIZE); + if (user->pool == NULL) { + err = -ENOMEM; + goto out; + } + user->name = name; + user->inuse++; +out: + return err; +} +EXPORT_SYMBOL(stmp3xxx_dma_request); + +int stmp3xxx_dma_release(int ch) +{ + struct stmp3xxx_dma_user *user = channels + ch; + int err = 0; + + if (!IS_VALID_CHANNEL(ch)) { + err = -ENODEV; + goto out; + } + if (!IS_USED(ch)) { + err = -EBUSY; + goto out; + } + BUG_ON(user->pool == NULL); + dma_pool_destroy(user->pool); + user->inuse--; +out: + return err; +} +EXPORT_SYMBOL(stmp3xxx_dma_release); + +int stmp3xxx_dma_read_semaphore(int channel) +{ + int sem = -1; + + switch (dmabus(channel)) { + case STMP3XXX_BUS_APBH: + sem = + (HW_APBH_CHn_SEMA_RD(dmach(channel)) & + BM_APBH_CHn_SEMA_PHORE) >> BP_APBH_CHn_SEMA_PHORE; + break; + + case STMP3XXX_BUS_APBX: + sem = + (HW_APBX_CHn_SEMA_RD(dmach(channel)) & + BM_APBX_CHn_SEMA_PHORE) >> BP_APBX_CHn_SEMA_PHORE; + break; + default: + BUG(); + } + return sem; +} +EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore); + +int stmp3xxx_dma_allocate_command(int channel, + struct stmp3xxx_dma_descriptor *descriptor) +{ + struct stmp3xxx_dma_user *user = channels + channel; + int err = 0; + + if (!IS_VALID_CHANNEL(channel)) { + err = -ENODEV; + goto out; + } + if (!IS_USED(channel)) { + err = -EBUSY; + goto out; + } + if (descriptor == NULL) { + err = -EINVAL; + goto out; + } + + /* Allocate memory for a command from the buffer */ + descriptor->command = + dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle); + + /* Check it worked */ + if (!descriptor->command) { + err = -ENOMEM; + goto out; + } + + memset(descriptor->command, 0, pool_item_size); +out: + WARN_ON(err); + return err; +} +EXPORT_SYMBOL(stmp3xxx_dma_allocate_command); + +int stmp3xxx_dma_free_command(int channel, + struct stmp3xxx_dma_descriptor *descriptor) +{ + int err = 0; + + if (!IS_VALID_CHANNEL(channel)) { + err = -ENODEV; + goto out; + } + if (!IS_USED(channel)) { + err = -EBUSY; + goto out; + } + + /* Return the command memory to the pool */ + dma_pool_free(channels[channel].pool, descriptor->command, + descriptor->handle); + + /* Initialise descriptor so we're not tempted to use it */ + descriptor->command = 0; + descriptor->handle = 0; + descriptor->virtual_buf_ptr = 0; + descriptor->next_descr = 0; + + WARN_ON(err); +out: + return err; +} +EXPORT_SYMBOL(stmp3xxx_dma_free_command); + +void stmp3xxx_dma_go(int channel, + struct stmp3xxx_dma_descriptor *head, u32 semaphore) +{ + int ch = dmach(channel); + + switch (dmabus(channel)) { + case STMP3XXX_BUS_APBH: + /* Set next command */ + HW_APBH_CHn_NXTCMDAR_WR(ch, head->handle); + /* Set counting semaphore (kicks off transfer). Assumes + peripheral has been set up correctly */ + HW_APBH_CHn_SEMA_WR(ch, semaphore); + break; + + case STMP3XXX_BUS_APBX: + /* Set next command */ + HW_APBX_CHn_NXTCMDAR_WR(ch, head->handle); + /* Set counting semaphore (kicks off transfer). Assumes + peripheral has been set up correctly */ + HW_APBX_CHn_SEMA_WR(ch, semaphore); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_dma_go); + +int stmp3xxx_dma_running(int channel) +{ + switch (dmabus(channel)) { + case STMP3XXX_BUS_APBH: + return HW_APBH_CHn_SEMA_RD(dmach(channel)) & + BM_APBH_CHn_SEMA_PHORE; + + case STMP3XXX_BUS_APBX: + return HW_APBX_CHn_SEMA_RD(dmach(channel)) & + BM_APBX_CHn_SEMA_PHORE; + + default: + BUG(); + return 0; + } +} +EXPORT_SYMBOL(stmp3xxx_dma_running); + +/* + * Circular dma chain management + */ +void stmp37cc_dma_print_chain(struct stmp37xx_circ_dma_chain *chain) +{ + int i; + struct stmp3xxx_dma_descriptor *d; + + for (i = 0; i < chain->total_count; i++) { + d = &chain->chain[i]; + printk(KERN_DEBUG"Chain item %d (%p), command = %p(%x)\n" + "...next = %x" + "...cmd = %x" + "...buf_ptr/alt = %x\n", + i, d, d->command, d->handle, + d->command->next, d->command->cmd, + d->command->alternate); + } +} + +void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain) +{ + int i; + + for (i = 0; i < chain->total_count; i++) + stmp3xxx_dma_free_command( + STMP3xxx_DMA(chain->channel, chain->bus), + &chain->chain[i]); +} +EXPORT_SYMBOL(stmp3xxx_dma_free_chain); + +int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain, + struct stmp3xxx_dma_descriptor descriptors[], + unsigned items) +{ + int i; + int err = 0; + + if (items == 0) + return err; + + for (i = 0; i < items; i++) { + err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]); + if (err) { + WARN_ON(err); + /* + * Couldn't allocate the whole chain. + * deallocate what has been allocated + */ + if (i) { + do { + stmp3xxx_dma_free_command(ch, + &descriptors + [i]); + } while (i-- >= 0); + } + return err; + } + + /* link them! */ + if (i > 0) { + descriptors[i - 1].next_descr = &descriptors[i]; + descriptors[i - 1].command->next = + descriptors[i].handle; + } + } + + /* make list circular */ + descriptors[items - 1].next_descr = &descriptors[0]; + descriptors[items - 1].command->next = descriptors[0].handle; + + chain->total_count = items; + chain->chain = descriptors; + chain->free_index = 0; + chain->active_index = 0; + chain->cooked_index = 0; + chain->free_count = items; + chain->active_count = 0; + chain->cooked_count = 0; + chain->bus = dmabus(ch); + chain->channel = dmach(ch); + return err; +} +EXPORT_SYMBOL(stmp3xxx_dma_make_chain); + +void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain) +{ + BUG_ON(stmp3xxx_dma_running(STMP3xxx_DMA(chain->channel, chain->bus)) > + 0); + chain->free_index = 0; + chain->active_index = 0; + chain->cooked_index = 0; + chain->free_count = chain->total_count; + chain->active_count = 0; + chain->cooked_count = 0; +} +EXPORT_SYMBOL(stmp37xx_circ_clear_chain); + +void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain, + unsigned count) +{ + BUG_ON(chain->cooked_count < count); + + chain->cooked_count -= count; + chain->cooked_index += count; + chain->cooked_index %= chain->total_count; + chain->free_count += count; +} +EXPORT_SYMBOL(stmp37xx_circ_advance_free); + +void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain, + unsigned count) +{ + BUG_ON(chain->free_count < count); + + chain->free_count -= count; + chain->free_index += count; + chain->free_index %= chain->total_count; + chain->active_count += count; + + switch (chain->bus) { + case STMP3XXX_BUS_APBH: + /* Set counting semaphore (kicks off transfer). Assumes + peripheral has been set up correctly */ + HW_APBH_CHn_SEMA_CLR(chain->channel, + BM_APBH_CHn_SEMA_INCREMENT_SEMA); + HW_APBH_CHn_SEMA_SET(chain->channel, + BF_APBH_CHn_SEMA_INCREMENT_SEMA(count)); + break; + + case STMP3XXX_BUS_APBX: + /* Set counting semaphore (kicks off transfer). Assumes + peripheral has been set up correctly */ + HW_APBX_CHn_SEMA_CLR(chain->channel, + BM_APBX_CHn_SEMA_INCREMENT_SEMA); + HW_APBX_CHn_SEMA_SET(chain->channel, + BF_APBX_CHn_SEMA_INCREMENT_SEMA(count)); + break; + + default: + BUG(); + } +} +EXPORT_SYMBOL(stmp37xx_circ_advance_active); + +unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain) +{ + unsigned cooked; + + cooked = chain->active_count - + stmp3xxx_dma_read_semaphore(STMP3xxx_DMA(chain->channel, chain->bus)); + + chain->active_count -= cooked; + chain->active_index += cooked; + chain->active_index %= chain->total_count; + + chain->cooked_count += cooked; + + return cooked; +} +EXPORT_SYMBOL(stmp37xx_circ_advance_cooked); + +void stmp3xxx_dma_set_alt_target(int channel, int function) +{ +#if defined(CONFIG_ARCH_STMP37XX) + unsigned bits = 4; +#elif defined(CONFIG_ARCH_STMP378X) + unsigned bits = 2; +#else +#error wrong arch +#endif + int shift = dmach(channel) * bits; + unsigned mask = (1<<bits) - 1; + + BUG_ON(function < 0 || function >= (1<<bits)); + pr_debug("%s: channel = %d, using mask %x, " + "shift = %d\n", __func__, channel, mask, shift); + + switch (dmabus(channel)) { + case STMP3XXX_BUS_APBH: + HW_APBH_DEVSEL_CLR(mask<<shift); + HW_APBH_DEVSEL_SET(function<<shift); + break; + case STMP3XXX_BUS_APBX: + HW_APBX_DEVSEL_CLR(mask<<shift); + HW_APBX_DEVSEL_SET(function<<shift); + break; + default: + BUG(); + } +} +EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target); + +void stmp3xxx_dma_suspend(void) +{ + HW_APBH_CTRL0_SET(BM_APBH_CTRL0_CLKGATE); + HW_APBX_CTRL0_SET(BM_APBX_CTRL0_CLKGATE); +} + +void stmp3xxx_dma_resume(void) +{ + HW_APBH_CTRL0_CLR(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST); + HW_APBX_CTRL0_CLR(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST); +} + +#ifdef CONFIG_CPU_FREQ + +struct dma_notifier_block { + struct notifier_block nb; + void *data; +}; + +static int dma_cpufreq_notifier(struct notifier_block *self, + unsigned long phase, void *p) +{ + switch (phase) { + case CPUFREQ_POSTCHANGE: + stmp3xxx_dma_resume(); + break; + + case CPUFREQ_PRECHANGE: + stmp3xxx_dma_suspend(); + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +static struct dma_notifier_block dma_cpufreq_nb = { + .nb = { + .notifier_call = dma_cpufreq_notifier, + }, +}; +#endif /* CONFIG_CPU_FREQ */ + + +static struct sysdev_class stmp3xxx_dma_sysclass = { + .name = "stmp3xxx-dma", +#ifdef CONFIG_PM + .suspend = NULL, + .resume = NULL, +#endif +}; + +static struct sys_device stmp3xxx_dma_device = { + .id = -1, + .cls = &stmp3xxx_dma_sysclass, +}; + +static ssize_t stmp3xxx_dma_list(struct sys_device *dev, + struct sysdev_attribute *attr, char *buf) +{ + int i, n = 0; + + for (i = 0; i < MAX_DMA_CHANNELS; i++) + if (IS_USED(i)) + n += sprintf(buf + n, "%d @ %s\t%s\n", + dmach(i), dmabus(i) == 0 ? "APBH" : "APBX", + channels[i].name ? channels[i].name : "unknown"); + return n; +} +SYSDEV_ATTR(channels, 0444, stmp3xxx_dma_list, NULL); + +void __init stmp3xxx_dma_init(void) +{ + HW_APBH_CTRL0_CLR(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST); + HW_APBX_CTRL0_CLR(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST); + sysdev_class_register(&stmp3xxx_dma_sysclass); + sysdev_register(&stmp3xxx_dma_device); + sysdev_create_file(&stmp3xxx_dma_device, &attr_channels); + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&dma_cpufreq_nb.nb, + CPUFREQ_TRANSITION_NOTIFIER); +#endif /* CONFIG_CPU_FREQ */ + +} diff --git a/arch/arm/mach-stmp3xxx/emi.S b/arch/arm/mach-stmp3xxx/emi.S new file mode 100644 index 000000000000..c134c3dfa159 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/emi.S @@ -0,0 +1,150 @@ +/* + * Freescale STMP378X low level RAM frequency manipulation + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <mach/hardware.h> +#include <asm/system.h> +#include <asm/pgtable-hwdef.h> +#include <mach/regs-power.h> +#include <mach/regs-clkctrl.h> +#include "clock.h" + +.global cpu_arm926_switch_mm + +.align 8 +ENTRY(stmp3xxx_ram_freq_scale) + stmfd sp!, {r1 - r9, lr} + + ldr r5, [r0, #SCALING_DATA_NEW_FREQ_OFFSET] + ldr r6, [r0, #SCALING_DATA_CUR_FREQ_OFFSET] + ldr r7, [r0, #SCALING_DATA_EMI_DIV_OFFSET] + ldr r8, [r0, #SCALING_DATA_FRAC_DIV_OFFSET] + + adr r9, __stmp_temp_stack + + @ clean cache + ldr r1, __stmp_flush_cache_addr + mov lr, pc + mov pc, r1 + + @ put DRAM into self refresh + ldr r0, __stmp_dram_ctl00 + ldr r1, [r0, #0x20] + orr r1, r1, #(1 << 8) + str r1, [r0, #0x20] + @ wait for it to actually happen + ldr r0, __stmp_dram_emi00 +1: ldr r1, [r0, #0x10] + tst r1, #(1 << 1) + beq 1b + nop + + @ prepare for change + cmp r5, #24 + bgt 2f + bl stmp3xxx_ram_24M_set_timings + b 100f +2: cmp r5, #48 + bgt 3f + bl stmp3xxx_ram_48M_set_timings + b 100f +3: cmp r5, #60 + bgt 4f + bl stmp3xxx_ram_60M_set_timings + b 100f +4: cmp r5, #80 + bgt 5f + bl stmp3xxx_ram_80M_set_timings + b 100f +5: cmp r5, #96 + bgt 6f + bl stmp3xxx_ram_96M_set_timings + b 100f +6: cmp r5, #120 + bgt 7f + bl stmp3xxx_ram_120M_set_timings + b 100f +7: cmp r5, #133 + bgt 8f + bl stmp3xxx_ram_133M_set_timings + b 100f +8: bl stmp3xxx_ram_150M_set_timings + +100: + @ RAM to clk from xtal + mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) + mov r1, #(1<<6) + str r1, [r0, #4] + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) +101: ldr r1, [r0] + tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 101b + + bl __stmp_emi_set_values + + @ EMI back to PLL + mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) + mov r1, #(1<<6) + str r1, [r0, #8] + + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) +1: ldr r1, [r0] + tst r1, #BM_CLKCTRL_EMI_BUSY_REF_EMI + bne 1b + bic r1, #BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE + str r1, [r0] + + @ restore normal DRAM mode + ldr r0, __stmp_dram_ctl00 + ldr r1, [r0, #0x20] + bic r1, r1, #(1 << 8) + str r1, [r0, #0x20] + @ wait for it to actually happen + ldr r0, __stmp_dram_emi00 +102: ldr r1, [r0, #0x10] + tst r1, #(1 << 1) + bne 102b + + @ restore regs and return + ldmfd sp!, {r1 - r9, lr} + mov pc, lr + + .space 0x100 +__stmp_temp_stack: + .word 0 + +#include "emi.inc" + +__stmp_flush_cache_addr: + .word arm926_flush_kern_cache_all + +ENTRY(stmp3xxx_ram_funcs_sz) + .word . - stmp3xxx_ram_freq_scale + diff --git a/arch/arm/mach-stmp3xxx/emi.inc b/arch/arm/mach-stmp3xxx/emi.inc new file mode 100644 index 000000000000..326af7226209 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/emi.inc @@ -0,0 +1,712 @@ +/* + * Freescale STMP378X low level RAM timings tables for Micron mDDR + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +__stmp_emi_set_values: + stmfd r9!, {r0 - r4, lr} + mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) + + mov r3, #BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE + + mov r0, #(HW_CLKCTRL_FRAC_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0xFF000000) + ldr r2, [r0] + + and r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC + lsr r4, r4, #8 + /* new pll div > cur pll div? */ + cmp r4, r8 + bgt 1f + bic r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC + orr r4, r4, r8, lsl #8 + str r4, [r0] + nop + nop + nop + +1: ldr r4, [r1] + and r4, r4, #BM_CLKCTRL_EMI_DIV_EMI + /* new emi div > cur emi div? */ + cmp r4, r7 + bgt 2f + mov r4, r7 + orr r4, r4, #0x100 + orr r4, r4, r3 + str r4, [r1] +11: ldr r4, [r1] + tst r4, #BM_CLKCTRL_EMI_BUSY_REF_EMI + bne 11b + tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 11b + tst r4, #BM_CLKCTRL_EMI_BUSY_DCC_RESYNC + bne 11b + +2: ldr r2, [r0] + + and r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC + lsr r4, r4, #8 + /* new pll div != cur pll div? */ + cmp r4, r8 + beq 3f + bic r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC + orr r4, r4, r8, lsl #8 + str r4, [r0] + nop + nop + nop + +3: ldr r4, [r1] + and r4, r4, #BM_CLKCTRL_EMI_DIV_EMI + /* new emi div != cur emi div? */ + cmp r4, r7 + beq 4f + mov r4, r7 + orr r4, r4, #0x100 + orr r4, r4, r3 + str r4, [r1] +31: ldr r4, [r1] + tst r4, #BM_CLKCTRL_EMI_BUSY_REF_EMI + bne 31b + tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 31b + tst r4, #BM_CLKCTRL_EMI_BUSY_DCC_RESYNC + bne 31b + +4: ldmfd r9!, {r0 - r4, lr} + mov pc, lr + +stmp3xxx_ram_24M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_24M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_48M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_48M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_60M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_60M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_80M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_80M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_96M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_96M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_120M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_120M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_133M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_133M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + str r3, [r0, r2, lsl #2] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +stmp3xxx_ram_150M_set_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_150M_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + str r3, [r0, r2, lsl #2] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +__stmp_dram_ctl00: + .word IO_ADDRESS(0x800E0000) +__stmp_dram_emi00: + .word IO_ADDRESS(0x80020000) +__stmp_power_vdddctrl: + .word IO_ADDRESS(0x80044040) + +stmp3xxx_ram_save_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_saved_values +1: ldr r2, [r1] + mov r4, r2, lsl #2 + ldr r3, [r0, r4] + str r3, [r1, #4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +#ifdef CONFIG_STMP378X_RAM_MDDR +__stmp_dram_24M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000101 + .word 12 + .word 0x02010002 + .word 13 + .word 0x06060a02 + .word 15 + .word 0x01030000 + .word 17 + .word 0x2d000002 + .word 18 + .word 0x20200000 + .word 19 + .word 0x027f1010 + .word 20 + .word 0x01021021 + .word 21 + .word 0x00000002 + .word 26 + .word 0x000000b3 + .word 32 + .word 0x00030687 + .word 33 + .word 0x00000003 + .word 34 + .word 0x000012c1 + .word 40 + .word 0x00010000 + +__stmp_dram_48M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000101 + .word 12 + .word 0x02010002 + .word 13 + .word 0x06060a02 + .word 15 + .word 0x02040000 + .word 17 + .word 0x2d000104 + .word 18 + .word 0x1f1f0000 + .word 19 + .word 0x027f1010 + .word 20 + .word 0x02030a10 + .word 21 + .word 0x00000004 + .word 26 + .word 0x0000016f + .word 32 + .word 0x00060d17 + .word 33 + .word 0x00000006 + .word 34 + .word 0x00002582 + .word 40 + .word 0x00020000 + +__stmp_dram_60M_values: +__stmp_dram_80M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000101 + .word 11 + .word 0x00070204 + .word 12 + .word 0x02010002 + .word 13 + .word 0x06060a02 + .word 15 + .word 0x02040000 + .word 16 + .word 0x02000000 + .word 17 + .word 0x2d000105 + .word 18 + .word 0x1f1f0000 + .word 19 + .word 0x027f1010 + .word 20 + .word 0x02031021 + .word 21 + .word 0x00000006 + .word 26 + .word 0x000001cc + .word 32 + .word 0x00081060 + .word 33 + .word 0x00000008 + .word 34 + .word 0x00002ee5 + .word 40 + .word 0x00020000 + +__stmp_dram_96M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 12 + .word 0x02020002 + .word 13 + .word 0x06060a02 + .word 15 + .word 0x03050000 + .word 17 + .word 0x25001508 + .word 18 + .word 0x1f1f0000 + .word 19 + .word 0x02141a1a + .word 20 + .word 0x03051c22 + .word 21 + .word 0x00000007 + .word 26 + .word 0x000002e6 + .word 32 + .word 0x000c1a3b + .word 33 + .word 0x0000000c + .word 34 + .word 0x00004b0d + .word 40 + .word 0x00030000 + +__stmp_dram_120M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000001 + .word 12 + .word 0x02020002 + .word 13 + .word 0x06060a02 + .word 15 + .word 0x03050000 + .word 17 + .word 0x1900110a + .word 18 + .word 0x1f1f0000 + .word 19 + .word 0x02141515 + .word 20 + .word 0x03061523 + .word 21 + .word 0x00000009 + .word 26 + .word 0x000003a1 + .word 32 + .word 0x000f20ca + .word 33 + .word 0x0000000f + .word 34 + .word 0x00005dca + .word 40 + .word 0x00040000 + +__stmp_dram_133M_values: +__stmp_dram_150M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 12 + .word 0x02020002 + .word 13 + .word 0x06070a02 + .word 15 + .word 0x03050000 + .word 17 + .word 0x19000f0a + .word 18 + .word 0x1f1f0000 + .word 19 + .word 0x027f1313 /* 0x02141313 */ + .word 20 + .word 0x0306131f /* 0x03061323 */ + .word 21 + .word 0x0000000a + .word 26 + .word 0x000003f7 + .word 32 + .word 0x001023cd + .word 33 + .word 0x00000010 + .word 34 + .word 0x00006665 + .word 40 + .word 0x00040000 + +#elif CONFIG_STMP378X_RAM_DDR +/* XXX: not quite ready yet */ +__stmp_dram_24M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000101 + .word 11 + .word 0x00070206 + .word 12 + .word 0x01010000 @ t_wr 1, t_rrd 1, t_cke 0 + .word 13 + .word 0x04040a01 @ t_wtr 1 + .word 15 + .word 0x01020000 @ t_rp 1, t_dal 2 + .word 17 + .word 0x3d000302 @ t_rc 2 + .word 20 + .word 0x01020508 + .word 21 + .word 0x00000002 @ t_rfc 2 + .word 26 + .word 0x000000b3 /* 0xd20 */ @ t_ref + .word 32 + .word 0x00020690 @ t_xsnr 2, t_rasmax 0x690 + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x000012c1 @ t_init + .word 40 + .word 0x00010000 + +@ not yet +__stmp_dram_48M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000101 + .word 11 + .word 0x00070206 + .word 12 + .word 0x01010000 @ t_wr 1, t_rrd 1, t_cke 0 + .word 13 + .word 0x04040a01 @ t_wtr 1 + .word 15 + .word 0x01020000 @ t_rp 1, t_dal 2 + .word 17 + .word 0x39000104 @ t_rc 4 + .word 19 + .word 0x027f1010 + .word 20 + .word 0x02030a10 + .word 21 + .word 0x00000004 @ t_rfc + .word 26 + .word 0x00000173 /* 0x1a42 */ @ t_ref + .word 32 + .word 0x00040d21 @ t_xsnr 4, t_rasmax 0xd21 + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00002586 @ t_init + .word 40 + .word 0x00010000 + +__stmp_dram_60M_values: + .word 4 + .word 0x01000101 + .word 7 + .word 0x01000101 + .word 11 + .word 0x00070206 + .word 12 + .word 0x01010000 @ t_wr 1, t_rrd 1, t_cke 0 + .word 13 + .word 0x04040a01 @ t_wtr 1 + .word 15 + .word 0x01020000 @ t_rp 1, t_dal 2 + .word 17 + .word 0x3d000105 @ t_rc 5 + .word 19 + .word 0x027f1313 + .word 20 + .word 0x01031523 @ t_rcd 1, t_rasmin 3 + .word 21 + .word 0x00000005 @ t_rfc 5 + .word 26 + .word 0x000001cc /* 0x20cd */ @ t_ref + .word 32 + .word 0x00051068 @ t_xsnr 5, t_rasmax 0x1068 + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00002ee5 @ t_init + .word 40 + .word 0x00010000 + +__stmp_dram_80M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 11 + .word 0x00070206 + .word 12 + .word 0x02010000 @ t_wr 2, t_rrd 1, t_cke 0 + .word 13 + .word 0x04040a01 @ t_wtr 1 + .word 15 + .word 0x02040000 @ t_rp 2, t_dal 4 + .word 17 + .word 0x20001c05 @ dll_start_point 0x20, dll_increment 0x1c, t_rc 5 + .word 19 + .word 0x027f1313 + .word 20 + .word 0x02041522 @ t_rcd 2, t_rasmin 4, wr_dqs_shift 0x22 + .word 21 + .word 0x00000006 @ t_rfc 6 + .word 26 + .word 0x00000269 @ t_ref + .word 32 + .word 0x000615d6 @ t_xsnr 6, t_rasmax 0x15d6 + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00003e80 @ t_init + .word 40 + .word 0x00010000 + +__stmp_dram_96M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 11 + .word 0x00070206 + .word 12 + .word 0x02020000 @ t_wr 2, t_rrd 2, t_cke 0 + .word 13 + .word 0x04040a01 @ t_wtr 1 + .word 15 + .word 0x02040000 @ t_rp 2, t_dal 4 + .word 17 + .word 0x2f001706 @ dll_start_point 0x2f, dll_increment 0x17, t_rc 6 + .word 19 + .word 0x027f1a1a + .word 20 + .word 0x02051c21 @ t_rcd 2, t_rasmin 5, wr_dqs_shift 0x22 + .word 21 + .word 0x00000007 @ t_rfc 7 + .word 26 + .word 0x000002e6 /* 0x347b */ @ t_ref + .word 32 + .word 0x00081a3e @ t_xsnr 8, t_rasmax 0x1a3e + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00004b0d @ t_init + .word 40 + .word 0x00010000 + +__stmp_dram_120M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 11 + .word 0x00070206 + .word 12 + .word 0x02020000 @ t_wr 2, t_rrd 2, t_cke 0 + .word 13 + .word 0x04040a01 @ t_wtr 1 + .word 15 + .word 0x02040000 @ t_rp 2, t_dal 4 + .word 17 + .word 0x26001308 @ dll_start_point 0x26, dll_increment 0x13, t_rc 8 + .word 19 + .word 0x027f1a1a + .word 20 + .word 0x02061c23 @ t_rcd 2, t_rasmin 6 + .word 21 + .word 0x00000009 @ t_rfc 9 + .word 26 + .word 0x000003a1 /* 0x41a6 */ @ t_ref + .word 32 + .word 0x000a20ca @ t_xsnr 9, t_rasmax 0x20ca + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00005dca @ t_init + .word 40 + .word 0x00010000 + +__stmp_dram_133M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 11 + .word 0x00070206 + .word 12 + .word 0x02020000 + .word 13 + .word 0x04040a01 + .word 15 + .word 0x02040000 + .word 17 + .word 0x2200110a @ t_rc 0xa + .word 19 + .word 0x027f1313 + .word 20 + .word 0x02061521 + .word 21 + .word 0x0000000a + .word 26 + .word 0x00000408 /* 0x48b9 */ + .word 32 + .word 0x000a23cd + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00006808 + .word 40 + .word 0x00010000 + +__stmp_dram_150M_values: + .word 4 + .word 0x00000101 + .word 7 + .word 0x01000001 + .word 11 + .word 0x00070206 + .word 12 + .word 0x02020000 @ t_wr 2, t_rrd 2, t_cke 0 + .word 13 + .word 0x05050a02 @ t_wtr 2 + .word 15 + .word 0x03060000 @ t_rp 3, t_dal 6 + .word 17 + .word 0x18000d0c @ dll_start_point 0x18, dll_increment 0xd, t_rc 0xc + .word 19 + .word 0x027f0f0f + .word 20 + .word 0x03071121 @ t_rcd 3, t_rasmin 7 + .word 21 + .word 0x0000000c @ t_rfc 0xc + .word 26 + .word 0x000001cc /* 0x20cd */ @ t_ref + .word 32 + .word 0x000c2860 @ t_xsnr 0xc, t_rasmax 0x2860 + .word 33 + .word 0x000000c8 @ t_xsr 0xc8 + .word 34 + .word 0x00007554 @ t_init + .word 40 + .word 0x00010000 + +#else +#error RAM chip not defined +#endif + +stmp3xxx_ram_restore_timings: + ldr r0, __stmp_dram_ctl00 + adr r1, __stmp_dram_saved_values +1: ldr r2, [r1] + ldr r3, [r1, #4] + mov r4, r2, lsl #2 + str r3, [r0, r4] + add r1, r1, #8 + cmp r2, #40 + bne 1b + mov pc, lr + +__stmp_dram_saved_values: + .word 4 + .word 0 + .word 7 + .word 0 + .word 12 + .word 0 + .word 13 + .word 0 + .word 15 + .word 0 + .word 17 + .word 0 + .word 18 + .word 0 + .word 19 + .word 0 + .word 20 + .word 0 + .word 21 + .word 0 + .word 26 + .word 0 + .word 32 + .word 0 + .word 33 + .word 0 + .word 34 + .word 0 + .word 40 + .word 0 + diff --git a/arch/arm/mach-stmp3xxx/gpio.c b/arch/arm/mach-stmp3xxx/gpio.c new file mode 100644 index 000000000000..3f5fad781319 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/gpio.c @@ -0,0 +1,110 @@ +/* + * Freescale STMP37XX/STMP378X GPIO driver + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sysdev.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <mach/hardware.h> +#include <mach/stmp3xxx_regs.h> + +#include "common.h" + +#define STMP3xxx_GPIO_TOTAL (3*32) /* three banks by 32 pins each */ + +int gpio_request(unsigned id, char *label) +{ + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + return stmp3xxx_request_pin(id, PIN_GPIO, label); +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned id) +{ + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + stmp3xxx_release_pin(id, NULL); +} +EXPORT_SYMBOL(gpio_free); + +void gpio_set_value(unsigned id, int value) +{ + struct stmp3xxx_pinmux_bank *b; + int num = STMP3XXX_PINID_TO_PINNUM(id); + + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + b = stmp_pinmux_banks(STMP3XXX_PINID_TO_BANK(id)); + spin_lock(&b->lock); + __raw_writel(1 << num, value ? b->hw_gpio_set : b->hw_gpio_clr); + spin_unlock(&b->lock); +} +EXPORT_SYMBOL(gpio_set_value); + +int gpio_get_value(unsigned id) +{ + struct stmp3xxx_pinmux_bank *b; + int v; + int num = STMP3XXX_PINID_TO_PINNUM(id); + + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + b = stmp_pinmux_banks(STMP3XXX_PINID_TO_BANK(id)); + spin_lock(&b->lock); + v = (__raw_readl(b->hw_gpio_read) & (1 << num)) >> num; + spin_unlock(&b->lock); + return v; +} +EXPORT_SYMBOL(gpio_get_value); + +int gpio_to_irq(unsigned id) +{ + struct stmp3xxx_pinmux_bank *b; + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + b = stmp_pinmux_banks(STMP3XXX_PINID_TO_BANK(id)); + return b->irq; +} +EXPORT_SYMBOL(gpio_to_irq); + +void gpio_direction_output(unsigned id, int value) +{ + struct stmp3xxx_pinmux_bank *b; + int num = STMP3XXX_PINID_TO_PINNUM(id); + + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + b = stmp_pinmux_banks(STMP3XXX_PINID_TO_BANK(id)); + spin_lock(&b->lock); + __raw_writel(1 << num, b->hw_gpio_doe + HW_STMP3xxx_SET); + __raw_writel(1 << num, value ? b->hw_gpio_set : b->hw_gpio_clr); + spin_unlock(&b->lock); +} +EXPORT_SYMBOL(gpio_direction_output); + +void gpio_direction_input(unsigned id) +{ + struct stmp3xxx_pinmux_bank *b; + int num = STMP3XXX_PINID_TO_PINNUM(id); + + BUG_ON(id > STMP3xxx_GPIO_TOTAL); + b = stmp_pinmux_banks(STMP3XXX_PINID_TO_BANK(id)); + spin_lock(&b->lock); + __raw_writel(1 << num, b->hw_gpio_doe + HW_STMP3xxx_CLR); + spin_unlock(&b->lock); +} +EXPORT_SYMBOL(gpio_direction_input); + +MODULE_AUTHOR("dmitry pervushin"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-stmp3xxx/gpmi.c b/arch/arm/mach-stmp3xxx/gpmi.c new file mode 100644 index 000000000000..b699f56095cd --- /dev/null +++ b/arch/arm/mach-stmp3xxx/gpmi.c @@ -0,0 +1,40 @@ +/* + * Freescale STMP37XX/STMP378X GPMI module pin multiplexing + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include "common.h" + +int gpmi_pinmux_request(char *title) +{ + int err = 0; + + err = stmp3xxx_request_pin_group(&gpmi_pins, title); + + return err; +} +EXPORT_SYMBOL_GPL(gpmi_pinmux_request); + +void gpmi_pinmux_free(char *title) +{ + stmp3xxx_release_pin_group(&gpmi_pins, title); +} +EXPORT_SYMBOL_GPL(gpmi_pinmux_free); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); diff --git a/arch/arm/mach-stmp3xxx/include/mach/cpu.h b/arch/arm/mach-stmp3xxx/include/mach/cpu.h new file mode 100644 index 000000000000..2d0267a1934b --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/cpu.h @@ -0,0 +1,33 @@ +/* + * Freescale STMP37XX/STMP378X CPU type detection + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_CPU_H +#define __ASM_PLAT_CPU_H + +#ifdef CONFIG_ARCH_STMP37XX +#define cpu_is_stmp37xx() (1) +#else +#define cpu_is_stmp37xx() (0) +#endif + +#ifdef CONFIG_ARCH_STMP378X +#define cpu_is_stmp378x() (1) +#else +#define cpu_is_stmp378x() (0) +#endif + +#endif /* __ASM_PLAT_CPU_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/dcp_bootstream_ioctl.h b/arch/arm/mach-stmp3xxx/include/mach/dcp_bootstream_ioctl.h new file mode 100644 index 000000000000..aec63a5bfef4 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/dcp_bootstream_ioctl.h @@ -0,0 +1,32 @@ +/* + * Freescale STMP378X DCP driver for bootstream update. Only handles the OTP KEY + * case and can only encrypt/decrypt. + * + * Author: Pantelis Antoniou <pantelis@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef DCP_BOOTSTREAM_IOCTL_H +#define DCP_BOOTSTREAM_IOCTL_H + +/* remember to have included the proper _IO definition + * file before hand. + * For user space it's <sys/ioctl.h> + */ + +#define DBS_IOCTL_BASE 'd' + +#define DBS_ENC _IOW(DBS_IOCTL_BASE, 0x00, uint8_t[16]) +#define DBS_DEC _IOW(DBS_IOCTL_BASE, 0x01, uint8_t[16]) + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/ddi_bc.h b/arch/arm/mach-stmp3xxx/include/mach/ddi_bc.h new file mode 100644 index 000000000000..6f59b98d2f86 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/ddi_bc.h @@ -0,0 +1,736 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc.h +//! \brief Header file for the Battery Charger device driver. +//! \date 06/2005 +//! +//! This file contains externally visible declarations for the Battery Charger +//! device driver. +//! +//! \see ddi_bc.c and related files. +//! \todo [PUBS] Add definitions for TBDs in this file. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _DDI_BC_H +#define _DDI_BC_H + +//////////////////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////////////////// + +#include <mach/stmp3xxx_regs.h> + +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// +#define DDI_BC_MAX_RESTART_CYCLES 100 + +#define DDI_BC_LIION_CHARGING_VOLTAGE 4200 +#define DDI_BC_ALKALINE_NIMH_CHARGING_VOLTAGE 1750 + +//! \brief Defines battery charger states. +typedef enum _ddi_bc_State { + //! \brief TBD + DDI_BC_STATE_UNINITIALIZED = 0, + //! \brief TBD + DDI_BC_STATE_BROKEN = 1, + //! \brief TBD + DDI_BC_STATE_DISABLED = 2, + //! \brief TBD + DDI_BC_STATE_WAITING_TO_CHARGE = 3, + //! \brief TBD + DDI_BC_STATE_CONDITIONING = 4, + //! \brief TBD + DDI_BC_STATE_CHARGING = 5, + //! \brief TBD + DDI_BC_STATE_TOPPING_OFF = 6, + //! \brief TBD + DDI_BC_STATE_DCDC_MODE_WAITING_TO_CHARGE = 7, + +} ddi_bc_State_t; + +typedef enum _ddi_bc_BrokenReason { + //! \brief TBD + DDI_BC_BROKEN_UNINITIALIZED = 0, + //! \brief TBD + DDI_BC_BROKEN_CHARGING_TIMEOUT = 1, + //! \brief TBD + DDI_BC_BROKEN_FORCED_BY_APPLICATION = 2, + //! \brief TBD + DDI_BC_BROKEN_EXTERNAL_BATTERY_VOLTAGE_DETECTED = 3, + //! \brief TBD + DDI_BC_BROKEN_NO_BATTERY_DETECTED = 4, + +} ddi_bc_BrokenReason_t; + +//! \brief Defines the battery charger configuration. +typedef struct _ddi_bc_Cfg { + //! \brief Units in milliseconds. + //! + //! This field configures the expected period between calls to + //! ddi_bc_StateMachine. If die temperature monitoring is + //! enabled, then the data sheet recommends the period be around + //! 100ms or less. + //! + //! Note that this period defines the minimum time resolution of + //! the battery charger. + + uint32_t u32StateMachinePeriod; + + //! \brief Units in mA/s. + //! + //! This field configures the slope of the current ramp. Any + //! time the battery charger increases its current draw, it will + //! ramp up the current no faster than this rate. + //! + //! Note that the minimum time resolution of the battery charger + //! is the configured period between calls to advance the state + //! machine. Also, the hardware has a minimum current resolution + //! of 10mA. If the given ramp slope cannot be expressed + //! exactly, then the largest expressible smaller slope will be + //! the result. If the actual period between calls to + //! ddi_bc_StateMachine is irregular, the current may ramp faster + //! than indicated. + + uint16_t u16CurrentRampSlope; + + //! \brief Units in millivolts. + //! + //! This field configures the threshold conditioning voltage. If + //! the battery’s voltage is below this value, it will be + //! conditioned until its voltage rises above the maximum + //! conditioning voltage. After that, the battery will be + //! charged normally. + //! + //! Note that the hardware has a minimum resolution of 8mV. If + //! the given voltage cannot be expressed exactly, then the + //! smallest expressible larger value will be used. + + uint16_t u16ConditioningThresholdVoltage; + + //! \brief Units in millivolts. + //! + //! This field configures the maximum conditioning voltage. If + //! the battery charger is conditioning a battery, normal + //! charging begins when the voltage rises above this value. + //! + //! This value should be slightly higher than the threshold + //! conditioning voltage because it is measured while a + //! conditioning current is actually flowing to the battery. + //! With a conditioning current of 0.1C, reasonable values for + //! the threshold and maximum conditioning voltages are 2.9V + //! and 3.0V respectively. + //! + //! Note that the hardware has a minimum resolution of 8mV. If + //! the given voltage cannot be expressed exactly, then the + //! smallest expressible larger value will be used. + + uint16_t u16ConditioningMaxVoltage; + + //! \brief Units in milliamps. + //! + //! This field configures the maximum conditioning current. + //! This is the maximum current that will be offered to a + //! battery while it is being conditioned. A typical value is + //! 0.1C. + //! + //! Note that the hardware has a minimum resolution of 10mA + //! (see the data sheet for details). If the given current + //! cannot be expressed exactly, then the largest expressible + //! smaller value will be used. + + uint16_t u16ConditioningCurrent; + + //! \brief Units in milliseconds. + //! + //! This field configures the conditioning time-out. This is + //! the maximum amount of time that a battery will be + //! conditioned before the battery charger declares it to be + //! broken. + //! + //! Note that the minimum time resolution of the battery + //! charger is the configured period between calls to advance + //! the state machine. If the given time-out cannot be + //! expressed exactly, then the shortest expressible longer + //! value will be used. + + uint32_t u32ConditioningTimeout; + + //! \brief Units in millivolts. + //! + //! This field configures the final charging voltage. At this + //! writing, only two values are permitted: 4100 or 4200. + + uint16_t u16ChargingVoltage; + + //! \brief Units in milliamps. + //! + //! This field configures the maximum current offered to a + //! charging battery. + //! + //! Note that the hardware has a minimum resolution of 10mA + //! (see the data sheet for details). If the given current + //! cannot be expressed exactly, then the largest expressible + //! smaller value will be used. + + uint16_t u16ChargingCurrent; + + //! \brief Units in milliamps. + //! + //! This field configures the current flow below which a + //! charging battery is regarded as fully charged (typical + //! 0.1C). At this point, the battery will be topped off. + //! + //! Note that the hardware has a minimum resolution of 10mA + //! (see the data sheet for details). If the given current + //! cannot be expressed exactly, then the largest expressible + //! smaller value will be used. + + uint16_t u16ChargingThresholdCurrent; + + //! \brief Units in milliamps. + //! + //! When charging while the DCDC converter's are enabled, the charger + //! is suppling current to both the battery and the Vbat input of the + //! DCDC converter. Once the total battery charger current falls + //! below this level, the charger will then stop charging until the + //! the battery voltage reaches the BC_LOW_DCDCMODE_BATTERY_VOLTAGE + //! threshold or until the DCDCs are no longer enabled. + //! + //! Typically, this value should be left at 180 to avoid the risk + //! of topping off the battery too long in DCDC mode and avoid + //! exceeding the BC_CHARGING_TIMEOUT time which would put the charger + //! driver in the broken state and completely disable charging. + //! + //! Note that the hardware has a minimum resolution of 10mA + //! (see the data sheet for details). If the given current + //! cannot be expressed exactly, then the largest expressible + //! smaller value will be used. + uint16_t u16DdcdModeChargingThresholdCurrent; + + //! \brief Units in milliseconds. + //! + //! This field configures the charging time-out. This is the + //! maximum amount of time that a battery will be charged + //! before the battery charger declares it to be broken. + //! + //! Note that the minimum time resolution of the battery + //! charger is the configured period between calls to advance + //! the state machine. If the given time-out cannot be + //! expressed exactly, then the shortest expressible longer + //! value will be used. + + uint32_t u32ChargingTimeout; + + //! \brief Units in milliseconds. + //! + //! This field configures the top-off period. This is the + //! amount of time a battery will be held in the Topping Off + //! state before it is declared fully charged. + //! + //! Note that the minimum time resolution of the battery + //! charger is the configured period between calls to advance + //! the state machine. If the given time-out cannot be + //! expressed exactly, then the shortest expressible longer + //! value will be used. + + uint32_t u32TopOffPeriod; + + //! \brief Units in milliseconds. + //! + //! This field configures the top-off period when the DCDC + //! converters are enabled. To avoid topping off the LiIon + //! battery too long and reducing it's long term capacity, + //! This time should be kept failry short. + //! + //! Note that the minimum time resolution of the battery + //! charger is the configured period between calls to advance + //! the state machine. If the given time-out cannot be + //! expressed exactly, then the shortest expressible longer + //! value will be used. + uint32_t u32DcdcModeTopOffPeriod; + + //! \brief Causes the battery charger to use an externally generated bias current + //! + //! If cleared, this causes the battery charger to use an + //! externally generated bias current, which is expected to be + //! quite precise. Otherwise, the battery charger will + //! generate a lesser-quality bias current internally. + + uint8_t useInternalBias:1; + + //! \brief Indicates that the battery charger is to monitor the die temperature. + //! + //! If set, this field indicates that the battery charger is to + //! monitor the die temperature. See below for fields that + //! configure the details. + + uint8_t monitorDieTemp:1; + + //! \brief Indicates that the battery charger is to monitor the battery temperature. + //! + //! If set, this field indicates that the battery charger is to + //! monitor the battery temperature. See below for fields that + //! configure the details. + + uint8_t monitorBatteryTemp:1; + + //! \brief Units in degrees centigrade. + //! + //! Note that the hardware reports die temperature in ranges of + //! 10 degree resolution minimum (see the data sheet for + //! details). If the battery charger is monitoring the die + //! temperature, and it rises to a range that includes a + //! temperature greater than or equal to this value, the + //! charging current will be clamped to the safe current. + + int8_t u8DieTempHigh; + + //! \brief Units in degrees centigrade. + //! + //! Note that the hardware reports die temperature in ranges of + //! 10 degrees minimum (see the data sheet for details). If the + //! charging current is being clamped because of a high die + //! temperature, and it falls to a range that doesn’t include a + //! temperatures greater than or equal to this value, the + //! charging current clamp will be released. + + int8_t u8DieTempLow; + + //! \brief Units in milliamps. + //! + //! If the battery charger detects a high die temperature, it + //! will clamp the charging current at or below this value. + + uint16_t u16DieTempSafeCurrent; + + //! \brief If the battery charger is monitoring the battery + //! temperature, this field indicates the LRADC channel to + //! read. + + uint8_t u8BatteryTempChannel; + + //! \brief If the battery charger is monitoring the battery + //! temperature, and it rises to a measurement greater than or + //! equal to this value, the charging current will be clamped + //! to the corresponding safe current. + + uint16_t u16BatteryTempHigh; + + //! \brief If the charging current is being clamped because of a high + //! battery temperature, and it falls below this value, the + //! charging current clamp will be released. + + uint16_t u16BatteryTempLow; + + //! \brief Units in milliamps. + //! + //! If the battery charger detects a high battery temperature, + //! it will clamp the charging current at or below this value. + + uint16_t u16BatteryTempSafeCurrent; + + //! \brief Units in millivolts. + //! + //! In the WaitingToCharge state, if we are in DCDC + //! operating modes, if the battery voltage measurement + //! is below this value, we immediately proceed with charging. + //! the low criteria for this value is that it must be high + //! to not risk the battery voltage getting too low. The + //! upper criteria is that you do not want the IR voltage + //! drop under heavy loads to make you start charging too soon + //! because the goal in DCDC operating mode is to not be constantly + //! topping off the battery which can shorten its life + + uint16_t u16LowDcdcBatteryVoltage_mv; + + uint32_t u32StateMachineNonChargingPeriod; +} ddi_bc_Cfg_t; + +//! Status returned by Battery Charger functions. + +typedef enum _ddi_bc_Status { + //! \brief TBD + DDI_BC_STATUS_SUCCESS = 0, + //! \brief TBD + DDI_BC_STATUS_HARDWARE_DISABLED, + //! \brief TBD + DDI_BC_STATUS_BAD_BATTERY_MODE, + //! \brief TBD + DDI_BC_STATUS_CLOCK_GATE_CLOSED, + //! \brief TBD + DDI_BC_STATUS_NOT_INITIALIZED, + //! \brief TBD + DDI_BC_STATUS_ALREADY_INITIALIZED, + //! \brief TBD + DDI_BC_STATUS_BROKEN, + //! \brief TBD + DDI_BC_STATUS_NOT_BROKEN, + //! \brief TBD + DDI_BC_STATUS_NOT_DISABLED, + //! \brief TBD + DDI_BC_STATUS_BAD_ARGUMENT, + //! \brief TBD + DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL, + //! \brief TBD + DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE, +} ddi_bc_Status_t; + +///////////////////////////////////////////////////////////////////////////////// +// BCM Event Codes +// +// These are the codes that might be published to PMI Subscribers. +///////////////////////////////////////////////////////////////////////////////// + +#define DDI_BC_EVENT_GROUP (11<<10) + +//! \brief TBD +//! \todo [PUBS] Add definition(s)... +typedef enum { + // Use the error code group value to make events unique for the EOI + //! \brief TBD + ddi_bc_MinEventCode = DDI_BC_EVENT_GROUP, + //! \brief TBD + ddi_bc_WaitingToChargeCode, + //! \brief TBD + ddi_bc_State_ConditioningCode, + //! \brief TBD + ddi_bc_State_Topping_OffCode, + //! \brief TBD + ddi_bc_State_BrokenCode, + //! \brief TBD + ddi_bc_SettingChargeCode, + //! \brief TBD + ddi_bc_RaisingDieTempAlarmCode, + //! \brief TBD + ddi_bc_DroppingDieTempAlarmCode, + + //! \brief TBD + ddi_bc_MaxEventCode, + //! \brief TBD + ddi_bc_DcdcModeWaitingToChargeCode +} ddi_bc_Event_t; + +//////////////////////////////////////////////////////////////////////////////// +// Prototypes +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! \brief Initialize the Battery Charger. +//! +//! \fntype Function +//! +//! This function initializes the Battery Charger. +//! +//! \param[in] pCfg A pointer to the new configuration. +//! +//! \retval DDI_BC_STATUS_SUCCESS +//! If the operation succeeded. +//! \retval DDI_BC_STATUS_ALREADY_INITIALIZED +//! If the Battery Charger is already initialized. +//! \retval DDI_BC_STATUS_HARDWARE_DISABLED +//! If the Battery Charger hardware is disabled by a laser fuse. +//! \retval DDI_BC_STATUS_BAD_BATTERY_MODE +//! If the power supply is set up for a non-rechargeable battery. +//! \retval DDI_BC_STATUS_CLOCK_GATE_CLOSED +//! If the clock gate for the power supply registers is closed. +//! \retval DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE +//! If the charging voltage is not either 4100 or 4200. +//! \retval DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL +//! If the LRADC channel number for monitoring battery temperature +//! is bad. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_init.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_Init(ddi_bc_Cfg_t * pCfg); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the Battery Charger configuration. +//! +//! \fntype Function +//! +//! This function reports the Battery Charger configuration. +//! +//! Note that, if the Battery Charger has not yet been initialized, the data +//! returned by this function is unknown. +//! +//! \param[in,out] pCfg A pointer to a structure that will receive the data. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern void ddi_bc_QueryCfg(ddi_bc_Cfg_t * pCfg); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Shut down the Battery Charger. +//! +//! \fntype Function +//! +//! This function immediately shuts down the Battery Charger hardware and +//! returns the state machine to the Uninitialized state. Use this function to +//! safely “mummify” the battery charger before retiring it from memory. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern void ddi_bc_ShutDown(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Advances the state machine. +//! +//! \fntype Function +//! +//! This function advances the state machine. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! \retval DDI_BC_STATUS_BROKEN If the battery violated a time-out +//! and has been declared broken. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_StateMachine(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Get the Battery Charger's current state. +//! +//! \fntype Function +//! +//! This function returns the current state. +//! +//! \retval The current state. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_State_t ddi_bc_GetState(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Disable the Battery Charger. +//! +//! \fntype Function +//! +//! This function forces the Battery Charger into the Disabled state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_SetDisable(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Enable the Battery Charger. +//! +//! \fntype Function +//! +//! If the Battery Charger is in the Disabled state, this function moves it to +//! the Waiting to Charge state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! \retval DDI_BC_STATUS_NOT_DISABLED If the Battery Charger is not +//! disabled. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_SetEnable(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Declare the battery to be broken. +//! +//! \fntype Function +//! +//! This function forces the Battery Charger into the Broken state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_SetBroken(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Declare the battery to be fixed. +//! +//! \fntype Function +//! +//! If the Battery Charger is in the Broken state, this function moves it to +//! the Disabled state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! \retval DDI_BC_STATUS_NOT_BROKEN If the Battery Charger is not broken. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_SetFixed(void); +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the current limit. +//! +//! \fntype Function +//! +//! This function applies a limit to the current that the Battery Charger can +//! draw. +//! +//! \param[in] u16Limit The maximum current the Battery Charger can draw +//! (in mA). +//! +//! \retval The expressible version of the limit. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern uint16_t ddi_bc_SetCurrentLimit(uint16_t u16Limit); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the current limit. +//! +//! \fntype Function +//! +//! This function reports the limit to the current that the Battery Charger can +//! draw. +//! +//! \retval The current limit. +//! +//! \internal +//! \see To view the function definition, see ddi_bc_api.c. +//////////////////////////////////////////////////////////////////////////////// +extern uint16_t ddi_bc_GetCurrentLimit(void); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the current threshold. +//! +//! \fntype Function +//! +//! +//! \param[in] u16Current Current threshold where charger deactivates (in mA). +//! +//! +//////////////////////////////////////////////////////////////////////////////// +extern uint16_t ddi_bc_SetCurrentThreshold(uint16_t u16Current); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the battery charger state machine period. +//! +//! \fntype Function +//! +//! This function sets a new state machine period. The Period and Slope should +//! be coordinated to achieve the minimal ramp step current which will minimize +//! transients on the system. +//! +//! \param[in] u32StateMachinePeriod (in milliseconds) +//! \param[in] u16CurrentRampSlope (in mA/s) +//! +//! \retval SUCCESS If all goes well +//! \retval ERROR_DDI_BCM_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//////////////////////////////////////////////////////////////////////////////// +extern ddi_bc_Status_t ddi_bc_SetNewPeriodAndSlope(uint32_t + u32StateMachinePeriod, + uint16_t + u16CurrentRampSlope); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the state machine period. +//! +//! \fntype Function +//! +//! This function reports the battery charger period. +//! +//! \retval The battery charger period (in milliseconds). +//! +//////////////////////////////////////////////////////////////////////////////// +extern uint32_t ddi_bc_GetStateMachinePeriod(void); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the current ramp slope. +//! +//! \fntype Function +//! +//! This function reports the current ramp slope. +//! +//! \retval The current ramp slope (in mA/s). +//! +//////////////////////////////////////////////////////////////////////////////// +extern uint32_t ddi_bc_GetCurrentRampSlope(void); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the time spent in the present state (milliseconds) +//! +//! \fntype Function +//! +//! This function reports the time spent in the present charging state. Note that +//! for the states that actually charge the battery, this time does not include the +//! time spent under alarm conditions such as die termperature alarm or battery +//! temperature alarm. +//! +//! \retval The time spent in the current state in milliseconds. +//! +//////////////////////////////////////////////////////////////////////////////// +uint32_t ddi_bc_GetStateTime(void); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the reason for being in the broken state +//! +//! \fntype Function +//! +//! +//! \retval ddi_bc_BrokenReason_t enumeration +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_BrokenReason_t ddi_bc_GetBrokenReason(void); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Restart the charge cycle +//! +//! \fntype Function +//! +//! \retval SUCCESS +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_ForceChargingToStart(void); + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +#endif // _DDI_BC_H +//! @} diff --git a/arch/arm/mach-stmp3xxx/include/mach/debug-macro.S b/arch/arm/mach-stmp3xxx/include/mach/debug-macro.S new file mode 100644 index 000000000000..c354e4e0cb72 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/debug-macro.S @@ -0,0 +1,38 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x80000000 @ physical base address + addeq \rx, \rx, #0x00070000 + movne \rx, #0xf0000000 @ virtual base + addne \rx, \rx, #0x00070000 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #0] @ data register at 0 + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy + bne 1001b + .endm diff --git a/arch/arm/mach-stmp3xxx/include/mach/dma.h b/arch/arm/mach-stmp3xxx/include/mach/dma.h new file mode 100644 index 000000000000..cc500ea3f053 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/dma.h @@ -0,0 +1,161 @@ +/* + * Freescale STMP37XX/STMP378X DMA helper interface + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_STMP3XXX_DMA_H +#define __ASM_PLAT_STMP3XXX_DMA_H + +#include <linux/platform_device.h> +#include <linux/dmapool.h> + +#if !defined(MAX_PIO_WORDS) +#define MAX_PIO_WORDS (15) +#endif + +#define STMP3XXX_BUS_APBH 0 +#define STMP3XXX_BUS_APBX 1 +#define STMP3XXX_DMA_MAX_CHANNEL 16 + + +#define STMP3xxx_DMA(channel, bus) ((bus) * 16 + (channel)) + +struct stmp3xxx_dma_command { + u32 next; + u32 cmd; + union { + u32 buf_ptr; + u32 alternate; + }; + u32 pio_words[MAX_PIO_WORDS]; +}; + +struct stmp3xxx_dma_descriptor { + struct stmp3xxx_dma_command *command; + dma_addr_t handle; + + /* The virtual address of the buffer pointer */ + void *virtual_buf_ptr; + /* The next descriptor in a the DMA chain (optional) */ + struct stmp3xxx_dma_descriptor *next_descr; +}; + +struct stmp37xx_circ_dma_chain { + unsigned total_count; + struct stmp3xxx_dma_descriptor *chain; + + unsigned free_index; + unsigned free_count; + unsigned active_index; + unsigned active_count; + unsigned cooked_index; + unsigned cooked_count; + + int bus; + unsigned channel; +}; + +static inline struct stmp3xxx_dma_descriptor + *stmp3xxx_dma_circ_get_free_head(struct stmp37xx_circ_dma_chain *chain) +{ + return &(chain->chain[chain->free_index]); +} + +static inline struct stmp3xxx_dma_descriptor + *stmp3xxx_dma_circ_get_cooked_head(struct stmp37xx_circ_dma_chain *chain) +{ + return &(chain->chain[chain->cooked_index]); +} + +int stmp3xxx_dma_request(int ch, struct device *dev, char *name); +int stmp3xxx_dma_release(int ch); +int stmp3xxx_dma_allocate_command(int ch, + struct stmp3xxx_dma_descriptor *descriptor); +int stmp3xxx_dma_free_command(int ch, + struct stmp3xxx_dma_descriptor *descriptor); +void stmp3xxx_dma_continue(int channel, u32 semaphore); +void stmp3xxx_dma_go(int ch, struct stmp3xxx_dma_descriptor *head, + u32 semaphore); +int stmp3xxx_dma_running(int ch); +int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain, + struct stmp3xxx_dma_descriptor descriptors[], + unsigned items); +void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain); +void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain); +void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain, + unsigned count); +void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain, + unsigned count); +unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain); +int stmp3xxx_dma_read_semaphore(int ch); +void stmp3xxx_dma_init(void); +void stmp3xxx_dma_set_alt_target(int ch, int target); +void stmp3xxx_dma_suspend(void); +void stmp3xxx_dma_resume(void); + +/* + * STMP37xx and STMP378x have different DMA control + * registers layout + */ + +void stmp3xxx_arch_dma_freeze(int ch); +void stmp3xxx_arch_dma_unfreeze(int ch); +void stmp3xxx_arch_dma_reset_channel(int ch); +void stmp3xxx_arch_dma_enable_interrupt(int ch); +void stmp3xxx_arch_dma_clear_interrupt(int ch); +int stmp3xxx_arch_dma_is_interrupt(int ch); + +static inline void stmp3xxx_dma_reset_channel(int ch) +{ + stmp3xxx_arch_dma_reset_channel(ch); +} + + +static inline void stmp3xxx_dma_freeze(int ch) +{ + stmp3xxx_arch_dma_freeze(ch); +} + +static inline void stmp3xxx_dma_unfreeze(int ch) +{ + stmp3xxx_arch_dma_unfreeze(ch); +} + +static inline void stmp3xxx_dma_enable_interrupt(int ch) +{ + stmp3xxx_arch_dma_enable_interrupt(ch); +} + +static inline void stmp3xxx_dma_clear_interrupt(int ch) +{ + stmp3xxx_arch_dma_clear_interrupt(ch); +} + +static inline int stmp3xxx_dma_is_interrupt(int ch) +{ + return stmp3xxx_arch_dma_is_interrupt(ch); +} + +#define MAX_DMA_ADDRESS 0xffffffff + +#define MAX_DMA_CHANNELS 32 + +/* + * Channel number on the APBX bus + */ + +#define STMP378X_APBX_I2C 3 + +#endif /* __ASM_PLAT_STMP3XXX_DMA_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/entry-macro.S b/arch/arm/mach-stmp3xxx/include/mach/entry-macro.S new file mode 100644 index 000000000000..731a92286da2 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/entry-macro.S @@ -0,0 +1,35 @@ +/* + * Low-level IRQ helper macros for Freescale STMP378X + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + mov \base, #0xf0000000 @ vm address of IRQ controller + ldr \irqnr, [\base, #0x70] @ HW_ICOLL_STAT + cmp \irqnr, #0x7f + moveqs \irqnr, #0 @ Zero flag set for no IRQ + + .endm + + .macro get_irqnr_preamble, base, tmp + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm diff --git a/arch/arm/mach-stmp3xxx/include/mach/gpio.h b/arch/arm/mach-stmp3xxx/include/mach/gpio.h new file mode 100644 index 000000000000..2dedc05cd7c0 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/gpio.h @@ -0,0 +1,29 @@ +/* + * Freescale STMP37XX/STMP378X GPIO interface + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_GPIO_H +#define __ASM_ARCH_GPIO_H + +extern int gpio_request(unsigned gpio, char *label); +extern void gpio_free(unsigned gpio); +extern void gpio_set_value(unsigned gpio, int value); +extern int gpio_get_value(unsigned gpio); +extern int gpio_to_irq(unsigned gpio); +extern void gpio_direction_input(unsigned id); +extern void gpio_direction_output(unsigned id, int value); + +#endif /* __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/gpmi.h b/arch/arm/mach-stmp3xxx/include/mach/gpmi.h new file mode 100644 index 000000000000..e3c00f02cfe4 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/gpmi.h @@ -0,0 +1,45 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * Arch-dependent structure and functions declarations + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_GPMI_H +#define __ASM_PLAT_GPMI_H + +#define GPMI_PART_CONCAT 0x8000 /* indicates that partitions + should be concatenated */ +extern int gpmi_pinmux_request(char *); +extern void gpmi_pinmux_free(char *); + +struct gpmi_platform_data { + + u_int32_t uid_offset; + u_int32_t uid_size; + + int items; + int io_uA; + char *concat_name; + char **concat_parts; + + struct { + const char **part_probe_types; + int nr_partitions; + struct mtd_partition *partitions; + } parts[]; + +}; +#endif /* __ASM_PLAT_GPMI_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/hardware.h b/arch/arm/mach-stmp3xxx/include/mach/hardware.h new file mode 100644 index 000000000000..095834f23d0a --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/hardware.h @@ -0,0 +1,32 @@ +/* + * This file contains the hardware definitions of the Freescale STMP378X + * + * Copyright (C) 2005 Sigmatel Inc + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +/* + * Where in virtual memory the IO devices (timers, system controllers + * and so on) + */ +#define IO_BASE 0xF0000000 /* VA of IO */ +#define IO_SIZE 0x00100000 /* How much? */ +#define IO_START 0x80000000 /* PA of IO */ + +/* macro to get at IO space when running virtually */ +#define IO_ADDRESS(x) (((x) & 0x000fffff) + IO_BASE) + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/i2c.h b/arch/arm/mach-stmp3xxx/include/mach/i2c.h new file mode 100644 index 000000000000..05a57f6351e3 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/i2c.h @@ -0,0 +1,48 @@ +/* + * Freescale STMP378X I2C low-level/dma functions + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef _ARM_ARCH_I2C_H +#define _ARM_ARCH_I2C_H + +#include <linux/device.h> +#include <linux/module.h> + +#include <linux/completion.h> +#include <linux/i2c.h> + +#define I2C_READ 1 +#define I2C_WRITE 0 + +void hw_i2c_clear_dma_interrupt(void); +int hw_i2c_init(struct device *dev); +void hw_i2c_stop(struct device *dev); +void hw_i2c_setup_write(u8 addr, void *buff, int len, int flags); +void hw_i2c_setup_read(u8 addr, void *buff, int len, int flags); +void hw_i2c_run(int dir); +void hw_i2c_reset_dma(void); +void hw_i2c_finish_read(void *buff, int len); + +struct stmp378x_i2c_dev { + struct device *dev; + int irq_dma; + int irq_err; + struct completion cmd_complete; + u32 cmd_err; + struct i2c_adapter adapter; +}; + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/io.h b/arch/arm/mach-stmp3xxx/include/mach/io.h new file mode 100644 index 000000000000..4cd92cf9c4f3 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/io.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005 Sigmatel Inc + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +static inline void __iomem *__io(unsigned long addr) +{ + return (void __iomem *)addr; +} +#define __io(a) __io(a) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/irqs.h b/arch/arm/mach-stmp3xxx/include/mach/irqs.h new file mode 100644 index 000000000000..27e63917f3f6 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/irqs.h @@ -0,0 +1,94 @@ +/* + * Freescale STMP378X interrupts + * + * Copyright (C) 2005 Sigmatel Inc + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#define IRQ_DEBUG_UART 0 +#define IRQ_COMMS_RX 1 +#define IRQ_COMMS_TX 1 +#define IRQ_SSP2_ERROR 2 +#define IRQ_VDD5V 3 +#define IRQ_HEADPHONE_SHORT 4 +#define IRQ_DAC_DMA 5 +#define IRQ_DAC_ERROR 6 +#define IRQ_ADC_DMA 7 +#define IRQ_ADC_ERROR 8 +#define IRQ_SPDIF_DMA 9 +#define IRQ_SAIF2_DMA 9 +#define IRQ_SPDIF_ERROR 10 +#define IRQ_SAIF1_IRQ 10 +#define IRQ_SAIF2_IRQ 10 +#define IRQ_USB_CTRL 11 +#define IRQ_USB_WAKEUP 12 +#define IRQ_GPMI_DMA 13 +#define IRQ_SSP1_DMA 14 +#define IRQ_SSP_ERROR 15 +#define IRQ_GPIO0 16 +#define IRQ_GPIO1 17 +#define IRQ_GPIO2 18 +#define IRQ_SAIF1_DMA 19 +#define IRQ_SSP2_DMA 20 +#define IRQ_ECC8_IRQ 21 +#define IRQ_RTC_ALARM 22 +#define IRQ_UARTAPP_TX_DMA 23 +#define IRQ_UARTAPP_INTERNAL 24 +#define IRQ_UARTAPP_RX_DMA 25 +#define IRQ_I2C_DMA 26 +#define IRQ_I2C_ERROR 27 +#define IRQ_TIMER0 28 +#define IRQ_TIMER1 29 +#define IRQ_TIMER2 30 +#define IRQ_TIMER3 31 +#define IRQ_BATT_BRNOUT 32 +#define IRQ_VDDD_BRNOUT 33 +#define IRQ_VDDIO_BRNOUT 34 +#define IRQ_VDD18_BRNOUT 35 +#define IRQ_TOUCH_DETECT 36 +#define IRQ_LRADC_CH0 37 +#define IRQ_LRADC_CH1 38 +#define IRQ_LRADC_CH2 39 +#define IRQ_LRADC_CH3 40 +#define IRQ_LRADC_CH4 41 +#define IRQ_LRADC_CH5 42 +#define IRQ_LRADC_CH6 43 +#define IRQ_LRADC_CH7 44 +#define IRQ_LCDIF_DMA 45 +#define IRQ_LCDIF_ERROR 46 +#define IRQ_DIGCTL_DEBUG_TRAP 47 +#define IRQ_RTC_1MSEC 48 +#define IRQ_DRI_DMA 49 +#define IRQ_DRI_ATTENTION 50 +#define IRQ_GPMI_ATTENTION 51 +#define IRQ_IR 52 +#define IRQ_DCP_VMI 53 +#define IRQ_DCP 54 +#define IRQ_BCH 56 +#define IRQ_PXP 57 +#define IRQ_UARTAPP2_TX_DMA 58 +#define IRQ_UARTAPP2_INTERNAL 59 +#define IRQ_UARTAPP2_RX_DMA 60 +#define IRQ_VDAC_DETECT 61 +#define IRQ_VDD5V_DROOP 64 +#define IRQ_DCDC4P2_BO 65 + + +#define NR_IRQS 128 + +/* All interrupts are FIQ capable */ +#define FIQ_START IRQ_DEBUG_UART + +/* Hard disk IRQ is a GPMI attention IRQ */ +#define IRQ_HARDDISK IRQ_GPMI_ATTENTION diff --git a/arch/arm/mach-stmp3xxx/include/mach/lcdif.h b/arch/arm/mach-stmp3xxx/include/mach/lcdif.h new file mode 100644 index 000000000000..1bdadff8713a --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/lcdif.h @@ -0,0 +1,430 @@ +/* + * Freescale STMP378X LCDIF interfaces + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef _ARCH_ARM_LCDIF_H +#define _ARCH_ARM_LCDIF_H + +#include <linux/types.h> +#include <linux/fb.h> +#include <linux/list.h> +#include <linux/backlight.h> +#include <linux/dma-mapping.h> +#include <linux/regulator/consumer.h> +#include "dma.h" + +#include "regs-lcdif.h" +#include "regs-apbh.h" + +enum { + SPI_MOSI = 0, + SPI_SCLK, + SPI_CS, +}; + +struct stmp3xxx_lcd_dma_chain_info { + dma_addr_t *dma_addr_p; + unsigned offset; +}; + + +enum { + STMP3XXX_LCD_PANEL_SYSTEM = 0, + STMP3XXX_LCD_PANEL_VSYNC, + STMP3XXX_LCD_PANEL_DOTCLK, + STMP3XXX_LCD_PANEL_DVI, +}; + +struct stmp3xxx_platform_bl_data; +struct stmp3xxx_platform_fb_entry { + char name[16]; + u16 x_res; + u16 y_res; + u16 bpp; + u32 cycle_time_ns; + int lcd_type; + int (*init_panel)(struct device *dev, dma_addr_t phys, int memsize, + struct stmp3xxx_platform_fb_entry *pentry); + void (*release_panel)(struct device *dev, + struct stmp3xxx_platform_fb_entry *pentry); + int (*blank_panel)(int blank); + void (*run_panel)(void); + void (*stop_panel)(void); + int (*pan_display)(dma_addr_t phys); + int (*update_panel)(void *p, struct stmp3xxx_platform_fb_entry *pentry); + struct list_head link; + struct stmp3xxx_platform_bl_data *bl_data; +}; + +struct stmp3xxx_platform_fb_data { + struct list_head list; + struct stmp3xxx_platform_fb_entry *cur; +}; + +#define STMP3XXX_LCDIF_PANEL_INIT 1 +#define STMP3XXX_LCDIF_PANEL_RELEASE 2 + +struct stmp3xxx_platform_bl_data { + struct list_head list; + struct regulator *regulator; + int bl_gpio; + int bl_max_intensity; + int bl_cons_intensity; + int bl_default_intensity; + int (*init_bl)(struct stmp3xxx_platform_bl_data *data); + int (*set_bl_intensity)(struct stmp3xxx_platform_bl_data *data, + struct backlight_device *bd, int suspended); + void (*free_bl)(struct stmp3xxx_platform_bl_data *data); +}; + +static inline void stmp3xxx_lcd_register_entry( + struct stmp3xxx_platform_fb_entry *pentry, + struct stmp3xxx_platform_fb_data *pdata) +{ + list_add_tail(&pentry->link, &pdata->list); + if (!pdata->cur) + pdata->cur = pentry; +} + +static inline void stmp3xxx_lcd_move_pentry_up( + struct stmp3xxx_platform_fb_entry *pentry, + struct stmp3xxx_platform_fb_data *pdata) +{ + list_del(&pentry->link); + list_add(&pentry->link, &pdata->list); +} + +static inline int stmp3xxx_lcd_iterate_pdata( + struct stmp3xxx_platform_fb_data *pdata, + int (*func)(struct stmp3xxx_platform_fb_entry *pentry, + void *data, + int ret_prev), + void *data) +{ + struct stmp3xxx_platform_fb_entry *pentry; + int ret = 0; + list_for_each_entry(pentry, &pdata->list, link) { + ret = func(pentry, data, ret); + } + return ret; +} + +static inline void stmp3xxx_lcd_set_bl_pdata( + struct stmp3xxx_platform_bl_data *pdata) +{ + extern struct platform_device stmp3xxx_backlight; + stmp3xxx_backlight.dev.platform_data = pdata; +} + +void stmp3xxx_init_lcdif(void); +int stmp3xxx_lcdif_dma_init(struct device *dev, dma_addr_t phys, int memsize, + int lcd_master); +void stmp3xxx_lcdif_dma_release(void); +void stmp3xxx_lcdif_run(void); +void stmp3xxx_lcdif_stop(void); +int stmp3xxx_lcdif_pan_display(dma_addr_t addr); + + +int stmp3xxx_lcdif_register_client(struct notifier_block *nb); +void stmp3xxx_lcdif_unregister_client(struct notifier_block *nb); +void stmp3xxx_lcdif_notify_clients(unsigned long event, + struct stmp3xxx_platform_fb_entry *pentry); + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) +#endif + +#define LCD_DMA_CHANNEL 0 + +static inline void setup_dotclk_panel(u16 v_pulse_width, + u16 v_period, + u16 v_wait_cnt, + u16 v_active, + u16 h_pulse_width, + u16 h_period, + u16 h_wait_cnt, + u16 h_active, + int enable_present) +{ + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_DATA_SHIFT_DIR); + + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_SHIFT_NUM_BITS); + + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT); + HW_LCDIF_CTRL1_SET(BF_LCDIF_CTRL1_BYTE_PACKING_FORMAT(7) | + BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW); + + HW_LCDIF_TRANSFER_COUNT_CLR(BM_LCDIF_TRANSFER_COUNT_H_COUNT | + BM_LCDIF_TRANSFER_COUNT_V_COUNT); + HW_LCDIF_TRANSFER_COUNT_SET(BF_LCDIF_TRANSFER_COUNT_H_COUNT(h_active) | + BF_LCDIF_TRANSFER_COUNT_V_COUNT(v_active)); + + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_VSYNC_MODE); + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE); + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_DVI_MODE); + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_DOTCLK_MODE); + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_BYPASS_COUNT); + + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_WORD_LENGTH | + BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE | + BM_LCDIF_CTRL_LCD_DATABUS_WIDTH); + HW_LCDIF_CTRL_SET(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ + BM_LCDIF_CTRL_DATA_SELECT | /* data mode */ + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ + BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3)); /* 24 bit */ + + HW_LCDIF_VDCTRL0_SET(BM_LCDIF_VDCTRL0_ENABLE_POL | + BM_LCDIF_VDCTRL0_DOTCLK_POL); + HW_LCDIF_VDCTRL0_CLR(BM_LCDIF_VDCTRL0_VSYNC_POL | + BM_LCDIF_VDCTRL0_HSYNC_POL); + + HW_LCDIF_VDCTRL0_CLR(BM_LCDIF_VDCTRL0_VSYNC_OEB); /* vsync is output */ + + /* + * need enable sig for true RGB i/f. Or, if not true RGB, leave it + * zero. + */ + HW_LCDIF_VDCTRL0_SET(BM_LCDIF_VDCTRL0_ENABLE_PRESENT); + + /* + * For DOTCLK mode, count VSYNC_PERIOD in terms of complete hz lines + */ + HW_LCDIF_VDCTRL0_SET(BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT | + BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT); + + HW_LCDIF_VDCTRL0_CLR(BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH); + HW_LCDIF_VDCTRL0_SET(v_pulse_width); + + HW_LCDIF_VDCTRL1_CLR(BM_LCDIF_VDCTRL1_VSYNC_PERIOD); + HW_LCDIF_VDCTRL1_SET(v_period); + + HW_LCDIF_VDCTRL2_CLR(BM_LCDIF_VDCTRL2_HSYNC_PERIOD | + BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH); + + HW_LCDIF_VDCTRL2_SET(BF_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(h_pulse_width) | + BF_LCDIF_VDCTRL2_HSYNC_PERIOD(h_period)); + + HW_LCDIF_VDCTRL4_CLR(BM_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT); + HW_LCDIF_VDCTRL4_SET( + BF_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(h_active)); + + HW_LCDIF_VDCTRL3_CLR(BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT | + BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT); + HW_LCDIF_VDCTRL3_SET(BF_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(h_wait_cnt) | + BF_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT(v_wait_cnt)); + + HW_LCDIF_VDCTRL4_SET(BM_LCDIF_VDCTRL4_SYNC_SIGNALS_ON); +} + +static inline void release_dotclk_panel(void) +{ + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_DOTCLK_MODE); + HW_LCDIF_VDCTRL0_WR(0); + HW_LCDIF_VDCTRL1_WR(0); + HW_LCDIF_VDCTRL2_WR(0); + HW_LCDIF_VDCTRL3_WR(0); +} + +static inline void dotclk_dma_chain_init(int memsize, dma_addr_t video_phys, + struct stmp3xxx_dma_descriptor *video_dma_descriptor, + struct stmp3xxx_lcd_dma_chain_info *dma_chain_info, + unsigned *dma_chain_info_pos) +{ + unsigned i, bytes_left; + dma_addr_t phys = video_phys; + bytes_left = memsize; + + for (i = 0; bytes_left > 0; ++i) { + unsigned this_chain = bytes_left < 0xff00 ? bytes_left : 0xff00; + /* Count of 0 in the DMA word means 65536 */ + unsigned xfer_count = this_chain & 65535; + stmp3xxx_dma_allocate_command( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), + &video_dma_descriptor[i]); + if (i != 0) { + /* Chain previous command to this one */ + video_dma_descriptor[i - 1].command->next = + video_dma_descriptor[i].handle; + /* Enable DMA chaining, disable IRQ and semaphore + * on previous command + */ + video_dma_descriptor[i - 1].command->cmd &= + ~(BM_APBH_CHn_CMD_IRQONCMPLT | + BM_APBH_CHn_CMD_SEMAPHORE); + } + video_dma_descriptor[i].command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(xfer_count) | + BF_APBH_CHn_CMD_CMDWORDS(1) | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(2); /* DMA read */ + video_dma_descriptor[i].command->pio_words[0] = + BM_LCDIF_CTRL_RUN | + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(1) | + BM_LCDIF_CTRL_DATA_SHIFT_DIR | + BM_LCDIF_CTRL_DOTCLK_MODE | + BM_LCDIF_CTRL_BYPASS_COUNT | + BM_LCDIF_CTRL_DATA_SELECT; + video_dma_descriptor[i].command->buf_ptr = phys; + dma_chain_info[*dma_chain_info_pos].dma_addr_p = + &video_dma_descriptor[i].command->buf_ptr; + dma_chain_info[*dma_chain_info_pos].offset = phys - video_phys; + ++*dma_chain_info_pos; + phys += this_chain; + bytes_left -= this_chain; + } + video_dma_descriptor[i-1].command->next = + video_dma_descriptor[0].handle; + pr_debug("%s: Used %u DMA chains to cover %u bytes\n", __func__, i, + memsize); +} + +static inline void setup_dvi_panel(u16 h_active, u16 v_active, + u16 h_blanking, u16 v_lines, + u16 v1_blank_start, u16 v1_blank_end, + u16 v2_blank_start, u16 v2_blank_end, + u16 f1_start, u16 f1_end, + u16 f2_start, u16 f2_end) +{ + /* 32bit packed format (RGB) */ + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT); + HW_LCDIF_CTRL1_SET(BF_LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x7) | + BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW); + + HW_LCDIF_TRANSFER_COUNT_CLR(BM_LCDIF_TRANSFER_COUNT_H_COUNT | + BM_LCDIF_TRANSFER_COUNT_V_COUNT); + HW_LCDIF_TRANSFER_COUNT_SET(BF_LCDIF_TRANSFER_COUNT_H_COUNT(h_active) | + BF_LCDIF_TRANSFER_COUNT_V_COUNT(v_active)); + + /* set lcdif to DVI mode */ + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_DVI_MODE); + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_VSYNC_MODE); + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_DOTCLK_MODE); + + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_BYPASS_COUNT); + /* convert input RGB -> YCbCr */ + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC); + /* interlace odd and even fields */ + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_INTERLACE_FIELDS); + + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_WORD_LENGTH | + BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE | + BM_LCDIF_CTRL_LCD_DATABUS_WIDTH); + HW_LCDIF_CTRL_SET(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ + BM_LCDIF_CTRL_DATA_SELECT | /* data mode */ + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ + BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(1)); /* 8 bit */ + + /* LCDIF_DVI */ + /* set frame size */ + HW_LCDIF_DVICTRL0_CLR(BM_LCDIF_DVICTRL0_H_ACTIVE_CNT | + BM_LCDIF_DVICTRL0_H_BLANKING_CNT | + BM_LCDIF_DVICTRL0_V_LINES_CNT); + HW_LCDIF_DVICTRL0_SET(BF_LCDIF_DVICTRL0_H_ACTIVE_CNT(1440) | + BF_LCDIF_DVICTRL0_H_BLANKING_CNT(h_blanking) | + BF_LCDIF_DVICTRL0_V_LINES_CNT(v_lines)); + + /* set start/end of field-1 and start of field-2 */ + HW_LCDIF_DVICTRL1_CLR(BM_LCDIF_DVICTRL1_F1_START_LINE | + BM_LCDIF_DVICTRL1_F1_END_LINE | + BM_LCDIF_DVICTRL1_F2_START_LINE); + HW_LCDIF_DVICTRL1_SET(BF_LCDIF_DVICTRL1_F1_START_LINE(f1_start) | + BF_LCDIF_DVICTRL1_F1_END_LINE(f1_end) | + BF_LCDIF_DVICTRL1_F2_START_LINE(f2_start)); + + /* set first vertical blanking interval and end of filed-2 */ + HW_LCDIF_DVICTRL2_CLR(BM_LCDIF_DVICTRL2_F2_END_LINE | + BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE | + BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE); + HW_LCDIF_DVICTRL2_SET(BF_LCDIF_DVICTRL2_F2_END_LINE(f2_end) | + BF_LCDIF_DVICTRL2_V1_BLANK_START_LINE( + v1_blank_start) | + BF_LCDIF_DVICTRL2_V1_BLANK_END_LINE( + v1_blank_end)); + + /* set second vertical blanking interval */ + HW_LCDIF_DVICTRL3_CLR(BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE | + BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE); + HW_LCDIF_DVICTRL3_SET(BF_LCDIF_DVICTRL3_V2_BLANK_START_LINE( + v2_blank_start) | + BF_LCDIF_DVICTRL3_V2_BLANK_END_LINE( + v2_blank_end)); + + /* fill the rest area black color if the input frame + * is not 720 pixels/line + */ + if (h_active != 720) { + /* the input frame can't be less then (720-256) pixels/line */ + if (720 - h_active > 0xff) + h_active = 720 - 0xff; + + HW_LCDIF_DVICTRL4_CLR(BM_LCDIF_DVICTRL4_H_FILL_CNT | + BM_LCDIF_DVICTRL4_Y_FILL_VALUE | + BM_LCDIF_DVICTRL4_CB_FILL_VALUE | + BM_LCDIF_DVICTRL4_CR_FILL_VALUE); + HW_LCDIF_DVICTRL4_SET(BF_LCDIF_DVICTRL4_H_FILL_CNT( + 720 - h_active) | + BF_LCDIF_DVICTRL4_Y_FILL_VALUE(16) | + BF_LCDIF_DVICTRL4_CB_FILL_VALUE(128) | + BF_LCDIF_DVICTRL4_CR_FILL_VALUE(128)); + } + + /* Color Space Conversion RGB->YCbCr */ + HW_LCDIF_CSC_COEFF0_CLR(BM_LCDIF_CSC_COEFF0_C0 | + BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER); + HW_LCDIF_CSC_COEFF0_SET(BF_LCDIF_CSC_COEFF0_C0(0x41) | + BF_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(3)); + + HW_LCDIF_CSC_COEFF1_CLR(BM_LCDIF_CSC_COEFF1_C1 | + BM_LCDIF_CSC_COEFF1_C2); + HW_LCDIF_CSC_COEFF1_SET(BF_LCDIF_CSC_COEFF1_C1(0x81) | + BF_LCDIF_CSC_COEFF1_C2(0x19)); + + HW_LCDIF_CSC_COEFF2_CLR(BM_LCDIF_CSC_COEFF2_C3 | + BM_LCDIF_CSC_COEFF2_C4); + HW_LCDIF_CSC_COEFF2_SET(BF_LCDIF_CSC_COEFF2_C3(0x3DB) | + BF_LCDIF_CSC_COEFF2_C4(0x3B6)); + + HW_LCDIF_CSC_COEFF3_CLR(BM_LCDIF_CSC_COEFF3_C5 | + BM_LCDIF_CSC_COEFF3_C6); + HW_LCDIF_CSC_COEFF3_SET(BF_LCDIF_CSC_COEFF3_C5(0x70) | + BF_LCDIF_CSC_COEFF3_C6(0x70)); + + HW_LCDIF_CSC_COEFF4_CLR(BM_LCDIF_CSC_COEFF4_C7 | + BM_LCDIF_CSC_COEFF4_C8); + HW_LCDIF_CSC_COEFF4_SET(BF_LCDIF_CSC_COEFF4_C7(0x3A2) | + BF_LCDIF_CSC_COEFF4_C8(0x3EE)); + + HW_LCDIF_CSC_OFFSET_CLR(BM_LCDIF_CSC_OFFSET_CBCR_OFFSET | + BM_LCDIF_CSC_OFFSET_Y_OFFSET); + HW_LCDIF_CSC_OFFSET_SET(BF_LCDIF_CSC_OFFSET_CBCR_OFFSET(0x80) | + BF_LCDIF_CSC_OFFSET_Y_OFFSET(0x10)); + + HW_LCDIF_CSC_LIMIT_CLR(BM_LCDIF_CSC_LIMIT_CBCR_MIN | + BM_LCDIF_CSC_LIMIT_CBCR_MAX | + BM_LCDIF_CSC_LIMIT_Y_MIN | + BM_LCDIF_CSC_LIMIT_Y_MAX); + HW_LCDIF_CSC_LIMIT_SET(BF_LCDIF_CSC_LIMIT_CBCR_MIN(16) | + BF_LCDIF_CSC_LIMIT_CBCR_MAX(240) | + BF_LCDIF_CSC_LIMIT_Y_MIN(16) | + BF_LCDIF_CSC_LIMIT_Y_MAX(235)); +} + +static inline void release_dvi_panel(void) +{ + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_DVI_MODE); +} + +#endif /* _ARCH_ARM_LCDIF_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/lradc.h b/arch/arm/mach-stmp3xxx/include/mach/lradc.h new file mode 100644 index 000000000000..56b686896f29 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/lradc.h @@ -0,0 +1,60 @@ +/* + * Freescale STMP37XX/STMP378X LRADC helper interface + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_LRADC_H +#define __ASM_PLAT_LRADC_H + +int hw_lradc_use_channel(int); +int hw_lradc_unuse_channel(int); +extern u32 hw_lradc_vddio(void); +void hw_lradc_set_delay_trigger_kick(int trigger, int value); +void hw_lradc_configure_channel(int channel, int enable_div2, + int enable_acc, int samples); +int hw_lradc_present(int channel); +int hw_lradc_init_ladder(int channel, int trigger, unsigned sampling); +int hw_lradc_stop_ladder(int channel, int trigger); +void hw_lradc_set_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers, u32 loops, u32 delays); +void hw_lradc_clear_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers); + + +#define LRADC_CH0 0 +#define LRADC_CH1 1 +#define LRADC_CH2 2 +#define LRADC_CH3 3 +#define LRADC_CH4 4 +#define LRADC_CH5 5 +#define LRADC_CH6 6 +#define LRADC_CH7 7 +#define LRADC_TOUCH_X_PLUS LRADC_CH2 +#define LRADC_TOUCH_Y_PLUS LRADC_CH3 +#define LRADC_TOUCH_X_MINUS LRADC_CH4 +#define LRADC_TOUCH_Y_MINUS LRADC_CH5 +#define VDDIO_VOLTAGE_CH LRADC_CH6 +#define BATTERY_VOLTAGE_CH LRADC_CH7 + +#define LRADC_CLOCK_6MHZ 0 +#define LRADC_CLOCK_4MHZ 1 +#define LRADC_CLOCK_3MHZ 2 +#define LRADC_CLOCK_2MHZ 3 + +#define LRADC_DELAY_TRIGGER_BUTTON 0 +#define LRADC_DELAY_TRIGGER_BATTERY 1 +#define LRADC_DELAY_TRIGGER_TOUCHSCREEN 2 + +#endif /* __ASM_PLAT_LRADC_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/memory.h b/arch/arm/mach-stmp3xxx/include/mach/memory.h new file mode 100644 index 000000000000..e6ea91270d62 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/memory.h @@ -0,0 +1,37 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* + * Physical DRAM offset. + */ +#define PHYS_OFFSET UL(0x40000000) +#define BUS_OFFSET UL(0x40000000) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt(x) __phys_to_virt(x) + +#define ISA_DMA_THRESHOLD (0x0003ffffULL) + +#define CONSISTENT_DMA_SIZE SZ_4M + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/ocram-malloc.h b/arch/arm/mach-stmp3xxx/include/mach/ocram-malloc.h new file mode 100644 index 000000000000..c8bee5352972 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/ocram-malloc.h @@ -0,0 +1,26 @@ +/* + * Freescale STMP37XX/STMP378X OCRAM allocator interface + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_OCRAM_MALLOC_H +#define __ASM_PLAT_OCRAM_MALLOC_H + +extern int ocram_malloc_init(void); + +extern void *ocram_malloc(size_t size, dma_addr_t *phys); +extern void ocram_free(void *tofree); + +#endif /* __ASM_PLAT_OCRAM_MALLOC_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/pins.h b/arch/arm/mach-stmp3xxx/include/mach/pins.h new file mode 100644 index 000000000000..e651a82f2cc1 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/pins.h @@ -0,0 +1,177 @@ +/* + * Freescale STMP378X SoC pin multiplexing + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_PINS_H +#define __ASM_ARCH_PINS_H + +/* + * The number of pin banks and pins per a bank on STMP378x + */ +#define STMP3XXX_PINMUX_NR_BANKS 4 +#define STMP3XXX_PINMUX_BANK_SIZE 32 + +/* + * Macro to convert a pin bank/number pair to a raw pin number + * STMP3XXX_PINMUX_BANK_SIZE and STMP3XXX_PINMUX_NR_BANKS should be + * defined before including this header. + */ +#define STMP3XXX_PINID(bank, pin) (bank * STMP3XXX_PINMUX_BANK_SIZE + pin) +#define STMP3XXX_PINID_TO_BANK(pinid) (pinid / STMP3XXX_PINMUX_BANK_SIZE) +#define STMP3XXX_PINID_TO_PINNUM(pinid) (pinid % STMP3XXX_PINMUX_BANK_SIZE) + +/* + * Special invalid pin identificator to show a pin doesn't exist + */ +#define PINID_NO_PIN STMP3XXX_PINID(STMP3XXX_PINMUX_NR_BANKS, 0) + +static inline int stmp3xxx_valid_pin(unsigned pin) +{ + return STMP3XXX_PINID_TO_BANK(pin) < STMP3XXX_PINMUX_NR_BANKS && + STMP3XXX_PINID_TO_PINNUM(pin) < STMP3XXX_PINMUX_BANK_SIZE; +} + +/* + * Define all STMP378x pins, a pin name corresponds to a STMP378x hardware + * interface this pin belongs to. + */ + +/* Bank 0 */ +#define PINID_GPMI_D00 STMP3XXX_PINID(0, 0) +#define PINID_GPMI_D01 STMP3XXX_PINID(0, 1) +#define PINID_GPMI_D02 STMP3XXX_PINID(0, 2) +#define PINID_GPMI_D03 STMP3XXX_PINID(0, 3) +#define PINID_GPMI_D04 STMP3XXX_PINID(0, 4) +#define PINID_GPMI_D05 STMP3XXX_PINID(0, 5) +#define PINID_GPMI_D06 STMP3XXX_PINID(0, 6) +#define PINID_GPMI_D07 STMP3XXX_PINID(0, 7) +#define PINID_GPMI_D08 STMP3XXX_PINID(0, 8) +#define PINID_GPMI_D09 STMP3XXX_PINID(0, 9) +#define PINID_GPMI_D10 STMP3XXX_PINID(0, 10) +#define PINID_GPMI_D11 STMP3XXX_PINID(0, 11) +#define PINID_GPMI_D12 STMP3XXX_PINID(0, 12) +#define PINID_GPMI_D13 STMP3XXX_PINID(0, 13) +#define PINID_GPMI_D14 STMP3XXX_PINID(0, 14) +#define PINID_GPMI_D15 STMP3XXX_PINID(0, 15) +#define PINID_GPMI_CLE STMP3XXX_PINID(0, 16) +#define PINID_GPMI_ALE STMP3XXX_PINID(0, 17) +#define PINID_GMPI_CE2N STMP3XXX_PINID(0, 18) +#define PINID_GPMI_RDY0 STMP3XXX_PINID(0, 19) +#define PINID_GPMI_RDY1 STMP3XXX_PINID(0, 20) +#define PINID_GPMI_RDY2 STMP3XXX_PINID(0, 21) +#define PINID_GPMI_RDY3 STMP3XXX_PINID(0, 22) +#define PINID_GPMI_WPN STMP3XXX_PINID(0, 23) +#define PINID_GPMI_WRN STMP3XXX_PINID(0, 24) +#define PINID_GPMI_RDN STMP3XXX_PINID(0, 25) +#define PINID_AUART1_CTS STMP3XXX_PINID(0, 26) +#define PINID_AUART1_RTS STMP3XXX_PINID(0, 27) +#define PINID_AUART1_RX STMP3XXX_PINID(0, 28) +#define PINID_AUART1_TX STMP3XXX_PINID(0, 29) +#define PINID_I2C_SCL STMP3XXX_PINID(0, 30) +#define PINID_I2C_SDA STMP3XXX_PINID(0, 31) + +/* Bank 1 */ +#define PINID_LCD_D00 STMP3XXX_PINID(1, 0) +#define PINID_LCD_D01 STMP3XXX_PINID(1, 1) +#define PINID_LCD_D02 STMP3XXX_PINID(1, 2) +#define PINID_LCD_D03 STMP3XXX_PINID(1, 3) +#define PINID_LCD_D04 STMP3XXX_PINID(1, 4) +#define PINID_LCD_D05 STMP3XXX_PINID(1, 5) +#define PINID_LCD_D06 STMP3XXX_PINID(1, 6) +#define PINID_LCD_D07 STMP3XXX_PINID(1, 7) +#define PINID_LCD_D08 STMP3XXX_PINID(1, 8) +#define PINID_LCD_D09 STMP3XXX_PINID(1, 9) +#define PINID_LCD_D10 STMP3XXX_PINID(1, 10) +#define PINID_LCD_D11 STMP3XXX_PINID(1, 11) +#define PINID_LCD_D12 STMP3XXX_PINID(1, 12) +#define PINID_LCD_D13 STMP3XXX_PINID(1, 13) +#define PINID_LCD_D14 STMP3XXX_PINID(1, 14) +#define PINID_LCD_D15 STMP3XXX_PINID(1, 15) +#define PINID_LCD_D16 STMP3XXX_PINID(1, 16) +#define PINID_LCD_D17 STMP3XXX_PINID(1, 17) +#define PINID_LCD_RESET STMP3XXX_PINID(1, 18) +#define PINID_LCD_RS STMP3XXX_PINID(1, 19) +#define PINID_LCD_WR STMP3XXX_PINID(1, 20) +#define PINID_LCD_CS STMP3XXX_PINID(1, 21) +#define PINID_LCD_DOTCK STMP3XXX_PINID(1, 22) +#define PINID_LCD_ENABLE STMP3XXX_PINID(1, 23) +#define PINID_LCD_HSYNC STMP3XXX_PINID(1, 24) +#define PINID_LCD_VSYNC STMP3XXX_PINID(1, 25) +#define PINID_PWM0 STMP3XXX_PINID(1, 26) +#define PINID_PWM1 STMP3XXX_PINID(1, 27) +#define PINID_PWM2 STMP3XXX_PINID(1, 28) +#define PINID_PWM3 STMP3XXX_PINID(1, 29) +#define PINID_PWM4 STMP3XXX_PINID(1, 30) + +/* Bank 2 */ +#define PINID_SSP1_CMD STMP3XXX_PINID(2, 0) +#define PINID_SSP1_DETECT STMP3XXX_PINID(2, 1) +#define PINID_SSP1_DATA0 STMP3XXX_PINID(2, 2) +#define PINID_SSP1_DATA1 STMP3XXX_PINID(2, 3) +#define PINID_SSP1_DATA2 STMP3XXX_PINID(2, 4) +#define PINID_SSP1_DATA3 STMP3XXX_PINID(2, 5) +#define PINID_SSP1_SCK STMP3XXX_PINID(2, 6) +#define PINID_ROTARYA STMP3XXX_PINID(2, 7) +#define PINID_ROTARYB STMP3XXX_PINID(2, 8) +#define PINID_EMI_A00 STMP3XXX_PINID(2, 9) +#define PINID_EMI_A01 STMP3XXX_PINID(2, 10) +#define PINID_EMI_A02 STMP3XXX_PINID(2, 11) +#define PINID_EMI_A03 STMP3XXX_PINID(2, 12) +#define PINID_EMI_A04 STMP3XXX_PINID(2, 13) +#define PINID_EMI_A05 STMP3XXX_PINID(2, 14) +#define PINID_EMI_A06 STMP3XXX_PINID(2, 15) +#define PINID_EMI_A07 STMP3XXX_PINID(2, 16) +#define PINID_EMI_A08 STMP3XXX_PINID(2, 17) +#define PINID_EMI_A09 STMP3XXX_PINID(2, 18) +#define PINID_EMI_A10 STMP3XXX_PINID(2, 19) +#define PINID_EMI_A11 STMP3XXX_PINID(2, 20) +#define PINID_EMI_A12 STMP3XXX_PINID(2, 21) +#define PINID_EMI_BA0 STMP3XXX_PINID(2, 22) +#define PINID_EMI_BA1 STMP3XXX_PINID(2, 23) +#define PINID_EMI_CASN STMP3XXX_PINID(2, 24) +#define PINID_EMI_CE0N STMP3XXX_PINID(2, 25) +#define PINID_EMI_CE1N STMP3XXX_PINID(2, 26) +#define PINID_GPMI_CE1N STMP3XXX_PINID(2, 27) +#define PINID_GPMI_CE0N STMP3XXX_PINID(2, 28) +#define PINID_EMI_CKE STMP3XXX_PINID(2, 29) +#define PINID_EMI_RASN STMP3XXX_PINID(2, 30) +#define PINID_EMI_WEN STMP3XXX_PINID(2, 31) + +/* Bank 3 */ +#define PINID_EMI_D00 STMP3XXX_PINID(3, 0) +#define PINID_EMI_D01 STMP3XXX_PINID(3, 1) +#define PINID_EMI_D02 STMP3XXX_PINID(3, 2) +#define PINID_EMI_D03 STMP3XXX_PINID(3, 3) +#define PINID_EMI_D04 STMP3XXX_PINID(3, 4) +#define PINID_EMI_D05 STMP3XXX_PINID(3, 5) +#define PINID_EMI_D06 STMP3XXX_PINID(3, 6) +#define PINID_EMI_D07 STMP3XXX_PINID(3, 7) +#define PINID_EMI_D08 STMP3XXX_PINID(3, 8) +#define PINID_EMI_D09 STMP3XXX_PINID(3, 9) +#define PINID_EMI_D10 STMP3XXX_PINID(3, 10) +#define PINID_EMI_D11 STMP3XXX_PINID(3, 11) +#define PINID_EMI_D12 STMP3XXX_PINID(3, 12) +#define PINID_EMI_D13 STMP3XXX_PINID(3, 13) +#define PINID_EMI_D14 STMP3XXX_PINID(3, 14) +#define PINID_EMI_D15 STMP3XXX_PINID(3, 15) +#define PINID_EMI_DQM0 STMP3XXX_PINID(3, 16) +#define PINID_EMI_DQM1 STMP3XXX_PINID(3, 17) +#define PINID_EMI_DQS0 STMP3XXX_PINID(3, 18) +#define PINID_EMI_DQS1 STMP3XXX_PINID(3, 19) +#define PINID_EMI_CLK STMP3XXX_PINID(3, 20) +#define PINID_EMI_CLKN STMP3XXX_PINID(3, 21) + +#endif /* __ASM_ARCH_PINS_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/platform.h b/arch/arm/mach-stmp3xxx/include/mach/platform.h new file mode 100644 index 000000000000..55ab0c323b94 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/platform.h @@ -0,0 +1,31 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_PLATFORM_H +#define __ASM_PLAT_PLATFORM_H + +#include <asm/sizes.h> + +#define STMP378X_OCRAM_BASE 0x00000000 +#define STMP378X_OCRAM_SIZE (32 * SZ_1K) + +#define STMP378X_REGS_BASE 0x80000000 +#define STMP378X_REGS_SIZE SZ_1M + +/* Virtual address where registers are mapped */ +#define STMP3XXX_REGS_VA_BASE 0xf0000000 + +/* Virtual address where OCRAM is mapped */ +#define STMP3XXX_OCRAM_VA_BASE 0xf1000000 + +#endif /* __ASM_ARCH_PLATFORM_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/power.h b/arch/arm/mach-stmp3xxx/include/mach/power.h new file mode 100644 index 000000000000..3ef58c15fc5e --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/power.h @@ -0,0 +1,65 @@ +/* + * Freescale STMP37XX/STMP378X voltage regulator structure declarations + * + * Embedded Alley Solutions, Inc <sources@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __VOLTAGE_H +#define __VOLTAGE_H +#include <linux/completion.h> +//#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> + +struct stmp3xxx_regulator { + struct regulator_desc regulator; + struct stmp3xxx_regulator *parent; + struct stmp3xxx_platform_regulator_data *rdata; + struct completion done; + + spinlock_t lock; + wait_queue_head_t wait_q; + struct notifier_block nb; + + int mode; + int cur_voltage; + int cur_current; + int next_current; +}; + + +struct stmp3xxx_platform_regulator_data { + char name[80]; + char *parent_name; + int (*reg_register)(struct stmp3xxx_regulator *sreg); + int (*set_voltage)(struct stmp3xxx_regulator *sreg, int uv); + int (*get_voltage)(struct stmp3xxx_regulator *sreg); + int (*set_current)(struct stmp3xxx_regulator *sreg, int uA); + int (*get_current)(struct stmp3xxx_regulator *sreg); + int (*enable)(struct stmp3xxx_regulator *sreg); + int (*disable)(struct stmp3xxx_regulator *sreg); + int (*is_enabled)(struct stmp3xxx_regulator *sreg); + int (*set_mode)(struct stmp3xxx_regulator *sreg, int mode); + int (*get_mode)(struct stmp3xxx_regulator *sreg); + int (*get_optimum_mode)(struct stmp3xxx_regulator *sreg, + int input_uV, int output_uV, int load_uA); + u32 control_reg; + int min_voltage; + int max_voltage; + int max_current; + struct regulation_constraints *constraints; +}; + +int stmp3xxx_platform_add_regulator(const char *name, int count); + +#endif /* __VOLTAGE_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/pwm-led.h b/arch/arm/mach-stmp3xxx/include/mach/pwm-led.h new file mode 100644 index 000000000000..dd9ded8fd682 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/pwm-led.h @@ -0,0 +1,26 @@ +/* + * Freescale STMP37XX/STMP378X PWM LED arch-dependent structure + * and functions declarations + * + * Author: Drew Benedetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_PWM_LED_H +#define __ASM_PLAT_PWM_LED_H + +extern int pwm_led_pinmux_request(int, char *); +extern void pwm_led_pinmux_free(int, char *); + +#endif /* __ASM_PLAT_PWM_LED_H */ + diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-apbh.h b/arch/arm/mach-stmp3xxx/include/mach/regs-apbh.h new file mode 100644 index 000000000000..ba2db1ddae09 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-apbh.h @@ -0,0 +1,300 @@ +/* + * STMP APBH Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___APBH_H +#define __ARCH_ARM___APBH_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_APBH_BASE (REGS_BASE + 0x4000) +#define REGS_APBH_BASE_PHYS (0x80004000) +#define REGS_APBH_SIZE 0x00002000 +HW_REGISTER(HW_APBH_CTRL0, REGS_APBH_BASE, 0x00000000) +#define HW_APBH_CTRL0_ADDR (REGS_APBH_BASE + 0x00000000) +#define BM_APBH_CTRL0_SFTRST 0x80000000 +#define BM_APBH_CTRL0_CLKGATE 0x40000000 +#define BM_APBH_CTRL0_AHB_BURST8_EN 0x20000000 +#define BM_APBH_CTRL0_APB_BURST4_EN 0x10000000 +#define BP_APBH_CTRL0_RESET_CHANNEL 16 +#define BM_APBH_CTRL0_RESET_CHANNEL 0x00FF0000 +#define BF_APBH_CTRL0_RESET_CHANNEL(v) \ + (((v) << 16) & BM_APBH_CTRL0_RESET_CHANNEL) +#define BV_APBH_CTRL0_RESET_CHANNEL__LCDIF 0x01 +#define BV_APBH_CTRL0_RESET_CHANNEL__SSP1 0x02 +#define BV_APBH_CTRL0_RESET_CHANNEL__SSP2 0x04 +#define BV_APBH_CTRL0_RESET_CHANNEL__ATA 0x10 +#define BV_APBH_CTRL0_RESET_CHANNEL__NAND0 0x10 +#define BV_APBH_CTRL0_RESET_CHANNEL__NAND1 0x20 +#define BV_APBH_CTRL0_RESET_CHANNEL__NAND2 0x40 +#define BV_APBH_CTRL0_RESET_CHANNEL__NAND3 0x80 +#define BP_APBH_CTRL0_CLKGATE_CHANNEL 8 +#define BM_APBH_CTRL0_CLKGATE_CHANNEL 0x0000FF00 +#define BF_APBH_CTRL0_CLKGATE_CHANNEL(v) \ + (((v) << 8) & BM_APBH_CTRL0_CLKGATE_CHANNEL) +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__LCDIF 0x01 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__SSP1 0x02 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__SSP2 0x04 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__ATA 0x10 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND0 0x10 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND1 0x20 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND2 0x40 +#define BV_APBH_CTRL0_CLKGATE_CHANNEL__NAND3 0x80 +#define BP_APBH_CTRL0_FREEZE_CHANNEL 0 +#define BM_APBH_CTRL0_FREEZE_CHANNEL 0x000000FF +#define BF_APBH_CTRL0_FREEZE_CHANNEL(v) \ + (((v) << 0) & BM_APBH_CTRL0_FREEZE_CHANNEL) +#define BV_APBH_CTRL0_FREEZE_CHANNEL__LCDIF 0x01 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__SSP1 0x02 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__SSP2 0x04 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__ATA 0x10 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__NAND0 0x10 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__NAND1 0x20 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__NAND2 0x40 +#define BV_APBH_CTRL0_FREEZE_CHANNEL__NAND3 0x80 +HW_REGISTER(HW_APBH_CTRL1, REGS_APBH_BASE, 0x00000010) +#define HW_APBH_CTRL1_ADDR (REGS_APBH_BASE + 0x00000010) +#define BM_APBH_CTRL1_CH7_CMDCMPLT_IRQ_EN 0x00800000 +#define BM_APBH_CTRL1_CH6_CMDCMPLT_IRQ_EN 0x00400000 +#define BM_APBH_CTRL1_CH5_CMDCMPLT_IRQ_EN 0x00200000 +#define BM_APBH_CTRL1_CH4_CMDCMPLT_IRQ_EN 0x00100000 +#define BM_APBH_CTRL1_CH3_CMDCMPLT_IRQ_EN 0x00080000 +#define BM_APBH_CTRL1_CH2_CMDCMPLT_IRQ_EN 0x00040000 +#define BM_APBH_CTRL1_CH1_CMDCMPLT_IRQ_EN 0x00020000 +#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ_EN 0x00010000 +#define BM_APBH_CTRL1_CH7_CMDCMPLT_IRQ 0x00000080 +#define BM_APBH_CTRL1_CH6_CMDCMPLT_IRQ 0x00000040 +#define BM_APBH_CTRL1_CH5_CMDCMPLT_IRQ 0x00000020 +#define BM_APBH_CTRL1_CH4_CMDCMPLT_IRQ 0x00000010 +#define BM_APBH_CTRL1_CH3_CMDCMPLT_IRQ 0x00000008 +#define BM_APBH_CTRL1_CH2_CMDCMPLT_IRQ 0x00000004 +#define BM_APBH_CTRL1_CH1_CMDCMPLT_IRQ 0x00000002 +#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001 +HW_REGISTER(HW_APBH_CTRL2, REGS_APBH_BASE, 0x00000020) +#define HW_APBH_CTRL2_ADDR (REGS_APBH_BASE + 0x00000020) +#define BM_APBH_CTRL2_CH7_ERROR_STATUS 0x00800000 +#define BV_APBH_CTRL2_CH7_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH7_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH6_ERROR_STATUS 0x00400000 +#define BV_APBH_CTRL2_CH6_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH6_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH5_ERROR_STATUS 0x00200000 +#define BV_APBH_CTRL2_CH5_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH5_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH4_ERROR_STATUS 0x00100000 +#define BV_APBH_CTRL2_CH4_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH4_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH3_ERROR_STATUS 0x00080000 +#define BV_APBH_CTRL2_CH3_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH3_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH2_ERROR_STATUS 0x00040000 +#define BV_APBH_CTRL2_CH2_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH2_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH1_ERROR_STATUS 0x00020000 +#define BV_APBH_CTRL2_CH1_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH1_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH0_ERROR_STATUS 0x00010000 +#define BV_APBH_CTRL2_CH0_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBH_CTRL2_CH0_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBH_CTRL2_CH7_ERROR_IRQ 0x00000080 +#define BM_APBH_CTRL2_CH6_ERROR_IRQ 0x00000040 +#define BM_APBH_CTRL2_CH5_ERROR_IRQ 0x00000020 +#define BM_APBH_CTRL2_CH4_ERROR_IRQ 0x00000010 +#define BM_APBH_CTRL2_CH3_ERROR_IRQ 0x00000008 +#define BM_APBH_CTRL2_CH2_ERROR_IRQ 0x00000004 +#define BM_APBH_CTRL2_CH1_ERROR_IRQ 0x00000002 +#define BM_APBH_CTRL2_CH0_ERROR_IRQ 0x00000001 +HW_REGISTER_0(HW_APBH_DEVSEL, REGS_APBH_BASE, 0x00000030) +#define HW_APBH_DEVSEL_ADDR (REGS_APBH_BASE + 0x00000030) +#define BP_APBH_DEVSEL_CH7 28 +#define BM_APBH_DEVSEL_CH7 0xF0000000 +#define BF_APBH_DEVSEL_CH7(v) \ + (((v) << 28) & BM_APBH_DEVSEL_CH7) +#define BP_APBH_DEVSEL_CH6 24 +#define BM_APBH_DEVSEL_CH6 0x0F000000 +#define BF_APBH_DEVSEL_CH6(v) \ + (((v) << 24) & BM_APBH_DEVSEL_CH6) +#define BP_APBH_DEVSEL_CH5 20 +#define BM_APBH_DEVSEL_CH5 0x00F00000 +#define BF_APBH_DEVSEL_CH5(v) \ + (((v) << 20) & BM_APBH_DEVSEL_CH5) +#define BP_APBH_DEVSEL_CH4 16 +#define BM_APBH_DEVSEL_CH4 0x000F0000 +#define BF_APBH_DEVSEL_CH4(v) \ + (((v) << 16) & BM_APBH_DEVSEL_CH4) +#define BP_APBH_DEVSEL_CH3 12 +#define BM_APBH_DEVSEL_CH3 0x0000F000 +#define BF_APBH_DEVSEL_CH3(v) \ + (((v) << 12) & BM_APBH_DEVSEL_CH3) +#define BP_APBH_DEVSEL_CH2 8 +#define BM_APBH_DEVSEL_CH2 0x00000F00 +#define BF_APBH_DEVSEL_CH2(v) \ + (((v) << 8) & BM_APBH_DEVSEL_CH2) +#define BP_APBH_DEVSEL_CH1 4 +#define BM_APBH_DEVSEL_CH1 0x000000F0 +#define BF_APBH_DEVSEL_CH1(v) \ + (((v) << 4) & BM_APBH_DEVSEL_CH1) +#define BP_APBH_DEVSEL_CH0 0 +#define BM_APBH_DEVSEL_CH0 0x0000000F +#define BF_APBH_DEVSEL_CH0(v) \ + (((v) << 0) & BM_APBH_DEVSEL_CH0) +/* + * multi-register-define name HW_APBH_CHn_CURCMDAR + * base 0x00000040 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_CURCMDAR, REGS_APBH_BASE, 0x00000040, 0x70) +#define BP_APBH_CHn_CURCMDAR_CMD_ADDR 0 +#define BM_APBH_CHn_CURCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBH_CHn_CURCMDAR_CMD_ADDR(v) (v) +/* + * multi-register-define name HW_APBH_CHn_NXTCMDAR + * base 0x00000050 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_NXTCMDAR, REGS_APBH_BASE, 0x00000050, 0x70) +#define BP_APBH_CHn_NXTCMDAR_CMD_ADDR 0 +#define BM_APBH_CHn_NXTCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBH_CHn_NXTCMDAR_CMD_ADDR(v) (v) +/* + * multi-register-define name HW_APBH_CHn_CMD + * base 0x00000060 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_CMD, REGS_APBH_BASE, 0x00000060, 0x70) +#define BP_APBH_CHn_CMD_XFER_COUNT 16 +#define BM_APBH_CHn_CMD_XFER_COUNT 0xFFFF0000 +#define BF_APBH_CHn_CMD_XFER_COUNT(v) \ + (((v) << 16) & BM_APBH_CHn_CMD_XFER_COUNT) +#define BP_APBH_CHn_CMD_CMDWORDS 12 +#define BM_APBH_CHn_CMD_CMDWORDS 0x0000F000 +#define BF_APBH_CHn_CMD_CMDWORDS(v) \ + (((v) << 12) & BM_APBH_CHn_CMD_CMDWORDS) +#define BM_APBH_CHn_CMD_HALTONTERMINATE 0x00000100 +#define BM_APBH_CHn_CMD_WAIT4ENDCMD 0x00000080 +#define BM_APBH_CHn_CMD_SEMAPHORE 0x00000040 +#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020 +#define BM_APBH_CHn_CMD_NANDLOCK 0x00000010 +#define BM_APBH_CHn_CMD_IRQONCMPLT 0x00000008 +#define BM_APBH_CHn_CMD_CHAIN 0x00000004 +#define BP_APBH_CHn_CMD_COMMAND 0 +#define BM_APBH_CHn_CMD_COMMAND 0x00000003 +#define BF_APBH_CHn_CMD_COMMAND(v) \ + (((v) << 0) & BM_APBH_CHn_CMD_COMMAND) +#define BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER 0x0 +#define BV_APBH_CHn_CMD_COMMAND__DMA_WRITE 0x1 +#define BV_APBH_CHn_CMD_COMMAND__DMA_READ 0x2 +#define BV_APBH_CHn_CMD_COMMAND__DMA_SENSE 0x3 +/* + * multi-register-define name HW_APBH_CHn_BAR + * base 0x00000070 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_BAR, REGS_APBH_BASE, 0x00000070, 0x70) +#define BP_APBH_CHn_BAR_ADDRESS 0 +#define BM_APBH_CHn_BAR_ADDRESS 0xFFFFFFFF +#define BF_APBH_CHn_BAR_ADDRESS(v) (v) +/* + * multi-register-define name HW_APBH_CHn_SEMA + * base 0x00000080 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_SEMA, REGS_APBH_BASE, 0x00000080, 0x70) +#define BP_APBH_CHn_SEMA_PHORE 16 +#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000 +#define BF_APBH_CHn_SEMA_PHORE(v) \ + (((v) << 16) & BM_APBH_CHn_SEMA_PHORE) +#define BP_APBH_CHn_SEMA_INCREMENT_SEMA 0 +#define BM_APBH_CHn_SEMA_INCREMENT_SEMA 0x000000FF +#define BF_APBH_CHn_SEMA_INCREMENT_SEMA(v) \ + (((v) << 0) & BM_APBH_CHn_SEMA_INCREMENT_SEMA) +/* + * multi-register-define name HW_APBH_CHn_DEBUG1 + * base 0x00000090 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_DEBUG1, REGS_APBH_BASE, 0x00000090, 0x70) +#define BM_APBH_CHn_DEBUG1_REQ 0x80000000 +#define BM_APBH_CHn_DEBUG1_BURST 0x40000000 +#define BM_APBH_CHn_DEBUG1_KICK 0x20000000 +#define BM_APBH_CHn_DEBUG1_END 0x10000000 +#define BM_APBH_CHn_DEBUG1_NEXTCMDADDRVALID 0x01000000 +#define BM_APBH_CHn_DEBUG1_RD_FIFO_EMPTY 0x00800000 +#define BM_APBH_CHn_DEBUG1_RD_FIFO_FULL 0x00400000 +#define BM_APBH_CHn_DEBUG1_WR_FIFO_EMPTY 0x00200000 +#define BM_APBH_CHn_DEBUG1_WR_FIFO_FULL 0x00100000 +#define BP_APBH_CHn_DEBUG1_STATEMACHINE 0 +#define BM_APBH_CHn_DEBUG1_STATEMACHINE 0x0000001F +#define BF_APBH_CHn_DEBUG1_STATEMACHINE(v) \ + (((v) << 0) & BM_APBH_CHn_DEBUG1_STATEMACHINE) +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__IDLE 0x00 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD1 0x01 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD3 0x02 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD2 0x03 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__XFER_DECODE 0x04 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_WAIT 0x05 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__REQ_CMD4 0x06 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__PIO_REQ 0x07 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_FLUSH 0x08 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_WAIT 0x09 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WRITE 0x0C +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__READ_REQ 0x0D +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__CHECK_CHAIN 0x0E +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__XFER_COMPLETE 0x0F +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__TERMINATE 0x14 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WAIT_END 0x15 +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__WRITE_WAIT 0x1C +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__HALT_AFTER_TERM 0x1D +#define BV_APBH_CHn_DEBUG1_STATEMACHINE__CHECK_WAIT 0x1E +/* + * multi-register-define name HW_APBH_CHn_DEBUG2 + * base 0x000000A0 + * count 8 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBH_CHn_DEBUG2, REGS_APBH_BASE, 0x000000a0, 0x70) +#define BP_APBH_CHn_DEBUG2_APB_BYTES 16 +#define BM_APBH_CHn_DEBUG2_APB_BYTES 0xFFFF0000 +#define BF_APBH_CHn_DEBUG2_APB_BYTES(v) \ + (((v) << 16) & BM_APBH_CHn_DEBUG2_APB_BYTES) +#define BP_APBH_CHn_DEBUG2_AHB_BYTES 0 +#define BM_APBH_CHn_DEBUG2_AHB_BYTES 0x0000FFFF +#define BF_APBH_CHn_DEBUG2_AHB_BYTES(v) \ + (((v) << 0) & BM_APBH_CHn_DEBUG2_AHB_BYTES) +HW_REGISTER_0(HW_APBH_VERSION, REGS_APBH_BASE, 0x000003f0) +#define HW_APBH_VERSION_ADDR (REGS_APBH_BASE + 0x000003f0) +#define BP_APBH_VERSION_MAJOR 24 +#define BM_APBH_VERSION_MAJOR 0xFF000000 +#define BF_APBH_VERSION_MAJOR(v) \ + (((v) << 24) & BM_APBH_VERSION_MAJOR) +#define BP_APBH_VERSION_MINOR 16 +#define BM_APBH_VERSION_MINOR 0x00FF0000 +#define BF_APBH_VERSION_MINOR(v) \ + (((v) << 16) & BM_APBH_VERSION_MINOR) +#define BP_APBH_VERSION_STEP 0 +#define BM_APBH_VERSION_STEP 0x0000FFFF +#define BF_APBH_VERSION_STEP(v) \ + (((v) << 0) & BM_APBH_VERSION_STEP) +#endif /* __ARCH_ARM___APBH_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-apbx.h b/arch/arm/mach-stmp3xxx/include/mach/regs-apbx.h new file mode 100644 index 000000000000..43f649e950ac --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-apbx.h @@ -0,0 +1,377 @@ +/* + * STMP APBX Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___APBX_H +#define __ARCH_ARM___APBX_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_APBX_BASE (REGS_BASE + 0x24000) +#define REGS_APBX_BASE_PHYS (0x80024000) +#define REGS_APBX_SIZE 0x00002000 +HW_REGISTER(HW_APBX_CTRL0, REGS_APBX_BASE, 0x00000000) +#define HW_APBX_CTRL0_ADDR (REGS_APBX_BASE + 0x00000000) +#define BM_APBX_CTRL0_SFTRST 0x80000000 +#define BM_APBX_CTRL0_CLKGATE 0x40000000 +HW_REGISTER(HW_APBX_CTRL1, REGS_APBX_BASE, 0x00000010) +#define HW_APBX_CTRL1_ADDR (REGS_APBX_BASE + 0x00000010) +#define BM_APBX_CTRL1_CH15_CMDCMPLT_IRQ_EN 0x80000000 +#define BM_APBX_CTRL1_CH14_CMDCMPLT_IRQ_EN 0x40000000 +#define BM_APBX_CTRL1_CH13_CMDCMPLT_IRQ_EN 0x20000000 +#define BM_APBX_CTRL1_CH12_CMDCMPLT_IRQ_EN 0x10000000 +#define BM_APBX_CTRL1_CH11_CMDCMPLT_IRQ_EN 0x08000000 +#define BM_APBX_CTRL1_CH10_CMDCMPLT_IRQ_EN 0x04000000 +#define BM_APBX_CTRL1_CH9_CMDCMPLT_IRQ_EN 0x02000000 +#define BM_APBX_CTRL1_CH8_CMDCMPLT_IRQ_EN 0x01000000 +#define BM_APBX_CTRL1_CH7_CMDCMPLT_IRQ_EN 0x00800000 +#define BM_APBX_CTRL1_CH6_CMDCMPLT_IRQ_EN 0x00400000 +#define BM_APBX_CTRL1_CH5_CMDCMPLT_IRQ_EN 0x00200000 +#define BM_APBX_CTRL1_CH4_CMDCMPLT_IRQ_EN 0x00100000 +#define BM_APBX_CTRL1_CH3_CMDCMPLT_IRQ_EN 0x00080000 +#define BM_APBX_CTRL1_CH2_CMDCMPLT_IRQ_EN 0x00040000 +#define BM_APBX_CTRL1_CH1_CMDCMPLT_IRQ_EN 0x00020000 +#define BM_APBX_CTRL1_CH0_CMDCMPLT_IRQ_EN 0x00010000 +#define BM_APBX_CTRL1_CH15_CMDCMPLT_IRQ 0x00008000 +#define BM_APBX_CTRL1_CH14_CMDCMPLT_IRQ 0x00004000 +#define BM_APBX_CTRL1_CH13_CMDCMPLT_IRQ 0x00002000 +#define BM_APBX_CTRL1_CH12_CMDCMPLT_IRQ 0x00001000 +#define BM_APBX_CTRL1_CH11_CMDCMPLT_IRQ 0x00000800 +#define BM_APBX_CTRL1_CH10_CMDCMPLT_IRQ 0x00000400 +#define BM_APBX_CTRL1_CH9_CMDCMPLT_IRQ 0x00000200 +#define BM_APBX_CTRL1_CH8_CMDCMPLT_IRQ 0x00000100 +#define BM_APBX_CTRL1_CH7_CMDCMPLT_IRQ 0x00000080 +#define BM_APBX_CTRL1_CH6_CMDCMPLT_IRQ 0x00000040 +#define BM_APBX_CTRL1_CH5_CMDCMPLT_IRQ 0x00000020 +#define BM_APBX_CTRL1_CH4_CMDCMPLT_IRQ 0x00000010 +#define BM_APBX_CTRL1_CH3_CMDCMPLT_IRQ 0x00000008 +#define BM_APBX_CTRL1_CH2_CMDCMPLT_IRQ 0x00000004 +#define BM_APBX_CTRL1_CH1_CMDCMPLT_IRQ 0x00000002 +#define BM_APBX_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001 +HW_REGISTER(HW_APBX_CTRL2, REGS_APBX_BASE, 0x00000020) +#define HW_APBX_CTRL2_ADDR (REGS_APBX_BASE + 0x00000020) +#define BM_APBX_CTRL2_CH15_ERROR_STATUS 0x80000000 +#define BV_APBX_CTRL2_CH15_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH15_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH14_ERROR_STATUS 0x40000000 +#define BV_APBX_CTRL2_CH14_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH14_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH13_ERROR_STATUS 0x20000000 +#define BV_APBX_CTRL2_CH13_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH13_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH12_ERROR_STATUS 0x10000000 +#define BV_APBX_CTRL2_CH12_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH12_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH11_ERROR_STATUS 0x08000000 +#define BV_APBX_CTRL2_CH11_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH11_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH10_ERROR_STATUS 0x04000000 +#define BV_APBX_CTRL2_CH10_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH10_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH9_ERROR_STATUS 0x02000000 +#define BV_APBX_CTRL2_CH9_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH9_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH8_ERROR_STATUS 0x01000000 +#define BV_APBX_CTRL2_CH8_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH8_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH7_ERROR_STATUS 0x00800000 +#define BV_APBX_CTRL2_CH7_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH7_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH6_ERROR_STATUS 0x00400000 +#define BV_APBX_CTRL2_CH6_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH6_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH5_ERROR_STATUS 0x00200000 +#define BV_APBX_CTRL2_CH5_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH5_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH4_ERROR_STATUS 0x00100000 +#define BV_APBX_CTRL2_CH4_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH4_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH3_ERROR_STATUS 0x00080000 +#define BV_APBX_CTRL2_CH3_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH3_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH2_ERROR_STATUS 0x00040000 +#define BV_APBX_CTRL2_CH2_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH2_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH1_ERROR_STATUS 0x00020000 +#define BV_APBX_CTRL2_CH1_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH1_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH0_ERROR_STATUS 0x00010000 +#define BV_APBX_CTRL2_CH0_ERROR_STATUS__TERMINATION 0x0 +#define BV_APBX_CTRL2_CH0_ERROR_STATUS__BUS_ERROR 0x1 +#define BM_APBX_CTRL2_CH15_ERROR_IRQ 0x00008000 +#define BM_APBX_CTRL2_CH14_ERROR_IRQ 0x00004000 +#define BM_APBX_CTRL2_CH13_ERROR_IRQ 0x00002000 +#define BM_APBX_CTRL2_CH12_ERROR_IRQ 0x00001000 +#define BM_APBX_CTRL2_CH11_ERROR_IRQ 0x00000800 +#define BM_APBX_CTRL2_CH10_ERROR_IRQ 0x00000400 +#define BM_APBX_CTRL2_CH9_ERROR_IRQ 0x00000200 +#define BM_APBX_CTRL2_CH8_ERROR_IRQ 0x00000100 +#define BM_APBX_CTRL2_CH7_ERROR_IRQ 0x00000080 +#define BM_APBX_CTRL2_CH6_ERROR_IRQ 0x00000040 +#define BM_APBX_CTRL2_CH5_ERROR_IRQ 0x00000020 +#define BM_APBX_CTRL2_CH4_ERROR_IRQ 0x00000010 +#define BM_APBX_CTRL2_CH3_ERROR_IRQ 0x00000008 +#define BM_APBX_CTRL2_CH2_ERROR_IRQ 0x00000004 +#define BM_APBX_CTRL2_CH1_ERROR_IRQ 0x00000002 +#define BM_APBX_CTRL2_CH0_ERROR_IRQ 0x00000001 +HW_REGISTER(HW_APBX_CHANNEL_CTRL, REGS_APBX_BASE, 0x00000030) +#define HW_APBX_CHANNEL_CTRL_ADDR (REGS_APBX_BASE + 0x00000030) +#define BP_APBX_CHANNEL_CTRL_RESET_CHANNEL 16 +#define BM_APBX_CHANNEL_CTRL_RESET_CHANNEL 0xFFFF0000 +#define BF_APBX_CHANNEL_CTRL_RESET_CHANNEL(v) \ + (((v) << 16) & BM_APBX_CHANNEL_CTRL_RESET_CHANNEL) +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__AUDIOIN 0x0001 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__AUDIOOUT 0x0002 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__SPDIF_TX 0x0004 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__I2C 0x0008 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__SAIF1 0x0010 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__DRI 0x0020 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__IRDA_RX 0x0040 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART0_RX 0x0040 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__IRDA_TX 0x0080 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART0_TX 0x0080 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART1_RX 0x0100 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__UART1_TX 0x0200 +#define BV_APBX_CHANNEL_CTRL_RESET_CHANNEL__SAIF2 0x0400 +#define BP_APBX_CHANNEL_CTRL_FREEZE_CHANNEL 0 +#define BM_APBX_CHANNEL_CTRL_FREEZE_CHANNEL 0x0000FFFF +#define BF_APBX_CHANNEL_CTRL_FREEZE_CHANNEL(v) \ + (((v) << 0) & BM_APBX_CHANNEL_CTRL_FREEZE_CHANNEL) +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__AUDIOIN 0x0001 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__AUDIOOUT 0x0002 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__SPDIF_TX 0x0004 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__I2C 0x0008 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__SAIF1 0x0010 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__DRI 0x0020 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__IRDA_RX 0x0040 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART0_RX 0x0040 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__IRDA_TX 0x0080 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART0_TX 0x0080 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART1_RX 0x0100 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__UART1_TX 0x0200 +#define BV_APBX_CHANNEL_CTRL_FREEZE_CHANNEL__SAIF2 0x0400 +HW_REGISTER_0(HW_APBX_DEVSEL, REGS_APBX_BASE, 0x00000040) +#define HW_APBX_DEVSEL_ADDR (REGS_APBX_BASE + 0x00000040) +#define BP_APBX_DEVSEL_CH15 30 +#define BM_APBX_DEVSEL_CH15 0xC0000000 +#define BF_APBX_DEVSEL_CH15(v) \ + (((v) << 30) & BM_APBX_DEVSEL_CH15) +#define BP_APBX_DEVSEL_CH14 28 +#define BM_APBX_DEVSEL_CH14 0x30000000 +#define BF_APBX_DEVSEL_CH14(v) \ + (((v) << 28) & BM_APBX_DEVSEL_CH14) +#define BP_APBX_DEVSEL_CH13 26 +#define BM_APBX_DEVSEL_CH13 0x0C000000 +#define BF_APBX_DEVSEL_CH13(v) \ + (((v) << 26) & BM_APBX_DEVSEL_CH13) +#define BP_APBX_DEVSEL_CH12 24 +#define BM_APBX_DEVSEL_CH12 0x03000000 +#define BF_APBX_DEVSEL_CH12(v) \ + (((v) << 24) & BM_APBX_DEVSEL_CH12) +#define BP_APBX_DEVSEL_CH11 22 +#define BM_APBX_DEVSEL_CH11 0x00C00000 +#define BF_APBX_DEVSEL_CH11(v) \ + (((v) << 22) & BM_APBX_DEVSEL_CH11) +#define BP_APBX_DEVSEL_CH10 20 +#define BM_APBX_DEVSEL_CH10 0x00300000 +#define BF_APBX_DEVSEL_CH10(v) \ + (((v) << 20) & BM_APBX_DEVSEL_CH10) +#define BP_APBX_DEVSEL_CH9 18 +#define BM_APBX_DEVSEL_CH9 0x000C0000 +#define BF_APBX_DEVSEL_CH9(v) \ + (((v) << 18) & BM_APBX_DEVSEL_CH9) +#define BP_APBX_DEVSEL_CH8 16 +#define BM_APBX_DEVSEL_CH8 0x00030000 +#define BF_APBX_DEVSEL_CH8(v) \ + (((v) << 16) & BM_APBX_DEVSEL_CH8) +#define BP_APBX_DEVSEL_CH7 14 +#define BM_APBX_DEVSEL_CH7 0x0000C000 +#define BF_APBX_DEVSEL_CH7(v) \ + (((v) << 14) & BM_APBX_DEVSEL_CH7) +#define BV_APBX_DEVSEL_CH7__USE_I2C1 0x0 +#define BV_APBX_DEVSEL_CH7__USE_IRDA 0x1 +#define BP_APBX_DEVSEL_CH6 12 +#define BM_APBX_DEVSEL_CH6 0x00003000 +#define BF_APBX_DEVSEL_CH6(v) \ + (((v) << 12) & BM_APBX_DEVSEL_CH6) +#define BV_APBX_DEVSEL_CH6__USE_SAIF1 0x0 +#define BV_APBX_DEVSEL_CH6__USE_IRDA 0x1 +#define BP_APBX_DEVSEL_CH5 10 +#define BM_APBX_DEVSEL_CH5 0x00000C00 +#define BF_APBX_DEVSEL_CH5(v) \ + (((v) << 10) & BM_APBX_DEVSEL_CH5) +#define BP_APBX_DEVSEL_CH4 8 +#define BM_APBX_DEVSEL_CH4 0x00000300 +#define BF_APBX_DEVSEL_CH4(v) \ + (((v) << 8) & BM_APBX_DEVSEL_CH4) +#define BP_APBX_DEVSEL_CH3 6 +#define BM_APBX_DEVSEL_CH3 0x000000C0 +#define BF_APBX_DEVSEL_CH3(v) \ + (((v) << 6) & BM_APBX_DEVSEL_CH3) +#define BP_APBX_DEVSEL_CH2 4 +#define BM_APBX_DEVSEL_CH2 0x00000030 +#define BF_APBX_DEVSEL_CH2(v) \ + (((v) << 4) & BM_APBX_DEVSEL_CH2) +#define BP_APBX_DEVSEL_CH1 2 +#define BM_APBX_DEVSEL_CH1 0x0000000C +#define BF_APBX_DEVSEL_CH1(v) \ + (((v) << 2) & BM_APBX_DEVSEL_CH1) +#define BP_APBX_DEVSEL_CH0 0 +#define BM_APBX_DEVSEL_CH0 0x00000003 +#define BF_APBX_DEVSEL_CH0(v) \ + (((v) << 0) & BM_APBX_DEVSEL_CH0) +/* + * multi-register-define name HW_APBX_CHn_CURCMDAR + * base 0x00000100 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_CURCMDAR, REGS_APBX_BASE, 0x00000100, 0x70) +#define BP_APBX_CHn_CURCMDAR_CMD_ADDR 0 +#define BM_APBX_CHn_CURCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBX_CHn_CURCMDAR_CMD_ADDR(v) (v) +/* + * multi-register-define name HW_APBX_CHn_NXTCMDAR + * base 0x00000110 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_NXTCMDAR, REGS_APBX_BASE, 0x00000110, 0x70) +#define BP_APBX_CHn_NXTCMDAR_CMD_ADDR 0 +#define BM_APBX_CHn_NXTCMDAR_CMD_ADDR 0xFFFFFFFF +#define BF_APBX_CHn_NXTCMDAR_CMD_ADDR(v) (v) +/* + * multi-register-define name HW_APBX_CHn_CMD + * base 0x00000120 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_CMD, REGS_APBX_BASE, 0x00000120, 0x70) +#define BP_APBX_CHn_CMD_XFER_COUNT 16 +#define BM_APBX_CHn_CMD_XFER_COUNT 0xFFFF0000 +#define BF_APBX_CHn_CMD_XFER_COUNT(v) \ + (((v) << 16) & BM_APBX_CHn_CMD_XFER_COUNT) +#define BP_APBX_CHn_CMD_CMDWORDS 12 +#define BM_APBX_CHn_CMD_CMDWORDS 0x0000F000 +#define BF_APBX_CHn_CMD_CMDWORDS(v) \ + (((v) << 12) & BM_APBX_CHn_CMD_CMDWORDS) +#define BM_APBX_CHn_CMD_HALTONTERMINATE 0x00000100 +#define BM_APBX_CHn_CMD_WAIT4ENDCMD 0x00000080 +#define BM_APBX_CHn_CMD_SEMAPHORE 0x00000040 +#define BM_APBX_CHn_CMD_IRQONCMPLT 0x00000008 +#define BM_APBX_CHn_CMD_CHAIN 0x00000004 +#define BP_APBX_CHn_CMD_COMMAND 0 +#define BM_APBX_CHn_CMD_COMMAND 0x00000003 +#define BF_APBX_CHn_CMD_COMMAND(v) \ + (((v) << 0) & BM_APBX_CHn_CMD_COMMAND) +#define BV_APBX_CHn_CMD_COMMAND__NO_DMA_XFER 0x0 +#define BV_APBX_CHn_CMD_COMMAND__DMA_WRITE 0x1 +#define BV_APBX_CHn_CMD_COMMAND__DMA_READ 0x2 +/* + * multi-register-define name HW_APBX_CHn_BAR + * base 0x00000130 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_BAR, REGS_APBX_BASE, 0x00000130, 0x70) +#define BP_APBX_CHn_BAR_ADDRESS 0 +#define BM_APBX_CHn_BAR_ADDRESS 0xFFFFFFFF +#define BF_APBX_CHn_BAR_ADDRESS(v) (v) +/* + * multi-register-define name HW_APBX_CHn_SEMA + * base 0x00000140 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_SEMA, REGS_APBX_BASE, 0x00000140, 0x70) +#define BP_APBX_CHn_SEMA_PHORE 16 +#define BM_APBX_CHn_SEMA_PHORE 0x00FF0000 +#define BF_APBX_CHn_SEMA_PHORE(v) \ + (((v) << 16) & BM_APBX_CHn_SEMA_PHORE) +#define BP_APBX_CHn_SEMA_INCREMENT_SEMA 0 +#define BM_APBX_CHn_SEMA_INCREMENT_SEMA 0x000000FF +#define BF_APBX_CHn_SEMA_INCREMENT_SEMA(v) \ + (((v) << 0) & BM_APBX_CHn_SEMA_INCREMENT_SEMA) +/* + * multi-register-define name HW_APBX_CHn_DEBUG1 + * base 0x00000150 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_DEBUG1, REGS_APBX_BASE, 0x00000150, 0x70) +#define BM_APBX_CHn_DEBUG1_REQ 0x80000000 +#define BM_APBX_CHn_DEBUG1_BURST 0x40000000 +#define BM_APBX_CHn_DEBUG1_KICK 0x20000000 +#define BM_APBX_CHn_DEBUG1_END 0x10000000 +#define BM_APBX_CHn_DEBUG1_NEXTCMDADDRVALID 0x01000000 +#define BM_APBX_CHn_DEBUG1_RD_FIFO_EMPTY 0x00800000 +#define BM_APBX_CHn_DEBUG1_RD_FIFO_FULL 0x00400000 +#define BM_APBX_CHn_DEBUG1_WR_FIFO_EMPTY 0x00200000 +#define BM_APBX_CHn_DEBUG1_WR_FIFO_FULL 0x00100000 +#define BP_APBX_CHn_DEBUG1_STATEMACHINE 0 +#define BM_APBX_CHn_DEBUG1_STATEMACHINE 0x0000001F +#define BF_APBX_CHn_DEBUG1_STATEMACHINE(v) \ + (((v) << 0) & BM_APBX_CHn_DEBUG1_STATEMACHINE) +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__IDLE 0x00 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD1 0x01 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD3 0x02 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD2 0x03 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__XFER_DECODE 0x04 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_WAIT 0x05 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__REQ_CMD4 0x06 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__PIO_REQ 0x07 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__READ_FLUSH 0x08 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__READ_WAIT 0x09 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__WRITE 0x0C +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__READ_REQ 0x0D +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__CHECK_CHAIN 0x0E +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__XFER_COMPLETE 0x0F +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__WAIT_END 0x15 +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__WRITE_WAIT 0x1C +#define BV_APBX_CHn_DEBUG1_STATEMACHINE__CHECK_WAIT 0x1E +/* + * multi-register-define name HW_APBX_CHn_DEBUG2 + * base 0x00000160 + * count 16 + * offset 0x70 + */ +HW_REGISTER_0_INDEXED(HW_APBX_CHn_DEBUG2, REGS_APBX_BASE, 0x00000160, 0x70) +#define BP_APBX_CHn_DEBUG2_APB_BYTES 16 +#define BM_APBX_CHn_DEBUG2_APB_BYTES 0xFFFF0000 +#define BF_APBX_CHn_DEBUG2_APB_BYTES(v) \ + (((v) << 16) & BM_APBX_CHn_DEBUG2_APB_BYTES) +#define BP_APBX_CHn_DEBUG2_AHB_BYTES 0 +#define BM_APBX_CHn_DEBUG2_AHB_BYTES 0x0000FFFF +#define BF_APBX_CHn_DEBUG2_AHB_BYTES(v) \ + (((v) << 0) & BM_APBX_CHn_DEBUG2_AHB_BYTES) +HW_REGISTER_0(HW_APBX_VERSION, REGS_APBX_BASE, 0x00000800) +#define HW_APBX_VERSION_ADDR (REGS_APBX_BASE + 0x00000800) +#define BP_APBX_VERSION_MAJOR 24 +#define BM_APBX_VERSION_MAJOR 0xFF000000 +#define BF_APBX_VERSION_MAJOR(v) \ + (((v) << 24) & BM_APBX_VERSION_MAJOR) +#define BP_APBX_VERSION_MINOR 16 +#define BM_APBX_VERSION_MINOR 0x00FF0000 +#define BF_APBX_VERSION_MINOR(v) \ + (((v) << 16) & BM_APBX_VERSION_MINOR) +#define BP_APBX_VERSION_STEP 0 +#define BM_APBX_VERSION_STEP 0x0000FFFF +#define BF_APBX_VERSION_STEP(v) \ + (((v) << 0) & BM_APBX_VERSION_STEP) +#endif /* __ARCH_ARM___APBX_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-audioin.h b/arch/arm/mach-stmp3xxx/include/mach/regs-audioin.h new file mode 100644 index 000000000000..ebcca024d3fb --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-audioin.h @@ -0,0 +1,161 @@ +/* + * STMP AUDIOIN Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___AUDIOIN_H +#define __ARCH_ARM___AUDIOIN_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_AUDIOIN_BASE (REGS_BASE + 0x4c000) +#define REGS_AUDIOIN_BASE_PHYS (0x8004C000) +#define REGS_AUDIOIN_SIZE 0x00002000 +HW_REGISTER(HW_AUDIOIN_CTRL, REGS_AUDIOIN_BASE, 0x00000000) +#define HW_AUDIOIN_CTRL_ADDR (REGS_AUDIOIN_BASE + 0x00000000) +#define BM_AUDIOIN_CTRL_SFTRST 0x80000000 +#define BM_AUDIOIN_CTRL_CLKGATE 0x40000000 +#define BP_AUDIOIN_CTRL_DMAWAIT_COUNT 16 +#define BM_AUDIOIN_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_AUDIOIN_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_AUDIOIN_CTRL_DMAWAIT_COUNT) +#define BM_AUDIOIN_CTRL_LR_SWAP 0x00000400 +#define BM_AUDIOIN_CTRL_EDGE_SYNC 0x00000200 +#define BM_AUDIOIN_CTRL_INVERT_1BIT 0x00000100 +#define BM_AUDIOIN_CTRL_OFFSET_ENABLE 0x00000080 +#define BM_AUDIOIN_CTRL_HPF_ENABLE 0x00000040 +#define BM_AUDIOIN_CTRL_WORD_LENGTH 0x00000020 +#define BM_AUDIOIN_CTRL_LOOPBACK 0x00000010 +#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008 +#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ 0x00000004 +#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN 0x00000002 +#define BM_AUDIOIN_CTRL_RUN 0x00000001 +HW_REGISTER(HW_AUDIOIN_STAT, REGS_AUDIOIN_BASE, 0x00000010) +#define HW_AUDIOIN_STAT_ADDR (REGS_AUDIOIN_BASE + 0x00000010) +#define BM_AUDIOIN_STAT_ADC_PRESENT 0x80000000 +HW_REGISTER(HW_AUDIOIN_ADCSRR, REGS_AUDIOIN_BASE, 0x00000020) +#define HW_AUDIOIN_ADCSRR_ADDR (REGS_AUDIOIN_BASE + 0x00000020) +#define BM_AUDIOIN_ADCSRR_OSR 0x80000000 +#define BV_AUDIOIN_ADCSRR_OSR__OSR6 0x0 +#define BV_AUDIOIN_ADCSRR_OSR__OSR12 0x1 +#define BP_AUDIOIN_ADCSRR_BASEMULT 28 +#define BM_AUDIOIN_ADCSRR_BASEMULT 0x70000000 +#define BF_AUDIOIN_ADCSRR_BASEMULT(v) \ + (((v) << 28) & BM_AUDIOIN_ADCSRR_BASEMULT) +#define BV_AUDIOIN_ADCSRR_BASEMULT__SINGLE_RATE 0x1 +#define BV_AUDIOIN_ADCSRR_BASEMULT__DOUBLE_RATE 0x2 +#define BV_AUDIOIN_ADCSRR_BASEMULT__QUAD_RATE 0x4 +#define BP_AUDIOIN_ADCSRR_SRC_HOLD 24 +#define BM_AUDIOIN_ADCSRR_SRC_HOLD 0x07000000 +#define BF_AUDIOIN_ADCSRR_SRC_HOLD(v) \ + (((v) << 24) & BM_AUDIOIN_ADCSRR_SRC_HOLD) +#define BP_AUDIOIN_ADCSRR_SRC_INT 16 +#define BM_AUDIOIN_ADCSRR_SRC_INT 0x001F0000 +#define BF_AUDIOIN_ADCSRR_SRC_INT(v) \ + (((v) << 16) & BM_AUDIOIN_ADCSRR_SRC_INT) +#define BP_AUDIOIN_ADCSRR_SRC_FRAC 0 +#define BM_AUDIOIN_ADCSRR_SRC_FRAC 0x00001FFF +#define BF_AUDIOIN_ADCSRR_SRC_FRAC(v) \ + (((v) << 0) & BM_AUDIOIN_ADCSRR_SRC_FRAC) +HW_REGISTER(HW_AUDIOIN_ADCVOLUME, REGS_AUDIOIN_BASE, 0x00000030) +#define HW_AUDIOIN_ADCVOLUME_ADDR (REGS_AUDIOIN_BASE + 0x00000030) +#define BM_AUDIOIN_ADCVOLUME_VOLUME_UPDATE_LEFT 0x10000000 +#define BM_AUDIOIN_ADCVOLUME_EN_ZCD 0x02000000 +#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT 16 +#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT 0x00FF0000 +#define BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(v) \ + (((v) << 16) & BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT) +#define BM_AUDIOIN_ADCVOLUME_VOLUME_UPDATE_RIGHT 0x00001000 +#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0 +#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0x000000FF +#define BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(v) \ + (((v) << 0) & BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT) +HW_REGISTER(HW_AUDIOIN_ADCDEBUG, REGS_AUDIOIN_BASE, 0x00000040) +#define HW_AUDIOIN_ADCDEBUG_ADDR (REGS_AUDIOIN_BASE + 0x00000040) +#define BM_AUDIOIN_ADCDEBUG_ENABLE_ADCDMA 0x80000000 +#define BM_AUDIOIN_ADCDEBUG_ADC_DMA_REQ_HAND_SHAKE_CLK_CROSS 0x00000008 +#define BM_AUDIOIN_ADCDEBUG_SET_INTERRUPT3_HAND_SHAKE 0x00000004 +#define BM_AUDIOIN_ADCDEBUG_DMA_PREQ 0x00000002 +#define BM_AUDIOIN_ADCDEBUG_FIFO_STATUS 0x00000001 +HW_REGISTER(HW_AUDIOIN_ADCVOL, REGS_AUDIOIN_BASE, 0x00000050) +#define HW_AUDIOIN_ADCVOL_ADDR (REGS_AUDIOIN_BASE + 0x00000050) +#define BM_AUDIOIN_ADCVOL_VOLUME_UPDATE_PENDING 0x10000000 +#define BM_AUDIOIN_ADCVOL_EN_ADC_ZCD 0x02000000 +#define BM_AUDIOIN_ADCVOL_MUTE 0x01000000 +#define BP_AUDIOIN_ADCVOL_SELECT_LEFT 12 +#define BM_AUDIOIN_ADCVOL_SELECT_LEFT 0x00003000 +#define BF_AUDIOIN_ADCVOL_SELECT_LEFT(v) \ + (((v) << 12) & BM_AUDIOIN_ADCVOL_SELECT_LEFT) +#define BP_AUDIOIN_ADCVOL_GAIN_LEFT 8 +#define BM_AUDIOIN_ADCVOL_GAIN_LEFT 0x00000F00 +#define BF_AUDIOIN_ADCVOL_GAIN_LEFT(v) \ + (((v) << 8) & BM_AUDIOIN_ADCVOL_GAIN_LEFT) +#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT 4 +#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT 0x00000030 +#define BF_AUDIOIN_ADCVOL_SELECT_RIGHT(v) \ + (((v) << 4) & BM_AUDIOIN_ADCVOL_SELECT_RIGHT) +#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT 0 +#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT 0x0000000F +#define BF_AUDIOIN_ADCVOL_GAIN_RIGHT(v) \ + (((v) << 0) & BM_AUDIOIN_ADCVOL_GAIN_RIGHT) +HW_REGISTER(HW_AUDIOIN_MICLINE, REGS_AUDIOIN_BASE, 0x00000060) +#define HW_AUDIOIN_MICLINE_ADDR (REGS_AUDIOIN_BASE + 0x00000060) +#define BM_AUDIOIN_MICLINE_DIVIDE_LINE1 0x20000000 +#define BM_AUDIOIN_MICLINE_DIVIDE_LINE2 0x10000000 +#define BM_AUDIOIN_MICLINE_MIC_SELECT 0x01000000 +#define BP_AUDIOIN_MICLINE_MIC_RESISTOR 20 +#define BM_AUDIOIN_MICLINE_MIC_RESISTOR 0x00300000 +#define BF_AUDIOIN_MICLINE_MIC_RESISTOR(v) \ + (((v) << 20) & BM_AUDIOIN_MICLINE_MIC_RESISTOR) +#define BP_AUDIOIN_MICLINE_MIC_BIAS 16 +#define BM_AUDIOIN_MICLINE_MIC_BIAS 0x00070000 +#define BF_AUDIOIN_MICLINE_MIC_BIAS(v) \ + (((v) << 16) & BM_AUDIOIN_MICLINE_MIC_BIAS) +#define BP_AUDIOIN_MICLINE_MIC_CHOPCLK 4 +#define BM_AUDIOIN_MICLINE_MIC_CHOPCLK 0x00000030 +#define BF_AUDIOIN_MICLINE_MIC_CHOPCLK(v) \ + (((v) << 4) & BM_AUDIOIN_MICLINE_MIC_CHOPCLK) +#define BP_AUDIOIN_MICLINE_MIC_GAIN 0 +#define BM_AUDIOIN_MICLINE_MIC_GAIN 0x00000003 +#define BF_AUDIOIN_MICLINE_MIC_GAIN(v) \ + (((v) << 0) & BM_AUDIOIN_MICLINE_MIC_GAIN) +HW_REGISTER(HW_AUDIOIN_ANACLKCTRL, REGS_AUDIOIN_BASE, 0x00000070) +#define HW_AUDIOIN_ANACLKCTRL_ADDR (REGS_AUDIOIN_BASE + 0x00000070) +#define BM_AUDIOIN_ANACLKCTRL_CLKGATE 0x80000000 +#define BM_AUDIOIN_ANACLKCTRL_DITHER_OFF 0x00000400 +#define BM_AUDIOIN_ANACLKCTRL_SLOW_DITHER 0x00000200 +#define BM_AUDIOIN_ANACLKCTRL_INVERT_ADCCLK 0x00000100 +#define BP_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT 4 +#define BM_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT 0x00000030 +#define BF_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT(v) \ + (((v) << 4) & BM_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT) +#define BP_AUDIOIN_ANACLKCTRL_ADCDIV 0 +#define BM_AUDIOIN_ANACLKCTRL_ADCDIV 0x00000007 +#define BF_AUDIOIN_ANACLKCTRL_ADCDIV(v) \ + (((v) << 0) & BM_AUDIOIN_ANACLKCTRL_ADCDIV) +HW_REGISTER(HW_AUDIOIN_DATA, REGS_AUDIOIN_BASE, 0x00000080) +#define HW_AUDIOIN_DATA_ADDR (REGS_AUDIOIN_BASE + 0x00000080) +#define BP_AUDIOIN_DATA_HIGH 16 +#define BM_AUDIOIN_DATA_HIGH 0xFFFF0000 +#define BF_AUDIOIN_DATA_HIGH(v) \ + (((v) << 16) & BM_AUDIOIN_DATA_HIGH) +#define BP_AUDIOIN_DATA_LOW 0 +#define BM_AUDIOIN_DATA_LOW 0x0000FFFF +#define BF_AUDIOIN_DATA_LOW(v) \ + (((v) << 0) & BM_AUDIOIN_DATA_LOW) +#endif /* __ARCH_ARM___AUDIOIN_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-audioout.h b/arch/arm/mach-stmp3xxx/include/mach/regs-audioout.h new file mode 100644 index 000000000000..ec74f5e6f94d --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-audioout.h @@ -0,0 +1,279 @@ +/* + * STMP AUDIOOUT Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___AUDIOOUT_H +#define __ARCH_ARM___AUDIOOUT_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_AUDIOOUT_BASE (REGS_BASE + 0x48000) +#define REGS_AUDIOOUT_BASE_PHYS (0x80048000) +#define REGS_AUDIOOUT_SIZE 0x00002000 +HW_REGISTER(HW_AUDIOOUT_CTRL, REGS_AUDIOOUT_BASE, 0x00000000) +#define HW_AUDIOOUT_CTRL_ADDR (REGS_AUDIOOUT_BASE + 0x00000000) +#define BM_AUDIOOUT_CTRL_SFTRST 0x80000000 +#define BM_AUDIOOUT_CTRL_CLKGATE 0x40000000 +#define BP_AUDIOOUT_CTRL_DMAWAIT_COUNT 16 +#define BM_AUDIOOUT_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_AUDIOOUT_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_AUDIOOUT_CTRL_DMAWAIT_COUNT) +#define BM_AUDIOOUT_CTRL_LR_SWAP 0x00004000 +#define BM_AUDIOOUT_CTRL_EDGE_SYNC 0x00002000 +#define BM_AUDIOOUT_CTRL_INVERT_1BIT 0x00001000 +#define BP_AUDIOOUT_CTRL_SS3D_EFFECT 8 +#define BM_AUDIOOUT_CTRL_SS3D_EFFECT 0x00000300 +#define BF_AUDIOOUT_CTRL_SS3D_EFFECT(v) \ + (((v) << 8) & BM_AUDIOOUT_CTRL_SS3D_EFFECT) +#define BM_AUDIOOUT_CTRL_WORD_LENGTH 0x00000040 +#define BM_AUDIOOUT_CTRL_DAC_ZERO_ENABLE 0x00000020 +#define BM_AUDIOOUT_CTRL_LOOPBACK 0x00000010 +#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008 +#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ 0x00000004 +#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN 0x00000002 +#define BM_AUDIOOUT_CTRL_RUN 0x00000001 +HW_REGISTER(HW_AUDIOOUT_STAT, REGS_AUDIOOUT_BASE, 0x00000010) +#define HW_AUDIOOUT_STAT_ADDR (REGS_AUDIOOUT_BASE + 0x00000010) +#define BM_AUDIOOUT_STAT_DAC_PRESENT 0x80000000 +HW_REGISTER(HW_AUDIOOUT_DACSRR, REGS_AUDIOOUT_BASE, 0x00000020) +#define HW_AUDIOOUT_DACSRR_ADDR (REGS_AUDIOOUT_BASE + 0x00000020) +#define BM_AUDIOOUT_DACSRR_OSR 0x80000000 +#define BV_AUDIOOUT_DACSRR_OSR__OSR6 0x0 +#define BV_AUDIOOUT_DACSRR_OSR__OSR12 0x1 +#define BP_AUDIOOUT_DACSRR_BASEMULT 28 +#define BM_AUDIOOUT_DACSRR_BASEMULT 0x70000000 +#define BF_AUDIOOUT_DACSRR_BASEMULT(v) \ + (((v) << 28) & BM_AUDIOOUT_DACSRR_BASEMULT) +#define BV_AUDIOOUT_DACSRR_BASEMULT__SINGLE_RATE 0x1 +#define BV_AUDIOOUT_DACSRR_BASEMULT__DOUBLE_RATE 0x2 +#define BV_AUDIOOUT_DACSRR_BASEMULT__QUAD_RATE 0x4 +#define BP_AUDIOOUT_DACSRR_SRC_HOLD 24 +#define BM_AUDIOOUT_DACSRR_SRC_HOLD 0x07000000 +#define BF_AUDIOOUT_DACSRR_SRC_HOLD(v) \ + (((v) << 24) & BM_AUDIOOUT_DACSRR_SRC_HOLD) +#define BP_AUDIOOUT_DACSRR_SRC_INT 16 +#define BM_AUDIOOUT_DACSRR_SRC_INT 0x001F0000 +#define BF_AUDIOOUT_DACSRR_SRC_INT(v) \ + (((v) << 16) & BM_AUDIOOUT_DACSRR_SRC_INT) +#define BP_AUDIOOUT_DACSRR_SRC_FRAC 0 +#define BM_AUDIOOUT_DACSRR_SRC_FRAC 0x00001FFF +#define BF_AUDIOOUT_DACSRR_SRC_FRAC(v) \ + (((v) << 0) & BM_AUDIOOUT_DACSRR_SRC_FRAC) +HW_REGISTER(HW_AUDIOOUT_DACVOLUME, REGS_AUDIOOUT_BASE, 0x00000030) +#define HW_AUDIOOUT_DACVOLUME_ADDR (REGS_AUDIOOUT_BASE + 0x00000030) +#define BM_AUDIOOUT_DACVOLUME_VOLUME_UPDATE_LEFT 0x10000000 +#define BM_AUDIOOUT_DACVOLUME_EN_ZCD 0x02000000 +#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT 0x01000000 +#define BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT 16 +#define BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT 0x00FF0000 +#define BF_AUDIOOUT_DACVOLUME_VOLUME_LEFT(v) \ + (((v) << 16) & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) +#define BM_AUDIOOUT_DACVOLUME_VOLUME_UPDATE_RIGHT 0x00001000 +#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT 0x00000100 +#define BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT 0 +#define BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT 0x000000FF +#define BF_AUDIOOUT_DACVOLUME_VOLUME_RIGHT(v) \ + (((v) << 0) & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) +HW_REGISTER(HW_AUDIOOUT_DACDEBUG, REGS_AUDIOOUT_BASE, 0x00000040) +#define HW_AUDIOOUT_DACDEBUG_ADDR (REGS_AUDIOOUT_BASE + 0x00000040) +#define BM_AUDIOOUT_DACDEBUG_ENABLE_DACDMA 0x80000000 +#define BP_AUDIOOUT_DACDEBUG_RAM_SS 8 +#define BM_AUDIOOUT_DACDEBUG_RAM_SS 0x00000F00 +#define BF_AUDIOOUT_DACDEBUG_RAM_SS(v) \ + (((v) << 8) & BM_AUDIOOUT_DACDEBUG_RAM_SS) +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT1_CLK_CROSS 0x00000020 +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT0_CLK_CROSS 0x00000010 +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT1_HAND_SHAKE 0x00000008 +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT0_HAND_SHAKE 0x00000004 +#define BM_AUDIOOUT_DACDEBUG_DMA_PREQ 0x00000002 +#define BM_AUDIOOUT_DACDEBUG_FIFO_STATUS 0x00000001 +HW_REGISTER(HW_AUDIOOUT_HPVOL, REGS_AUDIOOUT_BASE, 0x00000050) +#define HW_AUDIOOUT_HPVOL_ADDR (REGS_AUDIOOUT_BASE + 0x00000050) +#define BM_AUDIOOUT_HPVOL_VOLUME_UPDATE_PENDING 0x10000000 +#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD 0x02000000 +#define BM_AUDIOOUT_HPVOL_MUTE 0x01000000 +#define BM_AUDIOOUT_HPVOL_SELECT 0x00010000 +#define BP_AUDIOOUT_HPVOL_VOL_LEFT 8 +#define BM_AUDIOOUT_HPVOL_VOL_LEFT 0x00007F00 +#define BF_AUDIOOUT_HPVOL_VOL_LEFT(v) \ + (((v) << 8) & BM_AUDIOOUT_HPVOL_VOL_LEFT) +#define BP_AUDIOOUT_HPVOL_VOL_RIGHT 0 +#define BM_AUDIOOUT_HPVOL_VOL_RIGHT 0x0000007F +#define BF_AUDIOOUT_HPVOL_VOL_RIGHT(v) \ + (((v) << 0) & BM_AUDIOOUT_HPVOL_VOL_RIGHT) +HW_REGISTER(HW_AUDIOOUT_RESERVED, REGS_AUDIOOUT_BASE, 0x00000060) +#define HW_AUDIOOUT_RESERVED_ADDR (REGS_AUDIOOUT_BASE + 0x00000060) +HW_REGISTER(HW_AUDIOOUT_PWRDN, REGS_AUDIOOUT_BASE, 0x00000070) +#define HW_AUDIOOUT_PWRDN_ADDR (REGS_AUDIOOUT_BASE + 0x00000070) +#define BM_AUDIOOUT_PWRDN_SPEAKER 0x01000000 +#define BM_AUDIOOUT_PWRDN_SELFBIAS 0x00100000 +#define BM_AUDIOOUT_PWRDN_RIGHT_ADC 0x00010000 +#define BM_AUDIOOUT_PWRDN_DAC 0x00001000 +#define BM_AUDIOOUT_PWRDN_ADC 0x00000100 +#define BM_AUDIOOUT_PWRDN_CAPLESS 0x00000010 +#define BM_AUDIOOUT_PWRDN_HEADPHONE 0x00000001 +HW_REGISTER(HW_AUDIOOUT_REFCTRL, REGS_AUDIOOUT_BASE, 0x00000080) +#define HW_AUDIOOUT_REFCTRL_ADDR (REGS_AUDIOOUT_BASE + 0x00000080) +#define BM_AUDIOOUT_REFCTRL_FASTSETTLING 0x04000000 +#define BM_AUDIOOUT_REFCTRL_RAISE_REF 0x02000000 +#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS 0x01000000 +#define BP_AUDIOOUT_REFCTRL_VBG_ADJ 20 +#define BM_AUDIOOUT_REFCTRL_VBG_ADJ 0x00700000 +#define BF_AUDIOOUT_REFCTRL_VBG_ADJ(v) \ + (((v) << 20) & BM_AUDIOOUT_REFCTRL_VBG_ADJ) +#define BM_AUDIOOUT_REFCTRL_LOW_PWR 0x00080000 +#define BM_AUDIOOUT_REFCTRL_LW_REF 0x00040000 +#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL 16 +#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL 0x00030000 +#define BF_AUDIOOUT_REFCTRL_BIAS_CTRL(v) \ + (((v) << 16) & BM_AUDIOOUT_REFCTRL_BIAS_CTRL) +#define BM_AUDIOOUT_REFCTRL_VDDXTAL_TO_VDDD 0x00004000 +#define BM_AUDIOOUT_REFCTRL_ADJ_ADC 0x00002000 +#define BM_AUDIOOUT_REFCTRL_ADJ_VAG 0x00001000 +#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL 8 +#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL 0x00000F00 +#define BF_AUDIOOUT_REFCTRL_ADC_REFVAL(v) \ + (((v) << 8) & BM_AUDIOOUT_REFCTRL_ADC_REFVAL) +#define BP_AUDIOOUT_REFCTRL_VAG_VAL 4 +#define BM_AUDIOOUT_REFCTRL_VAG_VAL 0x000000F0 +#define BF_AUDIOOUT_REFCTRL_VAG_VAL(v) \ + (((v) << 4) & BM_AUDIOOUT_REFCTRL_VAG_VAL) +#define BP_AUDIOOUT_REFCTRL_DAC_ADJ 0 +#define BM_AUDIOOUT_REFCTRL_DAC_ADJ 0x00000007 +#define BF_AUDIOOUT_REFCTRL_DAC_ADJ(v) \ + (((v) << 0) & BM_AUDIOOUT_REFCTRL_DAC_ADJ) +HW_REGISTER(HW_AUDIOOUT_ANACTRL, REGS_AUDIOOUT_BASE, 0x00000090) +#define HW_AUDIOOUT_ANACTRL_ADDR (REGS_AUDIOOUT_BASE + 0x00000090) +#define BM_AUDIOOUT_ANACTRL_SHORT_CM_STS 0x10000000 +#define BM_AUDIOOUT_ANACTRL_SHORT_LR_STS 0x01000000 +#define BP_AUDIOOUT_ANACTRL_SHORTMODE_CM 20 +#define BM_AUDIOOUT_ANACTRL_SHORTMODE_CM 0x00300000 +#define BF_AUDIOOUT_ANACTRL_SHORTMODE_CM(v) \ + (((v) << 20) & BM_AUDIOOUT_ANACTRL_SHORTMODE_CM) +#define BP_AUDIOOUT_ANACTRL_SHORTMODE_LR 17 +#define BM_AUDIOOUT_ANACTRL_SHORTMODE_LR 0x00060000 +#define BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(v) \ + (((v) << 17) & BM_AUDIOOUT_ANACTRL_SHORTMODE_LR) +#define BP_AUDIOOUT_ANACTRL_SHORT_LVLADJL 12 +#define BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL 0x00007000 +#define BF_AUDIOOUT_ANACTRL_SHORT_LVLADJL(v) \ + (((v) << 12) & BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL) +#define BP_AUDIOOUT_ANACTRL_SHORT_LVLADJR 8 +#define BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR 0x00000700 +#define BF_AUDIOOUT_ANACTRL_SHORT_LVLADJR(v) \ + (((v) << 8) & BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR) +#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND 0x00000020 +#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB 0x00000010 +HW_REGISTER(HW_AUDIOOUT_TEST, REGS_AUDIOOUT_BASE, 0x000000a0) +#define HW_AUDIOOUT_TEST_ADDR (REGS_AUDIOOUT_BASE + 0x000000a0) +#define BP_AUDIOOUT_TEST_HP_ANTIPOP 28 +#define BM_AUDIOOUT_TEST_HP_ANTIPOP 0x70000000 +#define BF_AUDIOOUT_TEST_HP_ANTIPOP(v) \ + (((v) << 28) & BM_AUDIOOUT_TEST_HP_ANTIPOP) +#define BM_AUDIOOUT_TEST_TM_ADCIN_TOHP 0x04000000 +#define BM_AUDIOOUT_TEST_TM_LOOP 0x02000000 +#define BM_AUDIOOUT_TEST_TM_HPCOMMON 0x01000000 +#define BP_AUDIOOUT_TEST_HP_I1_ADJ 22 +#define BM_AUDIOOUT_TEST_HP_I1_ADJ 0x00C00000 +#define BF_AUDIOOUT_TEST_HP_I1_ADJ(v) \ + (((v) << 22) & BM_AUDIOOUT_TEST_HP_I1_ADJ) +#define BP_AUDIOOUT_TEST_HP_IALL_ADJ 20 +#define BM_AUDIOOUT_TEST_HP_IALL_ADJ 0x00300000 +#define BF_AUDIOOUT_TEST_HP_IALL_ADJ(v) \ + (((v) << 20) & BM_AUDIOOUT_TEST_HP_IALL_ADJ) +#define BM_AUDIOOUT_TEST_VAG_CLASSA 0x00002000 +#define BM_AUDIOOUT_TEST_VAG_DOUBLE_I 0x00001000 +#define BM_AUDIOOUT_TEST_ADCTODAC_LOOP 0x00000008 +#define BM_AUDIOOUT_TEST_DAC_CLASSA 0x00000004 +#define BM_AUDIOOUT_TEST_DAC_DOUBLE_I 0x00000002 +#define BM_AUDIOOUT_TEST_DAC_DIS_RTZ 0x00000001 +HW_REGISTER(HW_AUDIOOUT_BISTCTRL, REGS_AUDIOOUT_BASE, 0x000000b0) +#define HW_AUDIOOUT_BISTCTRL_ADDR (REGS_AUDIOOUT_BASE + 0x000000b0) +#define BM_AUDIOOUT_BISTCTRL_FAIL 0x00000008 +#define BM_AUDIOOUT_BISTCTRL_PASS 0x00000004 +#define BM_AUDIOOUT_BISTCTRL_DONE 0x00000002 +#define BM_AUDIOOUT_BISTCTRL_START 0x00000001 +HW_REGISTER(HW_AUDIOOUT_BISTSTAT0, REGS_AUDIOOUT_BASE, 0x000000c0) +#define HW_AUDIOOUT_BISTSTAT0_ADDR (REGS_AUDIOOUT_BASE + 0x000000c0) +#define BP_AUDIOOUT_BISTSTAT0_DATA 0 +#define BM_AUDIOOUT_BISTSTAT0_DATA 0x00FFFFFF +#define BF_AUDIOOUT_BISTSTAT0_DATA(v) \ + (((v) << 0) & BM_AUDIOOUT_BISTSTAT0_DATA) +HW_REGISTER(HW_AUDIOOUT_BISTSTAT1, REGS_AUDIOOUT_BASE, 0x000000d0) +#define HW_AUDIOOUT_BISTSTAT1_ADDR (REGS_AUDIOOUT_BASE + 0x000000d0) +#define BP_AUDIOOUT_BISTSTAT1_STATE 24 +#define BM_AUDIOOUT_BISTSTAT1_STATE 0x1F000000 +#define BF_AUDIOOUT_BISTSTAT1_STATE(v) \ + (((v) << 24) & BM_AUDIOOUT_BISTSTAT1_STATE) +#define BP_AUDIOOUT_BISTSTAT1_ADDR 0 +#define BM_AUDIOOUT_BISTSTAT1_ADDR 0x000000FF +#define BF_AUDIOOUT_BISTSTAT1_ADDR(v) \ + (((v) << 0) & BM_AUDIOOUT_BISTSTAT1_ADDR) +HW_REGISTER(HW_AUDIOOUT_ANACLKCTRL, REGS_AUDIOOUT_BASE, 0x000000e0) +#define HW_AUDIOOUT_ANACLKCTRL_ADDR (REGS_AUDIOOUT_BASE + 0x000000e0) +#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE 0x80000000 +#define BM_AUDIOOUT_ANACLKCTRL_INVERT_DACCLK 0x00000010 +#define BP_AUDIOOUT_ANACLKCTRL_DACDIV 0 +#define BM_AUDIOOUT_ANACLKCTRL_DACDIV 0x00000007 +#define BF_AUDIOOUT_ANACLKCTRL_DACDIV(v) \ + (((v) << 0) & BM_AUDIOOUT_ANACLKCTRL_DACDIV) +HW_REGISTER(HW_AUDIOOUT_DATA, REGS_AUDIOOUT_BASE, 0x000000f0) +#define HW_AUDIOOUT_DATA_ADDR (REGS_AUDIOOUT_BASE + 0x000000f0) +#define BP_AUDIOOUT_DATA_HIGH 16 +#define BM_AUDIOOUT_DATA_HIGH 0xFFFF0000 +#define BF_AUDIOOUT_DATA_HIGH(v) \ + (((v) << 16) & BM_AUDIOOUT_DATA_HIGH) +#define BP_AUDIOOUT_DATA_LOW 0 +#define BM_AUDIOOUT_DATA_LOW 0x0000FFFF +#define BF_AUDIOOUT_DATA_LOW(v) \ + (((v) << 0) & BM_AUDIOOUT_DATA_LOW) +HW_REGISTER(HW_AUDIOOUT_SPEAKERCTRL, REGS_AUDIOOUT_BASE, 0x00000100) +#define HW_AUDIOOUT_SPEAKERCTRL_ADDR (REGS_AUDIOOUT_BASE + 0x00000100) +#define BM_AUDIOOUT_SPEAKERCTRL_MUTE 0x01000000 +#define BP_AUDIOOUT_SPEAKERCTRL_I1_ADJ 22 +#define BM_AUDIOOUT_SPEAKERCTRL_I1_ADJ 0x00C00000 +#define BF_AUDIOOUT_SPEAKERCTRL_I1_ADJ(v) \ + (((v) << 22) & BM_AUDIOOUT_SPEAKERCTRL_I1_ADJ) +#define BP_AUDIOOUT_SPEAKERCTRL_IALL_ADJ 20 +#define BM_AUDIOOUT_SPEAKERCTRL_IALL_ADJ 0x00300000 +#define BF_AUDIOOUT_SPEAKERCTRL_IALL_ADJ(v) \ + (((v) << 20) & BM_AUDIOOUT_SPEAKERCTRL_IALL_ADJ) +#define BP_AUDIOOUT_SPEAKERCTRL_POSDRIVER 14 +#define BM_AUDIOOUT_SPEAKERCTRL_POSDRIVER 0x0000C000 +#define BF_AUDIOOUT_SPEAKERCTRL_POSDRIVER(v) \ + (((v) << 14) & BM_AUDIOOUT_SPEAKERCTRL_POSDRIVER) +#define BP_AUDIOOUT_SPEAKERCTRL_NEGDRIVER 12 +#define BM_AUDIOOUT_SPEAKERCTRL_NEGDRIVER 0x00003000 +#define BF_AUDIOOUT_SPEAKERCTRL_NEGDRIVER(v) \ + (((v) << 12) & BM_AUDIOOUT_SPEAKERCTRL_NEGDRIVER) +HW_REGISTER_0(HW_AUDIOOUT_VERSION, REGS_AUDIOOUT_BASE, 0x00000200) +#define HW_AUDIOOUT_VERSION_ADDR (REGS_AUDIOOUT_BASE + 0x00000200) +#define BP_AUDIOOUT_VERSION_MAJOR 24 +#define BM_AUDIOOUT_VERSION_MAJOR 0xFF000000 +#define BF_AUDIOOUT_VERSION_MAJOR(v) \ + (((v) << 24) & BM_AUDIOOUT_VERSION_MAJOR) +#define BP_AUDIOOUT_VERSION_MINOR 16 +#define BM_AUDIOOUT_VERSION_MINOR 0x00FF0000 +#define BF_AUDIOOUT_VERSION_MINOR(v) \ + (((v) << 16) & BM_AUDIOOUT_VERSION_MINOR) +#define BP_AUDIOOUT_VERSION_STEP 0 +#define BM_AUDIOOUT_VERSION_STEP 0x0000FFFF +#define BF_AUDIOOUT_VERSION_STEP(v) \ + (((v) << 0) & BM_AUDIOOUT_VERSION_STEP) +#endif /* __ARCH_ARM___AUDIOOUT_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-bch.h b/arch/arm/mach-stmp3xxx/include/mach/regs-bch.h new file mode 100644 index 000000000000..2e4257314878 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-bch.h @@ -0,0 +1,447 @@ +/* + * STMP BCH Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___BCH_H +#define __ARCH_ARM___BCH_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_BCH_BASE (REGS_BASE + 0xa000) +#define REGS_BCH_BASE_PHYS (0x8000A000) +#define REGS_BCH_SIZE 0x00002000 +HW_REGISTER(HW_BCH_CTRL, REGS_BCH_BASE, 0x00000000) +#define HW_BCH_CTRL_ADDR (REGS_BCH_BASE + 0x00000000) +#define BM_BCH_CTRL_SFTRST 0x80000000 +#define BV_BCH_CTRL_SFTRST__RUN 0x0 +#define BV_BCH_CTRL_SFTRST__RESET 0x1 +#define BM_BCH_CTRL_CLKGATE 0x40000000 +#define BV_BCH_CTRL_CLKGATE__RUN 0x0 +#define BV_BCH_CTRL_CLKGATE__NO_CLKS 0x1 +#define BM_BCH_CTRL_DEBUGSYNDROME 0x00400000 +#define BP_BCH_CTRL_M2M_LAYOUT 18 +#define BM_BCH_CTRL_M2M_LAYOUT 0x000C0000 +#define BF_BCH_CTRL_M2M_LAYOUT(v) \ + (((v) << 18) & BM_BCH_CTRL_M2M_LAYOUT) +#define BM_BCH_CTRL_M2M_ENCODE 0x00020000 +#define BM_BCH_CTRL_M2M_ENABLE 0x00010000 +#define BM_BCH_CTRL_DEBUG_STALL_IRQ_EN 0x00000400 +#define BM_BCH_CTRL_COMPLETE_IRQ_EN 0x00000100 +#define BM_BCH_CTRL_BM_ERROR_IRQ 0x00000008 +#define BM_BCH_CTRL_DEBUG_STALL_IRQ 0x00000004 +#define BM_BCH_CTRL_COMPLETE_IRQ 0x00000001 +HW_REGISTER_0(HW_BCH_STATUS0, REGS_BCH_BASE, 0x00000010) +#define HW_BCH_STATUS0_ADDR (REGS_BCH_BASE + 0x00000010) +#define BP_BCH_STATUS0_HANDLE 20 +#define BM_BCH_STATUS0_HANDLE 0xFFF00000 +#define BF_BCH_STATUS0_HANDLE(v) \ + (((v) << 20) & BM_BCH_STATUS0_HANDLE) +#define BP_BCH_STATUS0_COMPLETED_CE 16 +#define BM_BCH_STATUS0_COMPLETED_CE 0x000F0000 +#define BF_BCH_STATUS0_COMPLETED_CE(v) \ + (((v) << 16) & BM_BCH_STATUS0_COMPLETED_CE) +#define BP_BCH_STATUS0_STATUS_BLK0 8 +#define BM_BCH_STATUS0_STATUS_BLK0 0x0000FF00 +#define BF_BCH_STATUS0_STATUS_BLK0(v) \ + (((v) << 8) & BM_BCH_STATUS0_STATUS_BLK0) +#define BV_BCH_STATUS0_STATUS_BLK0__ZERO 0x00 +#define BV_BCH_STATUS0_STATUS_BLK0__ERROR1 0x01 +#define BV_BCH_STATUS0_STATUS_BLK0__ERROR2 0x02 +#define BV_BCH_STATUS0_STATUS_BLK0__ERROR3 0x03 +#define BV_BCH_STATUS0_STATUS_BLK0__ERROR4 0x04 +#define BV_BCH_STATUS0_STATUS_BLK0__UNCORRECTABLE 0xFE +#define BV_BCH_STATUS0_STATUS_BLK0__ERASED 0xFF +#define BM_BCH_STATUS0_ALLONES 0x00000010 +#define BM_BCH_STATUS0_CORRECTED 0x00000008 +#define BM_BCH_STATUS0_UNCORRECTABLE 0x00000004 +HW_REGISTER_0(HW_BCH_MODE, REGS_BCH_BASE, 0x00000020) +#define HW_BCH_MODE_ADDR (REGS_BCH_BASE + 0x00000020) +#define BP_BCH_MODE_ERASE_THRESHOLD 0 +#define BM_BCH_MODE_ERASE_THRESHOLD 0x000000FF +#define BF_BCH_MODE_ERASE_THRESHOLD(v) \ + (((v) << 0) & BM_BCH_MODE_ERASE_THRESHOLD) +HW_REGISTER_0(HW_BCH_ENCODEPTR, REGS_BCH_BASE, 0x00000030) +#define HW_BCH_ENCODEPTR_ADDR (REGS_BCH_BASE + 0x00000030) +#define BP_BCH_ENCODEPTR_ADDR 0 +#define BM_BCH_ENCODEPTR_ADDR 0xFFFFFFFF +#define BF_BCH_ENCODEPTR_ADDR(v) (v) +HW_REGISTER_0(HW_BCH_DATAPTR, REGS_BCH_BASE, 0x00000040) +#define HW_BCH_DATAPTR_ADDR (REGS_BCH_BASE + 0x00000040) +#define BP_BCH_DATAPTR_ADDR 0 +#define BM_BCH_DATAPTR_ADDR 0xFFFFFFFF +#define BF_BCH_DATAPTR_ADDR(v) (v) +HW_REGISTER_0(HW_BCH_METAPTR, REGS_BCH_BASE, 0x00000050) +#define HW_BCH_METAPTR_ADDR (REGS_BCH_BASE + 0x00000050) +#define BP_BCH_METAPTR_ADDR 0 +#define BM_BCH_METAPTR_ADDR 0xFFFFFFFF +#define BF_BCH_METAPTR_ADDR(v) (v) +HW_REGISTER_0(HW_BCH_LAYOUTSELECT, REGS_BCH_BASE, 0x00000070) +#define HW_BCH_LAYOUTSELECT_ADDR (REGS_BCH_BASE + 0x00000070) +#define BP_BCH_LAYOUTSELECT_CS15_SELECT 30 +#define BM_BCH_LAYOUTSELECT_CS15_SELECT 0xC0000000 +#define BF_BCH_LAYOUTSELECT_CS15_SELECT(v) \ + (((v) << 30) & BM_BCH_LAYOUTSELECT_CS15_SELECT) +#define BP_BCH_LAYOUTSELECT_CS14_SELECT 28 +#define BM_BCH_LAYOUTSELECT_CS14_SELECT 0x30000000 +#define BF_BCH_LAYOUTSELECT_CS14_SELECT(v) \ + (((v) << 28) & BM_BCH_LAYOUTSELECT_CS14_SELECT) +#define BP_BCH_LAYOUTSELECT_CS13_SELECT 26 +#define BM_BCH_LAYOUTSELECT_CS13_SELECT 0x0C000000 +#define BF_BCH_LAYOUTSELECT_CS13_SELECT(v) \ + (((v) << 26) & BM_BCH_LAYOUTSELECT_CS13_SELECT) +#define BP_BCH_LAYOUTSELECT_CS12_SELECT 24 +#define BM_BCH_LAYOUTSELECT_CS12_SELECT 0x03000000 +#define BF_BCH_LAYOUTSELECT_CS12_SELECT(v) \ + (((v) << 24) & BM_BCH_LAYOUTSELECT_CS12_SELECT) +#define BP_BCH_LAYOUTSELECT_CS11_SELECT 22 +#define BM_BCH_LAYOUTSELECT_CS11_SELECT 0x00C00000 +#define BF_BCH_LAYOUTSELECT_CS11_SELECT(v) \ + (((v) << 22) & BM_BCH_LAYOUTSELECT_CS11_SELECT) +#define BP_BCH_LAYOUTSELECT_CS10_SELECT 20 +#define BM_BCH_LAYOUTSELECT_CS10_SELECT 0x00300000 +#define BF_BCH_LAYOUTSELECT_CS10_SELECT(v) \ + (((v) << 20) & BM_BCH_LAYOUTSELECT_CS10_SELECT) +#define BP_BCH_LAYOUTSELECT_CS9_SELECT 18 +#define BM_BCH_LAYOUTSELECT_CS9_SELECT 0x000C0000 +#define BF_BCH_LAYOUTSELECT_CS9_SELECT(v) \ + (((v) << 18) & BM_BCH_LAYOUTSELECT_CS9_SELECT) +#define BP_BCH_LAYOUTSELECT_CS8_SELECT 16 +#define BM_BCH_LAYOUTSELECT_CS8_SELECT 0x00030000 +#define BF_BCH_LAYOUTSELECT_CS8_SELECT(v) \ + (((v) << 16) & BM_BCH_LAYOUTSELECT_CS8_SELECT) +#define BP_BCH_LAYOUTSELECT_CS7_SELECT 14 +#define BM_BCH_LAYOUTSELECT_CS7_SELECT 0x0000C000 +#define BF_BCH_LAYOUTSELECT_CS7_SELECT(v) \ + (((v) << 14) & BM_BCH_LAYOUTSELECT_CS7_SELECT) +#define BP_BCH_LAYOUTSELECT_CS6_SELECT 12 +#define BM_BCH_LAYOUTSELECT_CS6_SELECT 0x00003000 +#define BF_BCH_LAYOUTSELECT_CS6_SELECT(v) \ + (((v) << 12) & BM_BCH_LAYOUTSELECT_CS6_SELECT) +#define BP_BCH_LAYOUTSELECT_CS5_SELECT 10 +#define BM_BCH_LAYOUTSELECT_CS5_SELECT 0x00000C00 +#define BF_BCH_LAYOUTSELECT_CS5_SELECT(v) \ + (((v) << 10) & BM_BCH_LAYOUTSELECT_CS5_SELECT) +#define BP_BCH_LAYOUTSELECT_CS4_SELECT 8 +#define BM_BCH_LAYOUTSELECT_CS4_SELECT 0x00000300 +#define BF_BCH_LAYOUTSELECT_CS4_SELECT(v) \ + (((v) << 8) & BM_BCH_LAYOUTSELECT_CS4_SELECT) +#define BP_BCH_LAYOUTSELECT_CS3_SELECT 6 +#define BM_BCH_LAYOUTSELECT_CS3_SELECT 0x000000C0 +#define BF_BCH_LAYOUTSELECT_CS3_SELECT(v) \ + (((v) << 6) & BM_BCH_LAYOUTSELECT_CS3_SELECT) +#define BP_BCH_LAYOUTSELECT_CS2_SELECT 4 +#define BM_BCH_LAYOUTSELECT_CS2_SELECT 0x00000030 +#define BF_BCH_LAYOUTSELECT_CS2_SELECT(v) \ + (((v) << 4) & BM_BCH_LAYOUTSELECT_CS2_SELECT) +#define BP_BCH_LAYOUTSELECT_CS1_SELECT 2 +#define BM_BCH_LAYOUTSELECT_CS1_SELECT 0x0000000C +#define BF_BCH_LAYOUTSELECT_CS1_SELECT(v) \ + (((v) << 2) & BM_BCH_LAYOUTSELECT_CS1_SELECT) +#define BP_BCH_LAYOUTSELECT_CS0_SELECT 0 +#define BM_BCH_LAYOUTSELECT_CS0_SELECT 0x00000003 +#define BF_BCH_LAYOUTSELECT_CS0_SELECT(v) \ + (((v) << 0) & BM_BCH_LAYOUTSELECT_CS0_SELECT) +HW_REGISTER_0(HW_BCH_FLASH0LAYOUT0, REGS_BCH_BASE, 0x00000080) +#define HW_BCH_FLASH0LAYOUT0_ADDR (REGS_BCH_BASE + 0x00000080) +#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH0LAYOUT0_NBLOCKS 0xFF000000 +#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \ + (((v) << 24) & BM_BCH_FLASH0LAYOUT0_NBLOCKS) +#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000 +#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH0LAYOUT0_META_SIZE) +#define BP_BCH_FLASH0LAYOUT0_ECC0 12 +#define BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F000 +#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \ + (((v) << 12) & BM_BCH_FLASH0LAYOUT0_ECC0) +#define BV_BCH_FLASH0LAYOUT0_ECC0__NONE 0x0 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC2 0x1 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC4 0x2 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC6 0x3 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC8 0x4 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC10 0x5 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC12 0x6 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC14 0x7 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC16 0x8 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC18 0x9 +#define BV_BCH_FLASH0LAYOUT0_ECC0__ECC20 0xA +#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x00000FFF +#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) +HW_REGISTER_0(HW_BCH_FLASH0LAYOUT1, REGS_BCH_BASE, 0x00000090) +#define HW_BCH_FLASH0LAYOUT1_ADDR (REGS_BCH_BASE + 0x00000090) +#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000 +#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE) +#define BP_BCH_FLASH0LAYOUT1_ECCN 12 +#define BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F000 +#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \ + (((v) << 12) & BM_BCH_FLASH0LAYOUT1_ECCN) +#define BV_BCH_FLASH0LAYOUT1_ECCN__NONE 0x0 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC2 0x1 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC4 0x2 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC6 0x3 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC8 0x4 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC10 0x5 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC12 0x6 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC14 0x7 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC16 0x8 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC18 0x9 +#define BV_BCH_FLASH0LAYOUT1_ECCN__ECC20 0xA +#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x00000FFF +#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) +HW_REGISTER_0(HW_BCH_FLASH1LAYOUT0, REGS_BCH_BASE, 0x000000a0) +#define HW_BCH_FLASH1LAYOUT0_ADDR (REGS_BCH_BASE + 0x000000a0) +#define BP_BCH_FLASH1LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH1LAYOUT0_NBLOCKS 0xFF000000 +#define BF_BCH_FLASH1LAYOUT0_NBLOCKS(v) \ + (((v) << 24) & BM_BCH_FLASH1LAYOUT0_NBLOCKS) +#define BP_BCH_FLASH1LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH1LAYOUT0_META_SIZE 0x00FF0000 +#define BF_BCH_FLASH1LAYOUT0_META_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH1LAYOUT0_META_SIZE) +#define BP_BCH_FLASH1LAYOUT0_ECC0 12 +#define BM_BCH_FLASH1LAYOUT0_ECC0 0x0000F000 +#define BF_BCH_FLASH1LAYOUT0_ECC0(v) \ + (((v) << 12) & BM_BCH_FLASH1LAYOUT0_ECC0) +#define BV_BCH_FLASH1LAYOUT0_ECC0__NONE 0x0 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC2 0x1 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC4 0x2 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC6 0x3 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC8 0x4 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC10 0x5 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC12 0x6 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC14 0x7 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC16 0x8 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC18 0x9 +#define BV_BCH_FLASH1LAYOUT0_ECC0__ECC20 0xA +#define BP_BCH_FLASH1LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH1LAYOUT0_DATA0_SIZE 0x00000FFF +#define BF_BCH_FLASH1LAYOUT0_DATA0_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH1LAYOUT0_DATA0_SIZE) +HW_REGISTER_0(HW_BCH_FLASH1LAYOUT1, REGS_BCH_BASE, 0x000000b0) +#define HW_BCH_FLASH1LAYOUT1_ADDR (REGS_BCH_BASE + 0x000000b0) +#define BP_BCH_FLASH1LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH1LAYOUT1_PAGE_SIZE 0xFFFF0000 +#define BF_BCH_FLASH1LAYOUT1_PAGE_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH1LAYOUT1_PAGE_SIZE) +#define BP_BCH_FLASH1LAYOUT1_ECCN 12 +#define BM_BCH_FLASH1LAYOUT1_ECCN 0x0000F000 +#define BF_BCH_FLASH1LAYOUT1_ECCN(v) \ + (((v) << 12) & BM_BCH_FLASH1LAYOUT1_ECCN) +#define BV_BCH_FLASH1LAYOUT1_ECCN__NONE 0x0 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC2 0x1 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC4 0x2 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC6 0x3 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC8 0x4 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC10 0x5 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC12 0x6 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC14 0x7 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC16 0x8 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC18 0x9 +#define BV_BCH_FLASH1LAYOUT1_ECCN__ECC20 0xA +#define BP_BCH_FLASH1LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH1LAYOUT1_DATAN_SIZE 0x00000FFF +#define BF_BCH_FLASH1LAYOUT1_DATAN_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH1LAYOUT1_DATAN_SIZE) +HW_REGISTER_0(HW_BCH_FLASH2LAYOUT0, REGS_BCH_BASE, 0x000000c0) +#define HW_BCH_FLASH2LAYOUT0_ADDR (REGS_BCH_BASE + 0x000000c0) +#define BP_BCH_FLASH2LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH2LAYOUT0_NBLOCKS 0xFF000000 +#define BF_BCH_FLASH2LAYOUT0_NBLOCKS(v) \ + (((v) << 24) & BM_BCH_FLASH2LAYOUT0_NBLOCKS) +#define BP_BCH_FLASH2LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH2LAYOUT0_META_SIZE 0x00FF0000 +#define BF_BCH_FLASH2LAYOUT0_META_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH2LAYOUT0_META_SIZE) +#define BP_BCH_FLASH2LAYOUT0_ECC0 12 +#define BM_BCH_FLASH2LAYOUT0_ECC0 0x0000F000 +#define BF_BCH_FLASH2LAYOUT0_ECC0(v) \ + (((v) << 12) & BM_BCH_FLASH2LAYOUT0_ECC0) +#define BV_BCH_FLASH2LAYOUT0_ECC0__NONE 0x0 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC2 0x1 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC4 0x2 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC6 0x3 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC8 0x4 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC10 0x5 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC12 0x6 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC14 0x7 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC16 0x8 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC18 0x9 +#define BV_BCH_FLASH2LAYOUT0_ECC0__ECC20 0xA +#define BP_BCH_FLASH2LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH2LAYOUT0_DATA0_SIZE 0x00000FFF +#define BF_BCH_FLASH2LAYOUT0_DATA0_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH2LAYOUT0_DATA0_SIZE) +HW_REGISTER_0(HW_BCH_FLASH2LAYOUT1, REGS_BCH_BASE, 0x000000d0) +#define HW_BCH_FLASH2LAYOUT1_ADDR (REGS_BCH_BASE + 0x000000d0) +#define BP_BCH_FLASH2LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH2LAYOUT1_PAGE_SIZE 0xFFFF0000 +#define BF_BCH_FLASH2LAYOUT1_PAGE_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH2LAYOUT1_PAGE_SIZE) +#define BP_BCH_FLASH2LAYOUT1_ECCN 12 +#define BM_BCH_FLASH2LAYOUT1_ECCN 0x0000F000 +#define BF_BCH_FLASH2LAYOUT1_ECCN(v) \ + (((v) << 12) & BM_BCH_FLASH2LAYOUT1_ECCN) +#define BV_BCH_FLASH2LAYOUT1_ECCN__NONE 0x0 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC2 0x1 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC4 0x2 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC6 0x3 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC8 0x4 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC10 0x5 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC12 0x6 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC14 0x7 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC16 0x8 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC18 0x9 +#define BV_BCH_FLASH2LAYOUT1_ECCN__ECC20 0xA +#define BP_BCH_FLASH2LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH2LAYOUT1_DATAN_SIZE 0x00000FFF +#define BF_BCH_FLASH2LAYOUT1_DATAN_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH2LAYOUT1_DATAN_SIZE) +HW_REGISTER_0(HW_BCH_FLASH3LAYOUT0, REGS_BCH_BASE, 0x000000e0) +#define HW_BCH_FLASH3LAYOUT0_ADDR (REGS_BCH_BASE + 0x000000e0) +#define BP_BCH_FLASH3LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH3LAYOUT0_NBLOCKS 0xFF000000 +#define BF_BCH_FLASH3LAYOUT0_NBLOCKS(v) \ + (((v) << 24) & BM_BCH_FLASH3LAYOUT0_NBLOCKS) +#define BP_BCH_FLASH3LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH3LAYOUT0_META_SIZE 0x00FF0000 +#define BF_BCH_FLASH3LAYOUT0_META_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH3LAYOUT0_META_SIZE) +#define BP_BCH_FLASH3LAYOUT0_ECC0 12 +#define BM_BCH_FLASH3LAYOUT0_ECC0 0x0000F000 +#define BF_BCH_FLASH3LAYOUT0_ECC0(v) \ + (((v) << 12) & BM_BCH_FLASH3LAYOUT0_ECC0) +#define BV_BCH_FLASH3LAYOUT0_ECC0__NONE 0x0 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC2 0x1 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC4 0x2 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC6 0x3 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC8 0x4 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC10 0x5 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC12 0x6 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC14 0x7 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC16 0x8 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC18 0x9 +#define BV_BCH_FLASH3LAYOUT0_ECC0__ECC20 0xA +#define BP_BCH_FLASH3LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH3LAYOUT0_DATA0_SIZE 0x00000FFF +#define BF_BCH_FLASH3LAYOUT0_DATA0_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH3LAYOUT0_DATA0_SIZE) +HW_REGISTER_0(HW_BCH_FLASH3LAYOUT1, REGS_BCH_BASE, 0x000000f0) +#define HW_BCH_FLASH3LAYOUT1_ADDR (REGS_BCH_BASE + 0x000000f0) +#define BP_BCH_FLASH3LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH3LAYOUT1_PAGE_SIZE 0xFFFF0000 +#define BF_BCH_FLASH3LAYOUT1_PAGE_SIZE(v) \ + (((v) << 16) & BM_BCH_FLASH3LAYOUT1_PAGE_SIZE) +#define BP_BCH_FLASH3LAYOUT1_ECCN 12 +#define BM_BCH_FLASH3LAYOUT1_ECCN 0x0000F000 +#define BF_BCH_FLASH3LAYOUT1_ECCN(v) \ + (((v) << 12) & BM_BCH_FLASH3LAYOUT1_ECCN) +#define BV_BCH_FLASH3LAYOUT1_ECCN__NONE 0x0 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC2 0x1 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC4 0x2 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC6 0x3 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC8 0x4 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC10 0x5 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC12 0x6 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC14 0x7 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC16 0x8 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC18 0x9 +#define BV_BCH_FLASH3LAYOUT1_ECCN__ECC20 0xA +#define BP_BCH_FLASH3LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH3LAYOUT1_DATAN_SIZE 0x00000FFF +#define BF_BCH_FLASH3LAYOUT1_DATAN_SIZE(v) \ + (((v) << 0) & BM_BCH_FLASH3LAYOUT1_DATAN_SIZE) +HW_REGISTER(HW_BCH_DEBUG0, REGS_BCH_BASE, 0x00000100) +#define HW_BCH_DEBUG0_ADDR (REGS_BCH_BASE + 0x00000100) +#define BM_BCH_DEBUG0_ROM_BIST_ENABLE 0x04000000 +#define BM_BCH_DEBUG0_ROM_BIST_COMPLETE 0x02000000 +#define BP_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 16 +#define BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 0x01FF0000 +#define BF_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL(v) \ + (((v) << 16) & BM_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL) +#define BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__NORMAL 0x0 +#define BV_BCH_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__TEST_MODE 0x1 +#define BM_BCH_DEBUG0_KES_DEBUG_SHIFT_SYND 0x00008000 +#define BM_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG 0x00004000 +#define BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__DATA 0x1 +#define BV_BCH_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__AUX 0x1 +#define BM_BCH_DEBUG0_KES_DEBUG_MODE4K 0x00002000 +#define BV_BCH_DEBUG0_KES_DEBUG_MODE4K__4k 0x1 +#define BV_BCH_DEBUG0_KES_DEBUG_MODE4K__2k 0x1 +#define BM_BCH_DEBUG0_KES_DEBUG_KICK 0x00001000 +#define BM_BCH_DEBUG0_KES_STANDALONE 0x00000800 +#define BV_BCH_DEBUG0_KES_STANDALONE__NORMAL 0x0 +#define BV_BCH_DEBUG0_KES_STANDALONE__TEST_MODE 0x1 +#define BM_BCH_DEBUG0_KES_DEBUG_STEP 0x00000400 +#define BM_BCH_DEBUG0_KES_DEBUG_STALL 0x00000200 +#define BV_BCH_DEBUG0_KES_DEBUG_STALL__NORMAL 0x0 +#define BV_BCH_DEBUG0_KES_DEBUG_STALL__WAIT 0x1 +#define BM_BCH_DEBUG0_BM_KES_TEST_BYPASS 0x00000100 +#define BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__NORMAL 0x0 +#define BV_BCH_DEBUG0_BM_KES_TEST_BYPASS__TEST_MODE 0x1 +#define BP_BCH_DEBUG0_DEBUG_REG_SELECT 0 +#define BM_BCH_DEBUG0_DEBUG_REG_SELECT 0x0000003F +#define BF_BCH_DEBUG0_DEBUG_REG_SELECT(v) \ + (((v) << 0) & BM_BCH_DEBUG0_DEBUG_REG_SELECT) +HW_REGISTER_0(HW_BCH_DBGKESREAD, REGS_BCH_BASE, 0x00000110) +#define HW_BCH_DBGKESREAD_ADDR (REGS_BCH_BASE + 0x00000110) +#define BP_BCH_DBGKESREAD_VALUES 0 +#define BM_BCH_DBGKESREAD_VALUES 0xFFFFFFFF +#define BF_BCH_DBGKESREAD_VALUES(v) (v) +HW_REGISTER_0(HW_BCH_DBGCSFEREAD, REGS_BCH_BASE, 0x00000120) +#define HW_BCH_DBGCSFEREAD_ADDR (REGS_BCH_BASE + 0x00000120) +#define BP_BCH_DBGCSFEREAD_VALUES 0 +#define BM_BCH_DBGCSFEREAD_VALUES 0xFFFFFFFF +#define BF_BCH_DBGCSFEREAD_VALUES(v) (v) +HW_REGISTER_0(HW_BCH_DBGSYNDGENREAD, REGS_BCH_BASE, 0x00000130) +#define HW_BCH_DBGSYNDGENREAD_ADDR (REGS_BCH_BASE + 0x00000130) +#define BP_BCH_DBGSYNDGENREAD_VALUES 0 +#define BM_BCH_DBGSYNDGENREAD_VALUES 0xFFFFFFFF +#define BF_BCH_DBGSYNDGENREAD_VALUES(v) (v) +HW_REGISTER_0(HW_BCH_DBGAHBMREAD, REGS_BCH_BASE, 0x00000140) +#define HW_BCH_DBGAHBMREAD_ADDR (REGS_BCH_BASE + 0x00000140) +#define BP_BCH_DBGAHBMREAD_VALUES 0 +#define BM_BCH_DBGAHBMREAD_VALUES 0xFFFFFFFF +#define BF_BCH_DBGAHBMREAD_VALUES(v) (v) +HW_REGISTER_0(HW_BCH_BLOCKNAME, REGS_BCH_BASE, 0x00000150) +#define HW_BCH_BLOCKNAME_ADDR (REGS_BCH_BASE + 0x00000150) +#define BP_BCH_BLOCKNAME_NAME 0 +#define BM_BCH_BLOCKNAME_NAME 0xFFFFFFFF +#define BF_BCH_BLOCKNAME_NAME(v) (v) +HW_REGISTER_0(HW_BCH_VERSION, REGS_BCH_BASE, 0x00000160) +#define HW_BCH_VERSION_ADDR (REGS_BCH_BASE + 0x00000160) +#define BP_BCH_VERSION_MAJOR 24 +#define BM_BCH_VERSION_MAJOR 0xFF000000 +#define BF_BCH_VERSION_MAJOR(v) \ + (((v) << 24) & BM_BCH_VERSION_MAJOR) +#define BP_BCH_VERSION_MINOR 16 +#define BM_BCH_VERSION_MINOR 0x00FF0000 +#define BF_BCH_VERSION_MINOR(v) \ + (((v) << 16) & BM_BCH_VERSION_MINOR) +#define BP_BCH_VERSION_STEP 0 +#define BM_BCH_VERSION_STEP 0x0000FFFF +#define BF_BCH_VERSION_STEP(v) \ + (((v) << 0) & BM_BCH_VERSION_STEP) +#endif /* __ARCH_ARM___BCH_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp3xxx/include/mach/regs-clkctrl.h new file mode 100644 index 000000000000..49705907fa6e --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-clkctrl.h @@ -0,0 +1,275 @@ +/* + * STMP CLKCTRL Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___CLKCTRL_H +#define __ARCH_ARM___CLKCTRL_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_CLKCTRL_BASE (REGS_BASE + 0x40000) +#define REGS_CLKCTRL_BASE_PHYS (0x80040000) +#define REGS_CLKCTRL_SIZE 0x00002000 +HW_REGISTER(HW_CLKCTRL_PLLCTRL0, REGS_CLKCTRL_BASE, 0x00000000) +#define HW_CLKCTRL_PLLCTRL0_ADDR (REGS_CLKCTRL_BASE + 0x00000000) +#define BP_CLKCTRL_PLLCTRL0_LFR_SEL 28 +#define BM_CLKCTRL_PLLCTRL0_LFR_SEL 0x30000000 +#define BF_CLKCTRL_PLLCTRL0_LFR_SEL(v) \ + (((v) << 28) & BM_CLKCTRL_PLLCTRL0_LFR_SEL) +#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__DEFAULT 0x0 +#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_2 0x1 +#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_05 0x2 +#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__UNDEFINED 0x3 +#define BP_CLKCTRL_PLLCTRL0_CP_SEL 24 +#define BM_CLKCTRL_PLLCTRL0_CP_SEL 0x03000000 +#define BF_CLKCTRL_PLLCTRL0_CP_SEL(v) \ + (((v) << 24) & BM_CLKCTRL_PLLCTRL0_CP_SEL) +#define BV_CLKCTRL_PLLCTRL0_CP_SEL__DEFAULT 0x0 +#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_2 0x1 +#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_05 0x2 +#define BV_CLKCTRL_PLLCTRL0_CP_SEL__UNDEFINED 0x3 +#define BP_CLKCTRL_PLLCTRL0_DIV_SEL 20 +#define BM_CLKCTRL_PLLCTRL0_DIV_SEL 0x00300000 +#define BF_CLKCTRL_PLLCTRL0_DIV_SEL(v) \ + (((v) << 20) & BM_CLKCTRL_PLLCTRL0_DIV_SEL) +#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__DEFAULT 0x0 +#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWER 0x1 +#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWEST 0x2 +#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__UNDEFINED 0x3 +#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS 0x00040000 +#define BM_CLKCTRL_PLLCTRL0_POWER 0x00010000 +HW_REGISTER_0(HW_CLKCTRL_PLLCTRL1, REGS_CLKCTRL_BASE, 0x00000010) +#define HW_CLKCTRL_PLLCTRL1_ADDR (REGS_CLKCTRL_BASE + 0x00000010) +#define BM_CLKCTRL_PLLCTRL1_LOCK 0x80000000 +#define BM_CLKCTRL_PLLCTRL1_FORCE_LOCK 0x40000000 +#define BP_CLKCTRL_PLLCTRL1_LOCK_COUNT 0 +#define BM_CLKCTRL_PLLCTRL1_LOCK_COUNT 0x0000FFFF +#define BF_CLKCTRL_PLLCTRL1_LOCK_COUNT(v) \ + (((v) << 0) & BM_CLKCTRL_PLLCTRL1_LOCK_COUNT) +HW_REGISTER(HW_CLKCTRL_CPU, REGS_CLKCTRL_BASE, 0x00000020) +#define HW_CLKCTRL_CPU_ADDR (REGS_CLKCTRL_BASE + 0x00000020) +#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000 +#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000 +#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000 +#define BP_CLKCTRL_CPU_DIV_XTAL 16 +#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000 +#define BF_CLKCTRL_CPU_DIV_XTAL(v) \ + (((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL) +#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000 +#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400 +#define BP_CLKCTRL_CPU_DIV_CPU 0 +#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F +#define BF_CLKCTRL_CPU_DIV_CPU(v) \ + (((v) << 0) & BM_CLKCTRL_CPU_DIV_CPU) +HW_REGISTER(HW_CLKCTRL_HBUS, REGS_CLKCTRL_BASE, 0x00000030) +#define HW_CLKCTRL_HBUS_ADDR (REGS_CLKCTRL_BASE + 0x00000030) +#define BM_CLKCTRL_HBUS_BUSY 0x20000000 +#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x10000000 +#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x08000000 +#define BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE 0x04000000 +#define BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE 0x02000000 +#define BM_CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE 0x01000000 +#define BM_CLKCTRL_HBUS_TRAFFIC_AS_ENABLE 0x00800000 +#define BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE 0x00400000 +#define BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE 0x00200000 +#define BM_CLKCTRL_HBUS_AUTO_SLOW_MODE 0x00100000 +#define BP_CLKCTRL_HBUS_SLOW_DIV 16 +#define BM_CLKCTRL_HBUS_SLOW_DIV 0x00070000 +#define BF_CLKCTRL_HBUS_SLOW_DIV(v) \ + (((v) << 16) & BM_CLKCTRL_HBUS_SLOW_DIV) +#define BV_CLKCTRL_HBUS_SLOW_DIV__BY1 0x0 +#define BV_CLKCTRL_HBUS_SLOW_DIV__BY2 0x1 +#define BV_CLKCTRL_HBUS_SLOW_DIV__BY4 0x2 +#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3 +#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4 +#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5 +#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020 +#define BP_CLKCTRL_HBUS_DIV 0 +#define BM_CLKCTRL_HBUS_DIV 0x0000001F +#define BF_CLKCTRL_HBUS_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_HBUS_DIV) +HW_REGISTER_0(HW_CLKCTRL_XBUS, REGS_CLKCTRL_BASE, 0x00000040) +#define HW_CLKCTRL_XBUS_ADDR (REGS_CLKCTRL_BASE + 0x00000040) +#define BM_CLKCTRL_XBUS_BUSY 0x80000000 +#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400 +#define BP_CLKCTRL_XBUS_DIV 0 +#define BM_CLKCTRL_XBUS_DIV 0x000003FF +#define BF_CLKCTRL_XBUS_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_XBUS_DIV) +HW_REGISTER(HW_CLKCTRL_XTAL, REGS_CLKCTRL_BASE, 0x00000050) +#define HW_CLKCTRL_XTAL_ADDR (REGS_CLKCTRL_BASE + 0x00000050) +#define BM_CLKCTRL_XTAL_UART_CLK_GATE 0x80000000 +#define BM_CLKCTRL_XTAL_FILT_CLK24M_GATE 0x40000000 +#define BM_CLKCTRL_XTAL_PWM_CLK24M_GATE 0x20000000 +#define BM_CLKCTRL_XTAL_DRI_CLK24M_GATE 0x10000000 +#define BM_CLKCTRL_XTAL_DIGCTRL_CLK1M_GATE 0x08000000 +#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000 +#define BP_CLKCTRL_XTAL_DIV_UART 0 +#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003 +#define BF_CLKCTRL_XTAL_DIV_UART(v) \ + (((v) << 0) & BM_CLKCTRL_XTAL_DIV_UART) +HW_REGISTER_0(HW_CLKCTRL_PIX, REGS_CLKCTRL_BASE, 0x00000060) +#define HW_CLKCTRL_PIX_ADDR (REGS_CLKCTRL_BASE + 0x00000060) +#define BM_CLKCTRL_PIX_CLKGATE 0x80000000 +#define BM_CLKCTRL_PIX_BUSY 0x20000000 +#define BM_CLKCTRL_PIX_DIV_FRAC_EN 0x00001000 +#define BP_CLKCTRL_PIX_DIV 0 +#define BM_CLKCTRL_PIX_DIV 0x00000FFF +#define BF_CLKCTRL_PIX_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_PIX_DIV) +HW_REGISTER_0(HW_CLKCTRL_SSP, REGS_CLKCTRL_BASE, 0x00000070) +#define HW_CLKCTRL_SSP_ADDR (REGS_CLKCTRL_BASE + 0x00000070) +#define BM_CLKCTRL_SSP_CLKGATE 0x80000000 +#define BM_CLKCTRL_SSP_BUSY 0x20000000 +#define BM_CLKCTRL_SSP_DIV_FRAC_EN 0x00000200 +#define BP_CLKCTRL_SSP_DIV 0 +#define BM_CLKCTRL_SSP_DIV 0x000001FF +#define BF_CLKCTRL_SSP_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_SSP_DIV) +HW_REGISTER_0(HW_CLKCTRL_GPMI, REGS_CLKCTRL_BASE, 0x00000080) +#define HW_CLKCTRL_GPMI_ADDR (REGS_CLKCTRL_BASE + 0x00000080) +#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000 +#define BM_CLKCTRL_GPMI_BUSY 0x20000000 +#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400 +#define BP_CLKCTRL_GPMI_DIV 0 +#define BM_CLKCTRL_GPMI_DIV 0x000003FF +#define BF_CLKCTRL_GPMI_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_GPMI_DIV) +HW_REGISTER_0(HW_CLKCTRL_SPDIF, REGS_CLKCTRL_BASE, 0x00000090) +#define HW_CLKCTRL_SPDIF_ADDR (REGS_CLKCTRL_BASE + 0x00000090) +#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000 +HW_REGISTER_0(HW_CLKCTRL_EMI, REGS_CLKCTRL_BASE, 0x000000a0) +#define HW_CLKCTRL_EMI_ADDR (REGS_CLKCTRL_BASE + 0x000000a0) +#define BM_CLKCTRL_EMI_CLKGATE 0x80000000 +#define BM_CLKCTRL_EMI_SYNC_MODE_EN 0x40000000 +#define BM_CLKCTRL_EMI_BUSY_REF_XTAL 0x20000000 +#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000 +#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000 +#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000 +#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000 +#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000 +#define BP_CLKCTRL_EMI_DIV_XTAL 8 +#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00 +#define BF_CLKCTRL_EMI_DIV_XTAL(v) \ + (((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL) +#define BP_CLKCTRL_EMI_DIV_EMI 0 +#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F +#define BF_CLKCTRL_EMI_DIV_EMI(v) \ + (((v) << 0) & BM_CLKCTRL_EMI_DIV_EMI) +HW_REGISTER_0(HW_CLKCTRL_IR, REGS_CLKCTRL_BASE, 0x000000b0) +#define HW_CLKCTRL_IR_ADDR (REGS_CLKCTRL_BASE + 0x000000b0) +#define BM_CLKCTRL_IR_CLKGATE 0x80000000 +#define BM_CLKCTRL_IR_AUTO_DIV 0x20000000 +#define BM_CLKCTRL_IR_IR_BUSY 0x10000000 +#define BM_CLKCTRL_IR_IROV_BUSY 0x08000000 +#define BP_CLKCTRL_IR_IROV_DIV 16 +#define BM_CLKCTRL_IR_IROV_DIV 0x01FF0000 +#define BF_CLKCTRL_IR_IROV_DIV(v) \ + (((v) << 16) & BM_CLKCTRL_IR_IROV_DIV) +#define BP_CLKCTRL_IR_IR_DIV 0 +#define BM_CLKCTRL_IR_IR_DIV 0x000003FF +#define BF_CLKCTRL_IR_IR_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_IR_IR_DIV) +HW_REGISTER_0(HW_CLKCTRL_SAIF, REGS_CLKCTRL_BASE, 0x000000c0) +#define HW_CLKCTRL_SAIF_ADDR (REGS_CLKCTRL_BASE + 0x000000c0) +#define BM_CLKCTRL_SAIF_CLKGATE 0x80000000 +#define BM_CLKCTRL_SAIF_BUSY 0x20000000 +#define BM_CLKCTRL_SAIF_DIV_FRAC_EN 0x00010000 +#define BP_CLKCTRL_SAIF_DIV 0 +#define BM_CLKCTRL_SAIF_DIV 0x0000FFFF +#define BF_CLKCTRL_SAIF_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_SAIF_DIV) +HW_REGISTER_0(HW_CLKCTRL_TV, REGS_CLKCTRL_BASE, 0x000000d0) +#define HW_CLKCTRL_TV_ADDR (REGS_CLKCTRL_BASE + 0x000000d0) +#define BM_CLKCTRL_TV_CLK_TV108M_GATE 0x80000000 +#define BM_CLKCTRL_TV_CLK_TV_GATE 0x40000000 +HW_REGISTER_0(HW_CLKCTRL_ETM, REGS_CLKCTRL_BASE, 0x000000e0) +#define HW_CLKCTRL_ETM_ADDR (REGS_CLKCTRL_BASE + 0x000000e0) +#define BM_CLKCTRL_ETM_CLKGATE 0x80000000 +#define BM_CLKCTRL_ETM_BUSY 0x20000000 +#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000040 +#define BP_CLKCTRL_ETM_DIV 0 +#define BM_CLKCTRL_ETM_DIV 0x0000003F +#define BF_CLKCTRL_ETM_DIV(v) \ + (((v) << 0) & BM_CLKCTRL_ETM_DIV) +HW_REGISTER(HW_CLKCTRL_FRAC, REGS_CLKCTRL_BASE, 0x000000f0) +#define HW_CLKCTRL_FRAC_ADDR (REGS_CLKCTRL_BASE + 0x000000f0) +#define BM_CLKCTRL_FRAC_CLKGATEIO 0x80000000 +#define BM_CLKCTRL_FRAC_IO_STABLE 0x40000000 +#define BP_CLKCTRL_FRAC_IOFRAC 24 +#define BM_CLKCTRL_FRAC_IOFRAC 0x3F000000 +#define BF_CLKCTRL_FRAC_IOFRAC(v) \ + (((v) << 24) & BM_CLKCTRL_FRAC_IOFRAC) +#define BM_CLKCTRL_FRAC_CLKGATEPIX 0x00800000 +#define BM_CLKCTRL_FRAC_PIX_STABLE 0x00400000 +#define BP_CLKCTRL_FRAC_PIXFRAC 16 +#define BM_CLKCTRL_FRAC_PIXFRAC 0x003F0000 +#define BF_CLKCTRL_FRAC_PIXFRAC(v) \ + (((v) << 16) & BM_CLKCTRL_FRAC_PIXFRAC) +#define BM_CLKCTRL_FRAC_CLKGATEEMI 0x00008000 +#define BM_CLKCTRL_FRAC_EMI_STABLE 0x00004000 +#define BP_CLKCTRL_FRAC_EMIFRAC 8 +#define BM_CLKCTRL_FRAC_EMIFRAC 0x00003F00 +#define BF_CLKCTRL_FRAC_EMIFRAC(v) \ + (((v) << 8) & BM_CLKCTRL_FRAC_EMIFRAC) +#define BM_CLKCTRL_FRAC_CLKGATECPU 0x00000080 +#define BM_CLKCTRL_FRAC_CPU_STABLE 0x00000040 +#define BP_CLKCTRL_FRAC_CPUFRAC 0 +#define BM_CLKCTRL_FRAC_CPUFRAC 0x0000003F +#define BF_CLKCTRL_FRAC_CPUFRAC(v) \ + (((v) << 0) & BM_CLKCTRL_FRAC_CPUFRAC) +HW_REGISTER(HW_CLKCTRL_FRAC1, REGS_CLKCTRL_BASE, 0x00000100) +#define HW_CLKCTRL_FRAC1_ADDR (REGS_CLKCTRL_BASE + 0x00000100) +#define BM_CLKCTRL_FRAC1_CLKGATEVID 0x80000000 +#define BM_CLKCTRL_FRAC1_VID_STABLE 0x40000000 +HW_REGISTER(HW_CLKCTRL_CLKSEQ, REGS_CLKCTRL_BASE, 0x00000110) +#define HW_CLKCTRL_CLKSEQ_ADDR (REGS_CLKCTRL_BASE + 0x00000110) +#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100 +#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00000080 +#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000040 +#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP 0x00000020 +#define BM_CLKCTRL_CLKSEQ_BYPASS_GPMI 0x00000010 +#define BM_CLKCTRL_CLKSEQ_BYPASS_IR 0x00000008 +#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX 0x00000002 +#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF 0x00000001 +HW_REGISTER_0(HW_CLKCTRL_RESET, REGS_CLKCTRL_BASE, 0x00000120) +#define HW_CLKCTRL_RESET_ADDR (REGS_CLKCTRL_BASE + 0x00000120) +#define BM_CLKCTRL_RESET_CHIP 0x00000002 +#define BM_CLKCTRL_RESET_DIG 0x00000001 +HW_REGISTER_0(HW_CLKCTRL_STATUS, REGS_CLKCTRL_BASE, 0x00000130) +#define HW_CLKCTRL_STATUS_ADDR (REGS_CLKCTRL_BASE + 0x00000130) +#define BP_CLKCTRL_STATUS_CPU_LIMIT 30 +#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000 +#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \ + (((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT) +HW_REGISTER_0(HW_CLKCTRL_VERSION, REGS_CLKCTRL_BASE, 0x00000140) +#define HW_CLKCTRL_VERSION_ADDR (REGS_CLKCTRL_BASE + 0x00000140) +#define BP_CLKCTRL_VERSION_MAJOR 24 +#define BM_CLKCTRL_VERSION_MAJOR 0xFF000000 +#define BF_CLKCTRL_VERSION_MAJOR(v) \ + (((v) << 24) & BM_CLKCTRL_VERSION_MAJOR) +#define BP_CLKCTRL_VERSION_MINOR 16 +#define BM_CLKCTRL_VERSION_MINOR 0x00FF0000 +#define BF_CLKCTRL_VERSION_MINOR(v) \ + (((v) << 16) & BM_CLKCTRL_VERSION_MINOR) +#define BP_CLKCTRL_VERSION_STEP 0 +#define BM_CLKCTRL_VERSION_STEP 0x0000FFFF +#define BF_CLKCTRL_VERSION_STEP(v) \ + (((v) << 0) & BM_CLKCTRL_VERSION_STEP) +#endif /* __ARCH_ARM___CLKCTRL_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-dcp.h b/arch/arm/mach-stmp3xxx/include/mach/regs-dcp.h new file mode 100644 index 000000000000..014fae206f74 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-dcp.h @@ -0,0 +1,481 @@ +/* + * STMP DCP Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___DCP_H +#define __ARCH_ARM___DCP_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_DCP_BASE (REGS_BASE + 0x28000) +#define REGS_DCP_BASE_PHYS (0x80028000) +#define REGS_DCP_SIZE 0x00002000 +HW_REGISTER(HW_DCP_CTRL, REGS_DCP_BASE, 0x00000000) +#define HW_DCP_CTRL_ADDR (REGS_DCP_BASE + 0x00000000) +#define BM_DCP_CTRL_SFTRST 0x80000000 +#define BM_DCP_CTRL_CLKGATE 0x40000000 +#define BM_DCP_CTRL_PRESENT_CRYPTO 0x20000000 +#define BV_DCP_CTRL_PRESENT_CRYPTO__Present 0x1 +#define BV_DCP_CTRL_PRESENT_CRYPTO__Absent 0x0 +#define BM_DCP_CTRL_PRESENT_CSC 0x10000000 +#define BV_DCP_CTRL_PRESENT_CSC__Present 0x1 +#define BV_DCP_CTRL_PRESENT_CSC__Absent 0x0 +#define BM_DCP_CTRL_GATHER_RESIDUAL_WRITES 0x00800000 +#define BM_DCP_CTRL_ENABLE_CONTEXT_CACHING 0x00400000 +#define BM_DCP_CTRL_ENABLE_CONTEXT_SWITCHING 0x00200000 +#define BM_DCP_CTRL_CSC_INTERRUPT_ENABLE 0x00000100 +#define BP_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE 0 +#define BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE 0x000000FF +#define BF_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE(v) \ + (((v) << 0) & BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE) +#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH0 0x01 +#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH1 0x02 +#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH2 0x04 +#define BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH3 0x08 +HW_REGISTER(HW_DCP_STAT, REGS_DCP_BASE, 0x00000010) +#define HW_DCP_STAT_ADDR (REGS_DCP_BASE + 0x00000010) +#define BM_DCP_STAT_OTP_KEY_READY 0x10000000 +#define BP_DCP_STAT_CUR_CHANNEL 24 +#define BM_DCP_STAT_CUR_CHANNEL 0x0F000000 +#define BF_DCP_STAT_CUR_CHANNEL(v) \ + (((v) << 24) & BM_DCP_STAT_CUR_CHANNEL) +#define BV_DCP_STAT_CUR_CHANNEL__None 0x0 +#define BV_DCP_STAT_CUR_CHANNEL__CH0 0x1 +#define BV_DCP_STAT_CUR_CHANNEL__CH1 0x2 +#define BV_DCP_STAT_CUR_CHANNEL__CH2 0x3 +#define BV_DCP_STAT_CUR_CHANNEL__CH3 0x4 +#define BV_DCP_STAT_CUR_CHANNEL__CSC 0x8 +#define BP_DCP_STAT_READY_CHANNELS 16 +#define BM_DCP_STAT_READY_CHANNELS 0x00FF0000 +#define BF_DCP_STAT_READY_CHANNELS(v) \ + (((v) << 16) & BM_DCP_STAT_READY_CHANNELS) +#define BV_DCP_STAT_READY_CHANNELS__CH0 0x01 +#define BV_DCP_STAT_READY_CHANNELS__CH1 0x02 +#define BV_DCP_STAT_READY_CHANNELS__CH2 0x04 +#define BV_DCP_STAT_READY_CHANNELS__CH3 0x08 +#define BM_DCP_STAT_CSCIRQ 0x00000100 +#define BP_DCP_STAT_IRQ 0 +#define BM_DCP_STAT_IRQ 0x0000000F +#define BF_DCP_STAT_IRQ(v) \ + (((v) << 0) & BM_DCP_STAT_IRQ) +HW_REGISTER(HW_DCP_CHANNELCTRL, REGS_DCP_BASE, 0x00000020) +#define HW_DCP_CHANNELCTRL_ADDR (REGS_DCP_BASE + 0x00000020) +#define BP_DCP_CHANNELCTRL_CSC_PRIORITY 17 +#define BM_DCP_CHANNELCTRL_CSC_PRIORITY 0x00060000 +#define BF_DCP_CHANNELCTRL_CSC_PRIORITY(v) \ + (((v) << 17) & BM_DCP_CHANNELCTRL_CSC_PRIORITY) +#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__HIGH 0x3 +#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__MED 0x2 +#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__LOW 0x1 +#define BV_DCP_CHANNELCTRL_CSC_PRIORITY__BACKGROUND 0x0 +#define BM_DCP_CHANNELCTRL_CH0_IRQ_MERGED 0x00010000 +#define BP_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL 8 +#define BM_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL 0x0000FF00 +#define BF_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL(v) \ + (((v) << 8) & BM_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL) +#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH0 0x01 +#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH1 0x02 +#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH2 0x04 +#define BV_DCP_CHANNELCTRL_HIGH_PRIORITY_CHANNEL__CH3 0x08 +#define BP_DCP_CHANNELCTRL_ENABLE_CHANNEL 0 +#define BM_DCP_CHANNELCTRL_ENABLE_CHANNEL 0x000000FF +#define BF_DCP_CHANNELCTRL_ENABLE_CHANNEL(v) \ + (((v) << 0) & BM_DCP_CHANNELCTRL_ENABLE_CHANNEL) +#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH0 0x01 +#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH1 0x02 +#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH2 0x04 +#define BV_DCP_CHANNELCTRL_ENABLE_CHANNEL__CH3 0x08 +HW_REGISTER_0(HW_DCP_CAPABILITY0, REGS_DCP_BASE, 0x00000030) +#define HW_DCP_CAPABILITY0_ADDR (REGS_DCP_BASE + 0x00000030) +#define BM_DCP_CAPABILITY0_DISABLE_DECRYPT 0x80000000 +#define BM_DCP_CAPABILITY0_ENABLE_TZONE 0x40000000 +#define BP_DCP_CAPABILITY0_NUM_CHANNELS 8 +#define BM_DCP_CAPABILITY0_NUM_CHANNELS 0x00000F00 +#define BF_DCP_CAPABILITY0_NUM_CHANNELS(v) \ + (((v) << 8) & BM_DCP_CAPABILITY0_NUM_CHANNELS) +#define BP_DCP_CAPABILITY0_NUM_KEYS 0 +#define BM_DCP_CAPABILITY0_NUM_KEYS 0x000000FF +#define BF_DCP_CAPABILITY0_NUM_KEYS(v) \ + (((v) << 0) & BM_DCP_CAPABILITY0_NUM_KEYS) +HW_REGISTER_0(HW_DCP_CAPABILITY1, REGS_DCP_BASE, 0x00000040) +#define HW_DCP_CAPABILITY1_ADDR (REGS_DCP_BASE + 0x00000040) +#define BP_DCP_CAPABILITY1_HASH_ALGORITHMS 16 +#define BM_DCP_CAPABILITY1_HASH_ALGORITHMS 0xFFFF0000 +#define BF_DCP_CAPABILITY1_HASH_ALGORITHMS(v) \ + (((v) << 16) & BM_DCP_CAPABILITY1_HASH_ALGORITHMS) +#define BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA1 0x0001 +#define BV_DCP_CAPABILITY1_HASH_ALGORITHMS__CRC32 0x0002 +#define BP_DCP_CAPABILITY1_CIPHER_ALGORITHMS 0 +#define BM_DCP_CAPABILITY1_CIPHER_ALGORITHMS 0x0000FFFF +#define BF_DCP_CAPABILITY1_CIPHER_ALGORITHMS(v) \ + (((v) << 0) & BM_DCP_CAPABILITY1_CIPHER_ALGORITHMS) +#define BV_DCP_CAPABILITY1_CIPHER_ALGORITHMS__AES128 0x0001 +HW_REGISTER_0(HW_DCP_CONTEXT, REGS_DCP_BASE, 0x00000050) +#define HW_DCP_CONTEXT_ADDR (REGS_DCP_BASE + 0x00000050) +#define BP_DCP_CONTEXT_ADDR 0 +#define BM_DCP_CONTEXT_ADDR 0xFFFFFFFF +#define BF_DCP_CONTEXT_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_KEY, REGS_DCP_BASE, 0x00000060) +#define HW_DCP_KEY_ADDR (REGS_DCP_BASE + 0x00000060) +#define BP_DCP_KEY_INDEX 4 +#define BM_DCP_KEY_INDEX 0x00000030 +#define BF_DCP_KEY_INDEX(v) \ + (((v) << 4) & BM_DCP_KEY_INDEX) +#define BP_DCP_KEY_SUBWORD 0 +#define BM_DCP_KEY_SUBWORD 0x00000003 +#define BF_DCP_KEY_SUBWORD(v) \ + (((v) << 0) & BM_DCP_KEY_SUBWORD) +HW_REGISTER_0(HW_DCP_KEYDATA, REGS_DCP_BASE, 0x00000070) +#define HW_DCP_KEYDATA_ADDR (REGS_DCP_BASE + 0x00000070) +#define BP_DCP_KEYDATA_DATA 0 +#define BM_DCP_KEYDATA_DATA 0xFFFFFFFF +#define BF_DCP_KEYDATA_DATA(v) (v) +HW_REGISTER_0(HW_DCP_PACKET0, REGS_DCP_BASE, 0x00000080) +#define HW_DCP_PACKET0_ADDR (REGS_DCP_BASE + 0x00000080) +#define BP_DCP_PACKET0_ADDR 0 +#define BM_DCP_PACKET0_ADDR 0xFFFFFFFF +#define BF_DCP_PACKET0_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_PACKET1, REGS_DCP_BASE, 0x00000090) +#define HW_DCP_PACKET1_ADDR (REGS_DCP_BASE + 0x00000090) +#define BP_DCP_PACKET1_TAG 24 +#define BM_DCP_PACKET1_TAG 0xFF000000 +#define BF_DCP_PACKET1_TAG(v) \ + (((v) << 24) & BM_DCP_PACKET1_TAG) +#define BM_DCP_PACKET1_OUTPUT_WORDSWAP 0x00800000 +#define BM_DCP_PACKET1_OUTPUT_BYTESWAP 0x00400000 +#define BM_DCP_PACKET1_INPUT_WORDSWAP 0x00200000 +#define BM_DCP_PACKET1_INPUT_BYTESWAP 0x00100000 +#define BM_DCP_PACKET1_KEY_WORDSWAP 0x00080000 +#define BM_DCP_PACKET1_KEY_BYTESWAP 0x00040000 +#define BM_DCP_PACKET1_TEST_SEMA_IRQ 0x00020000 +#define BM_DCP_PACKET1_CONSTANT_FILL 0x00010000 +#define BM_DCP_PACKET1_HASH_OUTPUT 0x00008000 +#define BV_DCP_PACKET1_HASH_OUTPUT__INPUT 0x00 +#define BV_DCP_PACKET1_HASH_OUTPUT__OUTPUT 0x01 +#define BM_DCP_PACKET1_CHECK_HASH 0x00004000 +#define BM_DCP_PACKET1_HASH_TERM 0x00002000 +#define BM_DCP_PACKET1_HASH_INIT 0x00001000 +#define BM_DCP_PACKET1_PAYLOAD_KEY 0x00000800 +#define BM_DCP_PACKET1_OTP_KEY 0x00000400 +#define BM_DCP_PACKET1_CIPHER_INIT 0x00000200 +#define BM_DCP_PACKET1_CIPHER_ENCRYPT 0x00000100 +#define BV_DCP_PACKET1_CIPHER_ENCRYPT__ENCRYPT 0x01 +#define BV_DCP_PACKET1_CIPHER_ENCRYPT__DECRYPT 0x00 +#define BM_DCP_PACKET1_ENABLE_BLIT 0x00000080 +#define BM_DCP_PACKET1_ENABLE_HASH 0x00000040 +#define BM_DCP_PACKET1_ENABLE_CIPHER 0x00000020 +#define BM_DCP_PACKET1_ENABLE_MEMCOPY 0x00000010 +#define BM_DCP_PACKET1_CHAIN_CONTIGUOUS 0x00000008 +#define BM_DCP_PACKET1_CHAIN 0x00000004 +#define BM_DCP_PACKET1_DECR_SEMAPHORE 0x00000002 +#define BM_DCP_PACKET1_INTERRUPT 0x00000001 +HW_REGISTER_0(HW_DCP_PACKET2, REGS_DCP_BASE, 0x000000a0) +#define HW_DCP_PACKET2_ADDR (REGS_DCP_BASE + 0x000000a0) +#define BP_DCP_PACKET2_CIPHER_CFG 24 +#define BM_DCP_PACKET2_CIPHER_CFG 0xFF000000 +#define BF_DCP_PACKET2_CIPHER_CFG(v) \ + (((v) << 24) & BM_DCP_PACKET2_CIPHER_CFG) +#define BP_DCP_PACKET2_HASH_SELECT 16 +#define BM_DCP_PACKET2_HASH_SELECT 0x000F0000 +#define BF_DCP_PACKET2_HASH_SELECT(v) \ + (((v) << 16) & BM_DCP_PACKET2_HASH_SELECT) +#define BV_DCP_PACKET2_HASH_SELECT__SHA1 0x00 +#define BV_DCP_PACKET2_HASH_SELECT__CRC32 0x01 +#define BP_DCP_PACKET2_KEY_SELECT 8 +#define BM_DCP_PACKET2_KEY_SELECT 0x0000FF00 +#define BF_DCP_PACKET2_KEY_SELECT(v) \ + (((v) << 8) & BM_DCP_PACKET2_KEY_SELECT) +#define BP_DCP_PACKET2_CIPHER_MODE 4 +#define BM_DCP_PACKET2_CIPHER_MODE 0x000000F0 +#define BF_DCP_PACKET2_CIPHER_MODE(v) \ + (((v) << 4) & BM_DCP_PACKET2_CIPHER_MODE) +#define BV_DCP_PACKET2_CIPHER_MODE__ECB 0x00 +#define BV_DCP_PACKET2_CIPHER_MODE__CBC 0x01 +#define BP_DCP_PACKET2_CIPHER_SELECT 0 +#define BM_DCP_PACKET2_CIPHER_SELECT 0x0000000F +#define BF_DCP_PACKET2_CIPHER_SELECT(v) \ + (((v) << 0) & BM_DCP_PACKET2_CIPHER_SELECT) +#define BV_DCP_PACKET2_CIPHER_SELECT__AES128 0x00 +HW_REGISTER_0(HW_DCP_PACKET3, REGS_DCP_BASE, 0x000000b0) +#define HW_DCP_PACKET3_ADDR (REGS_DCP_BASE + 0x000000b0) +#define BP_DCP_PACKET3_ADDR 0 +#define BM_DCP_PACKET3_ADDR 0xFFFFFFFF +#define BF_DCP_PACKET3_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_PACKET4, REGS_DCP_BASE, 0x000000c0) +#define HW_DCP_PACKET4_ADDR (REGS_DCP_BASE + 0x000000c0) +#define BP_DCP_PACKET4_ADDR 0 +#define BM_DCP_PACKET4_ADDR 0xFFFFFFFF +#define BF_DCP_PACKET4_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_PACKET5, REGS_DCP_BASE, 0x000000d0) +#define HW_DCP_PACKET5_ADDR (REGS_DCP_BASE + 0x000000d0) +#define BP_DCP_PACKET5_COUNT 0 +#define BM_DCP_PACKET5_COUNT 0xFFFFFFFF +#define BF_DCP_PACKET5_COUNT(v) (v) +HW_REGISTER_0(HW_DCP_PACKET6, REGS_DCP_BASE, 0x000000e0) +#define HW_DCP_PACKET6_ADDR (REGS_DCP_BASE + 0x000000e0) +#define BP_DCP_PACKET6_ADDR 0 +#define BM_DCP_PACKET6_ADDR 0xFFFFFFFF +#define BF_DCP_PACKET6_ADDR(v) (v) +/* + * multi-register-define name HW_DCP_CHnCMDPTR + * base 0x00000100 + * count 4 + * offset 0x40 + */ +HW_REGISTER_0_INDEXED(HW_DCP_CHnCMDPTR, REGS_DCP_BASE, 0x00000100, 0x40) +#define BP_DCP_CHnCMDPTR_ADDR 0 +#define BM_DCP_CHnCMDPTR_ADDR 0xFFFFFFFF +#define BF_DCP_CHnCMDPTR_ADDR(v) (v) +/* + * multi-register-define name HW_DCP_CHnSEMA + * base 0x00000110 + * count 4 + * offset 0x40 + */ +HW_REGISTER_0_INDEXED(HW_DCP_CHnSEMA, REGS_DCP_BASE, 0x00000110, 0x40) +#define BP_DCP_CHnSEMA_VALUE 16 +#define BM_DCP_CHnSEMA_VALUE 0x00FF0000 +#define BF_DCP_CHnSEMA_VALUE(v) \ + (((v) << 16) & BM_DCP_CHnSEMA_VALUE) +#define BP_DCP_CHnSEMA_INCREMENT 0 +#define BM_DCP_CHnSEMA_INCREMENT 0x000000FF +#define BF_DCP_CHnSEMA_INCREMENT(v) \ + (((v) << 0) & BM_DCP_CHnSEMA_INCREMENT) +/* + * multi-register-define name HW_DCP_CHnSTAT + * base 0x00000120 + * count 4 + * offset 0x40 + */ +HW_REGISTER_INDEXED(HW_DCP_CHnSTAT, REGS_DCP_BASE, 0x00000120, 0x40) +#define BP_DCP_CHnSTAT_TAG 24 +#define BM_DCP_CHnSTAT_TAG 0xFF000000 +#define BF_DCP_CHnSTAT_TAG(v) \ + (((v) << 24) & BM_DCP_CHnSTAT_TAG) +#define BP_DCP_CHnSTAT_ERROR_CODE 16 +#define BM_DCP_CHnSTAT_ERROR_CODE 0x00FF0000 +#define BF_DCP_CHnSTAT_ERROR_CODE(v) \ + (((v) << 16) & BM_DCP_CHnSTAT_ERROR_CODE) +#define BV_DCP_CHnSTAT_ERROR_CODE__NEXT_CHAIN_IS_0 0x01 +#define BV_DCP_CHnSTAT_ERROR_CODE__NO_CHAIN 0x02 +#define BV_DCP_CHnSTAT_ERROR_CODE__CONTEXT_ERROR 0x03 +#define BV_DCP_CHnSTAT_ERROR_CODE__PAYLOAD_ERROR 0x04 +#define BV_DCP_CHnSTAT_ERROR_CODE__INVALID_MODE 0x05 +#define BM_DCP_CHnSTAT_ERROR_PAGEFAULT 0x00000040 +#define BM_DCP_CHnSTAT_ERROR_DST 0x00000020 +#define BM_DCP_CHnSTAT_ERROR_SRC 0x00000010 +#define BM_DCP_CHnSTAT_ERROR_PACKET 0x00000008 +#define BM_DCP_CHnSTAT_ERROR_SETUP 0x00000004 +#define BM_DCP_CHnSTAT_HASH_MISMATCH 0x00000002 +/* + * multi-register-define name HW_DCP_CHnOPTS + * base 0x00000130 + * count 4 + * offset 0x40 + */ +HW_REGISTER_INDEXED(HW_DCP_CHnOPTS, REGS_DCP_BASE, 0x00000130, 0x40) +#define BP_DCP_CHnOPTS_RECOVERY_TIMER 0 +#define BM_DCP_CHnOPTS_RECOVERY_TIMER 0x0000FFFF +#define BF_DCP_CHnOPTS_RECOVERY_TIMER(v) \ + (((v) << 0) & BM_DCP_CHnOPTS_RECOVERY_TIMER) +HW_REGISTER(HW_DCP_CSCCTRL0, REGS_DCP_BASE, 0x00000300) +#define HW_DCP_CSCCTRL0_ADDR (REGS_DCP_BASE + 0x00000300) +#define BM_DCP_CSCCTRL0_CLIP 0x00008000 +#define BM_DCP_CSCCTRL0_UPSAMPLE 0x00004000 +#define BM_DCP_CSCCTRL0_SCALE 0x00002000 +#define BM_DCP_CSCCTRL0_ROTATE 0x00001000 +#define BM_DCP_CSCCTRL0_SUBSAMPLE 0x00000800 +#define BM_DCP_CSCCTRL0_DELTA 0x00000400 +#define BP_DCP_CSCCTRL0_RGB_FORMAT 8 +#define BM_DCP_CSCCTRL0_RGB_FORMAT 0x00000300 +#define BF_DCP_CSCCTRL0_RGB_FORMAT(v) \ + (((v) << 8) & BM_DCP_CSCCTRL0_RGB_FORMAT) +#define BV_DCP_CSCCTRL0_RGB_FORMAT__RGB16_565 0x0 +#define BV_DCP_CSCCTRL0_RGB_FORMAT__YCbCrI 0x1 +#define BV_DCP_CSCCTRL0_RGB_FORMAT__RGB24 0x2 +#define BV_DCP_CSCCTRL0_RGB_FORMAT__YUV422I 0x3 +#define BP_DCP_CSCCTRL0_YUV_FORMAT 4 +#define BM_DCP_CSCCTRL0_YUV_FORMAT 0x000000F0 +#define BF_DCP_CSCCTRL0_YUV_FORMAT(v) \ + (((v) << 4) & BM_DCP_CSCCTRL0_YUV_FORMAT) +#define BV_DCP_CSCCTRL0_YUV_FORMAT__YUV420 0x0 +#define BV_DCP_CSCCTRL0_YUV_FORMAT__YUV422 0x2 +#define BM_DCP_CSCCTRL0_ENABLE 0x00000001 +HW_REGISTER(HW_DCP_CSCSTAT, REGS_DCP_BASE, 0x00000310) +#define HW_DCP_CSCSTAT_ADDR (REGS_DCP_BASE + 0x00000310) +#define BP_DCP_CSCSTAT_ERROR_CODE 16 +#define BM_DCP_CSCSTAT_ERROR_CODE 0x00FF0000 +#define BF_DCP_CSCSTAT_ERROR_CODE(v) \ + (((v) << 16) & BM_DCP_CSCSTAT_ERROR_CODE) +#define BV_DCP_CSCSTAT_ERROR_CODE__LUMA0_FETCH_ERROR_Y0 0x01 +#define BV_DCP_CSCSTAT_ERROR_CODE__LUMA1_FETCH_ERROR_Y1 0x02 +#define BV_DCP_CSCSTAT_ERROR_CODE__CHROMA_FETCH_ERROR_U 0x03 +#define BV_DCP_CSCSTAT_ERROR_CODE__CHROMA_FETCH_ERROR_V 0x04 +#define BM_DCP_CSCSTAT_ERROR_PAGEFAULT 0x00000040 +#define BM_DCP_CSCSTAT_ERROR_DST 0x00000020 +#define BM_DCP_CSCSTAT_ERROR_SRC 0x00000010 +#define BM_DCP_CSCSTAT_ERROR_SETUP 0x00000004 +#define BM_DCP_CSCSTAT_COMPLETE 0x00000001 +HW_REGISTER_0(HW_DCP_CSCOUTBUFPARAM, REGS_DCP_BASE, 0x00000320) +#define HW_DCP_CSCOUTBUFPARAM_ADDR (REGS_DCP_BASE + 0x00000320) +#define BP_DCP_CSCOUTBUFPARAM_FIELD_SIZE 12 +#define BM_DCP_CSCOUTBUFPARAM_FIELD_SIZE 0x00FFF000 +#define BF_DCP_CSCOUTBUFPARAM_FIELD_SIZE(v) \ + (((v) << 12) & BM_DCP_CSCOUTBUFPARAM_FIELD_SIZE) +#define BP_DCP_CSCOUTBUFPARAM_LINE_SIZE 0 +#define BM_DCP_CSCOUTBUFPARAM_LINE_SIZE 0x00000FFF +#define BF_DCP_CSCOUTBUFPARAM_LINE_SIZE(v) \ + (((v) << 0) & BM_DCP_CSCOUTBUFPARAM_LINE_SIZE) +HW_REGISTER_0(HW_DCP_CSCINBUFPARAM, REGS_DCP_BASE, 0x00000330) +#define HW_DCP_CSCINBUFPARAM_ADDR (REGS_DCP_BASE + 0x00000330) +#define BP_DCP_CSCINBUFPARAM_LINE_SIZE 0 +#define BM_DCP_CSCINBUFPARAM_LINE_SIZE 0x00000FFF +#define BF_DCP_CSCINBUFPARAM_LINE_SIZE(v) \ + (((v) << 0) & BM_DCP_CSCINBUFPARAM_LINE_SIZE) +HW_REGISTER_0(HW_DCP_CSCRGB, REGS_DCP_BASE, 0x00000340) +#define HW_DCP_CSCRGB_ADDR (REGS_DCP_BASE + 0x00000340) +#define BP_DCP_CSCRGB_ADDR 0 +#define BM_DCP_CSCRGB_ADDR 0xFFFFFFFF +#define BF_DCP_CSCRGB_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_CSCLUMA, REGS_DCP_BASE, 0x00000350) +#define HW_DCP_CSCLUMA_ADDR (REGS_DCP_BASE + 0x00000350) +#define BP_DCP_CSCLUMA_ADDR 0 +#define BM_DCP_CSCLUMA_ADDR 0xFFFFFFFF +#define BF_DCP_CSCLUMA_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_CSCCHROMAU, REGS_DCP_BASE, 0x00000360) +#define HW_DCP_CSCCHROMAU_ADDR (REGS_DCP_BASE + 0x00000360) +#define BP_DCP_CSCCHROMAU_ADDR 0 +#define BM_DCP_CSCCHROMAU_ADDR 0xFFFFFFFF +#define BF_DCP_CSCCHROMAU_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_CSCCHROMAV, REGS_DCP_BASE, 0x00000370) +#define HW_DCP_CSCCHROMAV_ADDR (REGS_DCP_BASE + 0x00000370) +#define BP_DCP_CSCCHROMAV_ADDR 0 +#define BM_DCP_CSCCHROMAV_ADDR 0xFFFFFFFF +#define BF_DCP_CSCCHROMAV_ADDR(v) (v) +HW_REGISTER_0(HW_DCP_CSCCOEFF0, REGS_DCP_BASE, 0x00000380) +#define HW_DCP_CSCCOEFF0_ADDR (REGS_DCP_BASE + 0x00000380) +#define BP_DCP_CSCCOEFF0_C0 16 +#define BM_DCP_CSCCOEFF0_C0 0x03FF0000 +#define BF_DCP_CSCCOEFF0_C0(v) \ + (((v) << 16) & BM_DCP_CSCCOEFF0_C0) +#define BP_DCP_CSCCOEFF0_UV_OFFSET 8 +#define BM_DCP_CSCCOEFF0_UV_OFFSET 0x0000FF00 +#define BF_DCP_CSCCOEFF0_UV_OFFSET(v) \ + (((v) << 8) & BM_DCP_CSCCOEFF0_UV_OFFSET) +#define BP_DCP_CSCCOEFF0_Y_OFFSET 0 +#define BM_DCP_CSCCOEFF0_Y_OFFSET 0x000000FF +#define BF_DCP_CSCCOEFF0_Y_OFFSET(v) \ + (((v) << 0) & BM_DCP_CSCCOEFF0_Y_OFFSET) +HW_REGISTER_0(HW_DCP_CSCCOEFF1, REGS_DCP_BASE, 0x00000390) +#define HW_DCP_CSCCOEFF1_ADDR (REGS_DCP_BASE + 0x00000390) +#define BP_DCP_CSCCOEFF1_C1 16 +#define BM_DCP_CSCCOEFF1_C1 0x03FF0000 +#define BF_DCP_CSCCOEFF1_C1(v) \ + (((v) << 16) & BM_DCP_CSCCOEFF1_C1) +#define BP_DCP_CSCCOEFF1_C4 0 +#define BM_DCP_CSCCOEFF1_C4 0x000003FF +#define BF_DCP_CSCCOEFF1_C4(v) \ + (((v) << 0) & BM_DCP_CSCCOEFF1_C4) +HW_REGISTER_0(HW_DCP_CSCCOEFF2, REGS_DCP_BASE, 0x000003a0) +#define HW_DCP_CSCCOEFF2_ADDR (REGS_DCP_BASE + 0x000003a0) +#define BP_DCP_CSCCOEFF2_C2 16 +#define BM_DCP_CSCCOEFF2_C2 0x03FF0000 +#define BF_DCP_CSCCOEFF2_C2(v) \ + (((v) << 16) & BM_DCP_CSCCOEFF2_C2) +#define BP_DCP_CSCCOEFF2_C3 0 +#define BM_DCP_CSCCOEFF2_C3 0x000003FF +#define BF_DCP_CSCCOEFF2_C3(v) \ + (((v) << 0) & BM_DCP_CSCCOEFF2_C3) +HW_REGISTER_0(HW_DCP_CSCCLIP, REGS_DCP_BASE, 0x000003d0) +#define HW_DCP_CSCCLIP_ADDR (REGS_DCP_BASE + 0x000003d0) +#define BP_DCP_CSCCLIP_HEIGHT 12 +#define BM_DCP_CSCCLIP_HEIGHT 0x00FFF000 +#define BF_DCP_CSCCLIP_HEIGHT(v) \ + (((v) << 12) & BM_DCP_CSCCLIP_HEIGHT) +#define BP_DCP_CSCCLIP_WIDTH 0 +#define BM_DCP_CSCCLIP_WIDTH 0x00000FFF +#define BF_DCP_CSCCLIP_WIDTH(v) \ + (((v) << 0) & BM_DCP_CSCCLIP_WIDTH) +HW_REGISTER_0(HW_DCP_CSCXSCALE, REGS_DCP_BASE, 0x000003e0) +#define HW_DCP_CSCXSCALE_ADDR (REGS_DCP_BASE + 0x000003e0) +#define BP_DCP_CSCXSCALE_INT 24 +#define BM_DCP_CSCXSCALE_INT 0x03000000 +#define BF_DCP_CSCXSCALE_INT(v) \ + (((v) << 24) & BM_DCP_CSCXSCALE_INT) +#define BP_DCP_CSCXSCALE_FRAC 12 +#define BM_DCP_CSCXSCALE_FRAC 0x00FFF000 +#define BF_DCP_CSCXSCALE_FRAC(v) \ + (((v) << 12) & BM_DCP_CSCXSCALE_FRAC) +#define BP_DCP_CSCXSCALE_WIDTH 0 +#define BM_DCP_CSCXSCALE_WIDTH 0x00000FFF +#define BF_DCP_CSCXSCALE_WIDTH(v) \ + (((v) << 0) & BM_DCP_CSCXSCALE_WIDTH) +HW_REGISTER_0(HW_DCP_CSCYSCALE, REGS_DCP_BASE, 0x000003f0) +#define HW_DCP_CSCYSCALE_ADDR (REGS_DCP_BASE + 0x000003f0) +#define BP_DCP_CSCYSCALE_INT 24 +#define BM_DCP_CSCYSCALE_INT 0x03000000 +#define BF_DCP_CSCYSCALE_INT(v) \ + (((v) << 24) & BM_DCP_CSCYSCALE_INT) +#define BP_DCP_CSCYSCALE_FRAC 12 +#define BM_DCP_CSCYSCALE_FRAC 0x00FFF000 +#define BF_DCP_CSCYSCALE_FRAC(v) \ + (((v) << 12) & BM_DCP_CSCYSCALE_FRAC) +#define BP_DCP_CSCYSCALE_HEIGHT 0 +#define BM_DCP_CSCYSCALE_HEIGHT 0x00000FFF +#define BF_DCP_CSCYSCALE_HEIGHT(v) \ + (((v) << 0) & BM_DCP_CSCYSCALE_HEIGHT) +HW_REGISTER_0(HW_DCP_DBGSELECT, REGS_DCP_BASE, 0x00000400) +#define HW_DCP_DBGSELECT_ADDR (REGS_DCP_BASE + 0x00000400) +#define BP_DCP_DBGSELECT_INDEX 0 +#define BM_DCP_DBGSELECT_INDEX 0x000000FF +#define BF_DCP_DBGSELECT_INDEX(v) \ + (((v) << 0) & BM_DCP_DBGSELECT_INDEX) +#define BV_DCP_DBGSELECT_INDEX__CONTROL 0x01 +#define BV_DCP_DBGSELECT_INDEX__OTPKEY0 0x10 +#define BV_DCP_DBGSELECT_INDEX__OTPKEY1 0x11 +#define BV_DCP_DBGSELECT_INDEX__OTPKEY2 0x12 +#define BV_DCP_DBGSELECT_INDEX__OTPKEY3 0x13 +HW_REGISTER_0(HW_DCP_DBGDATA, REGS_DCP_BASE, 0x00000410) +#define HW_DCP_DBGDATA_ADDR (REGS_DCP_BASE + 0x00000410) +#define BP_DCP_DBGDATA_DATA 0 +#define BM_DCP_DBGDATA_DATA 0xFFFFFFFF +#define BF_DCP_DBGDATA_DATA(v) (v) +HW_REGISTER_0(HW_DCP_PAGETABLE, REGS_DCP_BASE, 0x00000420) +#define HW_DCP_PAGETABLE_ADDR (REGS_DCP_BASE + 0x00000420) +#define BP_DCP_PAGETABLE_BASE 2 +#define BM_DCP_PAGETABLE_BASE 0xFFFFFFFC +#define BF_DCP_PAGETABLE_BASE(v) \ + (((v) << 2) & BM_DCP_PAGETABLE_BASE) +#define BM_DCP_PAGETABLE_FLUSH 0x00000002 +#define BM_DCP_PAGETABLE_ENABLE 0x00000001 +HW_REGISTER_0(HW_DCP_VERSION, REGS_DCP_BASE, 0x00000430) +#define HW_DCP_VERSION_ADDR (REGS_DCP_BASE + 0x00000430) +#define BP_DCP_VERSION_MAJOR 24 +#define BM_DCP_VERSION_MAJOR 0xFF000000 +#define BF_DCP_VERSION_MAJOR(v) \ + (((v) << 24) & BM_DCP_VERSION_MAJOR) +#define BP_DCP_VERSION_MINOR 16 +#define BM_DCP_VERSION_MINOR 0x00FF0000 +#define BF_DCP_VERSION_MINOR(v) \ + (((v) << 16) & BM_DCP_VERSION_MINOR) +#define BP_DCP_VERSION_STEP 0 +#define BM_DCP_VERSION_STEP 0x0000FFFF +#define BF_DCP_VERSION_STEP(v) \ + (((v) << 0) & BM_DCP_VERSION_STEP) +#endif /* __ARCH_ARM___DCP_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-digctl.h b/arch/arm/mach-stmp3xxx/include/mach/regs-digctl.h new file mode 100644 index 000000000000..287eb949ff7f --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-digctl.h @@ -0,0 +1,451 @@ +/* + * STMP DIGCTL Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___DIGCTL_H +#define __ARCH_ARM___DIGCTL_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_DIGCTL_BASE (REGS_BASE + 0x1c000) +#define REGS_DIGCTL_BASE_PHYS (0x8001C000) +#define REGS_DIGCTL_SIZE 0x00002000 +HW_REGISTER(HW_DIGCTL_CTRL, REGS_DIGCTL_BASE, 0x00000000) +#define HW_DIGCTL_CTRL_ADDR (REGS_DIGCTL_BASE + 0x00000000) +#define BM_DIGCTL_CTRL_XTAL24M_GATE 0x40000000 +#define BM_DIGCTL_CTRL_TRAP_IRQ 0x20000000 +#define BM_DIGCTL_CTRL_CACHE_BIST_TMODE 0x04000000 +#define BM_DIGCTL_CTRL_LCD_BIST_CLKEN 0x02000000 +#define BM_DIGCTL_CTRL_LCD_BIST_START 0x01000000 +#define BM_DIGCTL_CTRL_DCP_BIST_CLKEN 0x00800000 +#define BM_DIGCTL_CTRL_DCP_BIST_START 0x00400000 +#define BM_DIGCTL_CTRL_ARM_BIST_CLKEN 0x00200000 +#define BM_DIGCTL_CTRL_USB_TESTMODE 0x00100000 +#define BM_DIGCTL_CTRL_ANALOG_TESTMODE 0x00080000 +#define BM_DIGCTL_CTRL_DIGITAL_TESTMODE 0x00040000 +#define BM_DIGCTL_CTRL_ARM_BIST_START 0x00020000 +#define BM_DIGCTL_CTRL_UART_LOOPBACK 0x00010000 +#define BV_DIGCTL_CTRL_UART_LOOPBACK__NORMAL 0x0 +#define BV_DIGCTL_CTRL_UART_LOOPBACK__LOOPIT 0x1 +#define BM_DIGCTL_CTRL_SAIF_LOOPBACK 0x00008000 +#define BV_DIGCTL_CTRL_SAIF_LOOPBACK__NORMAL 0x0 +#define BV_DIGCTL_CTRL_SAIF_LOOPBACK__LOOPIT 0x1 +#define BP_DIGCTL_CTRL_SAIF_CLKMUX_SEL 13 +#define BM_DIGCTL_CTRL_SAIF_CLKMUX_SEL 0x00006000 +#define BF_DIGCTL_CTRL_SAIF_CLKMUX_SEL(v) \ + (((v) << 13) & BM_DIGCTL_CTRL_SAIF_CLKMUX_SEL) +#define BV_DIGCTL_CTRL_SAIF_CLKMUX_SEL__MBL_CLK_OUT 0x0 +#define BV_DIGCTL_CTRL_SAIF_CLKMUX_SEL__BL_CLK_OUT 0x1 +#define BV_DIGCTL_CTRL_SAIF_CLKMUX_SEL__M_CLK_OUT_BL_CLK_IN 0x2 +#define BV_DIGCTL_CTRL_SAIF_CLKMUX_SEL__BL_CLK_IN 0x3 +#define BM_DIGCTL_CTRL_SAIF_CLKMST_SEL 0x00001000 +#define BV_DIGCTL_CTRL_SAIF_CLKMST_SEL__SAIF1_MST 0x0 +#define BV_DIGCTL_CTRL_SAIF_CLKMST_SEL__SAIF2_MST 0x1 +#define BM_DIGCTL_CTRL_SAIF_ALT_BITCLK_SEL 0x00000800 +#define BM_DIGCTL_CTRL_SY_ENDIAN 0x00000200 +#define BM_DIGCTL_CTRL_SY_SFTRST 0x00000100 +#define BM_DIGCTL_CTRL_SY_CLKGATE 0x00000080 +#define BM_DIGCTL_CTRL_USE_SERIAL_JTAG 0x00000040 +#define BV_DIGCTL_CTRL_USE_SERIAL_JTAG__OLD_JTAG 0x0 +#define BV_DIGCTL_CTRL_USE_SERIAL_JTAG__SERIAL_JTAG 0x1 +#define BM_DIGCTL_CTRL_TRAP_IN_RANGE 0x00000020 +#define BM_DIGCTL_CTRL_TRAP_ENABLE 0x00000010 +#define BM_DIGCTL_CTRL_DEBUG_DISABLE 0x00000008 +#define BM_DIGCTL_CTRL_USB_CLKGATE 0x00000004 +#define BV_DIGCTL_CTRL_USB_CLKGATE__RUN 0x0 +#define BV_DIGCTL_CTRL_USB_CLKGATE__NO_CLKS 0x1 +#define BM_DIGCTL_CTRL_JTAG_SHIELD 0x00000002 +#define BV_DIGCTL_CTRL_JTAG_SHIELD__NORMAL 0x0 +#define BV_DIGCTL_CTRL_JTAG_SHIELD__SHIELDS_UP 0x1 +#define BM_DIGCTL_CTRL_LATCH_ENTROPY 0x00000001 +HW_REGISTER(HW_DIGCTL_STATUS, REGS_DIGCTL_BASE, 0x00000010) +#define HW_DIGCTL_STATUS_ADDR (REGS_DIGCTL_BASE + 0x00000010) +#define BM_DIGCTL_STATUS_USB_HS_PRESENT 0x80000000 +#define BM_DIGCTL_STATUS_USB_OTG_PRESENT 0x40000000 +#define BM_DIGCTL_STATUS_USB_HOST_PRESENT 0x20000000 +#define BM_DIGCTL_STATUS_USB_DEVICE_PRESENT 0x10000000 +#define BM_DIGCTL_STATUS_DCP_BIST_FAIL 0x00000400 +#define BM_DIGCTL_STATUS_DCP_BIST_PASS 0x00000200 +#define BM_DIGCTL_STATUS_DCP_BIST_DONE 0x00000100 +#define BM_DIGCTL_STATUS_LCD_BIST_FAIL 0x00000080 +#define BM_DIGCTL_STATUS_LCD_BIST_PASS 0x00000040 +#define BM_DIGCTL_STATUS_LCD_BIST_DONE 0x00000020 +#define BM_DIGCTL_STATUS_JTAG_IN_USE 0x00000010 +#define BP_DIGCTL_STATUS_PACKAGE_TYPE 1 +#define BM_DIGCTL_STATUS_PACKAGE_TYPE 0x0000000E +#define BF_DIGCTL_STATUS_PACKAGE_TYPE(v) \ + (((v) << 1) & BM_DIGCTL_STATUS_PACKAGE_TYPE) +#define BM_DIGCTL_STATUS_WRITTEN 0x00000001 +HW_REGISTER(HW_DIGCTL_HCLKCOUNT, REGS_DIGCTL_BASE, 0x00000020) +#define HW_DIGCTL_HCLKCOUNT_ADDR (REGS_DIGCTL_BASE + 0x00000020) +#define BP_DIGCTL_HCLKCOUNT_COUNT 0 +#define BM_DIGCTL_HCLKCOUNT_COUNT 0xFFFFFFFF +#define BF_DIGCTL_HCLKCOUNT_COUNT(v) (v) +HW_REGISTER(HW_DIGCTL_RAMCTRL, REGS_DIGCTL_BASE, 0x00000030) +#define HW_DIGCTL_RAMCTRL_ADDR (REGS_DIGCTL_BASE + 0x00000030) +#define BP_DIGCTL_RAMCTRL_SPEED_SELECT 8 +#define BM_DIGCTL_RAMCTRL_SPEED_SELECT 0x00000F00 +#define BF_DIGCTL_RAMCTRL_SPEED_SELECT(v) \ + (((v) << 8) & BM_DIGCTL_RAMCTRL_SPEED_SELECT) +#define BM_DIGCTL_RAMCTRL_RAM_REPAIR_EN 0x00000001 +HW_REGISTER(HW_DIGCTL_RAMREPAIR, REGS_DIGCTL_BASE, 0x00000040) +#define HW_DIGCTL_RAMREPAIR_ADDR (REGS_DIGCTL_BASE + 0x00000040) +#define BP_DIGCTL_RAMREPAIR_ADDR 0 +#define BM_DIGCTL_RAMREPAIR_ADDR 0x0000FFFF +#define BF_DIGCTL_RAMREPAIR_ADDR(v) \ + (((v) << 0) & BM_DIGCTL_RAMREPAIR_ADDR) +HW_REGISTER(HW_DIGCTL_ROMCTRL, REGS_DIGCTL_BASE, 0x00000050) +#define HW_DIGCTL_ROMCTRL_ADDR (REGS_DIGCTL_BASE + 0x00000050) +#define BP_DIGCTL_ROMCTRL_RD_MARGIN 0 +#define BM_DIGCTL_ROMCTRL_RD_MARGIN 0x0000000F +#define BF_DIGCTL_ROMCTRL_RD_MARGIN(v) \ + (((v) << 0) & BM_DIGCTL_ROMCTRL_RD_MARGIN) +HW_REGISTER_0(HW_DIGCTL_WRITEONCE, REGS_DIGCTL_BASE, 0x00000060) +#define HW_DIGCTL_WRITEONCE_ADDR (REGS_DIGCTL_BASE + 0x00000060) +#define BP_DIGCTL_WRITEONCE_BITS 0 +#define BM_DIGCTL_WRITEONCE_BITS 0xFFFFFFFF +#define BF_DIGCTL_WRITEONCE_BITS(v) (v) +HW_REGISTER_0(HW_DIGCTL_ENTROPY, REGS_DIGCTL_BASE, 0x00000090) +#define HW_DIGCTL_ENTROPY_ADDR (REGS_DIGCTL_BASE + 0x00000090) +#define BP_DIGCTL_ENTROPY_VALUE 0 +#define BM_DIGCTL_ENTROPY_VALUE 0xFFFFFFFF +#define BF_DIGCTL_ENTROPY_VALUE(v) (v) +HW_REGISTER_0(HW_DIGCTL_ENTROPY_LATCHED, REGS_DIGCTL_BASE, 0x000000a0) +#define HW_DIGCTL_ENTROPY_LATCHED_ADDR (REGS_DIGCTL_BASE + 0x000000a0) +#define BP_DIGCTL_ENTROPY_LATCHED_VALUE 0 +#define BM_DIGCTL_ENTROPY_LATCHED_VALUE 0xFFFFFFFF +#define BF_DIGCTL_ENTROPY_LATCHED_VALUE(v) (v) +HW_REGISTER(HW_DIGCTL_SJTAGDBG, REGS_DIGCTL_BASE, 0x000000b0) +#define HW_DIGCTL_SJTAGDBG_ADDR (REGS_DIGCTL_BASE + 0x000000b0) +#define BP_DIGCTL_SJTAGDBG_SJTAG_STATE 16 +#define BM_DIGCTL_SJTAGDBG_SJTAG_STATE 0x07FF0000 +#define BF_DIGCTL_SJTAGDBG_SJTAG_STATE(v) \ + (((v) << 16) & BM_DIGCTL_SJTAGDBG_SJTAG_STATE) +#define BM_DIGCTL_SJTAGDBG_SJTAG_TDO 0x00000400 +#define BM_DIGCTL_SJTAGDBG_SJTAG_TDI 0x00000200 +#define BM_DIGCTL_SJTAGDBG_SJTAG_MODE 0x00000100 +#define BP_DIGCTL_SJTAGDBG_DELAYED_ACTIVE 4 +#define BM_DIGCTL_SJTAGDBG_DELAYED_ACTIVE 0x000000F0 +#define BF_DIGCTL_SJTAGDBG_DELAYED_ACTIVE(v) \ + (((v) << 4) & BM_DIGCTL_SJTAGDBG_DELAYED_ACTIVE) +#define BM_DIGCTL_SJTAGDBG_ACTIVE 0x00000008 +#define BM_DIGCTL_SJTAGDBG_SJTAG_PIN_STATE 0x00000004 +#define BM_DIGCTL_SJTAGDBG_SJTAG_DEBUG_DATA 0x00000002 +#define BM_DIGCTL_SJTAGDBG_SJTAG_DEBUG_OE 0x00000001 +HW_REGISTER(HW_DIGCTL_MICROSECONDS, REGS_DIGCTL_BASE, 0x000000c0) +#define HW_DIGCTL_MICROSECONDS_ADDR (REGS_DIGCTL_BASE + 0x000000c0) +#define BP_DIGCTL_MICROSECONDS_VALUE 0 +#define BM_DIGCTL_MICROSECONDS_VALUE 0xFFFFFFFF +#define BF_DIGCTL_MICROSECONDS_VALUE(v) (v) +HW_REGISTER_0(HW_DIGCTL_DBGRD, REGS_DIGCTL_BASE, 0x000000d0) +#define HW_DIGCTL_DBGRD_ADDR (REGS_DIGCTL_BASE + 0x000000d0) +#define BP_DIGCTL_DBGRD_COMPLEMENT 0 +#define BM_DIGCTL_DBGRD_COMPLEMENT 0xFFFFFFFF +#define BF_DIGCTL_DBGRD_COMPLEMENT(v) (v) +HW_REGISTER_0(HW_DIGCTL_DBG, REGS_DIGCTL_BASE, 0x000000e0) +#define HW_DIGCTL_DBG_ADDR (REGS_DIGCTL_BASE + 0x000000e0) +#define BP_DIGCTL_DBG_VALUE 0 +#define BM_DIGCTL_DBG_VALUE 0xFFFFFFFF +#define BF_DIGCTL_DBG_VALUE(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_BIST_CSR, REGS_DIGCTL_BASE, 0x000000f0) +#define HW_DIGCTL_OCRAM_BIST_CSR_ADDR (REGS_DIGCTL_BASE + 0x000000f0) +#define BM_DIGCTL_OCRAM_BIST_CSR_BIST_DEBUG_MODE 0x00000400 +#define BM_DIGCTL_OCRAM_BIST_CSR_BIST_DATA_CHANGE 0x00000200 +#define BM_DIGCTL_OCRAM_BIST_CSR_BIST_CLKEN 0x00000100 +#define BM_DIGCTL_OCRAM_BIST_CSR_FAIL 0x00000008 +#define BM_DIGCTL_OCRAM_BIST_CSR_PASS 0x00000004 +#define BM_DIGCTL_OCRAM_BIST_CSR_DONE 0x00000002 +#define BM_DIGCTL_OCRAM_BIST_CSR_START 0x00000001 +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS0, REGS_DIGCTL_BASE, 0x00000110) +#define HW_DIGCTL_OCRAM_STATUS0_ADDR (REGS_DIGCTL_BASE + 0x00000110) +#define BP_DIGCTL_OCRAM_STATUS0_FAILDATA00 0 +#define BM_DIGCTL_OCRAM_STATUS0_FAILDATA00 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS0_FAILDATA00(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS1, REGS_DIGCTL_BASE, 0x00000120) +#define HW_DIGCTL_OCRAM_STATUS1_ADDR (REGS_DIGCTL_BASE + 0x00000120) +#define BP_DIGCTL_OCRAM_STATUS1_FAILDATA01 0 +#define BM_DIGCTL_OCRAM_STATUS1_FAILDATA01 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS1_FAILDATA01(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS2, REGS_DIGCTL_BASE, 0x00000130) +#define HW_DIGCTL_OCRAM_STATUS2_ADDR (REGS_DIGCTL_BASE + 0x00000130) +#define BP_DIGCTL_OCRAM_STATUS2_FAILDATA10 0 +#define BM_DIGCTL_OCRAM_STATUS2_FAILDATA10 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS2_FAILDATA10(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS3, REGS_DIGCTL_BASE, 0x00000140) +#define HW_DIGCTL_OCRAM_STATUS3_ADDR (REGS_DIGCTL_BASE + 0x00000140) +#define BP_DIGCTL_OCRAM_STATUS3_FAILDATA11 0 +#define BM_DIGCTL_OCRAM_STATUS3_FAILDATA11 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS3_FAILDATA11(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS4, REGS_DIGCTL_BASE, 0x00000150) +#define HW_DIGCTL_OCRAM_STATUS4_ADDR (REGS_DIGCTL_BASE + 0x00000150) +#define BP_DIGCTL_OCRAM_STATUS4_FAILDATA20 0 +#define BM_DIGCTL_OCRAM_STATUS4_FAILDATA20 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS4_FAILDATA20(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS5, REGS_DIGCTL_BASE, 0x00000160) +#define HW_DIGCTL_OCRAM_STATUS5_ADDR (REGS_DIGCTL_BASE + 0x00000160) +#define BP_DIGCTL_OCRAM_STATUS5_FAILDATA21 0 +#define BM_DIGCTL_OCRAM_STATUS5_FAILDATA21 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS5_FAILDATA21(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS6, REGS_DIGCTL_BASE, 0x00000170) +#define HW_DIGCTL_OCRAM_STATUS6_ADDR (REGS_DIGCTL_BASE + 0x00000170) +#define BP_DIGCTL_OCRAM_STATUS6_FAILDATA30 0 +#define BM_DIGCTL_OCRAM_STATUS6_FAILDATA30 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS6_FAILDATA30(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS7, REGS_DIGCTL_BASE, 0x00000180) +#define HW_DIGCTL_OCRAM_STATUS7_ADDR (REGS_DIGCTL_BASE + 0x00000180) +#define BP_DIGCTL_OCRAM_STATUS7_FAILDATA31 0 +#define BM_DIGCTL_OCRAM_STATUS7_FAILDATA31 0xFFFFFFFF +#define BF_DIGCTL_OCRAM_STATUS7_FAILDATA31(v) (v) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS8, REGS_DIGCTL_BASE, 0x00000190) +#define HW_DIGCTL_OCRAM_STATUS8_ADDR (REGS_DIGCTL_BASE + 0x00000190) +#define BP_DIGCTL_OCRAM_STATUS8_FAILADDR01 16 +#define BM_DIGCTL_OCRAM_STATUS8_FAILADDR01 0x1FFF0000 +#define BF_DIGCTL_OCRAM_STATUS8_FAILADDR01(v) \ + (((v) << 16) & BM_DIGCTL_OCRAM_STATUS8_FAILADDR01) +#define BP_DIGCTL_OCRAM_STATUS8_FAILADDR00 0 +#define BM_DIGCTL_OCRAM_STATUS8_FAILADDR00 0x00001FFF +#define BF_DIGCTL_OCRAM_STATUS8_FAILADDR00(v) \ + (((v) << 0) & BM_DIGCTL_OCRAM_STATUS8_FAILADDR00) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS9, REGS_DIGCTL_BASE, 0x000001a0) +#define HW_DIGCTL_OCRAM_STATUS9_ADDR (REGS_DIGCTL_BASE + 0x000001a0) +#define BP_DIGCTL_OCRAM_STATUS9_FAILADDR11 16 +#define BM_DIGCTL_OCRAM_STATUS9_FAILADDR11 0x1FFF0000 +#define BF_DIGCTL_OCRAM_STATUS9_FAILADDR11(v) \ + (((v) << 16) & BM_DIGCTL_OCRAM_STATUS9_FAILADDR11) +#define BP_DIGCTL_OCRAM_STATUS9_FAILADDR10 0 +#define BM_DIGCTL_OCRAM_STATUS9_FAILADDR10 0x00001FFF +#define BF_DIGCTL_OCRAM_STATUS9_FAILADDR10(v) \ + (((v) << 0) & BM_DIGCTL_OCRAM_STATUS9_FAILADDR10) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS10, REGS_DIGCTL_BASE, 0x000001b0) +#define HW_DIGCTL_OCRAM_STATUS10_ADDR (REGS_DIGCTL_BASE + 0x000001b0) +#define BP_DIGCTL_OCRAM_STATUS10_FAILADDR21 16 +#define BM_DIGCTL_OCRAM_STATUS10_FAILADDR21 0x1FFF0000 +#define BF_DIGCTL_OCRAM_STATUS10_FAILADDR21(v) \ + (((v) << 16) & BM_DIGCTL_OCRAM_STATUS10_FAILADDR21) +#define BP_DIGCTL_OCRAM_STATUS10_FAILADDR20 0 +#define BM_DIGCTL_OCRAM_STATUS10_FAILADDR20 0x00001FFF +#define BF_DIGCTL_OCRAM_STATUS10_FAILADDR20(v) \ + (((v) << 0) & BM_DIGCTL_OCRAM_STATUS10_FAILADDR20) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS11, REGS_DIGCTL_BASE, 0x000001c0) +#define HW_DIGCTL_OCRAM_STATUS11_ADDR (REGS_DIGCTL_BASE + 0x000001c0) +#define BP_DIGCTL_OCRAM_STATUS11_FAILADDR31 16 +#define BM_DIGCTL_OCRAM_STATUS11_FAILADDR31 0x1FFF0000 +#define BF_DIGCTL_OCRAM_STATUS11_FAILADDR31(v) \ + (((v) << 16) & BM_DIGCTL_OCRAM_STATUS11_FAILADDR31) +#define BP_DIGCTL_OCRAM_STATUS11_FAILADDR30 0 +#define BM_DIGCTL_OCRAM_STATUS11_FAILADDR30 0x00001FFF +#define BF_DIGCTL_OCRAM_STATUS11_FAILADDR30(v) \ + (((v) << 0) & BM_DIGCTL_OCRAM_STATUS11_FAILADDR30) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS12, REGS_DIGCTL_BASE, 0x000001d0) +#define HW_DIGCTL_OCRAM_STATUS12_ADDR (REGS_DIGCTL_BASE + 0x000001d0) +#define BP_DIGCTL_OCRAM_STATUS12_FAILSTATE11 24 +#define BM_DIGCTL_OCRAM_STATUS12_FAILSTATE11 0x0F000000 +#define BF_DIGCTL_OCRAM_STATUS12_FAILSTATE11(v) \ + (((v) << 24) & BM_DIGCTL_OCRAM_STATUS12_FAILSTATE11) +#define BP_DIGCTL_OCRAM_STATUS12_FAILSTATE10 16 +#define BM_DIGCTL_OCRAM_STATUS12_FAILSTATE10 0x000F0000 +#define BF_DIGCTL_OCRAM_STATUS12_FAILSTATE10(v) \ + (((v) << 16) & BM_DIGCTL_OCRAM_STATUS12_FAILSTATE10) +#define BP_DIGCTL_OCRAM_STATUS12_FAILSTATE01 8 +#define BM_DIGCTL_OCRAM_STATUS12_FAILSTATE01 0x00000F00 +#define BF_DIGCTL_OCRAM_STATUS12_FAILSTATE01(v) \ + (((v) << 8) & BM_DIGCTL_OCRAM_STATUS12_FAILSTATE01) +#define BP_DIGCTL_OCRAM_STATUS12_FAILSTATE00 0 +#define BM_DIGCTL_OCRAM_STATUS12_FAILSTATE00 0x0000000F +#define BF_DIGCTL_OCRAM_STATUS12_FAILSTATE00(v) \ + (((v) << 0) & BM_DIGCTL_OCRAM_STATUS12_FAILSTATE00) +HW_REGISTER(HW_DIGCTL_OCRAM_STATUS13, REGS_DIGCTL_BASE, 0x000001e0) +#define HW_DIGCTL_OCRAM_STATUS13_ADDR (REGS_DIGCTL_BASE + 0x000001e0) +#define BP_DIGCTL_OCRAM_STATUS13_FAILSTATE31 24 +#define BM_DIGCTL_OCRAM_STATUS13_FAILSTATE31 0x0F000000 +#define BF_DIGCTL_OCRAM_STATUS13_FAILSTATE31(v) \ + (((v) << 24) & BM_DIGCTL_OCRAM_STATUS13_FAILSTATE31) +#define BP_DIGCTL_OCRAM_STATUS13_FAILSTATE30 16 +#define BM_DIGCTL_OCRAM_STATUS13_FAILSTATE30 0x000F0000 +#define BF_DIGCTL_OCRAM_STATUS13_FAILSTATE30(v) \ + (((v) << 16) & BM_DIGCTL_OCRAM_STATUS13_FAILSTATE30) +#define BP_DIGCTL_OCRAM_STATUS13_FAILSTATE21 8 +#define BM_DIGCTL_OCRAM_STATUS13_FAILSTATE21 0x00000F00 +#define BF_DIGCTL_OCRAM_STATUS13_FAILSTATE21(v) \ + (((v) << 8) & BM_DIGCTL_OCRAM_STATUS13_FAILSTATE21) +#define BP_DIGCTL_OCRAM_STATUS13_FAILSTATE20 0 +#define BM_DIGCTL_OCRAM_STATUS13_FAILSTATE20 0x0000000F +#define BF_DIGCTL_OCRAM_STATUS13_FAILSTATE20(v) \ + (((v) << 0) & BM_DIGCTL_OCRAM_STATUS13_FAILSTATE20) +HW_REGISTER_0(HW_DIGCTL_SCRATCH0, REGS_DIGCTL_BASE, 0x00000290) +#define HW_DIGCTL_SCRATCH0_ADDR (REGS_DIGCTL_BASE + 0x00000290) +#define BP_DIGCTL_SCRATCH0_PTR 0 +#define BM_DIGCTL_SCRATCH0_PTR 0xFFFFFFFF +#define BF_DIGCTL_SCRATCH0_PTR(v) (v) +HW_REGISTER_0(HW_DIGCTL_SCRATCH1, REGS_DIGCTL_BASE, 0x000002a0) +#define HW_DIGCTL_SCRATCH1_ADDR (REGS_DIGCTL_BASE + 0x000002a0) +#define BP_DIGCTL_SCRATCH1_PTR 0 +#define BM_DIGCTL_SCRATCH1_PTR 0xFFFFFFFF +#define BF_DIGCTL_SCRATCH1_PTR(v) (v) +HW_REGISTER_0(HW_DIGCTL_ARMCACHE, REGS_DIGCTL_BASE, 0x000002b0) +#define HW_DIGCTL_ARMCACHE_ADDR (REGS_DIGCTL_BASE + 0x000002b0) +#define BP_DIGCTL_ARMCACHE_VALID_SS 16 +#define BM_DIGCTL_ARMCACHE_VALID_SS 0x00030000 +#define BF_DIGCTL_ARMCACHE_VALID_SS(v) \ + (((v) << 16) & BM_DIGCTL_ARMCACHE_VALID_SS) +#define BP_DIGCTL_ARMCACHE_DRTY_SS 12 +#define BM_DIGCTL_ARMCACHE_DRTY_SS 0x00003000 +#define BF_DIGCTL_ARMCACHE_DRTY_SS(v) \ + (((v) << 12) & BM_DIGCTL_ARMCACHE_DRTY_SS) +#define BP_DIGCTL_ARMCACHE_CACHE_SS 8 +#define BM_DIGCTL_ARMCACHE_CACHE_SS 0x00000300 +#define BF_DIGCTL_ARMCACHE_CACHE_SS(v) \ + (((v) << 8) & BM_DIGCTL_ARMCACHE_CACHE_SS) +#define BP_DIGCTL_ARMCACHE_DTAG_SS 4 +#define BM_DIGCTL_ARMCACHE_DTAG_SS 0x00000030 +#define BF_DIGCTL_ARMCACHE_DTAG_SS(v) \ + (((v) << 4) & BM_DIGCTL_ARMCACHE_DTAG_SS) +#define BP_DIGCTL_ARMCACHE_ITAG_SS 0 +#define BM_DIGCTL_ARMCACHE_ITAG_SS 0x00000003 +#define BF_DIGCTL_ARMCACHE_ITAG_SS(v) \ + (((v) << 0) & BM_DIGCTL_ARMCACHE_ITAG_SS) +HW_REGISTER_0(HW_DIGCTL_DEBUG_TRAP_ADDR_LOW, REGS_DIGCTL_BASE, 0x000002c0) +#define HW_DIGCTL_DEBUG_TRAP_ADDR_LOW_ADDR (REGS_DIGCTL_BASE + 0x000002c0) +#define BP_DIGCTL_DEBUG_TRAP_ADDR_LOW_ADDR 0 +#define BM_DIGCTL_DEBUG_TRAP_ADDR_LOW_ADDR 0xFFFFFFFF +#define BF_DIGCTL_DEBUG_TRAP_ADDR_LOW_ADDR(v) (v) +HW_REGISTER_0(HW_DIGCTL_DEBUG_TRAP_ADDR_HIGH, REGS_DIGCTL_BASE, 0x000002d0) +#define HW_DIGCTL_DEBUG_TRAP_ADDR_HIGH_ADDR (REGS_DIGCTL_BASE + 0x000002d0) +#define BP_DIGCTL_DEBUG_TRAP_ADDR_HIGH_ADDR 0 +#define BM_DIGCTL_DEBUG_TRAP_ADDR_HIGH_ADDR 0xFFFFFFFF +#define BF_DIGCTL_DEBUG_TRAP_ADDR_HIGH_ADDR(v) (v) +HW_REGISTER_0(HW_DIGCTL_SGTL, REGS_DIGCTL_BASE, 0x00000300) +#define HW_DIGCTL_SGTL_ADDR (REGS_DIGCTL_BASE + 0x00000300) +#define BP_DIGCTL_SGTL_COPYRIGHT 0 +#define BM_DIGCTL_SGTL_COPYRIGHT 0xFFFFFFFF +#define BF_DIGCTL_SGTL_COPYRIGHT(v) (v) +HW_REGISTER_0(HW_DIGCTL_CHIPID, REGS_DIGCTL_BASE, 0x00000310) +#define HW_DIGCTL_CHIPID_ADDR (REGS_DIGCTL_BASE + 0x00000310) +#define BP_DIGCTL_CHIPID_PRODUCT_CODE 16 +#define BM_DIGCTL_CHIPID_PRODUCT_CODE 0xFFFF0000 +#define BF_DIGCTL_CHIPID_PRODUCT_CODE(v) \ + (((v) << 16) & BM_DIGCTL_CHIPID_PRODUCT_CODE) +#define BP_DIGCTL_CHIPID_REVISION 0 +#define BM_DIGCTL_CHIPID_REVISION 0x000000FF +#define BF_DIGCTL_CHIPID_REVISION(v) \ + (((v) << 0) & BM_DIGCTL_CHIPID_REVISION) +HW_REGISTER_0(HW_DIGCTL_AHB_STATS_SELECT, REGS_DIGCTL_BASE, 0x00000330) +#define HW_DIGCTL_AHB_STATS_SELECT_ADDR (REGS_DIGCTL_BASE + 0x00000330) +#define BP_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT 24 +#define BM_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT 0x0F000000 +#define BF_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT(v) \ + (((v) << 24) & BM_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT) +#define BV_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT__APBH 0x1 +#define BV_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT__APBX 0x2 +#define BV_DIGCTL_AHB_STATS_SELECT_L3_MASTER_SELECT__USB 0x4 +#define BP_DIGCTL_AHB_STATS_SELECT_L2_MASTER_SELECT 16 +#define BM_DIGCTL_AHB_STATS_SELECT_L2_MASTER_SELECT 0x000F0000 +#define BF_DIGCTL_AHB_STATS_SELECT_L2_MASTER_SELECT(v) \ + (((v) << 16) & BM_DIGCTL_AHB_STATS_SELECT_L2_MASTER_SELECT) +#define BV_DIGCTL_AHB_STATS_SELECT_L2_MASTER_SELECT__ARM_D 0x1 +#define BP_DIGCTL_AHB_STATS_SELECT_L1_MASTER_SELECT 8 +#define BM_DIGCTL_AHB_STATS_SELECT_L1_MASTER_SELECT 0x00000F00 +#define BF_DIGCTL_AHB_STATS_SELECT_L1_MASTER_SELECT(v) \ + (((v) << 8) & BM_DIGCTL_AHB_STATS_SELECT_L1_MASTER_SELECT) +#define BV_DIGCTL_AHB_STATS_SELECT_L1_MASTER_SELECT__ARM_I 0x1 +#define BP_DIGCTL_AHB_STATS_SELECT_L0_MASTER_SELECT 0 +#define BM_DIGCTL_AHB_STATS_SELECT_L0_MASTER_SELECT 0x0000000F +#define BF_DIGCTL_AHB_STATS_SELECT_L0_MASTER_SELECT(v) \ + (((v) << 0) & BM_DIGCTL_AHB_STATS_SELECT_L0_MASTER_SELECT) +#define BV_DIGCTL_AHB_STATS_SELECT_L0_MASTER_SELECT__ECC8 0x1 +#define BV_DIGCTL_AHB_STATS_SELECT_L0_MASTER_SELECT__CRYPTO 0x2 +HW_REGISTER_0(HW_DIGCTL_L0_AHB_ACTIVE_CYCLES, REGS_DIGCTL_BASE, 0x00000340) +#define HW_DIGCTL_L0_AHB_ACTIVE_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x00000340) +#define BP_DIGCTL_L0_AHB_ACTIVE_CYCLES_COUNT 0 +#define BM_DIGCTL_L0_AHB_ACTIVE_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L0_AHB_ACTIVE_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L0_AHB_DATA_STALLED, REGS_DIGCTL_BASE, 0x00000350) +#define HW_DIGCTL_L0_AHB_DATA_STALLED_ADDR (REGS_DIGCTL_BASE + 0x00000350) +#define BP_DIGCTL_L0_AHB_DATA_STALLED_COUNT 0 +#define BM_DIGCTL_L0_AHB_DATA_STALLED_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L0_AHB_DATA_STALLED_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L0_AHB_DATA_CYCLES, REGS_DIGCTL_BASE, 0x00000360) +#define HW_DIGCTL_L0_AHB_DATA_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x00000360) +#define BP_DIGCTL_L0_AHB_DATA_CYCLES_COUNT 0 +#define BM_DIGCTL_L0_AHB_DATA_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L0_AHB_DATA_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L1_AHB_ACTIVE_CYCLES, REGS_DIGCTL_BASE, 0x00000370) +#define HW_DIGCTL_L1_AHB_ACTIVE_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x00000370) +#define BP_DIGCTL_L1_AHB_ACTIVE_CYCLES_COUNT 0 +#define BM_DIGCTL_L1_AHB_ACTIVE_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L1_AHB_ACTIVE_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L1_AHB_DATA_STALLED, REGS_DIGCTL_BASE, 0x00000380) +#define HW_DIGCTL_L1_AHB_DATA_STALLED_ADDR (REGS_DIGCTL_BASE + 0x00000380) +#define BP_DIGCTL_L1_AHB_DATA_STALLED_COUNT 0 +#define BM_DIGCTL_L1_AHB_DATA_STALLED_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L1_AHB_DATA_STALLED_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L1_AHB_DATA_CYCLES, REGS_DIGCTL_BASE, 0x00000390) +#define HW_DIGCTL_L1_AHB_DATA_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x00000390) +#define BP_DIGCTL_L1_AHB_DATA_CYCLES_COUNT 0 +#define BM_DIGCTL_L1_AHB_DATA_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L1_AHB_DATA_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L2_AHB_ACTIVE_CYCLES, REGS_DIGCTL_BASE, 0x000003a0) +#define HW_DIGCTL_L2_AHB_ACTIVE_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x000003a0) +#define BP_DIGCTL_L2_AHB_ACTIVE_CYCLES_COUNT 0 +#define BM_DIGCTL_L2_AHB_ACTIVE_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L2_AHB_ACTIVE_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L2_AHB_DATA_STALLED, REGS_DIGCTL_BASE, 0x000003b0) +#define HW_DIGCTL_L2_AHB_DATA_STALLED_ADDR (REGS_DIGCTL_BASE + 0x000003b0) +#define BP_DIGCTL_L2_AHB_DATA_STALLED_COUNT 0 +#define BM_DIGCTL_L2_AHB_DATA_STALLED_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L2_AHB_DATA_STALLED_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L2_AHB_DATA_CYCLES, REGS_DIGCTL_BASE, 0x000003c0) +#define HW_DIGCTL_L2_AHB_DATA_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x000003c0) +#define BP_DIGCTL_L2_AHB_DATA_CYCLES_COUNT 0 +#define BM_DIGCTL_L2_AHB_DATA_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L2_AHB_DATA_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L3_AHB_ACTIVE_CYCLES, REGS_DIGCTL_BASE, 0x000003d0) +#define HW_DIGCTL_L3_AHB_ACTIVE_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x000003d0) +#define BP_DIGCTL_L3_AHB_ACTIVE_CYCLES_COUNT 0 +#define BM_DIGCTL_L3_AHB_ACTIVE_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L3_AHB_ACTIVE_CYCLES_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L3_AHB_DATA_STALLED, REGS_DIGCTL_BASE, 0x000003e0) +#define HW_DIGCTL_L3_AHB_DATA_STALLED_ADDR (REGS_DIGCTL_BASE + 0x000003e0) +#define BP_DIGCTL_L3_AHB_DATA_STALLED_COUNT 0 +#define BM_DIGCTL_L3_AHB_DATA_STALLED_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L3_AHB_DATA_STALLED_COUNT(v) (v) +HW_REGISTER_0(HW_DIGCTL_L3_AHB_DATA_CYCLES, REGS_DIGCTL_BASE, 0x000003f0) +#define HW_DIGCTL_L3_AHB_DATA_CYCLES_ADDR (REGS_DIGCTL_BASE + 0x000003f0) +#define BP_DIGCTL_L3_AHB_DATA_CYCLES_COUNT 0 +#define BM_DIGCTL_L3_AHB_DATA_CYCLES_COUNT 0xFFFFFFFF +#define BF_DIGCTL_L3_AHB_DATA_CYCLES_COUNT(v) (v) +/* + * multi-register-define name HW_DIGCTL_MPTEn_LOC + * base 0x00000400 + * count 16 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_DIGCTL_MPTEn_LOC, REGS_DIGCTL_BASE, 0x00000400, + 0x10) +#define BP_DIGCTL_MPTEn_LOC_LOC 0 +#define BM_DIGCTL_MPTEn_LOC_LOC 0x00000FFF +#define BF_DIGCTL_MPTEn_LOC_LOC(v) \ + (((v) << 0) & BM_DIGCTL_MPTEn_LOC_LOC) +HW_REGISTER_0(HW_DIGCTL_EMICLK_DELAY, REGS_DIGCTL_BASE, 0x00000500) +#define HW_DIGCTL_EMICLK_DELAY_ADDR (REGS_DIGCTL_BASE + 0x00000500) +#define BP_DIGCTL_EMICLK_DELAY_NUM_TAPS 0 +#define BM_DIGCTL_EMICLK_DELAY_NUM_TAPS 0x0000001F +#define BF_DIGCTL_EMICLK_DELAY_NUM_TAPS(v) \ + (((v) << 0) & BM_DIGCTL_EMICLK_DELAY_NUM_TAPS) +#endif /* __ARCH_ARM___DIGCTL_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-dram.h b/arch/arm/mach-stmp3xxx/include/mach/regs-dram.h new file mode 100644 index 000000000000..059b2edd0db0 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-dram.h @@ -0,0 +1,454 @@ +/* + * STMP DRAM Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___DRAM_H +#define __ARCH_ARM___DRAM_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_DRAM_BASE (REGS_BASE + 0xe0000) +#define REGS_DRAM_BASE_PHYS (0x800E0000) +#define REGS_DRAM_SIZE 0x00002000 +HW_REGISTER_0(HW_DRAM_CTL00, REGS_DRAM_BASE, 0x00000000) +#define HW_DRAM_CTL00_ADDR (REGS_DRAM_BASE + 0x00000000) +#define BM_DRAM_CTL00_AHB0_W_PRIORITY 0x01000000 +#define BM_DRAM_CTL00_AHB0_R_PRIORITY 0x00010000 +#define BM_DRAM_CTL00_AHB0_FIFO_TYPE_REG 0x00000100 +#define BM_DRAM_CTL00_ADDR_CMP_EN 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL01, REGS_DRAM_BASE, 0x00000004) +#define HW_DRAM_CTL01_ADDR (REGS_DRAM_BASE + 0x00000004) +#define BM_DRAM_CTL01_AHB2_FIFO_TYPE_REG 0x01000000 +#define BM_DRAM_CTL01_AHB1_W_PRIORITY 0x00010000 +#define BM_DRAM_CTL01_AHB1_R_PRIORITY 0x00000100 +#define BM_DRAM_CTL01_AHB1_FIFO_TYPE_REG 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL02, REGS_DRAM_BASE, 0x00000008) +#define HW_DRAM_CTL02_ADDR (REGS_DRAM_BASE + 0x00000008) +#define BM_DRAM_CTL02_AHB3_R_PRIORITY 0x01000000 +#define BM_DRAM_CTL02_AHB3_FIFO_TYPE_REG 0x00010000 +#define BM_DRAM_CTL02_AHB2_W_PRIORITY 0x00000100 +#define BM_DRAM_CTL02_AHB2_R_PRIORITY 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL03, REGS_DRAM_BASE, 0x0000000c) +#define HW_DRAM_CTL03_ADDR (REGS_DRAM_BASE + 0x0000000c) +#define BM_DRAM_CTL03_AUTO_REFRESH_MODE 0x01000000 +#define BM_DRAM_CTL03_AREFRESH 0x00010000 +#define BM_DRAM_CTL03_AP 0x00000100 +#define BM_DRAM_CTL03_AHB3_W_PRIORITY 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL04, REGS_DRAM_BASE, 0x00000010) +#define HW_DRAM_CTL04_ADDR (REGS_DRAM_BASE + 0x00000010) +#define BM_DRAM_CTL04_DLL_BYPASS_MODE 0x01000000 +#define BM_DRAM_CTL04_DLLLOCKREG 0x00010000 +#define BM_DRAM_CTL04_CONCURRENTAP 0x00000100 +#define BM_DRAM_CTL04_BANK_SPLIT_EN 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL05, REGS_DRAM_BASE, 0x00000014) +#define HW_DRAM_CTL05_ADDR (REGS_DRAM_BASE + 0x00000014) +#define BM_DRAM_CTL05_INTRPTREADA 0x01000000 +#define BM_DRAM_CTL05_INTRPTAPBURST 0x00010000 +#define BM_DRAM_CTL05_FAST_WRITE 0x00000100 +#define BM_DRAM_CTL05_EN_LOWPOWER_MODE 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL06, REGS_DRAM_BASE, 0x00000018) +#define HW_DRAM_CTL06_ADDR (REGS_DRAM_BASE + 0x00000018) +#define BM_DRAM_CTL06_POWER_DOWN 0x01000000 +#define BM_DRAM_CTL06_PLACEMENT_EN 0x00010000 +#define BM_DRAM_CTL06_NO_CMD_INIT 0x00000100 +#define BM_DRAM_CTL06_INTRPTWRITEA 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL07, REGS_DRAM_BASE, 0x0000001c) +#define HW_DRAM_CTL07_ADDR (REGS_DRAM_BASE + 0x0000001c) +#define BM_DRAM_CTL07_RW_SAME_EN 0x01000000 +#define BM_DRAM_CTL07_REG_DIMM_ENABLE 0x00010000 +#define BM_DRAM_CTL07_RD2RD_TURN 0x00000100 +#define BM_DRAM_CTL07_PRIORITY_EN 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL08, REGS_DRAM_BASE, 0x00000020) +#define HW_DRAM_CTL08_ADDR (REGS_DRAM_BASE + 0x00000020) +#define BM_DRAM_CTL08_TRAS_LOCKOUT 0x01000000 +#define BM_DRAM_CTL08_START 0x00010000 +#define BM_DRAM_CTL08_SREFRESH 0x00000100 +#define BM_DRAM_CTL08_SDR_MODE 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL09, REGS_DRAM_BASE, 0x00000024) +#define HW_DRAM_CTL09_ADDR (REGS_DRAM_BASE + 0x00000024) +#define BP_DRAM_CTL09_OUT_OF_RANGE_TYPE 24 +#define BM_DRAM_CTL09_OUT_OF_RANGE_TYPE 0x03000000 +#define BF_DRAM_CTL09_OUT_OF_RANGE_TYPE(v) \ + (((v) << 24) & BM_DRAM_CTL09_OUT_OF_RANGE_TYPE) +#define BP_DRAM_CTL09_OUT_OF_RANGE_SOURCE_ID 16 +#define BM_DRAM_CTL09_OUT_OF_RANGE_SOURCE_ID 0x00030000 +#define BF_DRAM_CTL09_OUT_OF_RANGE_SOURCE_ID(v) \ + (((v) << 16) & BM_DRAM_CTL09_OUT_OF_RANGE_SOURCE_ID) +#define BM_DRAM_CTL09_WRITE_MODEREG 0x00000100 +#define BM_DRAM_CTL09_WRITEINTERP 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL10, REGS_DRAM_BASE, 0x00000028) +#define HW_DRAM_CTL10_ADDR (REGS_DRAM_BASE + 0x00000028) +#define BP_DRAM_CTL10_AGE_COUNT 24 +#define BM_DRAM_CTL10_AGE_COUNT 0x07000000 +#define BF_DRAM_CTL10_AGE_COUNT(v) \ + (((v) << 24) & BM_DRAM_CTL10_AGE_COUNT) +#define BP_DRAM_CTL10_ADDR_PINS 16 +#define BM_DRAM_CTL10_ADDR_PINS 0x00070000 +#define BF_DRAM_CTL10_ADDR_PINS(v) \ + (((v) << 16) & BM_DRAM_CTL10_ADDR_PINS) +#define BP_DRAM_CTL10_TEMRS 8 +#define BM_DRAM_CTL10_TEMRS 0x00000300 +#define BF_DRAM_CTL10_TEMRS(v) \ + (((v) << 8) & BM_DRAM_CTL10_TEMRS) +#define BP_DRAM_CTL10_Q_FULLNESS 0 +#define BM_DRAM_CTL10_Q_FULLNESS 0x00000003 +#define BF_DRAM_CTL10_Q_FULLNESS(v) \ + (((v) << 0) & BM_DRAM_CTL10_Q_FULLNESS) +HW_REGISTER_0(HW_DRAM_CTL11, REGS_DRAM_BASE, 0x0000002c) +#define HW_DRAM_CTL11_ADDR (REGS_DRAM_BASE + 0x0000002c) +#define BP_DRAM_CTL11_MAX_CS_REG 24 +#define BM_DRAM_CTL11_MAX_CS_REG 0x07000000 +#define BF_DRAM_CTL11_MAX_CS_REG(v) \ + (((v) << 24) & BM_DRAM_CTL11_MAX_CS_REG) +#define BP_DRAM_CTL11_COMMAND_AGE_COUNT 16 +#define BM_DRAM_CTL11_COMMAND_AGE_COUNT 0x00070000 +#define BF_DRAM_CTL11_COMMAND_AGE_COUNT(v) \ + (((v) << 16) & BM_DRAM_CTL11_COMMAND_AGE_COUNT) +#define BP_DRAM_CTL11_COLUMN_SIZE 8 +#define BM_DRAM_CTL11_COLUMN_SIZE 0x00000700 +#define BF_DRAM_CTL11_COLUMN_SIZE(v) \ + (((v) << 8) & BM_DRAM_CTL11_COLUMN_SIZE) +#define BP_DRAM_CTL11_CASLAT 0 +#define BM_DRAM_CTL11_CASLAT 0x00000007 +#define BF_DRAM_CTL11_CASLAT(v) \ + (((v) << 0) & BM_DRAM_CTL11_CASLAT) +HW_REGISTER_0(HW_DRAM_CTL12, REGS_DRAM_BASE, 0x00000030) +#define HW_DRAM_CTL12_ADDR (REGS_DRAM_BASE + 0x00000030) +#define BP_DRAM_CTL12_TWR_INT 24 +#define BM_DRAM_CTL12_TWR_INT 0x07000000 +#define BF_DRAM_CTL12_TWR_INT(v) \ + (((v) << 24) & BM_DRAM_CTL12_TWR_INT) +#define BP_DRAM_CTL12_TRRD 16 +#define BM_DRAM_CTL12_TRRD 0x00070000 +#define BF_DRAM_CTL12_TRRD(v) \ + (((v) << 16) & BM_DRAM_CTL12_TRRD) +#define BP_DRAM_CTL12_TCKE 0 +#define BM_DRAM_CTL12_TCKE 0x00000007 +#define BF_DRAM_CTL12_TCKE(v) \ + (((v) << 0) & BM_DRAM_CTL12_TCKE) +HW_REGISTER_0(HW_DRAM_CTL13, REGS_DRAM_BASE, 0x00000034) +#define HW_DRAM_CTL13_ADDR (REGS_DRAM_BASE + 0x00000034) +#define BP_DRAM_CTL13_CASLAT_LIN_GATE 24 +#define BM_DRAM_CTL13_CASLAT_LIN_GATE 0x0F000000 +#define BF_DRAM_CTL13_CASLAT_LIN_GATE(v) \ + (((v) << 24) & BM_DRAM_CTL13_CASLAT_LIN_GATE) +#define BP_DRAM_CTL13_CASLAT_LIN 16 +#define BM_DRAM_CTL13_CASLAT_LIN 0x000F0000 +#define BF_DRAM_CTL13_CASLAT_LIN(v) \ + (((v) << 16) & BM_DRAM_CTL13_CASLAT_LIN) +#define BP_DRAM_CTL13_APREBIT 8 +#define BM_DRAM_CTL13_APREBIT 0x00000F00 +#define BF_DRAM_CTL13_APREBIT(v) \ + (((v) << 8) & BM_DRAM_CTL13_APREBIT) +#define BP_DRAM_CTL13_TWTR 0 +#define BM_DRAM_CTL13_TWTR 0x00000007 +#define BF_DRAM_CTL13_TWTR(v) \ + (((v) << 0) & BM_DRAM_CTL13_TWTR) +HW_REGISTER_0(HW_DRAM_CTL14, REGS_DRAM_BASE, 0x00000038) +#define HW_DRAM_CTL14_ADDR (REGS_DRAM_BASE + 0x00000038) +#define BP_DRAM_CTL14_MAX_COL_REG 24 +#define BM_DRAM_CTL14_MAX_COL_REG 0x0F000000 +#define BF_DRAM_CTL14_MAX_COL_REG(v) \ + (((v) << 24) & BM_DRAM_CTL14_MAX_COL_REG) +#define BP_DRAM_CTL14_LOWPOWER_REFRESH_ENABLE 16 +#define BM_DRAM_CTL14_LOWPOWER_REFRESH_ENABLE 0x000F0000 +#define BF_DRAM_CTL14_LOWPOWER_REFRESH_ENABLE(v) \ + (((v) << 16) & BM_DRAM_CTL14_LOWPOWER_REFRESH_ENABLE) +#define BP_DRAM_CTL14_INITAREF 8 +#define BM_DRAM_CTL14_INITAREF 0x00000F00 +#define BF_DRAM_CTL14_INITAREF(v) \ + (((v) << 8) & BM_DRAM_CTL14_INITAREF) +#define BP_DRAM_CTL14_CS_MAP 0 +#define BM_DRAM_CTL14_CS_MAP 0x0000000F +#define BF_DRAM_CTL14_CS_MAP(v) \ + (((v) << 0) & BM_DRAM_CTL14_CS_MAP) +HW_REGISTER_0(HW_DRAM_CTL15, REGS_DRAM_BASE, 0x0000003c) +#define HW_DRAM_CTL15_ADDR (REGS_DRAM_BASE + 0x0000003c) +#define BP_DRAM_CTL15_TRP 24 +#define BM_DRAM_CTL15_TRP 0x0F000000 +#define BF_DRAM_CTL15_TRP(v) \ + (((v) << 24) & BM_DRAM_CTL15_TRP) +#define BP_DRAM_CTL15_TDAL 16 +#define BM_DRAM_CTL15_TDAL 0x000F0000 +#define BF_DRAM_CTL15_TDAL(v) \ + (((v) << 16) & BM_DRAM_CTL15_TDAL) +#define BP_DRAM_CTL15_PORT_BUSY 8 +#define BM_DRAM_CTL15_PORT_BUSY 0x00000F00 +#define BF_DRAM_CTL15_PORT_BUSY(v) \ + (((v) << 8) & BM_DRAM_CTL15_PORT_BUSY) +#define BP_DRAM_CTL15_MAX_ROW_REG 0 +#define BM_DRAM_CTL15_MAX_ROW_REG 0x0000000F +#define BF_DRAM_CTL15_MAX_ROW_REG(v) \ + (((v) << 0) & BM_DRAM_CTL15_MAX_ROW_REG) +HW_REGISTER_0(HW_DRAM_CTL16, REGS_DRAM_BASE, 0x00000040) +#define HW_DRAM_CTL16_ADDR (REGS_DRAM_BASE + 0x00000040) +#define BP_DRAM_CTL16_TMRD 24 +#define BM_DRAM_CTL16_TMRD 0x1F000000 +#define BF_DRAM_CTL16_TMRD(v) \ + (((v) << 24) & BM_DRAM_CTL16_TMRD) +#define BP_DRAM_CTL16_LOWPOWER_CONTROL 16 +#define BM_DRAM_CTL16_LOWPOWER_CONTROL 0x001F0000 +#define BF_DRAM_CTL16_LOWPOWER_CONTROL(v) \ + (((v) << 16) & BM_DRAM_CTL16_LOWPOWER_CONTROL) +#define BP_DRAM_CTL16_LOWPOWER_AUTO_ENABLE 8 +#define BM_DRAM_CTL16_LOWPOWER_AUTO_ENABLE 0x00001F00 +#define BF_DRAM_CTL16_LOWPOWER_AUTO_ENABLE(v) \ + (((v) << 8) & BM_DRAM_CTL16_LOWPOWER_AUTO_ENABLE) +#define BP_DRAM_CTL16_INT_ACK 0 +#define BM_DRAM_CTL16_INT_ACK 0x0000000F +#define BF_DRAM_CTL16_INT_ACK(v) \ + (((v) << 0) & BM_DRAM_CTL16_INT_ACK) +HW_REGISTER_0(HW_DRAM_CTL17, REGS_DRAM_BASE, 0x00000044) +#define HW_DRAM_CTL17_ADDR (REGS_DRAM_BASE + 0x00000044) +#define BP_DRAM_CTL17_DLL_START_POINT 24 +#define BM_DRAM_CTL17_DLL_START_POINT 0xFF000000 +#define BF_DRAM_CTL17_DLL_START_POINT(v) \ + (((v) << 24) & BM_DRAM_CTL17_DLL_START_POINT) +#define BP_DRAM_CTL17_DLL_LOCK 16 +#define BM_DRAM_CTL17_DLL_LOCK 0x00FF0000 +#define BF_DRAM_CTL17_DLL_LOCK(v) \ + (((v) << 16) & BM_DRAM_CTL17_DLL_LOCK) +#define BP_DRAM_CTL17_DLL_INCREMENT 8 +#define BM_DRAM_CTL17_DLL_INCREMENT 0x0000FF00 +#define BF_DRAM_CTL17_DLL_INCREMENT(v) \ + (((v) << 8) & BM_DRAM_CTL17_DLL_INCREMENT) +#define BP_DRAM_CTL17_TRC 0 +#define BM_DRAM_CTL17_TRC 0x0000001F +#define BF_DRAM_CTL17_TRC(v) \ + (((v) << 0) & BM_DRAM_CTL17_TRC) +HW_REGISTER_0(HW_DRAM_CTL18, REGS_DRAM_BASE, 0x00000048) +#define HW_DRAM_CTL18_ADDR (REGS_DRAM_BASE + 0x00000048) +#define BP_DRAM_CTL18_DLL_DQS_DELAY_1 24 +#define BM_DRAM_CTL18_DLL_DQS_DELAY_1 0x7F000000 +#define BF_DRAM_CTL18_DLL_DQS_DELAY_1(v) \ + (((v) << 24) & BM_DRAM_CTL18_DLL_DQS_DELAY_1) +#define BP_DRAM_CTL18_DLL_DQS_DELAY_0 16 +#define BM_DRAM_CTL18_DLL_DQS_DELAY_0 0x007F0000 +#define BF_DRAM_CTL18_DLL_DQS_DELAY_0(v) \ + (((v) << 16) & BM_DRAM_CTL18_DLL_DQS_DELAY_0) +#define BP_DRAM_CTL18_INT_STATUS 8 +#define BM_DRAM_CTL18_INT_STATUS 0x00001F00 +#define BF_DRAM_CTL18_INT_STATUS(v) \ + (((v) << 8) & BM_DRAM_CTL18_INT_STATUS) +#define BP_DRAM_CTL18_INT_MASK 0 +#define BM_DRAM_CTL18_INT_MASK 0x0000001F +#define BF_DRAM_CTL18_INT_MASK(v) \ + (((v) << 0) & BM_DRAM_CTL18_INT_MASK) +HW_REGISTER_0(HW_DRAM_CTL19, REGS_DRAM_BASE, 0x0000004c) +#define HW_DRAM_CTL19_ADDR (REGS_DRAM_BASE + 0x0000004c) +#define BP_DRAM_CTL19_DQS_OUT_SHIFT_BYPASS 24 +#define BM_DRAM_CTL19_DQS_OUT_SHIFT_BYPASS 0xFF000000 +#define BF_DRAM_CTL19_DQS_OUT_SHIFT_BYPASS(v) \ + (((v) << 24) & BM_DRAM_CTL19_DQS_OUT_SHIFT_BYPASS) +#define BP_DRAM_CTL19_DQS_OUT_SHIFT 16 +#define BM_DRAM_CTL19_DQS_OUT_SHIFT 0x007F0000 +#define BF_DRAM_CTL19_DQS_OUT_SHIFT(v) \ + (((v) << 16) & BM_DRAM_CTL19_DQS_OUT_SHIFT) +#define BP_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_1 8 +#define BM_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_1 0x0000FF00 +#define BF_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_1(v) \ + (((v) << 8) & BM_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_1) +#define BP_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_0 0 +#define BM_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_0 0x000000FF +#define BF_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_0(v) \ + (((v) << 0) & BM_DRAM_CTL19_DLL_DQS_DELAY_BYPASS_0) +HW_REGISTER_0(HW_DRAM_CTL20, REGS_DRAM_BASE, 0x00000050) +#define HW_DRAM_CTL20_ADDR (REGS_DRAM_BASE + 0x00000050) +#define BP_DRAM_CTL20_TRCD_INT 24 +#define BM_DRAM_CTL20_TRCD_INT 0xFF000000 +#define BF_DRAM_CTL20_TRCD_INT(v) \ + (((v) << 24) & BM_DRAM_CTL20_TRCD_INT) +#define BP_DRAM_CTL20_TRAS_MIN 16 +#define BM_DRAM_CTL20_TRAS_MIN 0x00FF0000 +#define BF_DRAM_CTL20_TRAS_MIN(v) \ + (((v) << 16) & BM_DRAM_CTL20_TRAS_MIN) +#define BP_DRAM_CTL20_WR_DQS_SHIFT_BYPASS 8 +#define BM_DRAM_CTL20_WR_DQS_SHIFT_BYPASS 0x0000FF00 +#define BF_DRAM_CTL20_WR_DQS_SHIFT_BYPASS(v) \ + (((v) << 8) & BM_DRAM_CTL20_WR_DQS_SHIFT_BYPASS) +#define BP_DRAM_CTL20_WR_DQS_SHIFT 0 +#define BM_DRAM_CTL20_WR_DQS_SHIFT 0x0000007F +#define BF_DRAM_CTL20_WR_DQS_SHIFT(v) \ + (((v) << 0) & BM_DRAM_CTL20_WR_DQS_SHIFT) +HW_REGISTER_0(HW_DRAM_CTL21, REGS_DRAM_BASE, 0x00000054) +#define HW_DRAM_CTL21_ADDR (REGS_DRAM_BASE + 0x00000054) +#define BP_DRAM_CTL21_OUT_OF_RANGE_LENGTH 8 +#define BM_DRAM_CTL21_OUT_OF_RANGE_LENGTH 0x0003FF00 +#define BF_DRAM_CTL21_OUT_OF_RANGE_LENGTH(v) \ + (((v) << 8) & BM_DRAM_CTL21_OUT_OF_RANGE_LENGTH) +#define BP_DRAM_CTL21_TRFC 0 +#define BM_DRAM_CTL21_TRFC 0x000000FF +#define BF_DRAM_CTL21_TRFC(v) \ + (((v) << 0) & BM_DRAM_CTL21_TRFC) +HW_REGISTER_0(HW_DRAM_CTL22, REGS_DRAM_BASE, 0x00000058) +#define HW_DRAM_CTL22_ADDR (REGS_DRAM_BASE + 0x00000058) +#define BP_DRAM_CTL22_AHB0_WRCNT 16 +#define BM_DRAM_CTL22_AHB0_WRCNT 0x07FF0000 +#define BF_DRAM_CTL22_AHB0_WRCNT(v) \ + (((v) << 16) & BM_DRAM_CTL22_AHB0_WRCNT) +#define BP_DRAM_CTL22_AHB0_RDCNT 0 +#define BM_DRAM_CTL22_AHB0_RDCNT 0x000007FF +#define BF_DRAM_CTL22_AHB0_RDCNT(v) \ + (((v) << 0) & BM_DRAM_CTL22_AHB0_RDCNT) +HW_REGISTER_0(HW_DRAM_CTL23, REGS_DRAM_BASE, 0x0000005c) +#define HW_DRAM_CTL23_ADDR (REGS_DRAM_BASE + 0x0000005c) +#define BP_DRAM_CTL23_AHB1_WRCNT 16 +#define BM_DRAM_CTL23_AHB1_WRCNT 0x07FF0000 +#define BF_DRAM_CTL23_AHB1_WRCNT(v) \ + (((v) << 16) & BM_DRAM_CTL23_AHB1_WRCNT) +#define BP_DRAM_CTL23_AHB1_RDCNT 0 +#define BM_DRAM_CTL23_AHB1_RDCNT 0x000007FF +#define BF_DRAM_CTL23_AHB1_RDCNT(v) \ + (((v) << 0) & BM_DRAM_CTL23_AHB1_RDCNT) +HW_REGISTER_0(HW_DRAM_CTL24, REGS_DRAM_BASE, 0x00000060) +#define HW_DRAM_CTL24_ADDR (REGS_DRAM_BASE + 0x00000060) +#define BP_DRAM_CTL24_AHB2_WRCNT 16 +#define BM_DRAM_CTL24_AHB2_WRCNT 0x07FF0000 +#define BF_DRAM_CTL24_AHB2_WRCNT(v) \ + (((v) << 16) & BM_DRAM_CTL24_AHB2_WRCNT) +#define BP_DRAM_CTL24_AHB2_RDCNT 0 +#define BM_DRAM_CTL24_AHB2_RDCNT 0x000007FF +#define BF_DRAM_CTL24_AHB2_RDCNT(v) \ + (((v) << 0) & BM_DRAM_CTL24_AHB2_RDCNT) +HW_REGISTER_0(HW_DRAM_CTL25, REGS_DRAM_BASE, 0x00000064) +#define HW_DRAM_CTL25_ADDR (REGS_DRAM_BASE + 0x00000064) +#define BP_DRAM_CTL25_AHB3_WRCNT 16 +#define BM_DRAM_CTL25_AHB3_WRCNT 0x07FF0000 +#define BF_DRAM_CTL25_AHB3_WRCNT(v) \ + (((v) << 16) & BM_DRAM_CTL25_AHB3_WRCNT) +#define BP_DRAM_CTL25_AHB3_RDCNT 0 +#define BM_DRAM_CTL25_AHB3_RDCNT 0x000007FF +#define BF_DRAM_CTL25_AHB3_RDCNT(v) \ + (((v) << 0) & BM_DRAM_CTL25_AHB3_RDCNT) +HW_REGISTER_0(HW_DRAM_CTL26, REGS_DRAM_BASE, 0x00000068) +#define HW_DRAM_CTL26_ADDR (REGS_DRAM_BASE + 0x00000068) +#define BP_DRAM_CTL26_TREF 0 +#define BM_DRAM_CTL26_TREF 0x00000FFF +#define BF_DRAM_CTL26_TREF(v) \ + (((v) << 0) & BM_DRAM_CTL26_TREF) +HW_REGISTER_0(HW_DRAM_CTL27, REGS_DRAM_BASE, 0x0000006c) +#define HW_DRAM_CTL27_ADDR (REGS_DRAM_BASE + 0x0000006c) +HW_REGISTER_0(HW_DRAM_CTL28, REGS_DRAM_BASE, 0x00000070) +#define HW_DRAM_CTL28_ADDR (REGS_DRAM_BASE + 0x00000070) +HW_REGISTER_0(HW_DRAM_CTL29, REGS_DRAM_BASE, 0x00000074) +#define HW_DRAM_CTL29_ADDR (REGS_DRAM_BASE + 0x00000074) +#define BP_DRAM_CTL29_LOWPOWER_INTERNAL_CNT 16 +#define BM_DRAM_CTL29_LOWPOWER_INTERNAL_CNT 0xFFFF0000 +#define BF_DRAM_CTL29_LOWPOWER_INTERNAL_CNT(v) \ + (((v) << 16) & BM_DRAM_CTL29_LOWPOWER_INTERNAL_CNT) +#define BP_DRAM_CTL29_LOWPOWER_EXTERNAL_CNT 0 +#define BM_DRAM_CTL29_LOWPOWER_EXTERNAL_CNT 0x0000FFFF +#define BF_DRAM_CTL29_LOWPOWER_EXTERNAL_CNT(v) \ + (((v) << 0) & BM_DRAM_CTL29_LOWPOWER_EXTERNAL_CNT) +HW_REGISTER_0(HW_DRAM_CTL30, REGS_DRAM_BASE, 0x00000078) +#define HW_DRAM_CTL30_ADDR (REGS_DRAM_BASE + 0x00000078) +#define BP_DRAM_CTL30_LOWPOWER_REFRESH_HOLD 16 +#define BM_DRAM_CTL30_LOWPOWER_REFRESH_HOLD 0xFFFF0000 +#define BF_DRAM_CTL30_LOWPOWER_REFRESH_HOLD(v) \ + (((v) << 16) & BM_DRAM_CTL30_LOWPOWER_REFRESH_HOLD) +#define BP_DRAM_CTL30_LOWPOWER_POWER_DOWN_CNT 0 +#define BM_DRAM_CTL30_LOWPOWER_POWER_DOWN_CNT 0x0000FFFF +#define BF_DRAM_CTL30_LOWPOWER_POWER_DOWN_CNT(v) \ + (((v) << 0) & BM_DRAM_CTL30_LOWPOWER_POWER_DOWN_CNT) +HW_REGISTER_0(HW_DRAM_CTL31, REGS_DRAM_BASE, 0x0000007c) +#define HW_DRAM_CTL31_ADDR (REGS_DRAM_BASE + 0x0000007c) +#define BP_DRAM_CTL31_TDLL 16 +#define BM_DRAM_CTL31_TDLL 0xFFFF0000 +#define BF_DRAM_CTL31_TDLL(v) \ + (((v) << 16) & BM_DRAM_CTL31_TDLL) +#define BP_DRAM_CTL31_LOWPOWER_SELF_REFRESH_CNT 0 +#define BM_DRAM_CTL31_LOWPOWER_SELF_REFRESH_CNT 0x0000FFFF +#define BF_DRAM_CTL31_LOWPOWER_SELF_REFRESH_CNT(v) \ + (((v) << 0) & BM_DRAM_CTL31_LOWPOWER_SELF_REFRESH_CNT) +HW_REGISTER_0(HW_DRAM_CTL32, REGS_DRAM_BASE, 0x00000080) +#define HW_DRAM_CTL32_ADDR (REGS_DRAM_BASE + 0x00000080) +#define BP_DRAM_CTL32_TXSNR 16 +#define BM_DRAM_CTL32_TXSNR 0xFFFF0000 +#define BF_DRAM_CTL32_TXSNR(v) \ + (((v) << 16) & BM_DRAM_CTL32_TXSNR) +#define BP_DRAM_CTL32_TRAS_MAX 0 +#define BM_DRAM_CTL32_TRAS_MAX 0x0000FFFF +#define BF_DRAM_CTL32_TRAS_MAX(v) \ + (((v) << 0) & BM_DRAM_CTL32_TRAS_MAX) +HW_REGISTER_0(HW_DRAM_CTL33, REGS_DRAM_BASE, 0x00000084) +#define HW_DRAM_CTL33_ADDR (REGS_DRAM_BASE + 0x00000084) +#define BP_DRAM_CTL33_VERSION 16 +#define BM_DRAM_CTL33_VERSION 0xFFFF0000 +#define BF_DRAM_CTL33_VERSION(v) \ + (((v) << 16) & BM_DRAM_CTL33_VERSION) +#define BP_DRAM_CTL33_TXSR 0 +#define BM_DRAM_CTL33_TXSR 0x0000FFFF +#define BF_DRAM_CTL33_TXSR(v) \ + (((v) << 0) & BM_DRAM_CTL33_TXSR) +HW_REGISTER_0(HW_DRAM_CTL34, REGS_DRAM_BASE, 0x00000088) +#define HW_DRAM_CTL34_ADDR (REGS_DRAM_BASE + 0x00000088) +#define BP_DRAM_CTL34_TINIT 0 +#define BM_DRAM_CTL34_TINIT 0x00FFFFFF +#define BF_DRAM_CTL34_TINIT(v) \ + (((v) << 0) & BM_DRAM_CTL34_TINIT) +HW_REGISTER_0(HW_DRAM_CTL35, REGS_DRAM_BASE, 0x0000008c) +#define HW_DRAM_CTL35_ADDR (REGS_DRAM_BASE + 0x0000008c) +#define BP_DRAM_CTL35_OUT_OF_RANGE_ADDR 0 +#define BM_DRAM_CTL35_OUT_OF_RANGE_ADDR 0x7FFFFFFF +#define BF_DRAM_CTL35_OUT_OF_RANGE_ADDR(v) \ + (((v) << 0) & BM_DRAM_CTL35_OUT_OF_RANGE_ADDR) +HW_REGISTER_0(HW_DRAM_CTL36, REGS_DRAM_BASE, 0x00000090) +#define HW_DRAM_CTL36_ADDR (REGS_DRAM_BASE + 0x00000090) +#define BM_DRAM_CTL36_PWRUP_SREFRESH_EXIT 0x01000000 +#define BM_DRAM_CTL36_ENABLE_QUICK_SREFRESH 0x00010000 +#define BM_DRAM_CTL36_BUS_SHARE_ENABLE 0x00000100 +#define BM_DRAM_CTL36_ACTIVE_AGING 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL37, REGS_DRAM_BASE, 0x00000094) +#define HW_DRAM_CTL37_ADDR (REGS_DRAM_BASE + 0x00000094) +#define BP_DRAM_CTL37_BUS_SHARE_TIMEOUT 8 +#define BM_DRAM_CTL37_BUS_SHARE_TIMEOUT 0x0003FF00 +#define BF_DRAM_CTL37_BUS_SHARE_TIMEOUT(v) \ + (((v) << 8) & BM_DRAM_CTL37_BUS_SHARE_TIMEOUT) +#define BM_DRAM_CTL37_TREF_ENABLE 0x00000001 +HW_REGISTER_0(HW_DRAM_CTL38, REGS_DRAM_BASE, 0x00000098) +#define HW_DRAM_CTL38_ADDR (REGS_DRAM_BASE + 0x00000098) +#define BP_DRAM_CTL38_EMRS2_DATA_0 16 +#define BM_DRAM_CTL38_EMRS2_DATA_0 0x1FFF0000 +#define BF_DRAM_CTL38_EMRS2_DATA_0(v) \ + (((v) << 16) & BM_DRAM_CTL38_EMRS2_DATA_0) +#define BP_DRAM_CTL38_EMRS1_DATA 0 +#define BM_DRAM_CTL38_EMRS1_DATA 0x00001FFF +#define BF_DRAM_CTL38_EMRS1_DATA(v) \ + (((v) << 0) & BM_DRAM_CTL38_EMRS1_DATA) +HW_REGISTER_0(HW_DRAM_CTL39, REGS_DRAM_BASE, 0x0000009c) +#define HW_DRAM_CTL39_ADDR (REGS_DRAM_BASE + 0x0000009c) +#define BP_DRAM_CTL39_EMRS2_DATA_2 16 +#define BM_DRAM_CTL39_EMRS2_DATA_2 0x1FFF0000 +#define BF_DRAM_CTL39_EMRS2_DATA_2(v) \ + (((v) << 16) & BM_DRAM_CTL39_EMRS2_DATA_2) +#define BP_DRAM_CTL39_EMRS2_DATA_1 0 +#define BM_DRAM_CTL39_EMRS2_DATA_1 0x00001FFF +#define BF_DRAM_CTL39_EMRS2_DATA_1(v) \ + (((v) << 0) & BM_DRAM_CTL39_EMRS2_DATA_1) +HW_REGISTER_0(HW_DRAM_CTL40, REGS_DRAM_BASE, 0x000000a0) +#define HW_DRAM_CTL40_ADDR (REGS_DRAM_BASE + 0x000000a0) +#define BP_DRAM_CTL40_TPDEX 16 +#define BM_DRAM_CTL40_TPDEX 0xFFFF0000 +#define BF_DRAM_CTL40_TPDEX(v) \ + (((v) << 16) & BM_DRAM_CTL40_TPDEX) +#define BP_DRAM_CTL40_EMRS2_DATA_3 0 +#define BM_DRAM_CTL40_EMRS2_DATA_3 0x00001FFF +#define BF_DRAM_CTL40_EMRS2_DATA_3(v) \ + (((v) << 0) & BM_DRAM_CTL40_EMRS2_DATA_3) +#endif /* __ARCH_ARM___DRAM_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-dri.h b/arch/arm/mach-stmp3xxx/include/mach/regs-dri.h new file mode 100644 index 000000000000..7dec7e09c871 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-dri.h @@ -0,0 +1,160 @@ +/* + * STMP DRI Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___DRI_H +#define __ARCH_ARM___DRI_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_DRI_BASE (REGS_BASE + 0x74000) +#define REGS_DRI_BASE_PHYS (0x80074000) +#define REGS_DRI_SIZE 0x00002000 +HW_REGISTER(HW_DRI_CTRL, REGS_DRI_BASE, 0x00000000) +#define HW_DRI_CTRL_ADDR (REGS_DRI_BASE + 0x00000000) +#define BM_DRI_CTRL_SFTRST 0x80000000 +#define BV_DRI_CTRL_SFTRST__RUN 0x0 +#define BV_DRI_CTRL_SFTRST__RESET 0x1 +#define BM_DRI_CTRL_CLKGATE 0x40000000 +#define BV_DRI_CTRL_CLKGATE__RUN 0x0 +#define BV_DRI_CTRL_CLKGATE__NO_CLKS 0x1 +#define BM_DRI_CTRL_ENABLE_INPUTS 0x20000000 +#define BV_DRI_CTRL_ENABLE_INPUTS__ANALOG_LINE_IN 0x0 +#define BV_DRI_CTRL_ENABLE_INPUTS__DRI_DIGITAL_IN 0x1 +#define BM_DRI_CTRL_STOP_ON_OFLOW_ERROR 0x04000000 +#define BV_DRI_CTRL_STOP_ON_OFLOW_ERROR__IGNORE 0x0 +#define BV_DRI_CTRL_STOP_ON_OFLOW_ERROR__STOP 0x1 +#define BM_DRI_CTRL_STOP_ON_PILOT_ERROR 0x02000000 +#define BV_DRI_CTRL_STOP_ON_PILOT_ERROR__IGNORE 0x0 +#define BV_DRI_CTRL_STOP_ON_PILOT_ERROR__STOP 0x1 +#define BP_DRI_CTRL_DMA_DELAY_COUNT 16 +#define BM_DRI_CTRL_DMA_DELAY_COUNT 0x001F0000 +#define BF_DRI_CTRL_DMA_DELAY_COUNT(v) \ + (((v) << 16) & BM_DRI_CTRL_DMA_DELAY_COUNT) +#define BM_DRI_CTRL_REACQUIRE_PHASE 0x00008000 +#define BV_DRI_CTRL_REACQUIRE_PHASE__NORMAL 0x0 +#define BV_DRI_CTRL_REACQUIRE_PHASE__NEW_PHASE 0x1 +#define BM_DRI_CTRL_OVERFLOW_IRQ_EN 0x00000800 +#define BV_DRI_CTRL_OVERFLOW_IRQ_EN__DISABLED 0x0 +#define BV_DRI_CTRL_OVERFLOW_IRQ_EN__ENABLED 0x1 +#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN 0x00000400 +#define BV_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN__DISABLED 0x0 +#define BV_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN__ENABLED 0x1 +#define BM_DRI_CTRL_ATTENTION_IRQ_EN 0x00000200 +#define BV_DRI_CTRL_ATTENTION_IRQ_EN__DISABLED 0x0 +#define BV_DRI_CTRL_ATTENTION_IRQ_EN__ENABLED 0x1 +#define BM_DRI_CTRL_OVERFLOW_IRQ 0x00000008 +#define BV_DRI_CTRL_OVERFLOW_IRQ__NO_REQUEST 0x0 +#define BV_DRI_CTRL_OVERFLOW_IRQ__REQUEST 0x1 +#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ 0x00000004 +#define BV_DRI_CTRL_PILOT_SYNC_LOSS_IRQ__NO_REQUEST 0x0 +#define BV_DRI_CTRL_PILOT_SYNC_LOSS_IRQ__REQUEST 0x1 +#define BM_DRI_CTRL_ATTENTION_IRQ 0x00000002 +#define BV_DRI_CTRL_ATTENTION_IRQ__NO_REQUEST 0x0 +#define BV_DRI_CTRL_ATTENTION_IRQ__REQUEST 0x1 +#define BM_DRI_CTRL_RUN 0x00000001 +#define BV_DRI_CTRL_RUN__HALT 0x0 +#define BV_DRI_CTRL_RUN__RUN 0x1 +HW_REGISTER_0(HW_DRI_TIMING, REGS_DRI_BASE, 0x00000010) +#define HW_DRI_TIMING_ADDR (REGS_DRI_BASE + 0x00000010) +#define BP_DRI_TIMING_PILOT_REP_RATE 16 +#define BM_DRI_TIMING_PILOT_REP_RATE 0x000F0000 +#define BF_DRI_TIMING_PILOT_REP_RATE(v) \ + (((v) << 16) & BM_DRI_TIMING_PILOT_REP_RATE) +#define BP_DRI_TIMING_GAP_DETECTION_INTERVAL 0 +#define BM_DRI_TIMING_GAP_DETECTION_INTERVAL 0x000000FF +#define BF_DRI_TIMING_GAP_DETECTION_INTERVAL(v) \ + (((v) << 0) & BM_DRI_TIMING_GAP_DETECTION_INTERVAL) +HW_REGISTER_0(HW_DRI_STAT, REGS_DRI_BASE, 0x00000020) +#define HW_DRI_STAT_ADDR (REGS_DRI_BASE + 0x00000020) +#define BM_DRI_STAT_DRI_PRESENT 0x80000000 +#define BV_DRI_STAT_DRI_PRESENT__UNAVAILABLE 0x0 +#define BV_DRI_STAT_DRI_PRESENT__AVAILABLE 0x1 +#define BP_DRI_STAT_PILOT_PHASE 16 +#define BM_DRI_STAT_PILOT_PHASE 0x000F0000 +#define BF_DRI_STAT_PILOT_PHASE(v) \ + (((v) << 16) & BM_DRI_STAT_PILOT_PHASE) +#define BM_DRI_STAT_OVERFLOW_IRQ_SUMMARY 0x00000008 +#define BV_DRI_STAT_OVERFLOW_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_DRI_STAT_OVERFLOW_IRQ_SUMMARY__REQUEST 0x1 +#define BM_DRI_STAT_PILOT_SYNC_LOSS_IRQ_SUMMARY 0x00000004 +#define BV_DRI_STAT_PILOT_SYNC_LOSS_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_DRI_STAT_PILOT_SYNC_LOSS_IRQ_SUMMARY__REQUEST 0x1 +#define BM_DRI_STAT_ATTENTION_IRQ_SUMMARY 0x00000002 +#define BV_DRI_STAT_ATTENTION_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_DRI_STAT_ATTENTION_IRQ_SUMMARY__REQUEST 0x1 +HW_REGISTER_0(HW_DRI_DATA, REGS_DRI_BASE, 0x00000030) +#define HW_DRI_DATA_ADDR (REGS_DRI_BASE + 0x00000030) +#define BP_DRI_DATA_DATA 0 +#define BM_DRI_DATA_DATA 0xFFFFFFFF +#define BF_DRI_DATA_DATA(v) (v) +HW_REGISTER(HW_DRI_DEBUG0, REGS_DRI_BASE, 0x00000040) +#define HW_DRI_DEBUG0_ADDR (REGS_DRI_BASE + 0x00000040) +#define BM_DRI_DEBUG0_DMAREQ 0x80000000 +#define BM_DRI_DEBUG0_DMACMDKICK 0x40000000 +#define BM_DRI_DEBUG0_DRI_CLK_INPUT 0x20000000 +#define BM_DRI_DEBUG0_DRI_DATA_INPUT 0x10000000 +#define BM_DRI_DEBUG0_TEST_MODE 0x08000000 +#define BM_DRI_DEBUG0_PILOT_REP_RATE 0x04000000 +#define BV_DRI_DEBUG0_PILOT_REP_RATE__8_AT_4MHZ 0x0 +#define BV_DRI_DEBUG0_PILOT_REP_RATE__12_AT_6MHZ 0x1 +#define BP_DRI_DEBUG0_SPARE 18 +#define BM_DRI_DEBUG0_SPARE 0x03FC0000 +#define BF_DRI_DEBUG0_SPARE(v) \ + (((v) << 18) & BM_DRI_DEBUG0_SPARE) +#define BP_DRI_DEBUG0_FRAME 0 +#define BM_DRI_DEBUG0_FRAME 0x0003FFFF +#define BF_DRI_DEBUG0_FRAME(v) \ + (((v) << 0) & BM_DRI_DEBUG0_FRAME) +HW_REGISTER(HW_DRI_DEBUG1, REGS_DRI_BASE, 0x00000050) +#define HW_DRI_DEBUG1_ADDR (REGS_DRI_BASE + 0x00000050) +#define BM_DRI_DEBUG1_INVERT_PILOT 0x80000000 +#define BV_DRI_DEBUG1_INVERT_PILOT__NORMAL 0x0 +#define BV_DRI_DEBUG1_INVERT_PILOT__INVERTED 0x1 +#define BM_DRI_DEBUG1_INVERT_ATTENTION 0x40000000 +#define BV_DRI_DEBUG1_INVERT_ATTENTION__NORMAL 0x0 +#define BV_DRI_DEBUG1_INVERT_ATTENTION__INVERTED 0x1 +#define BM_DRI_DEBUG1_INVERT_DRI_DATA 0x20000000 +#define BV_DRI_DEBUG1_INVERT_DRI_DATA__NORMAL 0x0 +#define BV_DRI_DEBUG1_INVERT_DRI_DATA__INVERTED 0x1 +#define BM_DRI_DEBUG1_INVERT_DRI_CLOCK 0x10000000 +#define BV_DRI_DEBUG1_INVERT_DRI_CLOCK__NORMAL 0x0 +#define BV_DRI_DEBUG1_INVERT_DRI_CLOCK__INVERTED 0x1 +#define BM_DRI_DEBUG1_REVERSE_FRAME 0x08000000 +#define BV_DRI_DEBUG1_REVERSE_FRAME__NORMAL 0x0 +#define BV_DRI_DEBUG1_REVERSE_FRAME__REVERSED 0x1 +#define BP_DRI_DEBUG1_SWIZZLED_FRAME 0 +#define BM_DRI_DEBUG1_SWIZZLED_FRAME 0x0003FFFF +#define BF_DRI_DEBUG1_SWIZZLED_FRAME(v) \ + (((v) << 0) & BM_DRI_DEBUG1_SWIZZLED_FRAME) +HW_REGISTER_0(HW_DRI_VERSION, REGS_DRI_BASE, 0x00000060) +#define HW_DRI_VERSION_ADDR (REGS_DRI_BASE + 0x00000060) +#define BP_DRI_VERSION_MAJOR 24 +#define BM_DRI_VERSION_MAJOR 0xFF000000 +#define BF_DRI_VERSION_MAJOR(v) \ + (((v) << 24) & BM_DRI_VERSION_MAJOR) +#define BP_DRI_VERSION_MINOR 16 +#define BM_DRI_VERSION_MINOR 0x00FF0000 +#define BF_DRI_VERSION_MINOR(v) \ + (((v) << 16) & BM_DRI_VERSION_MINOR) +#define BP_DRI_VERSION_STEP 0 +#define BM_DRI_VERSION_STEP 0x0000FFFF +#define BF_DRI_VERSION_STEP(v) \ + (((v) << 0) & BM_DRI_VERSION_STEP) +#endif /* __ARCH_ARM___DRI_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-ecc8.h b/arch/arm/mach-stmp3xxx/include/mach/regs-ecc8.h new file mode 100644 index 000000000000..527bce602f12 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-ecc8.h @@ -0,0 +1,279 @@ +/* + * STMP ECC8 Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___ECC8_H +#define __ARCH_ARM___ECC8_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_ECC8_BASE (REGS_BASE + 0x8000) +#define REGS_ECC8_BASE_PHYS (0x80008000) +#define REGS_ECC8_SIZE 0x00002000 +HW_REGISTER(HW_ECC8_CTRL, REGS_ECC8_BASE, 0x00000000) +#define HW_ECC8_CTRL_ADDR (REGS_ECC8_BASE + 0x00000000) +#define BM_ECC8_CTRL_SFTRST 0x80000000 +#define BV_ECC8_CTRL_SFTRST__RUN 0x0 +#define BV_ECC8_CTRL_SFTRST__RESET 0x1 +#define BM_ECC8_CTRL_CLKGATE 0x40000000 +#define BV_ECC8_CTRL_CLKGATE__RUN 0x0 +#define BV_ECC8_CTRL_CLKGATE__NO_CLKS 0x1 +#define BM_ECC8_CTRL_AHBM_SFTRST 0x20000000 +#define BV_ECC8_CTRL_AHBM_SFTRST__RUN 0x0 +#define BV_ECC8_CTRL_AHBM_SFTRST__RESET 0x1 +#define BP_ECC8_CTRL_THROTTLE 24 +#define BM_ECC8_CTRL_THROTTLE 0x0F000000 +#define BF_ECC8_CTRL_THROTTLE(v) \ + (((v) << 24) & BM_ECC8_CTRL_THROTTLE) +#define BM_ECC8_CTRL_DEBUG_STALL_IRQ_EN 0x00000400 +#define BM_ECC8_CTRL_DEBUG_WRITE_IRQ_EN 0x00000200 +#define BM_ECC8_CTRL_COMPLETE_IRQ_EN 0x00000100 +#define BM_ECC8_CTRL_BM_ERROR_IRQ 0x00000008 +#define BM_ECC8_CTRL_DEBUG_STALL_IRQ 0x00000004 +#define BM_ECC8_CTRL_DEBUG_WRITE_IRQ 0x00000002 +#define BM_ECC8_CTRL_COMPLETE_IRQ 0x00000001 +HW_REGISTER_0(HW_ECC8_STATUS0, REGS_ECC8_BASE, 0x00000010) +#define HW_ECC8_STATUS0_ADDR (REGS_ECC8_BASE + 0x00000010) +#define BP_ECC8_STATUS0_HANDLE 20 +#define BM_ECC8_STATUS0_HANDLE 0xFFF00000 +#define BF_ECC8_STATUS0_HANDLE(v) \ + (((v) << 20) & BM_ECC8_STATUS0_HANDLE) +#define BP_ECC8_STATUS0_COMPLETED_CE 16 +#define BM_ECC8_STATUS0_COMPLETED_CE 0x000F0000 +#define BF_ECC8_STATUS0_COMPLETED_CE(v) \ + (((v) << 16) & BM_ECC8_STATUS0_COMPLETED_CE) +#define BM_ECC8_STATUS0_RS8ECC_ENC_PRESENT 0x00008000 +#define BM_ECC8_STATUS0_RS8ECC_DEC_PRESENT 0x00004000 +#define BM_ECC8_STATUS0_RS4ECC_ENC_PRESENT 0x00002000 +#define BM_ECC8_STATUS0_RS4ECC_DEC_PRESENT 0x00001000 +#define BP_ECC8_STATUS0_STATUS_AUX 8 +#define BM_ECC8_STATUS0_STATUS_AUX 0x00000F00 +#define BF_ECC8_STATUS0_STATUS_AUX(v) \ + (((v) << 8) & BM_ECC8_STATUS0_STATUS_AUX) +#define BV_ECC8_STATUS0_STATUS_AUX__NO_ERRORS 0x0 +#define BV_ECC8_STATUS0_STATUS_AUX__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS0_STATUS_AUX__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS0_STATUS_AUX__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS0_STATUS_AUX__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS0_STATUS_AUX__NOT_CHECKED 0xC +#define BV_ECC8_STATUS0_STATUS_AUX__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS0_STATUS_AUX__ALL_ONES 0xF +#define BM_ECC8_STATUS0_ALLONES 0x00000010 +#define BM_ECC8_STATUS0_CORRECTED 0x00000008 +#define BM_ECC8_STATUS0_UNCORRECTABLE 0x00000004 +HW_REGISTER_0(HW_ECC8_STATUS1, REGS_ECC8_BASE, 0x00000020) +#define HW_ECC8_STATUS1_ADDR (REGS_ECC8_BASE + 0x00000020) +#define BP_ECC8_STATUS1_STATUS_PAYLOAD7 28 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD7 0xF0000000 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD7(v) \ + (((v) << 28) & BM_ECC8_STATUS1_STATUS_PAYLOAD7) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD7__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD6 24 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD6 0x0F000000 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD6(v) \ + (((v) << 24) & BM_ECC8_STATUS1_STATUS_PAYLOAD6) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD6__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD5 20 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD5 0x00F00000 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD5(v) \ + (((v) << 20) & BM_ECC8_STATUS1_STATUS_PAYLOAD5) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD5__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD4 16 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD4 0x000F0000 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD4(v) \ + (((v) << 16) & BM_ECC8_STATUS1_STATUS_PAYLOAD4) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD4__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD3 12 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD3 0x0000F000 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD3(v) \ + (((v) << 12) & BM_ECC8_STATUS1_STATUS_PAYLOAD3) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD3__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD2 8 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD2 0x00000F00 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD2(v) \ + (((v) << 8) & BM_ECC8_STATUS1_STATUS_PAYLOAD2) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD2__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD1 4 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD1 0x000000F0 +#define BF_ECC8_STATUS1_STATUS_PAYLOAD1(v) \ + (((v) << 4) & BM_ECC8_STATUS1_STATUS_PAYLOAD1) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD1__ALL_ONES 0xF +#define BP_ECC8_STATUS1_STATUS_PAYLOAD0 0 +#define BM_ECC8_STATUS1_STATUS_PAYLOAD0 0x0000000F +#define BF_ECC8_STATUS1_STATUS_PAYLOAD0(v) \ + (((v) << 0) & BM_ECC8_STATUS1_STATUS_PAYLOAD0) +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__NO_ERRORS 0x0 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__ONE_CORRECTABLE 0x1 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__TWO_CORRECTABLE 0x2 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__THREE_CORRECTABLE 0x3 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__FOUR_CORRECTABLE 0x4 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__FIVE_CORRECTABLE 0x5 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__SIX_CORRECTABLE 0x6 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__SEVEN_CORRECTABLE 0x7 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__EIGHT_CORRECTABLE 0x8 +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__NOT_CHECKED 0xC +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__UNCORRECTABLE 0xE +#define BV_ECC8_STATUS1_STATUS_PAYLOAD0__ALL_ONES 0xF +HW_REGISTER(HW_ECC8_DEBUG0, REGS_ECC8_BASE, 0x00000030) +#define HW_ECC8_DEBUG0_ADDR (REGS_ECC8_BASE + 0x00000030) +#define BP_ECC8_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 16 +#define BM_ECC8_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL 0x01FF0000 +#define BF_ECC8_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL(v) \ + (((v) << 16) & BM_ECC8_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL) +#define BV_ECC8_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__NORMAL 0x0 +#define BV_ECC8_DEBUG0_KES_DEBUG_SYNDROME_SYMBOL__TEST_MODE 0x1 +#define BM_ECC8_DEBUG0_KES_DEBUG_SHIFT_SYND 0x00008000 +#define BM_ECC8_DEBUG0_KES_DEBUG_PAYLOAD_FLAG 0x00004000 +#define BV_ECC8_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__DATA 0x1 +#define BV_ECC8_DEBUG0_KES_DEBUG_PAYLOAD_FLAG__AUX 0x1 +#define BM_ECC8_DEBUG0_KES_DEBUG_MODE4K 0x00002000 +#define BV_ECC8_DEBUG0_KES_DEBUG_MODE4K__4k 0x1 +#define BV_ECC8_DEBUG0_KES_DEBUG_MODE4K__2k 0x1 +#define BM_ECC8_DEBUG0_KES_DEBUG_KICK 0x00001000 +#define BM_ECC8_DEBUG0_KES_STANDALONE 0x00000800 +#define BV_ECC8_DEBUG0_KES_STANDALONE__NORMAL 0x0 +#define BV_ECC8_DEBUG0_KES_STANDALONE__TEST_MODE 0x1 +#define BM_ECC8_DEBUG0_KES_DEBUG_STEP 0x00000400 +#define BM_ECC8_DEBUG0_KES_DEBUG_STALL 0x00000200 +#define BV_ECC8_DEBUG0_KES_DEBUG_STALL__NORMAL 0x0 +#define BV_ECC8_DEBUG0_KES_DEBUG_STALL__WAIT 0x1 +#define BM_ECC8_DEBUG0_BM_KES_TEST_BYPASS 0x00000100 +#define BV_ECC8_DEBUG0_BM_KES_TEST_BYPASS__NORMAL 0x0 +#define BV_ECC8_DEBUG0_BM_KES_TEST_BYPASS__TEST_MODE 0x1 +#define BP_ECC8_DEBUG0_DEBUG_REG_SELECT 0 +#define BM_ECC8_DEBUG0_DEBUG_REG_SELECT 0x0000003F +#define BF_ECC8_DEBUG0_DEBUG_REG_SELECT(v) \ + (((v) << 0) & BM_ECC8_DEBUG0_DEBUG_REG_SELECT) +HW_REGISTER_0(HW_ECC8_DBGKESREAD, REGS_ECC8_BASE, 0x00000040) +#define HW_ECC8_DBGKESREAD_ADDR (REGS_ECC8_BASE + 0x00000040) +#define BP_ECC8_DBGKESREAD_VALUES 0 +#define BM_ECC8_DBGKESREAD_VALUES 0xFFFFFFFF +#define BF_ECC8_DBGKESREAD_VALUES(v) (v) +HW_REGISTER_0(HW_ECC8_DBGCSFEREAD, REGS_ECC8_BASE, 0x00000050) +#define HW_ECC8_DBGCSFEREAD_ADDR (REGS_ECC8_BASE + 0x00000050) +#define BP_ECC8_DBGCSFEREAD_VALUES 0 +#define BM_ECC8_DBGCSFEREAD_VALUES 0xFFFFFFFF +#define BF_ECC8_DBGCSFEREAD_VALUES(v) (v) +HW_REGISTER_0(HW_ECC8_DBGSYNDGENREAD, REGS_ECC8_BASE, 0x00000060) +#define HW_ECC8_DBGSYNDGENREAD_ADDR (REGS_ECC8_BASE + 0x00000060) +#define BP_ECC8_DBGSYNDGENREAD_VALUES 0 +#define BM_ECC8_DBGSYNDGENREAD_VALUES 0xFFFFFFFF +#define BF_ECC8_DBGSYNDGENREAD_VALUES(v) (v) +HW_REGISTER_0(HW_ECC8_DBGAHBMREAD, REGS_ECC8_BASE, 0x00000070) +#define HW_ECC8_DBGAHBMREAD_ADDR (REGS_ECC8_BASE + 0x00000070) +#define BP_ECC8_DBGAHBMREAD_VALUES 0 +#define BM_ECC8_DBGAHBMREAD_VALUES 0xFFFFFFFF +#define BF_ECC8_DBGAHBMREAD_VALUES(v) (v) +HW_REGISTER_0(HW_ECC8_BLOCKNAME, REGS_ECC8_BASE, 0x00000080) +#define HW_ECC8_BLOCKNAME_ADDR (REGS_ECC8_BASE + 0x00000080) +#define BP_ECC8_BLOCKNAME_NAME 0 +#define BM_ECC8_BLOCKNAME_NAME 0xFFFFFFFF +#define BF_ECC8_BLOCKNAME_NAME(v) (v) +HW_REGISTER_0(HW_ECC8_VERSION, REGS_ECC8_BASE, 0x000000a0) +#define HW_ECC8_VERSION_ADDR (REGS_ECC8_BASE + 0x000000a0) +#define BP_ECC8_VERSION_MAJOR 24 +#define BM_ECC8_VERSION_MAJOR 0xFF000000 +#define BF_ECC8_VERSION_MAJOR(v) \ + (((v) << 24) & BM_ECC8_VERSION_MAJOR) +#define BP_ECC8_VERSION_MINOR 16 +#define BM_ECC8_VERSION_MINOR 0x00FF0000 +#define BF_ECC8_VERSION_MINOR(v) \ + (((v) << 16) & BM_ECC8_VERSION_MINOR) +#define BP_ECC8_VERSION_STEP 0 +#define BM_ECC8_VERSION_STEP 0x0000FFFF +#define BF_ECC8_VERSION_STEP(v) \ + (((v) << 0) & BM_ECC8_VERSION_STEP) +#endif /* __ARCH_ARM___ECC8_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-emi.h b/arch/arm/mach-stmp3xxx/include/mach/regs-emi.h new file mode 100644 index 000000000000..79893ccc67b9 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-emi.h @@ -0,0 +1,175 @@ +/* + * STMP EMI Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___EMI_H +#define __ARCH_ARM___EMI_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_EMI_BASE (REGS_BASE + 0x20000) +#define REGS_EMI_BASE_PHYS (0x80020000) +#define REGS_EMI_SIZE 0x00002000 +HW_REGISTER(HW_EMI_CTRL, REGS_EMI_BASE, 0x00000000) +#define HW_EMI_CTRL_ADDR (REGS_EMI_BASE + 0x00000000) +#define BM_EMI_CTRL_SFTRST 0x80000000 +#define BM_EMI_CTRL_CLKGATE 0x40000000 +#define BM_EMI_CTRL_TRAP_SR 0x20000000 +#define BM_EMI_CTRL_TRAP_INIT 0x10000000 +#define BP_EMI_CTRL_AXI_DEPTH 26 +#define BM_EMI_CTRL_AXI_DEPTH 0x0C000000 +#define BF_EMI_CTRL_AXI_DEPTH(v) \ + (((v) << 26) & BM_EMI_CTRL_AXI_DEPTH) +#define BV_EMI_CTRL_AXI_DEPTH__ONE 0x0 +#define BV_EMI_CTRL_AXI_DEPTH__TWO 0x1 +#define BV_EMI_CTRL_AXI_DEPTH__THREE 0x2 +#define BV_EMI_CTRL_AXI_DEPTH__FOUR 0x3 +#define BM_EMI_CTRL_DLL_SHIFT_RESET 0x02000000 +#define BM_EMI_CTRL_DLL_RESET 0x01000000 +#define BP_EMI_CTRL_ARB_MODE 22 +#define BM_EMI_CTRL_ARB_MODE 0x00C00000 +#define BF_EMI_CTRL_ARB_MODE(v) \ + (((v) << 22) & BM_EMI_CTRL_ARB_MODE) +#define BV_EMI_CTRL_ARB_MODE__TIMESTAMP 0x0 +#define BV_EMI_CTRL_ARB_MODE__WRITE_HYBRID 0x1 +#define BV_EMI_CTRL_ARB_MODE__PORT_PRIORITY 0x2 +#define BP_EMI_CTRL_PORT_PRIORITY_ORDER 16 +#define BM_EMI_CTRL_PORT_PRIORITY_ORDER 0x001F0000 +#define BF_EMI_CTRL_PORT_PRIORITY_ORDER(v) \ + (((v) << 16) & BM_EMI_CTRL_PORT_PRIORITY_ORDER) +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT0123 0x00 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT0312 0x01 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT0231 0x02 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT0321 0x03 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT0213 0x04 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT0132 0x05 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT1023 0x06 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT1302 0x07 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT1230 0x08 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT1320 0x09 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT1203 0x0A +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT1032 0x0B +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT2013 0x0C +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT2301 0x0D +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT2130 0x0E +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT2310 0x0F +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT2103 0x10 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT2031 0x11 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT3012 0x12 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT3201 0x13 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT3120 0x14 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT3210 0x15 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT3102 0x16 +#define BV_EMI_CTRL_PORT_PRIORITY_ORDER__PORT3021 0x17 +#define BP_EMI_CTRL_PRIORITY_WRITE_ITER 12 +#define BM_EMI_CTRL_PRIORITY_WRITE_ITER 0x00007000 +#define BF_EMI_CTRL_PRIORITY_WRITE_ITER(v) \ + (((v) << 12) & BM_EMI_CTRL_PRIORITY_WRITE_ITER) +#define BP_EMI_CTRL_HIGH_PRIORITY_WRITE 8 +#define BM_EMI_CTRL_HIGH_PRIORITY_WRITE 0x00000700 +#define BF_EMI_CTRL_HIGH_PRIORITY_WRITE(v) \ + (((v) << 8) & BM_EMI_CTRL_HIGH_PRIORITY_WRITE) +#define BM_EMI_CTRL_MEM_WIDTH 0x00000040 +#define BM_EMI_CTRL_WRITE_PROTECT 0x00000020 +#define BM_EMI_CTRL_RESET_OUT 0x00000010 +#define BP_EMI_CTRL_CE_SELECT 0 +#define BM_EMI_CTRL_CE_SELECT 0x0000000F +#define BF_EMI_CTRL_CE_SELECT(v) \ + (((v) << 0) & BM_EMI_CTRL_CE_SELECT) +#define BV_EMI_CTRL_CE_SELECT__NONE 0x0 +#define BV_EMI_CTRL_CE_SELECT__CE0 0x1 +#define BV_EMI_CTRL_CE_SELECT__CE1 0x2 +#define BV_EMI_CTRL_CE_SELECT__CE2 0x4 +#define BV_EMI_CTRL_CE_SELECT__CE3 0x8 +HW_REGISTER_0(HW_EMI_STAT, REGS_EMI_BASE, 0x00000010) +#define HW_EMI_STAT_ADDR (REGS_EMI_BASE + 0x00000010) +#define BM_EMI_STAT_DRAM_PRESENT 0x80000000 +#define BM_EMI_STAT_NOR_PRESENT 0x40000000 +#define BM_EMI_STAT_LARGE_DRAM_ENABLED 0x20000000 +#define BM_EMI_STAT_DRAM_HALTED 0x00000002 +#define BV_EMI_STAT_DRAM_HALTED__NOT_HALTED 0x0 +#define BV_EMI_STAT_DRAM_HALTED__HALTED 0x1 +#define BM_EMI_STAT_NOR_BUSY 0x00000001 +#define BV_EMI_STAT_NOR_BUSY__NOT_BUSY 0x0 +#define BV_EMI_STAT_NOR_BUSY__BUSY 0x1 +HW_REGISTER(HW_EMI_TIME, REGS_EMI_BASE, 0x00000020) +#define HW_EMI_TIME_ADDR (REGS_EMI_BASE + 0x00000020) +#define BP_EMI_TIME_THZ 24 +#define BM_EMI_TIME_THZ 0x0F000000 +#define BF_EMI_TIME_THZ(v) \ + (((v) << 24) & BM_EMI_TIME_THZ) +#define BP_EMI_TIME_TDH 16 +#define BM_EMI_TIME_TDH 0x000F0000 +#define BF_EMI_TIME_TDH(v) \ + (((v) << 16) & BM_EMI_TIME_TDH) +#define BP_EMI_TIME_TDS 8 +#define BM_EMI_TIME_TDS 0x00001F00 +#define BF_EMI_TIME_TDS(v) \ + (((v) << 8) & BM_EMI_TIME_TDS) +#define BP_EMI_TIME_TAS 0 +#define BM_EMI_TIME_TAS 0x0000000F +#define BF_EMI_TIME_TAS(v) \ + (((v) << 0) & BM_EMI_TIME_TAS) +HW_REGISTER(HW_EMI_DDR_TEST_MODE_CSR, REGS_EMI_BASE, 0x00000030) +#define HW_EMI_DDR_TEST_MODE_CSR_ADDR (REGS_EMI_BASE + 0x00000030) +#define BM_EMI_DDR_TEST_MODE_CSR_DONE 0x00000002 +#define BM_EMI_DDR_TEST_MODE_CSR_START 0x00000001 +HW_REGISTER_0(HW_EMI_DEBUG, REGS_EMI_BASE, 0x00000080) +#define HW_EMI_DEBUG_ADDR (REGS_EMI_BASE + 0x00000080) +#define BP_EMI_DEBUG_NOR_STATE 0 +#define BM_EMI_DEBUG_NOR_STATE 0x0000000F +#define BF_EMI_DEBUG_NOR_STATE(v) \ + (((v) << 0) & BM_EMI_DEBUG_NOR_STATE) +HW_REGISTER_0(HW_EMI_DDR_TEST_MODE_STATUS0, REGS_EMI_BASE, 0x00000090) +#define HW_EMI_DDR_TEST_MODE_STATUS0_ADDR (REGS_EMI_BASE + 0x00000090) +#define BP_EMI_DDR_TEST_MODE_STATUS0_ADDR0 0 +#define BM_EMI_DDR_TEST_MODE_STATUS0_ADDR0 0x00001FFF +#define BF_EMI_DDR_TEST_MODE_STATUS0_ADDR0(v) \ + (((v) << 0) & BM_EMI_DDR_TEST_MODE_STATUS0_ADDR0) +HW_REGISTER_0(HW_EMI_DDR_TEST_MODE_STATUS1, REGS_EMI_BASE, 0x000000a0) +#define HW_EMI_DDR_TEST_MODE_STATUS1_ADDR (REGS_EMI_BASE + 0x000000a0) +#define BP_EMI_DDR_TEST_MODE_STATUS1_ADDR1 0 +#define BM_EMI_DDR_TEST_MODE_STATUS1_ADDR1 0x00001FFF +#define BF_EMI_DDR_TEST_MODE_STATUS1_ADDR1(v) \ + (((v) << 0) & BM_EMI_DDR_TEST_MODE_STATUS1_ADDR1) +HW_REGISTER_0(HW_EMI_DDR_TEST_MODE_STATUS2, REGS_EMI_BASE, 0x000000b0) +#define HW_EMI_DDR_TEST_MODE_STATUS2_ADDR (REGS_EMI_BASE + 0x000000b0) +#define BP_EMI_DDR_TEST_MODE_STATUS2_DATA0 0 +#define BM_EMI_DDR_TEST_MODE_STATUS2_DATA0 0xFFFFFFFF +#define BF_EMI_DDR_TEST_MODE_STATUS2_DATA0(v) (v) +HW_REGISTER_0(HW_EMI_DDR_TEST_MODE_STATUS3, REGS_EMI_BASE, 0x000000c0) +#define HW_EMI_DDR_TEST_MODE_STATUS3_ADDR (REGS_EMI_BASE + 0x000000c0) +#define BP_EMI_DDR_TEST_MODE_STATUS3_DATA1 0 +#define BM_EMI_DDR_TEST_MODE_STATUS3_DATA1 0xFFFFFFFF +#define BF_EMI_DDR_TEST_MODE_STATUS3_DATA1(v) (v) +HW_REGISTER_0(HW_EMI_VERSION, REGS_EMI_BASE, 0x000000f0) +#define HW_EMI_VERSION_ADDR (REGS_EMI_BASE + 0x000000f0) +#define BP_EMI_VERSION_MAJOR 24 +#define BM_EMI_VERSION_MAJOR 0xFF000000 +#define BF_EMI_VERSION_MAJOR(v) \ + (((v) << 24) & BM_EMI_VERSION_MAJOR) +#define BP_EMI_VERSION_MINOR 16 +#define BM_EMI_VERSION_MINOR 0x00FF0000 +#define BF_EMI_VERSION_MINOR(v) \ + (((v) << 16) & BM_EMI_VERSION_MINOR) +#define BP_EMI_VERSION_STEP 0 +#define BM_EMI_VERSION_STEP 0x0000FFFF +#define BF_EMI_VERSION_STEP(v) \ + (((v) << 0) & BM_EMI_VERSION_STEP) +#endif /* __ARCH_ARM___EMI_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-gpmi.h b/arch/arm/mach-stmp3xxx/include/mach/regs-gpmi.h new file mode 100644 index 000000000000..ea4f8904a034 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-gpmi.h @@ -0,0 +1,329 @@ +/* + * STMP GPMI Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___GPMI_H +#define __ARCH_ARM___GPMI_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_GPMI_BASE (REGS_BASE + 0xc000) +#define REGS_GPMI_BASE_PHYS (0x8000C000) +#define REGS_GPMI_SIZE 0x00002000 +HW_REGISTER(HW_GPMI_CTRL0, REGS_GPMI_BASE, 0x00000000) +#define HW_GPMI_CTRL0_ADDR (REGS_GPMI_BASE + 0x00000000) +#define BM_GPMI_CTRL0_SFTRST 0x80000000 +#define BV_GPMI_CTRL0_SFTRST__RUN 0x0 +#define BV_GPMI_CTRL0_SFTRST__RESET 0x1 +#define BM_GPMI_CTRL0_CLKGATE 0x40000000 +#define BV_GPMI_CTRL0_CLKGATE__RUN 0x0 +#define BV_GPMI_CTRL0_CLKGATE__NO_CLKS 0x1 +#define BM_GPMI_CTRL0_RUN 0x20000000 +#define BV_GPMI_CTRL0_RUN__IDLE 0x0 +#define BV_GPMI_CTRL0_RUN__BUSY 0x1 +#define BM_GPMI_CTRL0_DEV_IRQ_EN 0x10000000 +#define BM_GPMI_CTRL0_TIMEOUT_IRQ_EN 0x08000000 +#define BM_GPMI_CTRL0_UDMA 0x04000000 +#define BV_GPMI_CTRL0_UDMA__DISABLED 0x0 +#define BV_GPMI_CTRL0_UDMA__ENABLED 0x1 +#define BP_GPMI_CTRL0_COMMAND_MODE 24 +#define BM_GPMI_CTRL0_COMMAND_MODE 0x03000000 +#define BF_GPMI_CTRL0_COMMAND_MODE(v) \ + (((v) << 24) & BM_GPMI_CTRL0_COMMAND_MODE) +#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2 +#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3 +#define BM_GPMI_CTRL0_WORD_LENGTH 0x00800000 +#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0 +#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1 +#define BM_GPMI_CTRL0_LOCK_CS 0x00400000 +#define BV_GPMI_CTRL0_LOCK_CS__DISABLED 0x0 +#define BV_GPMI_CTRL0_LOCK_CS__ENABLED 0x1 +#define BP_GPMI_CTRL0_CS 20 +#define BM_GPMI_CTRL0_CS 0x00300000 +#define BF_GPMI_CTRL0_CS(v) \ + (((v) << 20) & BM_GPMI_CTRL0_CS) +#define BP_GPMI_CTRL0_ADDRESS 17 +#define BM_GPMI_CTRL0_ADDRESS 0x000E0000 +#define BF_GPMI_CTRL0_ADDRESS(v) \ + (((v) << 17) & BM_GPMI_CTRL0_ADDRESS) +#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0 +#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1 +#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2 +#define BM_GPMI_CTRL0_ADDRESS_INCREMENT 0x00010000 +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0 +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1 +#define BP_GPMI_CTRL0_XFER_COUNT 0 +#define BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF +#define BF_GPMI_CTRL0_XFER_COUNT(v) \ + (((v) << 0) & BM_GPMI_CTRL0_XFER_COUNT) +HW_REGISTER_0(HW_GPMI_COMPARE, REGS_GPMI_BASE, 0x00000010) +#define HW_GPMI_COMPARE_ADDR (REGS_GPMI_BASE + 0x00000010) +#define BP_GPMI_COMPARE_MASK 16 +#define BM_GPMI_COMPARE_MASK 0xFFFF0000 +#define BF_GPMI_COMPARE_MASK(v) \ + (((v) << 16) & BM_GPMI_COMPARE_MASK) +#define BP_GPMI_COMPARE_REFERENCE 0 +#define BM_GPMI_COMPARE_REFERENCE 0x0000FFFF +#define BF_GPMI_COMPARE_REFERENCE(v) \ + (((v) << 0) & BM_GPMI_COMPARE_REFERENCE) +HW_REGISTER(HW_GPMI_ECCCTRL, REGS_GPMI_BASE, 0x00000020) +#define HW_GPMI_ECCCTRL_ADDR (REGS_GPMI_BASE + 0x00000020) +#define BP_GPMI_ECCCTRL_HANDLE 16 +#define BM_GPMI_ECCCTRL_HANDLE 0xFFFF0000 +#define BF_GPMI_ECCCTRL_HANDLE(v) \ + (((v) << 16) & BM_GPMI_ECCCTRL_HANDLE) +#define BP_GPMI_ECCCTRL_ECC_CMD 13 +#define BM_GPMI_ECCCTRL_ECC_CMD 0x00006000 +#define BF_GPMI_ECCCTRL_ECC_CMD(v) \ + (((v) << 13) & BM_GPMI_ECCCTRL_ECC_CMD) +#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT 0x0 +#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT 0x1 +#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT 0x2 +#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT 0x3 +#define BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000 +#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1 +#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0 +#define BP_GPMI_ECCCTRL_BUFFER_MASK 0 +#define BM_GPMI_ECCCTRL_BUFFER_MASK 0x000001FF +#define BF_GPMI_ECCCTRL_BUFFER_MASK(v) \ + (((v) << 0) & BM_GPMI_ECCCTRL_BUFFER_MASK) +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF +#define BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY 0x100 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER7 0x080 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER6 0x040 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER5 0x020 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER4 0x010 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER3 0x008 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER2 0x004 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER1 0x002 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BUFFER0 0x001 +HW_REGISTER_0(HW_GPMI_ECCCOUNT, REGS_GPMI_BASE, 0x00000030) +#define HW_GPMI_ECCCOUNT_ADDR (REGS_GPMI_BASE + 0x00000030) +#define BP_GPMI_ECCCOUNT_COUNT 0 +#define BM_GPMI_ECCCOUNT_COUNT 0x0000FFFF +#define BF_GPMI_ECCCOUNT_COUNT(v) \ + (((v) << 0) & BM_GPMI_ECCCOUNT_COUNT) +HW_REGISTER_0(HW_GPMI_PAYLOAD, REGS_GPMI_BASE, 0x00000040) +#define HW_GPMI_PAYLOAD_ADDR (REGS_GPMI_BASE + 0x00000040) +#define BP_GPMI_PAYLOAD_ADDRESS 2 +#define BM_GPMI_PAYLOAD_ADDRESS 0xFFFFFFFC +#define BF_GPMI_PAYLOAD_ADDRESS(v) \ + (((v) << 2) & BM_GPMI_PAYLOAD_ADDRESS) +HW_REGISTER_0(HW_GPMI_AUXILIARY, REGS_GPMI_BASE, 0x00000050) +#define HW_GPMI_AUXILIARY_ADDR (REGS_GPMI_BASE + 0x00000050) +#define BP_GPMI_AUXILIARY_ADDRESS 2 +#define BM_GPMI_AUXILIARY_ADDRESS 0xFFFFFFFC +#define BF_GPMI_AUXILIARY_ADDRESS(v) \ + (((v) << 2) & BM_GPMI_AUXILIARY_ADDRESS) +HW_REGISTER(HW_GPMI_CTRL1, REGS_GPMI_BASE, 0x00000060) +#define HW_GPMI_CTRL1_ADDR (REGS_GPMI_BASE + 0x00000060) +#define BM_GPMI_CTRL1_CE3_SEL 0x00800000 +#define BM_GPMI_CTRL1_CE2_SEL 0x00400000 +#define BM_GPMI_CTRL1_CE1_SEL 0x00200000 +#define BM_GPMI_CTRL1_CE0_SEL 0x00100000 +#define BM_GPMI_CTRL1_GANGED_RDYBUSY 0x00080000 +#define BM_GPMI_CTRL1_BCH_MODE 0x00040000 +#define BM_GPMI_CTRL1_DLL_ENABLE 0x00020000 +#define BM_GPMI_CTRL1_HALF_PERIOD 0x00010000 +#define BP_GPMI_CTRL1_RDN_DELAY 12 +#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000 +#define BF_GPMI_CTRL1_RDN_DELAY(v) \ + (((v) << 12) & BM_GPMI_CTRL1_RDN_DELAY) +#define BM_GPMI_CTRL1_DMA2ECC_MODE 0x00000800 +#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400 +#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200 +#define BM_GPMI_CTRL1_BURST_EN 0x00000100 +#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY3 0x00000080 +#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY2 0x00000040 +#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY1 0x00000020 +#define BM_GPMI_CTRL1_ABORT_WAIT_FOR_READY0 0x00000010 +#define BM_GPMI_CTRL1_DEV_RESET 0x00000008 +#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0 +#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1 +#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004 +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0 +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1 +#define BM_GPMI_CTRL1_CAMERA_MODE 0x00000002 +#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001 +#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0 +#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1 +HW_REGISTER_0(HW_GPMI_TIMING0, REGS_GPMI_BASE, 0x00000070) +#define HW_GPMI_TIMING0_ADDR (REGS_GPMI_BASE + 0x00000070) +#define BP_GPMI_TIMING0_ADDRESS_SETUP 16 +#define BM_GPMI_TIMING0_ADDRESS_SETUP 0x00FF0000 +#define BF_GPMI_TIMING0_ADDRESS_SETUP(v) \ + (((v) << 16) & BM_GPMI_TIMING0_ADDRESS_SETUP) +#define BP_GPMI_TIMING0_DATA_HOLD 8 +#define BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00 +#define BF_GPMI_TIMING0_DATA_HOLD(v) \ + (((v) << 8) & BM_GPMI_TIMING0_DATA_HOLD) +#define BP_GPMI_TIMING0_DATA_SETUP 0 +#define BM_GPMI_TIMING0_DATA_SETUP 0x000000FF +#define BF_GPMI_TIMING0_DATA_SETUP(v) \ + (((v) << 0) & BM_GPMI_TIMING0_DATA_SETUP) +HW_REGISTER_0(HW_GPMI_TIMING1, REGS_GPMI_BASE, 0x00000080) +#define HW_GPMI_TIMING1_ADDR (REGS_GPMI_BASE + 0x00000080) +#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16 +#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000 +#define BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(v) \ + (((v) << 16) & BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT) +HW_REGISTER_0(HW_GPMI_TIMING2, REGS_GPMI_BASE, 0x00000090) +#define HW_GPMI_TIMING2_ADDR (REGS_GPMI_BASE + 0x00000090) +#define BP_GPMI_TIMING2_UDMA_TRP 24 +#define BM_GPMI_TIMING2_UDMA_TRP 0xFF000000 +#define BF_GPMI_TIMING2_UDMA_TRP(v) \ + (((v) << 24) & BM_GPMI_TIMING2_UDMA_TRP) +#define BP_GPMI_TIMING2_UDMA_ENV 16 +#define BM_GPMI_TIMING2_UDMA_ENV 0x00FF0000 +#define BF_GPMI_TIMING2_UDMA_ENV(v) \ + (((v) << 16) & BM_GPMI_TIMING2_UDMA_ENV) +#define BP_GPMI_TIMING2_UDMA_HOLD 8 +#define BM_GPMI_TIMING2_UDMA_HOLD 0x0000FF00 +#define BF_GPMI_TIMING2_UDMA_HOLD(v) \ + (((v) << 8) & BM_GPMI_TIMING2_UDMA_HOLD) +#define BP_GPMI_TIMING2_UDMA_SETUP 0 +#define BM_GPMI_TIMING2_UDMA_SETUP 0x000000FF +#define BF_GPMI_TIMING2_UDMA_SETUP(v) \ + (((v) << 0) & BM_GPMI_TIMING2_UDMA_SETUP) +HW_REGISTER_0(HW_GPMI_DATA, REGS_GPMI_BASE, 0x000000a0) +#define HW_GPMI_DATA_ADDR (REGS_GPMI_BASE + 0x000000a0) +#define BP_GPMI_DATA_DATA 0 +#define BM_GPMI_DATA_DATA 0xFFFFFFFF +#define BF_GPMI_DATA_DATA(v) (v) +HW_REGISTER_0(HW_GPMI_STAT, REGS_GPMI_BASE, 0x000000b0) +#define HW_GPMI_STAT_ADDR (REGS_GPMI_BASE + 0x000000b0) +#define BM_GPMI_STAT_PRESENT 0x80000000 +#define BV_GPMI_STAT_PRESENT__UNAVAILABLE 0x0 +#define BV_GPMI_STAT_PRESENT__AVAILABLE 0x1 +#define BP_GPMI_STAT_RDY_TIMEOUT 8 +#define BM_GPMI_STAT_RDY_TIMEOUT 0x00000F00 +#define BF_GPMI_STAT_RDY_TIMEOUT(v) \ + (((v) << 8) & BM_GPMI_STAT_RDY_TIMEOUT) +#define BM_GPMI_STAT_ATA_IRQ 0x00000080 +#define BM_GPMI_STAT_INVALID_BUFFER_MASK 0x00000040 +#define BM_GPMI_STAT_FIFO_EMPTY 0x00000020 +#define BV_GPMI_STAT_FIFO_EMPTY__NOT_EMPTY 0x0 +#define BV_GPMI_STAT_FIFO_EMPTY__EMPTY 0x1 +#define BM_GPMI_STAT_FIFO_FULL 0x00000010 +#define BV_GPMI_STAT_FIFO_FULL__NOT_FULL 0x0 +#define BV_GPMI_STAT_FIFO_FULL__FULL 0x1 +#define BM_GPMI_STAT_DEV3_ERROR 0x00000008 +#define BM_GPMI_STAT_DEV2_ERROR 0x00000004 +#define BM_GPMI_STAT_DEV1_ERROR 0x00000002 +#define BM_GPMI_STAT_DEV0_ERROR 0x00000001 +HW_REGISTER_0(HW_GPMI_DEBUG, REGS_GPMI_BASE, 0x000000c0) +#define HW_GPMI_DEBUG_ADDR (REGS_GPMI_BASE + 0x000000c0) +#define BM_GPMI_DEBUG_READY3 0x80000000 +#define BM_GPMI_DEBUG_READY2 0x40000000 +#define BM_GPMI_DEBUG_READY1 0x20000000 +#define BM_GPMI_DEBUG_READY0 0x10000000 +#define BM_GPMI_DEBUG_WAIT_FOR_READY_END3 0x08000000 +#define BM_GPMI_DEBUG_WAIT_FOR_READY_END2 0x04000000 +#define BM_GPMI_DEBUG_WAIT_FOR_READY_END1 0x02000000 +#define BM_GPMI_DEBUG_WAIT_FOR_READY_END0 0x01000000 +#define BM_GPMI_DEBUG_SENSE3 0x00800000 +#define BM_GPMI_DEBUG_SENSE2 0x00400000 +#define BM_GPMI_DEBUG_SENSE1 0x00200000 +#define BM_GPMI_DEBUG_SENSE0 0x00100000 +#define BM_GPMI_DEBUG_DMAREQ3 0x00080000 +#define BM_GPMI_DEBUG_DMAREQ2 0x00040000 +#define BM_GPMI_DEBUG_DMAREQ1 0x00020000 +#define BM_GPMI_DEBUG_DMAREQ0 0x00010000 +#define BP_GPMI_DEBUG_CMD_END 12 +#define BM_GPMI_DEBUG_CMD_END 0x0000F000 +#define BF_GPMI_DEBUG_CMD_END(v) \ + (((v) << 12) & BM_GPMI_DEBUG_CMD_END) +#define BP_GPMI_DEBUG_UDMA_STATE 8 +#define BM_GPMI_DEBUG_UDMA_STATE 0x00000F00 +#define BF_GPMI_DEBUG_UDMA_STATE(v) \ + (((v) << 8) & BM_GPMI_DEBUG_UDMA_STATE) +#define BM_GPMI_DEBUG_BUSY 0x00000080 +#define BV_GPMI_DEBUG_BUSY__DISABLED 0x0 +#define BV_GPMI_DEBUG_BUSY__ENABLED 0x1 +#define BP_GPMI_DEBUG_PIN_STATE 4 +#define BM_GPMI_DEBUG_PIN_STATE 0x00000070 +#define BF_GPMI_DEBUG_PIN_STATE(v) \ + (((v) << 4) & BM_GPMI_DEBUG_PIN_STATE) +#define BV_GPMI_DEBUG_PIN_STATE__PSM_IDLE 0x0 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_BYTCNT 0x1 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_ADDR 0x2 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_STALL 0x3 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_STROBE 0x4 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_ATARDY 0x5 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_DHOLD 0x6 +#define BV_GPMI_DEBUG_PIN_STATE__PSM_DONE 0x7 +#define BP_GPMI_DEBUG_MAIN_STATE 0 +#define BM_GPMI_DEBUG_MAIN_STATE 0x0000000F +#define BF_GPMI_DEBUG_MAIN_STATE(v) \ + (((v) << 0) & BM_GPMI_DEBUG_MAIN_STATE) +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_IDLE 0x0 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_BYTCNT 0x1 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFE 0x2 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFR 0x3 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAREQ 0x4 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DMAACK 0x5 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_WAITFF 0x6 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_LDFIFO 0x7 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_LDDMAR 0x8 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_RDCMP 0x9 +#define BV_GPMI_DEBUG_MAIN_STATE__MSM_DONE 0xA +HW_REGISTER_0(HW_GPMI_VERSION, REGS_GPMI_BASE, 0x000000d0) +#define HW_GPMI_VERSION_ADDR (REGS_GPMI_BASE + 0x000000d0) +#define BP_GPMI_VERSION_MAJOR 24 +#define BM_GPMI_VERSION_MAJOR 0xFF000000 +#define BF_GPMI_VERSION_MAJOR(v) \ + (((v) << 24) & BM_GPMI_VERSION_MAJOR) +#define BP_GPMI_VERSION_MINOR 16 +#define BM_GPMI_VERSION_MINOR 0x00FF0000 +#define BF_GPMI_VERSION_MINOR(v) \ + (((v) << 16) & BM_GPMI_VERSION_MINOR) +#define BP_GPMI_VERSION_STEP 0 +#define BM_GPMI_VERSION_STEP 0x0000FFFF +#define BF_GPMI_VERSION_STEP(v) \ + (((v) << 0) & BM_GPMI_VERSION_STEP) +HW_REGISTER_0(HW_GPMI_DEBUG2, REGS_GPMI_BASE, 0x000000e0) +#define HW_GPMI_DEBUG2_ADDR (REGS_GPMI_BASE + 0x000000e0) +#define BP_GPMI_DEBUG2_SYND2GPMI_BE 12 +#define BM_GPMI_DEBUG2_SYND2GPMI_BE 0x0000F000 +#define BF_GPMI_DEBUG2_SYND2GPMI_BE(v) \ + (((v) << 12) & BM_GPMI_DEBUG2_SYND2GPMI_BE) +#define BM_GPMI_DEBUG2_GPMI2SYND_VALID 0x00000800 +#define BM_GPMI_DEBUG2_GPMI2SYND_READY 0x00000400 +#define BM_GPMI_DEBUG2_SYND2GPMI_VALID 0x00000200 +#define BM_GPMI_DEBUG2_SYND2GPMI_READY 0x00000100 +#define BM_GPMI_DEBUG2_VIEW_DELAYED_RDN 0x00000080 +#define BM_GPMI_DEBUG2_UPDATE_WINDOW 0x00000040 +#define BP_GPMI_DEBUG2_RDN_TAP 0 +#define BM_GPMI_DEBUG2_RDN_TAP 0x0000003F +#define BF_GPMI_DEBUG2_RDN_TAP(v) \ + (((v) << 0) & BM_GPMI_DEBUG2_RDN_TAP) +HW_REGISTER_0(HW_GPMI_DEBUG3, REGS_GPMI_BASE, 0x000000f0) +#define HW_GPMI_DEBUG3_ADDR (REGS_GPMI_BASE + 0x000000f0) +#define BP_GPMI_DEBUG3_APB_WORD_CNTR 16 +#define BM_GPMI_DEBUG3_APB_WORD_CNTR 0xFFFF0000 +#define BF_GPMI_DEBUG3_APB_WORD_CNTR(v) \ + (((v) << 16) & BM_GPMI_DEBUG3_APB_WORD_CNTR) +#define BP_GPMI_DEBUG3_DEV_WORD_CNTR 0 +#define BM_GPMI_DEBUG3_DEV_WORD_CNTR 0x0000FFFF +#define BF_GPMI_DEBUG3_DEV_WORD_CNTR(v) \ + (((v) << 0) & BM_GPMI_DEBUG3_DEV_WORD_CNTR) +#endif /* __ARCH_ARM___GPMI_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-i2c.h b/arch/arm/mach-stmp3xxx/include/mach/regs-i2c.h new file mode 100644 index 000000000000..262faa25d4ea --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-i2c.h @@ -0,0 +1,306 @@ +/* + * STMP I2C Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___I2C_H +#define __ARCH_ARM___I2C_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_I2C_BASE (REGS_BASE + 0x58000) +#define REGS_I2C_BASE_PHYS (0x80058000) +#define REGS_I2C_SIZE 0x00002000 +HW_REGISTER(HW_I2C_CTRL0, REGS_I2C_BASE, 0x00000000) +#define HW_I2C_CTRL0_ADDR (REGS_I2C_BASE + 0x00000000) +#define BM_I2C_CTRL0_SFTRST 0x80000000 +#define BV_I2C_CTRL0_SFTRST__RUN 0x0 +#define BV_I2C_CTRL0_SFTRST__RESET 0x1 +#define BM_I2C_CTRL0_CLKGATE 0x40000000 +#define BV_I2C_CTRL0_CLKGATE__RUN 0x0 +#define BV_I2C_CTRL0_CLKGATE__NO_CLKS 0x1 +#define BM_I2C_CTRL0_RUN 0x20000000 +#define BV_I2C_CTRL0_RUN__HALT 0x0 +#define BV_I2C_CTRL0_RUN__RUN 0x1 +#define BM_I2C_CTRL0_PRE_ACK 0x08000000 +#define BM_I2C_CTRL0_ACKNOWLEDGE 0x04000000 +#define BV_I2C_CTRL0_ACKNOWLEDGE__SNAK 0x0 +#define BV_I2C_CTRL0_ACKNOWLEDGE__ACK 0x1 +#define BM_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000 +#define BV_I2C_CTRL0_SEND_NAK_ON_LAST__ACK_IT 0x0 +#define BV_I2C_CTRL0_SEND_NAK_ON_LAST__NAK_IT 0x1 +#define BM_I2C_CTRL0_PIO_MODE 0x01000000 +#define BM_I2C_CTRL0_MULTI_MASTER 0x00800000 +#define BV_I2C_CTRL0_MULTI_MASTER__SINGLE 0x0 +#define BV_I2C_CTRL0_MULTI_MASTER__MULTIPLE 0x1 +#define BM_I2C_CTRL0_CLOCK_HELD 0x00400000 +#define BV_I2C_CTRL0_CLOCK_HELD__RELEASE 0x0 +#define BV_I2C_CTRL0_CLOCK_HELD__HELD_LOW 0x1 +#define BM_I2C_CTRL0_RETAIN_CLOCK 0x00200000 +#define BV_I2C_CTRL0_RETAIN_CLOCK__RELEASE 0x0 +#define BV_I2C_CTRL0_RETAIN_CLOCK__HOLD_LOW 0x1 +#define BM_I2C_CTRL0_POST_SEND_STOP 0x00100000 +#define BV_I2C_CTRL0_POST_SEND_STOP__NO_STOP 0x0 +#define BV_I2C_CTRL0_POST_SEND_STOP__SEND_STOP 0x1 +#define BM_I2C_CTRL0_PRE_SEND_START 0x00080000 +#define BV_I2C_CTRL0_PRE_SEND_START__NO_START 0x0 +#define BV_I2C_CTRL0_PRE_SEND_START__SEND_START 0x1 +#define BM_I2C_CTRL0_SLAVE_ADDRESS_ENABLE 0x00040000 +#define BV_I2C_CTRL0_SLAVE_ADDRESS_ENABLE__DISABLED 0x0 +#define BV_I2C_CTRL0_SLAVE_ADDRESS_ENABLE__ENABLED 0x1 +#define BM_I2C_CTRL0_MASTER_MODE 0x00020000 +#define BV_I2C_CTRL0_MASTER_MODE__SLAVE 0x0 +#define BV_I2C_CTRL0_MASTER_MODE__MASTER 0x1 +#define BM_I2C_CTRL0_DIRECTION 0x00010000 +#define BV_I2C_CTRL0_DIRECTION__RECEIVE 0x0 +#define BV_I2C_CTRL0_DIRECTION__TRANSMIT 0x1 +#define BP_I2C_CTRL0_XFER_COUNT 0 +#define BM_I2C_CTRL0_XFER_COUNT 0x0000FFFF +#define BF_I2C_CTRL0_XFER_COUNT(v) \ + (((v) << 0) & BM_I2C_CTRL0_XFER_COUNT) +HW_REGISTER(HW_I2C_TIMING0, REGS_I2C_BASE, 0x00000010) +#define HW_I2C_TIMING0_ADDR (REGS_I2C_BASE + 0x00000010) +#define BP_I2C_TIMING0_HIGH_COUNT 16 +#define BM_I2C_TIMING0_HIGH_COUNT 0x03FF0000 +#define BF_I2C_TIMING0_HIGH_COUNT(v) \ + (((v) << 16) & BM_I2C_TIMING0_HIGH_COUNT) +#define BP_I2C_TIMING0_RCV_COUNT 0 +#define BM_I2C_TIMING0_RCV_COUNT 0x000003FF +#define BF_I2C_TIMING0_RCV_COUNT(v) \ + (((v) << 0) & BM_I2C_TIMING0_RCV_COUNT) +HW_REGISTER(HW_I2C_TIMING1, REGS_I2C_BASE, 0x00000020) +#define HW_I2C_TIMING1_ADDR (REGS_I2C_BASE + 0x00000020) +#define BP_I2C_TIMING1_LOW_COUNT 16 +#define BM_I2C_TIMING1_LOW_COUNT 0x03FF0000 +#define BF_I2C_TIMING1_LOW_COUNT(v) \ + (((v) << 16) & BM_I2C_TIMING1_LOW_COUNT) +#define BP_I2C_TIMING1_XMIT_COUNT 0 +#define BM_I2C_TIMING1_XMIT_COUNT 0x000003FF +#define BF_I2C_TIMING1_XMIT_COUNT(v) \ + (((v) << 0) & BM_I2C_TIMING1_XMIT_COUNT) +HW_REGISTER(HW_I2C_TIMING2, REGS_I2C_BASE, 0x00000030) +#define HW_I2C_TIMING2_ADDR (REGS_I2C_BASE + 0x00000030) +#define BP_I2C_TIMING2_BUS_FREE 16 +#define BM_I2C_TIMING2_BUS_FREE 0x03FF0000 +#define BF_I2C_TIMING2_BUS_FREE(v) \ + (((v) << 16) & BM_I2C_TIMING2_BUS_FREE) +#define BP_I2C_TIMING2_LEADIN_COUNT 0 +#define BM_I2C_TIMING2_LEADIN_COUNT 0x000003FF +#define BF_I2C_TIMING2_LEADIN_COUNT(v) \ + (((v) << 0) & BM_I2C_TIMING2_LEADIN_COUNT) +HW_REGISTER(HW_I2C_CTRL1, REGS_I2C_BASE, 0x00000040) +#define HW_I2C_CTRL1_ADDR (REGS_I2C_BASE + 0x00000040) +#define BM_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000 +#define BV_I2C_CTRL1_CLR_GOT_A_NAK__DO_NOTHING 0x0 +#define BV_I2C_CTRL1_CLR_GOT_A_NAK__CLEAR 0x1 +#define BM_I2C_CTRL1_ACK_MODE 0x08000000 +#define BV_I2C_CTRL1_ACK_MODE__ACK_AFTER_HOLD_LOW 0x0 +#define BV_I2C_CTRL1_ACK_MODE__ACK_BEFORE_HOLD_LOW 0x1 +#define BM_I2C_CTRL1_FORCE_DATA_IDLE 0x04000000 +#define BM_I2C_CTRL1_FORCE_CLK_IDLE 0x02000000 +#define BM_I2C_CTRL1_BCAST_SLAVE_EN 0x01000000 +#define BV_I2C_CTRL1_BCAST_SLAVE_EN__NO_BCAST 0x0 +#define BV_I2C_CTRL1_BCAST_SLAVE_EN__WATCH_BCAST 0x1 +#define BP_I2C_CTRL1_SLAVE_ADDRESS_BYTE 16 +#define BM_I2C_CTRL1_SLAVE_ADDRESS_BYTE 0x00FF0000 +#define BF_I2C_CTRL1_SLAVE_ADDRESS_BYTE(v) \ + (((v) << 16) & BM_I2C_CTRL1_SLAVE_ADDRESS_BYTE) +#define BM_I2C_CTRL1_BUS_FREE_IRQ_EN 0x00008000 +#define BV_I2C_CTRL1_BUS_FREE_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_BUS_FREE_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ_EN 0x00004000 +#define BV_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ_EN 0x00002000 +#define BV_I2C_CTRL1_NO_SLAVE_ACK_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_NO_SLAVE_ACK_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ_EN 0x00001000 +#define BV_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_EARLY_TERM_IRQ_EN 0x00000800 +#define BV_I2C_CTRL1_EARLY_TERM_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_EARLY_TERM_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_MASTER_LOSS_IRQ_EN 0x00000400 +#define BV_I2C_CTRL1_MASTER_LOSS_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_MASTER_LOSS_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_SLAVE_STOP_IRQ_EN 0x00000200 +#define BV_I2C_CTRL1_SLAVE_STOP_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_SLAVE_STOP_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_SLAVE_IRQ_EN 0x00000100 +#define BV_I2C_CTRL1_SLAVE_IRQ_EN__DISABLED 0x0 +#define BV_I2C_CTRL1_SLAVE_IRQ_EN__ENABLED 0x1 +#define BM_I2C_CTRL1_BUS_FREE_IRQ 0x00000080 +#define BV_I2C_CTRL1_BUS_FREE_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_BUS_FREE_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x00000040 +#define BV_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x00000020 +#define BV_I2C_CTRL1_NO_SLAVE_ACK_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_NO_SLAVE_ACK_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x00000010 +#define BV_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_EARLY_TERM_IRQ 0x00000008 +#define BV_I2C_CTRL1_EARLY_TERM_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_EARLY_TERM_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_MASTER_LOSS_IRQ 0x00000004 +#define BV_I2C_CTRL1_MASTER_LOSS_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_MASTER_LOSS_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_SLAVE_STOP_IRQ 0x00000002 +#define BV_I2C_CTRL1_SLAVE_STOP_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_SLAVE_STOP_IRQ__REQUEST 0x1 +#define BM_I2C_CTRL1_SLAVE_IRQ 0x00000001 +#define BV_I2C_CTRL1_SLAVE_IRQ__NO_REQUEST 0x0 +#define BV_I2C_CTRL1_SLAVE_IRQ__REQUEST 0x1 +HW_REGISTER_0(HW_I2C_STAT, REGS_I2C_BASE, 0x00000050) +#define HW_I2C_STAT_ADDR (REGS_I2C_BASE + 0x00000050) +#define BM_I2C_STAT_MASTER_PRESENT 0x80000000 +#define BV_I2C_STAT_MASTER_PRESENT__UNAVAILABLE 0x0 +#define BV_I2C_STAT_MASTER_PRESENT__AVAILABLE 0x1 +#define BM_I2C_STAT_SLAVE_PRESENT 0x40000000 +#define BV_I2C_STAT_SLAVE_PRESENT__UNAVAILABLE 0x0 +#define BV_I2C_STAT_SLAVE_PRESENT__AVAILABLE 0x1 +#define BM_I2C_STAT_ANY_ENABLED_IRQ 0x20000000 +#define BV_I2C_STAT_ANY_ENABLED_IRQ__NO_REQUESTS 0x0 +#define BV_I2C_STAT_ANY_ENABLED_IRQ__AT_LEAST_ONE_REQUEST 0x1 +#define BM_I2C_STAT_GOT_A_NAK 0x10000000 +#define BV_I2C_STAT_GOT_A_NAK__NO_NAK 0x0 +#define BV_I2C_STAT_GOT_A_NAK__DETECTED_NAK 0x1 +#define BP_I2C_STAT_RCVD_SLAVE_ADDR 16 +#define BM_I2C_STAT_RCVD_SLAVE_ADDR 0x00FF0000 +#define BF_I2C_STAT_RCVD_SLAVE_ADDR(v) \ + (((v) << 16) & BM_I2C_STAT_RCVD_SLAVE_ADDR) +#define BM_I2C_STAT_SLAVE_ADDR_EQ_ZERO 0x00008000 +#define BV_I2C_STAT_SLAVE_ADDR_EQ_ZERO__ZERO_NOT_MATCHED 0x0 +#define BV_I2C_STAT_SLAVE_ADDR_EQ_ZERO__WAS_ZERO 0x1 +#define BM_I2C_STAT_SLAVE_FOUND 0x00004000 +#define BV_I2C_STAT_SLAVE_FOUND__IDLE 0x0 +#define BV_I2C_STAT_SLAVE_FOUND__WAITING 0x1 +#define BM_I2C_STAT_SLAVE_SEARCHING 0x00002000 +#define BV_I2C_STAT_SLAVE_SEARCHING__IDLE 0x0 +#define BV_I2C_STAT_SLAVE_SEARCHING__ACTIVE 0x1 +#define BM_I2C_STAT_DATA_ENGINE_DMA_WAIT 0x00001000 +#define BV_I2C_STAT_DATA_ENGINE_DMA_WAIT__CONTINUE 0x0 +#define BV_I2C_STAT_DATA_ENGINE_DMA_WAIT__WAITING 0x1 +#define BM_I2C_STAT_BUS_BUSY 0x00000800 +#define BV_I2C_STAT_BUS_BUSY__IDLE 0x0 +#define BV_I2C_STAT_BUS_BUSY__BUSY 0x1 +#define BM_I2C_STAT_CLK_GEN_BUSY 0x00000400 +#define BV_I2C_STAT_CLK_GEN_BUSY__IDLE 0x0 +#define BV_I2C_STAT_CLK_GEN_BUSY__BUSY 0x1 +#define BM_I2C_STAT_DATA_ENGINE_BUSY 0x00000200 +#define BV_I2C_STAT_DATA_ENGINE_BUSY__IDLE 0x0 +#define BV_I2C_STAT_DATA_ENGINE_BUSY__BUSY 0x1 +#define BM_I2C_STAT_SLAVE_BUSY 0x00000100 +#define BV_I2C_STAT_SLAVE_BUSY__IDLE 0x0 +#define BV_I2C_STAT_SLAVE_BUSY__BUSY 0x1 +#define BM_I2C_STAT_BUS_FREE_IRQ_SUMMARY 0x00000080 +#define BV_I2C_STAT_BUS_FREE_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_BUS_FREE_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_DATA_ENGINE_CMPLT_IRQ_SUMMARY 0x00000040 +#define BV_I2C_STAT_DATA_ENGINE_CMPLT_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_DATA_ENGINE_CMPLT_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_NO_SLAVE_ACK_IRQ_SUMMARY 0x00000020 +#define BV_I2C_STAT_NO_SLAVE_ACK_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_NO_SLAVE_ACK_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_OVERSIZE_XFER_TERM_IRQ_SUMMARY 0x00000010 +#define BV_I2C_STAT_OVERSIZE_XFER_TERM_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_OVERSIZE_XFER_TERM_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_EARLY_TERM_IRQ_SUMMARY 0x00000008 +#define BV_I2C_STAT_EARLY_TERM_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_EARLY_TERM_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_MASTER_LOSS_IRQ_SUMMARY 0x00000004 +#define BV_I2C_STAT_MASTER_LOSS_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_MASTER_LOSS_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_SLAVE_STOP_IRQ_SUMMARY 0x00000002 +#define BV_I2C_STAT_SLAVE_STOP_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_SLAVE_STOP_IRQ_SUMMARY__REQUEST 0x1 +#define BM_I2C_STAT_SLAVE_IRQ_SUMMARY 0x00000001 +#define BV_I2C_STAT_SLAVE_IRQ_SUMMARY__NO_REQUEST 0x0 +#define BV_I2C_STAT_SLAVE_IRQ_SUMMARY__REQUEST 0x1 +HW_REGISTER_0(HW_I2C_DATA, REGS_I2C_BASE, 0x00000060) +#define HW_I2C_DATA_ADDR (REGS_I2C_BASE + 0x00000060) +#define BP_I2C_DATA_DATA 0 +#define BM_I2C_DATA_DATA 0xFFFFFFFF +#define BF_I2C_DATA_DATA(v) (v) +HW_REGISTER(HW_I2C_DEBUG0, REGS_I2C_BASE, 0x00000070) +#define HW_I2C_DEBUG0_ADDR (REGS_I2C_BASE + 0x00000070) +#define BM_I2C_DEBUG0_DMAREQ 0x80000000 +#define BM_I2C_DEBUG0_DMAENDCMD 0x40000000 +#define BM_I2C_DEBUG0_DMAKICK 0x20000000 +#define BM_I2C_DEBUG0_DMATERMINATE 0x10000000 +#define BP_I2C_DEBUG0_TBD 26 +#define BM_I2C_DEBUG0_TBD 0x0C000000 +#define BF_I2C_DEBUG0_TBD(v) \ + (((v) << 26) & BM_I2C_DEBUG0_TBD) +#define BP_I2C_DEBUG0_DMA_STATE 16 +#define BM_I2C_DEBUG0_DMA_STATE 0x03FF0000 +#define BF_I2C_DEBUG0_DMA_STATE(v) \ + (((v) << 16) & BM_I2C_DEBUG0_DMA_STATE) +#define BM_I2C_DEBUG0_START_TOGGLE 0x00008000 +#define BM_I2C_DEBUG0_STOP_TOGGLE 0x00004000 +#define BM_I2C_DEBUG0_GRAB_TOGGLE 0x00002000 +#define BM_I2C_DEBUG0_CHANGE_TOGGLE 0x00001000 +#define BM_I2C_DEBUG0_TESTMODE 0x00000800 +#define BM_I2C_DEBUG0_SLAVE_HOLD_CLK 0x00000400 +#define BP_I2C_DEBUG0_SLAVE_STATE 0 +#define BM_I2C_DEBUG0_SLAVE_STATE 0x000003FF +#define BF_I2C_DEBUG0_SLAVE_STATE(v) \ + (((v) << 0) & BM_I2C_DEBUG0_SLAVE_STATE) +HW_REGISTER(HW_I2C_DEBUG1, REGS_I2C_BASE, 0x00000080) +#define HW_I2C_DEBUG1_ADDR (REGS_I2C_BASE + 0x00000080) +#define BM_I2C_DEBUG1_I2C_CLK_IN 0x80000000 +#define BM_I2C_DEBUG1_I2C_DATA_IN 0x40000000 +#define BP_I2C_DEBUG1_DMA_BYTE_ENABLES 24 +#define BM_I2C_DEBUG1_DMA_BYTE_ENABLES 0x0F000000 +#define BF_I2C_DEBUG1_DMA_BYTE_ENABLES(v) \ + (((v) << 24) & BM_I2C_DEBUG1_DMA_BYTE_ENABLES) +#define BP_I2C_DEBUG1_CLK_GEN_STATE 16 +#define BM_I2C_DEBUG1_CLK_GEN_STATE 0x00FF0000 +#define BF_I2C_DEBUG1_CLK_GEN_STATE(v) \ + (((v) << 16) & BM_I2C_DEBUG1_CLK_GEN_STATE) +#define BP_I2C_DEBUG1_LST_MODE 9 +#define BM_I2C_DEBUG1_LST_MODE 0x00000600 +#define BF_I2C_DEBUG1_LST_MODE(v) \ + (((v) << 9) & BM_I2C_DEBUG1_LST_MODE) +#define BV_I2C_DEBUG1_LST_MODE__BCAST 0x0 +#define BV_I2C_DEBUG1_LST_MODE__MY_WRITE 0x1 +#define BV_I2C_DEBUG1_LST_MODE__MY_READ 0x2 +#define BV_I2C_DEBUG1_LST_MODE__NOT_ME 0x3 +#define BM_I2C_DEBUG1_LOCAL_SLAVE_TEST 0x00000100 +#define BM_I2C_DEBUG1_FORCE_CLK_ON 0x00000010 +#define BM_I2C_DEBUG1_FORCE_ARB_LOSS 0x00000008 +#define BM_I2C_DEBUG1_FORCE_RCV_ACK 0x00000004 +#define BM_I2C_DEBUG1_FORCE_I2C_DATA_OE 0x00000002 +#define BM_I2C_DEBUG1_FORCE_I2C_CLK_OE 0x00000001 +HW_REGISTER_0(HW_I2C_VERSION, REGS_I2C_BASE, 0x00000090) +#define HW_I2C_VERSION_ADDR (REGS_I2C_BASE + 0x00000090) +#define BP_I2C_VERSION_MAJOR 24 +#define BM_I2C_VERSION_MAJOR 0xFF000000 +#define BF_I2C_VERSION_MAJOR(v) \ + (((v) << 24) & BM_I2C_VERSION_MAJOR) +#define BP_I2C_VERSION_MINOR 16 +#define BM_I2C_VERSION_MINOR 0x00FF0000 +#define BF_I2C_VERSION_MINOR(v) \ + (((v) << 16) & BM_I2C_VERSION_MINOR) +#define BP_I2C_VERSION_STEP 0 +#define BM_I2C_VERSION_STEP 0x0000FFFF +#define BF_I2C_VERSION_STEP(v) \ + (((v) << 0) & BM_I2C_VERSION_STEP) +#endif /* __ARCH_ARM___I2C_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-icoll.h b/arch/arm/mach-stmp3xxx/include/mach/regs-icoll.h new file mode 100644 index 000000000000..fda52a92841c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-icoll.h @@ -0,0 +1,212 @@ +/* + * STMP ICOLL Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___ICOLL_H +#define __ARCH_ARM___ICOLL_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_ICOLL_BASE (REGS_BASE + 0x0) +#define REGS_ICOLL_BASE_PHYS (0x80000000) +#define REGS_ICOLL_SIZE 0x00002000 +HW_REGISTER(HW_ICOLL_VECTOR, REGS_ICOLL_BASE, 0x00000000) +#define HW_ICOLL_VECTOR_ADDR (REGS_ICOLL_BASE + 0x00000000) +#define BP_ICOLL_VECTOR_IRQVECTOR 2 +#define BM_ICOLL_VECTOR_IRQVECTOR 0xFFFFFFFC +#define BF_ICOLL_VECTOR_IRQVECTOR(v) \ + (((v) << 2) & BM_ICOLL_VECTOR_IRQVECTOR) +HW_REGISTER_0(HW_ICOLL_LEVELACK, REGS_ICOLL_BASE, 0x00000010) +#define HW_ICOLL_LEVELACK_ADDR (REGS_ICOLL_BASE + 0x00000010) +#define BP_ICOLL_LEVELACK_IRQLEVELACK 0 +#define BM_ICOLL_LEVELACK_IRQLEVELACK 0x0000000F +#define BF_ICOLL_LEVELACK_IRQLEVELACK(v) \ + (((v) << 0) & BM_ICOLL_LEVELACK_IRQLEVELACK) +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1 +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL1 0x2 +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL2 0x4 +#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL3 0x8 +HW_REGISTER(HW_ICOLL_CTRL, REGS_ICOLL_BASE, 0x00000020) +#define HW_ICOLL_CTRL_ADDR (REGS_ICOLL_BASE + 0x00000020) +#define BM_ICOLL_CTRL_SFTRST 0x80000000 +#define BV_ICOLL_CTRL_SFTRST__RUN 0x0 +#define BV_ICOLL_CTRL_SFTRST__IN_RESET 0x1 +#define BM_ICOLL_CTRL_CLKGATE 0x40000000 +#define BV_ICOLL_CTRL_CLKGATE__RUN 0x0 +#define BV_ICOLL_CTRL_CLKGATE__NO_CLOCKS 0x1 +#define BP_ICOLL_CTRL_VECTOR_PITCH 21 +#define BM_ICOLL_CTRL_VECTOR_PITCH 0x00E00000 +#define BF_ICOLL_CTRL_VECTOR_PITCH(v) \ + (((v) << 21) & BM_ICOLL_CTRL_VECTOR_PITCH) +#define BV_ICOLL_CTRL_VECTOR_PITCH__DEFAULT_BY4 0x0 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY4 0x1 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY8 0x2 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY12 0x3 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY16 0x4 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY20 0x5 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY24 0x6 +#define BV_ICOLL_CTRL_VECTOR_PITCH__BY28 0x7 +#define BM_ICOLL_CTRL_BYPASS_FSM 0x00100000 +#define BV_ICOLL_CTRL_BYPASS_FSM__NORMAL 0x0 +#define BV_ICOLL_CTRL_BYPASS_FSM__BYPASS 0x1 +#define BM_ICOLL_CTRL_NO_NESTING 0x00080000 +#define BV_ICOLL_CTRL_NO_NESTING__NORMAL 0x0 +#define BV_ICOLL_CTRL_NO_NESTING__NO_NEST 0x1 +#define BM_ICOLL_CTRL_ARM_RSE_MODE 0x00040000 +#define BM_ICOLL_CTRL_FIQ_FINAL_ENABLE 0x00020000 +#define BV_ICOLL_CTRL_FIQ_FINAL_ENABLE__DISABLE 0x0 +#define BV_ICOLL_CTRL_FIQ_FINAL_ENABLE__ENABLE 0x1 +#define BM_ICOLL_CTRL_IRQ_FINAL_ENABLE 0x00010000 +#define BV_ICOLL_CTRL_IRQ_FINAL_ENABLE__DISABLE 0x0 +#define BV_ICOLL_CTRL_IRQ_FINAL_ENABLE__ENABLE 0x1 +HW_REGISTER(HW_ICOLL_VBASE, REGS_ICOLL_BASE, 0x00000040) +#define HW_ICOLL_VBASE_ADDR (REGS_ICOLL_BASE + 0x00000040) +#define BP_ICOLL_VBASE_TABLE_ADDRESS 2 +#define BM_ICOLL_VBASE_TABLE_ADDRESS 0xFFFFFFFC +#define BF_ICOLL_VBASE_TABLE_ADDRESS(v) \ + (((v) << 2) & BM_ICOLL_VBASE_TABLE_ADDRESS) +HW_REGISTER_0(HW_ICOLL_STAT, REGS_ICOLL_BASE, 0x00000070) +#define HW_ICOLL_STAT_ADDR (REGS_ICOLL_BASE + 0x00000070) +#define BP_ICOLL_STAT_VECTOR_NUMBER 0 +#define BM_ICOLL_STAT_VECTOR_NUMBER 0x0000007F +#define BF_ICOLL_STAT_VECTOR_NUMBER(v) \ + (((v) << 0) & BM_ICOLL_STAT_VECTOR_NUMBER) +/* + * multi-register-define name HW_ICOLL_RAWn + * base 0x000000A0 + * count 4 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_ICOLL_RAWn, REGS_ICOLL_BASE, 0x000000a0, 0x10) +#define BP_ICOLL_RAWn_RAW_IRQS 0 +#define BM_ICOLL_RAWn_RAW_IRQS 0xFFFFFFFF +#define BF_ICOLL_RAWn_RAW_IRQS(v) (v) +/* + * multi-register-define name HW_ICOLL_INTERRUPTn + * base 0x00000120 + * count 128 + * offset 0x10 + */ +HW_REGISTER_INDEXED(HW_ICOLL_INTERRUPTn, REGS_ICOLL_BASE, 0x00000120, 0x10) +#define BM_ICOLL_INTERRUPTn_ENFIQ 0x00000010 +#define BV_ICOLL_INTERRUPTn_ENFIQ__DISABLE 0x0 +#define BV_ICOLL_INTERRUPTn_ENFIQ__ENABLE 0x1 +#define BM_ICOLL_INTERRUPTn_SOFTIRQ 0x00000008 +#define BV_ICOLL_INTERRUPTn_SOFTIRQ__NO_INTERRUPT 0x0 +#define BV_ICOLL_INTERRUPTn_SOFTIRQ__FORCE_INTERRUPT 0x1 +#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004 +#define BV_ICOLL_INTERRUPTn_ENABLE__DISABLE 0x0 +#define BV_ICOLL_INTERRUPTn_ENABLE__ENABLE 0x1 +#define BP_ICOLL_INTERRUPTn_PRIORITY 0 +#define BM_ICOLL_INTERRUPTn_PRIORITY 0x00000003 +#define BF_ICOLL_INTERRUPTn_PRIORITY(v) \ + (((v) << 0) & BM_ICOLL_INTERRUPTn_PRIORITY) +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL0 0x0 +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL1 0x1 +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL2 0x2 +#define BV_ICOLL_INTERRUPTn_PRIORITY__LEVEL3 0x3 +HW_REGISTER(HW_ICOLL_DEBUG, REGS_ICOLL_BASE, 0x00001120) +#define HW_ICOLL_DEBUG_ADDR (REGS_ICOLL_BASE + 0x00001120) +#define BP_ICOLL_DEBUG_INSERVICE 28 +#define BM_ICOLL_DEBUG_INSERVICE 0xF0000000 +#define BF_ICOLL_DEBUG_INSERVICE(v) \ + (((v) << 28) & BM_ICOLL_DEBUG_INSERVICE) +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL0 0x1 +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL1 0x2 +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL2 0x4 +#define BV_ICOLL_DEBUG_INSERVICE__LEVEL3 0x8 +#define BP_ICOLL_DEBUG_LEVEL_REQUESTS 24 +#define BM_ICOLL_DEBUG_LEVEL_REQUESTS 0x0F000000 +#define BF_ICOLL_DEBUG_LEVEL_REQUESTS(v) \ + (((v) << 24) & BM_ICOLL_DEBUG_LEVEL_REQUESTS) +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL0 0x1 +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL1 0x2 +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL2 0x4 +#define BV_ICOLL_DEBUG_LEVEL_REQUESTS__LEVEL3 0x8 +#define BP_ICOLL_DEBUG_REQUESTS_BY_LEVEL 20 +#define BM_ICOLL_DEBUG_REQUESTS_BY_LEVEL 0x00F00000 +#define BF_ICOLL_DEBUG_REQUESTS_BY_LEVEL(v) \ + (((v) << 20) & BM_ICOLL_DEBUG_REQUESTS_BY_LEVEL) +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL0 0x1 +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL1 0x2 +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL2 0x4 +#define BV_ICOLL_DEBUG_REQUESTS_BY_LEVEL__LEVEL3 0x8 +#define BM_ICOLL_DEBUG_FIQ 0x00020000 +#define BV_ICOLL_DEBUG_FIQ__NO_FIQ_REQUESTED 0x0 +#define BV_ICOLL_DEBUG_FIQ__FIQ_REQUESTED 0x1 +#define BM_ICOLL_DEBUG_IRQ 0x00010000 +#define BV_ICOLL_DEBUG_IRQ__NO_IRQ_REQUESTED 0x0 +#define BV_ICOLL_DEBUG_IRQ__IRQ_REQUESTED 0x1 +#define BP_ICOLL_DEBUG_VECTOR_FSM 0 +#define BM_ICOLL_DEBUG_VECTOR_FSM 0x000003FF +#define BF_ICOLL_DEBUG_VECTOR_FSM(v) \ + (((v) << 0) & BM_ICOLL_DEBUG_VECTOR_FSM) +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_IDLE 0x000 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE1 0x001 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE2 0x002 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_PENDING 0x004 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE3 0x008 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE4 0x010 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_ISR_RUNNING1 0x020 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_ISR_RUNNING2 0x040 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_ISR_RUNNING3 0x080 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE5 0x100 +#define BV_ICOLL_DEBUG_VECTOR_FSM__FSM_MULTICYCLE6 0x200 +HW_REGISTER(HW_ICOLL_DBGREAD0, REGS_ICOLL_BASE, 0x00001130) +#define HW_ICOLL_DBGREAD0_ADDR (REGS_ICOLL_BASE + 0x00001130) +#define BP_ICOLL_DBGREAD0_VALUE 0 +#define BM_ICOLL_DBGREAD0_VALUE 0xFFFFFFFF +#define BF_ICOLL_DBGREAD0_VALUE(v) (v) +HW_REGISTER(HW_ICOLL_DBGREAD1, REGS_ICOLL_BASE, 0x00001140) +#define HW_ICOLL_DBGREAD1_ADDR (REGS_ICOLL_BASE + 0x00001140) +#define BP_ICOLL_DBGREAD1_VALUE 0 +#define BM_ICOLL_DBGREAD1_VALUE 0xFFFFFFFF +#define BF_ICOLL_DBGREAD1_VALUE(v) (v) +HW_REGISTER(HW_ICOLL_DBGFLAG, REGS_ICOLL_BASE, 0x00001150) +#define HW_ICOLL_DBGFLAG_ADDR (REGS_ICOLL_BASE + 0x00001150) +#define BP_ICOLL_DBGFLAG_FLAG 0 +#define BM_ICOLL_DBGFLAG_FLAG 0x0000FFFF +#define BF_ICOLL_DBGFLAG_FLAG(v) \ + (((v) << 0) & BM_ICOLL_DBGFLAG_FLAG) +/* + * multi-register-define name HW_ICOLL_DBGREQUESTn + * base 0x00001160 + * count 4 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_ICOLL_DBGREQUESTn, REGS_ICOLL_BASE, 0x00001160, + 0x10) +#define BP_ICOLL_DBGREQUESTn_BITS 0 +#define BM_ICOLL_DBGREQUESTn_BITS 0xFFFFFFFF +#define BF_ICOLL_DBGREQUESTn_BITS(v) (v) +HW_REGISTER_0(HW_ICOLL_VERSION, REGS_ICOLL_BASE, 0x000011e0) +#define HW_ICOLL_VERSION_ADDR (REGS_ICOLL_BASE + 0x000011e0) +#define BP_ICOLL_VERSION_MAJOR 24 +#define BM_ICOLL_VERSION_MAJOR 0xFF000000 +#define BF_ICOLL_VERSION_MAJOR(v) \ + (((v) << 24) & BM_ICOLL_VERSION_MAJOR) +#define BP_ICOLL_VERSION_MINOR 16 +#define BM_ICOLL_VERSION_MINOR 0x00FF0000 +#define BF_ICOLL_VERSION_MINOR(v) \ + (((v) << 16) & BM_ICOLL_VERSION_MINOR) +#define BP_ICOLL_VERSION_STEP 0 +#define BM_ICOLL_VERSION_STEP 0x0000FFFF +#define BF_ICOLL_VERSION_STEP(v) \ + (((v) << 0) & BM_ICOLL_VERSION_STEP) +#endif /* __ARCH_ARM___ICOLL_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-ir.h b/arch/arm/mach-stmp3xxx/include/mach/regs-ir.h new file mode 100644 index 000000000000..4ea39bf721ac --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-ir.h @@ -0,0 +1,280 @@ +/* + * STMP IR Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___IR_H +#define __ARCH_ARM___IR_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_IR_BASE (REGS_BASE + 0x78000) +#define REGS_IR_BASE_PHYS (0x80078000) +#define REGS_IR_SIZE 0x00002000 +HW_REGISTER(HW_IR_CTRL, REGS_IR_BASE, 0x00000000) +#define HW_IR_CTRL_ADDR (REGS_IR_BASE + 0x00000000) +#define BM_IR_CTRL_SFTRST 0x80000000 +#define BV_IR_CTRL_SFTRST__RUN 0x0 +#define BV_IR_CTRL_SFTRST__RESET 0x1 +#define BM_IR_CTRL_CLKGATE 0x40000000 +#define BP_IR_CTRL_MTA 24 +#define BM_IR_CTRL_MTA 0x07000000 +#define BF_IR_CTRL_MTA(v) \ + (((v) << 24) & BM_IR_CTRL_MTA) +#define BV_IR_CTRL_MTA__MTA_10MS 0x0 +#define BV_IR_CTRL_MTA__MTA_5MS 0x1 +#define BV_IR_CTRL_MTA__MTA_1MS 0x2 +#define BV_IR_CTRL_MTA__MTA_500US 0x3 +#define BV_IR_CTRL_MTA__MTA_100US 0x4 +#define BV_IR_CTRL_MTA__MTA_50US 0x5 +#define BV_IR_CTRL_MTA__MTA_10US 0x6 +#define BV_IR_CTRL_MTA__MTA_0 0x7 +#define BP_IR_CTRL_MODE 22 +#define BM_IR_CTRL_MODE 0x00C00000 +#define BF_IR_CTRL_MODE(v) \ + (((v) << 22) & BM_IR_CTRL_MODE) +#define BV_IR_CTRL_MODE__SIR 0x0 +#define BV_IR_CTRL_MODE__MIR 0x1 +#define BV_IR_CTRL_MODE__FIR 0x2 +#define BV_IR_CTRL_MODE__VFIR 0x3 +#define BP_IR_CTRL_SPEED 19 +#define BM_IR_CTRL_SPEED 0x00380000 +#define BF_IR_CTRL_SPEED(v) \ + (((v) << 19) & BM_IR_CTRL_SPEED) +#define BV_IR_CTRL_SPEED__SPD000 0x0 +#define BV_IR_CTRL_SPEED__SPD001 0x1 +#define BV_IR_CTRL_SPEED__SPD010 0x2 +#define BV_IR_CTRL_SPEED__SPD011 0x3 +#define BV_IR_CTRL_SPEED__SPD100 0x4 +#define BV_IR_CTRL_SPEED__SPD101 0x5 +#define BP_IR_CTRL_TC_TIME_DIV 8 +#define BM_IR_CTRL_TC_TIME_DIV 0x00003F00 +#define BF_IR_CTRL_TC_TIME_DIV(v) \ + (((v) << 8) & BM_IR_CTRL_TC_TIME_DIV) +#define BM_IR_CTRL_TC_TYPE 0x00000080 +#define BP_IR_CTRL_SIR_GAP 4 +#define BM_IR_CTRL_SIR_GAP 0x00000070 +#define BF_IR_CTRL_SIR_GAP(v) \ + (((v) << 4) & BM_IR_CTRL_SIR_GAP) +#define BV_IR_CTRL_SIR_GAP__GAP_10K 0x0 +#define BV_IR_CTRL_SIR_GAP__GAP_5K 0x1 +#define BV_IR_CTRL_SIR_GAP__GAP_1K 0x2 +#define BV_IR_CTRL_SIR_GAP__GAP_500 0x3 +#define BV_IR_CTRL_SIR_GAP__GAP_100 0x4 +#define BV_IR_CTRL_SIR_GAP__GAP_50 0x5 +#define BV_IR_CTRL_SIR_GAP__GAP_10 0x6 +#define BV_IR_CTRL_SIR_GAP__GAP_0 0x7 +#define BM_IR_CTRL_SIPEN 0x00000008 +#define BM_IR_CTRL_TCEN 0x00000004 +#define BM_IR_CTRL_TXEN 0x00000002 +#define BM_IR_CTRL_RXEN 0x00000001 +HW_REGISTER(HW_IR_TXDMA, REGS_IR_BASE, 0x00000010) +#define HW_IR_TXDMA_ADDR (REGS_IR_BASE + 0x00000010) +#define BM_IR_TXDMA_RUN 0x80000000 +#define BM_IR_TXDMA_EMPTY 0x20000000 +#define BM_IR_TXDMA_INT 0x10000000 +#define BM_IR_TXDMA_CHANGE 0x08000000 +#define BP_IR_TXDMA_NEW_MTA 24 +#define BM_IR_TXDMA_NEW_MTA 0x07000000 +#define BF_IR_TXDMA_NEW_MTA(v) \ + (((v) << 24) & BM_IR_TXDMA_NEW_MTA) +#define BP_IR_TXDMA_NEW_MODE 22 +#define BM_IR_TXDMA_NEW_MODE 0x00C00000 +#define BF_IR_TXDMA_NEW_MODE(v) \ + (((v) << 22) & BM_IR_TXDMA_NEW_MODE) +#define BP_IR_TXDMA_NEW_SPEED 19 +#define BM_IR_TXDMA_NEW_SPEED 0x00380000 +#define BF_IR_TXDMA_NEW_SPEED(v) \ + (((v) << 19) & BM_IR_TXDMA_NEW_SPEED) +#define BM_IR_TXDMA_BOF_TYPE 0x00040000 +#define BP_IR_TXDMA_XBOFS 12 +#define BM_IR_TXDMA_XBOFS 0x0003F000 +#define BF_IR_TXDMA_XBOFS(v) \ + (((v) << 12) & BM_IR_TXDMA_XBOFS) +#define BP_IR_TXDMA_XFER_COUNT 0 +#define BM_IR_TXDMA_XFER_COUNT 0x00000FFF +#define BF_IR_TXDMA_XFER_COUNT(v) \ + (((v) << 0) & BM_IR_TXDMA_XFER_COUNT) +HW_REGISTER(HW_IR_RXDMA, REGS_IR_BASE, 0x00000020) +#define HW_IR_RXDMA_ADDR (REGS_IR_BASE + 0x00000020) +#define BM_IR_RXDMA_RUN 0x80000000 +#define BP_IR_RXDMA_XFER_COUNT 0 +#define BM_IR_RXDMA_XFER_COUNT 0x000003FF +#define BF_IR_RXDMA_XFER_COUNT(v) \ + (((v) << 0) & BM_IR_RXDMA_XFER_COUNT) +HW_REGISTER(HW_IR_DBGCTRL, REGS_IR_BASE, 0x00000030) +#define HW_IR_DBGCTRL_ADDR (REGS_IR_BASE + 0x00000030) +#define BM_IR_DBGCTRL_VFIRSWZ 0x00001000 +#define BV_IR_DBGCTRL_VFIRSWZ__NORMAL 0 +#define BV_IR_DBGCTRL_VFIRSWZ__SWAP 1 +#define BM_IR_DBGCTRL_RXFRMOFF 0x00000800 +#define BM_IR_DBGCTRL_RXCRCOFF 0x00000400 +#define BM_IR_DBGCTRL_RXINVERT 0x00000200 +#define BM_IR_DBGCTRL_TXFRMOFF 0x00000100 +#define BM_IR_DBGCTRL_TXCRCOFF 0x00000080 +#define BM_IR_DBGCTRL_TXINVERT 0x00000040 +#define BM_IR_DBGCTRL_INTLOOPBACK 0x00000020 +#define BM_IR_DBGCTRL_DUPLEX 0x00000010 +#define BM_IR_DBGCTRL_MIO_RX 0x00000008 +#define BM_IR_DBGCTRL_MIO_TX 0x00000004 +#define BM_IR_DBGCTRL_MIO_SCLK 0x00000002 +#define BM_IR_DBGCTRL_MIO_EN 0x00000001 +HW_REGISTER(HW_IR_INTR, REGS_IR_BASE, 0x00000040) +#define HW_IR_INTR_ADDR (REGS_IR_BASE + 0x00000040) +#define BM_IR_INTR_RXABORT_IRQ_EN 0x00400000 +#define BV_IR_INTR_RXABORT_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_RXABORT_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_SPEED_IRQ_EN 0x00200000 +#define BV_IR_INTR_SPEED_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_SPEED_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_RXOF_IRQ_EN 0x00100000 +#define BV_IR_INTR_RXOF_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_RXOF_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_TXUF_IRQ_EN 0x00080000 +#define BV_IR_INTR_TXUF_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_TXUF_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_TC_IRQ_EN 0x00040000 +#define BV_IR_INTR_TC_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_TC_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_RX_IRQ_EN 0x00020000 +#define BV_IR_INTR_RX_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_RX_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_TX_IRQ_EN 0x00010000 +#define BV_IR_INTR_TX_IRQ_EN__DISABLED 0x0 +#define BV_IR_INTR_TX_IRQ_EN__ENABLED 0x1 +#define BM_IR_INTR_RXABORT_IRQ 0x00000040 +#define BV_IR_INTR_RXABORT_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_RXABORT_IRQ__REQUEST 0x1 +#define BM_IR_INTR_SPEED_IRQ 0x00000020 +#define BV_IR_INTR_SPEED_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_SPEED_IRQ__REQUEST 0x1 +#define BM_IR_INTR_RXOF_IRQ 0x00000010 +#define BV_IR_INTR_RXOF_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_RXOF_IRQ__REQUEST 0x1 +#define BM_IR_INTR_TXUF_IRQ 0x00000008 +#define BV_IR_INTR_TXUF_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_TXUF_IRQ__REQUEST 0x1 +#define BM_IR_INTR_TC_IRQ 0x00000004 +#define BV_IR_INTR_TC_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_TC_IRQ__REQUEST 0x1 +#define BM_IR_INTR_RX_IRQ 0x00000002 +#define BV_IR_INTR_RX_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_RX_IRQ__REQUEST 0x1 +#define BM_IR_INTR_TX_IRQ 0x00000001 +#define BV_IR_INTR_TX_IRQ__NO_REQUEST 0x0 +#define BV_IR_INTR_TX_IRQ__REQUEST 0x1 +HW_REGISTER_0(HW_IR_DATA, REGS_IR_BASE, 0x00000050) +#define HW_IR_DATA_ADDR (REGS_IR_BASE + 0x00000050) +#define BP_IR_DATA_DATA 0 +#define BM_IR_DATA_DATA 0xFFFFFFFF +#define BF_IR_DATA_DATA(v) (v) +HW_REGISTER_0(HW_IR_STAT, REGS_IR_BASE, 0x00000060) +#define HW_IR_STAT_ADDR (REGS_IR_BASE + 0x00000060) +#define BM_IR_STAT_PRESENT 0x80000000 +#define BV_IR_STAT_PRESENT__UNAVAILABLE 0x0 +#define BV_IR_STAT_PRESENT__AVAILABLE 0x1 +#define BP_IR_STAT_MODE_ALLOWED 29 +#define BM_IR_STAT_MODE_ALLOWED 0x60000000 +#define BF_IR_STAT_MODE_ALLOWED(v) \ + (((v) << 29) & BM_IR_STAT_MODE_ALLOWED) +#define BV_IR_STAT_MODE_ALLOWED__VFIR 0x0 +#define BV_IR_STAT_MODE_ALLOWED__FIR 0x1 +#define BV_IR_STAT_MODE_ALLOWED__MIR 0x2 +#define BV_IR_STAT_MODE_ALLOWED__SIR 0x3 +#define BM_IR_STAT_ANY_IRQ 0x10000000 +#define BV_IR_STAT_ANY_IRQ__NO_REQUEST 0x0 +#define BV_IR_STAT_ANY_IRQ__REQUEST 0x1 +#define BM_IR_STAT_RXABORT_SUMMARY 0x00400000 +#define BV_IR_STAT_RXABORT_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_RXABORT_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_SPEED_SUMMARY 0x00200000 +#define BV_IR_STAT_SPEED_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_SPEED_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_RXOF_SUMMARY 0x00100000 +#define BV_IR_STAT_RXOF_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_RXOF_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_TXUF_SUMMARY 0x00080000 +#define BV_IR_STAT_TXUF_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_TXUF_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_TC_SUMMARY 0x00040000 +#define BV_IR_STAT_TC_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_TC_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_RX_SUMMARY 0x00020000 +#define BV_IR_STAT_RX_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_RX_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_TX_SUMMARY 0x00010000 +#define BV_IR_STAT_TX_SUMMARY__NO_REQUEST 0x0 +#define BV_IR_STAT_TX_SUMMARY__REQUEST 0x1 +#define BM_IR_STAT_MEDIA_BUSY 0x00000004 +#define BM_IR_STAT_RX_ACTIVE 0x00000002 +#define BM_IR_STAT_TX_ACTIVE 0x00000001 +HW_REGISTER(HW_IR_TCCTRL, REGS_IR_BASE, 0x00000070) +#define HW_IR_TCCTRL_ADDR (REGS_IR_BASE + 0x00000070) +#define BM_IR_TCCTRL_INIT 0x80000000 +#define BM_IR_TCCTRL_GO 0x40000000 +#define BM_IR_TCCTRL_BUSY 0x20000000 +#define BM_IR_TCCTRL_TEMIC 0x01000000 +#define BV_IR_TCCTRL_TEMIC__LOW 0x0 +#define BV_IR_TCCTRL_TEMIC__HIGH 0x1 +#define BP_IR_TCCTRL_EXT_DATA 16 +#define BM_IR_TCCTRL_EXT_DATA 0x00FF0000 +#define BF_IR_TCCTRL_EXT_DATA(v) \ + (((v) << 16) & BM_IR_TCCTRL_EXT_DATA) +#define BP_IR_TCCTRL_DATA 8 +#define BM_IR_TCCTRL_DATA 0x0000FF00 +#define BF_IR_TCCTRL_DATA(v) \ + (((v) << 8) & BM_IR_TCCTRL_DATA) +#define BP_IR_TCCTRL_ADDR 5 +#define BM_IR_TCCTRL_ADDR 0x000000E0 +#define BF_IR_TCCTRL_ADDR(v) \ + (((v) << 5) & BM_IR_TCCTRL_ADDR) +#define BP_IR_TCCTRL_INDX 1 +#define BM_IR_TCCTRL_INDX 0x0000001E +#define BF_IR_TCCTRL_INDX(v) \ + (((v) << 1) & BM_IR_TCCTRL_INDX) +#define BM_IR_TCCTRL_C 0x00000001 +HW_REGISTER_0(HW_IR_SI_READ, REGS_IR_BASE, 0x00000080) +#define HW_IR_SI_READ_ADDR (REGS_IR_BASE + 0x00000080) +#define BM_IR_SI_READ_ABORT 0x00000100 +#define BP_IR_SI_READ_DATA 0 +#define BM_IR_SI_READ_DATA 0x000000FF +#define BF_IR_SI_READ_DATA(v) \ + (((v) << 0) & BM_IR_SI_READ_DATA) +HW_REGISTER_0(HW_IR_DEBUG, REGS_IR_BASE, 0x00000090) +#define HW_IR_DEBUG_ADDR (REGS_IR_BASE + 0x00000090) +#define BM_IR_DEBUG_TXDMAKICK 0x00000020 +#define BM_IR_DEBUG_RXDMAKICK 0x00000010 +#define BM_IR_DEBUG_TXDMAEND 0x00000008 +#define BM_IR_DEBUG_RXDMAEND 0x00000004 +#define BM_IR_DEBUG_TXDMAREQ 0x00000002 +#define BM_IR_DEBUG_RXDMAREQ 0x00000001 +HW_REGISTER_0(HW_IR_VERSION, REGS_IR_BASE, 0x000000a0) +#define HW_IR_VERSION_ADDR (REGS_IR_BASE + 0x000000a0) +#define BP_IR_VERSION_MAJOR 24 +#define BM_IR_VERSION_MAJOR 0xFF000000 +#define BF_IR_VERSION_MAJOR(v) \ + (((v) << 24) & BM_IR_VERSION_MAJOR) +#define BP_IR_VERSION_MINOR 16 +#define BM_IR_VERSION_MINOR 0x00FF0000 +#define BF_IR_VERSION_MINOR(v) \ + (((v) << 16) & BM_IR_VERSION_MINOR) +#define BP_IR_VERSION_STEP 0 +#define BM_IR_VERSION_STEP 0x0000FFFF +#define BF_IR_VERSION_STEP(v) \ + (((v) << 0) & BM_IR_VERSION_STEP) +#endif /* __ARCH_ARM___IR_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-lcdif.h b/arch/arm/mach-stmp3xxx/include/mach/regs-lcdif.h new file mode 100644 index 000000000000..df60f2ca576c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-lcdif.h @@ -0,0 +1,497 @@ +/* + * STMP LCDIF Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___LCDIF_H +#define __ARCH_ARM___LCDIF_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_LCDIF_BASE (REGS_BASE + 0x30000) +#define REGS_LCDIF_BASE_PHYS (0x80030000) +#define REGS_LCDIF_SIZE 0x00002000 +HW_REGISTER(HW_LCDIF_CTRL, REGS_LCDIF_BASE, 0x00000000) +#define HW_LCDIF_CTRL_ADDR (REGS_LCDIF_BASE + 0x00000000) +#define BM_LCDIF_CTRL_SFTRST 0x80000000 +#define BM_LCDIF_CTRL_CLKGATE 0x40000000 +#define BM_LCDIF_CTRL_YCBCR422_INPUT 0x20000000 +#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE 0x08000000 +#define BM_LCDIF_CTRL_DATA_SHIFT_DIR 0x04000000 +#define BV_LCDIF_CTRL_DATA_SHIFT_DIR__TXDATA_SHIFT_LEFT 0x0 +#define BV_LCDIF_CTRL_DATA_SHIFT_DIR__TXDATA_SHIFT_RIGHT 0x1 +#define BP_LCDIF_CTRL_SHIFT_NUM_BITS 21 +#define BM_LCDIF_CTRL_SHIFT_NUM_BITS 0x03E00000 +#define BF_LCDIF_CTRL_SHIFT_NUM_BITS(v) \ + (((v) << 21) & BM_LCDIF_CTRL_SHIFT_NUM_BITS) +#define BM_LCDIF_CTRL_DVI_MODE 0x00100000 +#define BM_LCDIF_CTRL_BYPASS_COUNT 0x00080000 +#define BM_LCDIF_CTRL_VSYNC_MODE 0x00040000 +#define BM_LCDIF_CTRL_DOTCLK_MODE 0x00020000 +#define BM_LCDIF_CTRL_DATA_SELECT 0x00010000 +#define BV_LCDIF_CTRL_DATA_SELECT__CMD_MODE 0x0 +#define BV_LCDIF_CTRL_DATA_SELECT__DATA_MODE 0x1 +#define BP_LCDIF_CTRL_INPUT_DATA_SWIZZLE 14 +#define BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE 0x0000C000 +#define BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(v) \ + (((v) << 14) & BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE) +#define BV_LCDIF_CTRL_INPUT_DATA_SWIZZLE__NO_SWAP 0x0 +#define BV_LCDIF_CTRL_INPUT_DATA_SWIZZLE__LITTLE_ENDIAN 0x0 +#define BV_LCDIF_CTRL_INPUT_DATA_SWIZZLE__BIG_ENDIAN_SWAP 0x1 +#define BV_LCDIF_CTRL_INPUT_DATA_SWIZZLE__SWAP_ALL_BYTES 0x1 +#define BV_LCDIF_CTRL_INPUT_DATA_SWIZZLE__HWD_SWAP 0x2 +#define BV_LCDIF_CTRL_INPUT_DATA_SWIZZLE__HWD_BYTE_SWAP 0x3 +#define BP_LCDIF_CTRL_CSC_DATA_SWIZZLE 12 +#define BM_LCDIF_CTRL_CSC_DATA_SWIZZLE 0x00003000 +#define BF_LCDIF_CTRL_CSC_DATA_SWIZZLE(v) \ + (((v) << 12) & BM_LCDIF_CTRL_CSC_DATA_SWIZZLE) +#define BV_LCDIF_CTRL_CSC_DATA_SWIZZLE__NO_SWAP 0x0 +#define BV_LCDIF_CTRL_CSC_DATA_SWIZZLE__LITTLE_ENDIAN 0x0 +#define BV_LCDIF_CTRL_CSC_DATA_SWIZZLE__BIG_ENDIAN_SWAP 0x1 +#define BV_LCDIF_CTRL_CSC_DATA_SWIZZLE__SWAP_ALL_BYTES 0x1 +#define BV_LCDIF_CTRL_CSC_DATA_SWIZZLE__HWD_SWAP 0x2 +#define BV_LCDIF_CTRL_CSC_DATA_SWIZZLE__HWD_BYTE_SWAP 0x3 +#define BP_LCDIF_CTRL_LCD_DATABUS_WIDTH 10 +#define BM_LCDIF_CTRL_LCD_DATABUS_WIDTH 0x00000C00 +#define BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(v) \ + (((v) << 10) & BM_LCDIF_CTRL_LCD_DATABUS_WIDTH) +#define BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__16_BIT 0x0 +#define BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__8_BIT 0x1 +#define BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__18_BIT 0x2 +#define BV_LCDIF_CTRL_LCD_DATABUS_WIDTH__24_BIT 0x3 +#define BP_LCDIF_CTRL_WORD_LENGTH 8 +#define BM_LCDIF_CTRL_WORD_LENGTH 0x00000300 +#define BF_LCDIF_CTRL_WORD_LENGTH(v) \ + (((v) << 8) & BM_LCDIF_CTRL_WORD_LENGTH) +#define BV_LCDIF_CTRL_WORD_LENGTH__16_BIT 0x0 +#define BV_LCDIF_CTRL_WORD_LENGTH__8_BIT 0x1 +#define BV_LCDIF_CTRL_WORD_LENGTH__18_BIT 0x2 +#define BV_LCDIF_CTRL_WORD_LENGTH__24_BIT 0x3 +#define BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC 0x00000080 +#define BM_LCDIF_CTRL_ENABLE_PXP_HANDSHAKE 0x00000040 +#define BM_LCDIF_CTRL_LCDIF_MASTER 0x00000020 +#define BM_LCDIF_CTRL_DMA_BURST_LENGTH 0x00000010 +#define BM_LCDIF_CTRL_DATA_FORMAT_16_BIT 0x00000008 +#define BM_LCDIF_CTRL_DATA_FORMAT_18_BIT 0x00000004 +#define BV_LCDIF_CTRL_DATA_FORMAT_18_BIT__LOWER_18_BITS_VALID 0x0 +#define BV_LCDIF_CTRL_DATA_FORMAT_18_BIT__UPPER_18_BITS_VALID 0x1 +#define BM_LCDIF_CTRL_DATA_FORMAT_24_BIT 0x00000002 +#define BV_LCDIF_CTRL_DATA_FORMAT_24_BIT__ALL_24_BITS_VALID 0x0 +#define BV_LCDIF_CTRL_DATA_FORMAT_24_BIT__DROP_UPPER_2_BITS_PER_BYTE 0x1 +#define BM_LCDIF_CTRL_RUN 0x00000001 +HW_REGISTER(HW_LCDIF_CTRL1, REGS_LCDIF_BASE, 0x00000010) +#define HW_LCDIF_CTRL1_ADDR (REGS_LCDIF_BASE + 0x00000010) +#define BM_LCDIF_CTRL1_BM_ERROR_IRQ_EN 0x04000000 +#define BM_LCDIF_CTRL1_BM_ERROR_IRQ 0x02000000 +#define BV_LCDIF_CTRL1_BM_ERROR_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_CTRL1_BM_ERROR_IRQ__REQUEST 0x1 +#define BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW 0x01000000 +#define BM_LCDIF_CTRL1_INTERLACE_FIELDS 0x00800000 +#define BM_LCDIF_CTRL1_START_INTERLACE_FROM_SECOND_FIELD 0x00400000 +#define BM_LCDIF_CTRL1_FIFO_CLEAR 0x00200000 +#define BM_LCDIF_CTRL1_IRQ_ON_ALTERNATE_FIELDS 0x00100000 +#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT 16 +#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT 0x000F0000 +#define BF_LCDIF_CTRL1_BYTE_PACKING_FORMAT(v) \ + (((v) << 16) & BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT) +#define BM_LCDIF_CTRL1_OVERFLOW_IRQ_EN 0x00008000 +#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ_EN 0x00004000 +#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ_EN 0x00002000 +#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN 0x00001000 +#define BM_LCDIF_CTRL1_OVERFLOW_IRQ 0x00000800 +#define BV_LCDIF_CTRL1_OVERFLOW_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_CTRL1_OVERFLOW_IRQ__REQUEST 0x1 +#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ 0x00000400 +#define BV_LCDIF_CTRL1_UNDERFLOW_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_CTRL1_UNDERFLOW_IRQ__REQUEST 0x1 +#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ 0x00000200 +#define BV_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ__REQUEST 0x1 +#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ 0x00000100 +#define BV_LCDIF_CTRL1_VSYNC_EDGE_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_CTRL1_VSYNC_EDGE_IRQ__REQUEST 0x1 +#define BM_LCDIF_CTRL1_PAUSE_TRANSFER 0x00000040 +#define BM_LCDIF_CTRL1_PAUSE_TRANSFER_IRQ_EN 0x00000020 +#define BM_LCDIF_CTRL1_PAUSE_TRANSFER_IRQ 0x00000010 +#define BV_LCDIF_CTRL1_PAUSE_TRANSFER_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_CTRL1_PAUSE_TRANSFER_IRQ__REQUEST 0x1 +#define BM_LCDIF_CTRL1_LCD_CS_CTRL 0x00000008 +#define BM_LCDIF_CTRL1_BUSY_ENABLE 0x00000004 +#define BV_LCDIF_CTRL1_BUSY_ENABLE__BUSY_DISABLED 0x0 +#define BV_LCDIF_CTRL1_BUSY_ENABLE__BUSY_ENABLED 0x1 +#define BM_LCDIF_CTRL1_MODE86 0x00000002 +#define BV_LCDIF_CTRL1_MODE86__8080_MODE 0x0 +#define BV_LCDIF_CTRL1_MODE86__6800_MODE 0x1 +#define BM_LCDIF_CTRL1_RESET 0x00000001 +#define BV_LCDIF_CTRL1_RESET__LCDRESET_LOW 0x0 +#define BV_LCDIF_CTRL1_RESET__LCDRESET_HIGH 0x1 +HW_REGISTER_0(HW_LCDIF_TRANSFER_COUNT, REGS_LCDIF_BASE, 0x00000020) +#define HW_LCDIF_TRANSFER_COUNT_ADDR (REGS_LCDIF_BASE + 0x00000020) +#define BP_LCDIF_TRANSFER_COUNT_V_COUNT 16 +#define BM_LCDIF_TRANSFER_COUNT_V_COUNT 0xFFFF0000 +#define BF_LCDIF_TRANSFER_COUNT_V_COUNT(v) \ + (((v) << 16) & BM_LCDIF_TRANSFER_COUNT_V_COUNT) +#define BP_LCDIF_TRANSFER_COUNT_H_COUNT 0 +#define BM_LCDIF_TRANSFER_COUNT_H_COUNT 0x0000FFFF +#define BF_LCDIF_TRANSFER_COUNT_H_COUNT(v) \ + (((v) << 0) & BM_LCDIF_TRANSFER_COUNT_H_COUNT) +HW_REGISTER_0(HW_LCDIF_CUR_BUF, REGS_LCDIF_BASE, 0x00000030) +#define HW_LCDIF_CUR_BUF_ADDR (REGS_LCDIF_BASE + 0x00000030) +#define BP_LCDIF_CUR_BUF_ADDR 0 +#define BM_LCDIF_CUR_BUF_ADDR 0xFFFFFFFF +#define BF_LCDIF_CUR_BUF_ADDR(v) (v) +HW_REGISTER_0(HW_LCDIF_NEXT_BUF, REGS_LCDIF_BASE, 0x00000040) +#define HW_LCDIF_NEXT_BUF_ADDR (REGS_LCDIF_BASE + 0x00000040) +#define BP_LCDIF_NEXT_BUF_ADDR 0 +#define BM_LCDIF_NEXT_BUF_ADDR 0xFFFFFFFF +#define BF_LCDIF_NEXT_BUF_ADDR(v) (v) +HW_REGISTER_0(HW_LCDIF_PAGETABLE, REGS_LCDIF_BASE, 0x00000050) +#define HW_LCDIF_PAGETABLE_ADDR (REGS_LCDIF_BASE + 0x00000050) +#define BP_LCDIF_PAGETABLE_BASE 14 +#define BM_LCDIF_PAGETABLE_BASE 0xFFFFC000 +#define BF_LCDIF_PAGETABLE_BASE(v) \ + (((v) << 14) & BM_LCDIF_PAGETABLE_BASE) +#define BM_LCDIF_PAGETABLE_FLUSH 0x00000002 +#define BM_LCDIF_PAGETABLE_ENABLE 0x00000001 +HW_REGISTER_0(HW_LCDIF_TIMING, REGS_LCDIF_BASE, 0x00000060) +#define HW_LCDIF_TIMING_ADDR (REGS_LCDIF_BASE + 0x00000060) +#define BP_LCDIF_TIMING_CMD_HOLD 24 +#define BM_LCDIF_TIMING_CMD_HOLD 0xFF000000 +#define BF_LCDIF_TIMING_CMD_HOLD(v) \ + (((v) << 24) & BM_LCDIF_TIMING_CMD_HOLD) +#define BP_LCDIF_TIMING_CMD_SETUP 16 +#define BM_LCDIF_TIMING_CMD_SETUP 0x00FF0000 +#define BF_LCDIF_TIMING_CMD_SETUP(v) \ + (((v) << 16) & BM_LCDIF_TIMING_CMD_SETUP) +#define BP_LCDIF_TIMING_DATA_HOLD 8 +#define BM_LCDIF_TIMING_DATA_HOLD 0x0000FF00 +#define BF_LCDIF_TIMING_DATA_HOLD(v) \ + (((v) << 8) & BM_LCDIF_TIMING_DATA_HOLD) +#define BP_LCDIF_TIMING_DATA_SETUP 0 +#define BM_LCDIF_TIMING_DATA_SETUP 0x000000FF +#define BF_LCDIF_TIMING_DATA_SETUP(v) \ + (((v) << 0) & BM_LCDIF_TIMING_DATA_SETUP) +HW_REGISTER(HW_LCDIF_VDCTRL0, REGS_LCDIF_BASE, 0x00000070) +#define HW_LCDIF_VDCTRL0_ADDR (REGS_LCDIF_BASE + 0x00000070) +#define BM_LCDIF_VDCTRL0_VSYNC_OEB 0x20000000 +#define BV_LCDIF_VDCTRL0_VSYNC_OEB__VSYNC_OUTPUT 0x0 +#define BV_LCDIF_VDCTRL0_VSYNC_OEB__VSYNC_INPUT 0x1 +#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT 0x10000000 +#define BM_LCDIF_VDCTRL0_VSYNC_POL 0x08000000 +#define BM_LCDIF_VDCTRL0_HSYNC_POL 0x04000000 +#define BM_LCDIF_VDCTRL0_DOTCLK_POL 0x02000000 +#define BM_LCDIF_VDCTRL0_ENABLE_POL 0x01000000 +#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT 0x00200000 +#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT 0x00100000 +#define BM_LCDIF_VDCTRL0_HALF_LINE 0x00080000 +#define BM_LCDIF_VDCTRL0_HALF_LINE_MODE 0x00040000 +#define BP_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH 0 +#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH 0x0003FFFF +#define BF_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH(v) \ + (((v) << 0) & BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH) +HW_REGISTER_0(HW_LCDIF_VDCTRL1, REGS_LCDIF_BASE, 0x00000080) +#define HW_LCDIF_VDCTRL1_ADDR (REGS_LCDIF_BASE + 0x00000080) +#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD 0 +#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD 0xFFFFFFFF +#define BF_LCDIF_VDCTRL1_VSYNC_PERIOD(v) (v) +HW_REGISTER_0(HW_LCDIF_VDCTRL2, REGS_LCDIF_BASE, 0x00000090) +#define HW_LCDIF_VDCTRL2_ADDR (REGS_LCDIF_BASE + 0x00000090) +#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 24 +#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 0xFF000000 +#define BF_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(v) \ + (((v) << 24) & BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH) +#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD 0 +#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD 0x0003FFFF +#define BF_LCDIF_VDCTRL2_HSYNC_PERIOD(v) \ + (((v) << 0) & BM_LCDIF_VDCTRL2_HSYNC_PERIOD) +HW_REGISTER_0(HW_LCDIF_VDCTRL3, REGS_LCDIF_BASE, 0x000000a0) +#define HW_LCDIF_VDCTRL3_ADDR (REGS_LCDIF_BASE + 0x000000a0) +#define BM_LCDIF_VDCTRL3_MUX_SYNC_SIGNALS 0x20000000 +#define BM_LCDIF_VDCTRL3_VSYNC_ONLY 0x10000000 +#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 16 +#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 0x0FFF0000 +#define BF_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(v) \ + (((v) << 16) & BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT) +#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0 +#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0x0000FFFF +#define BF_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT(v) \ + (((v) << 0) & BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT) +HW_REGISTER_0(HW_LCDIF_VDCTRL4, REGS_LCDIF_BASE, 0x000000b0) +#define HW_LCDIF_VDCTRL4_ADDR (REGS_LCDIF_BASE + 0x000000b0) +#define BM_LCDIF_VDCTRL4_SYNC_SIGNALS_ON 0x00040000 +#define BP_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT 0 +#define BM_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT 0x0003FFFF +#define BF_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(v) \ + (((v) << 0) & BM_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT) +HW_REGISTER_0(HW_LCDIF_DVICTRL0, REGS_LCDIF_BASE, 0x000000c0) +#define HW_LCDIF_DVICTRL0_ADDR (REGS_LCDIF_BASE + 0x000000c0) +#define BM_LCDIF_DVICTRL0_START_TRS 0x80000000 +#define BP_LCDIF_DVICTRL0_H_ACTIVE_CNT 20 +#define BM_LCDIF_DVICTRL0_H_ACTIVE_CNT 0x7FF00000 +#define BF_LCDIF_DVICTRL0_H_ACTIVE_CNT(v) \ + (((v) << 20) & BM_LCDIF_DVICTRL0_H_ACTIVE_CNT) +#define BP_LCDIF_DVICTRL0_H_BLANKING_CNT 10 +#define BM_LCDIF_DVICTRL0_H_BLANKING_CNT 0x000FFC00 +#define BF_LCDIF_DVICTRL0_H_BLANKING_CNT(v) \ + (((v) << 10) & BM_LCDIF_DVICTRL0_H_BLANKING_CNT) +#define BP_LCDIF_DVICTRL0_V_LINES_CNT 0 +#define BM_LCDIF_DVICTRL0_V_LINES_CNT 0x000003FF +#define BF_LCDIF_DVICTRL0_V_LINES_CNT(v) \ + (((v) << 0) & BM_LCDIF_DVICTRL0_V_LINES_CNT) +HW_REGISTER_0(HW_LCDIF_DVICTRL1, REGS_LCDIF_BASE, 0x000000d0) +#define HW_LCDIF_DVICTRL1_ADDR (REGS_LCDIF_BASE + 0x000000d0) +#define BP_LCDIF_DVICTRL1_F1_START_LINE 20 +#define BM_LCDIF_DVICTRL1_F1_START_LINE 0x3FF00000 +#define BF_LCDIF_DVICTRL1_F1_START_LINE(v) \ + (((v) << 20) & BM_LCDIF_DVICTRL1_F1_START_LINE) +#define BP_LCDIF_DVICTRL1_F1_END_LINE 10 +#define BM_LCDIF_DVICTRL1_F1_END_LINE 0x000FFC00 +#define BF_LCDIF_DVICTRL1_F1_END_LINE(v) \ + (((v) << 10) & BM_LCDIF_DVICTRL1_F1_END_LINE) +#define BP_LCDIF_DVICTRL1_F2_START_LINE 0 +#define BM_LCDIF_DVICTRL1_F2_START_LINE 0x000003FF +#define BF_LCDIF_DVICTRL1_F2_START_LINE(v) \ + (((v) << 0) & BM_LCDIF_DVICTRL1_F2_START_LINE) +HW_REGISTER_0(HW_LCDIF_DVICTRL2, REGS_LCDIF_BASE, 0x000000e0) +#define HW_LCDIF_DVICTRL2_ADDR (REGS_LCDIF_BASE + 0x000000e0) +#define BP_LCDIF_DVICTRL2_F2_END_LINE 20 +#define BM_LCDIF_DVICTRL2_F2_END_LINE 0x3FF00000 +#define BF_LCDIF_DVICTRL2_F2_END_LINE(v) \ + (((v) << 20) & BM_LCDIF_DVICTRL2_F2_END_LINE) +#define BP_LCDIF_DVICTRL2_V1_BLANK_START_LINE 10 +#define BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE 0x000FFC00 +#define BF_LCDIF_DVICTRL2_V1_BLANK_START_LINE(v) \ + (((v) << 10) & BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE) +#define BP_LCDIF_DVICTRL2_V1_BLANK_END_LINE 0 +#define BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE 0x000003FF +#define BF_LCDIF_DVICTRL2_V1_BLANK_END_LINE(v) \ + (((v) << 0) & BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE) +HW_REGISTER_0(HW_LCDIF_DVICTRL3, REGS_LCDIF_BASE, 0x000000f0) +#define HW_LCDIF_DVICTRL3_ADDR (REGS_LCDIF_BASE + 0x000000f0) +#define BP_LCDIF_DVICTRL3_V2_BLANK_START_LINE 16 +#define BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE 0x03FF0000 +#define BF_LCDIF_DVICTRL3_V2_BLANK_START_LINE(v) \ + (((v) << 16) & BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE) +#define BP_LCDIF_DVICTRL3_V2_BLANK_END_LINE 0 +#define BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE 0x000003FF +#define BF_LCDIF_DVICTRL3_V2_BLANK_END_LINE(v) \ + (((v) << 0) & BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE) +HW_REGISTER_0(HW_LCDIF_DVICTRL4, REGS_LCDIF_BASE, 0x00000100) +#define HW_LCDIF_DVICTRL4_ADDR (REGS_LCDIF_BASE + 0x00000100) +#define BP_LCDIF_DVICTRL4_Y_FILL_VALUE 24 +#define BM_LCDIF_DVICTRL4_Y_FILL_VALUE 0xFF000000 +#define BF_LCDIF_DVICTRL4_Y_FILL_VALUE(v) \ + (((v) << 24) & BM_LCDIF_DVICTRL4_Y_FILL_VALUE) +#define BP_LCDIF_DVICTRL4_CB_FILL_VALUE 16 +#define BM_LCDIF_DVICTRL4_CB_FILL_VALUE 0x00FF0000 +#define BF_LCDIF_DVICTRL4_CB_FILL_VALUE(v) \ + (((v) << 16) & BM_LCDIF_DVICTRL4_CB_FILL_VALUE) +#define BP_LCDIF_DVICTRL4_CR_FILL_VALUE 8 +#define BM_LCDIF_DVICTRL4_CR_FILL_VALUE 0x0000FF00 +#define BF_LCDIF_DVICTRL4_CR_FILL_VALUE(v) \ + (((v) << 8) & BM_LCDIF_DVICTRL4_CR_FILL_VALUE) +#define BP_LCDIF_DVICTRL4_H_FILL_CNT 0 +#define BM_LCDIF_DVICTRL4_H_FILL_CNT 0x000000FF +#define BF_LCDIF_DVICTRL4_H_FILL_CNT(v) \ + (((v) << 0) & BM_LCDIF_DVICTRL4_H_FILL_CNT) +HW_REGISTER_0(HW_LCDIF_CSC_COEFF0, REGS_LCDIF_BASE, 0x00000110) +#define HW_LCDIF_CSC_COEFF0_ADDR (REGS_LCDIF_BASE + 0x00000110) +#define BP_LCDIF_CSC_COEFF0_C0 16 +#define BM_LCDIF_CSC_COEFF0_C0 0x03FF0000 +#define BF_LCDIF_CSC_COEFF0_C0(v) \ + (((v) << 16) & BM_LCDIF_CSC_COEFF0_C0) +#define BP_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER 0 +#define BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER 0x00000003 +#define BF_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(v) \ + (((v) << 0) & BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER) +#define BV_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__SAMPLE_AND_HOLD 0x0 +#define BV_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__RSRVD 0x1 +#define BV_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__INTERSTITIAL 0x2 +#define BV_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER__COSITED 0x3 +HW_REGISTER_0(HW_LCDIF_CSC_COEFF1, REGS_LCDIF_BASE, 0x00000120) +#define HW_LCDIF_CSC_COEFF1_ADDR (REGS_LCDIF_BASE + 0x00000120) +#define BP_LCDIF_CSC_COEFF1_C2 16 +#define BM_LCDIF_CSC_COEFF1_C2 0x03FF0000 +#define BF_LCDIF_CSC_COEFF1_C2(v) \ + (((v) << 16) & BM_LCDIF_CSC_COEFF1_C2) +#define BP_LCDIF_CSC_COEFF1_C1 0 +#define BM_LCDIF_CSC_COEFF1_C1 0x000003FF +#define BF_LCDIF_CSC_COEFF1_C1(v) \ + (((v) << 0) & BM_LCDIF_CSC_COEFF1_C1) +HW_REGISTER_0(HW_LCDIF_CSC_COEFF2, REGS_LCDIF_BASE, 0x00000130) +#define HW_LCDIF_CSC_COEFF2_ADDR (REGS_LCDIF_BASE + 0x00000130) +#define BP_LCDIF_CSC_COEFF2_C4 16 +#define BM_LCDIF_CSC_COEFF2_C4 0x03FF0000 +#define BF_LCDIF_CSC_COEFF2_C4(v) \ + (((v) << 16) & BM_LCDIF_CSC_COEFF2_C4) +#define BP_LCDIF_CSC_COEFF2_C3 0 +#define BM_LCDIF_CSC_COEFF2_C3 0x000003FF +#define BF_LCDIF_CSC_COEFF2_C3(v) \ + (((v) << 0) & BM_LCDIF_CSC_COEFF2_C3) +HW_REGISTER_0(HW_LCDIF_CSC_COEFF3, REGS_LCDIF_BASE, 0x00000140) +#define HW_LCDIF_CSC_COEFF3_ADDR (REGS_LCDIF_BASE + 0x00000140) +#define BP_LCDIF_CSC_COEFF3_C6 16 +#define BM_LCDIF_CSC_COEFF3_C6 0x03FF0000 +#define BF_LCDIF_CSC_COEFF3_C6(v) \ + (((v) << 16) & BM_LCDIF_CSC_COEFF3_C6) +#define BP_LCDIF_CSC_COEFF3_C5 0 +#define BM_LCDIF_CSC_COEFF3_C5 0x000003FF +#define BF_LCDIF_CSC_COEFF3_C5(v) \ + (((v) << 0) & BM_LCDIF_CSC_COEFF3_C5) +HW_REGISTER_0(HW_LCDIF_CSC_COEFF4, REGS_LCDIF_BASE, 0x00000150) +#define HW_LCDIF_CSC_COEFF4_ADDR (REGS_LCDIF_BASE + 0x00000150) +#define BP_LCDIF_CSC_COEFF4_C8 16 +#define BM_LCDIF_CSC_COEFF4_C8 0x03FF0000 +#define BF_LCDIF_CSC_COEFF4_C8(v) \ + (((v) << 16) & BM_LCDIF_CSC_COEFF4_C8) +#define BP_LCDIF_CSC_COEFF4_C7 0 +#define BM_LCDIF_CSC_COEFF4_C7 0x000003FF +#define BF_LCDIF_CSC_COEFF4_C7(v) \ + (((v) << 0) & BM_LCDIF_CSC_COEFF4_C7) +HW_REGISTER_0(HW_LCDIF_CSC_OFFSET, REGS_LCDIF_BASE, 0x00000160) +#define HW_LCDIF_CSC_OFFSET_ADDR (REGS_LCDIF_BASE + 0x00000160) +#define BP_LCDIF_CSC_OFFSET_CBCR_OFFSET 16 +#define BM_LCDIF_CSC_OFFSET_CBCR_OFFSET 0x01FF0000 +#define BF_LCDIF_CSC_OFFSET_CBCR_OFFSET(v) \ + (((v) << 16) & BM_LCDIF_CSC_OFFSET_CBCR_OFFSET) +#define BP_LCDIF_CSC_OFFSET_Y_OFFSET 0 +#define BM_LCDIF_CSC_OFFSET_Y_OFFSET 0x000001FF +#define BF_LCDIF_CSC_OFFSET_Y_OFFSET(v) \ + (((v) << 0) & BM_LCDIF_CSC_OFFSET_Y_OFFSET) +HW_REGISTER_0(HW_LCDIF_CSC_LIMIT, REGS_LCDIF_BASE, 0x00000170) +#define HW_LCDIF_CSC_LIMIT_ADDR (REGS_LCDIF_BASE + 0x00000170) +#define BP_LCDIF_CSC_LIMIT_CBCR_MIN 24 +#define BM_LCDIF_CSC_LIMIT_CBCR_MIN 0xFF000000 +#define BF_LCDIF_CSC_LIMIT_CBCR_MIN(v) \ + (((v) << 24) & BM_LCDIF_CSC_LIMIT_CBCR_MIN) +#define BP_LCDIF_CSC_LIMIT_CBCR_MAX 16 +#define BM_LCDIF_CSC_LIMIT_CBCR_MAX 0x00FF0000 +#define BF_LCDIF_CSC_LIMIT_CBCR_MAX(v) \ + (((v) << 16) & BM_LCDIF_CSC_LIMIT_CBCR_MAX) +#define BP_LCDIF_CSC_LIMIT_Y_MIN 8 +#define BM_LCDIF_CSC_LIMIT_Y_MIN 0x0000FF00 +#define BF_LCDIF_CSC_LIMIT_Y_MIN(v) \ + (((v) << 8) & BM_LCDIF_CSC_LIMIT_Y_MIN) +#define BP_LCDIF_CSC_LIMIT_Y_MAX 0 +#define BM_LCDIF_CSC_LIMIT_Y_MAX 0x000000FF +#define BF_LCDIF_CSC_LIMIT_Y_MAX(v) \ + (((v) << 0) & BM_LCDIF_CSC_LIMIT_Y_MAX) +HW_REGISTER(HW_LCDIF_PIN_SHARING_CTRL0, REGS_LCDIF_BASE, 0x00000180) +#define HW_LCDIF_PIN_SHARING_CTRL0_ADDR (REGS_LCDIF_BASE + 0x00000180) +#define BP_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE 4 +#define BM_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE 0x00000030 +#define BF_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE(v) \ + (((v) << 4) & BM_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE) +#define BV_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE__NO_OVERRIDE 0x0 +#define BV_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE__RSRVD 0x1 +#define BV_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE__LCDIF_SEL 0x2 +#define BV_LCDIF_PIN_SHARING_CTRL0_MUX_OVERRIDE__GPMI_SEL 0x3 +#define BM_LCDIF_PIN_SHARING_CTRL0_PIN_SHARING_IRQ_EN 0x00000004 +#define BM_LCDIF_PIN_SHARING_CTRL0_PIN_SHARING_IRQ 0x00000002 +#define BV_LCDIF_PIN_SHARING_CTRL0_PIN_SHARING_IRQ__NO_REQUEST 0x0 +#define BV_LCDIF_PIN_SHARING_CTRL0_PIN_SHARING_IRQ__REQUEST 0x1 +#define BM_LCDIF_PIN_SHARING_CTRL0_PIN_SHARING_ENABLE 0x00000001 +HW_REGISTER_0(HW_LCDIF_PIN_SHARING_CTRL1, REGS_LCDIF_BASE, 0x00000190) +#define HW_LCDIF_PIN_SHARING_CTRL1_ADDR (REGS_LCDIF_BASE + 0x00000190) +#define BP_LCDIF_PIN_SHARING_CTRL1_THRESHOLD1 0 +#define BM_LCDIF_PIN_SHARING_CTRL1_THRESHOLD1 0xFFFFFFFF +#define BF_LCDIF_PIN_SHARING_CTRL1_THRESHOLD1(v) (v) +HW_REGISTER_0(HW_LCDIF_PIN_SHARING_CTRL2, REGS_LCDIF_BASE, 0x000001a0) +#define HW_LCDIF_PIN_SHARING_CTRL2_ADDR (REGS_LCDIF_BASE + 0x000001a0) +#define BP_LCDIF_PIN_SHARING_CTRL2_THRESHOLD2 0 +#define BM_LCDIF_PIN_SHARING_CTRL2_THRESHOLD2 0xFFFFFFFF +#define BF_LCDIF_PIN_SHARING_CTRL2_THRESHOLD2(v) (v) +HW_REGISTER_0(HW_LCDIF_DATA, REGS_LCDIF_BASE, 0x000001b0) +#define HW_LCDIF_DATA_ADDR (REGS_LCDIF_BASE + 0x000001b0) +#define BP_LCDIF_DATA_DATA_THREE 24 +#define BM_LCDIF_DATA_DATA_THREE 0xFF000000 +#define BF_LCDIF_DATA_DATA_THREE(v) \ + (((v) << 24) & BM_LCDIF_DATA_DATA_THREE) +#define BP_LCDIF_DATA_DATA_TWO 16 +#define BM_LCDIF_DATA_DATA_TWO 0x00FF0000 +#define BF_LCDIF_DATA_DATA_TWO(v) \ + (((v) << 16) & BM_LCDIF_DATA_DATA_TWO) +#define BP_LCDIF_DATA_DATA_ONE 8 +#define BM_LCDIF_DATA_DATA_ONE 0x0000FF00 +#define BF_LCDIF_DATA_DATA_ONE(v) \ + (((v) << 8) & BM_LCDIF_DATA_DATA_ONE) +#define BP_LCDIF_DATA_DATA_ZERO 0 +#define BM_LCDIF_DATA_DATA_ZERO 0x000000FF +#define BF_LCDIF_DATA_DATA_ZERO(v) \ + (((v) << 0) & BM_LCDIF_DATA_DATA_ZERO) +HW_REGISTER_0(HW_LCDIF_BM_ERROR_STAT, REGS_LCDIF_BASE, 0x000001c0) +#define HW_LCDIF_BM_ERROR_STAT_ADDR (REGS_LCDIF_BASE + 0x000001c0) +#define BP_LCDIF_BM_ERROR_STAT_ADDR 0 +#define BM_LCDIF_BM_ERROR_STAT_ADDR 0xFFFFFFFF +#define BF_LCDIF_BM_ERROR_STAT_ADDR(v) (v) +HW_REGISTER_0(HW_LCDIF_STAT, REGS_LCDIF_BASE, 0x000001d0) +#define HW_LCDIF_STAT_ADDR (REGS_LCDIF_BASE + 0x000001d0) +#define BM_LCDIF_STAT_PRESENT 0x80000000 +#define BM_LCDIF_STAT_DMA_REQ 0x40000000 +#define BM_LCDIF_STAT_LFIFO_FULL 0x20000000 +#define BM_LCDIF_STAT_LFIFO_EMPTY 0x10000000 +#define BM_LCDIF_STAT_TXFIFO_FULL 0x08000000 +#define BM_LCDIF_STAT_TXFIFO_EMPTY 0x04000000 +#define BM_LCDIF_STAT_BUSY 0x02000000 +#define BM_LCDIF_STAT_DVI_CURRENT_FIELD 0x01000000 +HW_REGISTER_0(HW_LCDIF_VERSION, REGS_LCDIF_BASE, 0x000001e0) +#define HW_LCDIF_VERSION_ADDR (REGS_LCDIF_BASE + 0x000001e0) +#define BP_LCDIF_VERSION_MAJOR 24 +#define BM_LCDIF_VERSION_MAJOR 0xFF000000 +#define BF_LCDIF_VERSION_MAJOR(v) \ + (((v) << 24) & BM_LCDIF_VERSION_MAJOR) +#define BP_LCDIF_VERSION_MINOR 16 +#define BM_LCDIF_VERSION_MINOR 0x00FF0000 +#define BF_LCDIF_VERSION_MINOR(v) \ + (((v) << 16) & BM_LCDIF_VERSION_MINOR) +#define BP_LCDIF_VERSION_STEP 0 +#define BM_LCDIF_VERSION_STEP 0x0000FFFF +#define BF_LCDIF_VERSION_STEP(v) \ + (((v) << 0) & BM_LCDIF_VERSION_STEP) +HW_REGISTER_0(HW_LCDIF_DEBUG0, REGS_LCDIF_BASE, 0x000001f0) +#define HW_LCDIF_DEBUG0_ADDR (REGS_LCDIF_BASE + 0x000001f0) +#define BM_LCDIF_DEBUG0_STREAMING_END_DETECTED 0x80000000 +#define BM_LCDIF_DEBUG0_WAIT_FOR_VSYNC_EDGE_OUT 0x40000000 +#define BM_LCDIF_DEBUG0_SYNC_SIGNALS_ON_REG 0x20000000 +#define BM_LCDIF_DEBUG0_DMACMDKICK 0x10000000 +#define BM_LCDIF_DEBUG0_ENABLE 0x08000000 +#define BM_LCDIF_DEBUG0_HSYNC 0x04000000 +#define BM_LCDIF_DEBUG0_VSYNC 0x02000000 +#define BM_LCDIF_DEBUG0_CUR_FRAME_TX 0x01000000 +#define BM_LCDIF_DEBUG0_EMPTY_WORD 0x00800000 +#define BP_LCDIF_DEBUG0_CUR_STATE 16 +#define BM_LCDIF_DEBUG0_CUR_STATE 0x007F0000 +#define BF_LCDIF_DEBUG0_CUR_STATE(v) \ + (((v) << 16) & BM_LCDIF_DEBUG0_CUR_STATE) +#define BM_LCDIF_DEBUG0_PXP_LCDIF_B0_READY 0x00008000 +#define BM_LCDIF_DEBUG0_LCDIF_PXP_B0_DONE 0x00004000 +#define BM_LCDIF_DEBUG0_PXP_LCDIF_B1_READY 0x00002000 +#define BM_LCDIF_DEBUG0_LCDIF_PXP_B1_DONE 0x00001000 +#define BM_LCDIF_DEBUG0_GPMI_LCDIF_REQ 0x00000800 +#define BM_LCDIF_DEBUG0_LCDIF_GPMI_GRANT 0x00000400 +HW_REGISTER_0(HW_LCDIF_DEBUG1, REGS_LCDIF_BASE, 0x00000200) +#define HW_LCDIF_DEBUG1_ADDR (REGS_LCDIF_BASE + 0x00000200) +#define BP_LCDIF_DEBUG1_H_DATA_COUNT 16 +#define BM_LCDIF_DEBUG1_H_DATA_COUNT 0xFFFF0000 +#define BF_LCDIF_DEBUG1_H_DATA_COUNT(v) \ + (((v) << 16) & BM_LCDIF_DEBUG1_H_DATA_COUNT) +#define BP_LCDIF_DEBUG1_V_DATA_COUNT 0 +#define BM_LCDIF_DEBUG1_V_DATA_COUNT 0x0000FFFF +#define BF_LCDIF_DEBUG1_V_DATA_COUNT(v) \ + (((v) << 0) & BM_LCDIF_DEBUG1_V_DATA_COUNT) +#endif /* __ARCH_ARM___LCDIF_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-lradc.h b/arch/arm/mach-stmp3xxx/include/mach/regs-lradc.h new file mode 100644 index 000000000000..cf71a09b3ff9 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-lradc.h @@ -0,0 +1,520 @@ +/* + * STMP LRADC Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___LRADC_H +#define __ARCH_ARM___LRADC_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_LRADC_BASE (REGS_BASE + 0x50000) +#define REGS_LRADC_BASE_PHYS (0x80050000) +#define REGS_LRADC_SIZE 0x00002000 +HW_REGISTER(HW_LRADC_CTRL0, REGS_LRADC_BASE, 0x00000000) +#define HW_LRADC_CTRL0_ADDR (REGS_LRADC_BASE + 0x00000000) +#define BM_LRADC_CTRL0_SFTRST 0x80000000 +#define BM_LRADC_CTRL0_CLKGATE 0x40000000 +#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF 0x00200000 +#define BV_LRADC_CTRL0_ONCHIP_GROUNDREF__OFF 0x0 +#define BV_LRADC_CTRL0_ONCHIP_GROUNDREF__ON 0x1 +#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE 0x00100000 +#define BV_LRADC_CTRL0_TOUCH_DETECT_ENABLE__OFF 0x0 +#define BV_LRADC_CTRL0_TOUCH_DETECT_ENABLE__ON 0x1 +#define BM_LRADC_CTRL0_YMINUS_ENABLE 0x00080000 +#define BV_LRADC_CTRL0_YMINUS_ENABLE__OFF 0x0 +#define BV_LRADC_CTRL0_YMINUS_ENABLE__ON 0x1 +#define BM_LRADC_CTRL0_XMINUS_ENABLE 0x00040000 +#define BV_LRADC_CTRL0_XMINUS_ENABLE__OFF 0x0 +#define BV_LRADC_CTRL0_XMINUS_ENABLE__ON 0x1 +#define BM_LRADC_CTRL0_YPLUS_ENABLE 0x00020000 +#define BV_LRADC_CTRL0_YPLUS_ENABLE__OFF 0x0 +#define BV_LRADC_CTRL0_YPLUS_ENABLE__ON 0x1 +#define BM_LRADC_CTRL0_XPLUS_ENABLE 0x00010000 +#define BV_LRADC_CTRL0_XPLUS_ENABLE__OFF 0x0 +#define BV_LRADC_CTRL0_XPLUS_ENABLE__ON 0x1 +#define BP_LRADC_CTRL0_SCHEDULE 0 +#define BM_LRADC_CTRL0_SCHEDULE 0x000000FF +#define BF_LRADC_CTRL0_SCHEDULE(v) \ + (((v) << 0) & BM_LRADC_CTRL0_SCHEDULE) +HW_REGISTER(HW_LRADC_CTRL1, REGS_LRADC_BASE, 0x00000010) +#define HW_LRADC_CTRL1_ADDR (REGS_LRADC_BASE + 0x00000010) +#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN 0x01000000 +#define BV_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC7_IRQ_EN 0x00800000 +#define BV_LRADC_CTRL1_LRADC7_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC7_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC6_IRQ_EN 0x00400000 +#define BV_LRADC_CTRL1_LRADC6_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC6_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC5_IRQ_EN 0x00200000 +#define BV_LRADC_CTRL1_LRADC5_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC5_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC4_IRQ_EN 0x00100000 +#define BV_LRADC_CTRL1_LRADC4_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC4_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC3_IRQ_EN 0x00080000 +#define BV_LRADC_CTRL1_LRADC3_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC3_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC2_IRQ_EN 0x00040000 +#define BV_LRADC_CTRL1_LRADC2_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC2_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC1_IRQ_EN 0x00020000 +#define BV_LRADC_CTRL1_LRADC1_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC1_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_LRADC0_IRQ_EN 0x00010000 +#define BV_LRADC_CTRL1_LRADC0_IRQ_EN__DISABLE 0x0 +#define BV_LRADC_CTRL1_LRADC0_IRQ_EN__ENABLE 0x1 +#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ 0x00000100 +#define BV_LRADC_CTRL1_TOUCH_DETECT_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_TOUCH_DETECT_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC7_IRQ 0x00000080 +#define BV_LRADC_CTRL1_LRADC7_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC7_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC6_IRQ 0x00000040 +#define BV_LRADC_CTRL1_LRADC6_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC6_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC5_IRQ 0x00000020 +#define BV_LRADC_CTRL1_LRADC5_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC5_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC4_IRQ 0x00000010 +#define BV_LRADC_CTRL1_LRADC4_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC4_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC3_IRQ 0x00000008 +#define BV_LRADC_CTRL1_LRADC3_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC3_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC2_IRQ 0x00000004 +#define BV_LRADC_CTRL1_LRADC2_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC2_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC1_IRQ 0x00000002 +#define BV_LRADC_CTRL1_LRADC1_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC1_IRQ__PENDING 0x1 +#define BM_LRADC_CTRL1_LRADC0_IRQ 0x00000001 +#define BV_LRADC_CTRL1_LRADC0_IRQ__CLEAR 0x0 +#define BV_LRADC_CTRL1_LRADC0_IRQ__PENDING 0x1 +HW_REGISTER(HW_LRADC_CTRL2, REGS_LRADC_BASE, 0x00000020) +#define HW_LRADC_CTRL2_ADDR (REGS_LRADC_BASE + 0x00000020) +#define BP_LRADC_CTRL2_DIVIDE_BY_TWO 24 +#define BM_LRADC_CTRL2_DIVIDE_BY_TWO 0xFF000000 +#define BF_LRADC_CTRL2_DIVIDE_BY_TWO(v) \ + (((v) << 24) & BM_LRADC_CTRL2_DIVIDE_BY_TWO) +#define BM_LRADC_CTRL2_BL_AMP_BYPASS 0x00800000 +#define BV_LRADC_CTRL2_BL_AMP_BYPASS__DISABLE 0x0 +#define BV_LRADC_CTRL2_BL_AMP_BYPASS__ENABLE 0x1 +#define BM_LRADC_CTRL2_BL_ENABLE 0x00400000 +#define BM_LRADC_CTRL2_BL_MUX_SELECT 0x00200000 +#define BP_LRADC_CTRL2_BL_BRIGHTNESS 16 +#define BM_LRADC_CTRL2_BL_BRIGHTNESS 0x001F0000 +#define BF_LRADC_CTRL2_BL_BRIGHTNESS(v) \ + (((v) << 16) & BM_LRADC_CTRL2_BL_BRIGHTNESS) +#define BM_LRADC_CTRL2_TEMPSENSE_PWD 0x00008000 +#define BV_LRADC_CTRL2_TEMPSENSE_PWD__ENABLE 0x0 +#define BV_LRADC_CTRL2_TEMPSENSE_PWD__DISABLE 0x1 +#define BM_LRADC_CTRL2_EXT_EN1 0x00002000 +#define BV_LRADC_CTRL2_EXT_EN1__DISABLE 0x0 +#define BV_LRADC_CTRL2_EXT_EN1__ENABLE 0x1 +#define BM_LRADC_CTRL2_EXT_EN0 0x00001000 +#define BM_LRADC_CTRL2_TEMP_SENSOR_IENABLE1 0x00000200 +#define BV_LRADC_CTRL2_TEMP_SENSOR_IENABLE1__DISABLE 0x0 +#define BV_LRADC_CTRL2_TEMP_SENSOR_IENABLE1__ENABLE 0x1 +#define BM_LRADC_CTRL2_TEMP_SENSOR_IENABLE0 0x00000100 +#define BV_LRADC_CTRL2_TEMP_SENSOR_IENABLE0__DISABLE 0x0 +#define BV_LRADC_CTRL2_TEMP_SENSOR_IENABLE0__ENABLE 0x1 +#define BP_LRADC_CTRL2_TEMP_ISRC1 4 +#define BM_LRADC_CTRL2_TEMP_ISRC1 0x000000F0 +#define BF_LRADC_CTRL2_TEMP_ISRC1(v) \ + (((v) << 4) & BM_LRADC_CTRL2_TEMP_ISRC1) +#define BV_LRADC_CTRL2_TEMP_ISRC1__300 0xF +#define BV_LRADC_CTRL2_TEMP_ISRC1__280 0xE +#define BV_LRADC_CTRL2_TEMP_ISRC1__260 0xD +#define BV_LRADC_CTRL2_TEMP_ISRC1__240 0xC +#define BV_LRADC_CTRL2_TEMP_ISRC1__220 0xB +#define BV_LRADC_CTRL2_TEMP_ISRC1__200 0xA +#define BV_LRADC_CTRL2_TEMP_ISRC1__180 0x9 +#define BV_LRADC_CTRL2_TEMP_ISRC1__160 0x8 +#define BV_LRADC_CTRL2_TEMP_ISRC1__140 0x7 +#define BV_LRADC_CTRL2_TEMP_ISRC1__120 0x6 +#define BV_LRADC_CTRL2_TEMP_ISRC1__100 0x5 +#define BV_LRADC_CTRL2_TEMP_ISRC1__80 0x4 +#define BV_LRADC_CTRL2_TEMP_ISRC1__60 0x3 +#define BV_LRADC_CTRL2_TEMP_ISRC1__40 0x2 +#define BV_LRADC_CTRL2_TEMP_ISRC1__20 0x1 +#define BV_LRADC_CTRL2_TEMP_ISRC1__ZERO 0x0 +#define BP_LRADC_CTRL2_TEMP_ISRC0 0 +#define BM_LRADC_CTRL2_TEMP_ISRC0 0x0000000F +#define BF_LRADC_CTRL2_TEMP_ISRC0(v) \ + (((v) << 0) & BM_LRADC_CTRL2_TEMP_ISRC0) +#define BV_LRADC_CTRL2_TEMP_ISRC0__300 0xF +#define BV_LRADC_CTRL2_TEMP_ISRC0__280 0xE +#define BV_LRADC_CTRL2_TEMP_ISRC0__260 0xD +#define BV_LRADC_CTRL2_TEMP_ISRC0__240 0xC +#define BV_LRADC_CTRL2_TEMP_ISRC0__220 0xB +#define BV_LRADC_CTRL2_TEMP_ISRC0__200 0xA +#define BV_LRADC_CTRL2_TEMP_ISRC0__180 0x9 +#define BV_LRADC_CTRL2_TEMP_ISRC0__160 0x8 +#define BV_LRADC_CTRL2_TEMP_ISRC0__140 0x7 +#define BV_LRADC_CTRL2_TEMP_ISRC0__120 0x6 +#define BV_LRADC_CTRL2_TEMP_ISRC0__100 0x5 +#define BV_LRADC_CTRL2_TEMP_ISRC0__80 0x4 +#define BV_LRADC_CTRL2_TEMP_ISRC0__60 0x3 +#define BV_LRADC_CTRL2_TEMP_ISRC0__40 0x2 +#define BV_LRADC_CTRL2_TEMP_ISRC0__20 0x1 +#define BV_LRADC_CTRL2_TEMP_ISRC0__ZERO 0x0 +HW_REGISTER(HW_LRADC_CTRL3, REGS_LRADC_BASE, 0x00000030) +#define HW_LRADC_CTRL3_ADDR (REGS_LRADC_BASE + 0x00000030) +#define BP_LRADC_CTRL3_DISCARD 24 +#define BM_LRADC_CTRL3_DISCARD 0x03000000 +#define BF_LRADC_CTRL3_DISCARD(v) \ + (((v) << 24) & BM_LRADC_CTRL3_DISCARD) +#define BV_LRADC_CTRL3_DISCARD__1_SAMPLE 0x1 +#define BV_LRADC_CTRL3_DISCARD__2_SAMPLES 0x2 +#define BV_LRADC_CTRL3_DISCARD__3_SAMPLES 0x3 +#define BM_LRADC_CTRL3_FORCE_ANALOG_PWUP 0x00800000 +#define BV_LRADC_CTRL3_FORCE_ANALOG_PWUP__OFF 0x0 +#define BV_LRADC_CTRL3_FORCE_ANALOG_PWUP__ON 0x1 +#define BM_LRADC_CTRL3_FORCE_ANALOG_PWDN 0x00400000 +#define BV_LRADC_CTRL3_FORCE_ANALOG_PWDN__ON 0x0 +#define BV_LRADC_CTRL3_FORCE_ANALOG_PWDN__OFF 0x1 +#define BP_LRADC_CTRL3_CYCLE_TIME 8 +#define BM_LRADC_CTRL3_CYCLE_TIME 0x00000300 +#define BF_LRADC_CTRL3_CYCLE_TIME(v) \ + (((v) << 8) & BM_LRADC_CTRL3_CYCLE_TIME) +#define BV_LRADC_CTRL3_CYCLE_TIME__6MHZ 0x0 +#define BV_LRADC_CTRL3_CYCLE_TIME__4MHZ 0x1 +#define BV_LRADC_CTRL3_CYCLE_TIME__3MHZ 0x2 +#define BV_LRADC_CTRL3_CYCLE_TIME__2MHZ 0x3 +#define BP_LRADC_CTRL3_HIGH_TIME 4 +#define BM_LRADC_CTRL3_HIGH_TIME 0x00000030 +#define BF_LRADC_CTRL3_HIGH_TIME(v) \ + (((v) << 4) & BM_LRADC_CTRL3_HIGH_TIME) +#define BV_LRADC_CTRL3_HIGH_TIME__42NS 0x0 +#define BV_LRADC_CTRL3_HIGH_TIME__83NS 0x1 +#define BV_LRADC_CTRL3_HIGH_TIME__125NS 0x2 +#define BV_LRADC_CTRL3_HIGH_TIME__250NS 0x3 +#define BM_LRADC_CTRL3_DELAY_CLOCK 0x00000002 +#define BV_LRADC_CTRL3_DELAY_CLOCK__NORMAL 0x0 +#define BV_LRADC_CTRL3_DELAY_CLOCK__DELAYED 0x1 +#define BM_LRADC_CTRL3_INVERT_CLOCK 0x00000001 +#define BV_LRADC_CTRL3_INVERT_CLOCK__NORMAL 0x0 +#define BV_LRADC_CTRL3_INVERT_CLOCK__INVERT 0x1 +HW_REGISTER(HW_LRADC_STATUS, REGS_LRADC_BASE, 0x00000040) +#define HW_LRADC_STATUS_ADDR (REGS_LRADC_BASE + 0x00000040) +#define BM_LRADC_STATUS_TEMP1_PRESENT 0x04000000 +#define BM_LRADC_STATUS_TEMP0_PRESENT 0x02000000 +#define BM_LRADC_STATUS_TOUCH_PANEL_PRESENT 0x01000000 +#define BM_LRADC_STATUS_CHANNEL7_PRESENT 0x00800000 +#define BM_LRADC_STATUS_CHANNEL6_PRESENT 0x00400000 +#define BM_LRADC_STATUS_CHANNEL5_PRESENT 0x00200000 +#define BM_LRADC_STATUS_CHANNEL4_PRESENT 0x00100000 +#define BM_LRADC_STATUS_CHANNEL3_PRESENT 0x00080000 +#define BM_LRADC_STATUS_CHANNEL2_PRESENT 0x00040000 +#define BM_LRADC_STATUS_CHANNEL1_PRESENT 0x00020000 +#define BM_LRADC_STATUS_CHANNEL0_PRESENT 0x00010000 +#define BM_LRADC_STATUS_TOUCH_DETECT_RAW 0x00000001 +#define BV_LRADC_STATUS_TOUCH_DETECT_RAW__OPEN 0x0 +#define BV_LRADC_STATUS_TOUCH_DETECT_RAW__HIT 0x1 +/* + * multi-register-define name HW_LRADC_CHn + * base 0x00000050 + * count 6 + * offset 0x10 + */ +HW_REGISTER_INDEXED(HW_LRADC_CHn, REGS_LRADC_BASE, 0x00000050, 0x10) +#define BM_LRADC_CHn_TOGGLE 0x80000000 +#define BM_LRADC_CHn_ACCUMULATE 0x20000000 +#define BP_LRADC_CHn_NUM_SAMPLES 24 +#define BM_LRADC_CHn_NUM_SAMPLES 0x1F000000 +#define BF_LRADC_CHn_NUM_SAMPLES(v) \ + (((v) << 24) & BM_LRADC_CHn_NUM_SAMPLES) +#define BP_LRADC_CHn_VALUE 0 +#define BM_LRADC_CHn_VALUE 0x0003FFFF +#define BF_LRADC_CHn_VALUE(v) \ + (((v) << 0) & BM_LRADC_CHn_VALUE) +HW_REGISTER(HW_LRADC_CH6, REGS_LRADC_BASE, 0x000000b0) +#define HW_LRADC_CH6_ADDR (REGS_LRADC_BASE + 0x000000b0) +#define BM_LRADC_CH6_TOGGLE 0x80000000 +#define BM_LRADC_CH6_ACCUMULATE 0x20000000 +#define BP_LRADC_CH6_NUM_SAMPLES 24 +#define BM_LRADC_CH6_NUM_SAMPLES 0x1F000000 +#define BF_LRADC_CH6_NUM_SAMPLES(v) \ + (((v) << 24) & BM_LRADC_CH6_NUM_SAMPLES) +#define BP_LRADC_CH6_VALUE 0 +#define BM_LRADC_CH6_VALUE 0x0003FFFF +#define BF_LRADC_CH6_VALUE(v) \ + (((v) << 0) & BM_LRADC_CH6_VALUE) +HW_REGISTER(HW_LRADC_CH7, REGS_LRADC_BASE, 0x000000c0) +#define HW_LRADC_CH7_ADDR (REGS_LRADC_BASE + 0x000000c0) +#define BM_LRADC_CH7_TOGGLE 0x80000000 +#define BM_LRADC_CH7_TESTMODE_TOGGLE 0x40000000 +#define BM_LRADC_CH7_ACCUMULATE 0x20000000 +#define BP_LRADC_CH7_NUM_SAMPLES 24 +#define BM_LRADC_CH7_NUM_SAMPLES 0x1F000000 +#define BF_LRADC_CH7_NUM_SAMPLES(v) \ + (((v) << 24) & BM_LRADC_CH7_NUM_SAMPLES) +#define BP_LRADC_CH7_VALUE 0 +#define BM_LRADC_CH7_VALUE 0x0003FFFF +#define BF_LRADC_CH7_VALUE(v) \ + (((v) << 0) & BM_LRADC_CH7_VALUE) +/* + * multi-register-define name HW_LRADC_DELAYn + * base 0x000000D0 + * count 4 + * offset 0x10 + */ +HW_REGISTER_INDEXED(HW_LRADC_DELAYn, REGS_LRADC_BASE, 0x000000d0, 0x10) +#define BP_LRADC_DELAYn_TRIGGER_LRADCS 24 +#define BM_LRADC_DELAYn_TRIGGER_LRADCS 0xFF000000 +#define BF_LRADC_DELAYn_TRIGGER_LRADCS(v) \ + (((v) << 24) & BM_LRADC_DELAYn_TRIGGER_LRADCS) +#define BM_LRADC_DELAYn_KICK 0x00100000 +#define BP_LRADC_DELAYn_TRIGGER_DELAYS 16 +#define BM_LRADC_DELAYn_TRIGGER_DELAYS 0x000F0000 +#define BF_LRADC_DELAYn_TRIGGER_DELAYS(v) \ + (((v) << 16) & BM_LRADC_DELAYn_TRIGGER_DELAYS) +#define BP_LRADC_DELAYn_LOOP_COUNT 11 +#define BM_LRADC_DELAYn_LOOP_COUNT 0x0000F800 +#define BF_LRADC_DELAYn_LOOP_COUNT(v) \ + (((v) << 11) & BM_LRADC_DELAYn_LOOP_COUNT) +#define BP_LRADC_DELAYn_DELAY 0 +#define BM_LRADC_DELAYn_DELAY 0x000007FF +#define BF_LRADC_DELAYn_DELAY(v) \ + (((v) << 0) & BM_LRADC_DELAYn_DELAY) +HW_REGISTER(HW_LRADC_DEBUG0, REGS_LRADC_BASE, 0x00000110) +#define HW_LRADC_DEBUG0_ADDR (REGS_LRADC_BASE + 0x00000110) +#define BP_LRADC_DEBUG0_READONLY 16 +#define BM_LRADC_DEBUG0_READONLY 0xFFFF0000 +#define BF_LRADC_DEBUG0_READONLY(v) \ + (((v) << 16) & BM_LRADC_DEBUG0_READONLY) +#define BP_LRADC_DEBUG0_STATE 0 +#define BM_LRADC_DEBUG0_STATE 0x00000FFF +#define BF_LRADC_DEBUG0_STATE(v) \ + (((v) << 0) & BM_LRADC_DEBUG0_STATE) +HW_REGISTER(HW_LRADC_DEBUG1, REGS_LRADC_BASE, 0x00000120) +#define HW_LRADC_DEBUG1_ADDR (REGS_LRADC_BASE + 0x00000120) +#define BP_LRADC_DEBUG1_REQUEST 16 +#define BM_LRADC_DEBUG1_REQUEST 0x00FF0000 +#define BF_LRADC_DEBUG1_REQUEST(v) \ + (((v) << 16) & BM_LRADC_DEBUG1_REQUEST) +#define BP_LRADC_DEBUG1_TESTMODE_COUNT 8 +#define BM_LRADC_DEBUG1_TESTMODE_COUNT 0x00001F00 +#define BF_LRADC_DEBUG1_TESTMODE_COUNT(v) \ + (((v) << 8) & BM_LRADC_DEBUG1_TESTMODE_COUNT) +#define BM_LRADC_DEBUG1_TESTMODE6 0x00000004 +#define BV_LRADC_DEBUG1_TESTMODE6__NORMAL 0x0 +#define BV_LRADC_DEBUG1_TESTMODE6__TEST 0x1 +#define BM_LRADC_DEBUG1_TESTMODE5 0x00000002 +#define BV_LRADC_DEBUG1_TESTMODE5__NORMAL 0x0 +#define BV_LRADC_DEBUG1_TESTMODE5__TEST 0x1 +#define BM_LRADC_DEBUG1_TESTMODE 0x00000001 +#define BV_LRADC_DEBUG1_TESTMODE__NORMAL 0x0 +#define BV_LRADC_DEBUG1_TESTMODE__TEST 0x1 +HW_REGISTER(HW_LRADC_CONVERSION, REGS_LRADC_BASE, 0x00000130) +#define HW_LRADC_CONVERSION_ADDR (REGS_LRADC_BASE + 0x00000130) +#define BM_LRADC_CONVERSION_AUTOMATIC 0x00100000 +#define BV_LRADC_CONVERSION_AUTOMATIC__DISABLE 0x0 +#define BV_LRADC_CONVERSION_AUTOMATIC__ENABLE 0x1 +#define BP_LRADC_CONVERSION_SCALE_FACTOR 16 +#define BM_LRADC_CONVERSION_SCALE_FACTOR 0x00030000 +#define BF_LRADC_CONVERSION_SCALE_FACTOR(v) \ + (((v) << 16) & BM_LRADC_CONVERSION_SCALE_FACTOR) +#define BV_LRADC_CONVERSION_SCALE_FACTOR__NIMH 0x0 +#define BV_LRADC_CONVERSION_SCALE_FACTOR__DUAL_NIMH 0x1 +#define BV_LRADC_CONVERSION_SCALE_FACTOR__LI_ION 0x2 +#define BV_LRADC_CONVERSION_SCALE_FACTOR__ALT_LI_ION 0x3 +#define BP_LRADC_CONVERSION_SCALED_BATT_VOLTAGE 0 +#define BM_LRADC_CONVERSION_SCALED_BATT_VOLTAGE 0x000003FF +#define BF_LRADC_CONVERSION_SCALED_BATT_VOLTAGE(v) \ + (((v) << 0) & BM_LRADC_CONVERSION_SCALED_BATT_VOLTAGE) +HW_REGISTER(HW_LRADC_CTRL4, REGS_LRADC_BASE, 0x00000140) +#define HW_LRADC_CTRL4_ADDR (REGS_LRADC_BASE + 0x00000140) +#define BP_LRADC_CTRL4_LRADC7SELECT 28 +#define BM_LRADC_CTRL4_LRADC7SELECT 0xF0000000 +#define BF_LRADC_CTRL4_LRADC7SELECT(v) \ + (((v) << 28) & BM_LRADC_CTRL4_LRADC7SELECT) +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC7SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC6SELECT 24 +#define BM_LRADC_CTRL4_LRADC6SELECT 0x0F000000 +#define BF_LRADC_CTRL4_LRADC6SELECT(v) \ + (((v) << 24) & BM_LRADC_CTRL4_LRADC6SELECT) +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC5SELECT 20 +#define BM_LRADC_CTRL4_LRADC5SELECT 0x00F00000 +#define BF_LRADC_CTRL4_LRADC5SELECT(v) \ + (((v) << 20) & BM_LRADC_CTRL4_LRADC5SELECT) +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC5SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC4SELECT 16 +#define BM_LRADC_CTRL4_LRADC4SELECT 0x000F0000 +#define BF_LRADC_CTRL4_LRADC4SELECT(v) \ + (((v) << 16) & BM_LRADC_CTRL4_LRADC4SELECT) +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC4SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC3SELECT 12 +#define BM_LRADC_CTRL4_LRADC3SELECT 0x0000F000 +#define BF_LRADC_CTRL4_LRADC3SELECT(v) \ + (((v) << 12) & BM_LRADC_CTRL4_LRADC3SELECT) +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC3SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC2SELECT 8 +#define BM_LRADC_CTRL4_LRADC2SELECT 0x00000F00 +#define BF_LRADC_CTRL4_LRADC2SELECT(v) \ + (((v) << 8) & BM_LRADC_CTRL4_LRADC2SELECT) +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC2SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC1SELECT 4 +#define BM_LRADC_CTRL4_LRADC1SELECT 0x000000F0 +#define BF_LRADC_CTRL4_LRADC1SELECT(v) \ + (((v) << 4) & BM_LRADC_CTRL4_LRADC1SELECT) +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC1SELECT__CHANNEL15 0xF +#define BP_LRADC_CTRL4_LRADC0SELECT 0 +#define BM_LRADC_CTRL4_LRADC0SELECT 0x0000000F +#define BF_LRADC_CTRL4_LRADC0SELECT(v) \ + (((v) << 0) & BM_LRADC_CTRL4_LRADC0SELECT) +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL0 0x0 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL1 0x1 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL2 0x2 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL3 0x3 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL4 0x4 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL5 0x5 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL6 0x6 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL7 0x7 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL8 0x8 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL9 0x9 +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL10 0xA +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL11 0xB +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL12 0xC +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL13 0xD +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL14 0xE +#define BV_LRADC_CTRL4_LRADC0SELECT__CHANNEL15 0xF +HW_REGISTER_0(HW_LRADC_VERSION, REGS_LRADC_BASE, 0x00000150) +#define HW_LRADC_VERSION_ADDR (REGS_LRADC_BASE + 0x00000150) +#define BP_LRADC_VERSION_MAJOR 24 +#define BM_LRADC_VERSION_MAJOR 0xFF000000 +#define BF_LRADC_VERSION_MAJOR(v) \ + (((v) << 24) & BM_LRADC_VERSION_MAJOR) +#define BP_LRADC_VERSION_MINOR 16 +#define BM_LRADC_VERSION_MINOR 0x00FF0000 +#define BF_LRADC_VERSION_MINOR(v) \ + (((v) << 16) & BM_LRADC_VERSION_MINOR) +#define BP_LRADC_VERSION_STEP 0 +#define BM_LRADC_VERSION_STEP 0x0000FFFF +#define BF_LRADC_VERSION_STEP(v) \ + (((v) << 0) & BM_LRADC_VERSION_STEP) +#endif /* __ARCH_ARM___LRADC_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-ocotp.h b/arch/arm/mach-stmp3xxx/include/mach/regs-ocotp.h new file mode 100644 index 000000000000..97358459689c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-ocotp.h @@ -0,0 +1,166 @@ +/* + * STMP OCOTP Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___OCOTP_H +#define __ARCH_ARM___OCOTP_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_OCOTP_BASE (REGS_BASE + 0x2c000) +#define REGS_OCOTP_BASE_PHYS (0x8002C000) +#define REGS_OCOTP_SIZE 0x00002000 +HW_REGISTER(HW_OCOTP_CTRL, REGS_OCOTP_BASE, 0x00000000) +#define HW_OCOTP_CTRL_ADDR (REGS_OCOTP_BASE + 0x00000000) +#define BP_OCOTP_CTRL_WR_UNLOCK 16 +#define BM_OCOTP_CTRL_WR_UNLOCK 0xFFFF0000 +#define BF_OCOTP_CTRL_WR_UNLOCK(v) \ + (((v) << 16) & BM_OCOTP_CTRL_WR_UNLOCK) +#define BV_OCOTP_CTRL_WR_UNLOCK__KEY 0x3E77 +#define BM_OCOTP_CTRL_RELOAD_SHADOWS 0x00002000 +#define BM_OCOTP_CTRL_RD_BANK_OPEN 0x00001000 +#define BM_OCOTP_CTRL_ERROR 0x00000200 +#define BM_OCOTP_CTRL_BUSY 0x00000100 +#define BP_OCOTP_CTRL_ADDR 0 +#define BM_OCOTP_CTRL_ADDR 0x0000001F +#define BF_OCOTP_CTRL_ADDR(v) \ + (((v) << 0) & BM_OCOTP_CTRL_ADDR) +HW_REGISTER_0(HW_OCOTP_DATA, REGS_OCOTP_BASE, 0x00000010) +#define HW_OCOTP_DATA_ADDR (REGS_OCOTP_BASE + 0x00000010) +#define BP_OCOTP_DATA_DATA 0 +#define BM_OCOTP_DATA_DATA 0xFFFFFFFF +#define BF_OCOTP_DATA_DATA(v) (v) +/* + * multi-register-define name HW_OCOTP_CUSTn + * base 0x00000020 + * count 4 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_OCOTP_CUSTn, REGS_OCOTP_BASE, 0x00000020, 0x10) +#define BP_OCOTP_CUSTn_BITS 0 +#define BM_OCOTP_CUSTn_BITS 0xFFFFFFFF +#define BF_OCOTP_CUSTn_BITS(v) (v) +/* + * multi-register-define name HW_OCOTP_CRYPTOn + * base 0x00000060 + * count 4 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_OCOTP_CRYPTOn, REGS_OCOTP_BASE, 0x00000060, 0x10) +#define BP_OCOTP_CRYPTOn_BITS 0 +#define BM_OCOTP_CRYPTOn_BITS 0xFFFFFFFF +#define BF_OCOTP_CRYPTOn_BITS(v) (v) +/* + * multi-register-define name HW_OCOTP_HWCAPn + * base 0x000000A0 + * count 6 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_OCOTP_HWCAPn, REGS_OCOTP_BASE, 0x000000a0, 0x10) +#define BP_OCOTP_HWCAPn_BITS 0 +#define BM_OCOTP_HWCAPn_BITS 0xFFFFFFFF +#define BF_OCOTP_HWCAPn_BITS(v) (v) +HW_REGISTER_0(HW_OCOTP_SWCAP, REGS_OCOTP_BASE, 0x00000100) +#define HW_OCOTP_SWCAP_ADDR (REGS_OCOTP_BASE + 0x00000100) +#define BP_OCOTP_SWCAP_BITS 0 +#define BM_OCOTP_SWCAP_BITS 0xFFFFFFFF +#define BF_OCOTP_SWCAP_BITS(v) (v) +HW_REGISTER_0(HW_OCOTP_CUSTCAP, REGS_OCOTP_BASE, 0x00000110) +#define HW_OCOTP_CUSTCAP_ADDR (REGS_OCOTP_BASE + 0x00000110) +#define BP_OCOTP_CUSTCAP_BITS 0 +#define BM_OCOTP_CUSTCAP_BITS 0xFFFFFFFF +#define BF_OCOTP_CUSTCAP_BITS(v) (v) +HW_REGISTER_0(HW_OCOTP_LOCK, REGS_OCOTP_BASE, 0x00000120) +#define HW_OCOTP_LOCK_ADDR (REGS_OCOTP_BASE + 0x00000120) +#define BM_OCOTP_LOCK_ROM7 0x80000000 +#define BM_OCOTP_LOCK_ROM6 0x40000000 +#define BM_OCOTP_LOCK_ROM5 0x20000000 +#define BM_OCOTP_LOCK_ROM4 0x10000000 +#define BM_OCOTP_LOCK_ROM3 0x08000000 +#define BM_OCOTP_LOCK_ROM2 0x04000000 +#define BM_OCOTP_LOCK_ROM1 0x02000000 +#define BM_OCOTP_LOCK_ROM0 0x01000000 +#define BM_OCOTP_LOCK_HWSW_SHADOW_ALT 0x00800000 +#define BM_OCOTP_LOCK_CRYPTODCP_ALT 0x00400000 +#define BM_OCOTP_LOCK_CRYPTOKEY_ALT 0x00200000 +#define BM_OCOTP_LOCK_PIN 0x00100000 +#define BM_OCOTP_LOCK_OPS 0x00080000 +#define BM_OCOTP_LOCK_UN2 0x00040000 +#define BM_OCOTP_LOCK_UN1 0x00020000 +#define BM_OCOTP_LOCK_UN0 0x00010000 +#define BP_OCOTP_LOCK_UNALLOCATED 11 +#define BM_OCOTP_LOCK_UNALLOCATED 0x0000F800 +#define BF_OCOTP_LOCK_UNALLOCATED(v) \ + (((v) << 11) & BM_OCOTP_LOCK_UNALLOCATED) +#define BM_OCOTP_LOCK_ROM_SHADOW 0x00000400 +#define BM_OCOTP_LOCK_CUSTCAP 0x00000200 +#define BM_OCOTP_LOCK_HWSW 0x00000100 +#define BM_OCOTP_LOCK_CUSTCAP_SHADOW 0x00000080 +#define BM_OCOTP_LOCK_HWSW_SHADOW 0x00000040 +#define BM_OCOTP_LOCK_CRYPTODCP 0x00000020 +#define BM_OCOTP_LOCK_CRYPTOKEY 0x00000010 +#define BM_OCOTP_LOCK_CUST3 0x00000008 +#define BM_OCOTP_LOCK_CUST2 0x00000004 +#define BM_OCOTP_LOCK_CUST1 0x00000002 +#define BM_OCOTP_LOCK_CUST0 0x00000001 +/* + * multi-register-define name HW_OCOTP_OPSn + * base 0x00000130 + * count 4 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_OCOTP_OPSn, REGS_OCOTP_BASE, 0x00000130, 0x10) +#define BP_OCOTP_OPSn_BITS 0 +#define BM_OCOTP_OPSn_BITS 0xFFFFFFFF +#define BF_OCOTP_OPSn_BITS(v) (v) +/* + * multi-register-define name HW_OCOTP_UNn + * base 0x00000170 + * count 3 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_OCOTP_UNn, REGS_OCOTP_BASE, 0x00000170, 0x10) +#define BP_OCOTP_UNn_BITS 0 +#define BM_OCOTP_UNn_BITS 0xFFFFFFFF +#define BF_OCOTP_UNn_BITS(v) (v) +/* + * multi-register-define name HW_OCOTP_ROMn + * base 0x000001A0 + * count 8 + * offset 0x10 + */ +HW_REGISTER_0_INDEXED(HW_OCOTP_ROMn, REGS_OCOTP_BASE, 0x000001a0, 0x10) +#define BP_OCOTP_ROMn_BITS 0 +#define BM_OCOTP_ROMn_BITS 0xFFFFFFFF +#define BF_OCOTP_ROMn_BITS(v) (v) +HW_REGISTER_0(HW_OCOTP_VERSION, REGS_OCOTP_BASE, 0x00000220) +#define HW_OCOTP_VERSION_ADDR (REGS_OCOTP_BASE + 0x00000220) +#define BP_OCOTP_VERSION_MAJOR 24 +#define BM_OCOTP_VERSION_MAJOR 0xFF000000 +#define BF_OCOTP_VERSION_MAJOR(v) \ + (((v) << 24) & BM_OCOTP_VERSION_MAJOR) +#define BP_OCOTP_VERSION_MINOR 16 +#define BM_OCOTP_VERSION_MINOR 0x00FF0000 +#define BF_OCOTP_VERSION_MINOR(v) \ + (((v) << 16) & BM_OCOTP_VERSION_MINOR) +#define BP_OCOTP_VERSION_STEP 0 +#define BM_OCOTP_VERSION_STEP 0x0000FFFF +#define BF_OCOTP_VERSION_STEP(v) \ + (((v) << 0) & BM_OCOTP_VERSION_STEP) +#endif /* __ARCH_ARM___OCOTP_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp3xxx/include/mach/regs-pinctrl.h new file mode 100644 index 000000000000..00ed07d45384 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-pinctrl.h @@ -0,0 +1,1255 @@ +/* + * STMP PINCTRL Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___PINCTRL_H +#define __ARCH_ARM___PINCTRL_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_PINCTRL_BASE (REGS_BASE + 0x18000) +#define REGS_PINCTRL_BASE_PHYS (0x80018000) +#define REGS_PINCTRL_SIZE 0x00002000 +HW_REGISTER(HW_PINCTRL_CTRL, REGS_PINCTRL_BASE, 0x00000000) +#define HW_PINCTRL_CTRL_ADDR (REGS_PINCTRL_BASE + 0x00000000) +#define BM_PINCTRL_CTRL_SFTRST 0x80000000 +#define BM_PINCTRL_CTRL_CLKGATE 0x40000000 +#define BM_PINCTRL_CTRL_PRESENT3 0x08000000 +#define BM_PINCTRL_CTRL_PRESENT2 0x04000000 +#define BM_PINCTRL_CTRL_PRESENT1 0x02000000 +#define BM_PINCTRL_CTRL_PRESENT0 0x01000000 +#define BM_PINCTRL_CTRL_IRQOUT2 0x00000004 +#define BM_PINCTRL_CTRL_IRQOUT1 0x00000002 +#define BM_PINCTRL_CTRL_IRQOUT0 0x00000001 +HW_REGISTER(HW_PINCTRL_MUXSEL0, REGS_PINCTRL_BASE, 0x00000100) +#define HW_PINCTRL_MUXSEL0_ADDR (REGS_PINCTRL_BASE + 0x00000100) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN15 30 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN15 0xC0000000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN15(v) \ + (((v) << 30) & BM_PINCTRL_MUXSEL0_BANK0_PIN15) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN14 28 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN14 0x30000000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN14(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL0_BANK0_PIN14) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN13 26 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN13 0x0C000000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN13(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL0_BANK0_PIN13) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN12 24 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN12 0x03000000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN12(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL0_BANK0_PIN12) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN11 22 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN11 0x00C00000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN11(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL0_BANK0_PIN11) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN10 20 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN10 0x00300000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN10(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL0_BANK0_PIN10) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN09 18 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN09 0x000C0000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN09(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL0_BANK0_PIN09) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN08 16 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN08 0x00030000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN08(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL0_BANK0_PIN08) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN07 14 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN07 0x0000C000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN07(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL0_BANK0_PIN07) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN06 12 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN06 0x00003000 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN06(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL0_BANK0_PIN06) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN05 10 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN05 0x00000C00 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN05(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL0_BANK0_PIN05) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN04 8 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN04 0x00000300 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN04(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL0_BANK0_PIN04) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN03 6 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN03 0x000000C0 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN03(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL0_BANK0_PIN03) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN02 4 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN02 0x00000030 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN02(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL0_BANK0_PIN02) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN01 2 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN01 0x0000000C +#define BF_PINCTRL_MUXSEL0_BANK0_PIN01(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL0_BANK0_PIN01) +#define BP_PINCTRL_MUXSEL0_BANK0_PIN00 0 +#define BM_PINCTRL_MUXSEL0_BANK0_PIN00 0x00000003 +#define BF_PINCTRL_MUXSEL0_BANK0_PIN00(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL0_BANK0_PIN00) +HW_REGISTER(HW_PINCTRL_MUXSEL1, REGS_PINCTRL_BASE, 0x00000110) +#define HW_PINCTRL_MUXSEL1_ADDR (REGS_PINCTRL_BASE + 0x00000110) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN31 30 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN31 0xC0000000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN31(v) \ + (((v) << 30) & BM_PINCTRL_MUXSEL1_BANK0_PIN31) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN30 28 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN30 0x30000000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN30(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL1_BANK0_PIN30) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN29 26 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN29 0x0C000000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN29(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL1_BANK0_PIN29) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN28 24 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN28 0x03000000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN28(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL1_BANK0_PIN28) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN27 22 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN27 0x00C00000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN27(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL1_BANK0_PIN27) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN26 20 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN26 0x00300000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN26(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL1_BANK0_PIN26) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN25 18 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN25 0x000C0000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN25(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL1_BANK0_PIN25) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN24 16 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN24 0x00030000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN24(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL1_BANK0_PIN24) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN23 14 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN23 0x0000C000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN23(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL1_BANK0_PIN23) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN22 12 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN22 0x00003000 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN22(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL1_BANK0_PIN22) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN21 10 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN21 0x00000C00 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN21(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL1_BANK0_PIN21) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN20 8 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN20 0x00000300 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN20(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL1_BANK0_PIN20) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN19 6 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN19 0x000000C0 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN19(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL1_BANK0_PIN19) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN18 4 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN18 0x00000030 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN18(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL1_BANK0_PIN18) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN17 2 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN17 0x0000000C +#define BF_PINCTRL_MUXSEL1_BANK0_PIN17(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL1_BANK0_PIN17) +#define BP_PINCTRL_MUXSEL1_BANK0_PIN16 0 +#define BM_PINCTRL_MUXSEL1_BANK0_PIN16 0x00000003 +#define BF_PINCTRL_MUXSEL1_BANK0_PIN16(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL1_BANK0_PIN16) +HW_REGISTER(HW_PINCTRL_MUXSEL2, REGS_PINCTRL_BASE, 0x00000120) +#define HW_PINCTRL_MUXSEL2_ADDR (REGS_PINCTRL_BASE + 0x00000120) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN15 30 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN15 0xC0000000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN15(v) \ + (((v) << 30) & BM_PINCTRL_MUXSEL2_BANK1_PIN15) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN14 28 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN14 0x30000000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN14(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL2_BANK1_PIN14) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN13 26 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN13 0x0C000000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN13(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL2_BANK1_PIN13) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN12 24 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN12 0x03000000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN12(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL2_BANK1_PIN12) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN11 22 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN11 0x00C00000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN11(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL2_BANK1_PIN11) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN10 20 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN10 0x00300000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN10(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL2_BANK1_PIN10) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN09 18 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN09 0x000C0000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN09(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL2_BANK1_PIN09) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN08 16 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN08 0x00030000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN08(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL2_BANK1_PIN08) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN07 14 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN07 0x0000C000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN07(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL2_BANK1_PIN07) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN06 12 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN06 0x00003000 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN06(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL2_BANK1_PIN06) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN05 10 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN05 0x00000C00 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN05(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL2_BANK1_PIN05) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN04 8 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN04 0x00000300 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN04(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL2_BANK1_PIN04) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN03 6 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN03 0x000000C0 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN03(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL2_BANK1_PIN03) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN02 4 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN02 0x00000030 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN02(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL2_BANK1_PIN02) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN01 2 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN01 0x0000000C +#define BF_PINCTRL_MUXSEL2_BANK1_PIN01(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL2_BANK1_PIN01) +#define BP_PINCTRL_MUXSEL2_BANK1_PIN00 0 +#define BM_PINCTRL_MUXSEL2_BANK1_PIN00 0x00000003 +#define BF_PINCTRL_MUXSEL2_BANK1_PIN00(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL2_BANK1_PIN00) +HW_REGISTER(HW_PINCTRL_MUXSEL3, REGS_PINCTRL_BASE, 0x00000130) +#define HW_PINCTRL_MUXSEL3_ADDR (REGS_PINCTRL_BASE + 0x00000130) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN30 28 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN30 0x30000000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN30(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL3_BANK1_PIN30) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN29 26 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN29 0x0C000000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN29(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL3_BANK1_PIN29) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN28 24 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN28 0x03000000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN28(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL3_BANK1_PIN28) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN27 22 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN27 0x00C00000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN27(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL3_BANK1_PIN27) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN26 20 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN26 0x00300000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN26(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL3_BANK1_PIN26) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN25 18 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN25 0x000C0000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN25(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL3_BANK1_PIN25) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN24 16 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN24 0x00030000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN24(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL3_BANK1_PIN24) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN23 14 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN23 0x0000C000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN23(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL3_BANK1_PIN23) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN22 12 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN22 0x00003000 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN22(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL3_BANK1_PIN22) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN21 10 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN21 0x00000C00 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN21(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL3_BANK1_PIN21) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN20 8 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN20 0x00000300 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN20(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL3_BANK1_PIN20) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN19 6 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN19 0x000000C0 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN19(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL3_BANK1_PIN19) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN18 4 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN18 0x00000030 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN18(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL3_BANK1_PIN18) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN17 2 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN17 0x0000000C +#define BF_PINCTRL_MUXSEL3_BANK1_PIN17(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL3_BANK1_PIN17) +#define BP_PINCTRL_MUXSEL3_BANK1_PIN16 0 +#define BM_PINCTRL_MUXSEL3_BANK1_PIN16 0x00000003 +#define BF_PINCTRL_MUXSEL3_BANK1_PIN16(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL3_BANK1_PIN16) +HW_REGISTER(HW_PINCTRL_MUXSEL4, REGS_PINCTRL_BASE, 0x00000140) +#define HW_PINCTRL_MUXSEL4_ADDR (REGS_PINCTRL_BASE + 0x00000140) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN15 30 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN15 0xC0000000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN15(v) \ + (((v) << 30) & BM_PINCTRL_MUXSEL4_BANK2_PIN15) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN14 28 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN14 0x30000000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN14(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL4_BANK2_PIN14) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN13 26 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN13 0x0C000000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN13(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL4_BANK2_PIN13) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN12 24 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN12 0x03000000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN12(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL4_BANK2_PIN12) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN11 22 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN11 0x00C00000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN11(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL4_BANK2_PIN11) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN10 20 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN10 0x00300000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN10(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL4_BANK2_PIN10) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN09 18 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN09 0x000C0000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN09(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL4_BANK2_PIN09) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN08 16 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN08 0x00030000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN08(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL4_BANK2_PIN08) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN07 14 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN07 0x0000C000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN07(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL4_BANK2_PIN07) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN06 12 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN06 0x00003000 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN06(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL4_BANK2_PIN06) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN05 10 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN05 0x00000C00 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN05(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL4_BANK2_PIN05) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN04 8 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN04 0x00000300 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN04(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL4_BANK2_PIN04) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN03 6 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN03 0x000000C0 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN03(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL4_BANK2_PIN03) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN02 4 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN02 0x00000030 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN02(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL4_BANK2_PIN02) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN01 2 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN01 0x0000000C +#define BF_PINCTRL_MUXSEL4_BANK2_PIN01(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL4_BANK2_PIN01) +#define BP_PINCTRL_MUXSEL4_BANK2_PIN00 0 +#define BM_PINCTRL_MUXSEL4_BANK2_PIN00 0x00000003 +#define BF_PINCTRL_MUXSEL4_BANK2_PIN00(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL4_BANK2_PIN00) +HW_REGISTER(HW_PINCTRL_MUXSEL5, REGS_PINCTRL_BASE, 0x00000150) +#define HW_PINCTRL_MUXSEL5_ADDR (REGS_PINCTRL_BASE + 0x00000150) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN31 30 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN31 0xC0000000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN31(v) \ + (((v) << 30) & BM_PINCTRL_MUXSEL5_BANK2_PIN31) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN30 28 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN30 0x30000000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN30(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL5_BANK2_PIN30) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN29 26 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN29 0x0C000000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN29(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL5_BANK2_PIN29) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN28 24 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN28 0x03000000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN28(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL5_BANK2_PIN28) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN27 22 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN27 0x00C00000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN27(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL5_BANK2_PIN27) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN26 20 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN26 0x00300000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN26(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL5_BANK2_PIN26) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN25 18 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN25 0x000C0000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN25(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL5_BANK2_PIN25) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN24 16 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN24 0x00030000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN24(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL5_BANK2_PIN24) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN23 14 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN23 0x0000C000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN23(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL5_BANK2_PIN23) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN22 12 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN22 0x00003000 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN22(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL5_BANK2_PIN22) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN21 10 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN21 0x00000C00 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN21(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL5_BANK2_PIN21) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN20 8 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN20 0x00000300 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN20(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL5_BANK2_PIN20) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN19 6 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN19 0x000000C0 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN19(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL5_BANK2_PIN19) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN18 4 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN18 0x00000030 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN18(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL5_BANK2_PIN18) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN17 2 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN17 0x0000000C +#define BF_PINCTRL_MUXSEL5_BANK2_PIN17(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL5_BANK2_PIN17) +#define BP_PINCTRL_MUXSEL5_BANK2_PIN16 0 +#define BM_PINCTRL_MUXSEL5_BANK2_PIN16 0x00000003 +#define BF_PINCTRL_MUXSEL5_BANK2_PIN16(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL5_BANK2_PIN16) +HW_REGISTER(HW_PINCTRL_MUXSEL6, REGS_PINCTRL_BASE, 0x00000160) +#define HW_PINCTRL_MUXSEL6_ADDR (REGS_PINCTRL_BASE + 0x00000160) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN15 30 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN15 0xC0000000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN15(v) \ + (((v) << 30) & BM_PINCTRL_MUXSEL6_BANK3_PIN15) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN14 28 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN14 0x30000000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN14(v) \ + (((v) << 28) & BM_PINCTRL_MUXSEL6_BANK3_PIN14) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN13 26 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN13 0x0C000000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN13(v) \ + (((v) << 26) & BM_PINCTRL_MUXSEL6_BANK3_PIN13) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN12 24 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN12 0x03000000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN12(v) \ + (((v) << 24) & BM_PINCTRL_MUXSEL6_BANK3_PIN12) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN11 22 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN11 0x00C00000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN11(v) \ + (((v) << 22) & BM_PINCTRL_MUXSEL6_BANK3_PIN11) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN10 20 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN10 0x00300000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN10(v) \ + (((v) << 20) & BM_PINCTRL_MUXSEL6_BANK3_PIN10) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN09 18 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN09 0x000C0000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN09(v) \ + (((v) << 18) & BM_PINCTRL_MUXSEL6_BANK3_PIN09) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN08 16 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN08 0x00030000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN08(v) \ + (((v) << 16) & BM_PINCTRL_MUXSEL6_BANK3_PIN08) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN07 14 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN07 0x0000C000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN07(v) \ + (((v) << 14) & BM_PINCTRL_MUXSEL6_BANK3_PIN07) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN06 12 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN06 0x00003000 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN06(v) \ + (((v) << 12) & BM_PINCTRL_MUXSEL6_BANK3_PIN06) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN05 10 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN05 0x00000C00 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN05(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL6_BANK3_PIN05) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN04 8 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN04 0x00000300 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN04(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL6_BANK3_PIN04) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN03 6 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN03 0x000000C0 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN03(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL6_BANK3_PIN03) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN02 4 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN02 0x00000030 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN02(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL6_BANK3_PIN02) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN01 2 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN01 0x0000000C +#define BF_PINCTRL_MUXSEL6_BANK3_PIN01(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL6_BANK3_PIN01) +#define BP_PINCTRL_MUXSEL6_BANK3_PIN00 0 +#define BM_PINCTRL_MUXSEL6_BANK3_PIN00 0x00000003 +#define BF_PINCTRL_MUXSEL6_BANK3_PIN00(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL6_BANK3_PIN00) +HW_REGISTER(HW_PINCTRL_MUXSEL7, REGS_PINCTRL_BASE, 0x00000170) +#define HW_PINCTRL_MUXSEL7_ADDR (REGS_PINCTRL_BASE + 0x00000170) +#define BP_PINCTRL_MUXSEL7_BANK3_PIN21 10 +#define BM_PINCTRL_MUXSEL7_BANK3_PIN21 0x00000C00 +#define BF_PINCTRL_MUXSEL7_BANK3_PIN21(v) \ + (((v) << 10) & BM_PINCTRL_MUXSEL7_BANK3_PIN21) +#define BP_PINCTRL_MUXSEL7_BANK3_PIN20 8 +#define BM_PINCTRL_MUXSEL7_BANK3_PIN20 0x00000300 +#define BF_PINCTRL_MUXSEL7_BANK3_PIN20(v) \ + (((v) << 8) & BM_PINCTRL_MUXSEL7_BANK3_PIN20) +#define BP_PINCTRL_MUXSEL7_BANK3_PIN19 6 +#define BM_PINCTRL_MUXSEL7_BANK3_PIN19 0x000000C0 +#define BF_PINCTRL_MUXSEL7_BANK3_PIN19(v) \ + (((v) << 6) & BM_PINCTRL_MUXSEL7_BANK3_PIN19) +#define BP_PINCTRL_MUXSEL7_BANK3_PIN18 4 +#define BM_PINCTRL_MUXSEL7_BANK3_PIN18 0x00000030 +#define BF_PINCTRL_MUXSEL7_BANK3_PIN18(v) \ + (((v) << 4) & BM_PINCTRL_MUXSEL7_BANK3_PIN18) +#define BP_PINCTRL_MUXSEL7_BANK3_PIN17 2 +#define BM_PINCTRL_MUXSEL7_BANK3_PIN17 0x0000000C +#define BF_PINCTRL_MUXSEL7_BANK3_PIN17(v) \ + (((v) << 2) & BM_PINCTRL_MUXSEL7_BANK3_PIN17) +#define BP_PINCTRL_MUXSEL7_BANK3_PIN16 0 +#define BM_PINCTRL_MUXSEL7_BANK3_PIN16 0x00000003 +#define BF_PINCTRL_MUXSEL7_BANK3_PIN16(v) \ + (((v) << 0) & BM_PINCTRL_MUXSEL7_BANK3_PIN16) +HW_REGISTER(HW_PINCTRL_DRIVE0, REGS_PINCTRL_BASE, 0x00000200) +#define HW_PINCTRL_DRIVE0_ADDR (REGS_PINCTRL_BASE + 0x00000200) +#define BP_PINCTRL_DRIVE0_BANK0_PIN07_MA 28 +#define BM_PINCTRL_DRIVE0_BANK0_PIN07_MA 0x30000000 +#define BF_PINCTRL_DRIVE0_BANK0_PIN07_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE0_BANK0_PIN07_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN06_MA 24 +#define BM_PINCTRL_DRIVE0_BANK0_PIN06_MA 0x03000000 +#define BF_PINCTRL_DRIVE0_BANK0_PIN06_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE0_BANK0_PIN06_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN05_MA 20 +#define BM_PINCTRL_DRIVE0_BANK0_PIN05_MA 0x00300000 +#define BF_PINCTRL_DRIVE0_BANK0_PIN05_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE0_BANK0_PIN05_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN04_MA 16 +#define BM_PINCTRL_DRIVE0_BANK0_PIN04_MA 0x00030000 +#define BF_PINCTRL_DRIVE0_BANK0_PIN04_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE0_BANK0_PIN04_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN03_MA 12 +#define BM_PINCTRL_DRIVE0_BANK0_PIN03_MA 0x00003000 +#define BF_PINCTRL_DRIVE0_BANK0_PIN03_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE0_BANK0_PIN03_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN02_MA 8 +#define BM_PINCTRL_DRIVE0_BANK0_PIN02_MA 0x00000300 +#define BF_PINCTRL_DRIVE0_BANK0_PIN02_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE0_BANK0_PIN02_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN01_MA 4 +#define BM_PINCTRL_DRIVE0_BANK0_PIN01_MA 0x00000030 +#define BF_PINCTRL_DRIVE0_BANK0_PIN01_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE0_BANK0_PIN01_MA) +#define BP_PINCTRL_DRIVE0_BANK0_PIN00_MA 0 +#define BM_PINCTRL_DRIVE0_BANK0_PIN00_MA 0x00000003 +#define BF_PINCTRL_DRIVE0_BANK0_PIN00_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE0_BANK0_PIN00_MA) +HW_REGISTER(HW_PINCTRL_DRIVE1, REGS_PINCTRL_BASE, 0x00000210) +#define HW_PINCTRL_DRIVE1_ADDR (REGS_PINCTRL_BASE + 0x00000210) +#define BP_PINCTRL_DRIVE1_BANK0_PIN15_MA 28 +#define BM_PINCTRL_DRIVE1_BANK0_PIN15_MA 0x30000000 +#define BF_PINCTRL_DRIVE1_BANK0_PIN15_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE1_BANK0_PIN15_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN14_MA 24 +#define BM_PINCTRL_DRIVE1_BANK0_PIN14_MA 0x03000000 +#define BF_PINCTRL_DRIVE1_BANK0_PIN14_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE1_BANK0_PIN14_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN13_MA 20 +#define BM_PINCTRL_DRIVE1_BANK0_PIN13_MA 0x00300000 +#define BF_PINCTRL_DRIVE1_BANK0_PIN13_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE1_BANK0_PIN13_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN12_MA 16 +#define BM_PINCTRL_DRIVE1_BANK0_PIN12_MA 0x00030000 +#define BF_PINCTRL_DRIVE1_BANK0_PIN12_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE1_BANK0_PIN12_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN11_MA 12 +#define BM_PINCTRL_DRIVE1_BANK0_PIN11_MA 0x00003000 +#define BF_PINCTRL_DRIVE1_BANK0_PIN11_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE1_BANK0_PIN11_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN10_MA 8 +#define BM_PINCTRL_DRIVE1_BANK0_PIN10_MA 0x00000300 +#define BF_PINCTRL_DRIVE1_BANK0_PIN10_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE1_BANK0_PIN10_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN09_MA 4 +#define BM_PINCTRL_DRIVE1_BANK0_PIN09_MA 0x00000030 +#define BF_PINCTRL_DRIVE1_BANK0_PIN09_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE1_BANK0_PIN09_MA) +#define BP_PINCTRL_DRIVE1_BANK0_PIN08_MA 0 +#define BM_PINCTRL_DRIVE1_BANK0_PIN08_MA 0x00000003 +#define BF_PINCTRL_DRIVE1_BANK0_PIN08_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE1_BANK0_PIN08_MA) +HW_REGISTER(HW_PINCTRL_DRIVE2, REGS_PINCTRL_BASE, 0x00000220) +#define HW_PINCTRL_DRIVE2_ADDR (REGS_PINCTRL_BASE + 0x00000220) +#define BP_PINCTRL_DRIVE2_BANK0_PIN23_MA 28 +#define BM_PINCTRL_DRIVE2_BANK0_PIN23_MA 0x30000000 +#define BF_PINCTRL_DRIVE2_BANK0_PIN23_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE2_BANK0_PIN23_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN22_MA 24 +#define BM_PINCTRL_DRIVE2_BANK0_PIN22_MA 0x03000000 +#define BF_PINCTRL_DRIVE2_BANK0_PIN22_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE2_BANK0_PIN22_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN21_MA 20 +#define BM_PINCTRL_DRIVE2_BANK0_PIN21_MA 0x00300000 +#define BF_PINCTRL_DRIVE2_BANK0_PIN21_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE2_BANK0_PIN21_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN20_MA 16 +#define BM_PINCTRL_DRIVE2_BANK0_PIN20_MA 0x00030000 +#define BF_PINCTRL_DRIVE2_BANK0_PIN20_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE2_BANK0_PIN20_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN19_MA 12 +#define BM_PINCTRL_DRIVE2_BANK0_PIN19_MA 0x00003000 +#define BF_PINCTRL_DRIVE2_BANK0_PIN19_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE2_BANK0_PIN19_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN18_MA 8 +#define BM_PINCTRL_DRIVE2_BANK0_PIN18_MA 0x00000300 +#define BF_PINCTRL_DRIVE2_BANK0_PIN18_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE2_BANK0_PIN18_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN17_MA 4 +#define BM_PINCTRL_DRIVE2_BANK0_PIN17_MA 0x00000030 +#define BF_PINCTRL_DRIVE2_BANK0_PIN17_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE2_BANK0_PIN17_MA) +#define BP_PINCTRL_DRIVE2_BANK0_PIN16_MA 0 +#define BM_PINCTRL_DRIVE2_BANK0_PIN16_MA 0x00000003 +#define BF_PINCTRL_DRIVE2_BANK0_PIN16_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE2_BANK0_PIN16_MA) +HW_REGISTER(HW_PINCTRL_DRIVE3, REGS_PINCTRL_BASE, 0x00000230) +#define HW_PINCTRL_DRIVE3_ADDR (REGS_PINCTRL_BASE + 0x00000230) +#define BP_PINCTRL_DRIVE3_BANK0_PIN31_MA 28 +#define BM_PINCTRL_DRIVE3_BANK0_PIN31_MA 0x30000000 +#define BF_PINCTRL_DRIVE3_BANK0_PIN31_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE3_BANK0_PIN31_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN30_MA 24 +#define BM_PINCTRL_DRIVE3_BANK0_PIN30_MA 0x03000000 +#define BF_PINCTRL_DRIVE3_BANK0_PIN30_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE3_BANK0_PIN30_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN29_MA 20 +#define BM_PINCTRL_DRIVE3_BANK0_PIN29_MA 0x00300000 +#define BF_PINCTRL_DRIVE3_BANK0_PIN29_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE3_BANK0_PIN29_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN28_MA 16 +#define BM_PINCTRL_DRIVE3_BANK0_PIN28_MA 0x00030000 +#define BF_PINCTRL_DRIVE3_BANK0_PIN28_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE3_BANK0_PIN28_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN27_MA 12 +#define BM_PINCTRL_DRIVE3_BANK0_PIN27_MA 0x00003000 +#define BF_PINCTRL_DRIVE3_BANK0_PIN27_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE3_BANK0_PIN27_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN26_MA 8 +#define BM_PINCTRL_DRIVE3_BANK0_PIN26_MA 0x00000300 +#define BF_PINCTRL_DRIVE3_BANK0_PIN26_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE3_BANK0_PIN26_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN25_MA 4 +#define BM_PINCTRL_DRIVE3_BANK0_PIN25_MA 0x00000030 +#define BF_PINCTRL_DRIVE3_BANK0_PIN25_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE3_BANK0_PIN25_MA) +#define BP_PINCTRL_DRIVE3_BANK0_PIN24_MA 0 +#define BM_PINCTRL_DRIVE3_BANK0_PIN24_MA 0x00000003 +#define BF_PINCTRL_DRIVE3_BANK0_PIN24_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE3_BANK0_PIN24_MA) +HW_REGISTER(HW_PINCTRL_DRIVE4, REGS_PINCTRL_BASE, 0x00000240) +#define HW_PINCTRL_DRIVE4_ADDR (REGS_PINCTRL_BASE + 0x00000240) +#define BP_PINCTRL_DRIVE4_BANK1_PIN07_MA 28 +#define BM_PINCTRL_DRIVE4_BANK1_PIN07_MA 0x30000000 +#define BF_PINCTRL_DRIVE4_BANK1_PIN07_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE4_BANK1_PIN07_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN06_MA 24 +#define BM_PINCTRL_DRIVE4_BANK1_PIN06_MA 0x03000000 +#define BF_PINCTRL_DRIVE4_BANK1_PIN06_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE4_BANK1_PIN06_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN05_MA 20 +#define BM_PINCTRL_DRIVE4_BANK1_PIN05_MA 0x00300000 +#define BF_PINCTRL_DRIVE4_BANK1_PIN05_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE4_BANK1_PIN05_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN04_MA 16 +#define BM_PINCTRL_DRIVE4_BANK1_PIN04_MA 0x00030000 +#define BF_PINCTRL_DRIVE4_BANK1_PIN04_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE4_BANK1_PIN04_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN03_MA 12 +#define BM_PINCTRL_DRIVE4_BANK1_PIN03_MA 0x00003000 +#define BF_PINCTRL_DRIVE4_BANK1_PIN03_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE4_BANK1_PIN03_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN02_MA 8 +#define BM_PINCTRL_DRIVE4_BANK1_PIN02_MA 0x00000300 +#define BF_PINCTRL_DRIVE4_BANK1_PIN02_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE4_BANK1_PIN02_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN01_MA 4 +#define BM_PINCTRL_DRIVE4_BANK1_PIN01_MA 0x00000030 +#define BF_PINCTRL_DRIVE4_BANK1_PIN01_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE4_BANK1_PIN01_MA) +#define BP_PINCTRL_DRIVE4_BANK1_PIN00_MA 0 +#define BM_PINCTRL_DRIVE4_BANK1_PIN00_MA 0x00000003 +#define BF_PINCTRL_DRIVE4_BANK1_PIN00_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE4_BANK1_PIN00_MA) +HW_REGISTER(HW_PINCTRL_DRIVE5, REGS_PINCTRL_BASE, 0x00000250) +#define HW_PINCTRL_DRIVE5_ADDR (REGS_PINCTRL_BASE + 0x00000250) +#define BP_PINCTRL_DRIVE5_BANK1_PIN15_MA 28 +#define BM_PINCTRL_DRIVE5_BANK1_PIN15_MA 0x30000000 +#define BF_PINCTRL_DRIVE5_BANK1_PIN15_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE5_BANK1_PIN15_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN14_MA 24 +#define BM_PINCTRL_DRIVE5_BANK1_PIN14_MA 0x03000000 +#define BF_PINCTRL_DRIVE5_BANK1_PIN14_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE5_BANK1_PIN14_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN13_MA 20 +#define BM_PINCTRL_DRIVE5_BANK1_PIN13_MA 0x00300000 +#define BF_PINCTRL_DRIVE5_BANK1_PIN13_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE5_BANK1_PIN13_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN12_MA 16 +#define BM_PINCTRL_DRIVE5_BANK1_PIN12_MA 0x00030000 +#define BF_PINCTRL_DRIVE5_BANK1_PIN12_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE5_BANK1_PIN12_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN11_MA 12 +#define BM_PINCTRL_DRIVE5_BANK1_PIN11_MA 0x00003000 +#define BF_PINCTRL_DRIVE5_BANK1_PIN11_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE5_BANK1_PIN11_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN10_MA 8 +#define BM_PINCTRL_DRIVE5_BANK1_PIN10_MA 0x00000300 +#define BF_PINCTRL_DRIVE5_BANK1_PIN10_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE5_BANK1_PIN10_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN09_MA 4 +#define BM_PINCTRL_DRIVE5_BANK1_PIN09_MA 0x00000030 +#define BF_PINCTRL_DRIVE5_BANK1_PIN09_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE5_BANK1_PIN09_MA) +#define BP_PINCTRL_DRIVE5_BANK1_PIN08_MA 0 +#define BM_PINCTRL_DRIVE5_BANK1_PIN08_MA 0x00000003 +#define BF_PINCTRL_DRIVE5_BANK1_PIN08_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE5_BANK1_PIN08_MA) +HW_REGISTER(HW_PINCTRL_DRIVE6, REGS_PINCTRL_BASE, 0x00000260) +#define HW_PINCTRL_DRIVE6_ADDR (REGS_PINCTRL_BASE + 0x00000260) +#define BP_PINCTRL_DRIVE6_BANK1_PIN23_MA 28 +#define BM_PINCTRL_DRIVE6_BANK1_PIN23_MA 0x30000000 +#define BF_PINCTRL_DRIVE6_BANK1_PIN23_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE6_BANK1_PIN23_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN22_MA 24 +#define BM_PINCTRL_DRIVE6_BANK1_PIN22_MA 0x03000000 +#define BF_PINCTRL_DRIVE6_BANK1_PIN22_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE6_BANK1_PIN22_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN21_MA 20 +#define BM_PINCTRL_DRIVE6_BANK1_PIN21_MA 0x00300000 +#define BF_PINCTRL_DRIVE6_BANK1_PIN21_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE6_BANK1_PIN21_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN20_MA 16 +#define BM_PINCTRL_DRIVE6_BANK1_PIN20_MA 0x00030000 +#define BF_PINCTRL_DRIVE6_BANK1_PIN20_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE6_BANK1_PIN20_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN19_MA 12 +#define BM_PINCTRL_DRIVE6_BANK1_PIN19_MA 0x00003000 +#define BF_PINCTRL_DRIVE6_BANK1_PIN19_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE6_BANK1_PIN19_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN18_MA 8 +#define BM_PINCTRL_DRIVE6_BANK1_PIN18_MA 0x00000300 +#define BF_PINCTRL_DRIVE6_BANK1_PIN18_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE6_BANK1_PIN18_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN17_MA 4 +#define BM_PINCTRL_DRIVE6_BANK1_PIN17_MA 0x00000030 +#define BF_PINCTRL_DRIVE6_BANK1_PIN17_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE6_BANK1_PIN17_MA) +#define BP_PINCTRL_DRIVE6_BANK1_PIN16_MA 0 +#define BM_PINCTRL_DRIVE6_BANK1_PIN16_MA 0x00000003 +#define BF_PINCTRL_DRIVE6_BANK1_PIN16_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE6_BANK1_PIN16_MA) +HW_REGISTER(HW_PINCTRL_DRIVE7, REGS_PINCTRL_BASE, 0x00000270) +#define HW_PINCTRL_DRIVE7_ADDR (REGS_PINCTRL_BASE + 0x00000270) +#define BP_PINCTRL_DRIVE7_BANK1_PIN30_MA 24 +#define BM_PINCTRL_DRIVE7_BANK1_PIN30_MA 0x03000000 +#define BF_PINCTRL_DRIVE7_BANK1_PIN30_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE7_BANK1_PIN30_MA) +#define BP_PINCTRL_DRIVE7_BANK1_PIN29_MA 20 +#define BM_PINCTRL_DRIVE7_BANK1_PIN29_MA 0x00300000 +#define BF_PINCTRL_DRIVE7_BANK1_PIN29_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE7_BANK1_PIN29_MA) +#define BP_PINCTRL_DRIVE7_BANK1_PIN28_MA 16 +#define BM_PINCTRL_DRIVE7_BANK1_PIN28_MA 0x00030000 +#define BF_PINCTRL_DRIVE7_BANK1_PIN28_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE7_BANK1_PIN28_MA) +#define BP_PINCTRL_DRIVE7_BANK1_PIN27_MA 12 +#define BM_PINCTRL_DRIVE7_BANK1_PIN27_MA 0x00003000 +#define BF_PINCTRL_DRIVE7_BANK1_PIN27_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE7_BANK1_PIN27_MA) +#define BP_PINCTRL_DRIVE7_BANK1_PIN26_MA 8 +#define BM_PINCTRL_DRIVE7_BANK1_PIN26_MA 0x00000300 +#define BF_PINCTRL_DRIVE7_BANK1_PIN26_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE7_BANK1_PIN26_MA) +#define BP_PINCTRL_DRIVE7_BANK1_PIN25_MA 4 +#define BM_PINCTRL_DRIVE7_BANK1_PIN25_MA 0x00000030 +#define BF_PINCTRL_DRIVE7_BANK1_PIN25_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE7_BANK1_PIN25_MA) +#define BP_PINCTRL_DRIVE7_BANK1_PIN24_MA 0 +#define BM_PINCTRL_DRIVE7_BANK1_PIN24_MA 0x00000003 +#define BF_PINCTRL_DRIVE7_BANK1_PIN24_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE7_BANK1_PIN24_MA) +HW_REGISTER(HW_PINCTRL_DRIVE8, REGS_PINCTRL_BASE, 0x00000280) +#define HW_PINCTRL_DRIVE8_ADDR (REGS_PINCTRL_BASE + 0x00000280) +#define BP_PINCTRL_DRIVE8_BANK2_PIN07_MA 28 +#define BM_PINCTRL_DRIVE8_BANK2_PIN07_MA 0x30000000 +#define BF_PINCTRL_DRIVE8_BANK2_PIN07_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE8_BANK2_PIN07_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN06_MA 24 +#define BM_PINCTRL_DRIVE8_BANK2_PIN06_MA 0x03000000 +#define BF_PINCTRL_DRIVE8_BANK2_PIN06_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE8_BANK2_PIN06_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN05_MA 20 +#define BM_PINCTRL_DRIVE8_BANK2_PIN05_MA 0x00300000 +#define BF_PINCTRL_DRIVE8_BANK2_PIN05_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE8_BANK2_PIN05_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN04_MA 16 +#define BM_PINCTRL_DRIVE8_BANK2_PIN04_MA 0x00030000 +#define BF_PINCTRL_DRIVE8_BANK2_PIN04_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE8_BANK2_PIN04_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN03_MA 12 +#define BM_PINCTRL_DRIVE8_BANK2_PIN03_MA 0x00003000 +#define BF_PINCTRL_DRIVE8_BANK2_PIN03_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE8_BANK2_PIN03_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN02_MA 8 +#define BM_PINCTRL_DRIVE8_BANK2_PIN02_MA 0x00000300 +#define BF_PINCTRL_DRIVE8_BANK2_PIN02_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE8_BANK2_PIN02_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN01_MA 4 +#define BM_PINCTRL_DRIVE8_BANK2_PIN01_MA 0x00000030 +#define BF_PINCTRL_DRIVE8_BANK2_PIN01_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE8_BANK2_PIN01_MA) +#define BP_PINCTRL_DRIVE8_BANK2_PIN00_MA 0 +#define BM_PINCTRL_DRIVE8_BANK2_PIN00_MA 0x00000003 +#define BF_PINCTRL_DRIVE8_BANK2_PIN00_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE8_BANK2_PIN00_MA) +HW_REGISTER(HW_PINCTRL_DRIVE9, REGS_PINCTRL_BASE, 0x00000290) +#define HW_PINCTRL_DRIVE9_ADDR (REGS_PINCTRL_BASE + 0x00000290) +#define BM_PINCTRL_DRIVE9_BANK2_PIN15_V 0x40000000 +#define BP_PINCTRL_DRIVE9_BANK2_PIN15_MA 28 +#define BM_PINCTRL_DRIVE9_BANK2_PIN15_MA 0x30000000 +#define BF_PINCTRL_DRIVE9_BANK2_PIN15_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE9_BANK2_PIN15_MA) +#define BM_PINCTRL_DRIVE9_BANK2_PIN14_V 0x04000000 +#define BP_PINCTRL_DRIVE9_BANK2_PIN14_MA 24 +#define BM_PINCTRL_DRIVE9_BANK2_PIN14_MA 0x03000000 +#define BF_PINCTRL_DRIVE9_BANK2_PIN14_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE9_BANK2_PIN14_MA) +#define BM_PINCTRL_DRIVE9_BANK2_PIN13_V 0x00400000 +#define BP_PINCTRL_DRIVE9_BANK2_PIN13_MA 20 +#define BM_PINCTRL_DRIVE9_BANK2_PIN13_MA 0x00300000 +#define BF_PINCTRL_DRIVE9_BANK2_PIN13_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE9_BANK2_PIN13_MA) +#define BM_PINCTRL_DRIVE9_BANK2_PIN12_V 0x00040000 +#define BP_PINCTRL_DRIVE9_BANK2_PIN12_MA 16 +#define BM_PINCTRL_DRIVE9_BANK2_PIN12_MA 0x00030000 +#define BF_PINCTRL_DRIVE9_BANK2_PIN12_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE9_BANK2_PIN12_MA) +#define BM_PINCTRL_DRIVE9_BANK2_PIN11_V 0x00004000 +#define BP_PINCTRL_DRIVE9_BANK2_PIN11_MA 12 +#define BM_PINCTRL_DRIVE9_BANK2_PIN11_MA 0x00003000 +#define BF_PINCTRL_DRIVE9_BANK2_PIN11_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE9_BANK2_PIN11_MA) +#define BM_PINCTRL_DRIVE9_BANK2_PIN10_V 0x00000400 +#define BP_PINCTRL_DRIVE9_BANK2_PIN10_MA 8 +#define BM_PINCTRL_DRIVE9_BANK2_PIN10_MA 0x00000300 +#define BF_PINCTRL_DRIVE9_BANK2_PIN10_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE9_BANK2_PIN10_MA) +#define BM_PINCTRL_DRIVE9_BANK2_PIN09_V 0x00000040 +#define BP_PINCTRL_DRIVE9_BANK2_PIN09_MA 4 +#define BM_PINCTRL_DRIVE9_BANK2_PIN09_MA 0x00000030 +#define BF_PINCTRL_DRIVE9_BANK2_PIN09_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE9_BANK2_PIN09_MA) +#define BP_PINCTRL_DRIVE9_BANK2_PIN08_MA 0 +#define BM_PINCTRL_DRIVE9_BANK2_PIN08_MA 0x00000003 +#define BF_PINCTRL_DRIVE9_BANK2_PIN08_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE9_BANK2_PIN08_MA) +HW_REGISTER(HW_PINCTRL_DRIVE10, REGS_PINCTRL_BASE, 0x000002a0) +#define HW_PINCTRL_DRIVE10_ADDR (REGS_PINCTRL_BASE + 0x000002a0) +#define BM_PINCTRL_DRIVE10_BANK2_PIN23_V 0x40000000 +#define BP_PINCTRL_DRIVE10_BANK2_PIN23_MA 28 +#define BM_PINCTRL_DRIVE10_BANK2_PIN23_MA 0x30000000 +#define BF_PINCTRL_DRIVE10_BANK2_PIN23_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE10_BANK2_PIN23_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN22_V 0x04000000 +#define BP_PINCTRL_DRIVE10_BANK2_PIN22_MA 24 +#define BM_PINCTRL_DRIVE10_BANK2_PIN22_MA 0x03000000 +#define BF_PINCTRL_DRIVE10_BANK2_PIN22_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE10_BANK2_PIN22_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN21_V 0x00400000 +#define BP_PINCTRL_DRIVE10_BANK2_PIN21_MA 20 +#define BM_PINCTRL_DRIVE10_BANK2_PIN21_MA 0x00300000 +#define BF_PINCTRL_DRIVE10_BANK2_PIN21_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE10_BANK2_PIN21_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN20_V 0x00040000 +#define BP_PINCTRL_DRIVE10_BANK2_PIN20_MA 16 +#define BM_PINCTRL_DRIVE10_BANK2_PIN20_MA 0x00030000 +#define BF_PINCTRL_DRIVE10_BANK2_PIN20_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE10_BANK2_PIN20_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN19_V 0x00004000 +#define BP_PINCTRL_DRIVE10_BANK2_PIN19_MA 12 +#define BM_PINCTRL_DRIVE10_BANK2_PIN19_MA 0x00003000 +#define BF_PINCTRL_DRIVE10_BANK2_PIN19_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE10_BANK2_PIN19_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN18_V 0x00000400 +#define BP_PINCTRL_DRIVE10_BANK2_PIN18_MA 8 +#define BM_PINCTRL_DRIVE10_BANK2_PIN18_MA 0x00000300 +#define BF_PINCTRL_DRIVE10_BANK2_PIN18_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE10_BANK2_PIN18_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN17_V 0x00000040 +#define BP_PINCTRL_DRIVE10_BANK2_PIN17_MA 4 +#define BM_PINCTRL_DRIVE10_BANK2_PIN17_MA 0x00000030 +#define BF_PINCTRL_DRIVE10_BANK2_PIN17_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE10_BANK2_PIN17_MA) +#define BM_PINCTRL_DRIVE10_BANK2_PIN16_V 0x00000004 +#define BP_PINCTRL_DRIVE10_BANK2_PIN16_MA 0 +#define BM_PINCTRL_DRIVE10_BANK2_PIN16_MA 0x00000003 +#define BF_PINCTRL_DRIVE10_BANK2_PIN16_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE10_BANK2_PIN16_MA) +HW_REGISTER(HW_PINCTRL_DRIVE11, REGS_PINCTRL_BASE, 0x000002b0) +#define HW_PINCTRL_DRIVE11_ADDR (REGS_PINCTRL_BASE + 0x000002b0) +#define BM_PINCTRL_DRIVE11_BANK2_PIN31_V 0x40000000 +#define BP_PINCTRL_DRIVE11_BANK2_PIN31_MA 28 +#define BM_PINCTRL_DRIVE11_BANK2_PIN31_MA 0x30000000 +#define BF_PINCTRL_DRIVE11_BANK2_PIN31_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE11_BANK2_PIN31_MA) +#define BM_PINCTRL_DRIVE11_BANK2_PIN30_V 0x04000000 +#define BP_PINCTRL_DRIVE11_BANK2_PIN30_MA 24 +#define BM_PINCTRL_DRIVE11_BANK2_PIN30_MA 0x03000000 +#define BF_PINCTRL_DRIVE11_BANK2_PIN30_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE11_BANK2_PIN30_MA) +#define BM_PINCTRL_DRIVE11_BANK2_PIN29_V 0x00400000 +#define BP_PINCTRL_DRIVE11_BANK2_PIN29_MA 20 +#define BM_PINCTRL_DRIVE11_BANK2_PIN29_MA 0x00300000 +#define BF_PINCTRL_DRIVE11_BANK2_PIN29_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE11_BANK2_PIN29_MA) +#define BP_PINCTRL_DRIVE11_BANK2_PIN28_MA 16 +#define BM_PINCTRL_DRIVE11_BANK2_PIN28_MA 0x00030000 +#define BF_PINCTRL_DRIVE11_BANK2_PIN28_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE11_BANK2_PIN28_MA) +#define BP_PINCTRL_DRIVE11_BANK2_PIN27_MA 12 +#define BM_PINCTRL_DRIVE11_BANK2_PIN27_MA 0x00003000 +#define BF_PINCTRL_DRIVE11_BANK2_PIN27_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE11_BANK2_PIN27_MA) +#define BM_PINCTRL_DRIVE11_BANK2_PIN26_V 0x00000400 +#define BP_PINCTRL_DRIVE11_BANK2_PIN26_MA 8 +#define BM_PINCTRL_DRIVE11_BANK2_PIN26_MA 0x00000300 +#define BF_PINCTRL_DRIVE11_BANK2_PIN26_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE11_BANK2_PIN26_MA) +#define BM_PINCTRL_DRIVE11_BANK2_PIN25_V 0x00000040 +#define BP_PINCTRL_DRIVE11_BANK2_PIN25_MA 4 +#define BM_PINCTRL_DRIVE11_BANK2_PIN25_MA 0x00000030 +#define BF_PINCTRL_DRIVE11_BANK2_PIN25_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE11_BANK2_PIN25_MA) +#define BM_PINCTRL_DRIVE11_BANK2_PIN24_V 0x00000004 +#define BP_PINCTRL_DRIVE11_BANK2_PIN24_MA 0 +#define BM_PINCTRL_DRIVE11_BANK2_PIN24_MA 0x00000003 +#define BF_PINCTRL_DRIVE11_BANK2_PIN24_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE11_BANK2_PIN24_MA) +HW_REGISTER(HW_PINCTRL_DRIVE12, REGS_PINCTRL_BASE, 0x000002c0) +#define HW_PINCTRL_DRIVE12_ADDR (REGS_PINCTRL_BASE + 0x000002c0) +#define BM_PINCTRL_DRIVE12_BANK3_PIN07_V 0x40000000 +#define BP_PINCTRL_DRIVE12_BANK3_PIN07_MA 28 +#define BM_PINCTRL_DRIVE12_BANK3_PIN07_MA 0x30000000 +#define BF_PINCTRL_DRIVE12_BANK3_PIN07_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE12_BANK3_PIN07_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN06_V 0x04000000 +#define BP_PINCTRL_DRIVE12_BANK3_PIN06_MA 24 +#define BM_PINCTRL_DRIVE12_BANK3_PIN06_MA 0x03000000 +#define BF_PINCTRL_DRIVE12_BANK3_PIN06_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE12_BANK3_PIN06_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN05_V 0x00400000 +#define BP_PINCTRL_DRIVE12_BANK3_PIN05_MA 20 +#define BM_PINCTRL_DRIVE12_BANK3_PIN05_MA 0x00300000 +#define BF_PINCTRL_DRIVE12_BANK3_PIN05_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE12_BANK3_PIN05_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN04_V 0x00040000 +#define BP_PINCTRL_DRIVE12_BANK3_PIN04_MA 16 +#define BM_PINCTRL_DRIVE12_BANK3_PIN04_MA 0x00030000 +#define BF_PINCTRL_DRIVE12_BANK3_PIN04_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE12_BANK3_PIN04_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN03_V 0x00004000 +#define BP_PINCTRL_DRIVE12_BANK3_PIN03_MA 12 +#define BM_PINCTRL_DRIVE12_BANK3_PIN03_MA 0x00003000 +#define BF_PINCTRL_DRIVE12_BANK3_PIN03_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE12_BANK3_PIN03_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN02_V 0x00000400 +#define BP_PINCTRL_DRIVE12_BANK3_PIN02_MA 8 +#define BM_PINCTRL_DRIVE12_BANK3_PIN02_MA 0x00000300 +#define BF_PINCTRL_DRIVE12_BANK3_PIN02_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE12_BANK3_PIN02_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN01_V 0x00000040 +#define BP_PINCTRL_DRIVE12_BANK3_PIN01_MA 4 +#define BM_PINCTRL_DRIVE12_BANK3_PIN01_MA 0x00000030 +#define BF_PINCTRL_DRIVE12_BANK3_PIN01_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE12_BANK3_PIN01_MA) +#define BM_PINCTRL_DRIVE12_BANK3_PIN00_V 0x00000004 +#define BP_PINCTRL_DRIVE12_BANK3_PIN00_MA 0 +#define BM_PINCTRL_DRIVE12_BANK3_PIN00_MA 0x00000003 +#define BF_PINCTRL_DRIVE12_BANK3_PIN00_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE12_BANK3_PIN00_MA) +HW_REGISTER(HW_PINCTRL_DRIVE13, REGS_PINCTRL_BASE, 0x000002d0) +#define HW_PINCTRL_DRIVE13_ADDR (REGS_PINCTRL_BASE + 0x000002d0) +#define BM_PINCTRL_DRIVE13_BANK3_PIN15_V 0x40000000 +#define BP_PINCTRL_DRIVE13_BANK3_PIN15_MA 28 +#define BM_PINCTRL_DRIVE13_BANK3_PIN15_MA 0x30000000 +#define BF_PINCTRL_DRIVE13_BANK3_PIN15_MA(v) \ + (((v) << 28) & BM_PINCTRL_DRIVE13_BANK3_PIN15_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN14_V 0x04000000 +#define BP_PINCTRL_DRIVE13_BANK3_PIN14_MA 24 +#define BM_PINCTRL_DRIVE13_BANK3_PIN14_MA 0x03000000 +#define BF_PINCTRL_DRIVE13_BANK3_PIN14_MA(v) \ + (((v) << 24) & BM_PINCTRL_DRIVE13_BANK3_PIN14_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN13_V 0x00400000 +#define BP_PINCTRL_DRIVE13_BANK3_PIN13_MA 20 +#define BM_PINCTRL_DRIVE13_BANK3_PIN13_MA 0x00300000 +#define BF_PINCTRL_DRIVE13_BANK3_PIN13_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE13_BANK3_PIN13_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN12_V 0x00040000 +#define BP_PINCTRL_DRIVE13_BANK3_PIN12_MA 16 +#define BM_PINCTRL_DRIVE13_BANK3_PIN12_MA 0x00030000 +#define BF_PINCTRL_DRIVE13_BANK3_PIN12_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE13_BANK3_PIN12_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN11_V 0x00004000 +#define BP_PINCTRL_DRIVE13_BANK3_PIN11_MA 12 +#define BM_PINCTRL_DRIVE13_BANK3_PIN11_MA 0x00003000 +#define BF_PINCTRL_DRIVE13_BANK3_PIN11_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE13_BANK3_PIN11_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN10_V 0x00000400 +#define BP_PINCTRL_DRIVE13_BANK3_PIN10_MA 8 +#define BM_PINCTRL_DRIVE13_BANK3_PIN10_MA 0x00000300 +#define BF_PINCTRL_DRIVE13_BANK3_PIN10_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE13_BANK3_PIN10_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN09_V 0x00000040 +#define BP_PINCTRL_DRIVE13_BANK3_PIN09_MA 4 +#define BM_PINCTRL_DRIVE13_BANK3_PIN09_MA 0x00000030 +#define BF_PINCTRL_DRIVE13_BANK3_PIN09_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE13_BANK3_PIN09_MA) +#define BM_PINCTRL_DRIVE13_BANK3_PIN08_V 0x00000004 +#define BP_PINCTRL_DRIVE13_BANK3_PIN08_MA 0 +#define BM_PINCTRL_DRIVE13_BANK3_PIN08_MA 0x00000003 +#define BF_PINCTRL_DRIVE13_BANK3_PIN08_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE13_BANK3_PIN08_MA) +HW_REGISTER(HW_PINCTRL_DRIVE14, REGS_PINCTRL_BASE, 0x000002e0) +#define HW_PINCTRL_DRIVE14_ADDR (REGS_PINCTRL_BASE + 0x000002e0) +#define BM_PINCTRL_DRIVE14_BANK3_PIN21_V 0x00400000 +#define BP_PINCTRL_DRIVE14_BANK3_PIN21_MA 20 +#define BM_PINCTRL_DRIVE14_BANK3_PIN21_MA 0x00300000 +#define BF_PINCTRL_DRIVE14_BANK3_PIN21_MA(v) \ + (((v) << 20) & BM_PINCTRL_DRIVE14_BANK3_PIN21_MA) +#define BM_PINCTRL_DRIVE14_BANK3_PIN20_V 0x00040000 +#define BP_PINCTRL_DRIVE14_BANK3_PIN20_MA 16 +#define BM_PINCTRL_DRIVE14_BANK3_PIN20_MA 0x00030000 +#define BF_PINCTRL_DRIVE14_BANK3_PIN20_MA(v) \ + (((v) << 16) & BM_PINCTRL_DRIVE14_BANK3_PIN20_MA) +#define BM_PINCTRL_DRIVE14_BANK3_PIN19_V 0x00004000 +#define BP_PINCTRL_DRIVE14_BANK3_PIN19_MA 12 +#define BM_PINCTRL_DRIVE14_BANK3_PIN19_MA 0x00003000 +#define BF_PINCTRL_DRIVE14_BANK3_PIN19_MA(v) \ + (((v) << 12) & BM_PINCTRL_DRIVE14_BANK3_PIN19_MA) +#define BM_PINCTRL_DRIVE14_BANK3_PIN18_V 0x00000400 +#define BP_PINCTRL_DRIVE14_BANK3_PIN18_MA 8 +#define BM_PINCTRL_DRIVE14_BANK3_PIN18_MA 0x00000300 +#define BF_PINCTRL_DRIVE14_BANK3_PIN18_MA(v) \ + (((v) << 8) & BM_PINCTRL_DRIVE14_BANK3_PIN18_MA) +#define BM_PINCTRL_DRIVE14_BANK3_PIN17_V 0x00000040 +#define BP_PINCTRL_DRIVE14_BANK3_PIN17_MA 4 +#define BM_PINCTRL_DRIVE14_BANK3_PIN17_MA 0x00000030 +#define BF_PINCTRL_DRIVE14_BANK3_PIN17_MA(v) \ + (((v) << 4) & BM_PINCTRL_DRIVE14_BANK3_PIN17_MA) +#define BM_PINCTRL_DRIVE14_BANK3_PIN16_V 0x00000004 +#define BP_PINCTRL_DRIVE14_BANK3_PIN16_MA 0 +#define BM_PINCTRL_DRIVE14_BANK3_PIN16_MA 0x00000003 +#define BF_PINCTRL_DRIVE14_BANK3_PIN16_MA(v) \ + (((v) << 0) & BM_PINCTRL_DRIVE14_BANK3_PIN16_MA) +HW_REGISTER(HW_PINCTRL_PULL0, REGS_PINCTRL_BASE, 0x00000400) +#define HW_PINCTRL_PULL0_ADDR (REGS_PINCTRL_BASE + 0x00000400) +#define BM_PINCTRL_PULL0_BANK0_PIN31 0x80000000 +#define BM_PINCTRL_PULL0_BANK0_PIN30 0x40000000 +#define BM_PINCTRL_PULL0_BANK0_PIN29 0x20000000 +#define BM_PINCTRL_PULL0_BANK0_PIN28 0x10000000 +#define BM_PINCTRL_PULL0_BANK0_PIN27 0x08000000 +#define BM_PINCTRL_PULL0_BANK0_PIN26 0x04000000 +#define BM_PINCTRL_PULL0_BANK0_PIN22 0x00400000 +#define BM_PINCTRL_PULL0_BANK0_PIN21 0x00200000 +#define BM_PINCTRL_PULL0_BANK0_PIN20 0x00100000 +#define BM_PINCTRL_PULL0_BANK0_PIN19 0x00080000 +#define BM_PINCTRL_PULL0_BANK0_PIN18 0x00040000 +#define BM_PINCTRL_PULL0_BANK0_PIN15 0x00008000 +#define BM_PINCTRL_PULL0_BANK0_PIN11 0x00000800 +#define BM_PINCTRL_PULL0_BANK0_PIN10 0x00000400 +#define BM_PINCTRL_PULL0_BANK0_PIN09 0x00000200 +#define BM_PINCTRL_PULL0_BANK0_PIN08 0x00000100 +#define BM_PINCTRL_PULL0_BANK0_PIN07 0x00000080 +#define BM_PINCTRL_PULL0_BANK0_PIN06 0x00000040 +#define BM_PINCTRL_PULL0_BANK0_PIN05 0x00000020 +#define BM_PINCTRL_PULL0_BANK0_PIN04 0x00000010 +#define BM_PINCTRL_PULL0_BANK0_PIN03 0x00000008 +#define BM_PINCTRL_PULL0_BANK0_PIN02 0x00000004 +#define BM_PINCTRL_PULL0_BANK0_PIN01 0x00000002 +#define BM_PINCTRL_PULL0_BANK0_PIN00 0x00000001 +HW_REGISTER(HW_PINCTRL_PULL1, REGS_PINCTRL_BASE, 0x00000410) +#define HW_PINCTRL_PULL1_ADDR (REGS_PINCTRL_BASE + 0x00000410) +#define BM_PINCTRL_PULL1_BANK1_PIN28 0x10000000 +#define BM_PINCTRL_PULL1_BANK1_PIN22 0x00400000 +#define BM_PINCTRL_PULL1_BANK1_PIN18 0x00040000 +HW_REGISTER(HW_PINCTRL_PULL2, REGS_PINCTRL_BASE, 0x00000420) +#define HW_PINCTRL_PULL2_ADDR (REGS_PINCTRL_BASE + 0x00000420) +#define BM_PINCTRL_PULL2_BANK2_PIN28 0x10000000 +#define BM_PINCTRL_PULL2_BANK2_PIN27 0x08000000 +#define BM_PINCTRL_PULL2_BANK2_PIN08 0x00000100 +#define BM_PINCTRL_PULL2_BANK2_PIN05 0x00000020 +#define BM_PINCTRL_PULL2_BANK2_PIN04 0x00000010 +#define BM_PINCTRL_PULL2_BANK2_PIN03 0x00000008 +#define BM_PINCTRL_PULL2_BANK2_PIN02 0x00000004 +#define BM_PINCTRL_PULL2_BANK2_PIN01 0x00000002 +#define BM_PINCTRL_PULL2_BANK2_PIN00 0x00000001 +HW_REGISTER(HW_PINCTRL_PULL3, REGS_PINCTRL_BASE, 0x00000430) +#define HW_PINCTRL_PULL3_ADDR (REGS_PINCTRL_BASE + 0x00000430) +#define BM_PINCTRL_PULL3_BANK3_PIN17 0x00020000 +#define BM_PINCTRL_PULL3_BANK3_PIN16 0x00010000 +#define BM_PINCTRL_PULL3_BANK3_PIN15 0x00008000 +#define BM_PINCTRL_PULL3_BANK3_PIN14 0x00004000 +#define BM_PINCTRL_PULL3_BANK3_PIN13 0x00002000 +#define BM_PINCTRL_PULL3_BANK3_PIN12 0x00001000 +#define BM_PINCTRL_PULL3_BANK3_PIN11 0x00000800 +#define BM_PINCTRL_PULL3_BANK3_PIN10 0x00000400 +#define BM_PINCTRL_PULL3_BANK3_PIN09 0x00000200 +#define BM_PINCTRL_PULL3_BANK3_PIN08 0x00000100 +#define BM_PINCTRL_PULL3_BANK3_PIN07 0x00000080 +#define BM_PINCTRL_PULL3_BANK3_PIN06 0x00000040 +#define BM_PINCTRL_PULL3_BANK3_PIN05 0x00000020 +#define BM_PINCTRL_PULL3_BANK3_PIN04 0x00000010 +#define BM_PINCTRL_PULL3_BANK3_PIN03 0x00000008 +#define BM_PINCTRL_PULL3_BANK3_PIN02 0x00000004 +#define BM_PINCTRL_PULL3_BANK3_PIN01 0x00000002 +#define BM_PINCTRL_PULL3_BANK3_PIN00 0x00000001 +HW_REGISTER(HW_PINCTRL_DOUT0, REGS_PINCTRL_BASE, 0x00000500) +#define HW_PINCTRL_DOUT0_ADDR (REGS_PINCTRL_BASE + 0x00000500) +#define BP_PINCTRL_DOUT0_DOUT 0 +#define BM_PINCTRL_DOUT0_DOUT 0xFFFFFFFF +#define BF_PINCTRL_DOUT0_DOUT(v) (v) +HW_REGISTER(HW_PINCTRL_DOUT1, REGS_PINCTRL_BASE, 0x00000510) +#define HW_PINCTRL_DOUT1_ADDR (REGS_PINCTRL_BASE + 0x00000510) +#define BP_PINCTRL_DOUT1_DOUT 0 +#define BM_PINCTRL_DOUT1_DOUT 0x7FFFFFFF +#define BF_PINCTRL_DOUT1_DOUT(v) \ + (((v) << 0) & BM_PINCTRL_DOUT1_DOUT) +HW_REGISTER(HW_PINCTRL_DOUT2, REGS_PINCTRL_BASE, 0x00000520) +#define HW_PINCTRL_DOUT2_ADDR (REGS_PINCTRL_BASE + 0x00000520) +#define BP_PINCTRL_DOUT2_DOUT 0 +#define BM_PINCTRL_DOUT2_DOUT 0xFFFFFFFF +#define BF_PINCTRL_DOUT2_DOUT(v) (v) +HW_REGISTER(HW_PINCTRL_DIN0, REGS_PINCTRL_BASE, 0x00000600) +#define HW_PINCTRL_DIN0_ADDR (REGS_PINCTRL_BASE + 0x00000600) +#define BP_PINCTRL_DIN0_DIN 0 +#define BM_PINCTRL_DIN0_DIN 0xFFFFFFFF +#define BF_PINCTRL_DIN0_DIN(v) (v) +HW_REGISTER(HW_PINCTRL_DIN1, REGS_PINCTRL_BASE, 0x00000610) +#define HW_PINCTRL_DIN1_ADDR (REGS_PINCTRL_BASE + 0x00000610) +#define BP_PINCTRL_DIN1_DIN 0 +#define BM_PINCTRL_DIN1_DIN 0x7FFFFFFF +#define BF_PINCTRL_DIN1_DIN(v) \ + (((v) << 0) & BM_PINCTRL_DIN1_DIN) +HW_REGISTER(HW_PINCTRL_DIN2, REGS_PINCTRL_BASE, 0x00000620) +#define HW_PINCTRL_DIN2_ADDR (REGS_PINCTRL_BASE + 0x00000620) +#define BP_PINCTRL_DIN2_DIN 0 +#define BM_PINCTRL_DIN2_DIN 0xFFFFFFFF +#define BF_PINCTRL_DIN2_DIN(v) (v) +HW_REGISTER(HW_PINCTRL_DOE0, REGS_PINCTRL_BASE, 0x00000700) +#define HW_PINCTRL_DOE0_ADDR (REGS_PINCTRL_BASE + 0x00000700) +#define BP_PINCTRL_DOE0_DOE 0 +#define BM_PINCTRL_DOE0_DOE 0xFFFFFFFF +#define BF_PINCTRL_DOE0_DOE(v) (v) +HW_REGISTER(HW_PINCTRL_DOE1, REGS_PINCTRL_BASE, 0x00000710) +#define HW_PINCTRL_DOE1_ADDR (REGS_PINCTRL_BASE + 0x00000710) +#define BP_PINCTRL_DOE1_DOE 0 +#define BM_PINCTRL_DOE1_DOE 0x7FFFFFFF +#define BF_PINCTRL_DOE1_DOE(v) \ + (((v) << 0) & BM_PINCTRL_DOE1_DOE) +HW_REGISTER(HW_PINCTRL_DOE2, REGS_PINCTRL_BASE, 0x00000720) +#define HW_PINCTRL_DOE2_ADDR (REGS_PINCTRL_BASE + 0x00000720) +#define BP_PINCTRL_DOE2_DOE 0 +#define BM_PINCTRL_DOE2_DOE 0xFFFFFFFF +#define BF_PINCTRL_DOE2_DOE(v) (v) +HW_REGISTER(HW_PINCTRL_PIN2IRQ0, REGS_PINCTRL_BASE, 0x00000800) +#define HW_PINCTRL_PIN2IRQ0_ADDR (REGS_PINCTRL_BASE + 0x00000800) +#define BP_PINCTRL_PIN2IRQ0_PIN2IRQ 0 +#define BM_PINCTRL_PIN2IRQ0_PIN2IRQ 0xFFFFFFFF +#define BF_PINCTRL_PIN2IRQ0_PIN2IRQ(v) (v) +HW_REGISTER(HW_PINCTRL_PIN2IRQ1, REGS_PINCTRL_BASE, 0x00000810) +#define HW_PINCTRL_PIN2IRQ1_ADDR (REGS_PINCTRL_BASE + 0x00000810) +#define BP_PINCTRL_PIN2IRQ1_PIN2IRQ 0 +#define BM_PINCTRL_PIN2IRQ1_PIN2IRQ 0x7FFFFFFF +#define BF_PINCTRL_PIN2IRQ1_PIN2IRQ(v) \ + (((v) << 0) & BM_PINCTRL_PIN2IRQ1_PIN2IRQ) +HW_REGISTER(HW_PINCTRL_PIN2IRQ2, REGS_PINCTRL_BASE, 0x00000820) +#define HW_PINCTRL_PIN2IRQ2_ADDR (REGS_PINCTRL_BASE + 0x00000820) +#define BP_PINCTRL_PIN2IRQ2_PIN2IRQ 0 +#define BM_PINCTRL_PIN2IRQ2_PIN2IRQ 0xFFFFFFFF +#define BF_PINCTRL_PIN2IRQ2_PIN2IRQ(v) (v) +HW_REGISTER(HW_PINCTRL_IRQEN0, REGS_PINCTRL_BASE, 0x00000900) +#define HW_PINCTRL_IRQEN0_ADDR (REGS_PINCTRL_BASE + 0x00000900) +#define BP_PINCTRL_IRQEN0_IRQEN 0 +#define BM_PINCTRL_IRQEN0_IRQEN 0xFFFFFFFF +#define BF_PINCTRL_IRQEN0_IRQEN(v) (v) +HW_REGISTER(HW_PINCTRL_IRQEN1, REGS_PINCTRL_BASE, 0x00000910) +#define HW_PINCTRL_IRQEN1_ADDR (REGS_PINCTRL_BASE + 0x00000910) +#define BP_PINCTRL_IRQEN1_IRQEN 0 +#define BM_PINCTRL_IRQEN1_IRQEN 0x7FFFFFFF +#define BF_PINCTRL_IRQEN1_IRQEN(v) \ + (((v) << 0) & BM_PINCTRL_IRQEN1_IRQEN) +HW_REGISTER(HW_PINCTRL_IRQEN2, REGS_PINCTRL_BASE, 0x00000920) +#define HW_PINCTRL_IRQEN2_ADDR (REGS_PINCTRL_BASE + 0x00000920) +#define BP_PINCTRL_IRQEN2_IRQEN 0 +#define BM_PINCTRL_IRQEN2_IRQEN 0xFFFFFFFF +#define BF_PINCTRL_IRQEN2_IRQEN(v) (v) +HW_REGISTER(HW_PINCTRL_IRQLEVEL0, REGS_PINCTRL_BASE, 0x00000a00) +#define HW_PINCTRL_IRQLEVEL0_ADDR (REGS_PINCTRL_BASE + 0x00000a00) +#define BP_PINCTRL_IRQLEVEL0_IRQLEVEL 0 +#define BM_PINCTRL_IRQLEVEL0_IRQLEVEL 0xFFFFFFFF +#define BF_PINCTRL_IRQLEVEL0_IRQLEVEL(v) (v) +HW_REGISTER(HW_PINCTRL_IRQLEVEL1, REGS_PINCTRL_BASE, 0x00000a10) +#define HW_PINCTRL_IRQLEVEL1_ADDR (REGS_PINCTRL_BASE + 0x00000a10) +#define BP_PINCTRL_IRQLEVEL1_IRQLEVEL 0 +#define BM_PINCTRL_IRQLEVEL1_IRQLEVEL 0x7FFFFFFF +#define BF_PINCTRL_IRQLEVEL1_IRQLEVEL(v) \ + (((v) << 0) & BM_PINCTRL_IRQLEVEL1_IRQLEVEL) +HW_REGISTER(HW_PINCTRL_IRQLEVEL2, REGS_PINCTRL_BASE, 0x00000a20) +#define HW_PINCTRL_IRQLEVEL2_ADDR (REGS_PINCTRL_BASE + 0x00000a20) +#define BP_PINCTRL_IRQLEVEL2_IRQLEVEL 0 +#define BM_PINCTRL_IRQLEVEL2_IRQLEVEL 0xFFFFFFFF +#define BF_PINCTRL_IRQLEVEL2_IRQLEVEL(v) (v) +HW_REGISTER(HW_PINCTRL_IRQPOL0, REGS_PINCTRL_BASE, 0x00000b00) +#define HW_PINCTRL_IRQPOL0_ADDR (REGS_PINCTRL_BASE + 0x00000b00) +#define BP_PINCTRL_IRQPOL0_IRQPOL 0 +#define BM_PINCTRL_IRQPOL0_IRQPOL 0xFFFFFFFF +#define BF_PINCTRL_IRQPOL0_IRQPOL(v) (v) +HW_REGISTER(HW_PINCTRL_IRQPOL1, REGS_PINCTRL_BASE, 0x00000b10) +#define HW_PINCTRL_IRQPOL1_ADDR (REGS_PINCTRL_BASE + 0x00000b10) +#define BP_PINCTRL_IRQPOL1_IRQPOL 0 +#define BM_PINCTRL_IRQPOL1_IRQPOL 0x7FFFFFFF +#define BF_PINCTRL_IRQPOL1_IRQPOL(v) \ + (((v) << 0) & BM_PINCTRL_IRQPOL1_IRQPOL) +HW_REGISTER(HW_PINCTRL_IRQPOL2, REGS_PINCTRL_BASE, 0x00000b20) +#define HW_PINCTRL_IRQPOL2_ADDR (REGS_PINCTRL_BASE + 0x00000b20) +#define BP_PINCTRL_IRQPOL2_IRQPOL 0 +#define BM_PINCTRL_IRQPOL2_IRQPOL 0xFFFFFFFF +#define BF_PINCTRL_IRQPOL2_IRQPOL(v) (v) +HW_REGISTER(HW_PINCTRL_IRQSTAT0, REGS_PINCTRL_BASE, 0x00000c00) +#define HW_PINCTRL_IRQSTAT0_ADDR (REGS_PINCTRL_BASE + 0x00000c00) +#define BP_PINCTRL_IRQSTAT0_IRQSTAT 0 +#define BM_PINCTRL_IRQSTAT0_IRQSTAT 0xFFFFFFFF +#define BF_PINCTRL_IRQSTAT0_IRQSTAT(v) (v) +HW_REGISTER(HW_PINCTRL_IRQSTAT1, REGS_PINCTRL_BASE, 0x00000c10) +#define HW_PINCTRL_IRQSTAT1_ADDR (REGS_PINCTRL_BASE + 0x00000c10) +#define BP_PINCTRL_IRQSTAT1_IRQSTAT 0 +#define BM_PINCTRL_IRQSTAT1_IRQSTAT 0x7FFFFFFF +#define BF_PINCTRL_IRQSTAT1_IRQSTAT(v) \ + (((v) << 0) & BM_PINCTRL_IRQSTAT1_IRQSTAT) +HW_REGISTER(HW_PINCTRL_IRQSTAT2, REGS_PINCTRL_BASE, 0x00000c20) +#define HW_PINCTRL_IRQSTAT2_ADDR (REGS_PINCTRL_BASE + 0x00000c20) +#define BP_PINCTRL_IRQSTAT2_IRQSTAT 0 +#define BM_PINCTRL_IRQSTAT2_IRQSTAT 0xFFFFFFFF +#define BF_PINCTRL_IRQSTAT2_IRQSTAT(v) (v) +#endif /* __ARCH_ARM___PINCTRL_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-power.h b/arch/arm/mach-stmp3xxx/include/mach/regs-power.h new file mode 100644 index 000000000000..90fb0ff3a19c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-power.h @@ -0,0 +1,349 @@ +/* + * STMP POWER Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___POWER_H +#define __ARCH_ARM___POWER_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_POWER_BASE (REGS_BASE + 0x44000) +#define REGS_POWER_BASE_PHYS (0x80044000) +#define REGS_POWER_SIZE 0x00002000 +HW_REGISTER(HW_POWER_CTRL, REGS_POWER_BASE, 0x00000000) +#define HW_POWER_CTRL_ADDR (REGS_POWER_BASE + 0x00000000) +#define BM_POWER_CTRL_CLKGATE 0x40000000 +#define BM_POWER_CTRL_PSWITCH_MID_TRAN 0x08000000 +#define BM_POWER_CTRL_DCDC4P2_BO_IRQ 0x01000000 +#define BM_POWER_CTRL_ENIRQ_DCDC4P2_BO 0x00800000 +#define BM_POWER_CTRL_VDD5V_DROOP_IRQ 0x00400000 +#define BM_POWER_CTRL_ENIRQ_VDD5V_DROOP 0x00200000 +#define BM_POWER_CTRL_PSWITCH_IRQ 0x00100000 +#define BM_POWER_CTRL_PSWITCH_IRQ_SRC 0x00080000 +#define BM_POWER_CTRL_POLARITY_PSWITCH 0x00040000 +#define BM_POWER_CTRL_ENIRQ_PSWITCH 0x00020000 +#define BM_POWER_CTRL_POLARITY_DC_OK 0x00010000 +#define BM_POWER_CTRL_DC_OK_IRQ 0x00008000 +#define BM_POWER_CTRL_ENIRQ_DC_OK 0x00004000 +#define BM_POWER_CTRL_BATT_BO_IRQ 0x00002000 +#define BM_POWER_CTRL_ENIRQBATT_BO 0x00001000 +#define BM_POWER_CTRL_VDDIO_BO_IRQ 0x00000800 +#define BM_POWER_CTRL_ENIRQ_VDDIO_BO 0x00000400 +#define BM_POWER_CTRL_VDDA_BO_IRQ 0x00000200 +#define BM_POWER_CTRL_ENIRQ_VDDA_BO 0x00000100 +#define BM_POWER_CTRL_VDDD_BO_IRQ 0x00000080 +#define BM_POWER_CTRL_ENIRQ_VDDD_BO 0x00000040 +#define BM_POWER_CTRL_POLARITY_VBUSVALID 0x00000020 +#define BM_POWER_CTRL_VBUSVALID_IRQ 0x00000010 +#define BM_POWER_CTRL_ENIRQ_VBUS_VALID 0x00000008 +#define BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO 0x00000004 +#define BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ 0x00000002 +#define BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO 0x00000001 +HW_REGISTER(HW_POWER_5VCTRL, REGS_POWER_BASE, 0x00000010) +#define HW_POWER_5VCTRL_ADDR (REGS_POWER_BASE + 0x00000010) +#define BP_POWER_5VCTRL_VBUSDROOP_TRSH 28 +#define BM_POWER_5VCTRL_VBUSDROOP_TRSH 0x30000000 +#define BF_POWER_5VCTRL_VBUSDROOP_TRSH(v) \ + (((v) << 28) & BM_POWER_5VCTRL_VBUSDROOP_TRSH) +#define BP_POWER_5VCTRL_HEADROOM_ADJ 24 +#define BM_POWER_5VCTRL_HEADROOM_ADJ 0x07000000 +#define BF_POWER_5VCTRL_HEADROOM_ADJ(v) \ + (((v) << 24) & BM_POWER_5VCTRL_HEADROOM_ADJ) +#define BM_POWER_5VCTRL_PWD_CHARGE_4P2 0x00100000 +#define BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT 12 +#define BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT 0x0003F000 +#define BF_POWER_5VCTRL_CHARGE_4P2_ILIMIT(v) \ + (((v) << 12) & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) +#define BP_POWER_5VCTRL_VBUSVALID_TRSH 8 +#define BM_POWER_5VCTRL_VBUSVALID_TRSH 0x00000700 +#define BF_POWER_5VCTRL_VBUSVALID_TRSH(v) \ + (((v) << 8) & BM_POWER_5VCTRL_VBUSVALID_TRSH) +#define BM_POWER_5VCTRL_PWDN_5VBRNOUT 0x00000080 +#define BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT 0x00000040 +#define BM_POWER_5VCTRL_DCDC_XFER 0x00000020 +#define BM_POWER_5VCTRL_VBUSVALID_5VDETECT 0x00000010 +#define BM_POWER_5VCTRL_VBUSVALID_TO_B 0x00000008 +#define BM_POWER_5VCTRL_ILIMIT_EQ_ZERO 0x00000004 +#define BM_POWER_5VCTRL_PWRUP_VBUS_CMPS 0x00000002 +#define BM_POWER_5VCTRL_ENABLE_DCDC 0x00000001 +HW_REGISTER(HW_POWER_MINPWR, REGS_POWER_BASE, 0x00000020) +#define HW_POWER_MINPWR_ADDR (REGS_POWER_BASE + 0x00000020) +#define BM_POWER_MINPWR_LOWPWR_4P2 0x00004000 +#define BM_POWER_MINPWR_VDAC_DUMP_CTRL 0x00002000 +#define BM_POWER_MINPWR_PWD_BO 0x00001000 +#define BM_POWER_MINPWR_USE_VDDXTAL_VBG 0x00000800 +#define BM_POWER_MINPWR_PWD_ANA_CMPS 0x00000400 +#define BM_POWER_MINPWR_ENABLE_OSC 0x00000200 +#define BM_POWER_MINPWR_SELECT_OSC 0x00000100 +#define BM_POWER_MINPWR_VBG_OFF 0x00000080 +#define BM_POWER_MINPWR_DOUBLE_FETS 0x00000040 +#define BM_POWER_MINPWR_HALF_FETS 0x00000020 +#define BM_POWER_MINPWR_LESSANA_I 0x00000010 +#define BM_POWER_MINPWR_PWD_XTAL24 0x00000008 +#define BM_POWER_MINPWR_DC_STOPCLK 0x00000004 +#define BM_POWER_MINPWR_EN_DC_PFM 0x00000002 +#define BM_POWER_MINPWR_DC_HALFCLK 0x00000001 +HW_REGISTER(HW_POWER_CHARGE, REGS_POWER_BASE, 0x00000030) +#define HW_POWER_CHARGE_ADDR (REGS_POWER_BASE + 0x00000030) +#define BP_POWER_CHARGE_ADJ_VOLT 24 +#define BM_POWER_CHARGE_ADJ_VOLT 0x07000000 +#define BF_POWER_CHARGE_ADJ_VOLT(v) \ + (((v) << 24) & BM_POWER_CHARGE_ADJ_VOLT) +#define BM_POWER_CHARGE_RSRVD3 0x00800000 +#define BM_POWER_CHARGE_ENABLE_LOAD 0x00400000 +#define BM_POWER_CHARGE_ENABLE_CHARGER_RESISTORS 0x00200000 +#define BM_POWER_CHARGE_ENABLE_FAULT_DETECT 0x00100000 +#define BM_POWER_CHARGE_CHRG_STS_OFF 0x00080000 +#define BM_POWER_CHARGE_USE_EXTERN_R 0x00020000 +#define BM_POWER_CHARGE_PWD_BATTCHRG 0x00010000 +#define BP_POWER_CHARGE_STOP_ILIMIT 8 +#define BM_POWER_CHARGE_STOP_ILIMIT 0x00000F00 +#define BF_POWER_CHARGE_STOP_ILIMIT(v) \ + (((v) << 8) & BM_POWER_CHARGE_STOP_ILIMIT) +#define BP_POWER_CHARGE_BATTCHRG_I 0 +#define BM_POWER_CHARGE_BATTCHRG_I 0x0000003F +#define BF_POWER_CHARGE_BATTCHRG_I(v) \ + (((v) << 0) & BM_POWER_CHARGE_BATTCHRG_I) +HW_REGISTER_0(HW_POWER_VDDDCTRL, REGS_POWER_BASE, 0x00000040) +#define HW_POWER_VDDDCTRL_ADDR (REGS_POWER_BASE + 0x00000040) +#define BP_POWER_VDDDCTRL_ADJTN 28 +#define BM_POWER_VDDDCTRL_ADJTN 0xF0000000 +#define BF_POWER_VDDDCTRL_ADJTN(v) \ + (((v) << 28) & BM_POWER_VDDDCTRL_ADJTN) +#define BM_POWER_VDDDCTRL_PWDN_BRNOUT 0x00800000 +#define BM_POWER_VDDDCTRL_DISABLE_STEPPING 0x00400000 +#define BM_POWER_VDDDCTRL_ENABLE_LINREG 0x00200000 +#define BM_POWER_VDDDCTRL_DISABLE_FET 0x00100000 +#define BP_POWER_VDDDCTRL_LINREG_OFFSET 16 +#define BM_POWER_VDDDCTRL_LINREG_OFFSET 0x00030000 +#define BF_POWER_VDDDCTRL_LINREG_OFFSET(v) \ + (((v) << 16) & BM_POWER_VDDDCTRL_LINREG_OFFSET) +#define BP_POWER_VDDDCTRL_BO_OFFSET 8 +#define BM_POWER_VDDDCTRL_BO_OFFSET 0x00000700 +#define BF_POWER_VDDDCTRL_BO_OFFSET(v) \ + (((v) << 8) & BM_POWER_VDDDCTRL_BO_OFFSET) +#define BP_POWER_VDDDCTRL_TRG 0 +#define BM_POWER_VDDDCTRL_TRG 0x0000001F +#define BF_POWER_VDDDCTRL_TRG(v) \ + (((v) << 0) & BM_POWER_VDDDCTRL_TRG) +HW_REGISTER_0(HW_POWER_VDDACTRL, REGS_POWER_BASE, 0x00000050) +#define HW_POWER_VDDACTRL_ADDR (REGS_POWER_BASE + 0x00000050) +#define BM_POWER_VDDACTRL_PWDN_BRNOUT 0x00080000 +#define BM_POWER_VDDACTRL_DISABLE_STEPPING 0x00040000 +#define BM_POWER_VDDACTRL_ENABLE_LINREG 0x00020000 +#define BM_POWER_VDDACTRL_DISABLE_FET 0x00010000 +#define BP_POWER_VDDACTRL_LINREG_OFFSET 12 +#define BM_POWER_VDDACTRL_LINREG_OFFSET 0x00003000 +#define BF_POWER_VDDACTRL_LINREG_OFFSET(v) \ + (((v) << 12) & BM_POWER_VDDACTRL_LINREG_OFFSET) +#define BP_POWER_VDDACTRL_BO_OFFSET 8 +#define BM_POWER_VDDACTRL_BO_OFFSET 0x00000700 +#define BF_POWER_VDDACTRL_BO_OFFSET(v) \ + (((v) << 8) & BM_POWER_VDDACTRL_BO_OFFSET) +#define BP_POWER_VDDACTRL_TRG 0 +#define BM_POWER_VDDACTRL_TRG 0x0000001F +#define BF_POWER_VDDACTRL_TRG(v) \ + (((v) << 0) & BM_POWER_VDDACTRL_TRG) +HW_REGISTER_0(HW_POWER_VDDIOCTRL, REGS_POWER_BASE, 0x00000060) +#define HW_POWER_VDDIOCTRL_ADDR (REGS_POWER_BASE + 0x00000060) +#define BP_POWER_VDDIOCTRL_ADJTN 20 +#define BM_POWER_VDDIOCTRL_ADJTN 0x00F00000 +#define BF_POWER_VDDIOCTRL_ADJTN(v) \ + (((v) << 20) & BM_POWER_VDDIOCTRL_ADJTN) +#define BM_POWER_VDDIOCTRL_PWDN_BRNOUT 0x00040000 +#define BM_POWER_VDDIOCTRL_DISABLE_STEPPING 0x00020000 +#define BM_POWER_VDDIOCTRL_DISABLE_FET 0x00010000 +#define BP_POWER_VDDIOCTRL_LINREG_OFFSET 12 +#define BM_POWER_VDDIOCTRL_LINREG_OFFSET 0x00003000 +#define BF_POWER_VDDIOCTRL_LINREG_OFFSET(v) \ + (((v) << 12) & BM_POWER_VDDIOCTRL_LINREG_OFFSET) +#define BP_POWER_VDDIOCTRL_BO_OFFSET 8 +#define BM_POWER_VDDIOCTRL_BO_OFFSET 0x00000700 +#define BF_POWER_VDDIOCTRL_BO_OFFSET(v) \ + (((v) << 8) & BM_POWER_VDDIOCTRL_BO_OFFSET) +#define BP_POWER_VDDIOCTRL_TRG 0 +#define BM_POWER_VDDIOCTRL_TRG 0x0000001F +#define BF_POWER_VDDIOCTRL_TRG(v) \ + (((v) << 0) & BM_POWER_VDDIOCTRL_TRG) +HW_REGISTER_0(HW_POWER_VDDMEMCTRL, REGS_POWER_BASE, 0x00000070) +#define HW_POWER_VDDMEMCTRL_ADDR (REGS_POWER_BASE + 0x00000070) +#define BM_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE 0x00000400 +#define BM_POWER_VDDMEMCTRL_ENABLE_ILIMIT 0x00000200 +#define BM_POWER_VDDMEMCTRL_ENABLE_LINREG 0x00000100 +#define BP_POWER_VDDMEMCTRL_TRG 0 +#define BM_POWER_VDDMEMCTRL_TRG 0x0000001F +#define BF_POWER_VDDMEMCTRL_TRG(v) \ + (((v) << 0) & BM_POWER_VDDMEMCTRL_TRG) +HW_REGISTER_0(HW_POWER_DCDC4P2, REGS_POWER_BASE, 0x00000080) +#define HW_POWER_DCDC4P2_ADDR (REGS_POWER_BASE + 0x00000080) +#define BP_POWER_DCDC4P2_DROPOUT_CTRL 28 +#define BM_POWER_DCDC4P2_DROPOUT_CTRL 0xF0000000 +#define BF_POWER_DCDC4P2_DROPOUT_CTRL(v) \ + (((v) << 28) & BM_POWER_DCDC4P2_DROPOUT_CTRL) +#define BP_POWER_DCDC4P2_ISTEAL_THRESH 24 +#define BM_POWER_DCDC4P2_ISTEAL_THRESH 0x03000000 +#define BF_POWER_DCDC4P2_ISTEAL_THRESH(v) \ + (((v) << 24) & BM_POWER_DCDC4P2_ISTEAL_THRESH) +#define BM_POWER_DCDC4P2_ENABLE_4P2 0x00800000 +#define BM_POWER_DCDC4P2_ENABLE_DCDC 0x00400000 +#define BM_POWER_DCDC4P2_HYST_DIR 0x00200000 +#define BM_POWER_DCDC4P2_HYST_THRESH 0x00100000 +#define BP_POWER_DCDC4P2_TRG 16 +#define BM_POWER_DCDC4P2_TRG 0x00070000 +#define BF_POWER_DCDC4P2_TRG(v) \ + (((v) << 16) & BM_POWER_DCDC4P2_TRG) +#define BP_POWER_DCDC4P2_BO 8 +#define BM_POWER_DCDC4P2_BO 0x00001F00 +#define BF_POWER_DCDC4P2_BO(v) \ + (((v) << 8) & BM_POWER_DCDC4P2_BO) +#define BP_POWER_DCDC4P2_CMPTRIP 0 +#define BM_POWER_DCDC4P2_CMPTRIP 0x0000001F +#define BF_POWER_DCDC4P2_CMPTRIP(v) \ + (((v) << 0) & BM_POWER_DCDC4P2_CMPTRIP) +HW_REGISTER_0(HW_POWER_MISC, REGS_POWER_BASE, 0x00000090) +#define HW_POWER_MISC_ADDR (REGS_POWER_BASE + 0x00000090) +#define BP_POWER_MISC_FREQSEL 4 +#define BM_POWER_MISC_FREQSEL 0x00000070 +#define BF_POWER_MISC_FREQSEL(v) \ + (((v) << 4) & BM_POWER_MISC_FREQSEL) +#define BM_POWER_MISC_RSRVD1 0x00000008 +#define BM_POWER_MISC_DELAY_TIMING 0x00000004 +#define BM_POWER_MISC_TEST 0x00000002 +#define BM_POWER_MISC_SEL_PLLCLK 0x00000001 +HW_REGISTER_0(HW_POWER_DCLIMITS, REGS_POWER_BASE, 0x000000a0) +#define HW_POWER_DCLIMITS_ADDR (REGS_POWER_BASE + 0x000000a0) +#define BP_POWER_DCLIMITS_POSLIMIT_BUCK 8 +#define BM_POWER_DCLIMITS_POSLIMIT_BUCK 0x00007F00 +#define BF_POWER_DCLIMITS_POSLIMIT_BUCK(v) \ + (((v) << 8) & BM_POWER_DCLIMITS_POSLIMIT_BUCK) +#define BP_POWER_DCLIMITS_NEGLIMIT 0 +#define BM_POWER_DCLIMITS_NEGLIMIT 0x0000007F +#define BF_POWER_DCLIMITS_NEGLIMIT(v) \ + (((v) << 0) & BM_POWER_DCLIMITS_NEGLIMIT) +HW_REGISTER(HW_POWER_LOOPCTRL, REGS_POWER_BASE, 0x000000b0) +#define HW_POWER_LOOPCTRL_ADDR (REGS_POWER_BASE + 0x000000b0) +#define BM_POWER_LOOPCTRL_TOGGLE_DIF 0x00100000 +#define BM_POWER_LOOPCTRL_HYST_SIGN 0x00080000 +#define BM_POWER_LOOPCTRL_EN_CM_HYST 0x00040000 +#define BM_POWER_LOOPCTRL_EN_DF_HYST 0x00020000 +#define BM_POWER_LOOPCTRL_CM_HYST_THRESH 0x00010000 +#define BM_POWER_LOOPCTRL_DF_HYST_THRESH 0x00008000 +#define BM_POWER_LOOPCTRL_RCSCALE_THRESH 0x00004000 +#define BP_POWER_LOOPCTRL_EN_RCSCALE 12 +#define BM_POWER_LOOPCTRL_EN_RCSCALE 0x00003000 +#define BF_POWER_LOOPCTRL_EN_RCSCALE(v) \ + (((v) << 12) & BM_POWER_LOOPCTRL_EN_RCSCALE) +#define BP_POWER_LOOPCTRL_DC_FF 8 +#define BM_POWER_LOOPCTRL_DC_FF 0x00000700 +#define BF_POWER_LOOPCTRL_DC_FF(v) \ + (((v) << 8) & BM_POWER_LOOPCTRL_DC_FF) +#define BP_POWER_LOOPCTRL_DC_R 4 +#define BM_POWER_LOOPCTRL_DC_R 0x000000F0 +#define BF_POWER_LOOPCTRL_DC_R(v) \ + (((v) << 4) & BM_POWER_LOOPCTRL_DC_R) +#define BP_POWER_LOOPCTRL_DC_C 0 +#define BM_POWER_LOOPCTRL_DC_C 0x00000003 +#define BF_POWER_LOOPCTRL_DC_C(v) \ + (((v) << 0) & BM_POWER_LOOPCTRL_DC_C) +HW_REGISTER_0(HW_POWER_STS, REGS_POWER_BASE, 0x000000c0) +#define HW_POWER_STS_ADDR (REGS_POWER_BASE + 0x000000c0) +#define BP_POWER_STS_PWRUP_SOURCE 24 +#define BM_POWER_STS_PWRUP_SOURCE 0x3F000000 +#define BF_POWER_STS_PWRUP_SOURCE(v) \ + (((v) << 24) & BM_POWER_STS_PWRUP_SOURCE) +#define BP_POWER_STS_PSWITCH 20 +#define BM_POWER_STS_PSWITCH 0x00300000 +#define BF_POWER_STS_PSWITCH(v) \ + (((v) << 20) & BM_POWER_STS_PSWITCH) +#define BM_POWER_STS_AVALID_STATUS 0x00020000 +#define BM_POWER_STS_BVALID_STATUS 0x00010000 +#define BM_POWER_STS_VBUSVALID_STATUS 0x00008000 +#define BM_POWER_STS_SESSEND_STATUS 0x00004000 +#define BM_POWER_STS_BATT_BO 0x00002000 +#define BM_POWER_STS_VDD5V_FAULT 0x00001000 +#define BM_POWER_STS_CHRGSTS 0x00000800 +#define BM_POWER_STS_DCDC_4P2_BO 0x00000400 +#define BM_POWER_STS_DC_OK 0x00000200 +#define BM_POWER_STS_VDDIO_BO 0x00000100 +#define BM_POWER_STS_VDDA_BO 0x00000080 +#define BM_POWER_STS_VDDD_BO 0x00000040 +#define BM_POWER_STS_VDD5V_GT_VDDIO 0x00000020 +#define BM_POWER_STS_VDD5V_DROOP 0x00000010 +#define BM_POWER_STS_AVALID 0x00000008 +#define BM_POWER_STS_BVALID 0x00000004 +#define BM_POWER_STS_VBUSVALID 0x00000002 +#define BM_POWER_STS_SESSEND 0x00000001 +HW_REGISTER(HW_POWER_SPEED, REGS_POWER_BASE, 0x000000d0) +#define HW_POWER_SPEED_ADDR (REGS_POWER_BASE + 0x000000d0) +#define BP_POWER_SPEED_STATUS 16 +#define BM_POWER_SPEED_STATUS 0x00FF0000 +#define BF_POWER_SPEED_STATUS(v) \ + (((v) << 16) & BM_POWER_SPEED_STATUS) +#define BP_POWER_SPEED_CTRL 0 +#define BM_POWER_SPEED_CTRL 0x00000003 +#define BF_POWER_SPEED_CTRL(v) \ + (((v) << 0) & BM_POWER_SPEED_CTRL) +HW_REGISTER_0(HW_POWER_BATTMONITOR, REGS_POWER_BASE, 0x000000e0) +#define HW_POWER_BATTMONITOR_ADDR (REGS_POWER_BASE + 0x000000e0) +#define BP_POWER_BATTMONITOR_BATT_VAL 16 +#define BM_POWER_BATTMONITOR_BATT_VAL 0x03FF0000 +#define BF_POWER_BATTMONITOR_BATT_VAL(v) \ + (((v) << 16) & BM_POWER_BATTMONITOR_BATT_VAL) +#define BM_POWER_BATTMONITOR_EN_BATADJ 0x00000400 +#define BM_POWER_BATTMONITOR_PWDN_BATTBRNOUT 0x00000200 +#define BM_POWER_BATTMONITOR_BRWNOUT_PWD 0x00000100 +#define BP_POWER_BATTMONITOR_BRWNOUT_LVL 0 +#define BM_POWER_BATTMONITOR_BRWNOUT_LVL 0x0000001F +#define BF_POWER_BATTMONITOR_BRWNOUT_LVL(v) \ + (((v) << 0) & BM_POWER_BATTMONITOR_BRWNOUT_LVL) +HW_REGISTER(HW_POWER_RESET, REGS_POWER_BASE, 0x00000100) +#define HW_POWER_RESET_ADDR (REGS_POWER_BASE + 0x00000100) +#define BP_POWER_RESET_UNLOCK 16 +#define BM_POWER_RESET_UNLOCK 0xFFFF0000 +#define BF_POWER_RESET_UNLOCK(v) \ + (((v) << 16) & BM_POWER_RESET_UNLOCK) +#define BV_POWER_RESET_UNLOCK__KEY 0x3E77 +#define BM_POWER_RESET_PWD_OFF 0x00000002 +#define BM_POWER_RESET_PWD 0x00000001 +HW_REGISTER(HW_POWER_DEBUG, REGS_POWER_BASE, 0x00000110) +#define HW_POWER_DEBUG_ADDR (REGS_POWER_BASE + 0x00000110) +#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK 0x00000008 +#define BM_POWER_DEBUG_AVALIDPIOLOCK 0x00000004 +#define BM_POWER_DEBUG_BVALIDPIOLOCK 0x00000002 +#define BM_POWER_DEBUG_SESSENDPIOLOCK 0x00000001 +HW_REGISTER(HW_POWER_SPECIAL, REGS_POWER_BASE, 0x00000120) +#define HW_POWER_SPECIAL_ADDR (REGS_POWER_BASE + 0x00000120) +#define BP_POWER_SPECIAL_TEST 0 +#define BM_POWER_SPECIAL_TEST 0xFFFFFFFF +#define BF_POWER_SPECIAL_TEST(v) (v) +HW_REGISTER_0(HW_POWER_VERSION, REGS_POWER_BASE, 0x00000130) +#define HW_POWER_VERSION_ADDR (REGS_POWER_BASE + 0x00000130) +#define BP_POWER_VERSION_MAJOR 24 +#define BM_POWER_VERSION_MAJOR 0xFF000000 +#define BF_POWER_VERSION_MAJOR(v) \ + (((v) << 24) & BM_POWER_VERSION_MAJOR) +#define BP_POWER_VERSION_MINOR 16 +#define BM_POWER_VERSION_MINOR 0x00FF0000 +#define BF_POWER_VERSION_MINOR(v) \ + (((v) << 16) & BM_POWER_VERSION_MINOR) +#define BP_POWER_VERSION_STEP 0 +#define BM_POWER_VERSION_STEP 0x0000FFFF +#define BF_POWER_VERSION_STEP(v) \ + (((v) << 0) & BM_POWER_VERSION_STEP) +#endif /* __ARCH_ARM___POWER_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-pwm.h b/arch/arm/mach-stmp3xxx/include/mach/regs-pwm.h new file mode 100644 index 000000000000..a257ee685242 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-pwm.h @@ -0,0 +1,113 @@ +/* + * STMP PWM Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___PWM_H +#define __ARCH_ARM___PWM_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_PWM_BASE (REGS_BASE + 0x64000) +#define REGS_PWM_BASE_PHYS (0x80064000) +#define REGS_PWM_SIZE 0x00002000 +HW_REGISTER(HW_PWM_CTRL, REGS_PWM_BASE, 0x00000000) +#define HW_PWM_CTRL_ADDR (REGS_PWM_BASE + 0x00000000) +#define BM_PWM_CTRL_SFTRST 0x80000000 +#define BM_PWM_CTRL_CLKGATE 0x40000000 +#define BM_PWM_CTRL_PWM4_PRESENT 0x20000000 +#define BM_PWM_CTRL_PWM3_PRESENT 0x10000000 +#define BM_PWM_CTRL_PWM2_PRESENT 0x08000000 +#define BM_PWM_CTRL_PWM1_PRESENT 0x04000000 +#define BM_PWM_CTRL_PWM0_PRESENT 0x02000000 +#define BM_PWM_CTRL_OUTPUT_CUTOFF_EN 0x00000040 +#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE 0x00000020 +#define BM_PWM_CTRL_PWM4_ENABLE 0x00000010 +#define BM_PWM_CTRL_PWM3_ENABLE 0x00000008 +#define BM_PWM_CTRL_PWM2_ENABLE 0x00000004 +#define BM_PWM_CTRL_PWM1_ENABLE 0x00000002 +#define BM_PWM_CTRL_PWM0_ENABLE 0x00000001 +/* + * multi-register-define name HW_PWM_ACTIVEn + * base 0x00000010 + * count 5 + * offset 0x20 + */ +HW_REGISTER_INDEXED(HW_PWM_ACTIVEn, REGS_PWM_BASE, 0x00000010, 0x20) +#define BP_PWM_ACTIVEn_INACTIVE 16 +#define BM_PWM_ACTIVEn_INACTIVE 0xFFFF0000 +#define BF_PWM_ACTIVEn_INACTIVE(v) \ + (((v) << 16) & BM_PWM_ACTIVEn_INACTIVE) +#define BP_PWM_ACTIVEn_ACTIVE 0 +#define BM_PWM_ACTIVEn_ACTIVE 0x0000FFFF +#define BF_PWM_ACTIVEn_ACTIVE(v) \ + (((v) << 0) & BM_PWM_ACTIVEn_ACTIVE) +/* + * multi-register-define name HW_PWM_PERIODn + * base 0x00000020 + * count 5 + * offset 0x20 + */ +HW_REGISTER_INDEXED(HW_PWM_PERIODn, REGS_PWM_BASE, 0x00000020, 0x20) +#define BM_PWM_PERIODn_MATT_SEL 0x01000000 +#define BM_PWM_PERIODn_MATT 0x00800000 +#define BP_PWM_PERIODn_CDIV 20 +#define BM_PWM_PERIODn_CDIV 0x00700000 +#define BF_PWM_PERIODn_CDIV(v) \ + (((v) << 20) & BM_PWM_PERIODn_CDIV) +#define BV_PWM_PERIODn_CDIV__DIV_1 0x0 +#define BV_PWM_PERIODn_CDIV__DIV_2 0x1 +#define BV_PWM_PERIODn_CDIV__DIV_4 0x2 +#define BV_PWM_PERIODn_CDIV__DIV_8 0x3 +#define BV_PWM_PERIODn_CDIV__DIV_16 0x4 +#define BV_PWM_PERIODn_CDIV__DIV_64 0x5 +#define BV_PWM_PERIODn_CDIV__DIV_256 0x6 +#define BV_PWM_PERIODn_CDIV__DIV_1024 0x7 +#define BP_PWM_PERIODn_INACTIVE_STATE 18 +#define BM_PWM_PERIODn_INACTIVE_STATE 0x000C0000 +#define BF_PWM_PERIODn_INACTIVE_STATE(v) \ + (((v) << 18) & BM_PWM_PERIODn_INACTIVE_STATE) +#define BV_PWM_PERIODn_INACTIVE_STATE__HI_Z 0x0 +#define BV_PWM_PERIODn_INACTIVE_STATE__0 0x2 +#define BV_PWM_PERIODn_INACTIVE_STATE__1 0x3 +#define BP_PWM_PERIODn_ACTIVE_STATE 16 +#define BM_PWM_PERIODn_ACTIVE_STATE 0x00030000 +#define BF_PWM_PERIODn_ACTIVE_STATE(v) \ + (((v) << 16) & BM_PWM_PERIODn_ACTIVE_STATE) +#define BV_PWM_PERIODn_ACTIVE_STATE__HI_Z 0x0 +#define BV_PWM_PERIODn_ACTIVE_STATE__0 0x2 +#define BV_PWM_PERIODn_ACTIVE_STATE__1 0x3 +#define BP_PWM_PERIODn_PERIOD 0 +#define BM_PWM_PERIODn_PERIOD 0x0000FFFF +#define BF_PWM_PERIODn_PERIOD(v) \ + (((v) << 0) & BM_PWM_PERIODn_PERIOD) +HW_REGISTER_0(HW_PWM_VERSION, REGS_PWM_BASE, 0x000000b0) +#define HW_PWM_VERSION_ADDR (REGS_PWM_BASE + 0x000000b0) +#define BP_PWM_VERSION_MAJOR 24 +#define BM_PWM_VERSION_MAJOR 0xFF000000 +#define BF_PWM_VERSION_MAJOR(v) \ + (((v) << 24) & BM_PWM_VERSION_MAJOR) +#define BP_PWM_VERSION_MINOR 16 +#define BM_PWM_VERSION_MINOR 0x00FF0000 +#define BF_PWM_VERSION_MINOR(v) \ + (((v) << 16) & BM_PWM_VERSION_MINOR) +#define BP_PWM_VERSION_STEP 0 +#define BM_PWM_VERSION_STEP 0x0000FFFF +#define BF_PWM_VERSION_STEP(v) \ + (((v) << 0) & BM_PWM_VERSION_STEP) +#endif /* __ARCH_ARM___PWM_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-pxp.h b/arch/arm/mach-stmp3xxx/include/mach/regs-pxp.h new file mode 100644 index 000000000000..b4160f120c6e --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-pxp.h @@ -0,0 +1,404 @@ +/* + * STMP PXP Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___PXP_H +#define __ARCH_ARM___PXP_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_PXP_BASE (REGS_BASE + 0x2a000) +#define REGS_PXP_BASE_PHYS (0x8002A000) +#define REGS_PXP_SIZE 0x00002000 +HW_REGISTER(HW_PXP_CTRL, REGS_PXP_BASE, 0x00000000) +#define HW_PXP_CTRL_ADDR (REGS_PXP_BASE + 0x00000000) +#define BM_PXP_CTRL_SFTRST 0x80000000 +#define BM_PXP_CTRL_CLKGATE 0x40000000 +#define BP_PXP_CTRL_INTERLACED_OUTPUT 26 +#define BM_PXP_CTRL_INTERLACED_OUTPUT 0x0C000000 +#define BF_PXP_CTRL_INTERLACED_OUTPUT(v) \ + (((v) << 26) & BM_PXP_CTRL_INTERLACED_OUTPUT) +#define BV_PXP_CTRL_INTERLACED_OUTPUT__PROGRESSIVE 0x0 +#define BV_PXP_CTRL_INTERLACED_OUTPUT__FIELD0 0x1 +#define BV_PXP_CTRL_INTERLACED_OUTPUT__FIELD1 0x2 +#define BV_PXP_CTRL_INTERLACED_OUTPUT__INTERLACED 0x3 +#define BP_PXP_CTRL_INTERLACED_INPUT 24 +#define BM_PXP_CTRL_INTERLACED_INPUT 0x03000000 +#define BF_PXP_CTRL_INTERLACED_INPUT(v) \ + (((v) << 24) & BM_PXP_CTRL_INTERLACED_INPUT) +#define BV_PXP_CTRL_INTERLACED_INPUT__PROGRESSIVE 0x0 +#define BV_PXP_CTRL_INTERLACED_INPUT__FIELD0 0x2 +#define BV_PXP_CTRL_INTERLACED_INPUT__FIELD1 0x3 +#define BM_PXP_CTRL_ALPHA_OUTPUT 0x00400000 +#define BM_PXP_CTRL_IN_PLACE 0x00200000 +#define BM_PXP_CTRL_DELTA 0x00100000 +#define BM_PXP_CTRL_CROP 0x00080000 +#define BM_PXP_CTRL_SCALE 0x00040000 +#define BM_PXP_CTRL_UPSAMPLE 0x00020000 +#define BM_PXP_CTRL_SUBSAMPLE 0x00010000 +#define BP_PXP_CTRL_S0_FORMAT 12 +#define BM_PXP_CTRL_S0_FORMAT 0x0000F000 +#define BF_PXP_CTRL_S0_FORMAT(v) \ + (((v) << 12) & BM_PXP_CTRL_S0_FORMAT) +#define BV_PXP_CTRL_S0_FORMAT__RGB888 0x1 +#define BV_PXP_CTRL_S0_FORMAT__RGB565 0x4 +#define BV_PXP_CTRL_S0_FORMAT__RGB555 0x5 +#define BV_PXP_CTRL_S0_FORMAT__YUV422 0x8 +#define BV_PXP_CTRL_S0_FORMAT__YUV420 0x9 +#define BM_PXP_CTRL_VFLIP 0x00000800 +#define BM_PXP_CTRL_HFLIP 0x00000400 +#define BP_PXP_CTRL_ROTATE 8 +#define BM_PXP_CTRL_ROTATE 0x00000300 +#define BF_PXP_CTRL_ROTATE(v) \ + (((v) << 8) & BM_PXP_CTRL_ROTATE) +#define BV_PXP_CTRL_ROTATE__ROT_0 0x0 +#define BV_PXP_CTRL_ROTATE__ROT_90 0x1 +#define BV_PXP_CTRL_ROTATE__ROT_180 0x2 +#define BV_PXP_CTRL_ROTATE__ROT_270 0x3 +#define BP_PXP_CTRL_OUTPUT_RGB_FORMAT 4 +#define BM_PXP_CTRL_OUTPUT_RGB_FORMAT 0x000000F0 +#define BF_PXP_CTRL_OUTPUT_RGB_FORMAT(v) \ + (((v) << 4) & BM_PXP_CTRL_OUTPUT_RGB_FORMAT) +#define BV_PXP_CTRL_OUTPUT_RGB_FORMAT__ARGB8888 0x0 +#define BV_PXP_CTRL_OUTPUT_RGB_FORMAT__RGB888 0x1 +#define BV_PXP_CTRL_OUTPUT_RGB_FORMAT__RGB888P 0x2 +#define BV_PXP_CTRL_OUTPUT_RGB_FORMAT__ARGB1555 0x3 +#define BV_PXP_CTRL_OUTPUT_RGB_FORMAT__RGB565 0x4 +#define BV_PXP_CTRL_OUTPUT_RGB_FORMAT__RGB555 0x5 +#define BM_PXP_CTRL_ENABLE_LCD_HANDSHAKE 0x00000004 +#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002 +#define BM_PXP_CTRL_ENABLE 0x00000001 +HW_REGISTER(HW_PXP_STAT, REGS_PXP_BASE, 0x00000010) +#define HW_PXP_STAT_ADDR (REGS_PXP_BASE + 0x00000010) +#define BP_PXP_STAT_BLOCKX 24 +#define BM_PXP_STAT_BLOCKX 0xFF000000 +#define BF_PXP_STAT_BLOCKX(v) \ + (((v) << 24) & BM_PXP_STAT_BLOCKX) +#define BP_PXP_STAT_BLOCKY 16 +#define BM_PXP_STAT_BLOCKY 0x00FF0000 +#define BF_PXP_STAT_BLOCKY(v) \ + (((v) << 16) & BM_PXP_STAT_BLOCKY) +#define BP_PXP_STAT_AXI_ERROR_ID 4 +#define BM_PXP_STAT_AXI_ERROR_ID 0x000000F0 +#define BF_PXP_STAT_AXI_ERROR_ID(v) \ + (((v) << 4) & BM_PXP_STAT_AXI_ERROR_ID) +#define BM_PXP_STAT_AXI_READ_ERROR 0x00000004 +#define BM_PXP_STAT_AXI_WRITE_ERROR 0x00000002 +#define BM_PXP_STAT_IRQ 0x00000001 +HW_REGISTER_0(HW_PXP_RGBBUF, REGS_PXP_BASE, 0x00000020) +#define HW_PXP_RGBBUF_ADDR (REGS_PXP_BASE + 0x00000020) +#define BP_PXP_RGBBUF_ADDR 0 +#define BM_PXP_RGBBUF_ADDR 0xFFFFFFFF +#define BF_PXP_RGBBUF_ADDR(v) (v) +HW_REGISTER_0(HW_PXP_RGBBUF2, REGS_PXP_BASE, 0x00000030) +#define HW_PXP_RGBBUF2_ADDR (REGS_PXP_BASE + 0x00000030) +#define BP_PXP_RGBBUF2_ADDR 0 +#define BM_PXP_RGBBUF2_ADDR 0xFFFFFFFF +#define BF_PXP_RGBBUF2_ADDR(v) (v) +HW_REGISTER_0(HW_PXP_RGBSIZE, REGS_PXP_BASE, 0x00000040) +#define HW_PXP_RGBSIZE_ADDR (REGS_PXP_BASE + 0x00000040) +#define BP_PXP_RGBSIZE_ALPHA 24 +#define BM_PXP_RGBSIZE_ALPHA 0xFF000000 +#define BF_PXP_RGBSIZE_ALPHA(v) \ + (((v) << 24) & BM_PXP_RGBSIZE_ALPHA) +#define BP_PXP_RGBSIZE_WIDTH 12 +#define BM_PXP_RGBSIZE_WIDTH 0x00FFF000 +#define BF_PXP_RGBSIZE_WIDTH(v) \ + (((v) << 12) & BM_PXP_RGBSIZE_WIDTH) +#define BP_PXP_RGBSIZE_HEIGHT 0 +#define BM_PXP_RGBSIZE_HEIGHT 0x00000FFF +#define BF_PXP_RGBSIZE_HEIGHT(v) \ + (((v) << 0) & BM_PXP_RGBSIZE_HEIGHT) +HW_REGISTER_0(HW_PXP_S0BUF, REGS_PXP_BASE, 0x00000050) +#define HW_PXP_S0BUF_ADDR (REGS_PXP_BASE + 0x00000050) +#define BP_PXP_S0BUF_ADDR 0 +#define BM_PXP_S0BUF_ADDR 0xFFFFFFFF +#define BF_PXP_S0BUF_ADDR(v) (v) +HW_REGISTER_0(HW_PXP_S0UBUF, REGS_PXP_BASE, 0x00000060) +#define HW_PXP_S0UBUF_ADDR (REGS_PXP_BASE + 0x00000060) +#define BP_PXP_S0UBUF_ADDR 0 +#define BM_PXP_S0UBUF_ADDR 0xFFFFFFFF +#define BF_PXP_S0UBUF_ADDR(v) (v) +HW_REGISTER_0(HW_PXP_S0VBUF, REGS_PXP_BASE, 0x00000070) +#define HW_PXP_S0VBUF_ADDR (REGS_PXP_BASE + 0x00000070) +#define BP_PXP_S0VBUF_ADDR 0 +#define BM_PXP_S0VBUF_ADDR 0xFFFFFFFF +#define BF_PXP_S0VBUF_ADDR(v) (v) +HW_REGISTER_0(HW_PXP_S0PARAM, REGS_PXP_BASE, 0x00000080) +#define HW_PXP_S0PARAM_ADDR (REGS_PXP_BASE + 0x00000080) +#define BP_PXP_S0PARAM_XBASE 24 +#define BM_PXP_S0PARAM_XBASE 0xFF000000 +#define BF_PXP_S0PARAM_XBASE(v) \ + (((v) << 24) & BM_PXP_S0PARAM_XBASE) +#define BP_PXP_S0PARAM_YBASE 16 +#define BM_PXP_S0PARAM_YBASE 0x00FF0000 +#define BF_PXP_S0PARAM_YBASE(v) \ + (((v) << 16) & BM_PXP_S0PARAM_YBASE) +#define BP_PXP_S0PARAM_WIDTH 8 +#define BM_PXP_S0PARAM_WIDTH 0x0000FF00 +#define BF_PXP_S0PARAM_WIDTH(v) \ + (((v) << 8) & BM_PXP_S0PARAM_WIDTH) +#define BP_PXP_S0PARAM_HEIGHT 0 +#define BM_PXP_S0PARAM_HEIGHT 0x000000FF +#define BF_PXP_S0PARAM_HEIGHT(v) \ + (((v) << 0) & BM_PXP_S0PARAM_HEIGHT) +HW_REGISTER_0(HW_PXP_S0BACKGROUND, REGS_PXP_BASE, 0x00000090) +#define HW_PXP_S0BACKGROUND_ADDR (REGS_PXP_BASE + 0x00000090) +#define BP_PXP_S0BACKGROUND_COLOR 0 +#define BM_PXP_S0BACKGROUND_COLOR 0xFFFFFFFF +#define BF_PXP_S0BACKGROUND_COLOR(v) (v) +HW_REGISTER_0(HW_PXP_S0CROP, REGS_PXP_BASE, 0x000000a0) +#define HW_PXP_S0CROP_ADDR (REGS_PXP_BASE + 0x000000a0) +#define BP_PXP_S0CROP_XBASE 24 +#define BM_PXP_S0CROP_XBASE 0xFF000000 +#define BF_PXP_S0CROP_XBASE(v) \ + (((v) << 24) & BM_PXP_S0CROP_XBASE) +#define BP_PXP_S0CROP_YBASE 16 +#define BM_PXP_S0CROP_YBASE 0x00FF0000 +#define BF_PXP_S0CROP_YBASE(v) \ + (((v) << 16) & BM_PXP_S0CROP_YBASE) +#define BP_PXP_S0CROP_WIDTH 8 +#define BM_PXP_S0CROP_WIDTH 0x0000FF00 +#define BF_PXP_S0CROP_WIDTH(v) \ + (((v) << 8) & BM_PXP_S0CROP_WIDTH) +#define BP_PXP_S0CROP_HEIGHT 0 +#define BM_PXP_S0CROP_HEIGHT 0x000000FF +#define BF_PXP_S0CROP_HEIGHT(v) \ + (((v) << 0) & BM_PXP_S0CROP_HEIGHT) +HW_REGISTER_0(HW_PXP_S0SCALE, REGS_PXP_BASE, 0x000000b0) +#define HW_PXP_S0SCALE_ADDR (REGS_PXP_BASE + 0x000000b0) +#define BP_PXP_S0SCALE_YSCALE 16 +#define BM_PXP_S0SCALE_YSCALE 0x3FFF0000 +#define BF_PXP_S0SCALE_YSCALE(v) \ + (((v) << 16) & BM_PXP_S0SCALE_YSCALE) +#define BP_PXP_S0SCALE_XSCALE 0 +#define BM_PXP_S0SCALE_XSCALE 0x00003FFF +#define BF_PXP_S0SCALE_XSCALE(v) \ + (((v) << 0) & BM_PXP_S0SCALE_XSCALE) +HW_REGISTER_0(HW_PXP_S0OFFSET, REGS_PXP_BASE, 0x000000c0) +#define HW_PXP_S0OFFSET_ADDR (REGS_PXP_BASE + 0x000000c0) +#define BP_PXP_S0OFFSET_YOFFSET 16 +#define BM_PXP_S0OFFSET_YOFFSET 0x0FFF0000 +#define BF_PXP_S0OFFSET_YOFFSET(v) \ + (((v) << 16) & BM_PXP_S0OFFSET_YOFFSET) +#define BP_PXP_S0OFFSET_XOFFSET 0 +#define BM_PXP_S0OFFSET_XOFFSET 0x00000FFF +#define BF_PXP_S0OFFSET_XOFFSET(v) \ + (((v) << 0) & BM_PXP_S0OFFSET_XOFFSET) +HW_REGISTER_0(HW_PXP_CSCCOEFF0, REGS_PXP_BASE, 0x000000d0) +#define HW_PXP_CSCCOEFF0_ADDR (REGS_PXP_BASE + 0x000000d0) +#define BM_PXP_CSCCOEFF0_YCBCR_MODE 0x80000000 +#define BP_PXP_CSCCOEFF0_C0 18 +#define BM_PXP_CSCCOEFF0_C0 0x1FFC0000 +#define BF_PXP_CSCCOEFF0_C0(v) \ + (((v) << 18) & BM_PXP_CSCCOEFF0_C0) +#define BP_PXP_CSCCOEFF0_UV_OFFSET 9 +#define BM_PXP_CSCCOEFF0_UV_OFFSET 0x0003FE00 +#define BF_PXP_CSCCOEFF0_UV_OFFSET(v) \ + (((v) << 9) & BM_PXP_CSCCOEFF0_UV_OFFSET) +#define BP_PXP_CSCCOEFF0_Y_OFFSET 0 +#define BM_PXP_CSCCOEFF0_Y_OFFSET 0x000001FF +#define BF_PXP_CSCCOEFF0_Y_OFFSET(v) \ + (((v) << 0) & BM_PXP_CSCCOEFF0_Y_OFFSET) +HW_REGISTER_0(HW_PXP_CSCCOEFF1, REGS_PXP_BASE, 0x000000e0) +#define HW_PXP_CSCCOEFF1_ADDR (REGS_PXP_BASE + 0x000000e0) +#define BP_PXP_CSCCOEFF1_C1 16 +#define BM_PXP_CSCCOEFF1_C1 0x07FF0000 +#define BF_PXP_CSCCOEFF1_C1(v) \ + (((v) << 16) & BM_PXP_CSCCOEFF1_C1) +#define BP_PXP_CSCCOEFF1_C4 0 +#define BM_PXP_CSCCOEFF1_C4 0x000007FF +#define BF_PXP_CSCCOEFF1_C4(v) \ + (((v) << 0) & BM_PXP_CSCCOEFF1_C4) +HW_REGISTER_0(HW_PXP_CSCCOEFF2, REGS_PXP_BASE, 0x000000f0) +#define HW_PXP_CSCCOEFF2_ADDR (REGS_PXP_BASE + 0x000000f0) +#define BP_PXP_CSCCOEFF2_C2 16 +#define BM_PXP_CSCCOEFF2_C2 0x07FF0000 +#define BF_PXP_CSCCOEFF2_C2(v) \ + (((v) << 16) & BM_PXP_CSCCOEFF2_C2) +#define BP_PXP_CSCCOEFF2_C3 0 +#define BM_PXP_CSCCOEFF2_C3 0x000007FF +#define BF_PXP_CSCCOEFF2_C3(v) \ + (((v) << 0) & BM_PXP_CSCCOEFF2_C3) +HW_REGISTER(HW_PXP_NEXT, REGS_PXP_BASE, 0x00000100) +#define HW_PXP_NEXT_ADDR (REGS_PXP_BASE + 0x00000100) +#define BP_PXP_NEXT_POINTER 2 +#define BM_PXP_NEXT_POINTER 0xFFFFFFFC +#define BF_PXP_NEXT_POINTER(v) \ + (((v) << 2) & BM_PXP_NEXT_POINTER) +#define BM_PXP_NEXT_ENABLED 0x00000001 +HW_REGISTER_0(HW_PXP_PAGETABLE, REGS_PXP_BASE, 0x00000170) +#define HW_PXP_PAGETABLE_ADDR (REGS_PXP_BASE + 0x00000170) +#define BP_PXP_PAGETABLE_BASE 14 +#define BM_PXP_PAGETABLE_BASE 0xFFFFC000 +#define BF_PXP_PAGETABLE_BASE(v) \ + (((v) << 14) & BM_PXP_PAGETABLE_BASE) +#define BM_PXP_PAGETABLE_FLUSH 0x00000002 +#define BM_PXP_PAGETABLE_ENABLE 0x00000001 +HW_REGISTER_0(HW_PXP_S0COLORKEYLOW, REGS_PXP_BASE, 0x00000180) +#define HW_PXP_S0COLORKEYLOW_ADDR (REGS_PXP_BASE + 0x00000180) +#define BP_PXP_S0COLORKEYLOW_PIXEL 0 +#define BM_PXP_S0COLORKEYLOW_PIXEL 0x00FFFFFF +#define BF_PXP_S0COLORKEYLOW_PIXEL(v) \ + (((v) << 0) & BM_PXP_S0COLORKEYLOW_PIXEL) +HW_REGISTER_0(HW_PXP_S0COLORKEYHIGH, REGS_PXP_BASE, 0x00000190) +#define HW_PXP_S0COLORKEYHIGH_ADDR (REGS_PXP_BASE + 0x00000190) +#define BP_PXP_S0COLORKEYHIGH_PIXEL 0 +#define BM_PXP_S0COLORKEYHIGH_PIXEL 0x00FFFFFF +#define BF_PXP_S0COLORKEYHIGH_PIXEL(v) \ + (((v) << 0) & BM_PXP_S0COLORKEYHIGH_PIXEL) +HW_REGISTER_0(HW_PXP_OLCOLORKEYLOW, REGS_PXP_BASE, 0x000001a0) +#define HW_PXP_OLCOLORKEYLOW_ADDR (REGS_PXP_BASE + 0x000001a0) +#define BP_PXP_OLCOLORKEYLOW_PIXEL 0 +#define BM_PXP_OLCOLORKEYLOW_PIXEL 0x00FFFFFF +#define BF_PXP_OLCOLORKEYLOW_PIXEL(v) \ + (((v) << 0) & BM_PXP_OLCOLORKEYLOW_PIXEL) +HW_REGISTER_0(HW_PXP_OLCOLORKEYHIGH, REGS_PXP_BASE, 0x000001b0) +#define HW_PXP_OLCOLORKEYHIGH_ADDR (REGS_PXP_BASE + 0x000001b0) +#define BP_PXP_OLCOLORKEYHIGH_PIXEL 0 +#define BM_PXP_OLCOLORKEYHIGH_PIXEL 0x00FFFFFF +#define BF_PXP_OLCOLORKEYHIGH_PIXEL(v) \ + (((v) << 0) & BM_PXP_OLCOLORKEYHIGH_PIXEL) +HW_REGISTER_0(HW_PXP_DEBUGCTRL, REGS_PXP_BASE, 0x000001d0) +#define HW_PXP_DEBUGCTRL_ADDR (REGS_PXP_BASE + 0x000001d0) +#define BM_PXP_DEBUGCTRL_RESET_TLB_STATS 0x00000100 +#define BP_PXP_DEBUGCTRL_SELECT 0 +#define BM_PXP_DEBUGCTRL_SELECT 0x000000FF +#define BF_PXP_DEBUGCTRL_SELECT(v) \ + (((v) << 0) & BM_PXP_DEBUGCTRL_SELECT) +#define BV_PXP_DEBUGCTRL_SELECT__NONE 0x0 +#define BV_PXP_DEBUGCTRL_SELECT__CTRL 0x1 +#define BV_PXP_DEBUGCTRL_SELECT__S0REGS 0x2 +#define BV_PXP_DEBUGCTRL_SELECT__S0BAX 0x3 +#define BV_PXP_DEBUGCTRL_SELECT__S0BAY 0x4 +#define BV_PXP_DEBUGCTRL_SELECT__PXBUF 0x5 +#define BV_PXP_DEBUGCTRL_SELECT__ROTATION 0x6 +#define BV_PXP_DEBUGCTRL_SELECT__ROTBUF0 0x7 +#define BV_PXP_DEBUGCTRL_SELECT__ROTBUF1 0x8 +#define BV_PXP_DEBUGCTRL_SELECT__TLBCOUNT 0xF0 +#define BV_PXP_DEBUGCTRL_SELECT__TLBHIT 0xF1 +#define BV_PXP_DEBUGCTRL_SELECT__TLBMISS 0xF2 +#define BV_PXP_DEBUGCTRL_SELECT__TLBLAT 0xF3 +#define BV_PXP_DEBUGCTRL_SELECT__TLBSTATE 0xF8 +HW_REGISTER_0(HW_PXP_DEBUG, REGS_PXP_BASE, 0x000001e0) +#define HW_PXP_DEBUG_ADDR (REGS_PXP_BASE + 0x000001e0) +#define BP_PXP_DEBUG_DATA 0 +#define BM_PXP_DEBUG_DATA 0xFFFFFFFF +#define BF_PXP_DEBUG_DATA(v) (v) +HW_REGISTER_0(HW_PXP_VERSION, REGS_PXP_BASE, 0x000001f0) +#define HW_PXP_VERSION_ADDR (REGS_PXP_BASE + 0x000001f0) +#define BP_PXP_VERSION_MAJOR 24 +#define BM_PXP_VERSION_MAJOR 0xFF000000 +#define BF_PXP_VERSION_MAJOR(v) \ + (((v) << 24) & BM_PXP_VERSION_MAJOR) +#define BP_PXP_VERSION_MINOR 16 +#define BM_PXP_VERSION_MINOR 0x00FF0000 +#define BF_PXP_VERSION_MINOR(v) \ + (((v) << 16) & BM_PXP_VERSION_MINOR) +#define BP_PXP_VERSION_STEP 0 +#define BM_PXP_VERSION_STEP 0x0000FFFF +#define BF_PXP_VERSION_STEP(v) \ + (((v) << 0) & BM_PXP_VERSION_STEP) +/* + * multi-register-define name HW_PXP_OLn + * base 0x00000200 + * count 8 + * offset 0x40 + */ +HW_REGISTER_0_INDEXED(HW_PXP_OLn, REGS_PXP_BASE, 0x00000200, 0x40) +#define BP_PXP_OLn_ADDR 0 +#define BM_PXP_OLn_ADDR 0xFFFFFFFF +#define BF_PXP_OLn_ADDR(v) (v) +/* + * multi-register-define name HW_PXP_OLnSIZE + * base 0x00000210 + * count 8 + * offset 0x40 + */ +HW_REGISTER_0_INDEXED(HW_PXP_OLnSIZE, REGS_PXP_BASE, 0x00000210, 0x40) +#define BP_PXP_OLnSIZE_XBASE 24 +#define BM_PXP_OLnSIZE_XBASE 0xFF000000 +#define BF_PXP_OLnSIZE_XBASE(v) \ + (((v) << 24) & BM_PXP_OLnSIZE_XBASE) +#define BP_PXP_OLnSIZE_YBASE 16 +#define BM_PXP_OLnSIZE_YBASE 0x00FF0000 +#define BF_PXP_OLnSIZE_YBASE(v) \ + (((v) << 16) & BM_PXP_OLnSIZE_YBASE) +#define BP_PXP_OLnSIZE_WIDTH 8 +#define BM_PXP_OLnSIZE_WIDTH 0x0000FF00 +#define BF_PXP_OLnSIZE_WIDTH(v) \ + (((v) << 8) & BM_PXP_OLnSIZE_WIDTH) +#define BP_PXP_OLnSIZE_HEIGHT 0 +#define BM_PXP_OLnSIZE_HEIGHT 0x000000FF +#define BF_PXP_OLnSIZE_HEIGHT(v) \ + (((v) << 0) & BM_PXP_OLnSIZE_HEIGHT) +/* + * multi-register-define name HW_PXP_OLnPARAM + * base 0x00000220 + * count 8 + * offset 0x40 + */ +HW_REGISTER_0_INDEXED(HW_PXP_OLnPARAM, REGS_PXP_BASE, 0x00000220, 0x40) +#define BP_PXP_OLnPARAM_ROP 16 +#define BM_PXP_OLnPARAM_ROP 0x000F0000 +#define BF_PXP_OLnPARAM_ROP(v) \ + (((v) << 16) & BM_PXP_OLnPARAM_ROP) +#define BV_PXP_OLnPARAM_ROP__MASKOL 0x0 +#define BV_PXP_OLnPARAM_ROP__MASKNOTOL 0x1 +#define BV_PXP_OLnPARAM_ROP__MASKOLNOT 0x2 +#define BV_PXP_OLnPARAM_ROP__MERGEOL 0x3 +#define BV_PXP_OLnPARAM_ROP__MERGENOTOL 0x4 +#define BV_PXP_OLnPARAM_ROP__MERGEOLNOT 0x5 +#define BV_PXP_OLnPARAM_ROP__NOTCOPYOL 0x6 +#define BV_PXP_OLnPARAM_ROP__NOT 0x7 +#define BV_PXP_OLnPARAM_ROP__NOTMASKOL 0x8 +#define BV_PXP_OLnPARAM_ROP__NOTMERGEOL 0x9 +#define BV_PXP_OLnPARAM_ROP__XOROL 0xA +#define BV_PXP_OLnPARAM_ROP__NOTXOROL 0xB +#define BP_PXP_OLnPARAM_ALPHA 8 +#define BM_PXP_OLnPARAM_ALPHA 0x0000FF00 +#define BF_PXP_OLnPARAM_ALPHA(v) \ + (((v) << 8) & BM_PXP_OLnPARAM_ALPHA) +#define BP_PXP_OLnPARAM_FORMAT 4 +#define BM_PXP_OLnPARAM_FORMAT 0x000000F0 +#define BF_PXP_OLnPARAM_FORMAT(v) \ + (((v) << 4) & BM_PXP_OLnPARAM_FORMAT) +#define BV_PXP_OLnPARAM_FORMAT__ARGB8888 0x0 +#define BV_PXP_OLnPARAM_FORMAT__RGB888 0x1 +#define BV_PXP_OLnPARAM_FORMAT__ARGB1555 0x3 +#define BV_PXP_OLnPARAM_FORMAT__RGB565 0x4 +#define BV_PXP_OLnPARAM_FORMAT__RGB555 0x5 +#define BM_PXP_OLnPARAM_ENABLE_COLORKEY 0x00000008 +#define BP_PXP_OLnPARAM_ALPHA_CNTL 1 +#define BM_PXP_OLnPARAM_ALPHA_CNTL 0x00000006 +#define BF_PXP_OLnPARAM_ALPHA_CNTL(v) \ + (((v) << 1) & BM_PXP_OLnPARAM_ALPHA_CNTL) +#define BV_PXP_OLnPARAM_ALPHA_CNTL__Embedded 0x0 +#define BV_PXP_OLnPARAM_ALPHA_CNTL__Override 0x1 +#define BV_PXP_OLnPARAM_ALPHA_CNTL__Multiply 0x2 +#define BV_PXP_OLnPARAM_ALPHA_CNTL__ROPs 0x3 +#define BM_PXP_OLnPARAM_ENABLE 0x00000001 +/* + * multi-register-define name HW_PXP_OLnPARAM2 + * base 0x00000230 + * count 8 + * offset 0x40 + */ +HW_REGISTER_0_INDEXED(HW_PXP_OLnPARAM2, REGS_PXP_BASE, 0x00000230, 0x40) +#endif /* __ARCH_ARM___PXP_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-rtc.h b/arch/arm/mach-stmp3xxx/include/mach/regs-rtc.h new file mode 100644 index 000000000000..6ee096587538 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-rtc.h @@ -0,0 +1,149 @@ +/* + * STMP RTC Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___RTC_H +#define __ARCH_ARM___RTC_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_RTC_BASE (REGS_BASE + 0x5c000) +#define REGS_RTC_BASE_PHYS (0x8005C000) +#define REGS_RTC_SIZE 0x00002000 +HW_REGISTER(HW_RTC_CTRL, REGS_RTC_BASE, 0x00000000) +#define HW_RTC_CTRL_ADDR (REGS_RTC_BASE + 0x00000000) +#define BM_RTC_CTRL_SFTRST 0x80000000 +#define BM_RTC_CTRL_CLKGATE 0x40000000 +#define BM_RTC_CTRL_SUPPRESS_COPY2ANALOG 0x00000040 +#define BM_RTC_CTRL_FORCE_UPDATE 0x00000020 +#define BM_RTC_CTRL_WATCHDOGEN 0x00000010 +#define BM_RTC_CTRL_ONEMSEC_IRQ 0x00000008 +#define BM_RTC_CTRL_ALARM_IRQ 0x00000004 +#define BM_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 +#define BM_RTC_CTRL_ALARM_IRQ_EN 0x00000001 +HW_REGISTER(HW_RTC_STAT, REGS_RTC_BASE, 0x00000010) +#define HW_RTC_STAT_ADDR (REGS_RTC_BASE + 0x00000010) +#define BM_RTC_STAT_RTC_PRESENT 0x80000000 +#define BM_RTC_STAT_ALARM_PRESENT 0x40000000 +#define BM_RTC_STAT_WATCHDOG_PRESENT 0x20000000 +#define BM_RTC_STAT_XTAL32000_PRESENT 0x10000000 +#define BM_RTC_STAT_XTAL32768_PRESENT 0x08000000 +#define BP_RTC_STAT_STALE_REGS 16 +#define BM_RTC_STAT_STALE_REGS 0x00FF0000 +#define BF_RTC_STAT_STALE_REGS(v) \ + (((v) << 16) & BM_RTC_STAT_STALE_REGS) +#define BP_RTC_STAT_NEW_REGS 8 +#define BM_RTC_STAT_NEW_REGS 0x0000FF00 +#define BF_RTC_STAT_NEW_REGS(v) \ + (((v) << 8) & BM_RTC_STAT_NEW_REGS) +HW_REGISTER(HW_RTC_MILLISECONDS, REGS_RTC_BASE, 0x00000020) +#define HW_RTC_MILLISECONDS_ADDR (REGS_RTC_BASE + 0x00000020) +#define BP_RTC_MILLISECONDS_COUNT 0 +#define BM_RTC_MILLISECONDS_COUNT 0xFFFFFFFF +#define BF_RTC_MILLISECONDS_COUNT(v) (v) +HW_REGISTER(HW_RTC_SECONDS, REGS_RTC_BASE, 0x00000030) +#define HW_RTC_SECONDS_ADDR (REGS_RTC_BASE + 0x00000030) +#define BP_RTC_SECONDS_COUNT 0 +#define BM_RTC_SECONDS_COUNT 0xFFFFFFFF +#define BF_RTC_SECONDS_COUNT(v) (v) +HW_REGISTER(HW_RTC_ALARM, REGS_RTC_BASE, 0x00000040) +#define HW_RTC_ALARM_ADDR (REGS_RTC_BASE + 0x00000040) +#define BP_RTC_ALARM_VALUE 0 +#define BM_RTC_ALARM_VALUE 0xFFFFFFFF +#define BF_RTC_ALARM_VALUE(v) (v) +HW_REGISTER(HW_RTC_WATCHDOG, REGS_RTC_BASE, 0x00000050) +#define HW_RTC_WATCHDOG_ADDR (REGS_RTC_BASE + 0x00000050) +#define BP_RTC_WATCHDOG_COUNT 0 +#define BM_RTC_WATCHDOG_COUNT 0xFFFFFFFF +#define BF_RTC_WATCHDOG_COUNT(v) (v) +HW_REGISTER(HW_RTC_PERSISTENT0, REGS_RTC_BASE, 0x00000060) +#define HW_RTC_PERSISTENT0_ADDR (REGS_RTC_BASE + 0x00000060) +#define BP_RTC_PERSISTENT0_SPARE_ANALOG 18 +#define BM_RTC_PERSISTENT0_SPARE_ANALOG 0xFFFC0000 +#define BF_RTC_PERSISTENT0_SPARE_ANALOG(v) \ + (((v) << 18) & BM_RTC_PERSISTENT0_SPARE_ANALOG) +#define BM_RTC_PERSISTENT0_AUTO_RESTART 0x00020000 +#define BM_RTC_PERSISTENT0_DISABLE_PSWITCH 0x00010000 +#define BP_RTC_PERSISTENT0_LOWERBIAS 14 +#define BM_RTC_PERSISTENT0_LOWERBIAS 0x0000C000 +#define BF_RTC_PERSISTENT0_LOWERBIAS(v) \ + (((v) << 14) & BM_RTC_PERSISTENT0_LOWERBIAS) +#define BM_RTC_PERSISTENT0_DISABLE_XTALOK 0x00002000 +#define BP_RTC_PERSISTENT0_MSEC_RES 8 +#define BM_RTC_PERSISTENT0_MSEC_RES 0x00001F00 +#define BF_RTC_PERSISTENT0_MSEC_RES(v) \ + (((v) << 8) & BM_RTC_PERSISTENT0_MSEC_RES) +#define BM_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 +#define BM_RTC_PERSISTENT0_XTAL32_FREQ 0x00000040 +#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP 0x00000020 +#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP 0x00000010 +#define BM_RTC_PERSISTENT0_LCK_SECS 0x00000008 +#define BM_RTC_PERSISTENT0_ALARM_EN 0x00000004 +#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 +#define BM_RTC_PERSISTENT0_CLOCKSOURCE 0x00000001 +HW_REGISTER(HW_RTC_PERSISTENT1, REGS_RTC_BASE, 0x00000070) +#define HW_RTC_PERSISTENT1_ADDR (REGS_RTC_BASE + 0x00000070) +#define BP_RTC_PERSISTENT1_GENERAL 0 +#define BM_RTC_PERSISTENT1_GENERAL 0xFFFFFFFF +#define BF_RTC_PERSISTENT1_GENERAL(v) (v) +#define BV_RTC_PERSISTENT1_GENERAL__ENUMERATE_500MA_TWICE 0x1000 +#define BV_RTC_PERSISTENT1_GENERAL__USB_BOOT_PLAYER_MODE 0x0800 +#define BV_RTC_PERSISTENT1_GENERAL__SKIP_CHECKDISK 0x0400 +#define BV_RTC_PERSISTENT1_GENERAL__USB_LOW_POWER_MODE 0x0200 +#define BV_RTC_PERSISTENT1_GENERAL__OTG_HNP_BIT 0x0100 +#define BV_RTC_PERSISTENT1_GENERAL__OTG_ATL_ROLE_BIT 0x0080 +HW_REGISTER(HW_RTC_PERSISTENT2, REGS_RTC_BASE, 0x00000080) +#define HW_RTC_PERSISTENT2_ADDR (REGS_RTC_BASE + 0x00000080) +#define BP_RTC_PERSISTENT2_GENERAL 0 +#define BM_RTC_PERSISTENT2_GENERAL 0xFFFFFFFF +#define BF_RTC_PERSISTENT2_GENERAL(v) (v) +HW_REGISTER(HW_RTC_PERSISTENT3, REGS_RTC_BASE, 0x00000090) +#define HW_RTC_PERSISTENT3_ADDR (REGS_RTC_BASE + 0x00000090) +#define BP_RTC_PERSISTENT3_GENERAL 0 +#define BM_RTC_PERSISTENT3_GENERAL 0xFFFFFFFF +#define BF_RTC_PERSISTENT3_GENERAL(v) (v) +HW_REGISTER(HW_RTC_PERSISTENT4, REGS_RTC_BASE, 0x000000a0) +#define HW_RTC_PERSISTENT4_ADDR (REGS_RTC_BASE + 0x000000a0) +#define BP_RTC_PERSISTENT4_GENERAL 0 +#define BM_RTC_PERSISTENT4_GENERAL 0xFFFFFFFF +#define BF_RTC_PERSISTENT4_GENERAL(v) (v) +HW_REGISTER(HW_RTC_PERSISTENT5, REGS_RTC_BASE, 0x000000b0) +#define HW_RTC_PERSISTENT5_ADDR (REGS_RTC_BASE + 0x000000b0) +#define BP_RTC_PERSISTENT5_GENERAL 0 +#define BM_RTC_PERSISTENT5_GENERAL 0xFFFFFFFF +#define BF_RTC_PERSISTENT5_GENERAL(v) (v) +HW_REGISTER(HW_RTC_DEBUG, REGS_RTC_BASE, 0x000000c0) +#define HW_RTC_DEBUG_ADDR (REGS_RTC_BASE + 0x000000c0) +#define BM_RTC_DEBUG_WATCHDOG_RESET_MASK 0x00000002 +#define BM_RTC_DEBUG_WATCHDOG_RESET 0x00000001 +HW_REGISTER_0(HW_RTC_VERSION, REGS_RTC_BASE, 0x000000d0) +#define HW_RTC_VERSION_ADDR (REGS_RTC_BASE + 0x000000d0) +#define BP_RTC_VERSION_MAJOR 24 +#define BM_RTC_VERSION_MAJOR 0xFF000000 +#define BF_RTC_VERSION_MAJOR(v) \ + (((v) << 24) & BM_RTC_VERSION_MAJOR) +#define BP_RTC_VERSION_MINOR 16 +#define BM_RTC_VERSION_MINOR 0x00FF0000 +#define BF_RTC_VERSION_MINOR(v) \ + (((v) << 16) & BM_RTC_VERSION_MINOR) +#define BP_RTC_VERSION_STEP 0 +#define BM_RTC_VERSION_STEP 0x0000FFFF +#define BF_RTC_VERSION_STEP(v) \ + (((v) << 0) & BM_RTC_VERSION_STEP) +#endif /* __ARCH_ARM___RTC_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-saif.h b/arch/arm/mach-stmp3xxx/include/mach/regs-saif.h new file mode 100644 index 000000000000..494ea274c0c1 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-saif.h @@ -0,0 +1,94 @@ +/* + * STMP SAIF Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___SAIF_H +#define __ARCH_ARM___SAIF_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_SAIF_BASE (REGS_BASE + 0x42000) +#define REGS_SAIF1_BASE_PHYS (0x80042000) +#define REGS_SAIF2_BASE_PHYS (0x80046000) +#define REGS_SAIF_SIZE 0x00002000 +HW_REGISTER(HW_SAIF_CTRL, REGS_SAIF_BASE, 0x00000000) +#define HW_SAIF_CTRL_ADDR (REGS_SAIF_BASE + 0x00000000) +#define BM_SAIF_CTRL_SFTRST 0x80000000 +#define BM_SAIF_CTRL_CLKGATE 0x40000000 +#define BP_SAIF_CTRL_BITCLK_MULT_RATE 27 +#define BM_SAIF_CTRL_BITCLK_MULT_RATE 0x38000000 +#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \ + (((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE) +#define BM_SAIF_CTRL_BITCLK_BASE_RATE 0x04000000 +#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN 0x02000000 +#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN 0x01000000 +#define BP_SAIF_CTRL_DMAWAIT_COUNT 16 +#define BM_SAIF_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT) +#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14 +#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000 +#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \ + (((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT) +#define BM_SAIF_CTRL_BIT_ORDER 0x00001000 +#define BM_SAIF_CTRL_DELAY 0x00000800 +#define BM_SAIF_CTRL_JUSTIFY 0x00000400 +#define BM_SAIF_CTRL_LRCLK_POLARITY 0x00000200 +#define BM_SAIF_CTRL_BITCLK_EDGE 0x00000100 +#define BP_SAIF_CTRL_WORD_LENGTH 4 +#define BM_SAIF_CTRL_WORD_LENGTH 0x000000F0 +#define BF_SAIF_CTRL_WORD_LENGTH(v) \ + (((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH) +#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE 0x00000008 +#define BM_SAIF_CTRL_SLAVE_MODE 0x00000004 +#define BM_SAIF_CTRL_READ_MODE 0x00000002 +#define BM_SAIF_CTRL_RUN 0x00000001 +HW_REGISTER(HW_SAIF_STAT, REGS_SAIF_BASE, 0x00000010) +#define HW_SAIF_STAT_ADDR (REGS_SAIF_BASE + 0x00000010) +#define BM_SAIF_STAT_PRESENT 0x80000000 +#define BM_SAIF_STAT_DMA_PREQ 0x00010000 +#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040 +#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ 0x00000020 +#define BM_SAIF_STAT_FIFO_SERVICE_IRQ 0x00000010 +#define BM_SAIF_STAT_BUSY 0x00000001 +HW_REGISTER(HW_SAIF_DATA, REGS_SAIF_BASE, 0x00000020) +#define HW_SAIF_DATA_ADDR (REGS_SAIF_BASE + 0x00000020) +#define BP_SAIF_DATA_PCM_RIGHT 16 +#define BM_SAIF_DATA_PCM_RIGHT 0xFFFF0000 +#define BF_SAIF_DATA_PCM_RIGHT(v) \ + (((v) << 16) & BM_SAIF_DATA_PCM_RIGHT) +#define BP_SAIF_DATA_PCM_LEFT 0 +#define BM_SAIF_DATA_PCM_LEFT 0x0000FFFF +#define BF_SAIF_DATA_PCM_LEFT(v) \ + (((v) << 0) & BM_SAIF_DATA_PCM_LEFT) +HW_REGISTER_0(HW_SAIF_VERSION, REGS_SAIF_BASE, 0x00000030) +#define HW_SAIF_VERSION_ADDR (REGS_SAIF_BASE + 0x00000030) +#define BP_SAIF_VERSION_MAJOR 24 +#define BM_SAIF_VERSION_MAJOR 0xFF000000 +#define BF_SAIF_VERSION_MAJOR(v) \ + (((v) << 24) & BM_SAIF_VERSION_MAJOR) +#define BP_SAIF_VERSION_MINOR 16 +#define BM_SAIF_VERSION_MINOR 0x00FF0000 +#define BF_SAIF_VERSION_MINOR(v) \ + (((v) << 16) & BM_SAIF_VERSION_MINOR) +#define BP_SAIF_VERSION_STEP 0 +#define BM_SAIF_VERSION_STEP 0x0000FFFF +#define BF_SAIF_VERSION_STEP(v) \ + (((v) << 0) & BM_SAIF_VERSION_STEP) +#endif /* __ARCH_ARM___SAIF_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-spdif.h b/arch/arm/mach-stmp3xxx/include/mach/regs-spdif.h new file mode 100644 index 000000000000..da03b86a01f2 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-spdif.h @@ -0,0 +1,100 @@ +/* + * STMP SPDIF Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___SPDIF_H +#define __ARCH_ARM___SPDIF_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_SPDIF_BASE (REGS_BASE + 0x54000) +#define REGS_SPDIF_BASE_PHYS (0x80054000) +#define REGS_SPDIF_SIZE 0x00002000 +HW_REGISTER(HW_SPDIF_CTRL, REGS_SPDIF_BASE, 0x00000000) +#define HW_SPDIF_CTRL_ADDR (REGS_SPDIF_BASE + 0x00000000) +#define BM_SPDIF_CTRL_SFTRST 0x80000000 +#define BM_SPDIF_CTRL_CLKGATE 0x40000000 +#define BP_SPDIF_CTRL_DMAWAIT_COUNT 16 +#define BM_SPDIF_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_SPDIF_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_SPDIF_CTRL_DMAWAIT_COUNT) +#define BM_SPDIF_CTRL_WAIT_END_XFER 0x00000020 +#define BM_SPDIF_CTRL_WORD_LENGTH 0x00000010 +#define BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008 +#define BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ 0x00000004 +#define BM_SPDIF_CTRL_FIFO_ERROR_IRQ_EN 0x00000002 +#define BM_SPDIF_CTRL_RUN 0x00000001 +HW_REGISTER(HW_SPDIF_STAT, REGS_SPDIF_BASE, 0x00000010) +#define HW_SPDIF_STAT_ADDR (REGS_SPDIF_BASE + 0x00000010) +#define BM_SPDIF_STAT_PRESENT 0x80000000 +#define BM_SPDIF_STAT_END_XFER 0x00000001 +HW_REGISTER(HW_SPDIF_FRAMECTRL, REGS_SPDIF_BASE, 0x00000020) +#define HW_SPDIF_FRAMECTRL_ADDR (REGS_SPDIF_BASE + 0x00000020) +#define BM_SPDIF_FRAMECTRL_V_CONFIG 0x00020000 +#define BM_SPDIF_FRAMECTRL_AUTO_MUTE 0x00010000 +#define BM_SPDIF_FRAMECTRL_USER_DATA 0x00004000 +#define BM_SPDIF_FRAMECTRL_V 0x00002000 +#define BM_SPDIF_FRAMECTRL_L 0x00001000 +#define BP_SPDIF_FRAMECTRL_CC 4 +#define BM_SPDIF_FRAMECTRL_CC 0x000007F0 +#define BF_SPDIF_FRAMECTRL_CC(v) \ + (((v) << 4) & BM_SPDIF_FRAMECTRL_CC) +#define BM_SPDIF_FRAMECTRL_PRE 0x00000008 +#define BM_SPDIF_FRAMECTRL_COPY 0x00000004 +#define BM_SPDIF_FRAMECTRL_AUDIO 0x00000002 +#define BM_SPDIF_FRAMECTRL_PRO 0x00000001 +HW_REGISTER(HW_SPDIF_SRR, REGS_SPDIF_BASE, 0x00000030) +#define HW_SPDIF_SRR_ADDR (REGS_SPDIF_BASE + 0x00000030) +#define BP_SPDIF_SRR_BASEMULT 28 +#define BM_SPDIF_SRR_BASEMULT 0x70000000 +#define BF_SPDIF_SRR_BASEMULT(v) \ + (((v) << 28) & BM_SPDIF_SRR_BASEMULT) +#define BP_SPDIF_SRR_RATE 0 +#define BM_SPDIF_SRR_RATE 0x000FFFFF +#define BF_SPDIF_SRR_RATE(v) \ + (((v) << 0) & BM_SPDIF_SRR_RATE) +HW_REGISTER(HW_SPDIF_DEBUG, REGS_SPDIF_BASE, 0x00000040) +#define HW_SPDIF_DEBUG_ADDR (REGS_SPDIF_BASE + 0x00000040) +#define BM_SPDIF_DEBUG_DMA_PREQ 0x00000002 +#define BM_SPDIF_DEBUG_FIFO_STATUS 0x00000001 +HW_REGISTER(HW_SPDIF_DATA, REGS_SPDIF_BASE, 0x00000050) +#define HW_SPDIF_DATA_ADDR (REGS_SPDIF_BASE + 0x00000050) +#define BP_SPDIF_DATA_HIGH 16 +#define BM_SPDIF_DATA_HIGH 0xFFFF0000 +#define BF_SPDIF_DATA_HIGH(v) \ + (((v) << 16) & BM_SPDIF_DATA_HIGH) +#define BP_SPDIF_DATA_LOW 0 +#define BM_SPDIF_DATA_LOW 0x0000FFFF +#define BF_SPDIF_DATA_LOW(v) \ + (((v) << 0) & BM_SPDIF_DATA_LOW) +HW_REGISTER_0(HW_SPDIF_VERSION, REGS_SPDIF_BASE, 0x00000060) +#define HW_SPDIF_VERSION_ADDR (REGS_SPDIF_BASE + 0x00000060) +#define BP_SPDIF_VERSION_MAJOR 24 +#define BM_SPDIF_VERSION_MAJOR 0xFF000000 +#define BF_SPDIF_VERSION_MAJOR(v) \ + (((v) << 24) & BM_SPDIF_VERSION_MAJOR) +#define BP_SPDIF_VERSION_MINOR 16 +#define BM_SPDIF_VERSION_MINOR 0x00FF0000 +#define BF_SPDIF_VERSION_MINOR(v) \ + (((v) << 16) & BM_SPDIF_VERSION_MINOR) +#define BP_SPDIF_VERSION_STEP 0 +#define BM_SPDIF_VERSION_STEP 0x0000FFFF +#define BF_SPDIF_VERSION_STEP(v) \ + (((v) << 0) & BM_SPDIF_VERSION_STEP) +#endif /* __ARCH_ARM___SPDIF_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-ssp.h b/arch/arm/mach-stmp3xxx/include/mach/regs-ssp.h new file mode 100644 index 000000000000..54b9beaebd7c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-ssp.h @@ -0,0 +1,355 @@ +/* + * STMP SSP Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___SSP_H +#define __ARCH_ARM___SSP_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_SSP_BASE (REGS_BASE + 0x10000) +#define REGS_SSP1_BASE_PHYS (0x80010000) +#define REGS_SSP2_BASE_PHYS (0x80034000) +#define REGS_SSP_SIZE 0x00002000 +HW_REGISTER(HW_SSP_CTRL0, REGS_SSP_BASE, 0x00000000) +#define HW_SSP_CTRL0_ADDR (REGS_SSP_BASE + 0x00000000) +#define BM_SSP_CTRL0_SFTRST 0x80000000 +#define BM_SSP_CTRL0_CLKGATE 0x40000000 +#define BM_SSP_CTRL0_RUN 0x20000000 +#define BM_SSP_CTRL0_SDIO_IRQ_CHECK 0x10000000 +#define BM_SSP_CTRL0_LOCK_CS 0x08000000 +#define BM_SSP_CTRL0_IGNORE_CRC 0x04000000 +#define BM_SSP_CTRL0_READ 0x02000000 +#define BM_SSP_CTRL0_DATA_XFER 0x01000000 +#define BP_SSP_CTRL0_BUS_WIDTH 22 +#define BM_SSP_CTRL0_BUS_WIDTH 0x00C00000 +#define BF_SSP_CTRL0_BUS_WIDTH(v) \ + (((v) << 22) & BM_SSP_CTRL0_BUS_WIDTH) +#define BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT 0x0 +#define BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT 0x1 +#define BV_SSP_CTRL0_BUS_WIDTH__EIGHT_BIT 0x2 +#define BM_SSP_CTRL0_WAIT_FOR_IRQ 0x00200000 +#define BM_SSP_CTRL0_WAIT_FOR_CMD 0x00100000 +#define BM_SSP_CTRL0_LONG_RESP 0x00080000 +#define BM_SSP_CTRL0_CHECK_RESP 0x00040000 +#define BM_SSP_CTRL0_GET_RESP 0x00020000 +#define BM_SSP_CTRL0_ENABLE 0x00010000 +#define BP_SSP_CTRL0_XFER_COUNT 0 +#define BM_SSP_CTRL0_XFER_COUNT 0x0000FFFF +#define BF_SSP_CTRL0_XFER_COUNT(v) \ + (((v) << 0) & BM_SSP_CTRL0_XFER_COUNT) +HW_REGISTER(HW_SSP_CMD0, REGS_SSP_BASE, 0x00000010) +#define HW_SSP_CMD0_ADDR (REGS_SSP_BASE + 0x00000010) +#define BM_SSP_CMD0_SLOW_CLKING_EN 0x00400000 +#define BM_SSP_CMD0_CONT_CLKING_EN 0x00200000 +#define BM_SSP_CMD0_APPEND_8CYC 0x00100000 +#define BP_SSP_CMD0_BLOCK_SIZE 16 +#define BM_SSP_CMD0_BLOCK_SIZE 0x000F0000 +#define BF_SSP_CMD0_BLOCK_SIZE(v) \ + (((v) << 16) & BM_SSP_CMD0_BLOCK_SIZE) +#define BP_SSP_CMD0_BLOCK_COUNT 8 +#define BM_SSP_CMD0_BLOCK_COUNT 0x0000FF00 +#define BF_SSP_CMD0_BLOCK_COUNT(v) \ + (((v) << 8) & BM_SSP_CMD0_BLOCK_COUNT) +#define BP_SSP_CMD0_CMD 0 +#define BM_SSP_CMD0_CMD 0x000000FF +#define BF_SSP_CMD0_CMD(v) \ + (((v) << 0) & BM_SSP_CMD0_CMD) +#define BV_SSP_CMD0_CMD__MMC_GO_IDLE_STATE 0x00 +#define BV_SSP_CMD0_CMD__MMC_SEND_OP_COND 0x01 +#define BV_SSP_CMD0_CMD__MMC_ALL_SEND_CID 0x02 +#define BV_SSP_CMD0_CMD__MMC_SET_RELATIVE_ADDR 0x03 +#define BV_SSP_CMD0_CMD__MMC_SET_DSR 0x04 +#define BV_SSP_CMD0_CMD__MMC_RESERVED_5 0x05 +#define BV_SSP_CMD0_CMD__MMC_SWITCH 0x06 +#define BV_SSP_CMD0_CMD__MMC_SELECT_DESELECT_CARD 0x07 +#define BV_SSP_CMD0_CMD__MMC_SEND_EXT_CSD 0x08 +#define BV_SSP_CMD0_CMD__MMC_SEND_CSD 0x09 +#define BV_SSP_CMD0_CMD__MMC_SEND_CID 0x0A +#define BV_SSP_CMD0_CMD__MMC_READ_DAT_UNTIL_STOP 0x0B +#define BV_SSP_CMD0_CMD__MMC_STOP_TRANSMISSION 0x0C +#define BV_SSP_CMD0_CMD__MMC_SEND_STATUS 0x0D +#define BV_SSP_CMD0_CMD__MMC_BUSTEST_R 0x0E +#define BV_SSP_CMD0_CMD__MMC_GO_INACTIVE_STATE 0x0F +#define BV_SSP_CMD0_CMD__MMC_SET_BLOCKLEN 0x10 +#define BV_SSP_CMD0_CMD__MMC_READ_SINGLE_BLOCK 0x11 +#define BV_SSP_CMD0_CMD__MMC_READ_MULTIPLE_BLOCK 0x12 +#define BV_SSP_CMD0_CMD__MMC_BUSTEST_W 0x13 +#define BV_SSP_CMD0_CMD__MMC_WRITE_DAT_UNTIL_STOP 0x14 +#define BV_SSP_CMD0_CMD__MMC_SET_BLOCK_COUNT 0x17 +#define BV_SSP_CMD0_CMD__MMC_WRITE_BLOCK 0x18 +#define BV_SSP_CMD0_CMD__MMC_WRITE_MULTIPLE_BLOCK 0x19 +#define BV_SSP_CMD0_CMD__MMC_PROGRAM_CID 0x1A +#define BV_SSP_CMD0_CMD__MMC_PROGRAM_CSD 0x1B +#define BV_SSP_CMD0_CMD__MMC_SET_WRITE_PROT 0x1C +#define BV_SSP_CMD0_CMD__MMC_CLR_WRITE_PROT 0x1D +#define BV_SSP_CMD0_CMD__MMC_SEND_WRITE_PROT 0x1E +#define BV_SSP_CMD0_CMD__MMC_ERASE_GROUP_START 0x23 +#define BV_SSP_CMD0_CMD__MMC_ERASE_GROUP_END 0x24 +#define BV_SSP_CMD0_CMD__MMC_ERASE 0x26 +#define BV_SSP_CMD0_CMD__MMC_FAST_IO 0x27 +#define BV_SSP_CMD0_CMD__MMC_GO_IRQ_STATE 0x28 +#define BV_SSP_CMD0_CMD__MMC_LOCK_UNLOCK 0x2A +#define BV_SSP_CMD0_CMD__MMC_APP_CMD 0x37 +#define BV_SSP_CMD0_CMD__MMC_GEN_CMD 0x38 +#define BV_SSP_CMD0_CMD__SD_GO_IDLE_STATE 0x00 +#define BV_SSP_CMD0_CMD__SD_ALL_SEND_CID 0x02 +#define BV_SSP_CMD0_CMD__SD_SEND_RELATIVE_ADDR 0x03 +#define BV_SSP_CMD0_CMD__SD_SET_DSR 0x04 +#define BV_SSP_CMD0_CMD__SD_IO_SEND_OP_COND 0x05 +#define BV_SSP_CMD0_CMD__SD_SELECT_DESELECT_CARD 0x07 +#define BV_SSP_CMD0_CMD__SD_SEND_CSD 0x09 +#define BV_SSP_CMD0_CMD__SD_SEND_CID 0x0A +#define BV_SSP_CMD0_CMD__SD_STOP_TRANSMISSION 0x0C +#define BV_SSP_CMD0_CMD__SD_SEND_STATUS 0x0D +#define BV_SSP_CMD0_CMD__SD_GO_INACTIVE_STATE 0x0F +#define BV_SSP_CMD0_CMD__SD_SET_BLOCKLEN 0x10 +#define BV_SSP_CMD0_CMD__SD_READ_SINGLE_BLOCK 0x11 +#define BV_SSP_CMD0_CMD__SD_READ_MULTIPLE_BLOCK 0x12 +#define BV_SSP_CMD0_CMD__SD_WRITE_BLOCK 0x18 +#define BV_SSP_CMD0_CMD__SD_WRITE_MULTIPLE_BLOCK 0x19 +#define BV_SSP_CMD0_CMD__SD_PROGRAM_CSD 0x1B +#define BV_SSP_CMD0_CMD__SD_SET_WRITE_PROT 0x1C +#define BV_SSP_CMD0_CMD__SD_CLR_WRITE_PROT 0x1D +#define BV_SSP_CMD0_CMD__SD_SEND_WRITE_PROT 0x1E +#define BV_SSP_CMD0_CMD__SD_ERASE_WR_BLK_START 0x20 +#define BV_SSP_CMD0_CMD__SD_ERASE_WR_BLK_END 0x21 +#define BV_SSP_CMD0_CMD__SD_ERASE_GROUP_START 0x23 +#define BV_SSP_CMD0_CMD__SD_ERASE_GROUP_END 0x24 +#define BV_SSP_CMD0_CMD__SD_ERASE 0x26 +#define BV_SSP_CMD0_CMD__SD_LOCK_UNLOCK 0x2A +#define BV_SSP_CMD0_CMD__SD_IO_RW_DIRECT 0x34 +#define BV_SSP_CMD0_CMD__SD_IO_RW_EXTENDED 0x35 +#define BV_SSP_CMD0_CMD__SD_APP_CMD 0x37 +#define BV_SSP_CMD0_CMD__SD_GEN_CMD 0x38 +HW_REGISTER_0(HW_SSP_CMD1, REGS_SSP_BASE, 0x00000020) +#define HW_SSP_CMD1_ADDR (REGS_SSP_BASE + 0x00000020) +#define BP_SSP_CMD1_CMD_ARG 0 +#define BM_SSP_CMD1_CMD_ARG 0xFFFFFFFF +#define BF_SSP_CMD1_CMD_ARG(v) (v) +HW_REGISTER_0(HW_SSP_COMPREF, REGS_SSP_BASE, 0x00000030) +#define HW_SSP_COMPREF_ADDR (REGS_SSP_BASE + 0x00000030) +#define BP_SSP_COMPREF_REFERENCE 0 +#define BM_SSP_COMPREF_REFERENCE 0xFFFFFFFF +#define BF_SSP_COMPREF_REFERENCE(v) (v) +HW_REGISTER_0(HW_SSP_COMPMASK, REGS_SSP_BASE, 0x00000040) +#define HW_SSP_COMPMASK_ADDR (REGS_SSP_BASE + 0x00000040) +#define BP_SSP_COMPMASK_MASK 0 +#define BM_SSP_COMPMASK_MASK 0xFFFFFFFF +#define BF_SSP_COMPMASK_MASK(v) (v) +HW_REGISTER_0(HW_SSP_TIMING, REGS_SSP_BASE, 0x00000050) +#define HW_SSP_TIMING_ADDR (REGS_SSP_BASE + 0x00000050) +#define BP_SSP_TIMING_TIMEOUT 16 +#define BM_SSP_TIMING_TIMEOUT 0xFFFF0000 +#define BF_SSP_TIMING_TIMEOUT(v) \ + (((v) << 16) & BM_SSP_TIMING_TIMEOUT) +#define BP_SSP_TIMING_CLOCK_DIVIDE 8 +#define BM_SSP_TIMING_CLOCK_DIVIDE 0x0000FF00 +#define BF_SSP_TIMING_CLOCK_DIVIDE(v) \ + (((v) << 8) & BM_SSP_TIMING_CLOCK_DIVIDE) +#define BP_SSP_TIMING_CLOCK_RATE 0 +#define BM_SSP_TIMING_CLOCK_RATE 0x000000FF +#define BF_SSP_TIMING_CLOCK_RATE(v) \ + (((v) << 0) & BM_SSP_TIMING_CLOCK_RATE) +HW_REGISTER(HW_SSP_CTRL1, REGS_SSP_BASE, 0x00000060) +#define HW_SSP_CTRL1_ADDR (REGS_SSP_BASE + 0x00000060) +#define BM_SSP_CTRL1_SDIO_IRQ 0x80000000 +#define BM_SSP_CTRL1_SDIO_IRQ_EN 0x40000000 +#define BM_SSP_CTRL1_RESP_ERR_IRQ 0x20000000 +#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN 0x10000000 +#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ 0x08000000 +#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN 0x04000000 +#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ 0x02000000 +#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN 0x01000000 +#define BM_SSP_CTRL1_DATA_CRC_IRQ 0x00800000 +#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN 0x00400000 +#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ 0x00200000 +#define BM_SSP_CTRL1_FIFO_UNDERRUN_EN 0x00100000 +#define BM_SSP_CTRL1_CEATA_CCS_ERR_IRQ 0x00080000 +#define BM_SSP_CTRL1_CEATA_CCS_ERR_IRQ_EN 0x00040000 +#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ 0x00020000 +#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN 0x00010000 +#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ 0x00008000 +#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN 0x00004000 +#define BM_SSP_CTRL1_DMA_ENABLE 0x00002000 +#define BM_SSP_CTRL1_CEATA_CCS_ERR_EN 0x00001000 +#define BM_SSP_CTRL1_SLAVE_OUT_DISABLE 0x00000800 +#define BM_SSP_CTRL1_PHASE 0x00000400 +#define BM_SSP_CTRL1_POLARITY 0x00000200 +#define BM_SSP_CTRL1_SLAVE_MODE 0x00000100 +#define BP_SSP_CTRL1_WORD_LENGTH 4 +#define BM_SSP_CTRL1_WORD_LENGTH 0x000000F0 +#define BF_SSP_CTRL1_WORD_LENGTH(v) \ + (((v) << 4) & BM_SSP_CTRL1_WORD_LENGTH) +#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED0 0x0 +#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED1 0x1 +#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED2 0x2 +#define BV_SSP_CTRL1_WORD_LENGTH__FOUR_BITS 0x3 +#define BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS 0x7 +#define BV_SSP_CTRL1_WORD_LENGTH__SIXTEEN_BITS 0xF +#define BP_SSP_CTRL1_SSP_MODE 0 +#define BM_SSP_CTRL1_SSP_MODE 0x0000000F +#define BF_SSP_CTRL1_SSP_MODE(v) \ + (((v) << 0) & BM_SSP_CTRL1_SSP_MODE) +#define BV_SSP_CTRL1_SSP_MODE__SPI 0x0 +#define BV_SSP_CTRL1_SSP_MODE__SSI 0x1 +#define BV_SSP_CTRL1_SSP_MODE__SD_MMC 0x3 +#define BV_SSP_CTRL1_SSP_MODE__MS 0x4 +#define BV_SSP_CTRL1_SSP_MODE__CE_ATA 0x7 +HW_REGISTER_0(HW_SSP_DATA, REGS_SSP_BASE, 0x00000070) +#define HW_SSP_DATA_ADDR (REGS_SSP_BASE + 0x00000070) +#define BP_SSP_DATA_DATA 0 +#define BM_SSP_DATA_DATA 0xFFFFFFFF +#define BF_SSP_DATA_DATA(v) (v) +HW_REGISTER_0(HW_SSP_SDRESP0, REGS_SSP_BASE, 0x00000080) +#define HW_SSP_SDRESP0_ADDR (REGS_SSP_BASE + 0x00000080) +#define BP_SSP_SDRESP0_RESP0 0 +#define BM_SSP_SDRESP0_RESP0 0xFFFFFFFF +#define BF_SSP_SDRESP0_RESP0(v) (v) +HW_REGISTER_0(HW_SSP_SDRESP1, REGS_SSP_BASE, 0x00000090) +#define HW_SSP_SDRESP1_ADDR (REGS_SSP_BASE + 0x00000090) +#define BP_SSP_SDRESP1_RESP1 0 +#define BM_SSP_SDRESP1_RESP1 0xFFFFFFFF +#define BF_SSP_SDRESP1_RESP1(v) (v) +HW_REGISTER_0(HW_SSP_SDRESP2, REGS_SSP_BASE, 0x000000a0) +#define HW_SSP_SDRESP2_ADDR (REGS_SSP_BASE + 0x000000a0) +#define BP_SSP_SDRESP2_RESP2 0 +#define BM_SSP_SDRESP2_RESP2 0xFFFFFFFF +#define BF_SSP_SDRESP2_RESP2(v) (v) +HW_REGISTER_0(HW_SSP_SDRESP3, REGS_SSP_BASE, 0x000000b0) +#define HW_SSP_SDRESP3_ADDR (REGS_SSP_BASE + 0x000000b0) +#define BP_SSP_SDRESP3_RESP3 0 +#define BM_SSP_SDRESP3_RESP3 0xFFFFFFFF +#define BF_SSP_SDRESP3_RESP3(v) (v) +HW_REGISTER_0(HW_SSP_STATUS, REGS_SSP_BASE, 0x000000c0) +#define HW_SSP_STATUS_ADDR (REGS_SSP_BASE + 0x000000c0) +#define BM_SSP_STATUS_PRESENT 0x80000000 +#define BM_SSP_STATUS_MS_PRESENT 0x40000000 +#define BM_SSP_STATUS_SD_PRESENT 0x20000000 +#define BM_SSP_STATUS_CARD_DETECT 0x10000000 +#define BM_SSP_STATUS_DMASENSE 0x00200000 +#define BM_SSP_STATUS_DMATERM 0x00100000 +#define BM_SSP_STATUS_DMAREQ 0x00080000 +#define BM_SSP_STATUS_DMAEND 0x00040000 +#define BM_SSP_STATUS_SDIO_IRQ 0x00020000 +#define BM_SSP_STATUS_RESP_CRC_ERR 0x00010000 +#define BM_SSP_STATUS_RESP_ERR 0x00008000 +#define BM_SSP_STATUS_RESP_TIMEOUT 0x00004000 +#define BM_SSP_STATUS_DATA_CRC_ERR 0x00002000 +#define BM_SSP_STATUS_TIMEOUT 0x00001000 +#define BM_SSP_STATUS_RECV_TIMEOUT_STAT 0x00000800 +#define BM_SSP_STATUS_CEATA_CCS_ERR 0x00000400 +#define BM_SSP_STATUS_FIFO_OVRFLW 0x00000200 +#define BM_SSP_STATUS_FIFO_FULL 0x00000100 +#define BM_SSP_STATUS_FIFO_EMPTY 0x00000020 +#define BM_SSP_STATUS_FIFO_UNDRFLW 0x00000010 +#define BM_SSP_STATUS_CMD_BUSY 0x00000008 +#define BM_SSP_STATUS_DATA_BUSY 0x00000004 +#define BM_SSP_STATUS_BUSY 0x00000001 +HW_REGISTER_0(HW_SSP_DEBUG, REGS_SSP_BASE, 0x00000100) +#define HW_SSP_DEBUG_ADDR (REGS_SSP_BASE + 0x00000100) +#define BP_SSP_DEBUG_DATACRC_ERR 28 +#define BM_SSP_DEBUG_DATACRC_ERR 0xF0000000 +#define BF_SSP_DEBUG_DATACRC_ERR(v) \ + (((v) << 28) & BM_SSP_DEBUG_DATACRC_ERR) +#define BM_SSP_DEBUG_DATA_STALL 0x08000000 +#define BP_SSP_DEBUG_DAT_SM 24 +#define BM_SSP_DEBUG_DAT_SM 0x07000000 +#define BF_SSP_DEBUG_DAT_SM(v) \ + (((v) << 24) & BM_SSP_DEBUG_DAT_SM) +#define BV_SSP_DEBUG_DAT_SM__DSM_IDLE 0x0 +#define BV_SSP_DEBUG_DAT_SM__DSM_WORD 0x2 +#define BV_SSP_DEBUG_DAT_SM__DSM_CRC1 0x3 +#define BV_SSP_DEBUG_DAT_SM__DSM_CRC2 0x4 +#define BV_SSP_DEBUG_DAT_SM__DSM_END 0x5 +#define BP_SSP_DEBUG_MSTK_SM 20 +#define BM_SSP_DEBUG_MSTK_SM 0x00F00000 +#define BF_SSP_DEBUG_MSTK_SM(v) \ + (((v) << 20) & BM_SSP_DEBUG_MSTK_SM) +#define BV_SSP_DEBUG_MSTK_SM__MSTK_IDLE 0x0 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_CKON 0x1 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS1 0x2 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_TPC 0x3 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS2 0x4 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_HDSHK 0x5 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS3 0x6 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_RW 0x7 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_CRC1 0x8 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_CRC2 0x9 +#define BV_SSP_DEBUG_MSTK_SM__MSTK_BS0 0xA +#define BV_SSP_DEBUG_MSTK_SM__MSTK_END1 0xB +#define BV_SSP_DEBUG_MSTK_SM__MSTK_END2W 0xC +#define BV_SSP_DEBUG_MSTK_SM__MSTK_END2R 0xD +#define BV_SSP_DEBUG_MSTK_SM__MSTK_DONE 0xE +#define BM_SSP_DEBUG_CMD_OE 0x00080000 +#define BP_SSP_DEBUG_DMA_SM 16 +#define BM_SSP_DEBUG_DMA_SM 0x00070000 +#define BF_SSP_DEBUG_DMA_SM(v) \ + (((v) << 16) & BM_SSP_DEBUG_DMA_SM) +#define BV_SSP_DEBUG_DMA_SM__DMA_IDLE 0x0 +#define BV_SSP_DEBUG_DMA_SM__DMA_DMAREQ 0x1 +#define BV_SSP_DEBUG_DMA_SM__DMA_DMAACK 0x2 +#define BV_SSP_DEBUG_DMA_SM__DMA_STALL 0x3 +#define BV_SSP_DEBUG_DMA_SM__DMA_BUSY 0x4 +#define BV_SSP_DEBUG_DMA_SM__DMA_DONE 0x5 +#define BV_SSP_DEBUG_DMA_SM__DMA_COUNT 0x6 +#define BP_SSP_DEBUG_MMC_SM 12 +#define BM_SSP_DEBUG_MMC_SM 0x0000F000 +#define BF_SSP_DEBUG_MMC_SM(v) \ + (((v) << 12) & BM_SSP_DEBUG_MMC_SM) +#define BV_SSP_DEBUG_MMC_SM__MMC_IDLE 0x0 +#define BV_SSP_DEBUG_MMC_SM__MMC_CMD 0x1 +#define BV_SSP_DEBUG_MMC_SM__MMC_TRC 0x2 +#define BV_SSP_DEBUG_MMC_SM__MMC_RESP 0x3 +#define BV_SSP_DEBUG_MMC_SM__MMC_RPRX 0x4 +#define BV_SSP_DEBUG_MMC_SM__MMC_TX 0x5 +#define BV_SSP_DEBUG_MMC_SM__MMC_CTOK 0x6 +#define BV_SSP_DEBUG_MMC_SM__MMC_RX 0x7 +#define BV_SSP_DEBUG_MMC_SM__MMC_CCS 0x8 +#define BV_SSP_DEBUG_MMC_SM__MMC_PUP 0x9 +#define BV_SSP_DEBUG_MMC_SM__MMC_WAIT 0xA +#define BP_SSP_DEBUG_CMD_SM 10 +#define BM_SSP_DEBUG_CMD_SM 0x00000C00 +#define BF_SSP_DEBUG_CMD_SM(v) \ + (((v) << 10) & BM_SSP_DEBUG_CMD_SM) +#define BV_SSP_DEBUG_CMD_SM__CSM_IDLE 0x0 +#define BV_SSP_DEBUG_CMD_SM__CSM_INDEX 0x1 +#define BV_SSP_DEBUG_CMD_SM__CSM_ARG 0x2 +#define BV_SSP_DEBUG_CMD_SM__CSM_CRC 0x3 +#define BM_SSP_DEBUG_SSP_CMD 0x00000200 +#define BM_SSP_DEBUG_SSP_RESP 0x00000100 +#define BP_SSP_DEBUG_SSP_RXD 0 +#define BM_SSP_DEBUG_SSP_RXD 0x000000FF +#define BF_SSP_DEBUG_SSP_RXD(v) \ + (((v) << 0) & BM_SSP_DEBUG_SSP_RXD) +HW_REGISTER_0(HW_SSP_VERSION, REGS_SSP_BASE, 0x00000110) +#define HW_SSP_VERSION_ADDR (REGS_SSP_BASE + 0x00000110) +#define BP_SSP_VERSION_MAJOR 24 +#define BM_SSP_VERSION_MAJOR 0xFF000000 +#define BF_SSP_VERSION_MAJOR(v) \ + (((v) << 24) & BM_SSP_VERSION_MAJOR) +#define BP_SSP_VERSION_MINOR 16 +#define BM_SSP_VERSION_MINOR 0x00FF0000 +#define BF_SSP_VERSION_MINOR(v) \ + (((v) << 16) & BM_SSP_VERSION_MINOR) +#define BP_SSP_VERSION_STEP 0 +#define BM_SSP_VERSION_STEP 0x0000FFFF +#define BF_SSP_VERSION_STEP(v) \ + (((v) << 0) & BM_SSP_VERSION_STEP) +#endif /* __ARCH_ARM___SSP_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-sydma.h b/arch/arm/mach-stmp3xxx/include/mach/regs-sydma.h new file mode 100644 index 000000000000..c08fbdf95605 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-sydma.h @@ -0,0 +1,117 @@ +/* + * STMP SYDMA Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___SYDMA_H +#define __ARCH_ARM___SYDMA_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_SYDMA_BASE (REGS_BASE + 0x26000) +#define REGS_SYDMA_BASE_PHYS (0x80026000) +#define REGS_SYDMA_SIZE 0x00002000 +HW_REGISTER(HW_SYDMA_CTRL, REGS_SYDMA_BASE, 0x00000000) +#define HW_SYDMA_CTRL_ADDR (REGS_SYDMA_BASE + 0x00000000) +#define BM_SYDMA_CTRL_SFTRST 0x80000000 +#define BV_SYDMA_CTRL_SFTRST__RUN 0x0 +#define BV_SYDMA_CTRL_SFTRST__RESET 0x1 +#define BM_SYDMA_CTRL_CLKGATE 0x40000000 +#define BV_SYDMA_CTRL_CLKGATE__RUN 0x0 +#define BV_SYDMA_CTRL_CLKGATE__NO_CLKS 0x1 +#define BM_SYDMA_CTRL_COMPLETE_IRQ_EN 0x00000200 +#define BV_SYDMA_CTRL_COMPLETE_IRQ_EN__DISABLED 0x0 +#define BV_SYDMA_CTRL_COMPLETE_IRQ_EN__ENABLED 0x1 +#define BM_SYDMA_CTRL_ERROR_IRQ 0x00000004 +#define BM_SYDMA_CTRL_COMPLETE_IRQ 0x00000002 +#define BM_SYDMA_CTRL_RUN 0x00000001 +#define BV_SYDMA_CTRL_RUN__HALT 0x0 +#define BV_SYDMA_CTRL_RUN__RUN 0x1 +HW_REGISTER_0(HW_SYDMA_RADDR, REGS_SYDMA_BASE, 0x00000010) +#define HW_SYDMA_RADDR_ADDR (REGS_SYDMA_BASE + 0x00000010) +#define BP_SYDMA_RADDR_RSRC_ADDR 0 +#define BM_SYDMA_RADDR_RSRC_ADDR 0xFFFFFFFF +#define BF_SYDMA_RADDR_RSRC_ADDR(v) (v) +HW_REGISTER_0(HW_SYDMA_WADDR, REGS_SYDMA_BASE, 0x00000020) +#define HW_SYDMA_WADDR_ADDR (REGS_SYDMA_BASE + 0x00000020) +#define BP_SYDMA_WADDR_WSRC_ADDR 0 +#define BM_SYDMA_WADDR_WSRC_ADDR 0xFFFFFFFF +#define BF_SYDMA_WADDR_WSRC_ADDR(v) (v) +HW_REGISTER_0(HW_SYDMA_XFER_COUNT, REGS_SYDMA_BASE, 0x00000030) +#define HW_SYDMA_XFER_COUNT_ADDR (REGS_SYDMA_BASE + 0x00000030) +#define BP_SYDMA_XFER_COUNT_SIZE 0 +#define BM_SYDMA_XFER_COUNT_SIZE 0xFFFFFFFF +#define BF_SYDMA_XFER_COUNT_SIZE(v) (v) +HW_REGISTER_0(HW_SYDMA_BURST, REGS_SYDMA_BASE, 0x00000040) +#define HW_SYDMA_BURST_ADDR (REGS_SYDMA_BASE + 0x00000040) +#define BP_SYDMA_BURST_WLEN 2 +#define BM_SYDMA_BURST_WLEN 0x0000000C +#define BF_SYDMA_BURST_WLEN(v) \ + (((v) << 2) & BM_SYDMA_BURST_WLEN) +#define BV_SYDMA_BURST_WLEN__1 0x0 +#define BV_SYDMA_BURST_WLEN__2 0x1 +#define BV_SYDMA_BURST_WLEN__4 0x2 +#define BV_SYDMA_BURST_WLEN__8 0x3 +#define BP_SYDMA_BURST_RLEN 0 +#define BM_SYDMA_BURST_RLEN 0x00000003 +#define BF_SYDMA_BURST_RLEN(v) \ + (((v) << 0) & BM_SYDMA_BURST_RLEN) +#define BV_SYDMA_BURST_RLEN__1 0x0 +#define BV_SYDMA_BURST_RLEN__2 0x1 +#define BV_SYDMA_BURST_RLEN__4 0x2 +#define BV_SYDMA_BURST_RLEN__8 0x3 +HW_REGISTER_0(HW_SYDMA_DACK, REGS_SYDMA_BASE, 0x00000050) +#define HW_SYDMA_DACK_ADDR (REGS_SYDMA_BASE + 0x00000050) +#define BP_SYDMA_DACK_WDELAY 4 +#define BM_SYDMA_DACK_WDELAY 0x000000F0 +#define BF_SYDMA_DACK_WDELAY(v) \ + (((v) << 4) & BM_SYDMA_DACK_WDELAY) +#define BP_SYDMA_DACK_RDELAY 0 +#define BM_SYDMA_DACK_RDELAY 0x0000000F +#define BF_SYDMA_DACK_RDELAY(v) \ + (((v) << 0) & BM_SYDMA_DACK_RDELAY) +HW_REGISTER_0(HW_SYDMA_DEBUG0, REGS_SYDMA_BASE, 0x00000100) +#define HW_SYDMA_DEBUG0_ADDR (REGS_SYDMA_BASE + 0x00000100) +#define BP_SYDMA_DEBUG0_DATA 0 +#define BM_SYDMA_DEBUG0_DATA 0xFFFFFFFF +#define BF_SYDMA_DEBUG0_DATA(v) (v) +HW_REGISTER_0(HW_SYDMA_DEBUG1, REGS_SYDMA_BASE, 0x00000110) +#define HW_SYDMA_DEBUG1_ADDR (REGS_SYDMA_BASE + 0x00000110) +#define BP_SYDMA_DEBUG1_DATA 0 +#define BM_SYDMA_DEBUG1_DATA 0xFFFFFFFF +#define BF_SYDMA_DEBUG1_DATA(v) (v) +HW_REGISTER_0(HW_SYDMA_DEBUG2, REGS_SYDMA_BASE, 0x00000120) +#define HW_SYDMA_DEBUG2_ADDR (REGS_SYDMA_BASE + 0x00000120) +#define BP_SYDMA_DEBUG2_DATA 0 +#define BM_SYDMA_DEBUG2_DATA 0xFFFFFFFF +#define BF_SYDMA_DEBUG2_DATA(v) (v) +HW_REGISTER_0(HW_SYDMA_VERSION, REGS_SYDMA_BASE, 0x00000130) +#define HW_SYDMA_VERSION_ADDR (REGS_SYDMA_BASE + 0x00000130) +#define BP_SYDMA_VERSION_MAJOR 24 +#define BM_SYDMA_VERSION_MAJOR 0xFF000000 +#define BF_SYDMA_VERSION_MAJOR(v) \ + (((v) << 24) & BM_SYDMA_VERSION_MAJOR) +#define BP_SYDMA_VERSION_MINOR 16 +#define BM_SYDMA_VERSION_MINOR 0x00FF0000 +#define BF_SYDMA_VERSION_MINOR(v) \ + (((v) << 16) & BM_SYDMA_VERSION_MINOR) +#define BP_SYDMA_VERSION_STEP 0 +#define BM_SYDMA_VERSION_STEP 0x0000FFFF +#define BF_SYDMA_VERSION_STEP(v) \ + (((v) << 0) & BM_SYDMA_VERSION_STEP) +#endif /* __ARCH_ARM___SYDMA_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-timrot.h b/arch/arm/mach-stmp3xxx/include/mach/regs-timrot.h new file mode 100644 index 000000000000..75f4aa1c7558 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-timrot.h @@ -0,0 +1,215 @@ +/* + * STMP TIMROT Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___TIMROT_H +#define __ARCH_ARM___TIMROT_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_TIMROT_BASE (REGS_BASE + 0x68000) +#define REGS_TIMROT_BASE_PHYS (0x80068000) +#define REGS_TIMROT_SIZE 0x00002000 +HW_REGISTER(HW_TIMROT_ROTCTRL, REGS_TIMROT_BASE, 0x00000000) +#define HW_TIMROT_ROTCTRL_ADDR (REGS_TIMROT_BASE + 0x00000000) +#define BM_TIMROT_ROTCTRL_SFTRST 0x80000000 +#define BM_TIMROT_ROTCTRL_CLKGATE 0x40000000 +#define BM_TIMROT_ROTCTRL_ROTARY_PRESENT 0x20000000 +#define BM_TIMROT_ROTCTRL_TIM3_PRESENT 0x10000000 +#define BM_TIMROT_ROTCTRL_TIM2_PRESENT 0x08000000 +#define BM_TIMROT_ROTCTRL_TIM1_PRESENT 0x04000000 +#define BM_TIMROT_ROTCTRL_TIM0_PRESENT 0x02000000 +#define BP_TIMROT_ROTCTRL_STATE 22 +#define BM_TIMROT_ROTCTRL_STATE 0x01C00000 +#define BF_TIMROT_ROTCTRL_STATE(v) \ + (((v) << 22) & BM_TIMROT_ROTCTRL_STATE) +#define BP_TIMROT_ROTCTRL_DIVIDER 16 +#define BM_TIMROT_ROTCTRL_DIVIDER 0x003F0000 +#define BF_TIMROT_ROTCTRL_DIVIDER(v) \ + (((v) << 16) & BM_TIMROT_ROTCTRL_DIVIDER) +#define BM_TIMROT_ROTCTRL_RELATIVE 0x00001000 +#define BP_TIMROT_ROTCTRL_OVERSAMPLE 10 +#define BM_TIMROT_ROTCTRL_OVERSAMPLE 0x00000C00 +#define BF_TIMROT_ROTCTRL_OVERSAMPLE(v) \ + (((v) << 10) & BM_TIMROT_ROTCTRL_OVERSAMPLE) +#define BV_TIMROT_ROTCTRL_OVERSAMPLE__8X 0x0 +#define BV_TIMROT_ROTCTRL_OVERSAMPLE__4X 0x1 +#define BV_TIMROT_ROTCTRL_OVERSAMPLE__2X 0x2 +#define BV_TIMROT_ROTCTRL_OVERSAMPLE__1X 0x3 +#define BM_TIMROT_ROTCTRL_POLARITY_B 0x00000200 +#define BM_TIMROT_ROTCTRL_POLARITY_A 0x00000100 +#define BP_TIMROT_ROTCTRL_SELECT_B 4 +#define BM_TIMROT_ROTCTRL_SELECT_B 0x00000070 +#define BF_TIMROT_ROTCTRL_SELECT_B(v) \ + (((v) << 4) & BM_TIMROT_ROTCTRL_SELECT_B) +#define BV_TIMROT_ROTCTRL_SELECT_B__NEVER_TICK 0x0 +#define BV_TIMROT_ROTCTRL_SELECT_B__PWM0 0x1 +#define BV_TIMROT_ROTCTRL_SELECT_B__PWM1 0x2 +#define BV_TIMROT_ROTCTRL_SELECT_B__PWM2 0x3 +#define BV_TIMROT_ROTCTRL_SELECT_B__PWM3 0x4 +#define BV_TIMROT_ROTCTRL_SELECT_B__PWM4 0x5 +#define BV_TIMROT_ROTCTRL_SELECT_B__ROTARYA 0x6 +#define BV_TIMROT_ROTCTRL_SELECT_B__ROTARYB 0x7 +#define BP_TIMROT_ROTCTRL_SELECT_A 0 +#define BM_TIMROT_ROTCTRL_SELECT_A 0x00000007 +#define BF_TIMROT_ROTCTRL_SELECT_A(v) \ + (((v) << 0) & BM_TIMROT_ROTCTRL_SELECT_A) +#define BV_TIMROT_ROTCTRL_SELECT_A__NEVER_TICK 0x0 +#define BV_TIMROT_ROTCTRL_SELECT_A__PWM0 0x1 +#define BV_TIMROT_ROTCTRL_SELECT_A__PWM1 0x2 +#define BV_TIMROT_ROTCTRL_SELECT_A__PWM2 0x3 +#define BV_TIMROT_ROTCTRL_SELECT_A__PWM3 0x4 +#define BV_TIMROT_ROTCTRL_SELECT_A__PWM4 0x5 +#define BV_TIMROT_ROTCTRL_SELECT_A__ROTARYA 0x6 +#define BV_TIMROT_ROTCTRL_SELECT_A__ROTARYB 0x7 +HW_REGISTER_0(HW_TIMROT_ROTCOUNT, REGS_TIMROT_BASE, 0x00000010) +#define HW_TIMROT_ROTCOUNT_ADDR (REGS_TIMROT_BASE + 0x00000010) +#define BP_TIMROT_ROTCOUNT_UPDOWN 0 +#define BM_TIMROT_ROTCOUNT_UPDOWN 0x0000FFFF +#define BF_TIMROT_ROTCOUNT_UPDOWN(v) \ + (((v) << 0) & BM_TIMROT_ROTCOUNT_UPDOWN) +/* + * multi-register-define name HW_TIMROT_TIMCTRLn + * base 0x00000020 + * count 3 + * offset 0x20 + */ +HW_REGISTER_INDEXED(HW_TIMROT_TIMCTRLn, REGS_TIMROT_BASE, 0x00000020, 0x20) +#define BM_TIMROT_TIMCTRLn_IRQ 0x00008000 +#define BM_TIMROT_TIMCTRLn_IRQ_EN 0x00004000 +#define BM_TIMROT_TIMCTRLn_POLARITY 0x00000100 +#define BM_TIMROT_TIMCTRLn_UPDATE 0x00000080 +#define BM_TIMROT_TIMCTRLn_RELOAD 0x00000040 +#define BP_TIMROT_TIMCTRLn_PRESCALE 4 +#define BM_TIMROT_TIMCTRLn_PRESCALE 0x00000030 +#define BF_TIMROT_TIMCTRLn_PRESCALE(v) \ + (((v) << 4) & BM_TIMROT_TIMCTRLn_PRESCALE) +#define BV_TIMROT_TIMCTRLn_PRESCALE__DIV_BY_1 0x0 +#define BV_TIMROT_TIMCTRLn_PRESCALE__DIV_BY_2 0x1 +#define BV_TIMROT_TIMCTRLn_PRESCALE__DIV_BY_4 0x2 +#define BV_TIMROT_TIMCTRLn_PRESCALE__DIV_BY_8 0x3 +#define BP_TIMROT_TIMCTRLn_SELECT 0 +#define BM_TIMROT_TIMCTRLn_SELECT 0x0000000F +#define BF_TIMROT_TIMCTRLn_SELECT(v) \ + (((v) << 0) & BM_TIMROT_TIMCTRLn_SELECT) +#define BV_TIMROT_TIMCTRLn_SELECT__NEVER_TICK 0x0 +#define BV_TIMROT_TIMCTRLn_SELECT__PWM0 0x1 +#define BV_TIMROT_TIMCTRLn_SELECT__PWM1 0x2 +#define BV_TIMROT_TIMCTRLn_SELECT__PWM2 0x3 +#define BV_TIMROT_TIMCTRLn_SELECT__PWM3 0x4 +#define BV_TIMROT_TIMCTRLn_SELECT__PWM4 0x5 +#define BV_TIMROT_TIMCTRLn_SELECT__ROTARYA 0x6 +#define BV_TIMROT_TIMCTRLn_SELECT__ROTARYB 0x7 +#define BV_TIMROT_TIMCTRLn_SELECT__32KHZ_XTAL 0x8 +#define BV_TIMROT_TIMCTRLn_SELECT__8KHZ_XTAL 0x9 +#define BV_TIMROT_TIMCTRLn_SELECT__4KHZ_XTAL 0xA +#define BV_TIMROT_TIMCTRLn_SELECT__1KHZ_XTAL 0xB +#define BV_TIMROT_TIMCTRLn_SELECT__TICK_ALWAYS 0xC +/* + * multi-register-define name HW_TIMROT_TIMCOUNTn + * base 0x00000030 + * count 3 + * offset 0x20 + */ +HW_REGISTER_0_INDEXED(HW_TIMROT_TIMCOUNTn, REGS_TIMROT_BASE, 0x00000030, + 0x20) +#define BP_TIMROT_TIMCOUNTn_RUNNING_COUNT 16 +#define BM_TIMROT_TIMCOUNTn_RUNNING_COUNT 0xFFFF0000 +#define BF_TIMROT_TIMCOUNTn_RUNNING_COUNT(v) \ + (((v) << 16) & BM_TIMROT_TIMCOUNTn_RUNNING_COUNT) +#define BP_TIMROT_TIMCOUNTn_FIXED_COUNT 0 +#define BM_TIMROT_TIMCOUNTn_FIXED_COUNT 0x0000FFFF +#define BF_TIMROT_TIMCOUNTn_FIXED_COUNT(v) \ + (((v) << 0) & BM_TIMROT_TIMCOUNTn_FIXED_COUNT) +HW_REGISTER(HW_TIMROT_TIMCTRL3, REGS_TIMROT_BASE, 0x00000080) +#define HW_TIMROT_TIMCTRL3_ADDR (REGS_TIMROT_BASE + 0x00000080) +#define BP_TIMROT_TIMCTRL3_TEST_SIGNAL 16 +#define BM_TIMROT_TIMCTRL3_TEST_SIGNAL 0x000F0000 +#define BF_TIMROT_TIMCTRL3_TEST_SIGNAL(v) \ + (((v) << 16) & BM_TIMROT_TIMCTRL3_TEST_SIGNAL) +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__NEVER_TICK 0x0 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__PWM0 0x1 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__PWM1 0x2 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__PWM2 0x3 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__PWM3 0x4 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__PWM4 0x5 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__ROTARYA 0x6 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__ROTARYB 0x7 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__32KHZ_XTAL 0x8 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__8KHZ_XTAL 0x9 +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__4KHZ_XTAL 0xA +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__1KHZ_XTAL 0xB +#define BV_TIMROT_TIMCTRL3_TEST_SIGNAL__TICK_ALWAYS 0xC +#define BM_TIMROT_TIMCTRL3_IRQ 0x00008000 +#define BM_TIMROT_TIMCTRL3_IRQ_EN 0x00004000 +#define BM_TIMROT_TIMCTRL3_DUTY_VALID 0x00000400 +#define BM_TIMROT_TIMCTRL3_DUTY_CYCLE 0x00000200 +#define BM_TIMROT_TIMCTRL3_POLARITY 0x00000100 +#define BM_TIMROT_TIMCTRL3_UPDATE 0x00000080 +#define BM_TIMROT_TIMCTRL3_RELOAD 0x00000040 +#define BP_TIMROT_TIMCTRL3_PRESCALE 4 +#define BM_TIMROT_TIMCTRL3_PRESCALE 0x00000030 +#define BF_TIMROT_TIMCTRL3_PRESCALE(v) \ + (((v) << 4) & BM_TIMROT_TIMCTRL3_PRESCALE) +#define BV_TIMROT_TIMCTRL3_PRESCALE__DIV_BY_1 0x0 +#define BV_TIMROT_TIMCTRL3_PRESCALE__DIV_BY_2 0x1 +#define BV_TIMROT_TIMCTRL3_PRESCALE__DIV_BY_4 0x2 +#define BV_TIMROT_TIMCTRL3_PRESCALE__DIV_BY_8 0x3 +#define BP_TIMROT_TIMCTRL3_SELECT 0 +#define BM_TIMROT_TIMCTRL3_SELECT 0x0000000F +#define BF_TIMROT_TIMCTRL3_SELECT(v) \ + (((v) << 0) & BM_TIMROT_TIMCTRL3_SELECT) +#define BV_TIMROT_TIMCTRL3_SELECT__NEVER_TICK 0x0 +#define BV_TIMROT_TIMCTRL3_SELECT__PWM0 0x1 +#define BV_TIMROT_TIMCTRL3_SELECT__PWM1 0x2 +#define BV_TIMROT_TIMCTRL3_SELECT__PWM2 0x3 +#define BV_TIMROT_TIMCTRL3_SELECT__PWM3 0x4 +#define BV_TIMROT_TIMCTRL3_SELECT__PWM4 0x5 +#define BV_TIMROT_TIMCTRL3_SELECT__ROTARYA 0x6 +#define BV_TIMROT_TIMCTRL3_SELECT__ROTARYB 0x7 +#define BV_TIMROT_TIMCTRL3_SELECT__32KHZ_XTAL 0x8 +#define BV_TIMROT_TIMCTRL3_SELECT__8KHZ_XTAL 0x9 +#define BV_TIMROT_TIMCTRL3_SELECT__4KHZ_XTAL 0xA +#define BV_TIMROT_TIMCTRL3_SELECT__1KHZ_XTAL 0xB +#define BV_TIMROT_TIMCTRL3_SELECT__TICK_ALWAYS 0xC +HW_REGISTER_0(HW_TIMROT_TIMCOUNT3, REGS_TIMROT_BASE, 0x00000090) +#define HW_TIMROT_TIMCOUNT3_ADDR (REGS_TIMROT_BASE + 0x00000090) +#define BP_TIMROT_TIMCOUNT3_LOW_RUNNING_COUNT 16 +#define BM_TIMROT_TIMCOUNT3_LOW_RUNNING_COUNT 0xFFFF0000 +#define BF_TIMROT_TIMCOUNT3_LOW_RUNNING_COUNT(v) \ + (((v) << 16) & BM_TIMROT_TIMCOUNT3_LOW_RUNNING_COUNT) +#define BP_TIMROT_TIMCOUNT3_HIGH_FIXED_COUNT 0 +#define BM_TIMROT_TIMCOUNT3_HIGH_FIXED_COUNT 0x0000FFFF +#define BF_TIMROT_TIMCOUNT3_HIGH_FIXED_COUNT(v) \ + (((v) << 0) & BM_TIMROT_TIMCOUNT3_HIGH_FIXED_COUNT) +HW_REGISTER_0(HW_TIMROT_VERSION, REGS_TIMROT_BASE, 0x000000a0) +#define HW_TIMROT_VERSION_ADDR (REGS_TIMROT_BASE + 0x000000a0) +#define BP_TIMROT_VERSION_MAJOR 24 +#define BM_TIMROT_VERSION_MAJOR 0xFF000000 +#define BF_TIMROT_VERSION_MAJOR(v) \ + (((v) << 24) & BM_TIMROT_VERSION_MAJOR) +#define BP_TIMROT_VERSION_MINOR 16 +#define BM_TIMROT_VERSION_MINOR 0x00FF0000 +#define BF_TIMROT_VERSION_MINOR(v) \ + (((v) << 16) & BM_TIMROT_VERSION_MINOR) +#define BP_TIMROT_VERSION_STEP 0 +#define BM_TIMROT_VERSION_STEP 0x0000FFFF +#define BF_TIMROT_VERSION_STEP(v) \ + (((v) << 0) & BM_TIMROT_VERSION_STEP) +#endif /* __ARCH_ARM___TIMROT_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-tvenc.h b/arch/arm/mach-stmp3xxx/include/mach/regs-tvenc.h new file mode 100644 index 000000000000..788d0978cf6d --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-tvenc.h @@ -0,0 +1,337 @@ +/* + * STMP TVENC Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___TVENC_H +#define __ARCH_ARM___TVENC_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_TVENC_BASE (REGS_BASE + 0x38000) +#define REGS_TVENC_BASE_PHYS (0x80038000) +#define REGS_TVENC_SIZE 0x00002000 +HW_REGISTER(HW_TVENC_CTRL, REGS_TVENC_BASE, 0x00000000) +#define HW_TVENC_CTRL_ADDR (REGS_TVENC_BASE + 0x00000000) +#define BM_TVENC_CTRL_SFTRST 0x80000000 +#define BM_TVENC_CTRL_CLKGATE 0x40000000 +#define BM_TVENC_CTRL_TVENC_MACROVISION_PRESENT 0x20000000 +#define BM_TVENC_CTRL_TVENC_COMPOSITE_PRESENT 0x10000000 +#define BM_TVENC_CTRL_TVENC_SVIDEO_PRESENT 0x08000000 +#define BM_TVENC_CTRL_TVENC_COMPONENT_PRESENT 0x04000000 +#define BM_TVENC_CTRL_DAC_FIFO_NO_WRITE 0x00000020 +#define BM_TVENC_CTRL_DAC_FIFO_NO_READ 0x00000010 +#define BM_TVENC_CTRL_DAC_DATA_FIFO_RST 0x00000008 +#define BM_TVENC_CTRL_DAC_MUX_MODE 0x00000001 +HW_REGISTER(HW_TVENC_CONFIG, REGS_TVENC_BASE, 0x00000010) +#define HW_TVENC_CONFIG_ADDR (REGS_TVENC_BASE + 0x00000010) +#define BM_TVENC_CONFIG_DEFAULT_PICFORM 0x08000000 +#define BP_TVENC_CONFIG_YDEL_ADJ 24 +#define BM_TVENC_CONFIG_YDEL_ADJ 0x07000000 +#define BF_TVENC_CONFIG_YDEL_ADJ(v) \ + (((v) << 24) & BM_TVENC_CONFIG_YDEL_ADJ) +#define BM_TVENC_CONFIG_ADD_YPBPR_PED 0x00200000 +#define BM_TVENC_CONFIG_PAL_SHAPE 0x00100000 +#define BM_TVENC_CONFIG_NO_PED 0x00080000 +#define BM_TVENC_CONFIG_COLOR_BAR_EN 0x00040000 +#define BP_TVENC_CONFIG_YGAIN_SEL 16 +#define BM_TVENC_CONFIG_YGAIN_SEL 0x00030000 +#define BF_TVENC_CONFIG_YGAIN_SEL(v) \ + (((v) << 16) & BM_TVENC_CONFIG_YGAIN_SEL) +#define BP_TVENC_CONFIG_CGAIN 14 +#define BM_TVENC_CONFIG_CGAIN 0x0000C000 +#define BF_TVENC_CONFIG_CGAIN(v) \ + (((v) << 14) & BM_TVENC_CONFIG_CGAIN) +#define BP_TVENC_CONFIG_CLK_PHS 12 +#define BM_TVENC_CONFIG_CLK_PHS 0x00003000 +#define BF_TVENC_CONFIG_CLK_PHS(v) \ + (((v) << 12) & BM_TVENC_CONFIG_CLK_PHS) +#define BM_TVENC_CONFIG_FSYNC_ENBL 0x00000400 +#define BM_TVENC_CONFIG_FSYNC_PHS 0x00000200 +#define BM_TVENC_CONFIG_HSYNC_PHS 0x00000100 +#define BM_TVENC_CONFIG_VSYNC_PHS 0x00000080 +#define BP_TVENC_CONFIG_SYNC_MODE 4 +#define BM_TVENC_CONFIG_SYNC_MODE 0x00000070 +#define BF_TVENC_CONFIG_SYNC_MODE(v) \ + (((v) << 4) & BM_TVENC_CONFIG_SYNC_MODE) +#define BP_TVENC_CONFIG_ENCD_MODE 0 +#define BM_TVENC_CONFIG_ENCD_MODE 0x00000007 +#define BF_TVENC_CONFIG_ENCD_MODE(v) \ + (((v) << 0) & BM_TVENC_CONFIG_ENCD_MODE) +HW_REGISTER(HW_TVENC_FILTCTRL, REGS_TVENC_BASE, 0x00000020) +#define HW_TVENC_FILTCTRL_ADDR (REGS_TVENC_BASE + 0x00000020) +#define BM_TVENC_FILTCTRL_YSHARP_BW 0x00080000 +#define BM_TVENC_FILTCTRL_YD_OFFSETSEL 0x00040000 +#define BM_TVENC_FILTCTRL_SEL_YLPF 0x00020000 +#define BM_TVENC_FILTCTRL_SEL_CLPF 0x00010000 +#define BM_TVENC_FILTCTRL_SEL_YSHARP 0x00008000 +#define BM_TVENC_FILTCTRL_YLPF_COEFSEL 0x00004000 +#define BM_TVENC_FILTCTRL_COEFSEL_CLPF 0x00002000 +#define BM_TVENC_FILTCTRL_YS_GAINSGN 0x00001000 +#define BP_TVENC_FILTCTRL_YS_GAINSEL 10 +#define BM_TVENC_FILTCTRL_YS_GAINSEL 0x00000C00 +#define BF_TVENC_FILTCTRL_YS_GAINSEL(v) \ + (((v) << 10) & BM_TVENC_FILTCTRL_YS_GAINSEL) +HW_REGISTER(HW_TVENC_SYNCOFFSET, REGS_TVENC_BASE, 0x00000030) +#define HW_TVENC_SYNCOFFSET_ADDR (REGS_TVENC_BASE + 0x00000030) +#define BP_TVENC_SYNCOFFSET_HSO 20 +#define BM_TVENC_SYNCOFFSET_HSO 0x7FF00000 +#define BF_TVENC_SYNCOFFSET_HSO(v) \ + (((v) << 20) & BM_TVENC_SYNCOFFSET_HSO) +#define BP_TVENC_SYNCOFFSET_VSO 10 +#define BM_TVENC_SYNCOFFSET_VSO 0x000FFC00 +#define BF_TVENC_SYNCOFFSET_VSO(v) \ + (((v) << 10) & BM_TVENC_SYNCOFFSET_VSO) +#define BP_TVENC_SYNCOFFSET_HLC 0 +#define BM_TVENC_SYNCOFFSET_HLC 0x000003FF +#define BF_TVENC_SYNCOFFSET_HLC(v) \ + (((v) << 0) & BM_TVENC_SYNCOFFSET_HLC) +HW_REGISTER(HW_TVENC_HTIMINGSYNC0, REGS_TVENC_BASE, 0x00000040) +#define HW_TVENC_HTIMINGSYNC0_ADDR (REGS_TVENC_BASE + 0x00000040) +#define BP_TVENC_HTIMINGSYNC0_SYNC_END 16 +#define BM_TVENC_HTIMINGSYNC0_SYNC_END 0x03FF0000 +#define BF_TVENC_HTIMINGSYNC0_SYNC_END(v) \ + (((v) << 16) & BM_TVENC_HTIMINGSYNC0_SYNC_END) +#define BP_TVENC_HTIMINGSYNC0_SYNC_STRT 0 +#define BM_TVENC_HTIMINGSYNC0_SYNC_STRT 0x000003FF +#define BF_TVENC_HTIMINGSYNC0_SYNC_STRT(v) \ + (((v) << 0) & BM_TVENC_HTIMINGSYNC0_SYNC_STRT) +HW_REGISTER(HW_TVENC_HTIMINGSYNC1, REGS_TVENC_BASE, 0x00000050) +#define HW_TVENC_HTIMINGSYNC1_ADDR (REGS_TVENC_BASE + 0x00000050) +#define BP_TVENC_HTIMINGSYNC1_SYNC_EQEND 16 +#define BM_TVENC_HTIMINGSYNC1_SYNC_EQEND 0x03FF0000 +#define BF_TVENC_HTIMINGSYNC1_SYNC_EQEND(v) \ + (((v) << 16) & BM_TVENC_HTIMINGSYNC1_SYNC_EQEND) +#define BP_TVENC_HTIMINGSYNC1_SYNC_SREND 0 +#define BM_TVENC_HTIMINGSYNC1_SYNC_SREND 0x000003FF +#define BF_TVENC_HTIMINGSYNC1_SYNC_SREND(v) \ + (((v) << 0) & BM_TVENC_HTIMINGSYNC1_SYNC_SREND) +HW_REGISTER(HW_TVENC_HTIMINGACTIVE, REGS_TVENC_BASE, 0x00000060) +#define HW_TVENC_HTIMINGACTIVE_ADDR (REGS_TVENC_BASE + 0x00000060) +#define BP_TVENC_HTIMINGACTIVE_ACTV_END 16 +#define BM_TVENC_HTIMINGACTIVE_ACTV_END 0x03FF0000 +#define BF_TVENC_HTIMINGACTIVE_ACTV_END(v) \ + (((v) << 16) & BM_TVENC_HTIMINGACTIVE_ACTV_END) +#define BP_TVENC_HTIMINGACTIVE_ACTV_STRT 0 +#define BM_TVENC_HTIMINGACTIVE_ACTV_STRT 0x000003FF +#define BF_TVENC_HTIMINGACTIVE_ACTV_STRT(v) \ + (((v) << 0) & BM_TVENC_HTIMINGACTIVE_ACTV_STRT) +HW_REGISTER(HW_TVENC_HTIMINGBURST0, REGS_TVENC_BASE, 0x00000070) +#define HW_TVENC_HTIMINGBURST0_ADDR (REGS_TVENC_BASE + 0x00000070) +#define BP_TVENC_HTIMINGBURST0_WBRST_STRT 16 +#define BM_TVENC_HTIMINGBURST0_WBRST_STRT 0x03FF0000 +#define BF_TVENC_HTIMINGBURST0_WBRST_STRT(v) \ + (((v) << 16) & BM_TVENC_HTIMINGBURST0_WBRST_STRT) +#define BP_TVENC_HTIMINGBURST0_NBRST_STRT 0 +#define BM_TVENC_HTIMINGBURST0_NBRST_STRT 0x000003FF +#define BF_TVENC_HTIMINGBURST0_NBRST_STRT(v) \ + (((v) << 0) & BM_TVENC_HTIMINGBURST0_NBRST_STRT) +HW_REGISTER(HW_TVENC_HTIMINGBURST1, REGS_TVENC_BASE, 0x00000080) +#define HW_TVENC_HTIMINGBURST1_ADDR (REGS_TVENC_BASE + 0x00000080) +#define BP_TVENC_HTIMINGBURST1_BRST_END 0 +#define BM_TVENC_HTIMINGBURST1_BRST_END 0x000003FF +#define BF_TVENC_HTIMINGBURST1_BRST_END(v) \ + (((v) << 0) & BM_TVENC_HTIMINGBURST1_BRST_END) +HW_REGISTER(HW_TVENC_VTIMING0, REGS_TVENC_BASE, 0x00000090) +#define HW_TVENC_VTIMING0_ADDR (REGS_TVENC_BASE + 0x00000090) +#define BP_TVENC_VTIMING0_VSTRT_PREEQ 16 +#define BM_TVENC_VTIMING0_VSTRT_PREEQ 0x03FF0000 +#define BF_TVENC_VTIMING0_VSTRT_PREEQ(v) \ + (((v) << 16) & BM_TVENC_VTIMING0_VSTRT_PREEQ) +#define BP_TVENC_VTIMING0_VSTRT_ACTV 8 +#define BM_TVENC_VTIMING0_VSTRT_ACTV 0x00003F00 +#define BF_TVENC_VTIMING0_VSTRT_ACTV(v) \ + (((v) << 8) & BM_TVENC_VTIMING0_VSTRT_ACTV) +#define BP_TVENC_VTIMING0_VSTRT_SUBPH 0 +#define BM_TVENC_VTIMING0_VSTRT_SUBPH 0x0000003F +#define BF_TVENC_VTIMING0_VSTRT_SUBPH(v) \ + (((v) << 0) & BM_TVENC_VTIMING0_VSTRT_SUBPH) +HW_REGISTER(HW_TVENC_VTIMING1, REGS_TVENC_BASE, 0x000000a0) +#define HW_TVENC_VTIMING1_ADDR (REGS_TVENC_BASE + 0x000000a0) +#define BP_TVENC_VTIMING1_VSTRT_POSTEQ 24 +#define BM_TVENC_VTIMING1_VSTRT_POSTEQ 0x3F000000 +#define BF_TVENC_VTIMING1_VSTRT_POSTEQ(v) \ + (((v) << 24) & BM_TVENC_VTIMING1_VSTRT_POSTEQ) +#define BP_TVENC_VTIMING1_VSTRT_SERRA 16 +#define BM_TVENC_VTIMING1_VSTRT_SERRA 0x003F0000 +#define BF_TVENC_VTIMING1_VSTRT_SERRA(v) \ + (((v) << 16) & BM_TVENC_VTIMING1_VSTRT_SERRA) +#define BP_TVENC_VTIMING1_LAST_FLD_LN 0 +#define BM_TVENC_VTIMING1_LAST_FLD_LN 0x000003FF +#define BF_TVENC_VTIMING1_LAST_FLD_LN(v) \ + (((v) << 0) & BM_TVENC_VTIMING1_LAST_FLD_LN) +HW_REGISTER(HW_TVENC_MISC, REGS_TVENC_BASE, 0x000000b0) +#define HW_TVENC_MISC_ADDR (REGS_TVENC_BASE + 0x000000b0) +#define BP_TVENC_MISC_LPF_RST_OFF 16 +#define BM_TVENC_MISC_LPF_RST_OFF 0x01FF0000 +#define BF_TVENC_MISC_LPF_RST_OFF(v) \ + (((v) << 16) & BM_TVENC_MISC_LPF_RST_OFF) +#define BM_TVENC_MISC_NTSC_LN_CNT 0x00000800 +#define BM_TVENC_MISC_PAL_FSC_PHASE_ALT 0x00000400 +#define BP_TVENC_MISC_FSC_PHASE_RST 8 +#define BM_TVENC_MISC_FSC_PHASE_RST 0x00000300 +#define BF_TVENC_MISC_FSC_PHASE_RST(v) \ + (((v) << 8) & BM_TVENC_MISC_FSC_PHASE_RST) +#define BP_TVENC_MISC_BRUCHB 6 +#define BM_TVENC_MISC_BRUCHB 0x000000C0 +#define BF_TVENC_MISC_BRUCHB(v) \ + (((v) << 6) & BM_TVENC_MISC_BRUCHB) +#define BP_TVENC_MISC_AGC_LVL_CTRL 4 +#define BM_TVENC_MISC_AGC_LVL_CTRL 0x00000030 +#define BF_TVENC_MISC_AGC_LVL_CTRL(v) \ + (((v) << 4) & BM_TVENC_MISC_AGC_LVL_CTRL) +#define BM_TVENC_MISC_CS_INVERT_CTRL 0x00000004 +#define BP_TVENC_MISC_Y_BLANK_CTRL 0 +#define BM_TVENC_MISC_Y_BLANK_CTRL 0x00000003 +#define BF_TVENC_MISC_Y_BLANK_CTRL(v) \ + (((v) << 0) & BM_TVENC_MISC_Y_BLANK_CTRL) +HW_REGISTER(HW_TVENC_COLORSUB0, REGS_TVENC_BASE, 0x000000c0) +#define HW_TVENC_COLORSUB0_ADDR (REGS_TVENC_BASE + 0x000000c0) +#define BP_TVENC_COLORSUB0_PHASE_INC 0 +#define BM_TVENC_COLORSUB0_PHASE_INC 0xFFFFFFFF +#define BF_TVENC_COLORSUB0_PHASE_INC(v) (v) +HW_REGISTER(HW_TVENC_COLORSUB1, REGS_TVENC_BASE, 0x000000d0) +#define HW_TVENC_COLORSUB1_ADDR (REGS_TVENC_BASE + 0x000000d0) +#define BP_TVENC_COLORSUB1_PHASE_OFFSET 0 +#define BM_TVENC_COLORSUB1_PHASE_OFFSET 0xFFFFFFFF +#define BF_TVENC_COLORSUB1_PHASE_OFFSET(v) (v) +HW_REGISTER(HW_TVENC_COPYPROTECT, REGS_TVENC_BASE, 0x000000e0) +#define HW_TVENC_COPYPROTECT_ADDR (REGS_TVENC_BASE + 0x000000e0) +#define BM_TVENC_COPYPROTECT_WSS_ENBL 0x00008000 +#define BM_TVENC_COPYPROTECT_CGMS_ENBL 0x00004000 +#define BP_TVENC_COPYPROTECT_WSS_CGMS_DATA 0 +#define BM_TVENC_COPYPROTECT_WSS_CGMS_DATA 0x00003FFF +#define BF_TVENC_COPYPROTECT_WSS_CGMS_DATA(v) \ + (((v) << 0) & BM_TVENC_COPYPROTECT_WSS_CGMS_DATA) +HW_REGISTER(HW_TVENC_CLOSEDCAPTION, REGS_TVENC_BASE, 0x000000f0) +#define HW_TVENC_CLOSEDCAPTION_ADDR (REGS_TVENC_BASE + 0x000000f0) +#define BP_TVENC_CLOSEDCAPTION_CC_ENBL 18 +#define BM_TVENC_CLOSEDCAPTION_CC_ENBL 0x000C0000 +#define BF_TVENC_CLOSEDCAPTION_CC_ENBL(v) \ + (((v) << 18) & BM_TVENC_CLOSEDCAPTION_CC_ENBL) +#define BP_TVENC_CLOSEDCAPTION_CC_FILL 16 +#define BM_TVENC_CLOSEDCAPTION_CC_FILL 0x00030000 +#define BF_TVENC_CLOSEDCAPTION_CC_FILL(v) \ + (((v) << 16) & BM_TVENC_CLOSEDCAPTION_CC_FILL) +#define BP_TVENC_CLOSEDCAPTION_CC_DATA 0 +#define BM_TVENC_CLOSEDCAPTION_CC_DATA 0x0000FFFF +#define BF_TVENC_CLOSEDCAPTION_CC_DATA(v) \ + (((v) << 0) & BM_TVENC_CLOSEDCAPTION_CC_DATA) +HW_REGISTER(HW_TVENC_COLORBURST, REGS_TVENC_BASE, 0x00000140) +#define HW_TVENC_COLORBURST_ADDR (REGS_TVENC_BASE + 0x00000140) +#define BP_TVENC_COLORBURST_NBA 24 +#define BM_TVENC_COLORBURST_NBA 0xFF000000 +#define BF_TVENC_COLORBURST_NBA(v) \ + (((v) << 24) & BM_TVENC_COLORBURST_NBA) +#define BP_TVENC_COLORBURST_PBA 16 +#define BM_TVENC_COLORBURST_PBA 0x00FF0000 +#define BF_TVENC_COLORBURST_PBA(v) \ + (((v) << 16) & BM_TVENC_COLORBURST_PBA) +HW_REGISTER(HW_TVENC_MACROVISION0, REGS_TVENC_BASE, 0x00000150) +#define HW_TVENC_MACROVISION0_ADDR (REGS_TVENC_BASE + 0x00000150) +#define BP_TVENC_MACROVISION0_DATA 0 +#define BM_TVENC_MACROVISION0_DATA 0xFFFFFFFF +#define BF_TVENC_MACROVISION0_DATA(v) (v) +HW_REGISTER(HW_TVENC_MACROVISION1, REGS_TVENC_BASE, 0x00000160) +#define HW_TVENC_MACROVISION1_ADDR (REGS_TVENC_BASE + 0x00000160) +#define BP_TVENC_MACROVISION1_DATA 0 +#define BM_TVENC_MACROVISION1_DATA 0xFFFFFFFF +#define BF_TVENC_MACROVISION1_DATA(v) (v) +HW_REGISTER(HW_TVENC_MACROVISION2, REGS_TVENC_BASE, 0x00000170) +#define HW_TVENC_MACROVISION2_ADDR (REGS_TVENC_BASE + 0x00000170) +#define BP_TVENC_MACROVISION2_DATA 0 +#define BM_TVENC_MACROVISION2_DATA 0xFFFFFFFF +#define BF_TVENC_MACROVISION2_DATA(v) (v) +HW_REGISTER(HW_TVENC_MACROVISION3, REGS_TVENC_BASE, 0x00000180) +#define HW_TVENC_MACROVISION3_ADDR (REGS_TVENC_BASE + 0x00000180) +#define BP_TVENC_MACROVISION3_DATA 0 +#define BM_TVENC_MACROVISION3_DATA 0xFFFFFFFF +#define BF_TVENC_MACROVISION3_DATA(v) (v) +HW_REGISTER(HW_TVENC_MACROVISION4, REGS_TVENC_BASE, 0x00000190) +#define HW_TVENC_MACROVISION4_ADDR (REGS_TVENC_BASE + 0x00000190) +#define BP_TVENC_MACROVISION4_MACV_TST 16 +#define BM_TVENC_MACROVISION4_MACV_TST 0x00FF0000 +#define BF_TVENC_MACROVISION4_MACV_TST(v) \ + (((v) << 16) & BM_TVENC_MACROVISION4_MACV_TST) +#define BP_TVENC_MACROVISION4_DATA 0 +#define BM_TVENC_MACROVISION4_DATA 0x000007FF +#define BF_TVENC_MACROVISION4_DATA(v) \ + (((v) << 0) & BM_TVENC_MACROVISION4_DATA) +HW_REGISTER(HW_TVENC_DACCTRL, REGS_TVENC_BASE, 0x000001a0) +#define HW_TVENC_DACCTRL_ADDR (REGS_TVENC_BASE + 0x000001a0) +#define BM_TVENC_DACCTRL_TEST3 0x80000000 +#define BM_TVENC_DACCTRL_JACK1_DIS_DET_EN 0x10000000 +#define BM_TVENC_DACCTRL_TEST2 0x08000000 +#define BM_TVENC_DACCTRL_JACK1_DET_EN 0x01000000 +#define BM_TVENC_DACCTRL_TEST1 0x00800000 +#define BM_TVENC_DACCTRL_DISABLE_GND_DETECT 0x00400000 +#define BP_TVENC_DACCTRL_JACK_DIS_ADJ 20 +#define BM_TVENC_DACCTRL_JACK_DIS_ADJ 0x00300000 +#define BF_TVENC_DACCTRL_JACK_DIS_ADJ(v) \ + (((v) << 20) & BM_TVENC_DACCTRL_JACK_DIS_ADJ) +#define BM_TVENC_DACCTRL_GAINDN 0x00080000 +#define BM_TVENC_DACCTRL_GAINUP 0x00040000 +#define BM_TVENC_DACCTRL_INVERT_CLK 0x00020000 +#define BM_TVENC_DACCTRL_SELECT_CLK 0x00010000 +#define BM_TVENC_DACCTRL_BYPASS_ACT_CASCODE 0x00008000 +#define BM_TVENC_DACCTRL_PWRUP1 0x00001000 +#define BM_TVENC_DACCTRL_WELL_TOVDD 0x00000800 +#define BM_TVENC_DACCTRL_DUMP_TOVDD1 0x00000100 +#define BM_TVENC_DACCTRL_LOWER_SIGNAL 0x00000080 +#define BP_TVENC_DACCTRL_RVAL 4 +#define BM_TVENC_DACCTRL_RVAL 0x00000070 +#define BF_TVENC_DACCTRL_RVAL(v) \ + (((v) << 4) & BM_TVENC_DACCTRL_RVAL) +#define BM_TVENC_DACCTRL_NO_INTERNAL_TERM 0x00000008 +#define BM_TVENC_DACCTRL_HALF_CURRENT 0x00000004 +#define BP_TVENC_DACCTRL_CASC_ADJ 0 +#define BM_TVENC_DACCTRL_CASC_ADJ 0x00000003 +#define BF_TVENC_DACCTRL_CASC_ADJ(v) \ + (((v) << 0) & BM_TVENC_DACCTRL_CASC_ADJ) +HW_REGISTER(HW_TVENC_DACSTATUS, REGS_TVENC_BASE, 0x000001b0) +#define HW_TVENC_DACSTATUS_ADDR (REGS_TVENC_BASE + 0x000001b0) +#define BM_TVENC_DACSTATUS_JACK1_DET_STATUS 0x00000400 +#define BM_TVENC_DACSTATUS_JACK1_GROUNDED 0x00000080 +#define BM_TVENC_DACSTATUS_JACK1_DIS_DET_IRQ 0x00000010 +#define BM_TVENC_DACSTATUS_JACK1_DET_IRQ 0x00000002 +#define BM_TVENC_DACSTATUS_ENIRQ_JACK 0x00000001 +HW_REGISTER(HW_TVENC_VDACTEST, REGS_TVENC_BASE, 0x000001c0) +#define HW_TVENC_VDACTEST_ADDR (REGS_TVENC_BASE + 0x000001c0) +#define BM_TVENC_VDACTEST_ENABLE_PIX_INT_GAIN 0x00002000 +#define BM_TVENC_VDACTEST_BYPASS_PIX_INT 0x00001000 +#define BM_TVENC_VDACTEST_BYPASS_PIX_INT_DROOP 0x00000800 +#define BM_TVENC_VDACTEST_TEST_FIFO_FULL 0x00000400 +#define BP_TVENC_VDACTEST_DATA 0 +#define BM_TVENC_VDACTEST_DATA 0x000003FF +#define BF_TVENC_VDACTEST_DATA(v) \ + (((v) << 0) & BM_TVENC_VDACTEST_DATA) +HW_REGISTER_0(HW_TVENC_VERSION, REGS_TVENC_BASE, 0x000001d0) +#define HW_TVENC_VERSION_ADDR (REGS_TVENC_BASE + 0x000001d0) +#define BP_TVENC_VERSION_MAJOR 24 +#define BM_TVENC_VERSION_MAJOR 0xFF000000 +#define BF_TVENC_VERSION_MAJOR(v) \ + (((v) << 24) & BM_TVENC_VERSION_MAJOR) +#define BP_TVENC_VERSION_MINOR 16 +#define BM_TVENC_VERSION_MINOR 0x00FF0000 +#define BF_TVENC_VERSION_MINOR(v) \ + (((v) << 16) & BM_TVENC_VERSION_MINOR) +#define BP_TVENC_VERSION_STEP 0 +#define BM_TVENC_VERSION_STEP 0x0000FFFF +#define BF_TVENC_VERSION_STEP(v) \ + (((v) << 0) & BM_TVENC_VERSION_STEP) +#endif /* __ARCH_ARM___TVENC_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-uartapp.h b/arch/arm/mach-stmp3xxx/include/mach/regs-uartapp.h new file mode 100644 index 000000000000..a4246dc4ff97 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-uartapp.h @@ -0,0 +1,238 @@ +/* + * STMP UARTAPP Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___UARTAPP_H +#define __ARCH_ARM___UARTAPP_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_UARTAPP_BASE (REGS_BASE + 0x6c000) +#define REGS_UARTAPP1_BASE_PHYS (0x8006C000) +#define REGS_UARTAPP2_BASE_PHYS (0x8006E000) +#define REGS_UARTAPP_SIZE 0x00002000 +HW_REGISTER(HW_UARTAPP_CTRL0, REGS_UARTAPP_BASE, 0x00000000) +#define HW_UARTAPP_CTRL0_ADDR (REGS_UARTAPP_BASE + 0x00000000) +#define BM_UARTAPP_CTRL0_SFTRST 0x80000000 +#define BM_UARTAPP_CTRL0_CLKGATE 0x40000000 +#define BM_UARTAPP_CTRL0_RUN 0x20000000 +#define BM_UARTAPP_CTRL0_RX_SOURCE 0x10000000 +#define BM_UARTAPP_CTRL0_RXTO_ENABLE 0x08000000 +#define BP_UARTAPP_CTRL0_RXTIMEOUT 16 +#define BM_UARTAPP_CTRL0_RXTIMEOUT 0x07FF0000 +#define BF_UARTAPP_CTRL0_RXTIMEOUT(v) \ + (((v) << 16) & BM_UARTAPP_CTRL0_RXTIMEOUT) +#define BP_UARTAPP_CTRL0_XFER_COUNT 0 +#define BM_UARTAPP_CTRL0_XFER_COUNT 0x0000FFFF +#define BF_UARTAPP_CTRL0_XFER_COUNT(v) \ + (((v) << 0) & BM_UARTAPP_CTRL0_XFER_COUNT) +HW_REGISTER(HW_UARTAPP_CTRL1, REGS_UARTAPP_BASE, 0x00000010) +#define HW_UARTAPP_CTRL1_ADDR (REGS_UARTAPP_BASE + 0x00000010) +#define BM_UARTAPP_CTRL1_RUN 0x10000000 +#define BP_UARTAPP_CTRL1_XFER_COUNT 0 +#define BM_UARTAPP_CTRL1_XFER_COUNT 0x0000FFFF +#define BF_UARTAPP_CTRL1_XFER_COUNT(v) \ + (((v) << 0) & BM_UARTAPP_CTRL1_XFER_COUNT) +HW_REGISTER(HW_UARTAPP_CTRL2, REGS_UARTAPP_BASE, 0x00000020) +#define HW_UARTAPP_CTRL2_ADDR (REGS_UARTAPP_BASE + 0x00000020) +#define BM_UARTAPP_CTRL2_INVERT_RTS 0x80000000 +#define BM_UARTAPP_CTRL2_INVERT_CTS 0x40000000 +#define BM_UARTAPP_CTRL2_INVERT_TX 0x20000000 +#define BM_UARTAPP_CTRL2_INVERT_RX 0x10000000 +#define BM_UARTAPP_CTRL2_RTS_SEMAPHORE 0x08000000 +#define BM_UARTAPP_CTRL2_DMAONERR 0x04000000 +#define BM_UARTAPP_CTRL2_TXDMAE 0x02000000 +#define BM_UARTAPP_CTRL2_RXDMAE 0x01000000 +#define BP_UARTAPP_CTRL2_RXIFLSEL 20 +#define BM_UARTAPP_CTRL2_RXIFLSEL 0x00700000 +#define BF_UARTAPP_CTRL2_RXIFLSEL(v) \ + (((v) << 20) & BM_UARTAPP_CTRL2_RXIFLSEL) +#define BV_UARTAPP_CTRL2_RXIFLSEL__NOT_EMPTY 0x0 +#define BV_UARTAPP_CTRL2_RXIFLSEL__ONE_QUARTER 0x1 +#define BV_UARTAPP_CTRL2_RXIFLSEL__ONE_HALF 0x2 +#define BV_UARTAPP_CTRL2_RXIFLSEL__THREE_QUARTERS 0x3 +#define BV_UARTAPP_CTRL2_RXIFLSEL__SEVEN_EIGHTHS 0x4 +#define BV_UARTAPP_CTRL2_RXIFLSEL__INVALID5 0x5 +#define BV_UARTAPP_CTRL2_RXIFLSEL__INVALID6 0x6 +#define BV_UARTAPP_CTRL2_RXIFLSEL__INVALID7 0x7 +#define BP_UARTAPP_CTRL2_TXIFLSEL 16 +#define BM_UARTAPP_CTRL2_TXIFLSEL 0x00070000 +#define BF_UARTAPP_CTRL2_TXIFLSEL(v) \ + (((v) << 16) & BM_UARTAPP_CTRL2_TXIFLSEL) +#define BV_UARTAPP_CTRL2_TXIFLSEL__EMPTY 0x0 +#define BV_UARTAPP_CTRL2_TXIFLSEL__ONE_QUARTER 0x1 +#define BV_UARTAPP_CTRL2_TXIFLSEL__ONE_HALF 0x2 +#define BV_UARTAPP_CTRL2_TXIFLSEL__THREE_QUARTERS 0x3 +#define BV_UARTAPP_CTRL2_TXIFLSEL__SEVEN_EIGHTHS 0x4 +#define BV_UARTAPP_CTRL2_TXIFLSEL__INVALID5 0x5 +#define BV_UARTAPP_CTRL2_TXIFLSEL__INVALID6 0x6 +#define BV_UARTAPP_CTRL2_TXIFLSEL__INVALID7 0x7 +#define BM_UARTAPP_CTRL2_CTSEN 0x00008000 +#define BM_UARTAPP_CTRL2_RTSEN 0x00004000 +#define BM_UARTAPP_CTRL2_OUT2 0x00002000 +#define BM_UARTAPP_CTRL2_OUT1 0x00001000 +#define BM_UARTAPP_CTRL2_RTS 0x00000800 +#define BM_UARTAPP_CTRL2_DTR 0x00000400 +#define BM_UARTAPP_CTRL2_RXE 0x00000200 +#define BM_UARTAPP_CTRL2_TXE 0x00000100 +#define BM_UARTAPP_CTRL2_LBE 0x00000080 +#define BM_UARTAPP_CTRL2_USE_LCR2 0x00000040 +#define BM_UARTAPP_CTRL2_SIRLP 0x00000004 +#define BM_UARTAPP_CTRL2_SIREN 0x00000002 +#define BM_UARTAPP_CTRL2_UARTEN 0x00000001 +HW_REGISTER(HW_UARTAPP_LINECTRL, REGS_UARTAPP_BASE, 0x00000030) +#define HW_UARTAPP_LINECTRL_ADDR (REGS_UARTAPP_BASE + 0x00000030) +#define BP_UARTAPP_LINECTRL_BAUD_DIVINT 16 +#define BM_UARTAPP_LINECTRL_BAUD_DIVINT 0xFFFF0000 +#define BF_UARTAPP_LINECTRL_BAUD_DIVINT(v) \ + (((v) << 16) & BM_UARTAPP_LINECTRL_BAUD_DIVINT) +#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC 8 +#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC 0x00003F00 +#define BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(v) \ + (((v) << 8) & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC) +#define BM_UARTAPP_LINECTRL_SPS 0x00000080 +#define BP_UARTAPP_LINECTRL_WLEN 5 +#define BM_UARTAPP_LINECTRL_WLEN 0x00000060 +#define BF_UARTAPP_LINECTRL_WLEN(v) \ + (((v) << 5) & BM_UARTAPP_LINECTRL_WLEN) +#define BM_UARTAPP_LINECTRL_FEN 0x00000010 +#define BM_UARTAPP_LINECTRL_STP2 0x00000008 +#define BM_UARTAPP_LINECTRL_EPS 0x00000004 +#define BM_UARTAPP_LINECTRL_PEN 0x00000002 +#define BM_UARTAPP_LINECTRL_BRK 0x00000001 +HW_REGISTER(HW_UARTAPP_LINECTRL2, REGS_UARTAPP_BASE, 0x00000040) +#define HW_UARTAPP_LINECTRL2_ADDR (REGS_UARTAPP_BASE + 0x00000040) +#define BP_UARTAPP_LINECTRL2_BAUD_DIVINT 16 +#define BM_UARTAPP_LINECTRL2_BAUD_DIVINT 0xFFFF0000 +#define BF_UARTAPP_LINECTRL2_BAUD_DIVINT(v) \ + (((v) << 16) & BM_UARTAPP_LINECTRL2_BAUD_DIVINT) +#define BP_UARTAPP_LINECTRL2_BAUD_DIVFRAC 8 +#define BM_UARTAPP_LINECTRL2_BAUD_DIVFRAC 0x00003F00 +#define BF_UARTAPP_LINECTRL2_BAUD_DIVFRAC(v) \ + (((v) << 8) & BM_UARTAPP_LINECTRL2_BAUD_DIVFRAC) +#define BM_UARTAPP_LINECTRL2_SPS 0x00000080 +#define BP_UARTAPP_LINECTRL2_WLEN 5 +#define BM_UARTAPP_LINECTRL2_WLEN 0x00000060 +#define BF_UARTAPP_LINECTRL2_WLEN(v) \ + (((v) << 5) & BM_UARTAPP_LINECTRL2_WLEN) +#define BM_UARTAPP_LINECTRL2_FEN 0x00000010 +#define BM_UARTAPP_LINECTRL2_STP2 0x00000008 +#define BM_UARTAPP_LINECTRL2_EPS 0x00000004 +#define BM_UARTAPP_LINECTRL2_PEN 0x00000002 +HW_REGISTER(HW_UARTAPP_INTR, REGS_UARTAPP_BASE, 0x00000050) +#define HW_UARTAPP_INTR_ADDR (REGS_UARTAPP_BASE + 0x00000050) +#define BM_UARTAPP_INTR_OEIEN 0x04000000 +#define BM_UARTAPP_INTR_BEIEN 0x02000000 +#define BM_UARTAPP_INTR_PEIEN 0x01000000 +#define BM_UARTAPP_INTR_FEIEN 0x00800000 +#define BM_UARTAPP_INTR_RTIEN 0x00400000 +#define BM_UARTAPP_INTR_TXIEN 0x00200000 +#define BM_UARTAPP_INTR_RXIEN 0x00100000 +#define BM_UARTAPP_INTR_DSRMIEN 0x00080000 +#define BM_UARTAPP_INTR_DCDMIEN 0x00040000 +#define BM_UARTAPP_INTR_CTSMIEN 0x00020000 +#define BM_UARTAPP_INTR_RIMIEN 0x00010000 +#define BM_UARTAPP_INTR_OEIS 0x00000400 +#define BM_UARTAPP_INTR_BEIS 0x00000200 +#define BM_UARTAPP_INTR_PEIS 0x00000100 +#define BM_UARTAPP_INTR_FEIS 0x00000080 +#define BM_UARTAPP_INTR_RTIS 0x00000040 +#define BM_UARTAPP_INTR_TXIS 0x00000020 +#define BM_UARTAPP_INTR_RXIS 0x00000010 +#define BM_UARTAPP_INTR_DSRMIS 0x00000008 +#define BM_UARTAPP_INTR_DCDMIS 0x00000004 +#define BM_UARTAPP_INTR_CTSMIS 0x00000002 +#define BM_UARTAPP_INTR_RIMIS 0x00000001 +HW_REGISTER_0(HW_UARTAPP_DATA, REGS_UARTAPP_BASE, 0x00000060) +#define HW_UARTAPP_DATA_ADDR (REGS_UARTAPP_BASE + 0x00000060) +#define BP_UARTAPP_DATA_DATA 0 +#define BM_UARTAPP_DATA_DATA 0xFFFFFFFF +#define BF_UARTAPP_DATA_DATA(v) (v) +HW_REGISTER_0(HW_UARTAPP_STAT, REGS_UARTAPP_BASE, 0x00000070) +#define HW_UARTAPP_STAT_ADDR (REGS_UARTAPP_BASE + 0x00000070) +#define BM_UARTAPP_STAT_PRESENT 0x80000000 +#define BV_UARTAPP_STAT_PRESENT__UNAVAILABLE 0x0 +#define BV_UARTAPP_STAT_PRESENT__AVAILABLE 0x1 +#define BM_UARTAPP_STAT_HISPEED 0x40000000 +#define BV_UARTAPP_STAT_HISPEED__UNAVAILABLE 0x0 +#define BV_UARTAPP_STAT_HISPEED__AVAILABLE 0x1 +#define BM_UARTAPP_STAT_BUSY 0x20000000 +#define BM_UARTAPP_STAT_CTS 0x10000000 +#define BM_UARTAPP_STAT_TXFE 0x08000000 +#define BM_UARTAPP_STAT_RXFF 0x04000000 +#define BM_UARTAPP_STAT_TXFF 0x02000000 +#define BM_UARTAPP_STAT_RXFE 0x01000000 +#define BP_UARTAPP_STAT_RXBYTE_INVALID 20 +#define BM_UARTAPP_STAT_RXBYTE_INVALID 0x00F00000 +#define BF_UARTAPP_STAT_RXBYTE_INVALID(v) \ + (((v) << 20) & BM_UARTAPP_STAT_RXBYTE_INVALID) +#define BM_UARTAPP_STAT_OERR 0x00080000 +#define BM_UARTAPP_STAT_BERR 0x00040000 +#define BM_UARTAPP_STAT_PERR 0x00020000 +#define BM_UARTAPP_STAT_FERR 0x00010000 +#define BP_UARTAPP_STAT_RXCOUNT 0 +#define BM_UARTAPP_STAT_RXCOUNT 0x0000FFFF +#define BF_UARTAPP_STAT_RXCOUNT(v) \ + (((v) << 0) & BM_UARTAPP_STAT_RXCOUNT) +HW_REGISTER_0(HW_UARTAPP_DEBUG, REGS_UARTAPP_BASE, 0x00000080) +#define HW_UARTAPP_DEBUG_ADDR (REGS_UARTAPP_BASE + 0x00000080) +#define BP_UARTAPP_DEBUG_RXIBAUD_DIV 16 +#define BM_UARTAPP_DEBUG_RXIBAUD_DIV 0xFFFF0000 +#define BF_UARTAPP_DEBUG_RXIBAUD_DIV(v) \ + (((v) << 16) & BM_UARTAPP_DEBUG_RXIBAUD_DIV) +#define BP_UARTAPP_DEBUG_RXFBAUD_DIV 10 +#define BM_UARTAPP_DEBUG_RXFBAUD_DIV 0x0000FC00 +#define BF_UARTAPP_DEBUG_RXFBAUD_DIV(v) \ + (((v) << 10) & BM_UARTAPP_DEBUG_RXFBAUD_DIV) +#define BM_UARTAPP_DEBUG_TXDMARUN 0x00000020 +#define BM_UARTAPP_DEBUG_RXDMARUN 0x00000010 +#define BM_UARTAPP_DEBUG_TXCMDEND 0x00000008 +#define BM_UARTAPP_DEBUG_RXCMDEND 0x00000004 +#define BM_UARTAPP_DEBUG_TXDMARQ 0x00000002 +#define BM_UARTAPP_DEBUG_RXDMARQ 0x00000001 +HW_REGISTER_0(HW_UARTAPP_VERSION, REGS_UARTAPP_BASE, 0x00000090) +#define HW_UARTAPP_VERSION_ADDR (REGS_UARTAPP_BASE + 0x00000090) +#define BP_UARTAPP_VERSION_MAJOR 24 +#define BM_UARTAPP_VERSION_MAJOR 0xFF000000 +#define BF_UARTAPP_VERSION_MAJOR(v) \ + (((v) << 24) & BM_UARTAPP_VERSION_MAJOR) +#define BP_UARTAPP_VERSION_MINOR 16 +#define BM_UARTAPP_VERSION_MINOR 0x00FF0000 +#define BF_UARTAPP_VERSION_MINOR(v) \ + (((v) << 16) & BM_UARTAPP_VERSION_MINOR) +#define BP_UARTAPP_VERSION_STEP 0 +#define BM_UARTAPP_VERSION_STEP 0x0000FFFF +#define BF_UARTAPP_VERSION_STEP(v) \ + (((v) << 0) & BM_UARTAPP_VERSION_STEP) +HW_REGISTER_0(HW_UARTAPP_AUTOBAUD, REGS_UARTAPP_BASE, 0x000000a0) +#define HW_UARTAPP_AUTOBAUD_ADDR (REGS_UARTAPP_BASE + 0x000000a0) +#define BP_UARTAPP_AUTOBAUD_REFCHAR1 24 +#define BM_UARTAPP_AUTOBAUD_REFCHAR1 0xFF000000 +#define BF_UARTAPP_AUTOBAUD_REFCHAR1(v) \ + (((v) << 24) & BM_UARTAPP_AUTOBAUD_REFCHAR1) +#define BP_UARTAPP_AUTOBAUD_REFCHAR0 16 +#define BM_UARTAPP_AUTOBAUD_REFCHAR0 0x00FF0000 +#define BF_UARTAPP_AUTOBAUD_REFCHAR0(v) \ + (((v) << 16) & BM_UARTAPP_AUTOBAUD_REFCHAR0) +#define BM_UARTAPP_AUTOBAUD_UPDATE_TX 0x00000010 +#define BM_UARTAPP_AUTOBAUD_TWO_REF_CHARS 0x00000008 +#define BM_UARTAPP_AUTOBAUD_START_WITH_RUNBIT 0x00000004 +#define BM_UARTAPP_AUTOBAUD_START_BAUD_DETECT 0x00000002 +#define BM_UARTAPP_AUTOBAUD_BAUD_DETECT_ENABLE 0x00000001 +#endif /* __ARCH_ARM___UARTAPP_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp3xxx/include/mach/regs-uartdbg.h new file mode 100644 index 000000000000..172faef91577 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-uartdbg.h @@ -0,0 +1,287 @@ +/* + * STMP UARTDBG Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___UARTDBG_H +#define __ARCH_ARM___UARTDBG_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_UARTDBG_BASE (REGS_BASE + 0x70000) +#define REGS_UARTDBG_BASE_PHYS (0x80070000) +#define REGS_UARTDBG_SIZE 0x00002000 +HW_REGISTER_0(HW_UARTDBGDR, REGS_UARTDBG_BASE, 0x00000000) +#define HW_UARTDBGDR_ADDR (REGS_UARTDBG_BASE + 0x00000000) +#define BP_UARTDBGDR_UNAVAILABLE 16 +#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGDR_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGDR_UNAVAILABLE) +#define BP_UARTDBGDR_RESERVED 12 +#define BM_UARTDBGDR_RESERVED 0x0000F000 +#define BF_UARTDBGDR_RESERVED(v) \ + (((v) << 12) & BM_UARTDBGDR_RESERVED) +#define BM_UARTDBGDR_OE 0x00000800 +#define BM_UARTDBGDR_BE 0x00000400 +#define BM_UARTDBGDR_PE 0x00000200 +#define BM_UARTDBGDR_FE 0x00000100 +#define BP_UARTDBGDR_DATA 0 +#define BM_UARTDBGDR_DATA 0x000000FF +#define BF_UARTDBGDR_DATA(v) \ + (((v) << 0) & BM_UARTDBGDR_DATA) +HW_REGISTER_0(HW_UARTDBGRSR_ECR, REGS_UARTDBG_BASE, 0x00000004) +#define HW_UARTDBGRSR_ECR_ADDR (REGS_UARTDBG_BASE + 0x00000004) +#define BP_UARTDBGRSR_ECR_UNAVAILABLE 8 +#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00 +#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \ + (((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE) +#define BP_UARTDBGRSR_ECR_EC 4 +#define BM_UARTDBGRSR_ECR_EC 0x000000F0 +#define BF_UARTDBGRSR_ECR_EC(v) \ + (((v) << 4) & BM_UARTDBGRSR_ECR_EC) +#define BM_UARTDBGRSR_ECR_OE 0x00000008 +#define BM_UARTDBGRSR_ECR_BE 0x00000004 +#define BM_UARTDBGRSR_ECR_PE 0x00000002 +#define BM_UARTDBGRSR_ECR_FE 0x00000001 +HW_REGISTER_0(HW_UARTDBGFR, REGS_UARTDBG_BASE, 0x00000018) +#define HW_UARTDBGFR_ADDR (REGS_UARTDBG_BASE + 0x00000018) +#define BP_UARTDBGFR_UNAVAILABLE 16 +#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGFR_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGFR_UNAVAILABLE) +#define BP_UARTDBGFR_RESERVED 9 +#define BM_UARTDBGFR_RESERVED 0x0000FE00 +#define BF_UARTDBGFR_RESERVED(v) \ + (((v) << 9) & BM_UARTDBGFR_RESERVED) +#define BM_UARTDBGFR_RI 0x00000100 +#define BM_UARTDBGFR_TXFE 0x00000080 +#define BM_UARTDBGFR_RXFF 0x00000040 +#define BM_UARTDBGFR_TXFF 0x00000020 +#define BM_UARTDBGFR_RXFE 0x00000010 +#define BM_UARTDBGFR_BUSY 0x00000008 +#define BM_UARTDBGFR_DCD 0x00000004 +#define BM_UARTDBGFR_DSR 0x00000002 +#define BM_UARTDBGFR_CTS 0x00000001 +HW_REGISTER_0(HW_UARTDBGILPR, REGS_UARTDBG_BASE, 0x00000020) +#define HW_UARTDBGILPR_ADDR (REGS_UARTDBG_BASE + 0x00000020) +#define BP_UARTDBGILPR_UNAVAILABLE 8 +#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00 +#define BF_UARTDBGILPR_UNAVAILABLE(v) \ + (((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE) +#define BP_UARTDBGILPR_ILPDVSR 0 +#define BM_UARTDBGILPR_ILPDVSR 0x000000FF +#define BF_UARTDBGILPR_ILPDVSR(v) \ + (((v) << 0) & BM_UARTDBGILPR_ILPDVSR) +HW_REGISTER_0(HW_UARTDBGIBRD, REGS_UARTDBG_BASE, 0x00000024) +#define HW_UARTDBGIBRD_ADDR (REGS_UARTDBG_BASE + 0x00000024) +#define BP_UARTDBGIBRD_UNAVAILABLE 16 +#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGIBRD_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE) +#define BP_UARTDBGIBRD_BAUD_DIVINT 0 +#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF +#define BF_UARTDBGIBRD_BAUD_DIVINT(v) \ + (((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT) +HW_REGISTER_0(HW_UARTDBGFBRD, REGS_UARTDBG_BASE, 0x00000028) +#define HW_UARTDBGFBRD_ADDR (REGS_UARTDBG_BASE + 0x00000028) +#define BP_UARTDBGFBRD_UNAVAILABLE 8 +#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00 +#define BF_UARTDBGFBRD_UNAVAILABLE(v) \ + (((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE) +#define BP_UARTDBGFBRD_RESERVED 6 +#define BM_UARTDBGFBRD_RESERVED 0x000000C0 +#define BF_UARTDBGFBRD_RESERVED(v) \ + (((v) << 6) & BM_UARTDBGFBRD_RESERVED) +#define BP_UARTDBGFBRD_BAUD_DIVFRAC 0 +#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F +#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v) \ + (((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC) +HW_REGISTER_0(HW_UARTDBGLCR_H, REGS_UARTDBG_BASE, 0x0000002c) +#define HW_UARTDBGLCR_H_ADDR (REGS_UARTDBG_BASE + 0x0000002c) +#define BP_UARTDBGLCR_H_UNAVAILABLE 16 +#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE) +#define BP_UARTDBGLCR_H_RESERVED 8 +#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00 +#define BF_UARTDBGLCR_H_RESERVED(v) \ + (((v) << 8) & BM_UARTDBGLCR_H_RESERVED) +#define BM_UARTDBGLCR_H_SPS 0x00000080 +#define BP_UARTDBGLCR_H_WLEN 5 +#define BM_UARTDBGLCR_H_WLEN 0x00000060 +#define BF_UARTDBGLCR_H_WLEN(v) \ + (((v) << 5) & BM_UARTDBGLCR_H_WLEN) +#define BM_UARTDBGLCR_H_FEN 0x00000010 +#define BM_UARTDBGLCR_H_STP2 0x00000008 +#define BM_UARTDBGLCR_H_EPS 0x00000004 +#define BM_UARTDBGLCR_H_PEN 0x00000002 +#define BM_UARTDBGLCR_H_BRK 0x00000001 +HW_REGISTER_0(HW_UARTDBGCR, REGS_UARTDBG_BASE, 0x00000030) +#define HW_UARTDBGCR_ADDR (REGS_UARTDBG_BASE + 0x00000030) +#define BP_UARTDBGCR_UNAVAILABLE 16 +#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGCR_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGCR_UNAVAILABLE) +#define BM_UARTDBGCR_CTSEN 0x00008000 +#define BM_UARTDBGCR_RTSEN 0x00004000 +#define BM_UARTDBGCR_OUT2 0x00002000 +#define BM_UARTDBGCR_OUT1 0x00001000 +#define BM_UARTDBGCR_RTS 0x00000800 +#define BM_UARTDBGCR_DTR 0x00000400 +#define BM_UARTDBGCR_RXE 0x00000200 +#define BM_UARTDBGCR_TXE 0x00000100 +#define BM_UARTDBGCR_LBE 0x00000080 +#define BP_UARTDBGCR_RESERVED 3 +#define BM_UARTDBGCR_RESERVED 0x00000078 +#define BF_UARTDBGCR_RESERVED(v) \ + (((v) << 3) & BM_UARTDBGCR_RESERVED) +#define BM_UARTDBGCR_SIRLP 0x00000004 +#define BM_UARTDBGCR_SIREN 0x00000002 +#define BM_UARTDBGCR_UARTEN 0x00000001 +HW_REGISTER_0(HW_UARTDBGIFLS, REGS_UARTDBG_BASE, 0x00000034) +#define HW_UARTDBGIFLS_ADDR (REGS_UARTDBG_BASE + 0x00000034) +#define BP_UARTDBGIFLS_UNAVAILABLE 16 +#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGIFLS_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE) +#define BP_UARTDBGIFLS_RESERVED 6 +#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0 +#define BF_UARTDBGIFLS_RESERVED(v) \ + (((v) << 6) & BM_UARTDBGIFLS_RESERVED) +#define BP_UARTDBGIFLS_RXIFLSEL 3 +#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038 +#define BF_UARTDBGIFLS_RXIFLSEL(v) \ + (((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL) +#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY 0x0 +#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER 0x1 +#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF 0x2 +#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3 +#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS 0x4 +#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5 0x5 +#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6 0x6 +#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7 0x7 +#define BP_UARTDBGIFLS_TXIFLSEL 0 +#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007 +#define BF_UARTDBGIFLS_TXIFLSEL(v) \ + (((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL) +#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY 0x0 +#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER 0x1 +#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF 0x2 +#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3 +#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS 0x4 +#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5 0x5 +#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6 0x6 +#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7 0x7 +HW_REGISTER_0(HW_UARTDBGIMSC, REGS_UARTDBG_BASE, 0x00000038) +#define HW_UARTDBGIMSC_ADDR (REGS_UARTDBG_BASE + 0x00000038) +#define BP_UARTDBGIMSC_UNAVAILABLE 16 +#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGIMSC_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE) +#define BP_UARTDBGIMSC_RESERVED 11 +#define BM_UARTDBGIMSC_RESERVED 0x0000F800 +#define BF_UARTDBGIMSC_RESERVED(v) \ + (((v) << 11) & BM_UARTDBGIMSC_RESERVED) +#define BM_UARTDBGIMSC_OEIM 0x00000400 +#define BM_UARTDBGIMSC_BEIM 0x00000200 +#define BM_UARTDBGIMSC_PEIM 0x00000100 +#define BM_UARTDBGIMSC_FEIM 0x00000080 +#define BM_UARTDBGIMSC_RTIM 0x00000040 +#define BM_UARTDBGIMSC_TXIM 0x00000020 +#define BM_UARTDBGIMSC_RXIM 0x00000010 +#define BM_UARTDBGIMSC_DSRMIM 0x00000008 +#define BM_UARTDBGIMSC_DCDMIM 0x00000004 +#define BM_UARTDBGIMSC_CTSMIM 0x00000002 +#define BM_UARTDBGIMSC_RIMIM 0x00000001 +HW_REGISTER_0(HW_UARTDBGRIS, REGS_UARTDBG_BASE, 0x0000003c) +#define HW_UARTDBGRIS_ADDR (REGS_UARTDBG_BASE + 0x0000003c) +#define BP_UARTDBGRIS_UNAVAILABLE 16 +#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGRIS_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE) +#define BP_UARTDBGRIS_RESERVED 11 +#define BM_UARTDBGRIS_RESERVED 0x0000F800 +#define BF_UARTDBGRIS_RESERVED(v) \ + (((v) << 11) & BM_UARTDBGRIS_RESERVED) +#define BM_UARTDBGRIS_OERIS 0x00000400 +#define BM_UARTDBGRIS_BERIS 0x00000200 +#define BM_UARTDBGRIS_PERIS 0x00000100 +#define BM_UARTDBGRIS_FERIS 0x00000080 +#define BM_UARTDBGRIS_RTRIS 0x00000040 +#define BM_UARTDBGRIS_TXRIS 0x00000020 +#define BM_UARTDBGRIS_RXRIS 0x00000010 +#define BM_UARTDBGRIS_DSRRMIS 0x00000008 +#define BM_UARTDBGRIS_DCDRMIS 0x00000004 +#define BM_UARTDBGRIS_CTSRMIS 0x00000002 +#define BM_UARTDBGRIS_RIRMIS 0x00000001 +HW_REGISTER_0(HW_UARTDBGMIS, REGS_UARTDBG_BASE, 0x00000040) +#define HW_UARTDBGMIS_ADDR (REGS_UARTDBG_BASE + 0x00000040) +#define BP_UARTDBGMIS_UNAVAILABLE 16 +#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGMIS_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE) +#define BP_UARTDBGMIS_RESERVED 11 +#define BM_UARTDBGMIS_RESERVED 0x0000F800 +#define BF_UARTDBGMIS_RESERVED(v) \ + (((v) << 11) & BM_UARTDBGMIS_RESERVED) +#define BM_UARTDBGMIS_OEMIS 0x00000400 +#define BM_UARTDBGMIS_BEMIS 0x00000200 +#define BM_UARTDBGMIS_PEMIS 0x00000100 +#define BM_UARTDBGMIS_FEMIS 0x00000080 +#define BM_UARTDBGMIS_RTMIS 0x00000040 +#define BM_UARTDBGMIS_TXMIS 0x00000020 +#define BM_UARTDBGMIS_RXMIS 0x00000010 +#define BM_UARTDBGMIS_DSRMMIS 0x00000008 +#define BM_UARTDBGMIS_DCDMMIS 0x00000004 +#define BM_UARTDBGMIS_CTSMMIS 0x00000002 +#define BM_UARTDBGMIS_RIMMIS 0x00000001 +HW_REGISTER_0(HW_UARTDBGICR, REGS_UARTDBG_BASE, 0x00000044) +#define HW_UARTDBGICR_ADDR (REGS_UARTDBG_BASE + 0x00000044) +#define BP_UARTDBGICR_UNAVAILABLE 16 +#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGICR_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGICR_UNAVAILABLE) +#define BP_UARTDBGICR_RESERVED 11 +#define BM_UARTDBGICR_RESERVED 0x0000F800 +#define BF_UARTDBGICR_RESERVED(v) \ + (((v) << 11) & BM_UARTDBGICR_RESERVED) +#define BM_UARTDBGICR_OEIC 0x00000400 +#define BM_UARTDBGICR_BEIC 0x00000200 +#define BM_UARTDBGICR_PEIC 0x00000100 +#define BM_UARTDBGICR_FEIC 0x00000080 +#define BM_UARTDBGICR_RTIC 0x00000040 +#define BM_UARTDBGICR_TXIC 0x00000020 +#define BM_UARTDBGICR_RXIC 0x00000010 +#define BM_UARTDBGICR_DSRMIC 0x00000008 +#define BM_UARTDBGICR_DCDMIC 0x00000004 +#define BM_UARTDBGICR_CTSMIC 0x00000002 +#define BM_UARTDBGICR_RIMIC 0x00000001 +HW_REGISTER_0(HW_UARTDBGDMACR, REGS_UARTDBG_BASE, 0x00000048) +#define HW_UARTDBGDMACR_ADDR (REGS_UARTDBG_BASE + 0x00000048) +#define BP_UARTDBGDMACR_UNAVAILABLE 16 +#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000 +#define BF_UARTDBGDMACR_UNAVAILABLE(v) \ + (((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE) +#define BP_UARTDBGDMACR_RESERVED 3 +#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8 +#define BF_UARTDBGDMACR_RESERVED(v) \ + (((v) << 3) & BM_UARTDBGDMACR_RESERVED) +#define BM_UARTDBGDMACR_DMAONERR 0x00000004 +#define BM_UARTDBGDMACR_TXDMAE 0x00000002 +#define BM_UARTDBGDMACR_RXDMAE 0x00000001 +#endif /* __ARCH_ARM___UARTDBG_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp3xxx/include/mach/regs-usbctrl.h new file mode 100644 index 000000000000..daf0f0c94fb3 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-usbctrl.h @@ -0,0 +1,642 @@ +/* + * STMP USBCTRL Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___USBCTRL_H +#define __ARCH_ARM___USBCTRL_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_USBCTRL_BASE (REGS_BASE + 0x80000) +#define REGS_USBCTRL_BASE_PHYS (0x80080000) +#define REGS_USBCTRL_SIZE 0x00002000 +HW_REGISTER_0(HW_USBCTRL_ID, REGS_USBCTRL_BASE, 0x00000000) +#define HW_USBCTRL_ID_ADDR (REGS_USBCTRL_BASE + 0x00000000) +#define BP_USBCTRL_ID_CIVERSION 29 +#define BM_USBCTRL_ID_CIVERSION 0xE0000000 +#define BF_USBCTRL_ID_CIVERSION(v) \ + (((v) << 29) & BM_USBCTRL_ID_CIVERSION) +#define BP_USBCTRL_ID_VERSION 25 +#define BM_USBCTRL_ID_VERSION 0x1E000000 +#define BF_USBCTRL_ID_VERSION(v) \ + (((v) << 25) & BM_USBCTRL_ID_VERSION) +#define BP_USBCTRL_ID_REVISION 21 +#define BM_USBCTRL_ID_REVISION 0x01E00000 +#define BF_USBCTRL_ID_REVISION(v) \ + (((v) << 21) & BM_USBCTRL_ID_REVISION) +#define BP_USBCTRL_ID_TAG 16 +#define BM_USBCTRL_ID_TAG 0x001F0000 +#define BF_USBCTRL_ID_TAG(v) \ + (((v) << 16) & BM_USBCTRL_ID_TAG) +#define BP_USBCTRL_ID_NID 8 +#define BM_USBCTRL_ID_NID 0x00003F00 +#define BF_USBCTRL_ID_NID(v) \ + (((v) << 8) & BM_USBCTRL_ID_NID) +#define BP_USBCTRL_ID_ID 0 +#define BM_USBCTRL_ID_ID 0x0000003F +#define BF_USBCTRL_ID_ID(v) \ + (((v) << 0) & BM_USBCTRL_ID_ID) +HW_REGISTER_0(HW_USBCTRL_HWGENERAL, REGS_USBCTRL_BASE, 0x00000004) +#define HW_USBCTRL_HWGENERAL_ADDR (REGS_USBCTRL_BASE + 0x00000004) +#define BP_USBCTRL_HWGENERAL_SM 9 +#define BM_USBCTRL_HWGENERAL_SM 0x00000600 +#define BF_USBCTRL_HWGENERAL_SM(v) \ + (((v) << 9) & BM_USBCTRL_HWGENERAL_SM) +#define BP_USBCTRL_HWGENERAL_PHYM 6 +#define BM_USBCTRL_HWGENERAL_PHYM 0x000001C0 +#define BF_USBCTRL_HWGENERAL_PHYM(v) \ + (((v) << 6) & BM_USBCTRL_HWGENERAL_PHYM) +#define BP_USBCTRL_HWGENERAL_PHYW 4 +#define BM_USBCTRL_HWGENERAL_PHYW 0x00000030 +#define BF_USBCTRL_HWGENERAL_PHYW(v) \ + (((v) << 4) & BM_USBCTRL_HWGENERAL_PHYW) +#define BM_USBCTRL_HWGENERAL_BWT 0x00000008 +#define BP_USBCTRL_HWGENERAL_CLKC 1 +#define BM_USBCTRL_HWGENERAL_CLKC 0x00000006 +#define BF_USBCTRL_HWGENERAL_CLKC(v) \ + (((v) << 1) & BM_USBCTRL_HWGENERAL_CLKC) +#define BM_USBCTRL_HWGENERAL_RT 0x00000001 +HW_REGISTER_0(HW_USBCTRL_HWHOST, REGS_USBCTRL_BASE, 0x00000008) +#define HW_USBCTRL_HWHOST_ADDR (REGS_USBCTRL_BASE + 0x00000008) +#define BP_USBCTRL_HWHOST_TTPER 24 +#define BM_USBCTRL_HWHOST_TTPER 0xFF000000 +#define BF_USBCTRL_HWHOST_TTPER(v) \ + (((v) << 24) & BM_USBCTRL_HWHOST_TTPER) +#define BP_USBCTRL_HWHOST_TTASY 16 +#define BM_USBCTRL_HWHOST_TTASY 0x00FF0000 +#define BF_USBCTRL_HWHOST_TTASY(v) \ + (((v) << 16) & BM_USBCTRL_HWHOST_TTASY) +#define BP_USBCTRL_HWHOST_NPORT 1 +#define BM_USBCTRL_HWHOST_NPORT 0x0000000E +#define BF_USBCTRL_HWHOST_NPORT(v) \ + (((v) << 1) & BM_USBCTRL_HWHOST_NPORT) +#define BM_USBCTRL_HWHOST_HC 0x00000001 +HW_REGISTER_0(HW_USBCTRL_HWDEVICE, REGS_USBCTRL_BASE, 0x0000000c) +#define HW_USBCTRL_HWDEVICE_ADDR (REGS_USBCTRL_BASE + 0x0000000c) +#define BP_USBCTRL_HWDEVICE_DEVEP 1 +#define BM_USBCTRL_HWDEVICE_DEVEP 0x0000003E +#define BF_USBCTRL_HWDEVICE_DEVEP(v) \ + (((v) << 1) & BM_USBCTRL_HWDEVICE_DEVEP) +#define BM_USBCTRL_HWDEVICE_DC 0x00000001 +HW_REGISTER_0(HW_USBCTRL_HWTXBUF, REGS_USBCTRL_BASE, 0x00000010) +#define HW_USBCTRL_HWTXBUF_ADDR (REGS_USBCTRL_BASE + 0x00000010) +#define BM_USBCTRL_HWTXBUF_TXLCR 0x80000000 +#define BP_USBCTRL_HWTXBUF_TXCHANADD 16 +#define BM_USBCTRL_HWTXBUF_TXCHANADD 0x00FF0000 +#define BF_USBCTRL_HWTXBUF_TXCHANADD(v) \ + (((v) << 16) & BM_USBCTRL_HWTXBUF_TXCHANADD) +#define BP_USBCTRL_HWTXBUF_TXADD 8 +#define BM_USBCTRL_HWTXBUF_TXADD 0x0000FF00 +#define BF_USBCTRL_HWTXBUF_TXADD(v) \ + (((v) << 8) & BM_USBCTRL_HWTXBUF_TXADD) +#define BP_USBCTRL_HWTXBUF_TXBURST 0 +#define BM_USBCTRL_HWTXBUF_TXBURST 0x000000FF +#define BF_USBCTRL_HWTXBUF_TXBURST(v) \ + (((v) << 0) & BM_USBCTRL_HWTXBUF_TXBURST) +HW_REGISTER_0(HW_USBCTRL_HWRXBUF, REGS_USBCTRL_BASE, 0x00000014) +#define HW_USBCTRL_HWRXBUF_ADDR (REGS_USBCTRL_BASE + 0x00000014) +#define BP_USBCTRL_HWRXBUF_RXADD 8 +#define BM_USBCTRL_HWRXBUF_RXADD 0x0000FF00 +#define BF_USBCTRL_HWRXBUF_RXADD(v) \ + (((v) << 8) & BM_USBCTRL_HWRXBUF_RXADD) +#define BP_USBCTRL_HWRXBUF_RXBURST 0 +#define BM_USBCTRL_HWRXBUF_RXBURST 0x000000FF +#define BF_USBCTRL_HWRXBUF_RXBURST(v) \ + (((v) << 0) & BM_USBCTRL_HWRXBUF_RXBURST) +HW_REGISTER_0(HW_USBCTRL_GPTIMER0LD, REGS_USBCTRL_BASE, 0x00000080) +#define HW_USBCTRL_GPTIMER0LD_ADDR (REGS_USBCTRL_BASE + 0x00000080) +#define BP_USBCTRL_GPTIMER0LD_GPTLD 0 +#define BM_USBCTRL_GPTIMER0LD_GPTLD 0x00FFFFFF +#define BF_USBCTRL_GPTIMER0LD_GPTLD(v) \ + (((v) << 0) & BM_USBCTRL_GPTIMER0LD_GPTLD) +HW_REGISTER_0(HW_USBCTRL_GPTIMER0CTRL, REGS_USBCTRL_BASE, 0x00000084) +#define HW_USBCTRL_GPTIMER0CTRL_ADDR (REGS_USBCTRL_BASE + 0x00000084) +#define BM_USBCTRL_GPTIMER0CTRL_GPTRUN 0x80000000 +#define BV_USBCTRL_GPTIMER0CTRL_GPTRUN__STOP 0 +#define BV_USBCTRL_GPTIMER0CTRL_GPTRUN__RUN 1 +#define BM_USBCTRL_GPTIMER0CTRL_GPTRST 0x40000000 +#define BV_USBCTRL_GPTIMER0CTRL_GPTRST__NOACTION 0 +#define BV_USBCTRL_GPTIMER0CTRL_GPTRST__LOADCOUNTER 1 +#define BM_USBCTRL_GPTIMER0CTRL_GPTMODE 0x01000000 +#define BV_USBCTRL_GPTIMER0CTRL_GPTMODE__ONESHOT 0 +#define BV_USBCTRL_GPTIMER0CTRL_GPTMODE__REPEAT 1 +#define BP_USBCTRL_GPTIMER0CTRL_GPTCNT 0 +#define BM_USBCTRL_GPTIMER0CTRL_GPTCNT 0x00FFFFFF +#define BF_USBCTRL_GPTIMER0CTRL_GPTCNT(v) \ + (((v) << 0) & BM_USBCTRL_GPTIMER0CTRL_GPTCNT) +HW_REGISTER_0(HW_USBCTRL_GPTIMER1LD, REGS_USBCTRL_BASE, 0x00000088) +#define HW_USBCTRL_GPTIMER1LD_ADDR (REGS_USBCTRL_BASE + 0x00000088) +#define BP_USBCTRL_GPTIMER1LD_GPTLD 0 +#define BM_USBCTRL_GPTIMER1LD_GPTLD 0x00FFFFFF +#define BF_USBCTRL_GPTIMER1LD_GPTLD(v) \ + (((v) << 0) & BM_USBCTRL_GPTIMER1LD_GPTLD) +HW_REGISTER_0(HW_USBCTRL_GPTIMER1CTRL, REGS_USBCTRL_BASE, 0x0000008c) +#define HW_USBCTRL_GPTIMER1CTRL_ADDR (REGS_USBCTRL_BASE + 0x0000008c) +#define BM_USBCTRL_GPTIMER1CTRL_GPTRUN 0x80000000 +#define BV_USBCTRL_GPTIMER1CTRL_GPTRUN__STOP 0 +#define BV_USBCTRL_GPTIMER1CTRL_GPTRUN__RUN 1 +#define BM_USBCTRL_GPTIMER1CTRL_GPTRST 0x40000000 +#define BV_USBCTRL_GPTIMER1CTRL_GPTRST__NOACTION 0 +#define BV_USBCTRL_GPTIMER1CTRL_GPTRST__LOADCOUNTER 1 +#define BM_USBCTRL_GPTIMER1CTRL_GPTMODE 0x01000000 +#define BV_USBCTRL_GPTIMER1CTRL_GPTMODE__ONESHOT 0 +#define BV_USBCTRL_GPTIMER1CTRL_GPTMODE__REPEAT 1 +#define BP_USBCTRL_GPTIMER1CTRL_GPTCNT 0 +#define BM_USBCTRL_GPTIMER1CTRL_GPTCNT 0x00FFFFFF +#define BF_USBCTRL_GPTIMER1CTRL_GPTCNT(v) \ + (((v) << 0) & BM_USBCTRL_GPTIMER1CTRL_GPTCNT) +HW_REGISTER_0(HW_USBCTRL_SBUSCFG, REGS_USBCTRL_BASE, 0x00000090) +#define HW_USBCTRL_SBUSCFG_ADDR (REGS_USBCTRL_BASE + 0x00000090) +#define BP_USBCTRL_SBUSCFG_AHBBRST 0 +#define BM_USBCTRL_SBUSCFG_AHBBRST 0x00000007 +#define BF_USBCTRL_SBUSCFG_AHBBRST(v) \ + (((v) << 0) & BM_USBCTRL_SBUSCFG_AHBBRST) +#define BV_USBCTRL_SBUSCFG_AHBBRST__U_INCR 0x0 +#define BV_USBCTRL_SBUSCFG_AHBBRST__S_INCR4 0x1 +#define BV_USBCTRL_SBUSCFG_AHBBRST__S_INCR8 0x2 +#define BV_USBCTRL_SBUSCFG_AHBBRST__S_INCR16 0x3 +#define BV_USBCTRL_SBUSCFG_AHBBRST__RESERVED 0x4 +#define BV_USBCTRL_SBUSCFG_AHBBRST__U_INCR4 0x5 +#define BV_USBCTRL_SBUSCFG_AHBBRST__U_INCR8 0x6 +#define BV_USBCTRL_SBUSCFG_AHBBRST__U_INCR16 0x7 +HW_REGISTER_0(HW_USBCTRL_CAPLENGTH, REGS_USBCTRL_BASE, 0x00000100) +#define HW_USBCTRL_CAPLENGTH_ADDR (REGS_USBCTRL_BASE + 0x00000100) +#define BP_USBCTRL_CAPLENGTH_HCIVERSION 16 +#define BM_USBCTRL_CAPLENGTH_HCIVERSION 0xFFFF0000 +#define BF_USBCTRL_CAPLENGTH_HCIVERSION(v) \ + (((v) << 16) & BM_USBCTRL_CAPLENGTH_HCIVERSION) +#define BP_USBCTRL_CAPLENGTH_CAPLENGTH 0 +#define BM_USBCTRL_CAPLENGTH_CAPLENGTH 0x000000FF +#define BF_USBCTRL_CAPLENGTH_CAPLENGTH(v) \ + (((v) << 0) & BM_USBCTRL_CAPLENGTH_CAPLENGTH) +HW_REGISTER_0(HW_USBCTRL_HCSPARAMS, REGS_USBCTRL_BASE, 0x00000104) +#define HW_USBCTRL_HCSPARAMS_ADDR (REGS_USBCTRL_BASE + 0x00000104) +#define BP_USBCTRL_HCSPARAMS_N_TT 24 +#define BM_USBCTRL_HCSPARAMS_N_TT 0x0F000000 +#define BF_USBCTRL_HCSPARAMS_N_TT(v) \ + (((v) << 24) & BM_USBCTRL_HCSPARAMS_N_TT) +#define BP_USBCTRL_HCSPARAMS_N_PTT 20 +#define BM_USBCTRL_HCSPARAMS_N_PTT 0x00F00000 +#define BF_USBCTRL_HCSPARAMS_N_PTT(v) \ + (((v) << 20) & BM_USBCTRL_HCSPARAMS_N_PTT) +#define BM_USBCTRL_HCSPARAMS_PI 0x00010000 +#define BP_USBCTRL_HCSPARAMS_N_CC 12 +#define BM_USBCTRL_HCSPARAMS_N_CC 0x0000F000 +#define BF_USBCTRL_HCSPARAMS_N_CC(v) \ + (((v) << 12) & BM_USBCTRL_HCSPARAMS_N_CC) +#define BP_USBCTRL_HCSPARAMS_N_PCC 8 +#define BM_USBCTRL_HCSPARAMS_N_PCC 0x00000F00 +#define BF_USBCTRL_HCSPARAMS_N_PCC(v) \ + (((v) << 8) & BM_USBCTRL_HCSPARAMS_N_PCC) +#define BM_USBCTRL_HCSPARAMS_PPC 0x00000010 +#define BP_USBCTRL_HCSPARAMS_N_PORTS 0 +#define BM_USBCTRL_HCSPARAMS_N_PORTS 0x0000000F +#define BF_USBCTRL_HCSPARAMS_N_PORTS(v) \ + (((v) << 0) & BM_USBCTRL_HCSPARAMS_N_PORTS) +HW_REGISTER_0(HW_USBCTRL_HCCPARAMS, REGS_USBCTRL_BASE, 0x00000108) +#define HW_USBCTRL_HCCPARAMS_ADDR (REGS_USBCTRL_BASE + 0x00000108) +#define BP_USBCTRL_HCCPARAMS_EECP 8 +#define BM_USBCTRL_HCCPARAMS_EECP 0x0000FF00 +#define BF_USBCTRL_HCCPARAMS_EECP(v) \ + (((v) << 8) & BM_USBCTRL_HCCPARAMS_EECP) +#define BP_USBCTRL_HCCPARAMS_IST 4 +#define BM_USBCTRL_HCCPARAMS_IST 0x000000F0 +#define BF_USBCTRL_HCCPARAMS_IST(v) \ + (((v) << 4) & BM_USBCTRL_HCCPARAMS_IST) +#define BM_USBCTRL_HCCPARAMS_ASP 0x00000004 +#define BM_USBCTRL_HCCPARAMS_PFL 0x00000002 +#define BM_USBCTRL_HCCPARAMS_ADC 0x00000001 +HW_REGISTER_0(HW_USBCTRL_DCIVERSION, REGS_USBCTRL_BASE, 0x00000120) +#define HW_USBCTRL_DCIVERSION_ADDR (REGS_USBCTRL_BASE + 0x00000120) +#define BP_USBCTRL_DCIVERSION_DCIVERSION 0 +#define BM_USBCTRL_DCIVERSION_DCIVERSION 0x0000FFFF +#define BF_USBCTRL_DCIVERSION_DCIVERSION(v) \ + (((v) << 0) & BM_USBCTRL_DCIVERSION_DCIVERSION) +HW_REGISTER_0(HW_USBCTRL_DCCPARAMS, REGS_USBCTRL_BASE, 0x00000124) +#define HW_USBCTRL_DCCPARAMS_ADDR (REGS_USBCTRL_BASE + 0x00000124) +#define BM_USBCTRL_DCCPARAMS_HC 0x00000100 +#define BM_USBCTRL_DCCPARAMS_DC 0x00000080 +#define BP_USBCTRL_DCCPARAMS_DEN 0 +#define BM_USBCTRL_DCCPARAMS_DEN 0x0000001F +#define BF_USBCTRL_DCCPARAMS_DEN(v) \ + (((v) << 0) & BM_USBCTRL_DCCPARAMS_DEN) +HW_REGISTER_0(HW_USBCTRL_USBCMD, REGS_USBCTRL_BASE, 0x00000140) +#define HW_USBCTRL_USBCMD_ADDR (REGS_USBCTRL_BASE + 0x00000140) +#define BP_USBCTRL_USBCMD_ITC 16 +#define BM_USBCTRL_USBCMD_ITC 0x00FF0000 +#define BF_USBCTRL_USBCMD_ITC(v) \ + (((v) << 16) & BM_USBCTRL_USBCMD_ITC) +#define BV_USBCTRL_USBCMD_ITC__IMM 0x0 +#define BV_USBCTRL_USBCMD_ITC__1_MICROFRAME 0x1 +#define BV_USBCTRL_USBCMD_ITC__2_MICROFRAME 0x2 +#define BV_USBCTRL_USBCMD_ITC__4_MICROFRAME 0x4 +#define BV_USBCTRL_USBCMD_ITC__8_MICROFRAME 0x8 +#define BV_USBCTRL_USBCMD_ITC__16_MICROFRAME 0x10 +#define BV_USBCTRL_USBCMD_ITC__32_MICROFRAME 0x20 +#define BV_USBCTRL_USBCMD_ITC__64_MICROFRAME 0x40 +#define BM_USBCTRL_USBCMD_FS2 0x00008000 +#define BM_USBCTRL_USBCMD_ATDTW 0x00004000 +#define BM_USBCTRL_USBCMD_SUTW 0x00002000 +#define BM_USBCTRL_USBCMD_ASPE 0x00000800 +#define BP_USBCTRL_USBCMD_ASP 8 +#define BM_USBCTRL_USBCMD_ASP 0x00000300 +#define BF_USBCTRL_USBCMD_ASP(v) \ + (((v) << 8) & BM_USBCTRL_USBCMD_ASP) +#define BM_USBCTRL_USBCMD_LR 0x00000080 +#define BM_USBCTRL_USBCMD_IAA 0x00000040 +#define BM_USBCTRL_USBCMD_ASE 0x00000020 +#define BM_USBCTRL_USBCMD_PSE 0x00000010 +#define BM_USBCTRL_USBCMD_FS1 0x00000008 +#define BM_USBCTRL_USBCMD_FS0 0x00000004 +#define BM_USBCTRL_USBCMD_RST 0x00000002 +#define BM_USBCTRL_USBCMD_RS 0x00000001 +HW_REGISTER_0(HW_USBCTRL_USBSTS, REGS_USBCTRL_BASE, 0x00000144) +#define HW_USBCTRL_USBSTS_ADDR (REGS_USBCTRL_BASE + 0x00000144) +#define BM_USBCTRL_USBSTS_TI1 0x02000000 +#define BM_USBCTRL_USBSTS_TI0 0x01000000 +#define BM_USBCTRL_USBSTS_UPI 0x00080000 +#define BM_USBCTRL_USBSTS_UAI 0x00040000 +#define BM_USBCTRL_USBSTS_NAKI 0x00010000 +#define BM_USBCTRL_USBSTS_AS 0x00008000 +#define BM_USBCTRL_USBSTS_PS 0x00004000 +#define BM_USBCTRL_USBSTS_RCL 0x00002000 +#define BM_USBCTRL_USBSTS_HCH 0x00001000 +#define BM_USBCTRL_USBSTS_ULPII 0x00000400 +#define BM_USBCTRL_USBSTS_SLI 0x00000100 +#define BM_USBCTRL_USBSTS_SRI 0x00000080 +#define BM_USBCTRL_USBSTS_URI 0x00000040 +#define BM_USBCTRL_USBSTS_AAI 0x00000020 +#define BM_USBCTRL_USBSTS_SEI 0x00000010 +#define BM_USBCTRL_USBSTS_FRI 0x00000008 +#define BM_USBCTRL_USBSTS_PCI 0x00000004 +#define BM_USBCTRL_USBSTS_UEI 0x00000002 +#define BM_USBCTRL_USBSTS_UI 0x00000001 +HW_REGISTER_0(HW_USBCTRL_USBINTR, REGS_USBCTRL_BASE, 0x00000148) +#define HW_USBCTRL_USBINTR_ADDR (REGS_USBCTRL_BASE + 0x00000148) +#define BM_USBCTRL_USBINTR_TIE1 0x02000000 +#define BM_USBCTRL_USBINTR_TIE0 0x01000000 +#define BM_USBCTRL_USBINTR_UPIE 0x00080000 +#define BM_USBCTRL_USBINTR_UAIE 0x00040000 +#define BM_USBCTRL_USBINTR_NAKE 0x00010000 +#define BM_USBCTRL_USBINTR_ULPIE 0x00000400 +#define BM_USBCTRL_USBINTR_SLE 0x00000100 +#define BM_USBCTRL_USBINTR_SRE 0x00000080 +#define BM_USBCTRL_USBINTR_URE 0x00000040 +#define BM_USBCTRL_USBINTR_AAE 0x00000020 +#define BM_USBCTRL_USBINTR_SEE 0x00000010 +#define BM_USBCTRL_USBINTR_FRE 0x00000008 +#define BM_USBCTRL_USBINTR_PCE 0x00000004 +#define BM_USBCTRL_USBINTR_UEE 0x00000002 +#define BM_USBCTRL_USBINTR_UE 0x00000001 +HW_REGISTER_0(HW_USBCTRL_FRINDEX, REGS_USBCTRL_BASE, 0x0000014c) +#define HW_USBCTRL_FRINDEX_ADDR (REGS_USBCTRL_BASE + 0x0000014c) +#define BP_USBCTRL_FRINDEX_FRINDEX 3 +#define BM_USBCTRL_FRINDEX_FRINDEX 0x00003FF8 +#define BF_USBCTRL_FRINDEX_FRINDEX(v) \ + (((v) << 3) & BM_USBCTRL_FRINDEX_FRINDEX) +#define BV_USBCTRL_FRINDEX_FRINDEX__N_12 12 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_11 11 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_10 10 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_9 9 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_8 8 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_7 7 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_6 6 +#define BV_USBCTRL_FRINDEX_FRINDEX__N_5 5 +#define BP_USBCTRL_FRINDEX_UINDEX 0 +#define BM_USBCTRL_FRINDEX_UINDEX 0x00000007 +#define BF_USBCTRL_FRINDEX_UINDEX(v) \ + (((v) << 0) & BM_USBCTRL_FRINDEX_UINDEX) +HW_REGISTER_0(HW_USBCTRL_PERIODICLISTBASE, REGS_USBCTRL_BASE, 0x00000154) +#define HW_USBCTRL_PERIODICLISTBASE_ADDR (REGS_USBCTRL_BASE + 0x00000154) +#define BP_USBCTRL_PERIODICLISTBASE_PERBASE 12 +#define BM_USBCTRL_PERIODICLISTBASE_PERBASE 0xFFFFF000 +#define BF_USBCTRL_PERIODICLISTBASE_PERBASE(v) \ + (((v) << 12) & BM_USBCTRL_PERIODICLISTBASE_PERBASE) +HW_REGISTER_0(HW_USBCTRL_DEVICEADDR, REGS_USBCTRL_BASE, 0x00000154) +#define HW_USBCTRL_DEVICEADDR_ADDR (REGS_USBCTRL_BASE + 0x00000154) +#define BP_USBCTRL_DEVICEADDR_USBADR 25 +#define BM_USBCTRL_DEVICEADDR_USBADR 0xFE000000 +#define BF_USBCTRL_DEVICEADDR_USBADR(v) \ + (((v) << 25) & BM_USBCTRL_DEVICEADDR_USBADR) +#define BM_USBCTRL_DEVICEADDR_USBADRA 0x01000000 +HW_REGISTER_0(HW_USBCTRL_ASYNCLISTADDR, REGS_USBCTRL_BASE, 0x00000158) +#define HW_USBCTRL_ASYNCLISTADDR_ADDR (REGS_USBCTRL_BASE + 0x00000158) +#define BP_USBCTRL_ASYNCLISTADDR_ASYBASE 5 +#define BM_USBCTRL_ASYNCLISTADDR_ASYBASE 0xFFFFFFE0 +#define BF_USBCTRL_ASYNCLISTADDR_ASYBASE(v) \ + (((v) << 5) & BM_USBCTRL_ASYNCLISTADDR_ASYBASE) +HW_REGISTER_0(HW_USBCTRL_ENDPOINTLISTADDR, REGS_USBCTRL_BASE, 0x00000158) +#define HW_USBCTRL_ENDPOINTLISTADDR_ADDR (REGS_USBCTRL_BASE + 0x00000158) +#define BP_USBCTRL_ENDPOINTLISTADDR_EPBASE 11 +#define BM_USBCTRL_ENDPOINTLISTADDR_EPBASE 0xFFFFF800 +#define BF_USBCTRL_ENDPOINTLISTADDR_EPBASE(v) \ + (((v) << 11) & BM_USBCTRL_ENDPOINTLISTADDR_EPBASE) +HW_REGISTER_0(HW_USBCTRL_TTCTRL, REGS_USBCTRL_BASE, 0x0000015c) +#define HW_USBCTRL_TTCTRL_ADDR (REGS_USBCTRL_BASE + 0x0000015c) +#define BP_USBCTRL_TTCTRL_TTHA 24 +#define BM_USBCTRL_TTCTRL_TTHA 0x7F000000 +#define BF_USBCTRL_TTCTRL_TTHA(v) \ + (((v) << 24) & BM_USBCTRL_TTCTRL_TTHA) +HW_REGISTER_0(HW_USBCTRL_BURSTSIZE, REGS_USBCTRL_BASE, 0x00000160) +#define HW_USBCTRL_BURSTSIZE_ADDR (REGS_USBCTRL_BASE + 0x00000160) +#define BP_USBCTRL_BURSTSIZE_TXPBURST 8 +#define BM_USBCTRL_BURSTSIZE_TXPBURST 0x0000FF00 +#define BF_USBCTRL_BURSTSIZE_TXPBURST(v) \ + (((v) << 8) & BM_USBCTRL_BURSTSIZE_TXPBURST) +#define BP_USBCTRL_BURSTSIZE_RXPBURST 0 +#define BM_USBCTRL_BURSTSIZE_RXPBURST 0x000000FF +#define BF_USBCTRL_BURSTSIZE_RXPBURST(v) \ + (((v) << 0) & BM_USBCTRL_BURSTSIZE_RXPBURST) +HW_REGISTER_0(HW_USBCTRL_TXFILLTUNING, REGS_USBCTRL_BASE, 0x00000164) +#define HW_USBCTRL_TXFILLTUNING_ADDR (REGS_USBCTRL_BASE + 0x00000164) +#define BP_USBCTRL_TXFILLTUNING_TXFIFOTHRES 16 +#define BM_USBCTRL_TXFILLTUNING_TXFIFOTHRES 0x003F0000 +#define BF_USBCTRL_TXFILLTUNING_TXFIFOTHRES(v) \ + (((v) << 16) & BM_USBCTRL_TXFILLTUNING_TXFIFOTHRES) +#define BP_USBCTRL_TXFILLTUNING_TXSCHEALTH 8 +#define BM_USBCTRL_TXFILLTUNING_TXSCHEALTH 0x00001F00 +#define BF_USBCTRL_TXFILLTUNING_TXSCHEALTH(v) \ + (((v) << 8) & BM_USBCTRL_TXFILLTUNING_TXSCHEALTH) +#define BP_USBCTRL_TXFILLTUNING_TXSCHOH 0 +#define BM_USBCTRL_TXFILLTUNING_TXSCHOH 0x0000007F +#define BF_USBCTRL_TXFILLTUNING_TXSCHOH(v) \ + (((v) << 0) & BM_USBCTRL_TXFILLTUNING_TXSCHOH) +HW_REGISTER_0(HW_USBCTRL_IC_USB, REGS_USBCTRL_BASE, 0x0000016c) +#define HW_USBCTRL_IC_USB_ADDR (REGS_USBCTRL_BASE + 0x0000016c) +#define BM_USBCTRL_IC_USB_IC_ENABLE 0x00000008 +#define BP_USBCTRL_IC_USB_IC_VDD 0 +#define BM_USBCTRL_IC_USB_IC_VDD 0x00000007 +#define BF_USBCTRL_IC_USB_IC_VDD(v) \ + (((v) << 0) & BM_USBCTRL_IC_USB_IC_VDD) +#define BV_USBCTRL_IC_USB_IC_VDD__VOLTAGE_NONE 0x0 +#define BV_USBCTRL_IC_USB_IC_VDD__VOLTAGE_1_0 0x1 +#define BV_USBCTRL_IC_USB_IC_VDD__VOLTAGE_1_2 0x2 +#define BV_USBCTRL_IC_USB_IC_VDD__VOLTAGE_1_5 0x3 +#define BV_USBCTRL_IC_USB_IC_VDD__VOLTAGE_1_8 0x4 +#define BV_USBCTRL_IC_USB_IC_VDD__VOLTAGE_3_0 0x5 +#define BV_USBCTRL_IC_USB_IC_VDD__RESERVED0 0x6 +#define BV_USBCTRL_IC_USB_IC_VDD__RESERVED1 0x7 +HW_REGISTER_0(HW_USBCTRL_ULPI, REGS_USBCTRL_BASE, 0x00000170) +#define HW_USBCTRL_ULPI_ADDR (REGS_USBCTRL_BASE + 0x00000170) +#define BM_USBCTRL_ULPI_ULPIWU 0x80000000 +#define BM_USBCTRL_ULPI_ULPIRUN 0x40000000 +#define BM_USBCTRL_ULPI_ULPIRW 0x20000000 +#define BM_USBCTRL_ULPI_ULPISS 0x08000000 +#define BP_USBCTRL_ULPI_ULPIPORT 24 +#define BM_USBCTRL_ULPI_ULPIPORT 0x07000000 +#define BF_USBCTRL_ULPI_ULPIPORT(v) \ + (((v) << 24) & BM_USBCTRL_ULPI_ULPIPORT) +#define BP_USBCTRL_ULPI_ULPIADDR 16 +#define BM_USBCTRL_ULPI_ULPIADDR 0x00FF0000 +#define BF_USBCTRL_ULPI_ULPIADDR(v) \ + (((v) << 16) & BM_USBCTRL_ULPI_ULPIADDR) +#define BP_USBCTRL_ULPI_ULPIDATRD 8 +#define BM_USBCTRL_ULPI_ULPIDATRD 0x0000FF00 +#define BF_USBCTRL_ULPI_ULPIDATRD(v) \ + (((v) << 8) & BM_USBCTRL_ULPI_ULPIDATRD) +#define BP_USBCTRL_ULPI_ULPIDATWR 0 +#define BM_USBCTRL_ULPI_ULPIDATWR 0x000000FF +#define BF_USBCTRL_ULPI_ULPIDATWR(v) \ + (((v) << 0) & BM_USBCTRL_ULPI_ULPIDATWR) +HW_REGISTER_0(HW_USBCTRL_ENDPTNAK, REGS_USBCTRL_BASE, 0x00000178) +#define HW_USBCTRL_ENDPTNAK_ADDR (REGS_USBCTRL_BASE + 0x00000178) +#define BP_USBCTRL_ENDPTNAK_EPTN 16 +#define BM_USBCTRL_ENDPTNAK_EPTN 0x001F0000 +#define BF_USBCTRL_ENDPTNAK_EPTN(v) \ + (((v) << 16) & BM_USBCTRL_ENDPTNAK_EPTN) +#define BP_USBCTRL_ENDPTNAK_EPRN 0 +#define BM_USBCTRL_ENDPTNAK_EPRN 0x0000001F +#define BF_USBCTRL_ENDPTNAK_EPRN(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTNAK_EPRN) +HW_REGISTER_0(HW_USBCTRL_ENDPTNAKEN, REGS_USBCTRL_BASE, 0x0000017c) +#define HW_USBCTRL_ENDPTNAKEN_ADDR (REGS_USBCTRL_BASE + 0x0000017c) +#define BP_USBCTRL_ENDPTNAKEN_EPTNE 16 +#define BM_USBCTRL_ENDPTNAKEN_EPTNE 0x001F0000 +#define BF_USBCTRL_ENDPTNAKEN_EPTNE(v) \ + (((v) << 16) & BM_USBCTRL_ENDPTNAKEN_EPTNE) +#define BP_USBCTRL_ENDPTNAKEN_EPRNE 0 +#define BM_USBCTRL_ENDPTNAKEN_EPRNE 0x0000001F +#define BF_USBCTRL_ENDPTNAKEN_EPRNE(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTNAKEN_EPRNE) +HW_REGISTER_0(HW_USBCTRL_PORTSC1, REGS_USBCTRL_BASE, 0x00000184) +#define HW_USBCTRL_PORTSC1_ADDR (REGS_USBCTRL_BASE + 0x00000184) +#define BP_USBCTRL_PORTSC1_PTS 30 +#define BM_USBCTRL_PORTSC1_PTS 0xC0000000 +#define BF_USBCTRL_PORTSC1_PTS(v) \ + (((v) << 30) & BM_USBCTRL_PORTSC1_PTS) +#define BV_USBCTRL_PORTSC1_PTS__UTMI 0 +#define BV_USBCTRL_PORTSC1_PTS__PHIL 1 +#define BV_USBCTRL_PORTSC1_PTS__ULPI 2 +#define BV_USBCTRL_PORTSC1_PTS__SERIAL 3 +#define BM_USBCTRL_PORTSC1_STS 0x20000000 +#define BM_USBCTRL_PORTSC1_PTW 0x10000000 +#define BP_USBCTRL_PORTSC1_PSPD 26 +#define BM_USBCTRL_PORTSC1_PSPD 0x0C000000 +#define BF_USBCTRL_PORTSC1_PSPD(v) \ + (((v) << 26) & BM_USBCTRL_PORTSC1_PSPD) +#define BV_USBCTRL_PORTSC1_PSPD__FULL 0 +#define BV_USBCTRL_PORTSC1_PSPD__LOW 1 +#define BV_USBCTRL_PORTSC1_PSPD__HIGH 2 +#define BM_USBCTRL_PORTSC1_SRT 0x02000000 +#define BM_USBCTRL_PORTSC1_PFSC 0x01000000 +#define BM_USBCTRL_PORTSC1_PHCD 0x00800000 +#define BM_USBCTRL_PORTSC1_WKOC 0x00400000 +#define BM_USBCTRL_PORTSC1_WKDS 0x00200000 +#define BM_USBCTRL_PORTSC1_WKCN 0x00100000 +#define BP_USBCTRL_PORTSC1_PTC 16 +#define BM_USBCTRL_PORTSC1_PTC 0x000F0000 +#define BF_USBCTRL_PORTSC1_PTC(v) \ + (((v) << 16) & BM_USBCTRL_PORTSC1_PTC) +#define BV_USBCTRL_PORTSC1_PTC__TEST_DISABLE 0 +#define BV_USBCTRL_PORTSC1_PTC__TEST_J_STATE 1 +#define BV_USBCTRL_PORTSC1_PTC__TEST_K_STATE 2 +#define BV_USBCTRL_PORTSC1_PTC__TEST_J_SE0_NAK 3 +#define BV_USBCTRL_PORTSC1_PTC__TEST_PACKET 4 +#define BV_USBCTRL_PORTSC1_PTC__TEST_FORCE_ENABLE_HS 5 +#define BV_USBCTRL_PORTSC1_PTC__TEST_FORCE_ENABLE_FS 6 +#define BV_USBCTRL_PORTSC1_PTC__TEST_FORCE_ENABLE_LS 7 +#define BP_USBCTRL_PORTSC1_PIC 14 +#define BM_USBCTRL_PORTSC1_PIC 0x0000C000 +#define BF_USBCTRL_PORTSC1_PIC(v) \ + (((v) << 14) & BM_USBCTRL_PORTSC1_PIC) +#define BV_USBCTRL_PORTSC1_PIC__OFF 0 +#define BV_USBCTRL_PORTSC1_PIC__AMBER 1 +#define BV_USBCTRL_PORTSC1_PIC__GREEN 2 +#define BV_USBCTRL_PORTSC1_PIC__UNDEF 3 +#define BM_USBCTRL_PORTSC1_PO 0x00002000 +#define BM_USBCTRL_PORTSC1_PP 0x00001000 +#define BP_USBCTRL_PORTSC1_LS 10 +#define BM_USBCTRL_PORTSC1_LS 0x00000C00 +#define BF_USBCTRL_PORTSC1_LS(v) \ + (((v) << 10) & BM_USBCTRL_PORTSC1_LS) +#define BV_USBCTRL_PORTSC1_LS__SE0 0 +#define BV_USBCTRL_PORTSC1_LS__K_STATE 1 +#define BV_USBCTRL_PORTSC1_LS__J_STATE 2 +#define BV_USBCTRL_PORTSC1_LS__UNDEF 3 +#define BM_USBCTRL_PORTSC1_HSP 0x00000200 +#define BM_USBCTRL_PORTSC1_PR 0x00000100 +#define BM_USBCTRL_PORTSC1_SUSP 0x00000080 +#define BM_USBCTRL_PORTSC1_FPR 0x00000040 +#define BM_USBCTRL_PORTSC1_OCC 0x00000020 +#define BM_USBCTRL_PORTSC1_OCA 0x00000010 +#define BM_USBCTRL_PORTSC1_PEC 0x00000008 +#define BM_USBCTRL_PORTSC1_PE 0x00000004 +#define BM_USBCTRL_PORTSC1_CSC 0x00000002 +#define BM_USBCTRL_PORTSC1_CCS 0x00000001 +HW_REGISTER_0(HW_USBCTRL_OTGSC, REGS_USBCTRL_BASE, 0x000001a4) +#define HW_USBCTRL_OTGSC_ADDR (REGS_USBCTRL_BASE + 0x000001a4) +#define BM_USBCTRL_OTGSC_DPIE 0x40000000 +#define BM_USBCTRL_OTGSC_ONEMSE 0x20000000 +#define BM_USBCTRL_OTGSC_BSEIE 0x10000000 +#define BM_USBCTRL_OTGSC_BSVIE 0x08000000 +#define BM_USBCTRL_OTGSC_ASVIE 0x04000000 +#define BM_USBCTRL_OTGSC_AVVIE 0x02000000 +#define BM_USBCTRL_OTGSC_IDIE 0x01000000 +#define BM_USBCTRL_OTGSC_DPIS 0x00400000 +#define BM_USBCTRL_OTGSC_ONEMSS 0x00200000 +#define BM_USBCTRL_OTGSC_BSEIS 0x00100000 +#define BM_USBCTRL_OTGSC_BSVIS 0x00080000 +#define BM_USBCTRL_OTGSC_ASVIS 0x00040000 +#define BM_USBCTRL_OTGSC_AVVIS 0x00020000 +#define BM_USBCTRL_OTGSC_IDIS 0x00010000 +#define BM_USBCTRL_OTGSC_DPS 0x00004000 +#define BM_USBCTRL_OTGSC_ONEMST 0x00002000 +#define BM_USBCTRL_OTGSC_BSE 0x00001000 +#define BM_USBCTRL_OTGSC_BSV 0x00000800 +#define BM_USBCTRL_OTGSC_ASV 0x00000400 +#define BM_USBCTRL_OTGSC_AVV 0x00000200 +#define BM_USBCTRL_OTGSC_ID 0x00000100 +#define BM_USBCTRL_OTGSC_HABA 0x00000080 +#define BM_USBCTRL_OTGSC_HADP 0x00000040 +#define BM_USBCTRL_OTGSC_IDPU 0x00000020 +#define BM_USBCTRL_OTGSC_DP 0x00000010 +#define BM_USBCTRL_OTGSC_OT 0x00000008 +#define BM_USBCTRL_OTGSC_HAAR 0x00000004 +#define BM_USBCTRL_OTGSC_VC 0x00000002 +#define BM_USBCTRL_OTGSC_VD 0x00000001 +HW_REGISTER_0(HW_USBCTRL_USBMODE, REGS_USBCTRL_BASE, 0x000001a8) +#define HW_USBCTRL_USBMODE_ADDR (REGS_USBCTRL_BASE + 0x000001a8) +#define BM_USBCTRL_USBMODE_VBPS 0x00000020 +#define BM_USBCTRL_USBMODE_SDIS 0x00000010 +#define BM_USBCTRL_USBMODE_SLOM 0x00000008 +#define BM_USBCTRL_USBMODE_ES 0x00000004 +#define BP_USBCTRL_USBMODE_CM 0 +#define BM_USBCTRL_USBMODE_CM 0x00000003 +#define BF_USBCTRL_USBMODE_CM(v) \ + (((v) << 0) & BM_USBCTRL_USBMODE_CM) +#define BV_USBCTRL_USBMODE_CM__IDLE 0x0 +#define BV_USBCTRL_USBMODE_CM__DEVICE 0x2 +#define BV_USBCTRL_USBMODE_CM__HOST 0x3 +HW_REGISTER_0(HW_USBCTRL_ENDPTSETUPSTAT, REGS_USBCTRL_BASE, 0x000001ac) +#define HW_USBCTRL_ENDPTSETUPSTAT_ADDR (REGS_USBCTRL_BASE + 0x000001ac) +#define BP_USBCTRL_ENDPTSETUPSTAT_ENDPTSETUPSTAT 0 +#define BM_USBCTRL_ENDPTSETUPSTAT_ENDPTSETUPSTAT 0x0000001F +#define BF_USBCTRL_ENDPTSETUPSTAT_ENDPTSETUPSTAT(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTSETUPSTAT_ENDPTSETUPSTAT) +HW_REGISTER_0(HW_USBCTRL_ENDPTPRIME, REGS_USBCTRL_BASE, 0x000001b0) +#define HW_USBCTRL_ENDPTPRIME_ADDR (REGS_USBCTRL_BASE + 0x000001b0) +#define BP_USBCTRL_ENDPTPRIME_PETB 16 +#define BM_USBCTRL_ENDPTPRIME_PETB 0x001F0000 +#define BF_USBCTRL_ENDPTPRIME_PETB(v) \ + (((v) << 16) & BM_USBCTRL_ENDPTPRIME_PETB) +#define BP_USBCTRL_ENDPTPRIME_PERB 0 +#define BM_USBCTRL_ENDPTPRIME_PERB 0x0000001F +#define BF_USBCTRL_ENDPTPRIME_PERB(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTPRIME_PERB) +HW_REGISTER_0(HW_USBCTRL_ENDPTFLUSH, REGS_USBCTRL_BASE, 0x000001b4) +#define HW_USBCTRL_ENDPTFLUSH_ADDR (REGS_USBCTRL_BASE + 0x000001b4) +#define BP_USBCTRL_ENDPTFLUSH_FETB 16 +#define BM_USBCTRL_ENDPTFLUSH_FETB 0x001F0000 +#define BF_USBCTRL_ENDPTFLUSH_FETB(v) \ + (((v) << 16) & BM_USBCTRL_ENDPTFLUSH_FETB) +#define BP_USBCTRL_ENDPTFLUSH_FERB 0 +#define BM_USBCTRL_ENDPTFLUSH_FERB 0x0000001F +#define BF_USBCTRL_ENDPTFLUSH_FERB(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTFLUSH_FERB) +HW_REGISTER_0(HW_USBCTRL_ENDPTSTAT, REGS_USBCTRL_BASE, 0x000001b8) +#define HW_USBCTRL_ENDPTSTAT_ADDR (REGS_USBCTRL_BASE + 0x000001b8) +#define BP_USBCTRL_ENDPTSTAT_ETBR 16 +#define BM_USBCTRL_ENDPTSTAT_ETBR 0x001F0000 +#define BF_USBCTRL_ENDPTSTAT_ETBR(v) \ + (((v) << 16) & BM_USBCTRL_ENDPTSTAT_ETBR) +#define BP_USBCTRL_ENDPTSTAT_ERBR 0 +#define BM_USBCTRL_ENDPTSTAT_ERBR 0x0000001F +#define BF_USBCTRL_ENDPTSTAT_ERBR(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTSTAT_ERBR) +HW_REGISTER_0(HW_USBCTRL_ENDPTCOMPLETE, REGS_USBCTRL_BASE, 0x000001bc) +#define HW_USBCTRL_ENDPTCOMPLETE_ADDR (REGS_USBCTRL_BASE + 0x000001bc) +#define BP_USBCTRL_ENDPTCOMPLETE_ETCE 16 +#define BM_USBCTRL_ENDPTCOMPLETE_ETCE 0x001F0000 +#define BF_USBCTRL_ENDPTCOMPLETE_ETCE(v) \ + (((v) << 16) & BM_USBCTRL_ENDPTCOMPLETE_ETCE) +#define BP_USBCTRL_ENDPTCOMPLETE_ERCE 0 +#define BM_USBCTRL_ENDPTCOMPLETE_ERCE 0x0000001F +#define BF_USBCTRL_ENDPTCOMPLETE_ERCE(v) \ + (((v) << 0) & BM_USBCTRL_ENDPTCOMPLETE_ERCE) +HW_REGISTER_0(HW_USBCTRL_ENDPTCTRL0, REGS_USBCTRL_BASE, 0x000001c0) +#define HW_USBCTRL_ENDPTCTRL0_ADDR (REGS_USBCTRL_BASE + 0x000001c0) +#define BM_USBCTRL_ENDPTCTRL0_TXE 0x00800000 +#define BP_USBCTRL_ENDPTCTRL0_TXT 18 +#define BM_USBCTRL_ENDPTCTRL0_TXT 0x000C0000 +#define BF_USBCTRL_ENDPTCTRL0_TXT(v) \ + (((v) << 18) & BM_USBCTRL_ENDPTCTRL0_TXT) +#define BV_USBCTRL_ENDPTCTRL0_TXT__CONTROL 0 +#define BM_USBCTRL_ENDPTCTRL0_TXS 0x00010000 +#define BM_USBCTRL_ENDPTCTRL0_RXE 0x00000080 +#define BP_USBCTRL_ENDPTCTRL0_RXT 2 +#define BM_USBCTRL_ENDPTCTRL0_RXT 0x0000000C +#define BF_USBCTRL_ENDPTCTRL0_RXT(v) \ + (((v) << 2) & BM_USBCTRL_ENDPTCTRL0_RXT) +#define BV_USBCTRL_ENDPTCTRL0_RXT__CONTROL 0 +#define BM_USBCTRL_ENDPTCTRL0_RXS 0x00000001 +/* + * multi-register-define name HW_USBCTRL_ENDPTCTRLn + * base 0x000001C0 + * count 5 + * offset 0x4 + */ +HW_REGISTER_0_INDEXED(HW_USBCTRL_ENDPTCTRLn, REGS_USBCTRL_BASE, 0x000001c4, + 0x4) +#define BM_USBCTRL_ENDPTCTRLn_TXE 0x00800000 +#define BM_USBCTRL_ENDPTCTRLn_TXR 0x00400000 +#define BM_USBCTRL_ENDPTCTRLn_TXI 0x00200000 +#define BP_USBCTRL_ENDPTCTRLn_TXT 18 +#define BM_USBCTRL_ENDPTCTRLn_TXT 0x000C0000 +#define BF_USBCTRL_ENDPTCTRLn_TXT(v) \ + (((v) << 18) & BM_USBCTRL_ENDPTCTRLn_TXT) +#define BV_USBCTRL_ENDPTCTRLn_TXT__CONTROL 0 +#define BV_USBCTRL_ENDPTCTRLn_TXT__ISO 1 +#define BV_USBCTRL_ENDPTCTRLn_TXT__BULK 2 +#define BV_USBCTRL_ENDPTCTRLn_TXT__INT 3 +#define BM_USBCTRL_ENDPTCTRLn_TXD 0x00020000 +#define BM_USBCTRL_ENDPTCTRLn_TXS 0x00010000 +#define BM_USBCTRL_ENDPTCTRLn_RXE 0x00000080 +#define BM_USBCTRL_ENDPTCTRLn_RXR 0x00000040 +#define BM_USBCTRL_ENDPTCTRLn_RXI 0x00000020 +#define BP_USBCTRL_ENDPTCTRLn_RXT 2 +#define BM_USBCTRL_ENDPTCTRLn_RXT 0x0000000C +#define BF_USBCTRL_ENDPTCTRLn_RXT(v) \ + (((v) << 2) & BM_USBCTRL_ENDPTCTRLn_RXT) +#define BV_USBCTRL_ENDPTCTRLn_RXT__CONTROL 0 +#define BV_USBCTRL_ENDPTCTRLn_RXT__ISO 1 +#define BV_USBCTRL_ENDPTCTRLn_RXT__BULK 2 +#define BV_USBCTRL_ENDPTCTRLn_RXT__INT 3 +#define BM_USBCTRL_ENDPTCTRLn_RXD 0x00000002 +#define BM_USBCTRL_ENDPTCTRLn_RXS 0x00000001 +#endif /* __ARCH_ARM___USBCTRL_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regs-usbphy.h b/arch/arm/mach-stmp3xxx/include/mach/regs-usbphy.h new file mode 100644 index 000000000000..044cd95a631d --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regs-usbphy.h @@ -0,0 +1,193 @@ +/* + * STMP USBPHY Register Definitions + * + * Copyright 2008-2009 Freescale Semiconductor + * + * 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 __ARCH_ARM___USBPHY_H +#define __ARCH_ARM___USBPHY_H 1 + +#include <mach/stmp3xxx_regs.h> + +#define REGS_USBPHY_BASE (REGS_BASE + 0x7c000) +#define REGS_USBPHY_BASE_PHYS (0x8007C000) +#define REGS_USBPHY_SIZE 0x00002000 +HW_REGISTER(HW_USBPHY_PWD, REGS_USBPHY_BASE, 0x00000000) +#define HW_USBPHY_PWD_ADDR (REGS_USBPHY_BASE + 0x00000000) +#define BM_USBPHY_PWD_RXPWDRX 0x00100000 +#define BM_USBPHY_PWD_RXPWDDIFF 0x00080000 +#define BM_USBPHY_PWD_RXPWD1PT1 0x00040000 +#define BM_USBPHY_PWD_RXPWDENV 0x00020000 +#define BM_USBPHY_PWD_TXPWDV2I 0x00001000 +#define BM_USBPHY_PWD_TXPWDIBIAS 0x00000800 +#define BM_USBPHY_PWD_TXPWDFS 0x00000400 +HW_REGISTER(HW_USBPHY_TX, REGS_USBPHY_BASE, 0x00000010) +#define HW_USBPHY_TX_ADDR (REGS_USBPHY_BASE + 0x00000010) +#define BP_USBPHY_TX_USBPHY_TX_EDGECTRL 26 +#define BM_USBPHY_TX_USBPHY_TX_EDGECTRL 0x1C000000 +#define BF_USBPHY_TX_USBPHY_TX_EDGECTRL(v) \ + (((v) << 26) & BM_USBPHY_TX_USBPHY_TX_EDGECTRL) +#define BM_USBPHY_TX_USBPHY_TX_SYNC_INVERT 0x02000000 +#define BM_USBPHY_TX_USBPHY_TX_SYNC_MUX 0x01000000 +#define BM_USBPHY_TX_TXENCAL45DP 0x00200000 +#define BP_USBPHY_TX_TXCAL45DP 16 +#define BM_USBPHY_TX_TXCAL45DP 0x000F0000 +#define BF_USBPHY_TX_TXCAL45DP(v) \ + (((v) << 16) & BM_USBPHY_TX_TXCAL45DP) +#define BM_USBPHY_TX_TXENCAL45DN 0x00002000 +#define BP_USBPHY_TX_TXCAL45DN 8 +#define BM_USBPHY_TX_TXCAL45DN 0x00000F00 +#define BF_USBPHY_TX_TXCAL45DN(v) \ + (((v) << 8) & BM_USBPHY_TX_TXCAL45DN) +#define BP_USBPHY_TX_D_CAL 0 +#define BM_USBPHY_TX_D_CAL 0x0000000F +#define BF_USBPHY_TX_D_CAL(v) \ + (((v) << 0) & BM_USBPHY_TX_D_CAL) +HW_REGISTER(HW_USBPHY_RX, REGS_USBPHY_BASE, 0x00000020) +#define HW_USBPHY_RX_ADDR (REGS_USBPHY_BASE + 0x00000020) +#define BM_USBPHY_RX_RXDBYPASS 0x00400000 +#define BP_USBPHY_RX_DISCONADJ 4 +#define BM_USBPHY_RX_DISCONADJ 0x00000070 +#define BF_USBPHY_RX_DISCONADJ(v) \ + (((v) << 4) & BM_USBPHY_RX_DISCONADJ) +#define BP_USBPHY_RX_ENVADJ 0 +#define BM_USBPHY_RX_ENVADJ 0x00000007 +#define BF_USBPHY_RX_ENVADJ(v) \ + (((v) << 0) & BM_USBPHY_RX_ENVADJ) +HW_REGISTER(HW_USBPHY_CTRL, REGS_USBPHY_BASE, 0x00000030) +#define HW_USBPHY_CTRL_ADDR (REGS_USBPHY_BASE + 0x00000030) +#define BM_USBPHY_CTRL_SFTRST 0x80000000 +#define BM_USBPHY_CTRL_CLKGATE 0x40000000 +#define BM_USBPHY_CTRL_UTMI_SUSPENDM 0x20000000 +#define BM_USBPHY_CTRL_HOST_FORCE_LS_SE0 0x10000000 +#define BM_USBPHY_CTRL_DATA_ON_LRADC 0x00002000 +#define BM_USBPHY_CTRL_DEVPLUGIN_IRQ 0x00001000 +#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN 0x00000800 +#define BM_USBPHY_CTRL_RESUME_IRQ 0x00000400 +#define BM_USBPHY_CTRL_ENIRQRESUMEDETECT 0x00000200 +#define BM_USBPHY_CTRL_ENOTGIDDETECT 0x00000080 +#define BM_USBPHY_CTRL_DEVPLUGIN_POLARITY 0x00000020 +#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT 0x00000010 +#define BM_USBPHY_CTRL_HOSTDISCONDETECT_IRQ 0x00000008 +#define BM_USBPHY_CTRL_ENIRQHOSTDISCON 0x00000004 +#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT 0x00000002 +HW_REGISTER_0(HW_USBPHY_STATUS, REGS_USBPHY_BASE, 0x00000040) +#define HW_USBPHY_STATUS_ADDR (REGS_USBPHY_BASE + 0x00000040) +#define BM_USBPHY_STATUS_RESUME_STATUS 0x00000400 +#define BM_USBPHY_STATUS_OTGID_STATUS 0x00000100 +#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS 0x00000040 +#define BM_USBPHY_STATUS_HOSTDISCONDETECT_STATUS 0x00000008 +HW_REGISTER(HW_USBPHY_DEBUG, REGS_USBPHY_BASE, 0x00000050) +#define HW_USBPHY_DEBUG_ADDR (REGS_USBPHY_BASE + 0x00000050) +#define BM_USBPHY_DEBUG_CLKGATE 0x40000000 +#define BM_USBPHY_DEBUG_HOST_RESUME_DEBUG 0x20000000 +#define BP_USBPHY_DEBUG_SQUELCHRESETLENGTH 25 +#define BM_USBPHY_DEBUG_SQUELCHRESETLENGTH 0x1E000000 +#define BF_USBPHY_DEBUG_SQUELCHRESETLENGTH(v) \ + (((v) << 25) & BM_USBPHY_DEBUG_SQUELCHRESETLENGTH) +#define BM_USBPHY_DEBUG_ENSQUELCHRESET 0x01000000 +#define BP_USBPHY_DEBUG_SQUELCHRESETCOUNT 16 +#define BM_USBPHY_DEBUG_SQUELCHRESETCOUNT 0x001F0000 +#define BF_USBPHY_DEBUG_SQUELCHRESETCOUNT(v) \ + (((v) << 16) & BM_USBPHY_DEBUG_SQUELCHRESETCOUNT) +#define BM_USBPHY_DEBUG_ENTX2RXCOUNT 0x00001000 +#define BP_USBPHY_DEBUG_TX2RXCOUNT 8 +#define BM_USBPHY_DEBUG_TX2RXCOUNT 0x00000F00 +#define BF_USBPHY_DEBUG_TX2RXCOUNT(v) \ + (((v) << 8) & BM_USBPHY_DEBUG_TX2RXCOUNT) +#define BP_USBPHY_DEBUG_ENHSTPULLDOWN 4 +#define BM_USBPHY_DEBUG_ENHSTPULLDOWN 0x00000030 +#define BF_USBPHY_DEBUG_ENHSTPULLDOWN(v) \ + (((v) << 4) & BM_USBPHY_DEBUG_ENHSTPULLDOWN) +#define BP_USBPHY_DEBUG_HSTPULLDOWN 2 +#define BM_USBPHY_DEBUG_HSTPULLDOWN 0x0000000C +#define BF_USBPHY_DEBUG_HSTPULLDOWN(v) \ + (((v) << 2) & BM_USBPHY_DEBUG_HSTPULLDOWN) +#define BM_USBPHY_DEBUG_DEBUG_INTERFACE_HOLD 0x00000002 +#define BM_USBPHY_DEBUG_OTGIDPIOLOCK 0x00000001 +HW_REGISTER_0(HW_USBPHY_DEBUG0_STATUS, REGS_USBPHY_BASE, 0x00000060) +#define HW_USBPHY_DEBUG0_STATUS_ADDR (REGS_USBPHY_BASE + 0x00000060) +#define BP_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 26 +#define BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT 0xFC000000 +#define BF_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT(v) \ + (((v) << 26) & BM_USBPHY_DEBUG0_STATUS_SQUELCH_COUNT) +#define BP_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 16 +#define BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT 0x03FF0000 +#define BF_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT(v) \ + (((v) << 16) & BM_USBPHY_DEBUG0_STATUS_UTMI_RXERROR_FAIL_COUNT) +#define BP_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0 +#define BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT 0x0000FFFF +#define BF_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT(v) \ + (((v) << 0) & BM_USBPHY_DEBUG0_STATUS_LOOP_BACK_FAIL_COUNT) +HW_REGISTER(HW_USBPHY_DEBUG1, REGS_USBPHY_BASE, 0x00000070) +#define HW_USBPHY_DEBUG1_ADDR (REGS_USBPHY_BASE + 0x00000070) +#define BP_USBPHY_DEBUG1_ENTAILADJVD 13 +#define BM_USBPHY_DEBUG1_ENTAILADJVD 0x00006000 +#define BF_USBPHY_DEBUG1_ENTAILADJVD(v) \ + (((v) << 13) & BM_USBPHY_DEBUG1_ENTAILADJVD) +#define BM_USBPHY_DEBUG1_ENTX2TX 0x00001000 +#define BP_USBPHY_DEBUG1_DBG_ADDRESS 0 +#define BM_USBPHY_DEBUG1_DBG_ADDRESS 0x0000000F +#define BF_USBPHY_DEBUG1_DBG_ADDRESS(v) \ + (((v) << 0) & BM_USBPHY_DEBUG1_DBG_ADDRESS) +HW_REGISTER_0(HW_USBPHY_VERSION, REGS_USBPHY_BASE, 0x00000080) +#define HW_USBPHY_VERSION_ADDR (REGS_USBPHY_BASE + 0x00000080) +#define BP_USBPHY_VERSION_MAJOR 24 +#define BM_USBPHY_VERSION_MAJOR 0xFF000000 +#define BF_USBPHY_VERSION_MAJOR(v) \ + (((v) << 24) & BM_USBPHY_VERSION_MAJOR) +#define BP_USBPHY_VERSION_MINOR 16 +#define BM_USBPHY_VERSION_MINOR 0x00FF0000 +#define BF_USBPHY_VERSION_MINOR(v) \ + (((v) << 16) & BM_USBPHY_VERSION_MINOR) +#define BP_USBPHY_VERSION_STEP 0 +#define BM_USBPHY_VERSION_STEP 0x0000FFFF +#define BF_USBPHY_VERSION_STEP(v) \ + (((v) << 0) & BM_USBPHY_VERSION_STEP) +HW_REGISTER(HW_USBPHY_IP, REGS_USBPHY_BASE, 0x00000090) +#define HW_USBPHY_IP_ADDR (REGS_USBPHY_BASE + 0x00000090) +#define BP_USBPHY_IP_DIV_SEL 23 +#define BM_USBPHY_IP_DIV_SEL 0x01800000 +#define BF_USBPHY_IP_DIV_SEL(v) \ + (((v) << 23) & BM_USBPHY_IP_DIV_SEL) +#define BV_USBPHY_IP_DIV_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_DIV_SEL__LOWER 0x1 +#define BV_USBPHY_IP_DIV_SEL__LOWEST 0x2 +#define BV_USBPHY_IP_DIV_SEL__UNDEFINED 0x3 +#define BP_USBPHY_IP_LFR_SEL 21 +#define BM_USBPHY_IP_LFR_SEL 0x00600000 +#define BF_USBPHY_IP_LFR_SEL(v) \ + (((v) << 21) & BM_USBPHY_IP_LFR_SEL) +#define BV_USBPHY_IP_LFR_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_LFR_SEL__TIMES_2 0x1 +#define BV_USBPHY_IP_LFR_SEL__TIMES_05 0x2 +#define BV_USBPHY_IP_LFR_SEL__UNDEFINED 0x3 +#define BP_USBPHY_IP_CP_SEL 19 +#define BM_USBPHY_IP_CP_SEL 0x00180000 +#define BF_USBPHY_IP_CP_SEL(v) \ + (((v) << 19) & BM_USBPHY_IP_CP_SEL) +#define BV_USBPHY_IP_CP_SEL__DEFAULT 0x0 +#define BV_USBPHY_IP_CP_SEL__TIMES_2 0x1 +#define BV_USBPHY_IP_CP_SEL__TIMES_05 0x2 +#define BV_USBPHY_IP_CP_SEL__UNDEFINED 0x3 +#define BM_USBPHY_IP_TSTI_TX_DP 0x00040000 +#define BM_USBPHY_IP_TSTI_TX_DM 0x00020000 +#define BM_USBPHY_IP_ANALOG_TESTMODE 0x00010000 +#define BM_USBPHY_IP_EN_USB_CLKS 0x00000004 +#define BM_USBPHY_IP_PLL_LOCKED 0x00000002 +#define BM_USBPHY_IP_PLL_POWER 0x00000001 +#endif /* __ARCH_ARM___USBPHY_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/regulator.h b/arch/arm/mach-stmp3xxx/include/mach/regulator.h new file mode 100644 index 000000000000..c2a8e0f127fa --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/regulator.h @@ -0,0 +1,17 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __PLAT_REGULATOR_H_ +#define __PLAT_REGULATOR_H_ +#define STMP3XXX_REG5V_NOT_USB 0 +#define STMP3XXX_REG5V_IS_USB 1 +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/rotdec.h b/arch/arm/mach-stmp3xxx/include/mach/rotdec.h new file mode 100644 index 000000000000..9a8d305de5d9 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/rotdec.h @@ -0,0 +1,26 @@ +/* + * Freescale STMP37XX/STMP378X dev board rotary encoder arch-dependent + * structure and functions declarations + * + * Author: Drew Benedetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_ROTDEC_H +#define __ASM_PLAT_ROTDEC_H + +extern int rotdec_pinmux_request(void); +extern void rotdec_pinmux_free(void); + +#endif /* __ASM_PLAT_ROTDEC_H */ + diff --git a/arch/arm/mach-stmp3xxx/include/mach/smp.h b/arch/arm/mach-stmp3xxx/include/mach/smp.h new file mode 100644 index 000000000000..4c1091e227c0 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/smp.h @@ -0,0 +1,30 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef ASMARM_ARCH_SMP_H +#define ASMARM_ARCH_SMP_H + +#include <linux/io.h> +#include <mach/hardware.h> + +#define hard_smp_processor_id() \ + ({ \ + unsigned int cpunum; \ + __asm__("mrc p15, 0, %0, c0, c0, 5" \ + : "=r" (cpunum)); \ + cpunum &= 0x0F; \ + }) + +extern void secondary_scan_irqs(void); + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/stmp3xxx.h b/arch/arm/mach-stmp3xxx/include/mach/stmp3xxx.h new file mode 100644 index 000000000000..a505687bfc39 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/stmp3xxx.h @@ -0,0 +1,91 @@ +/* + * Freescale STMP37XX/STMP378X core structure and function declarations + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_STMP3XXX_H +#define __ASM_PLAT_STMP3XXX_H + +#include <linux/suspend.h> + +struct stmpkbd_keypair { + int raw; + int kcode; +}; + +struct stmp3xxxmmc_platform_data { + int (*hw_init)(void); + void (*hw_release)(void); + void (*cmd_pullup)(int enable); + int (*get_wp)(void); + unsigned long (*setclock)(unsigned long hz); + int read_uA; + int write_uA; +}; + +struct stmp37xx_spi_platform_data { + unsigned irq_pin; + + int (*hw_init)(void *spi); + int (*hw_release)(void *spi); +}; + +struct stmp3xxx_persistent_bit_config { + int reg; + int start; + int width; + const char *name; +}; + +struct stmp3xxx_platform_persistent_data { + const struct stmp3xxx_persistent_bit_config *bit_config_tab; + int bit_config_cnt; +}; + +#define STMP3XXX_USB_DONT_REMAP 0x00000001 +struct stmp3xxx_usb_platform_data { + unsigned flags; + void (*phy_enable)(void); + void (*hw_init)(void); + void (*hw_release)(void); +}; + +extern int stmp3xxx_reset_block(u32 hwreg, int just_enable); + +extern struct platform_device stmp3xxx_appuart, stmp3xxx_dbguart, + stmp3xxx_watchdog, stmp3xxx_gpmi, + stmp3xxx_mmc, stmp3xxx_mmc2, + stmp3xxx_udc, stmp3xxx_touchscreen, + stmp3xxx_keyboard, stmp3xxx_rtc, + stmp3xxx_ehci, stmp3xxx_framebuffer, + stmp3xxx_backlight, + stmp3xxx_rotdec, + stmp3xxx_ssp1, stmp3xxx_ssp2, stmp378x_i2c, + stmp3xxx_usb, stmp3xxx_battery, + stmp3xxx_persistent, stmp3xxx_dcp_bootstream, + stmp3xxx_dcp, + stmp3xxx_mtest, stmp3xxx_pxp; +#ifdef CONFIG_PM +suspend_state_t stmp37xx_pm_get_target(void); +int stmp37xx_pm_sleep_was_deep(void); +#endif + +extern int stmp3xxx_ssp1_device_register(void); +extern int stmp3xxx_ssp2_device_register(void); + +extern int spdif_pinmux_request(void); +extern void spdif_pinmux_release(void); + +#endif /* __ASM_PLAT_STMP3XXX_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/stmp3xxx_regs.h b/arch/arm/mach-stmp3xxx/include/mach/stmp3xxx_regs.h new file mode 100644 index 000000000000..1ba0d2a01121 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/stmp3xxx_regs.h @@ -0,0 +1,201 @@ +/* + * Freescale STMP37XX/STMP378X SoC register access interfaces + * + * The SoC registers may be accessed via: + * + * - single 32 bit address, or + * - four 32 bit addresses - general purpose, set, clear and toggle bits + * + * Multiple IP blocks (e.g. SSP, UART) provide identical register sets per + * each module + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_PLAT_STMP3XXX_REGS_H +#define __ASM_PLAT_STMP3XXX_REGS_H + +#ifndef __ASSEMBLER__ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/suspend.h> +#endif + +#include "platform.h" + +#define REGS_BASE STMP3XXX_REGS_VA_BASE + +#define HW_STMP3xxx_SET 0x04 +#define HW_STMP3xxx_CLR 0x08 +#define HW_STMP3xxx_TOG 0x0c + +#ifndef __ASSEMBLER__ +#define HW_REGISTER_FUNCS(id, base, offset, regset, rd, wr) \ + static const u32 id##_OFFSET = offset; \ + static inline u32 id##_RD_NB(u32 regbase) { \ + if (!rd) \ + printk(KERN_ERR"%s: cannot READ at %x+%x\n", \ + #id, regbase, offset); \ + return __raw_readl(regbase + offset); \ + } \ + static inline void id##_WR_NB(u32 regbase, u32 v) { \ + if (!wr) \ + printk(KERN_ERR"%s: cannot WRITE at %x+%x\n", \ + #id, regbase, offset); \ + __raw_writel(v, regbase + offset); \ + } \ + static inline void id##_SET_NB(u32 regbase, u32 v) { \ + if (!wr) \ + printk(KERN_ERR"%s: cannot SET at %x+%x\n", \ + #id, regbase, offset); \ + if (regset) \ + __raw_writel(v, regbase + \ + offset + HW_STMP3xxx_SET); \ + else \ + __raw_writel(v | __raw_readl(regbase + offset), \ + regbase + offset); \ + } \ + static inline void id##_CLR_NB(u32 regbase, u32 v) { \ + if (!wr) \ + printk(KERN_ERR"%s: cannot CLR at %x+%x\n", \ + #id, regbase, offset); \ + if (regset) \ + __raw_writel(v, regbase + \ + offset + HW_STMP3xxx_CLR); \ + else \ + __raw_writel( \ + ~v & __raw_readl(regbase + offset), \ + regbase + offset); \ + } \ + static inline void id##_TOG_NB(u32 regbase, u32 v) { \ + if (!wr) \ + printk(KERN_ERR"%s: cannot TOG at %x+%x\n", \ + #id, regbase, offset); \ + if (regset) \ + __raw_writel(v, regbase + \ + offset + HW_STMP3xxx_TOG); \ + else \ + __raw_writel(v ^ __raw_readl(regbase + offset), \ + regbase + offset); \ + } \ + static inline u32 id##_RD(void) { return id##_RD_NB(base); } \ + static inline void id##_WR(u32 v) { id##_WR_NB(base, v); } \ + static inline void id##_SET(u32 v) { id##_SET_NB(base, v); } \ + static inline void id##_CLR(u32 v) { id##_CLR_NB(base, v); } \ + static inline void id##_TOG(u32 v) { id##_TOG_NB(base, v); } + +#define HW_REGISTER_FUNCS_INDEXED(id, base, offset, regset, rd, wr, step)\ + static inline u32 id##_OFFSET(int i) { \ + return offset + i * step; \ + } \ + static inline u32 id##_RD_NB(u32 regbase, int i) { \ + if (!rd) \ + printk(KERN_ERR"%s(%d): can't READ at %x+%x\n", \ + #id, i, regbase, offset + i * step); \ + return __raw_readl(regbase + offset + i * step); \ + } \ + static inline void id##_WR_NB(u32 regbase, int i, u32 v) \ + { \ + if (!wr) \ + printk(KERN_ERR"%s(%d): can't WRITE at %x+%x\n",\ + #id, i, regbase, offset + i * step); \ + __raw_writel(v, regbase + offset + i * step); \ + } \ + static inline void id##_SET_NB(u32 regbase, int i, u32 v) \ + { \ + if (!wr) \ + printk(KERN_ERR"%s(%d): can't SET at %x+%x\n", \ + #id, i, regbase, offset + i * step); \ + if (regset) \ + __raw_writel(v, regbase + offset + \ + i * step + HW_STMP3xxx_SET); \ + else \ + __raw_writel(v | __raw_readl(regbase + \ + offset + i * step), \ + regbase + offset + i * step); \ + } \ + static inline void id##_CLR_NB(u32 regbase, int i, u32 v) \ + { \ + if (!wr) \ + printk(KERN_ERR"%s(%d): cannot CLR at %x+%x\n", \ + #id, i, regbase, offset + i * step); \ + if (regset) \ + __raw_writel(v, regbase + offset + \ + i * step + HW_STMP3xxx_CLR); \ + else \ + __raw_writel(~v & __raw_readl(regbase + \ + offset + i * step), \ + regbase + offset + i * step); \ + } \ + static inline void id##_TOG_NB(u32 regbase, int i, u32 v) \ + { \ + if (!wr) \ + printk(KERN_ERR"%s(%d): cannot TOG at %x+%x\n", \ + #id, i, regbase, offset + i * step); \ + if (regset) \ + __raw_writel(v, regbase + offset + \ + i * step + HW_STMP3xxx_TOG); \ + else \ + __raw_writel(v ^ __raw_readl(regbase + offset \ + + i * step), \ + regbase + offset + i * step); \ + } \ + static inline u32 id##_RD(int i) \ + { \ + return id##_RD_NB(base, i); \ + } \ + static inline void id##_WR(int i, u32 v) \ + { \ + id##_WR_NB(base, i, v); \ + } \ + static inline void id##_SET(int i, u32 v) \ + { \ + id##_SET_NB(base, i, v); \ + } \ + static inline void id##_CLR(int i, u32 v) \ + { \ + id##_CLR_NB(base, i, v); \ + } \ + static inline void id##_TOG(int i, u32 v) \ + { \ + id##_TOG_NB(base, i, v); \ + } + +#define HW_REGISTER_WO(id, base, offset)\ + HW_REGISTER_FUNCS(id, base, offset, 1, 0, 1) +#define HW_REGISTER_RO(id, base, offset)\ + HW_REGISTER_FUNCS(id, base, offset, 1, 1, 0) +#define HW_REGISTER(id, base, offset) \ + HW_REGISTER_FUNCS(id, base, offset, 1, 1, 1) +#define HW_REGISTER_0(id, base, offset) \ + HW_REGISTER_FUNCS(id, base, offset, 0, 1, 1) +#define HW_REGISTER_INDEXED(id, base, offset, step) \ + HW_REGISTER_FUNCS_INDEXED(id, base, offset, 1, 1, 1, step) +#define HW_REGISTER_RO_INDEXED(id, base, offset, step) \ + HW_REGISTER_FUNCS_INDEXED(id, base, offset, 1, 1, 0, step) +#define HW_REGISTER_0_INDEXED(id, base, offset, step) \ + HW_REGISTER_FUNCS_INDEXED(id, base, offset, 0, 1, 1, step) +#else /* __ASSEMBLER__ */ +#define HW_REGISTER_FUNCS(id, base, offset, regset, rd, wr) +#define HW_REGISTER_FUNCS_INDEXED(id, base, offset, regset, rd, wr, step) +#define HW_REGISTER_WO(id, base, offset) +#define HW_REGISTER_RO(id, base, offset) +#define HW_REGISTER(id, base, offset) +#define HW_REGISTER_0(id, base, offset) +#define HW_REGISTER_INDEXED(id, base, offset, step) +#define HW_REGISTER_RO_INDEXED(id, base, offset, step) +#define HW_REGISTER_0_INDEXED(id, base, offset, step) +#endif /* __ASSEMBLER__ */ + +#endif /* __ASM_PLAT_STMP3XXX_REGS_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/system.h b/arch/arm/mach-stmp3xxx/include/mach/system.h new file mode 100644 index 000000000000..d0a1fdf87687 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/system.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005 Sigmatel Inc + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include <asm/proc-fns.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-power.h> + +static inline void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ + + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* Set BATTCHRG to default value */ + HW_POWER_CHARGE_WR(0x00010000); + + /* Set MINPWR to default value */ + HW_POWER_MINPWR_WR(0); + + /* Reset digital side of chip (but not power or RTC) */ + HW_CLKCTRL_RESET_WR(BM_CLKCTRL_RESET_DIG); + + /* Should not return */ +} + +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/timex.h b/arch/arm/mach-stmp3xxx/include/mach/timex.h new file mode 100644 index 000000000000..5ba435b51df5 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/timex.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 1999 ARM Limited + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * System time clock is sourced from the 32k clock + */ +#define CLOCK_TICK_RATE (32000) diff --git a/arch/arm/mach-stmp3xxx/include/mach/uncompress.h b/arch/arm/mach-stmp3xxx/include/mach/uncompress.h new file mode 100644 index 000000000000..9f551ae0f39b --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/uncompress.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005 Sigmatel Inc + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +/* + * Register includes are for when the MMU enabled; we need to define our + * own stuff here for pre-MMU use + */ +#define UARTDBG_BASE 0x80070000 +#define UART(c) (((volatile unsigned *)UARTDBG_BASE)[c]) + +/* + * This does not append a newline + */ +static void putc(char c) +{ + /* Wait for TX fifo empty */ + while ((UART(6) & (1<<7)) == 0) + continue; + + /* Write byte */ + UART(0) = c; + + /* Wait for last bit to exit the UART */ + while (UART(6) & (1<<3)) + continue; +} + +static void flush(void) +{ +} + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() + +#endif /* __ASM_ARCH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-stmp3xxx/include/mach/unique-id.h b/arch/arm/mach-stmp3xxx/include/mach/unique-id.h new file mode 100644 index 000000000000..ee22ec2502c5 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/unique-id.h @@ -0,0 +1,30 @@ +/* + * Unique ID interface for ID storage providers + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __UNIQUE_ID_H +#define __UNIQUE_ID_H + +struct uid_ops { + ssize_t (*id_show)(void *context, char *page, int ascii); + ssize_t (*id_store)(void *context, const char *page, + size_t count, int ascii); +}; + +struct kobject *uid_provider_init(const char *name, + struct uid_ops *ops, void *context); +void uid_provider_remove(const char *name); +#endif diff --git a/arch/arm/mach-stmp3xxx/include/mach/vmalloc.h b/arch/arm/mach-stmp3xxx/include/mach/vmalloc.h new file mode 100644 index 000000000000..f7228a84ea0c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/include/mach/vmalloc.h @@ -0,0 +1,17 @@ +/* + * Based on include/asm/arm/arch-integrator/vmalloc.h + * Copyright (C) 2000 Russell King. + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff --git a/arch/arm/mach-stmp3xxx/irq.c b/arch/arm/mach-stmp3xxx/irq.c new file mode 100644 index 000000000000..19bd285c8398 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/irq.c @@ -0,0 +1,86 @@ +/* + * Freescale STMP37XX/STMP378X common interrupt handling code + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/sysdev.h> + +#include <mach/regs-icoll.h> + +void __init stmp3xxx_init_irq(struct irq_chip *chip1, + struct irq_chip *chip2, int (*is_chip_2)(int)) +{ + unsigned int i; + struct irq_chip *chip; + + /* Reset the interrupt controller */ + HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_CLKGATE); + udelay(10); + HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_SFTRST); + udelay(10); + HW_ICOLL_CTRL_SET(BM_ICOLL_CTRL_SFTRST); + while (!(HW_ICOLL_CTRL_RD() & BM_ICOLL_CTRL_CLKGATE)) + continue; + HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_SFTRST | BM_ICOLL_CTRL_CLKGATE); + + /* Disable all interrupts initially */ + for (i = 0; i < NR_IRQS; i++) { + chip = chip1; + if (is_chip_2 && is_chip_2(i)) + chip = chip2; + chip->mask(i); + set_irq_chip(i, chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + + /* Ensure vector is cleared */ + HW_ICOLL_LEVELACK_WR(1); + HW_ICOLL_LEVELACK_WR(2); + HW_ICOLL_LEVELACK_WR(4); + HW_ICOLL_LEVELACK_WR(8); + + HW_ICOLL_VECTOR_WR(0); + /* Barrier */ + (void) HW_ICOLL_STAT_RD(); +} + +#define irq_suspend NULL +#define irq_resume NULL + +static struct sysdev_class irq_class = { + .name = "irq", + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static struct sys_device irq_device = { + .id = 0, + .cls = &irq_class, +}; + +static int __init irq_init_sysfs(void) +{ + int ret = sysdev_class_register(&irq_class); + if (ret == 0) + ret = sysdev_register(&irq_device); + return ret; +} + +device_initcall(irq_init_sysfs); diff --git a/arch/arm/mach-stmp3xxx/lcd_hx8238a.c b/arch/arm/mach-stmp3xxx/lcd_hx8238a.c new file mode 100644 index 000000000000..faa2740e04a5 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/lcd_hx8238a.c @@ -0,0 +1,367 @@ +/* + * Freescale STMP37XX/STMP378X dotclk panel initialization + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> + +#include <mach/regs-lcdif.h> +#include <mach/regs-lradc.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-pwm.h> +#include <mach/regs-apbh.h> +#include <mach/gpio.h> +#include <mach/pins.h> +#include <mach/lcdif.h> +#include <mach/cpu.h> +#include <mach/stmp3xxx.h> + +#include "common.h" + +#define MAX_CHAIN_LEN 10 + +#define DOTCLK_H_ACTIVE 960 +#define DOTCLK_H_PULSE_WIDTH 2 +#define DOTCLK_HF_PORCH 1 +#define DOTCLK_HB_PORCH 67 +#define DOTCLK_H_WAIT_CNT (DOTCLK_H_PULSE_WIDTH + (3 * DOTCLK_HB_PORCH)) +#define DOTCLK_H_PERIOD (DOTCLK_H_WAIT_CNT + DOTCLK_HF_PORCH + DOTCLK_H_ACTIVE) + +#define DOTCLK_V_PULSE_WIDTH 2 +#define DOTCLK_V_ACTIVE 240 +#define DOTCLK_VF_PORCH 1 +#define DOTCLK_VB_PORCH 16 +#define DOTCLK_V_WAIT_CNT (DOTCLK_V_PULSE_WIDTH + DOTCLK_VB_PORCH) +#define DOTCLK_V_PERIOD (DOTCLK_VF_PORCH + DOTCLK_V_ACTIVE + DOTCLK_V_WAIT_CNT) + +static struct pin_group *lcd_pins; +static unsigned *lcd_spi_pins; +static struct stmp3xxx_platform_bl_data bl_data; + +static void spi_write(u32 val) +{ + u32 mask; + + gpio_set_value(lcd_spi_pins[SPI_MOSI], 0); + gpio_set_value(lcd_spi_pins[SPI_SCLK], 0); + gpio_set_value(lcd_spi_pins[SPI_CS], 0); + + for (mask = 0x00800000; mask != 0; mask >>= 1) { + gpio_set_value(lcd_spi_pins[SPI_SCLK], 0); + if (val & mask) + gpio_set_value(lcd_spi_pins[SPI_MOSI], 1); + else + gpio_set_value(lcd_spi_pins[SPI_MOSI], 0); + + gpio_set_value(lcd_spi_pins[SPI_SCLK], 1); + } + + udelay(10); + gpio_set_value(lcd_spi_pins[SPI_MOSI], 0); + gpio_set_value(lcd_spi_pins[SPI_SCLK], 0); + gpio_set_value(lcd_spi_pins[SPI_CS], 1); +} + +static void write_reg(u16 reg, u16 val) +{ + pr_debug("%s: writing %x to %x\n", __func__, reg, val); + spi_write(0x00700000 | reg); + spi_write(0x00720000 | val); +} + +static void init_panel_hw(void) +{ + int i; + const unsigned short seq[] = { + 0x02, 0x0200, + 0x03, 0x6164, + 0x0E, 0x3380, + 0x1E, 0x00D2, + 0x01, 0x733F, + 0x04, 0x0448, + 0x05, 0xBC54, + 0x0A, 0x4008, + 0x0B, 0xD400, + 0x0D, 0x3229, + 0x0F, 0x0000, + 0x30, 0x0000, + 0x31, 0x0407, + 0x32, 0x0202, + 0x33, 0x0000, + 0x34, 0x0505, + 0x35, 0x0003, + 0x36, 0x0707, + 0x37, 0x0000, + 0x3A, 0x0904, + 0x3B, 0x0904, + }; + + for (i = 0; i < sizeof(seq) / sizeof(seq[0]); i += 2) + write_reg(seq[i], seq[i + 1]); +} + +static int init_pinmux(void) +{ + int ret = -EINVAL; + + if (cpu_is_stmp37xx()) + lcd_pins = &stmp37xx_lcd_pins; + else if (cpu_is_stmp378x()) + lcd_pins = &stmp378x_lcd_pins; + else + goto out; + ret = stmp3xxx_request_pin_group(lcd_pins, "lcd_hx8238a"); + +out: + return ret; +} + +static int init_pinmux_spi(void) +{ + int ret = -EINVAL; + + if (cpu_is_stmp37xx()) + lcd_spi_pins = stmp37xx_lcd_spi_pins; + else if (cpu_is_stmp378x()) + lcd_spi_pins = stmp378x_lcd_spi_pins; + else + goto out_1; + + ret = gpio_request(lcd_spi_pins[SPI_MOSI], "lcd_hx8238a"); + if (ret) + goto out_1; + + ret = gpio_request(lcd_spi_pins[SPI_SCLK], "lcd_hx8238a"); + if (ret) + goto out_2; + ret = gpio_request(lcd_spi_pins[SPI_CS], "lcd_hx8238a"); + if (ret) + goto out_3; + + /* Enable these pins as outputs */ + gpio_direction_output(lcd_spi_pins[SPI_MOSI], 0); + gpio_direction_output(lcd_spi_pins[SPI_SCLK], 0); + gpio_direction_output(lcd_spi_pins[SPI_CS], 1); + + return 0; + +out_3: + gpio_free(lcd_spi_pins[SPI_SCLK]); +out_2: + gpio_free(lcd_spi_pins[SPI_MOSI]); +out_1: + return ret; +} + +static void uninit_pinmux(void) +{ + stmp3xxx_release_pin_group(lcd_pins, "lcd_hx8238a"); +} + +static void uninit_pinmux_spi(void) +{ + gpio_free(lcd_spi_pins[SPI_MOSI]); + gpio_free(lcd_spi_pins[SPI_SCLK]); + gpio_free(lcd_spi_pins[SPI_CS]); +} + +static struct clk *lcd_clk; + +static int init_panel(struct device *dev, dma_addr_t phys, int memsize, + struct stmp3xxx_platform_fb_entry *pentry) +{ + int ret = 0; + + lcd_clk = clk_get(dev, "lcdif"); + if (IS_ERR(lcd_clk)) { + ret = PTR_ERR(lcd_clk); + goto out_1; + } + ret = clk_enable(lcd_clk); + if (ret) { + clk_put(lcd_clk); + goto out_1; + } + ret = clk_set_rate(lcd_clk, + 1000000/pentry->cycle_time_ns); /* kHz */ + if (ret) { + clk_disable(lcd_clk); + clk_put(lcd_clk); + goto out_1; + } + + ret = init_pinmux(); + if (ret) + goto out_1; + ret = init_pinmux_spi(); + if (ret) + goto out_2; + init_panel_hw(); + + ret = stmp3xxx_lcdif_dma_init(dev, phys, memsize, 0); + if (ret) + goto out_3; + + setup_dotclk_panel(DOTCLK_V_PULSE_WIDTH, DOTCLK_V_PERIOD, + DOTCLK_V_WAIT_CNT, DOTCLK_V_ACTIVE, + DOTCLK_H_PULSE_WIDTH, DOTCLK_H_PERIOD, + DOTCLK_V_WAIT_CNT, DOTCLK_H_ACTIVE, 1); + + stmp3xxx_lcd_set_bl_pdata(pentry->bl_data); + stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_INIT, pentry); + return 0; +out_3: + uninit_pinmux_spi(); +out_2: + uninit_pinmux(); +out_1: + return ret; +} + +static void release_panel(struct device *dev, + struct stmp3xxx_platform_fb_entry *pentry) +{ + stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_RELEASE, pentry); + uninit_pinmux_spi(); + uninit_pinmux(); + release_dotclk_panel(); + stmp3xxx_lcdif_dma_release(); + clk_disable(lcd_clk); + clk_put(lcd_clk); +} + +static int blank_panel(int blank) +{ + int ret = 0; + + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_RUN); + break; + + case FB_BLANK_UNBLANK: + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_RUN); + break; + + default: + ret = -EINVAL; + } + return ret; +} + +static struct stmp3xxx_platform_fb_entry fb_entry = { + .name = "hx8238a", + .x_res = 240, + .y_res = 320, + .bpp = 32, + .cycle_time_ns = 150, + .lcd_type = STMP3XXX_LCD_PANEL_DOTCLK, + .init_panel = init_panel, + .release_panel = release_panel, + .blank_panel = blank_panel, + .run_panel = stmp3xxx_lcdif_run, + .stop_panel = stmp3xxx_lcdif_stop, + .pan_display = stmp3xxx_lcdif_pan_display, + .bl_data = &bl_data, +}; + +static struct clk *pwm_clk; +static int init_bl(struct stmp3xxx_platform_bl_data *data) +{ + int ret = 0; + + pwm_clk = clk_get(NULL, "pwm"); + if (IS_ERR(pwm_clk)) { + ret = PTR_ERR(pwm_clk); + goto out; + } + clk_enable(pwm_clk); + stmp3xxx_reset_block(REGS_PWM_BASE, 1); + + ret = stmp3xxx_request_pin(PINID_PWM2, PIN_FUN1, "lcd_hx8238a"); + if (ret) + goto out_mux; + stmp3xxx_pin_voltage(PINID_PWM2, PIN_12MA, "lcd_hx8238a"); + stmp3xxx_pin_strength(PINID_PWM2, PIN_3_3V, "lcd_hx8238a"); + + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM2_ENABLE); + HW_PWM_CTRL_SET(BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE); + HW_PWM_ACTIVEn_WR(2, BF_PWM_ACTIVEn_INACTIVE(10) | + BF_PWM_ACTIVEn_ACTIVE(5)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(1) | /* divide by 2 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(14)); + return 0; + +out_mux: + clk_put(pwm_clk); +out: + return ret; +} + +static void free_bl(struct stmp3xxx_platform_bl_data *data) +{ + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM2_ENABLE); + stmp3xxx_release_pin(PINID_PWM2, "lcd_hx8238a"); + clk_disable(pwm_clk); + clk_put(pwm_clk); +} + +static void set_bl_intensity(struct stmp3xxx_platform_bl_data *data, + struct backlight_device *bd, int suspended) +{ + int intensity = bd->props.brightness; + + if (bd->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bd->props.fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + if (suspended) + intensity = 0; + + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM2_ENABLE); + if (intensity) { + HW_LRADC_CTRL2_CLR(BM_LRADC_CTRL2_BL_BRIGHTNESS); + HW_LRADC_CTRL2_SET(BM_LRADC_CTRL2_BL_ENABLE | + BM_LRADC_CTRL2_BL_MUX_SELECT | + BF_LRADC_CTRL2_BL_BRIGHTNESS(intensity - 1)); + HW_PWM_CTRL_SET(BM_PWM_CTRL_PWM2_ENABLE); + } +} + +static struct stmp3xxx_platform_bl_data bl_data = { + .bl_max_intensity = (BM_LRADC_CTRL2_BL_BRIGHTNESS >> + BP_LRADC_CTRL2_BL_BRIGHTNESS) + 1, + .bl_default_intensity = 0x10, + .init_bl = init_bl, + .free_bl = free_bl, + .set_bl_intensity = set_bl_intensity, +}; + +static int __init register_devices(void) +{ + stmp3xxx_lcd_register_entry(&fb_entry, + stmp3xxx_framebuffer.dev.platform_data); + return 0; +} +subsys_initcall(register_devices); diff --git a/arch/arm/mach-stmp3xxx/lcd_lms350.c b/arch/arm/mach-stmp3xxx/lcd_lms350.c new file mode 100644 index 000000000000..ded3110a1da3 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/lcd_lms350.c @@ -0,0 +1,537 @@ +/* + * Freescale STMP378X Samsung LMS350 LCD panel initialization + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/notifier.h> +#include <linux/regulator/consumer.h> + +#include <mach/regs-lcdif.h> +#include <mach/regs-lradc.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-pwm.h> +#include <mach/regs-apbh.h> +#include <mach/gpio.h> +#include <mach/pins.h> +#include <mach/lcdif.h> +#include <mach/cpu.h> +#include <mach/stmp3xxx.h> + +#include "common.h" + +#define DOTCLK_H_ACTIVE 320 +#define DOTCLK_H_PULSE_WIDTH 3 +#define DOTCLK_HF_PORCH 5 +#define DOTCLK_HB_PORCH 4 +#define DOTCLK_H_WAIT_CNT (DOTCLK_H_PULSE_WIDTH + (3 * DOTCLK_HB_PORCH)) +#define DOTCLK_H_PERIOD (DOTCLK_H_WAIT_CNT + DOTCLK_HF_PORCH + DOTCLK_H_ACTIVE) + +#define DOTCLK_V_PULSE_WIDTH 2 +#define DOTCLK_V_ACTIVE 240 +#define DOTCLK_VF_PORCH 2 +#define DOTCLK_VB_PORCH 5 +#define DOTCLK_V_WAIT_CNT (DOTCLK_V_PULSE_WIDTH + DOTCLK_VB_PORCH) +#define DOTCLK_V_PERIOD (DOTCLK_VF_PORCH + DOTCLK_V_ACTIVE + DOTCLK_V_WAIT_CNT) + +static struct stmp3xxx_platform_bl_data bl_data; +static struct pin_group *lcd_pins; +static unsigned *lcd_spi_pins; + +static void spi_write(u32 val) +{ + u32 mask; + + gpio_set_value(lcd_spi_pins[SPI_MOSI], 0); + gpio_set_value(lcd_spi_pins[SPI_SCLK], 1); + gpio_set_value(lcd_spi_pins[SPI_CS], 0); + + for (mask = 0x00800000; mask != 0; mask >>= 1) { + gpio_set_value(lcd_spi_pins[SPI_SCLK], 0); + if (val & mask) + gpio_set_value(lcd_spi_pins[SPI_MOSI], 1); + else + gpio_set_value(lcd_spi_pins[SPI_MOSI], 0); + + gpio_set_value(lcd_spi_pins[SPI_SCLK], 1); + } + + udelay(10); + gpio_set_value(lcd_spi_pins[SPI_MOSI], 1); + gpio_set_value(lcd_spi_pins[SPI_SCLK], 1); + gpio_set_value(lcd_spi_pins[SPI_CS], 1); +} + +static void write_reg(u16 reg, u16 val) +{ + pr_debug("%s: writing %x to %x\n", __func__, reg, val); + spi_write(0x00740000 | reg); + spi_write(0x00760000 | val); +} + +static const unsigned short pon_seq[] = { + /* power on */ + 0x07, 0x0000, 20, + 0x12, 0x1618, 0, + 0x11, 0x222f, 0, + 0x13, 0x40ca, 0, + 0x10, 0x3108, 300, + 0x12, 0x1658, 250, + 0x01, 0x2b1d, 0, + 0x02, 0x0300, 0, + 0x03, 0xD040, 0, + 0x08, (DOTCLK_VB_PORCH + DOTCLK_V_PULSE_WIDTH) - 2, 0, + 0x09, ((DOTCLK_H_PULSE_WIDTH / 3) + DOTCLK_HB_PORCH) - 2, 0, + 0x76, 0x2213, 0, + 0x0b, 0x33e1, 0, + 0x0c, 0x0020, 0, + 0x76, 0x0000, 0, + 0x0d, 0x0000, 0, + 0x0e, 0x0000, 0, + 0x14, 0x0000, 0, + 0x15, 0x0803, 0, + 0x16, 0x0000, 0, + 0x30, 0x0209, 0, + 0x31, 0x0404, 0, + 0x32, 0x0e07, 0, + 0x33, 0x0602, 0, + 0x34, 0x0707, 0, + 0x35, 0x0707, 0, + 0x36, 0x0707, 0, + 0x37, 0x0206, 0, + 0x38, 0x0f06, 0, + 0x39, 0x0611, 20, +}; + +static const unsigned short don_seq[] = { + /* display on */ + 0x07, 0x0001, 150, + 0x07, 0x0101, 150, + 0x76, 0x2213, 0, + 0x1c, 0x6650, 0, + 0x0b, 0x33e0, 0, + 0x76, 0x0000, 0, + 0x07, 0x0103, 0, +}; + + +static const unsigned short doff_seq[] = { + /* display off */ + 0x0b, 0x33e1, 0, + 0x07, 0x0102, 150, + 0x07, 0x0100, 150, + 0x12, 0x0000, 0, + 0x10, 0x0000, 0, +}; + +static const unsigned short poff_seq[] = { + /* power off */ + /* called after display off */ + 0x07, 0x0000, 0, + 0x10, 0x0000, 0, + 0x11, 0x0000, 0, +}; + +static const unsigned short sby_seq[] = { + /* standby */ + /* called after display off */ + 0x10, 0x0001, 0 +}; + +static const unsigned short csby_seq[] = { + /* cancel standby */ + /* called after display on */ + 0x10, 0x0000, 0 +}; + +static void display_off(void) +{ + int i; + const unsigned short *seq; + + seq = doff_seq; + for (i = 0; i < ARRAY_SIZE(doff_seq); i += 3) { + write_reg(seq[i], seq[i + 1]); + if (seq[i + 2]) + udelay(seq[i + 2]); + } +} + +static void display_on(void) +{ + int i; + const unsigned short *seq; + + seq = don_seq; + for (i = 0; i < ARRAY_SIZE(don_seq); i += 3) { + write_reg(seq[i], seq[i + 1]); + if (seq[i + 2]) + udelay(seq[i + 2]); + } +} + +static void init_panel_hw(void) +{ + int i; + const unsigned short *seq; + + seq = pon_seq; + for (i = 0; i < ARRAY_SIZE(pon_seq); i += 3) { + write_reg(seq[i], seq[i + 1]); + if (seq[i + 2]) + udelay(seq[i + 2]); + } + display_on(); +} + +static int init_pinmux(void) +{ + int ret = -EINVAL; + + if (cpu_is_stmp37xx()) + lcd_pins = &stmp37xx_lcd_pins; + else if (cpu_is_stmp378x()) + lcd_pins = &stmp378x_lcd_pins; + else + goto out; + ret = stmp3xxx_request_pin_group(lcd_pins, "lcd_lms350"); + +out: + return ret; +} + +static int init_pinmux_spi(void) +{ + int ret = -EINVAL; + + if (cpu_is_stmp37xx()) + lcd_spi_pins = stmp37xx_lcd_spi_pins; + else if (cpu_is_stmp378x()) + lcd_spi_pins = stmp378x_lcd_spi_pins; + else + goto out_1; + + ret = gpio_request(lcd_spi_pins[SPI_MOSI], "lcd_lms350"); + if (ret) + goto out_1; + + ret = gpio_request(lcd_spi_pins[SPI_SCLK], "lcd_lms350"); + if (ret) + goto out_2; + ret = gpio_request(lcd_spi_pins[SPI_CS], "lcd_lms350"); + if (ret) + goto out_3; + + /* Enable these pins as outputs */ + gpio_direction_output(lcd_spi_pins[SPI_MOSI], 1); + gpio_direction_output(lcd_spi_pins[SPI_SCLK], 1); + gpio_direction_output(lcd_spi_pins[SPI_CS], 1); + + return 0; +out_3: + gpio_free(lcd_spi_pins[SPI_SCLK]); +out_2: + gpio_free(lcd_spi_pins[SPI_MOSI]); +out_1: + return ret; +} + +static void uninit_pinmux(void) +{ + stmp3xxx_release_pin_group(lcd_pins, "lcd_lms350"); +} + +static void uninit_pinmux_spi(void) +{ + gpio_free(lcd_spi_pins[SPI_MOSI]); + gpio_free(lcd_spi_pins[SPI_SCLK]); + gpio_free(lcd_spi_pins[SPI_CS]); +} + +static struct clk *lcd_clk; + +static int init_panel(struct device *dev, dma_addr_t phys, int memsize, + struct stmp3xxx_platform_fb_entry *pentry) +{ + int ret = 0; + + lcd_clk = clk_get(dev, "lcdif"); + if (IS_ERR(lcd_clk)) { + ret = PTR_ERR(lcd_clk); + goto out_1; + } + ret = clk_enable(lcd_clk); + if (ret) { + clk_put(lcd_clk); + goto out_1; + } + ret = clk_set_rate(lcd_clk, + 1000000/pentry->cycle_time_ns); /* kHz */ + if (ret) { + clk_disable(lcd_clk); + clk_put(lcd_clk); + goto out_1; + } + + /* + * Make sure we do a high-to-low transition to reset the panel. + * First make it low for 100 msec, hi for 10 msec, low for 10 msec, + * then hi. + */ + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_RESET); /* low */ + mdelay(100); + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_RESET); /* high */ + mdelay(10); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_RESET); /* low */ + + /* For the Samsung, Reset must be held low at least 30 uSec + * Therefore, we'll hold it low for about 10 mSec just to be sure. + * Then we'll wait 1 mSec afterwards. + */ + mdelay(10); + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_RESET); /* high */ + mdelay(1); + + ret = init_pinmux(); + if (ret) + goto out_1; + ret = init_pinmux_spi(); + if (ret) + goto out_2; + init_panel_hw(); + + setup_dotclk_panel(DOTCLK_V_PULSE_WIDTH, DOTCLK_V_PERIOD, + DOTCLK_V_WAIT_CNT, DOTCLK_V_ACTIVE, + DOTCLK_H_PULSE_WIDTH, DOTCLK_H_PERIOD, + DOTCLK_H_WAIT_CNT, DOTCLK_H_ACTIVE, 0); + + ret = stmp3xxx_lcdif_dma_init(dev, phys, memsize, 1); + if (ret) + goto out_3; + + stmp3xxx_lcd_set_bl_pdata(pentry->bl_data); + stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_INIT, pentry); + return 0; +out_3: + uninit_pinmux_spi(); +out_2: + uninit_pinmux(); +out_1: + return ret; +} + +static void release_panel(struct device *dev, + struct stmp3xxx_platform_fb_entry *pentry) +{ + stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_RELEASE, pentry); + display_off(); + uninit_pinmux_spi(); + uninit_pinmux(); + release_dotclk_panel(); + stmp3xxx_lcdif_dma_release(); + clk_disable(lcd_clk); + clk_put(lcd_clk); +} + +static int blank_panel(int blank) +{ + int ret = 0, count; + + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_BYPASS_COUNT); + for (count = 10000; count; count--) { + if (HW_LCDIF_STAT_RD() & BM_LCDIF_STAT_TXFIFO_EMPTY) + break; + udelay(1); + } + break; + + case FB_BLANK_UNBLANK: + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_BYPASS_COUNT); + break; + + default: + ret = -EINVAL; + } + return ret; +} + +static void stop_panel(void) +{ + stmp3xxx_lcdif_stop(); + display_off(); +} + +static void run_panel(void) +{ + display_on(); + stmp3xxx_lcdif_run(); +} + +static struct stmp3xxx_platform_fb_entry fb_entry = { + .name = "lms350", + .x_res = 240, + .y_res = 320, + .bpp = 32, + .cycle_time_ns = 200, + .lcd_type = STMP3XXX_LCD_PANEL_DOTCLK, + .init_panel = init_panel, + .release_panel = release_panel, + .blank_panel = blank_panel, + .run_panel = run_panel, + .stop_panel = stop_panel, + .pan_display = stmp3xxx_lcdif_pan_display, + .bl_data = &bl_data, +}; + +static struct clk *pwm_clk; + +static int init_bl(struct stmp3xxx_platform_bl_data *data) +{ + int ret = 0; + + pwm_clk = clk_get(NULL, "pwm"); + if (IS_ERR(pwm_clk)) { + ret = PTR_ERR(pwm_clk); + goto out; + } + clk_enable(pwm_clk); + stmp3xxx_reset_block(REGS_PWM_BASE, 1); + + ret = stmp3xxx_request_pin(PINID_PWM2, PIN_FUN1, "lcd_lms350"); + if (ret) + goto out_mux; + + stmp3xxx_pin_voltage(PINID_PWM2, PIN_8MA, "lcd_lms350"); + stmp3xxx_pin_strength(PINID_PWM2, PIN_3_3V, "lcd_lms350"); + + HW_PWM_ACTIVEn_WR(2, BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599)); + HW_PWM_CTRL_SET(BM_PWM_CTRL_PWM2_ENABLE); + + return 0; + +out_mux: + clk_put(pwm_clk); +out: + return ret; +} + +static void free_bl(struct stmp3xxx_platform_bl_data *data) +{ + HW_PWM_ACTIVEn_WR(2, BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599)); + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM2_ENABLE); + stmp3xxx_pin_voltage(PINID_PWM2, PIN_4MA, "lcd_lms350"); + stmp3xxx_pin_strength(PINID_PWM2, PIN_1_8V, "lcd_lms350"); + + stmp3xxx_release_pin(PINID_PWM2, "lcd_lms350"); + clk_disable(pwm_clk); + clk_put(pwm_clk); +} + +static int values[] = { 6, 9, 12, 15, 19, 24, 30, 40, 55, 75, 100 }; +static int power[] = { + 0, 1500, 3600, 6100, 10300, + 15500, 74200, 114200, 155200, + 190100, 191000 +}; + +static int bl_to_power(int br) +{ + int base; + int rem; + + if (br > 100) + br = 100; + base = power[br/10]; + rem = br % 10; + if (!rem) + return base; + else + return base + (rem * (power[br/10 + 1]) - base) / 10; +} + +static int set_bl_intensity(struct stmp3xxx_platform_bl_data *data, + struct backlight_device *bd, int suspended) +{ + int intensity = bd->props.brightness; + int scaled_int; + + if (bd->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bd->props.fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + if (suspended) + intensity = 0; + + /* + * This is not too cool but what can we do? + * Luminance changes non-linearly... + */ + if (regulator_set_current_limit(data->regulator, bl_to_power(intensity), + bl_to_power(intensity))) + return -EBUSY; + + scaled_int = values[intensity/10]; + if (scaled_int < 100) { + int rem = intensity - 10 * (intensity/10); /* r = i % 10;*/ + scaled_int += rem*(values[intensity/10 + 1] - + values[intensity/10])/10; + } + HW_PWM_ACTIVEn_WR(2, + BF_PWM_ACTIVEn_INACTIVE(scaled_int) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599)); + return 0; +} + +static struct stmp3xxx_platform_bl_data bl_data = { + .bl_max_intensity = 100, + .bl_default_intensity = 50, + .bl_cons_intensity = 50, + .init_bl = init_bl, + .free_bl = free_bl, + .set_bl_intensity = set_bl_intensity, +}; + +static int __init register_devices(void) +{ + stmp3xxx_lcd_register_entry(&fb_entry, + stmp3xxx_framebuffer.dev.platform_data); + return 0; +} +subsys_initcall(register_devices); diff --git a/arch/arm/mach-stmp3xxx/lcd_lms430.c b/arch/arm/mach-stmp3xxx/lcd_lms430.c new file mode 100644 index 000000000000..3dc31dd641f4 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/lcd_lms430.c @@ -0,0 +1,376 @@ +/* + * Freescale STMP378X Samsung LMS430 LCD panel initialization + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/notifier.h> +#include <linux/regulator/consumer.h> + +#include <mach/regs-lcdif.h> +#include <mach/regs-lradc.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-pwm.h> +#include <mach/regs-apbh.h> +#include <mach/gpio.h> +#include <mach/pins.h> +#include <mach/lcdif.h> +#include <mach/cpu.h> +#include <mach/stmp3xxx.h> + +#include "common.h" + +#define DOTCLK_H_ACTIVE 480 +#define DOTCLK_H_PULSE_WIDTH 1 +#define DOTCLK_HF_PORCH 8 +#define DOTCLK_HB_PORCH 15 +#define DOTCLK_H_WAIT_CNT (DOTCLK_H_PULSE_WIDTH + (3 * DOTCLK_HB_PORCH)) +#define DOTCLK_H_PERIOD (DOTCLK_H_WAIT_CNT + DOTCLK_HF_PORCH + DOTCLK_H_ACTIVE) + +#define DOTCLK_V_PULSE_WIDTH 1 +#define DOTCLK_V_ACTIVE 272 +#define DOTCLK_VF_PORCH 4 +#define DOTCLK_VB_PORCH 12 +#define DOTCLK_V_WAIT_CNT (DOTCLK_V_PULSE_WIDTH + DOTCLK_VB_PORCH) +#define DOTCLK_V_PERIOD (DOTCLK_VF_PORCH + DOTCLK_V_ACTIVE + DOTCLK_V_WAIT_CNT) + +static struct stmp3xxx_platform_bl_data bl_data; +static struct pin_group *lcd_pins; +static unsigned *lcd_spi_pins; + +static int init_pinmux(void) +{ + int ret = -EINVAL; + + if (cpu_is_stmp37xx()) + lcd_pins = &stmp37xx_lcd_pins; + else if (cpu_is_stmp378x()) + lcd_pins = &stmp378x_lcd_pins; + else + goto out; + ret = stmp3xxx_request_pin_group(lcd_pins, "lcd_lms430"); + +out: + return ret; +} + +static int init_pinmux_spi(void) +{ + int ret = -EINVAL; + + if (cpu_is_stmp37xx()) + lcd_spi_pins = stmp37xx_lcd_spi_pins; + else if (cpu_is_stmp378x()) + lcd_spi_pins = stmp378x_lcd_spi_pins; + else + goto out_1; + + ret = gpio_request(lcd_spi_pins[SPI_MOSI], "lcd_lms430"); + if (ret) + goto out_1; + + ret = gpio_request(lcd_spi_pins[SPI_SCLK], "lcd_lms430"); + if (ret) + goto out_2; + ret = gpio_request(lcd_spi_pins[SPI_CS], "lcd_lms430"); + if (ret) + goto out_3; + + /* Enable these pins as outputs */ + gpio_direction_output(lcd_spi_pins[SPI_MOSI], 1); + gpio_direction_output(lcd_spi_pins[SPI_SCLK], 1); + gpio_direction_output(lcd_spi_pins[SPI_CS], 1); + + return 0; +out_3: + gpio_free(lcd_spi_pins[SPI_SCLK]); +out_2: + gpio_free(lcd_spi_pins[SPI_MOSI]); +out_1: + return ret; +} + +static void uninit_pinmux(void) +{ + stmp3xxx_release_pin_group(lcd_pins, "lcd_lms430"); +} + +static void uninit_pinmux_spi(void) +{ + gpio_free(lcd_spi_pins[SPI_MOSI]); + gpio_free(lcd_spi_pins[SPI_SCLK]); + gpio_free(lcd_spi_pins[SPI_CS]); +} + +static struct clk *lcd_clk; + +static int init_panel(struct device *dev, dma_addr_t phys, int memsize, + struct stmp3xxx_platform_fb_entry *pentry) +{ + int ret = 0; + + lcd_clk = clk_get(dev, "lcdif"); + if (IS_ERR(lcd_clk)) { + ret = PTR_ERR(lcd_clk); + goto out_1; + } + ret = clk_enable(lcd_clk); + if (ret) { + clk_put(lcd_clk); + goto out_1; + } + ret = clk_set_rate(lcd_clk, + 1000000/pentry->cycle_time_ns); /* kHz */ + if (ret) { + clk_disable(lcd_clk); + clk_put(lcd_clk); + goto out_1; + } + + /* + * Make sure we do a high-to-low transition to reset the panel. + * First make it low for 100 msec, hi for 10 msec, low for 10 msec, + * then hi. + */ + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_RESET); /* low */ + mdelay(100); + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_RESET); /* high */ + mdelay(10); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_RESET); /* low */ + + /* For the Samsung, Reset must be held low at least 30 uSec + * Therefore, we'll hold it low for about 10 mSec just to be sure. + * Then we'll wait 1 mSec afterwards. + */ + mdelay(10); + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_RESET); /* high */ + mdelay(1); + + ret = init_pinmux(); + if (ret) + goto out_1; + ret = init_pinmux_spi(); + if (ret) + goto out_2; + + setup_dotclk_panel(DOTCLK_V_PULSE_WIDTH, DOTCLK_V_PERIOD, + DOTCLK_V_WAIT_CNT, DOTCLK_V_ACTIVE, + DOTCLK_H_PULSE_WIDTH, DOTCLK_H_PERIOD, + DOTCLK_H_WAIT_CNT, DOTCLK_H_ACTIVE, 0); + + ret = stmp3xxx_lcdif_dma_init(dev, phys, memsize, 1); + if (ret) + goto out_3; + + stmp3xxx_lcd_set_bl_pdata(pentry->bl_data); + stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_INIT, pentry); + return 0; +out_3: + uninit_pinmux_spi(); +out_2: + uninit_pinmux(); +out_1: + return ret; +} + +static void release_panel(struct device *dev, + struct stmp3xxx_platform_fb_entry *pentry) +{ + stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_RELEASE, pentry); + uninit_pinmux_spi(); + uninit_pinmux(); + release_dotclk_panel(); + stmp3xxx_lcdif_dma_release(); + clk_disable(lcd_clk); + clk_put(lcd_clk); +} + +static int blank_panel(int blank) +{ + int ret = 0, count; + + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_BYPASS_COUNT); + for (count = 10000; count; count--) { + if (HW_LCDIF_STAT_RD() & BM_LCDIF_STAT_TXFIFO_EMPTY) + break; + udelay(1); + } + break; + + case FB_BLANK_UNBLANK: + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_BYPASS_COUNT); + break; + + default: + ret = -EINVAL; + } + return ret; +} + +static struct stmp3xxx_platform_fb_entry fb_entry = { + .name = "lms430", + .x_res = 272, + .y_res = 480, + .bpp = 32, + .cycle_time_ns = 150, + .lcd_type = STMP3XXX_LCD_PANEL_DOTCLK, + .init_panel = init_panel, + .release_panel = release_panel, + .blank_panel = blank_panel, + .run_panel = stmp3xxx_lcdif_run, + .stop_panel = stmp3xxx_lcdif_stop, + .pan_display = stmp3xxx_lcdif_pan_display, + .bl_data = &bl_data, +}; + +static struct clk *pwm_clk; + +static int init_bl(struct stmp3xxx_platform_bl_data *data) +{ + int ret = 0; + + pwm_clk = clk_get(NULL, "pwm"); + if (IS_ERR(pwm_clk)) { + ret = PTR_ERR(pwm_clk); + goto out; + } + clk_enable(pwm_clk); + stmp3xxx_reset_block(REGS_PWM_BASE, 1); + + ret = stmp3xxx_request_pin(PINID_PWM2, PIN_FUN1, "lcd_lms430"); + if (ret) + goto out_mux; + + stmp3xxx_pin_voltage(PINID_PWM2, PIN_8MA, "lcd_lms430"); + stmp3xxx_pin_strength(PINID_PWM2, PIN_3_3V, "lcd_lms430"); + + HW_PWM_ACTIVEn_WR(2, BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599)); + HW_PWM_CTRL_SET(BM_PWM_CTRL_PWM2_ENABLE); + + return 0; + +out_mux: + clk_put(pwm_clk); +out: + return ret; +} + +static void free_bl(struct stmp3xxx_platform_bl_data *data) +{ + HW_PWM_ACTIVEn_WR(2, BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599)); + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM2_ENABLE); + stmp3xxx_pin_voltage(PINID_PWM2, PIN_4MA, "lcd_lms430"); + stmp3xxx_pin_strength(PINID_PWM2, PIN_1_8V, "lcd_lms430"); + + stmp3xxx_release_pin(PINID_PWM2, "lcd_lms430"); + clk_disable(pwm_clk); + clk_put(pwm_clk); +} + +static int values[] = { 0, 4, 9, 14, 20, 27, 35, 45, 57, 75, 100 }; +static int power[] = { + 0, 1500, 3600, 6100, 10300, + 15500, 74200, 114200, 155200, + 190100, 191000 +}; + +static int bl_to_power(int br) +{ + int base; + int rem; + + if (br > 100) + br = 100; + base = power[br/10]; + rem = br % 10; + if (!rem) + return base; + else + return base + (rem * (power[br/10 + 1]) - base) / 10; +} + +static int set_bl_intensity(struct stmp3xxx_platform_bl_data *data, + struct backlight_device *bd, int suspended) +{ + int intensity = bd->props.brightness; + int scaled_int; + + if (bd->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bd->props.fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + if (suspended) + intensity = 0; + + /* + * This is not too cool but what can we do? + * Luminance changes non-linearly... + */ + if (regulator_set_current_limit(data->regulator, bl_to_power(intensity), bl_to_power(intensity))) + return -EBUSY; + + scaled_int = values[intensity/10]; + if (scaled_int < 100) { + int rem = intensity - 10 * (intensity/10); /* r = i % 10;*/ + scaled_int += rem*(values[intensity/10 + 1] - + values[intensity/10])/10; + } + HW_PWM_ACTIVEn_WR(2, + BF_PWM_ACTIVEn_INACTIVE(scaled_int) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(2, + BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(399)); + return 0; +} + +static struct stmp3xxx_platform_bl_data bl_data = { + .bl_max_intensity = 100, + .bl_default_intensity = 50, + .bl_cons_intensity = 50, + .init_bl = init_bl, + .free_bl = free_bl, + .set_bl_intensity = set_bl_intensity, +}; + +static int __init register_devices(void) +{ + stmp3xxx_lcd_register_entry(&fb_entry, + stmp3xxx_framebuffer.dev.platform_data); + return 0; +} +subsys_initcall(register_devices); diff --git a/arch/arm/mach-stmp3xxx/lradc.c b/arch/arm/mach-stmp3xxx/lradc.c new file mode 100644 index 000000000000..6f23022b41c6 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/lradc.c @@ -0,0 +1,294 @@ +/* + * Freescale STMP37XX/STMP378X LRADC helper routines + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sysdev.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <mach/hardware.h> +#include <linux/delay.h> +#include <mach/regs-lradc.h> +#include <mach/lradc.h> + +static int channels[8]; + +int hw_lradc_use_channel(int channel) +{ + if (channel < 0 || channel > 7) + return -EINVAL; + channels[channel]++; + return 0; +} +EXPORT_SYMBOL(hw_lradc_use_channel); + +int hw_lradc_unuse_channel(int channel) +{ + if (channel < 0 || channel > 7) + return -EINVAL; + channels[channel]--; + return 0; +} +EXPORT_SYMBOL(hw_lradc_unuse_channel); + +void hw_lradc_reinit(int enable_ground_ref, unsigned freq) +{ + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_SFTRST); + udelay(1); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_SFTRST); + + /* Clear the Clock Gate for normal operation */ + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_CLKGATE); + + if (enable_ground_ref) + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_ONCHIP_GROUNDREF); + else + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_ONCHIP_GROUNDREF); + + HW_LRADC_CTRL3_CLR(BM_LRADC_CTRL3_CYCLE_TIME); + HW_LRADC_CTRL3_SET(BF_LRADC_CTRL3_CYCLE_TIME(freq)); + + HW_LRADC_CTRL4_CLR(BM_LRADC_CTRL4_LRADC6SELECT | + BM_LRADC_CTRL4_LRADC7SELECT); + HW_LRADC_CTRL4_SET(BF_LRADC_CTRL4_LRADC6SELECT(VDDIO_VOLTAGE_CH)); + HW_LRADC_CTRL4_SET(BF_LRADC_CTRL4_LRADC7SELECT(BATTERY_VOLTAGE_CH)); +} + +int hw_lradc_init_ladder(int channel, int trigger, unsigned sampling) +{ + /* + * check if the lradc channel is present in this product + */ + if (!hw_lradc_present(channel)) + return -ENODEV; + + hw_lradc_configure_channel(channel, + !0 /* div2 */, + 0 /* acc */, + 0 /* num_samples */); + + /* Setup the trigger loop forever */ + hw_lradc_set_delay_trigger(trigger, 1<<channel, + 1<<trigger, 0, sampling); + + /* Clear the accumulator & NUM_SAMPLES */ + HW_LRADC_CHn_CLR(channel, 0xFFFFFFFF); + return 0; +} +EXPORT_SYMBOL(hw_lradc_init_ladder); + +int hw_lradc_stop_ladder(int channel, int trigger) +{ + /* + * check if the lradc channel is present in this product + */ + if (!hw_lradc_present(channel)) + return -ENODEV; + hw_lradc_clear_delay_trigger(trigger, 1<<channel, 1<<trigger); + return 0; +} +EXPORT_SYMBOL(hw_lradc_stop_ladder); + +int hw_lradc_present(int channel) +{ + if (channel < 0 || channel > 7) + return 0; + return HW_LRADC_STATUS_RD() & (1<<(16+channel)); +} +EXPORT_SYMBOL(hw_lradc_present); + +void hw_lradc_configure_channel(int channel, int enable_div2, + int enable_acc, int samples) +{ + if (enable_div2) + HW_LRADC_CTRL2_SET(BF_LRADC_CTRL2_DIVIDE_BY_TWO(1<<channel)); + else + HW_LRADC_CTRL2_CLR(BF_LRADC_CTRL2_DIVIDE_BY_TWO(1<<channel)); + + /* Clear the accumulator & NUM_SAMPLES */ + HW_LRADC_CHn_CLR(channel, 0xFFFFFFFF); + + /* Sets NUM_SAMPLES bitfield of HW_LRADC_CHn register. */ + HW_LRADC_CHn_CLR(channel, BM_LRADC_CHn_NUM_SAMPLES); + HW_LRADC_CHn_SET(channel, BF_LRADC_CHn_NUM_SAMPLES(samples)); + + if (enable_acc) + HW_LRADC_CHn_SET(channel, BM_LRADC_CHn_ACCUMULATE); + else + HW_LRADC_CHn_CLR(channel, BM_LRADC_CHn_ACCUMULATE); +} +EXPORT_SYMBOL(hw_lradc_configure_channel); + +void hw_lradc_set_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers, u32 loops, u32 delays) +{ + /* set TRIGGER_LRADCS in HW_LRADC_DELAYn */ + HW_LRADC_DELAYn_SET(trigger, + BF_LRADC_DELAYn_TRIGGER_LRADCS(trigger_lradc)); + HW_LRADC_DELAYn_SET(trigger, + BF_LRADC_DELAYn_TRIGGER_DELAYS(delay_triggers)); + + HW_LRADC_DELAYn_CLR(trigger, + BM_LRADC_DELAYn_LOOP_COUNT | BM_LRADC_DELAYn_DELAY); + HW_LRADC_DELAYn_SET(trigger, + BF_LRADC_DELAYn_LOOP_COUNT(loops)); + HW_LRADC_DELAYn_SET(trigger, + BF_LRADC_DELAYn_DELAY(delays)); +} +EXPORT_SYMBOL(hw_lradc_set_delay_trigger); + +void hw_lradc_clear_delay_trigger(int trigger, u32 trigger_lradc, + u32 delay_triggers) +{ + HW_LRADC_DELAYn_CLR(trigger, + BF_LRADC_DELAYn_TRIGGER_LRADCS(trigger_lradc)); + HW_LRADC_DELAYn_CLR(trigger, + BF_LRADC_DELAYn_TRIGGER_DELAYS(delay_triggers)); +} +EXPORT_SYMBOL(hw_lradc_clear_delay_trigger); + +void hw_lradc_set_delay_trigger_kick(int trigger, int value) +{ + if (value) + HW_LRADC_DELAYn_SET(trigger, BM_LRADC_DELAYn_KICK); + else + HW_LRADC_DELAYn_CLR(trigger, BM_LRADC_DELAYn_KICK); +} +EXPORT_SYMBOL(hw_lradc_set_delay_trigger_kick); + +u32 hw_lradc_vddio(void) +{ + /* Clear the Soft Reset and Clock Gate for normal operation */ + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_SFTRST | BM_LRADC_CTRL0_CLKGATE); + + /* + * Clear the divide by two for channel 6 since + * it has a HW divide-by-two built in. + */ + HW_LRADC_CTRL2_CLR(BF_LRADC_CTRL2_DIVIDE_BY_TWO(1<<VDDIO_VOLTAGE_CH)); + + /* Clear the accumulator & NUM_SAMPLES */ + HW_LRADC_CHn_CLR(VDDIO_VOLTAGE_CH, 0xFFFFFFFF); + + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC6_IRQ); + + /* + * Get VddIO; this is the max scale value for the button resistor + * ladder. + * schedule ch 6: + */ + HW_LRADC_CTRL0_SET(BF_LRADC_CTRL0_SCHEDULE(1<<VDDIO_VOLTAGE_CH)); + + /* wait for completion */ + while ((HW_LRADC_CTRL1_RD() & BM_LRADC_CTRL1_LRADC6_IRQ) != + BM_LRADC_CTRL1_LRADC6_IRQ) + cpu_relax(); + + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC6_IRQ); + + /* read ch 6 value. */ + return HW_LRADC_CHn_RD(6) & BM_LRADC_CHn_VALUE; +} +EXPORT_SYMBOL(hw_lradc_vddio); + +static u32 lradc_registers[0x16]; +static int do_gate; + +static int hw_lradc_suspend(struct sys_device *dev, pm_message_t state) +{ + int i; + + do_gate = 1; + for (i = 0; i < ARRAY_SIZE(channels); i++) + if (channels[i] > 0) { + do_gate = 0; + break; + } + + for (i = 0; i < ARRAY_SIZE(lradc_registers); i++) + lradc_registers[i] = __raw_readl(REGS_LRADC_BASE + (i << 4)); + + if (do_gate) + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_CLKGATE); + return 0; +} + +static int hw_lradc_resume(struct sys_device *dev) +{ + int i; + + if (do_gate) { + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_SFTRST); + udelay(10); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_SFTRST | + BM_LRADC_CTRL0_CLKGATE); + } + for (i = 0; i < ARRAY_SIZE(lradc_registers); i++) + __raw_writel(lradc_registers[i], REGS_LRADC_BASE + (i << 4)); + return 0; +} + +static struct sysdev_class stmp3xxx_lradc_sysclass = { + .name = "stmp3xxx-lradc", +#ifdef CONFIG_PM + .suspend = hw_lradc_suspend, + .resume = hw_lradc_resume, +#endif +}; + +static struct sys_device stmp3xxx_lradc_device = { + .id = -1, + .cls = &stmp3xxx_lradc_sysclass, +}; + +static int __initdata lradc_freq = LRADC_CLOCK_6MHZ; + +static int __init lradc_freq_setup(char *str) +{ + long freq; + + if (strict_strtol(str, 0, &freq) < 0) + return 0; + + if (freq < 0) + return 0; + if (freq >= 6) + lradc_freq = LRADC_CLOCK_6MHZ; + else if (freq >= 4) + lradc_freq = LRADC_CLOCK_4MHZ; + else if (freq >= 3) + lradc_freq = LRADC_CLOCK_3MHZ; + else if (freq >= 2) + lradc_freq = LRADC_CLOCK_2MHZ; + else + return 0; + return 1; +} + +__setup("lradc_freq=", lradc_freq_setup); + +static int __init hw_lradc_init(void) +{ + hw_lradc_reinit(0, lradc_freq); + sysdev_class_register(&stmp3xxx_lradc_sysclass); + sysdev_register(&stmp3xxx_lradc_device); + return 0; +} +subsys_initcall(hw_lradc_init); diff --git a/arch/arm/mach-stmp3xxx/mmc.c b/arch/arm/mach-stmp3xxx/mmc.c new file mode 100644 index 000000000000..e8e30fbd4d8d --- /dev/null +++ b/arch/arm/mach-stmp3xxx/mmc.c @@ -0,0 +1,167 @@ +/* + * Freescale STMP37XX/STMP378X MMC pin multiplexing + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/gpio.h> +#include <mach/stmp3xxx.h> +#include <mach/regs-ssp.h> +#include "common.h" + +#if defined(CONFIG_MACH_STMP378X) +#define MMC_POWER PINID_PWM3 +#define MMC_WP PINID_PWM4 +#elif defined(CONFIG_MACH_STMP37XX) +#define MMC_POWER PINID_PWM3 +#define MMC_WP PINID_PWM4 +#else +#define MMC_POWER PINID_NO_PIN +#define MMC_WP PINID_NO_PIN +#endif + +static int mmc_drive_power; +static int mmc_wp_supported; + +static struct pin_desc mmc_pins_desc[] = { + { PINID_SSP1_DATA0, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 }, + { PINID_SSP1_DATA1, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 }, + { PINID_SSP1_DATA2, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 }, + { PINID_SSP1_DATA3, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 }, + { PINID_SSP1_CMD, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 }, + { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 }, + { PINID_SSP1_DETECT, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 }, +}; + +static struct pin_group mmc_pins = { + .pins = mmc_pins_desc, + .nr_pins = ARRAY_SIZE(mmc_pins_desc), +}; + +static int stmp3xxxmmc_get_wp(void) +{ + if (mmc_wp_supported) + return gpio_get_value(MMC_WP); + + return 0; +} + +static int stmp3xxxmmc_hw_init_ssp1(void) +{ + int ret; + + mmc_drive_power = stmp3xxx_valid_pin(MMC_POWER); + mmc_wp_supported = stmp3xxx_valid_pin(MMC_WP); + + ret = stmp3xxx_request_pin_group(&mmc_pins, "mmc"); + if (ret) + goto out; + + if (mmc_wp_supported) { + /* Configure write protect GPIO pin */ + ret = gpio_request(MMC_WP, "mmc wp"); + if (ret) + goto out_wp; + + gpio_set_value(MMC_POWER, 0); + gpio_direction_input(MMC_WP); + } + + if (mmc_drive_power) { + /* Configure POWER pin as gpio to drive power to MMC slot */ + ret = gpio_request(MMC_POWER, "mmc power"); + if (ret) + goto out_power; + + gpio_direction_output(MMC_POWER, 0); + + /* Drive power to MMC slot */ + mdelay(100); + gpio_set_value(MMC_POWER, 1); + mdelay(100); + gpio_set_value(MMC_POWER, 0); + mdelay(100); + } + + return 0; + +out_power: + if (mmc_wp_supported) + gpio_free(MMC_WP); +out_wp: + stmp3xxx_release_pin_group(&mmc_pins, "mmc"); +out: + return ret; +} + +static void stmp3xxxmmc_hw_release_ssp1(void) +{ + if (mmc_drive_power) + gpio_free(MMC_POWER); + + if (mmc_wp_supported) + gpio_free(MMC_WP); + + stmp3xxx_release_pin_group(&mmc_pins, "mmc"); +} + +static void stmp3xxxmmc_cmd_pullup_ssp1(int enable) +{ + stmp3xxx_pin_pullup(PINID_SSP1_CMD, enable, "mmc"); +} + +static unsigned long stmp3xxxmmc_setclock_ssp1(unsigned long hz) +{ + struct clk *ssp = clk_get(NULL, "ssp"), *parent; + char *p; + long r; + + /* using SSP1, no timeout, clock rate 1 */ + HW_SSP_TIMING_WR(BF_SSP_TIMING_CLOCK_DIVIDE(2) | + BF_SSP_TIMING_TIMEOUT(0xFFFF)); + + if (hz > 1000000) + p = "io"; + else + p = "osc_24M"; + + parent = clk_get(NULL, p); + clk_set_parent(ssp, parent); + r = clk_set_rate(ssp, 2 * hz / 1000); + clk_put(parent); + clk_put(ssp); + + return hz; +} + +static struct stmp3xxxmmc_platform_data mmc_data = { + .hw_init = stmp3xxxmmc_hw_init_ssp1, + .hw_release = stmp3xxxmmc_hw_release_ssp1, + .get_wp = stmp3xxxmmc_get_wp, + .cmd_pullup = stmp3xxxmmc_cmd_pullup_ssp1, + .setclock = stmp3xxxmmc_setclock_ssp1, + .read_uA = 50000, + .write_uA = 70000, +}; + +void stmp3xxx_set_mmc_data(struct device *dev) +{ + dev->platform_data = &mmc_data; +} +EXPORT_SYMBOL(stmp3xxx_set_mmc_data); diff --git a/arch/arm/mach-stmp3xxx/otp.c b/arch/arm/mach-stmp3xxx/otp.c new file mode 100644 index 000000000000..ac0de7038490 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/otp.c @@ -0,0 +1,434 @@ +/* + * Unique ID manipulation: Freescale STMP378X OTP bits read/write procedures + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/fcntl.h> +#include <linux/mutex.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <mach/unique-id.h> +#include <mach/regs-ocotp.h> +#include <mach/regs-power.h> + +static DEFINE_MUTEX(otp_mutex); +static unsigned otp_mode; +static unsigned long otp_hclk_saved; +static u32 otp_voltage_saved; + +static int otp_full; /* = 0. By default, show/set only customer bits */ +#define OTP_USER_OFFSET 0 +#define OTP_USER_SIZE 4 + +/** + * otp_wait_busy - wait for completion of operation + * + * @flags: flags that should be clear in addition to _BUSY and _ERROR + * + * Returns 0 on success or -ETIMEDOUT on error + **/ +static int otp_wait_busy(u32 flags) +{ + int count; + u32 c; + + for (count = 10000; count >= 0; count--) { + c = HW_OCOTP_CTRL_RD(); + if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags))) + break; + cpu_relax(); + } + if (count < 0) + return -ETIMEDOUT; + return 0; +} + +/** + * otp_open - open OTP bits for read or write access + * + * @mode: either O_RDONLY or O_WRONLY + * + * Returns 0 on success, error code otherwise + **/ +static int otp_open(int mode) +{ + int r; + struct clk *hclk; + int err; + + if (!mutex_trylock(&otp_mutex)) { + printk(KERN_ERR"%s: already opened\n", __func__); + return -EAGAIN; + } + + if (mode == O_RDONLY) { + pr_debug("%s: read-only mode\n", __func__); + + r = otp_wait_busy(0); + if (r) { + err = -ETIMEDOUT; + goto out; + } + + /* 2. Set RD_BANK_OPEN */ + HW_OCOTP_CTRL_SET(BM_OCOTP_CTRL_RD_BANK_OPEN); + udelay(10); + + otp_wait_busy(0); + } + + else if (mode == O_WRONLY) { + pr_debug("%s: write-only mode\n", __func__); + hclk = clk_get(NULL, "hclk"); + if (IS_ERR(hclk)) { + err = PTR_ERR(hclk); + goto out; + } + + /* + WARNING ACHTUNG UWAGA + + the code below changes HCLK clock rate to 24M. This is + required to write OTP bits (7.2.2 in STMP378x Target + Specification), and might affect LCD operation, for example. + Moreover, this hacky code changes VDDIO to 2.8V; and resto- + res it only on otp_close(). This may affect... anything. + + You are warned now. + */ + otp_hclk_saved = clk_get_rate(hclk); + clk_set_rate(hclk, 24000); + /* Set the voltage to 2.8V */ + otp_voltage_saved = HW_POWER_VDDIOCTRL_RD(); + HW_POWER_VDDIOCTRL_WR( + (otp_voltage_saved & ~BM_POWER_VDDIOCTRL_TRG) | 0x00); + + r = otp_wait_busy(BM_OCOTP_CTRL_RD_BANK_OPEN); + if (r < 0) { + HW_POWER_VDDIOCTRL_WR(otp_voltage_saved); + clk_set_rate(hclk, otp_hclk_saved); + clk_put(hclk); + err = -ETIMEDOUT; + goto out; + } + + clk_put(hclk); + } + + else { + pr_debug("%s: unknown mode '%d'\n", __func__, mode); + err = -EINVAL; + goto out; + } + + otp_mode = mode; + return 0; +out: + mutex_unlock(&otp_mutex); + pr_debug("%s: status %d\n", __func__, err); + return err; +} + +/** + * otp_close - close the OTP bits after opening by otp_open + **/ +static void otp_close(void) +{ + struct clk *hclk; + + if (!mutex_is_locked(&otp_mutex)) { + printk(KERN_ERR"%s: wasn't opened\n", __func__); + return; + } + + if (otp_mode == O_RDONLY) { + /* 5. clear RD_BANK_OPEN */ + HW_OCOTP_CTRL_CLR(BM_OCOTP_CTRL_RD_BANK_OPEN); + } + + else if (otp_mode == O_WRONLY) { + hclk = clk_get(NULL, "hclk"); + clk_set_rate(hclk, otp_hclk_saved); + HW_POWER_VDDIOCTRL_WR(otp_voltage_saved); + otp_wait_busy(0); + HW_OCOTP_CTRL_SET(BM_OCOTP_CTRL_RELOAD_SHADOWS); + otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS); + } + + else { + return; /* -EINVAL. Who does really check close? */ + } + + otp_mode = 0; + mutex_unlock(&otp_mutex); +} + +/** + * otp_read_bits - read the content of OTP + * + * @start: offset from 0, in u32's + * @len: number of OTP u32's to read + * @bits: caller-allocated buffer to save bits + * @size: size of @bits + * + * Returns number of u32's saved to buffer + **/ +static size_t otp_read_bits(int start, int len, u32 *bits, size_t size) +{ + int ofs; + + BUG_ON(!mutex_is_locked(&otp_mutex)); + + /* read all stuff that caller needs */ + if (start + len > 4 * 8) /* 4 banks, 8 registers each */ + len = 4 * 8 - start; + + for (ofs = start; ofs < len; ofs++) { + if (size/sizeof(*bits) <= 0) /* we drained out the buffer */ + break; + *bits = __raw_readl(REGS_OCOTP_BASE + + HW_OCOTP_CUSTn_OFFSET(0) + ofs * 0x10); + bits++; + size -= sizeof(*bits); + } + + return ofs - start; /* number of u32's that we saved to buffer */ +} + +/** + * otp_write_bits - store OTP bits + * + * @offset: offset from 0, in u32's + * @data: the u32 to write + * @magic: the magic value to be stored in UNLOCK field + * + **/ +static int otp_write_bits(int offset, u32 data, u32 magic) +{ + u32 c; + int r; + + BUG_ON(!mutex_is_locked(&otp_mutex)); + + if (offset < 0 || offset > 0x1F) + return -EINVAL; + + c = HW_OCOTP_CTRL_RD(); + c &= ~BM_OCOTP_CTRL_ADDR; + c |= BF_OCOTP_CTRL_ADDR(offset); + c |= BF_OCOTP_CTRL_WR_UNLOCK(magic); + HW_OCOTP_CTRL_WR(c); + + HW_OCOTP_DATA_WR(data); + + r = otp_wait_busy(0); + if (r < 0) + return r; + + udelay(2); + return 0; +} + +static ssize_t otp_id_show(void *context, char *page, int ascii) +{ + char s[60]; + int ret; + int n, i, j, r; + u32 otp_bits[4 * 8]; + + r = otp_open(O_RDONLY); + if (r < 0) + return 0; + n = otp_read_bits(0, 4 * 8, otp_bits, sizeof(otp_bits)); + otp_close(); + + ret = 0; + + + if (ascii) { + + strcpy(page, ""); + ret = 0; + + if (otp_full) { + for (i = 0; i < 4; i++) { + + ret += sprintf(s, "Bank %d: ", i); + strcat(page, s); + + for (j = 0; j < 8; j++) { + + if (i * 4 + j > n) + break; + ret += sprintf(s, "%08X ", + otp_bits[i * 4 + j]); + strcat(page, s); + } + + strcat(page, "\n"); + ret++; + } + } else { + for (i = 0; i < OTP_USER_SIZE; i++) { + ret += sprintf(s, "%08X ", + otp_bits[i + OTP_USER_OFFSET]); + strcat(page, s); + } + strcat(page, "\n"); + ret++; + } + } else { + + if (otp_full) { + memcpy(page, otp_bits, sizeof(otp_bits)); + ret = sizeof(otp_bits); + } else { + memcpy(page, otp_bits + OTP_USER_OFFSET, + OTP_USER_SIZE * sizeof(u32)); + ret = OTP_USER_SIZE * sizeof(u32); + } + } + + return ret; +} + +static int otp_check_dry_run(const char *page, size_t count) +{ + if (count >= 3 && memcmp(page, "+++", 3) == 0) + return 3; + return 0; +} + +static ssize_t otp_id_store(void *context, const char *page, + size_t count, int ascii) +{ + int r = 0; + const char *p, *cp, *d; + unsigned long index, value; + char tmps[20]; /* subject of strtoul */ + int dry_run; + + r = otp_open(O_WRONLY); + if (r < 0) { + printk(KERN_ERR"Cannot open OTP in WRITE mode\n"); + return r; + } + + if (ascii) { + + dry_run = otp_check_dry_run(page, count); + if (dry_run > 0) + page += dry_run; + + index = 0; + cp = page; + + memset(tmps, 0, sizeof(tmps)); + + for (index = 0, cp = page; cp != NULL; index++) { + p = strchr(cp, ','); + + d = strchr(cp, ':'); + if (d && (!p || d < p)) { + strncpy(tmps, cp, + min_t(int, d - cp, sizeof(tmps) - 1)); + r = strict_strtoul(tmps, 0, &index); + if (r < 0) { + pr_debug("Cannot parse '%s'\n", tmps); + break; + } + cp = d + 1; + } + + memset(tmps, 0, sizeof(tmps)); + + if (!p) + strncpy(tmps, cp, sizeof(tmps)); + else + strncpy(tmps, cp, + min_t(int, p - cp, sizeof(tmps) - 1)); + r = strict_strtoul(tmps, 0, &value); + if (r < 0) { + pr_debug("Cannot parse '%s'\n", tmps); + break; + } + + memset(tmps, 0, sizeof(tmps)); + + cp = p ? ++p : NULL; + + if (!otp_full) { + index += OTP_USER_OFFSET; + if (index > OTP_USER_SIZE) { + printk(KERN_ERR"Cannot write at " + "offset %ld\n", index); + continue; + } + } + + r = 0; + if (!dry_run) { + pr_debug("Index %ld, value 0x%08lx\n", + index, value); + r = otp_write_bits(index, value, 0x3e77); + } else + printk(KERN_NOTICE + "Dry-run: writing 0x%08lX => [%ld]\n", + value, index); + if (r < 0) + break; + } + } else { + printk(KERN_ERR"Binary write is not supported\n"); + r = -ENOSYS; + } + otp_close(); + return (r >= 0) ? count : r; +} + +static struct uid_ops otp_ops = { + .id_show = otp_id_show, + .id_store = otp_id_store, +}; + +static int __init_or_module otp_init(void) +{ + void *p; + + mutex_init(&otp_mutex); + p = uid_provider_init("otp", &otp_ops, NULL); + if (IS_ERR(p)) + return PTR_ERR(p); + return 0; +} + +static void __exit otp_remove(void) +{ + uid_provider_remove("otp"); +} + +module_param(otp_full, int, 0600); +module_init(otp_init); +module_exit(otp_remove); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_DESCRIPTION("Unique ID: OTP"); diff --git a/arch/arm/mach-stmp3xxx/persistent.c b/arch/arm/mach-stmp3xxx/persistent.c new file mode 100644 index 000000000000..ea4efb650f82 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/persistent.c @@ -0,0 +1,257 @@ +/* + * Freescale STMP378X Persistent bits manipulation driver + * + * Author: Pantelis Antoniou <pantelis@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sysdev.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> +#include <mach/hardware.h> +#include <asm/irq.h> +#include <mach/stmp3xxx_regs.h> +#include <mach/stmp3xxx.h> + +#include <mach/regs-rtc.h> + +struct stmp3xxx_persistent_data { + struct device *dev; + struct stmp3xxx_platform_persistent_data *pdata; + int count; + struct attribute_group attr_group; + /* attribute ** follow */ + /* device_attribute follow */ +}; + +#define pd_attribute_ptr(x) \ + ((struct attribute **)((x) + 1)) +#define pd_device_attribute_ptr(x) \ + ((struct device_attribute *)(pd_attribute_ptr(x) + (x)->count + 1)) + +static inline u32 persistent_reg_read(int reg) +{ + u32 msk; + + /* wait for stable value */ + msk = BF_RTC_STAT_STALE_REGS(0x01 << reg); + while (HW_RTC_STAT_RD() & msk) + cpu_relax(); + + return __raw_readl(REGS_RTC_BASE + 0x60 + (reg * 0x10)); +} + +static inline void persistent_reg_wait_settle(int reg) +{ + u32 msk; + + /* wait until the change is propagated */ + msk = BF_RTC_STAT_NEW_REGS(0x01 << reg); + while (HW_RTC_STAT_RD() & msk) + cpu_relax(); +} + +static inline void persistent_reg_write(u32 val, int reg) +{ + __raw_writel(val, REGS_RTC_BASE + 0x60 + (reg * 0x10)); + persistent_reg_wait_settle(reg); +} + +static inline void persistent_reg_set(u32 val, int reg) +{ + __raw_writel(val, REGS_RTC_BASE + 0x60 + (reg * 0x10) + 0x4); + persistent_reg_wait_settle(reg); +} + +static inline void persistent_reg_clr(u32 val, int reg) +{ + __raw_writel(val, REGS_RTC_BASE + 0x60 + (reg * 0x10) + 0x8); + persistent_reg_wait_settle(reg); +} + +static inline void persistent_reg_tog(u32 val, int reg) +{ + __raw_writel(val, REGS_RTC_BASE + 0x60 + (reg * 0x10) + 0xc); + persistent_reg_wait_settle(reg); +} + +static ssize_t +persistent_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stmp3xxx_persistent_data *pd = platform_get_drvdata(pdev); + struct device_attribute *devattr = pd_device_attribute_ptr(pd); + const struct stmp3xxx_persistent_bit_config *pb; + int idx; + u32 val; + + idx = attr - devattr; + if ((unsigned int)idx >= pd->count) + return -EINVAL; + + pb = &pd->pdata->bit_config_tab[idx]; + + /* read value and shift */ + val = persistent_reg_read(pb->reg); + val >>= pb->start; + val &= (1 << pb->width) - 1; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t +persistent_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stmp3xxx_persistent_data *pd = platform_get_drvdata(pdev); + struct device_attribute *devattr = pd_device_attribute_ptr(pd); + const struct stmp3xxx_persistent_bit_config *pb; + int idx, r; + unsigned long val, msk; + + idx = attr - devattr; + if ((unsigned int)idx >= pd->count) + return -EINVAL; + + pb = &pd->pdata->bit_config_tab[idx]; + + /* get value to write */ + r = strict_strtoul(buf, 10, &val); + if (r != 0) + return r; + + /* verify it fits */ + if ((unsigned int)val > (1 << pb->width) - 1) + return -EINVAL; + + /* lockless update, first clear the area */ + msk = ((1 << pb->width) - 1) << pb->start; + persistent_reg_clr(msk, pb->reg); + + /* shift into position */ + val <<= pb->start; + persistent_reg_set(val, pb->reg); + + return count; +} + + +static int __devinit stmp3xxx_persistent_probe(struct platform_device *pdev) +{ + struct stmp3xxx_persistent_data *pd; + struct stmp3xxx_platform_persistent_data *pdata; + const struct stmp3xxx_persistent_bit_config *pb; + struct attribute **attr; + struct device_attribute *devattr; + int i, cnt, size; + int err; + + pdata = pdev->dev.platform_data; + if (pdata == NULL) + return -ENODEV; + + cnt = pdata->bit_config_cnt; + size = sizeof(*pd) + + (cnt + 1) * sizeof(struct atrribute *) + + cnt * sizeof(struct device_attribute); + pd = kzalloc(size, GFP_KERNEL); + if (pd == NULL) + return -ENOMEM; + pd->dev = &pdev->dev; + pd->pdata = pdata; + platform_set_drvdata(pdev, pd); + pd->count = cnt; + attr = pd_attribute_ptr(pd); + devattr = pd_device_attribute_ptr(pd); + + /* build the attributes structures */ + pd->attr_group.attrs = attr; + pb = pdata->bit_config_tab; + for (i = 0; i < cnt; i++) { + devattr[i].attr.name = pb[i].name; + devattr[i].attr.mode = S_IWUSR | S_IRUGO; + devattr[i].show = persistent_show; + devattr[i].store = persistent_store; + attr[i] = &devattr[i].attr; + } + + err = sysfs_create_group(&pdev->dev.kobj, &pd->attr_group); + if (err != 0) { + platform_set_drvdata(pdev, NULL); + kfree(pd); + return err; + } + + return 0; +} + +static int stmp3xxx_persistent_remove(struct platform_device *pdev) +{ + struct stmp3xxx_persistent_data *pd; + + pd = platform_get_drvdata(pdev); + sysfs_remove_group(&pdev->dev.kobj, &pd->attr_group); + platform_set_drvdata(pdev, NULL); + kfree(pd); + + return 0; +} + +#ifdef CONFIG_PM +static int +stmp3xxx_persistent_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int stmp3xxx_persistent_resume(struct platform_device *pdev) +{ + return 0; +} +#else +#define stmp3xxx_persistent_suspend NULL +#define stmp3xxx_persistent_resume NULL +#endif + +static struct platform_driver stmp3xxx_persistent_driver = { + .probe = stmp3xxx_persistent_probe, + .remove = stmp3xxx_persistent_remove, + .suspend = stmp3xxx_persistent_suspend, + .resume = stmp3xxx_persistent_resume, + .driver = { + .name = "stmp3xxx-persistent", + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxx_persistent_init(void) +{ + return platform_driver_register(&stmp3xxx_persistent_driver); +} + +static void __exit stmp3xxx_persistent_exit(void) +{ + platform_driver_unregister(&stmp3xxx_persistent_driver); +} + +MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>"); +MODULE_DESCRIPTION("Persistent bits user-access driver"); +MODULE_LICENSE("GPL"); + +module_init(stmp3xxx_persistent_init); +module_exit(stmp3xxx_persistent_exit); diff --git a/arch/arm/mach-stmp3xxx/pinmux.c b/arch/arm/mach-stmp3xxx/pinmux.c new file mode 100644 index 000000000000..263f58550d2a --- /dev/null +++ b/arch/arm/mach-stmp3xxx/pinmux.c @@ -0,0 +1,614 @@ +/* + * Freescale STMP378X/STMP378X Pin Multiplexing + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sysdev.h> +#include <linux/string.h> +#include <linux/bitops.h> +#include <linux/sysdev.h> +#include <linux/irq.h> +#include <mach/hardware.h> +#include <mach/regs-pinctrl.h> +#include "pinmux.h" + + +static struct stmp3xxx_pinmux_bank pinmux_banks[STMP3XXX_PINMUX_NR_BANKS] = { + [0] = { + .hw_muxsel = {HW_PINCTRL_MUXSEL0_ADDR, HW_PINCTRL_MUXSEL1_ADDR}, + .hw_drive = {HW_PINCTRL_DRIVE0_ADDR, HW_PINCTRL_DRIVE1_ADDR, + HW_PINCTRL_DRIVE2_ADDR, HW_PINCTRL_DRIVE3_ADDR}, + .hw_pull = HW_PINCTRL_PULL0_ADDR, + .functions = {0x0, 0x1, 0x2, 0x3}, + .strengths = {0x0, 0x1, 0x2, 0x3, 0xff}, + .hw_gpio_read = HW_PINCTRL_DIN0_ADDR, + .hw_gpio_set = HW_PINCTRL_DOUT0_ADDR + HW_STMP3xxx_SET, + .hw_gpio_clr = HW_PINCTRL_DOUT0_ADDR + HW_STMP3xxx_CLR, + .hw_gpio_doe = HW_PINCTRL_DOE0_ADDR, + .irq = IRQ_GPIO0, + + .pin2irq = HW_PINCTRL_PIN2IRQ0_ADDR, + .irqstat = HW_PINCTRL_IRQSTAT0_ADDR, + .irqlevel = HW_PINCTRL_IRQLEVEL0_ADDR, + .irqpolarity = HW_PINCTRL_IRQPOL0_ADDR, + .irqen = HW_PINCTRL_IRQEN0_ADDR, + }, + [1] = { + .hw_muxsel = {HW_PINCTRL_MUXSEL2_ADDR, HW_PINCTRL_MUXSEL3_ADDR}, + .hw_drive = {HW_PINCTRL_DRIVE4_ADDR, HW_PINCTRL_DRIVE5_ADDR, + HW_PINCTRL_DRIVE6_ADDR, HW_PINCTRL_DRIVE7_ADDR}, + .hw_pull = HW_PINCTRL_PULL1_ADDR, + .functions = {0x0, 0x1, 0x2, 0x3}, + .strengths = {0x0, 0x1, 0x2, 0x3, 0xff}, + .hw_gpio_read = HW_PINCTRL_DIN1_ADDR, + .hw_gpio_set = HW_PINCTRL_DOUT1_ADDR + HW_STMP3xxx_SET, + .hw_gpio_clr = HW_PINCTRL_DOUT1_ADDR + HW_STMP3xxx_CLR, + .hw_gpio_doe = HW_PINCTRL_DOE1_ADDR, + .irq = IRQ_GPIO1, + + .pin2irq = HW_PINCTRL_PIN2IRQ1_ADDR, + .irqstat = HW_PINCTRL_IRQSTAT1_ADDR, + .irqlevel = HW_PINCTRL_IRQLEVEL1_ADDR, + .irqpolarity = HW_PINCTRL_IRQPOL1_ADDR, + .irqen = HW_PINCTRL_IRQEN1_ADDR, + + }, + [2] = { + .hw_muxsel = {HW_PINCTRL_MUXSEL4_ADDR, HW_PINCTRL_MUXSEL5_ADDR}, + .hw_drive = {HW_PINCTRL_DRIVE8_ADDR, HW_PINCTRL_DRIVE9_ADDR, + HW_PINCTRL_DRIVE10_ADDR, HW_PINCTRL_DRIVE11_ADDR}, + .hw_pull = HW_PINCTRL_PULL2_ADDR, + .functions = {0x0, 0x1, 0x2, 0x3}, + .strengths = {0x0, 0x1, 0x2, 0x1, 0x2}, + .hw_gpio_read = HW_PINCTRL_DIN2_ADDR, + .hw_gpio_set = HW_PINCTRL_DOUT2_ADDR + HW_STMP3xxx_SET, + .hw_gpio_clr = HW_PINCTRL_DOUT2_ADDR + HW_STMP3xxx_CLR, + .hw_gpio_doe = HW_PINCTRL_DOE2_ADDR, + .irq = IRQ_GPIO2, + + .pin2irq = HW_PINCTRL_PIN2IRQ2_ADDR, + .irqstat = HW_PINCTRL_IRQSTAT2_ADDR, + .irqlevel = HW_PINCTRL_IRQLEVEL2_ADDR, + .irqpolarity = HW_PINCTRL_IRQPOL2_ADDR, + .irqen = HW_PINCTRL_IRQEN2_ADDR, + }, + [3] = { + .hw_muxsel = {HW_PINCTRL_MUXSEL6_ADDR, HW_PINCTRL_MUXSEL7_ADDR}, + .hw_drive = {HW_PINCTRL_DRIVE12_ADDR, HW_PINCTRL_DRIVE13_ADDR, + HW_PINCTRL_DRIVE14_ADDR, 0}, + .hw_pull = HW_PINCTRL_PULL3_ADDR, + .functions = {0x0, 0x1, 0x2, 0x3}, + .strengths = {0x0, 0x1, 0x2, 0x3, 0xff}, + }, +}; + +struct stmp3xxx_pinmux_bank *stmp_pinmux_banks(int i) +{ + BUG_ON(i < 0 || i > sizeof(pinmux_banks)/sizeof(pinmux_banks[0])); + return &pinmux_banks[i]; +} +/* Compares pin owner and caller labels */ +static inline int stmp3xxx_check_owner(u32 bank, u32 pin, char *label) +{ + return label && strcmp(label, pinmux_banks[bank].pin_labels[pin]); +} + +/* Check if requested pin is owned by caller */ +static int stmp3xxx_check_pin(u32 bank, u32 pin, char *label) +{ + struct stmp3xxx_pinmux_bank *pbank = &pinmux_banks[bank]; + + if (!test_bit(pin, &pbank->pin_map)) { + printk(KERN_WARNING + "%s: Accessing free pin %d:%d, caller %s\n", + __func__, bank, pin, label); + + return -EINVAL; + } + + if (stmp3xxx_check_owner(bank, pin, label)) { + printk(KERN_WARNING + "%s: Wrong pin owner %d:%d, caller %s owner %s\n", + __func__, bank, pin, label, pbank->pin_labels[pin]); + + return -EINVAL; + } + + return 0; +} + +void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength, char *label) +{ + struct stmp3xxx_pinmux_bank *pbank; + u32 hwdrive, shift, val; + u32 bank, pin; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + + pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label, + bank, pin, strength); + + pbank = &pinmux_banks[bank]; + + hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM]; + shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN; + val = pbank->strengths[strength]; + if (val == 0xff) { + printk(KERN_WARNING + "%s: strength is not supported for bank %d, caller %s", + __func__, bank, label); + return; + } + + spin_lock(&pbank->lock); + if (stmp3xxx_check_pin(bank, pin, label)) { + printk(KERN_WARNING "%s: Pin %d:%d access failure\n", + __func__, bank, pin); + goto out; + } + + pr_debug("%s: writing 0x%x to 0x%x register\n", __func__, + val << shift, hwdrive); + __raw_writel(HW_DRIVE_PINDRV_MASK << shift, hwdrive + HW_STMP3xxx_CLR); + __raw_writel(val << shift, hwdrive + HW_STMP3xxx_SET); + +out: + spin_unlock(&pbank->lock); +} + +void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage, char *label) +{ + struct stmp3xxx_pinmux_bank *pbank; + u32 hwdrive, shift; + u32 bank, pin; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + + pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label, + bank, pin, voltage); + + pbank = &pinmux_banks[bank]; + + hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM]; + shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN; + + spin_lock(&pbank->lock); + if (stmp3xxx_check_pin(bank, pin, label)) { + printk(KERN_WARNING "%s: Pin %d:%d access failure\n", + __func__, bank, pin); + goto out; + } + + pr_debug("%s: changing 0x%x bit in 0x%x register\n", + __func__, HW_DRIVE_PINV_MASK << shift, hwdrive); + if (voltage == PIN_1_8V) + __raw_writel(HW_DRIVE_PINV_MASK << shift, + hwdrive + HW_STMP3xxx_CLR); + else + __raw_writel(HW_DRIVE_PINV_MASK << shift, + hwdrive + HW_STMP3xxx_SET); +out: + spin_unlock(&pbank->lock); +} + +void stmp3xxx_pin_pullup(unsigned id, int enable, char *label) +{ + struct stmp3xxx_pinmux_bank *pbank; + u32 hwpull; + u32 bank, pin; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + + pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label, + bank, pin, enable); + + pbank = &pinmux_banks[bank]; + + hwpull = pbank->hw_pull; + + spin_lock(&pbank->lock); + if (stmp3xxx_check_pin(bank, pin, label)) { + printk(KERN_WARNING "%s: Pin %d:%d access failure\n", + __func__, bank, pin); + goto out; + } + + pr_debug("%s: changing 0x%x bit in 0x%x register\n", + __func__, 1 << pin, hwpull); + __raw_writel(1 << pin, + hwpull + (enable ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR)); +out: + spin_unlock(&pbank->lock); +} + +int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, char *label) +{ + struct stmp3xxx_pinmux_bank *pbank; + u32 bank, pin; + int ret = 0; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + + pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label, + bank, pin, fun); + + pbank = &pinmux_banks[bank]; + + spin_lock(&pbank->lock); + if (test_bit(pin, &pbank->pin_map)) { + printk(KERN_WARNING + "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n", + __func__, bank, pin, label, pbank->pin_labels[pin]); + ret = -EBUSY; + goto out; + } + + set_bit(pin, &pbank->pin_map); + pbank->pin_labels[pin] = label; + + stmp3xxx_set_pin_type_chklock(id, fun, 0); + +out: + spin_unlock(&pbank->lock); + return ret; +} + +void stmp3xxx_set_pin_type_chklock(unsigned id, enum pin_fun fun, int lock) +{ + struct stmp3xxx_pinmux_bank *pbank; + u32 hwmux, shift, val; + u32 bank, pin; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + + pbank = &pinmux_banks[bank]; + hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM]; + shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN; + + val = pbank->functions[fun]; + if (lock) + spin_lock(&pbank->lock); + shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN; + pr_debug("%s: writing 0x%x to 0x%x register\n", + __func__, val << shift, hwmux); + __raw_writel(HW_MUXSEL_PINFUN_MASK << shift, hwmux + HW_STMP3xxx_CLR); + __raw_writel(val << shift, hwmux + HW_STMP3xxx_SET); + if (lock) + spin_unlock(&pbank->lock); +} + +void stmp3xxx_release_pin(unsigned id, char *label) +{ + struct stmp3xxx_pinmux_bank *pbank; + u32 bank, pin; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + + pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin); + + pbank = &pinmux_banks[bank]; + + spin_lock(&pbank->lock); + if (stmp3xxx_check_pin(bank, pin, label)) { + printk(KERN_WARNING "%s: Pin %d:%d access failure\n", + __func__, bank, pin); + goto out; + } + + clear_bit(pin, &pbank->pin_map); + pbank->pin_labels[pin] = NULL; +out: + spin_unlock(&pbank->lock); +} + +int stmp3xxx_request_pin_group(struct pin_group *pin_group, char *label) +{ + + struct pin_desc *pin; + int p; + int err = 0; + + /* Allocate and configure pins */ + for (p = 0; p < pin_group->nr_pins; p++) { + pr_debug("%s: #%d\n", __func__, p); + pin = &pin_group->pins[p]; + + err = stmp3xxx_request_pin(pin->id, pin->fun, label); + if (err) + goto out_err; + + stmp3xxx_pin_strength(pin->id, pin->strength, label); + stmp3xxx_pin_voltage(pin->id, pin->voltage, label); + stmp3xxx_pin_pullup(pin->id, pin->pullup, label); + } + + return 0; + +out_err: + /* Release allocated pins in case of error */ + while (--p >= 0) { + pr_debug("%s: releasing #%d\n", __func__, p); + stmp3xxx_release_pin(pin_group->pins[p].id, label); + } + return err; +} + +void stmp3xxx_release_pin_group(struct pin_group *pin_group, char *label) +{ + struct pin_desc *pin; + int p; + + for (p = 0; p < pin_group->nr_pins; p++) { + pin = &pin_group->pins[p]; + stmp3xxx_release_pin(pin->id, label); + } +} + +/** + * stmp3xxx_configure_irq + * + * Configure the pin as interrupt source + * + * id: pin id + * type: interrupt type, as in linux/irq.h; IRQ_TYPE_NONE disables irq + * + **/ + +void stmp3xxx_configure_irq(unsigned id, unsigned type) +{ + struct stmp3xxx_pinmux_bank *pbank; + unsigned pin, bank; + unsigned m; + int l, p; + + bank = STMP3XXX_PINID_TO_BANK(id); + pin = STMP3XXX_PINID_TO_PINNUM(id); + BUG_ON(bank >= STMP3XXX_PINMUX_NR_BANKS); + pbank = &pinmux_banks[bank]; + + spin_lock(&pbank->lock); + if (stmp3xxx_check_pin(bank, pin, NULL)) { + printk(KERN_WARNING "%s: Pin %d:%d access failure\n", + __func__, bank, pin); + goto out; + } + + pr_debug("%s: caller configures %d(%d:%d) as IRQ type 0x%x\n", + __func__, id, bank, pin, type); + m = 1<<pin; + + if (type == IRQ_TYPE_NONE) { + pr_debug("%s: cleared\n", __func__); + __raw_writel(m, pbank->irqen + HW_STMP3xxx_CLR); + __raw_writel(m, pbank->pin2irq + HW_STMP3xxx_CLR); + goto out; + } + switch (type) { + case IRQ_TYPE_EDGE_RISING: + l = 0; p = 1; break; + case IRQ_TYPE_EDGE_FALLING: + l = 0; p = 0; break; + case IRQ_TYPE_LEVEL_HIGH: + l = 1; p = 1; break; + case IRQ_TYPE_LEVEL_LOW: + l = 1; p = 0; break; + default: + pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n", + __func__, type); + goto out; + } + + __raw_writel(m, + pbank->irqlevel + (l ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR)); + __raw_writel(m, + pbank->irqpolarity + (p ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR)); + + __raw_writel(m, pbank->irqstat + HW_STMP3xxx_CLR); + + __raw_writel(m, pbank->pin2irq + HW_STMP3xxx_SET); + + __raw_writel(m, pbank->irqen + HW_STMP3xxx_SET); +out: + spin_unlock(&pbank->lock); + return; +} +EXPORT_SYMBOL(stmp3xxx_configure_irq); + +void stmp3xxx_pin_ack_irq(int irq) +{ + int b; + u32 stat; + + for (b = 0; b < STMP3XXX_PINMUX_NR_BANKS; b++) { + if (irq != pinmux_banks[b].irq) + continue; + stat = __raw_readl(pinmux_banks[b].irqstat); + if (stat) + __raw_writel(stat, + pinmux_banks[b].irqstat + HW_STMP3xxx_CLR); + } +} +EXPORT_SYMBOL(stmp3xxx_pin_ack_irq); + +#ifdef CONFIG_PM +static int pinmux_suspend(struct sys_device *dev, pm_message_t state) +{ + return 0; +} + +static int pinmux_resume(struct sys_device *dev) +{ + return 0; +} +#endif + +static struct sysdev_class stmp3xxx_pinmux_sysclass = { + .name = "stmp3xxx-pinmux", +#ifdef CONFIG_PM + .suspend = pinmux_suspend, + .resume = pinmux_resume, +#endif +}; + +static struct sys_device stmp3xxx_pinmux_device = { + .id = -1, + .cls = &stmp3xxx_pinmux_sysclass, +}; + +static char *str_function(unsigned f) +{ + static char s[10]; + + if (f != 3) + sprintf(s, "FUNC_%d", f); + else + strcpy(s, "GPIO"); + return s; +} + +static char *str_strength(unsigned f) +{ + static char *s[] = { + "4mA", "8mA", "12mA", "16mA", "20mA" + }; + return s[f]; +} + +static char *str_pullup(unsigned f) +{ + return f ? "Pullup" : ""; +} + +static char *str_voltage(unsigned f) +{ + return f ? "3.3V" : "1.8V"; +} + +static char *str_irqtype(int level, int pol) +{ + if (level) + return pol ? "high lvl" : "low lvl"; + return pol ? "raising edge" : "falling edge"; +} + +static char *str_irq(int v_icfg, int v_ien, int v_ilevel, + int v_ipol, int v_istat) +{ + static char irqcfg[30]; + + if (v_icfg <= 0) + return ""; + sprintf(irqcfg, "IRQ%c %s %s", + v_istat ? '!' : ' ', + str_irqtype(v_ilevel, v_ipol), + v_ien ? "Enabled" : "Disabled"); + return irqcfg; +} + +static ssize_t pinmux_all_list(struct sys_device *dev, + struct sysdev_attribute *attr, char *buf) +{ + int b, pin, n = 0; + struct stmp3xxx_pinmux_bank *p; + u32 hwpull, hwmux, hwdrive, hwdrive_v, pm; + int shift1, shift2; + unsigned v_strength, v_pull, v_fun, v_voltage; + int v_ien, v_icfg, v_ilevel, v_ipol, v_istat; + + for (b = 0; b < STMP3XXX_PINMUX_NR_BANKS; b++) { + + p = pinmux_banks + b; + + for (pin = 0, pm = 1; pin < 32; pin++, pm <<= 1) { + if ((p->pin_map & pm) == 0) + continue; + + hwmux = p->hw_muxsel[pin / HW_MUXSEL_PIN_NUM]; + shift1 = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN; + hwpull = p->hw_pull; + hwdrive = p->hw_drive[pin / HW_DRIVE_PIN_NUM]; + shift2 = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN; + + hwdrive_v = __raw_readl(hwdrive) >> shift2; + v_strength = hwdrive_v & HW_DRIVE_PINDRV_MASK; + v_voltage = hwdrive_v & HW_DRIVE_PINV_MASK; + v_pull = __raw_readl(hwpull) & pm; + v_fun = (__raw_readl(hwmux) >> shift1) & + HW_MUXSEL_PINFUN_MASK; + + if (p->irqen == 0) { + v_icfg = -1; + v_ien = -1; + v_ilevel = -1; + v_ipol = -1; + v_istat = -1; + } else { + v_icfg = (__raw_readl(p->pin2irq) & pm) + >> pin; + v_ien = (__raw_readl(p->irqen) & pm) + >> pin; + v_ilevel = (__raw_readl(p->irqlevel) & pm) + >> pin; + v_ipol = (__raw_readl(p->irqpolarity) & pm) + >> pin; + v_istat = (__raw_readl(p->irqstat) & pm) + >> pin; + } + n += sprintf(buf + n, + "%d:%d\t%-15.15s\t%s\t%s\t%s\t%s\t%s\n", + b, pin, p->pin_labels[pin], + str_function(v_fun), + str_strength(v_strength), + str_voltage(v_voltage), + str_pullup(v_pull), + str_irq(v_icfg, v_ien, v_ilevel, v_ipol, v_istat)); + } + } + return n; +} +SYSDEV_ATTR(all, 0444, pinmux_all_list, NULL); + +static int __init stmp3xxx_pinmux_init(void) +{ + int b; + + for (b = 0; b < STMP3XXX_PINMUX_NR_BANKS; b++) + spin_lock_init(&pinmux_banks[b].lock); + sysdev_class_register(&stmp3xxx_pinmux_sysclass); + sysdev_register(&stmp3xxx_pinmux_device); + sysdev_create_file(&stmp3xxx_pinmux_device, &attr_all); + + return 0; +} + +arch_initcall(stmp3xxx_pinmux_init); + +MODULE_AUTHOR("Vladislav Buzov"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-stmp3xxx/pinmux.h b/arch/arm/mach-stmp3xxx/pinmux.h new file mode 100644 index 000000000000..60e2e14bcd84 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/pinmux.h @@ -0,0 +1,161 @@ +/* + * Freescale STMP37XX/STMP378X Pin Multiplexing + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __PINMUX_H +#define __PINMUX_H + +#include <linux/spinlock.h> +#include <linux/types.h> + +/* Pin definitions */ +#include <mach/pins.h> + +/* + * Each pin may be routed up to four different HW interfaces + * including GPIO + */ +enum pin_fun { + PIN_FUN1 = 0, + PIN_FUN2, + PIN_FUN3, + PIN_GPIO, +}; + +/* + * Each pin may have different output drive strength in range from + * 4mA to 20mA. The most common case is 4, 8 and 12 mA strengths. + */ +enum pin_strength { + PIN_4MA = 0, + PIN_8MA, + PIN_12MA, + PIN_16MA, + PIN_20MA, +}; + +/* + * Each pin can be programmed for 1.8V or 3.3V + */ +enum pin_voltage { + PIN_1_8V = 0, + PIN_3_3V, +}; + +/* + * Structure to define a group of pins and their parameters + */ +struct pin_desc { + unsigned id; + enum pin_fun fun; + enum pin_strength strength; + enum pin_voltage voltage; + unsigned pullup:1; +}; + +struct pin_group { + struct pin_desc *pins; + int nr_pins; +}; + +/* Set pin drive strength */ +void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength, + char *label); + +/* Set pin voltage */ +void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage, char *label); + +/* Enable pull-up resisitor for a pin */ +void stmp3xxx_pin_pullup(unsigned id, int enable, char *label); + +/* + * Request a pin ownership, only one module (identified by @label) + * may own a pin. + */ +int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, char *label); + +/* Release pin */ +void stmp3xxx_release_pin(unsigned id, char *label); + +void stmp3xxx_set_pin_type_chklock(unsigned id, enum pin_fun fun, int lock); +#define stmp3xxx_set_pin_type(id, fun) stmp37xx_set_pin_type_chklock(id, fun, 1) + +/* Request and configure a group of pins */ +int stmp3xxx_request_pin_group(struct pin_group *pin_group, char *label); + +/* Release a group of pin for device */ +void stmp3xxx_release_pin_group(struct pin_group *pin_group, char *label); + +/* Configure pin as interrupt source */ +void stmp3xxx_configure_irq(unsigned id, unsigned type); + +/* Acknowledge irq in pinctrl registers */ +void stmp3xxx_pin_ack_irq(int irq); + +/* + * Each bank is associated with a number of registers to control + * pin function, drive strength, voltage and pull-up reigster. The + * number of registers of a given type depends on the number of bits + * describin particular pin. + */ +#define HW_MUXSEL_NUM 2 /* registers per bank */ +#define HW_MUXSEL_PIN_LEN 2 /* bits per pin */ +#define HW_MUXSEL_PIN_NUM 16 /* pins per register */ +#define HW_MUXSEL_PINFUN_MASK 0x3 /* pin function mask */ +#define HW_MUXSEL_PINFUN_NUM 4 /* four options for a pin */ + +#define HW_DRIVE_NUM 4 /* registers per bank */ +#define HW_DRIVE_PIN_LEN 4 /* bits per pin */ +#define HW_DRIVE_PIN_NUM 8 /* pins per register */ +#define HW_DRIVE_PINDRV_MASK 0x3 /* pin strength mask - 2 bits */ +#define HW_DRIVE_PINDRV_NUM 5 /* five possible strength values */ +#define HW_DRIVE_PINV_MASK 0x4 /* pin voltage mask - 1 bit */ + + +struct stmp3xxx_pinmux_bank { + /* Pins allocation map */ + unsigned long pin_map; + + /* Pin owner names */ + char *pin_labels[STMP3XXX_PINMUX_BANK_SIZE]; + + /* spin lock to protect an access to pin map */ + spinlock_t lock; + + /* Bank registers */ + u32 hw_muxsel[HW_MUXSEL_NUM]; + u32 hw_drive[HW_DRIVE_NUM]; + u32 hw_pull; + + u32 pin2irq, irqlevel, irqpolarity, irqen, irqstat; + + /* HW MUXSEL register function bit values */ + u8 functions[HW_MUXSEL_PINFUN_NUM]; + + /* + * HW DRIVE register strength bit values: + * 0xff - requested strength is not supported for this bank + */ + u8 strengths[HW_DRIVE_PINDRV_NUM]; + + /* GPIO things */ + u32 hw_gpio_read, hw_gpio_set, hw_gpio_clr, hw_gpio_doe; + int irq; +}; + +struct stmp3xxx_pinmux_bank *stmp_pinmux_banks(int i); + +#endif /* __PINMUX_H */ diff --git a/arch/arm/mach-stmp3xxx/pm.c b/arch/arm/mach-stmp3xxx/pm.c new file mode 100644 index 000000000000..4ffa9f867eea --- /dev/null +++ b/arch/arm/mach-stmp3xxx/pm.c @@ -0,0 +1,352 @@ +/* + * Static Power Management support for Freescale STMP37XX/STMP378X + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/suspend.h> +#include <linux/rtc.h> +#include <linux/pm.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <asm/dma.h> +#include <asm/cacheflush.h> +#include <asm/mach-types.h> + +#include <asm/mach/time.h> + +#include <mach/platform.h> + +#include <mach/regs-icoll.h> +#include <mach/regs-rtc.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-power.h> + +#include "clock.h" +#include "sleep.h" +#include "common.h" + +static void *saved_sram; +static int saved_sleep_state; + +static inline void do_standby(void) +{ + void (*stmp37xx_cpu_standby_ptr) (void); + struct clk *cpu_clk; + struct clk *osc_clk; + struct clk *pll_clk; + struct clk *hbus_clk; + struct clk *cpu_parent = NULL; + int cpu_rate = 0; + int hbus_rate = 0; + + /* + * 1) switch clock domains from PLL to 24MHz + * 2) lower voltage (TODO) + * 3) switch EMI to 24MHz and turn PLL off (done in sleep.S) + */ + + /* save portion of SRAM to be used by suspend function. */ + memcpy(saved_sram, (void *)STMP3XXX_OCRAM_VA_BASE, + stmp_standby_alloc_sz); + + /* make sure SRAM copy gets physically written into SDRAM. + * SDRAM will be placed into self-refresh during power down + */ + flush_cache_all(); + + /* copy suspend function into SRAM */ + memcpy((void *)STMP3XXX_OCRAM_VA_BASE, stmp37xx_cpu_standby, + stmp_standby_alloc_sz); + + /* now switch the CPU to ref_xtal */ + cpu_clk = clk_get(NULL, "cpu"); + osc_clk = clk_get(NULL, "osc_24M"); + pll_clk = clk_get(NULL, "pll"); + hbus_clk = clk_get(NULL, "hclk"); + + if (!IS_ERR(cpu_clk) && !IS_ERR(osc_clk)) { + cpu_rate = clk_get_rate(cpu_clk); + cpu_parent = cpu_clk->parent; + hbus_rate = clk_get_rate(hbus_clk); + clk_set_parent(cpu_clk, osc_clk); + } + + local_irq_disable(); + local_fiq_disable(); + + stmp3xxx_dma_suspend(); + stmp3xxx_suspend_timer(); + + HW_POWER_CTRL_SET(BM_POWER_CTRL_ENIRQ_PSWITCH); + HW_ICOLL_INTERRUPTn_SET(IRQ_VDD5V, BM_ICOLL_INTERRUPTn_ENABLE); + /* clear pending interrupt, if any */ + + /* do suspend */ + stmp37xx_cpu_standby_ptr = (void *)STMP3XXX_OCRAM_VA_BASE; + stmp37xx_cpu_standby_ptr(); + + saved_sleep_state = 0; /* waking from standby */ + HW_POWER_CTRL_CLR(BM_POWER_CTRL_ENIRQ_PSWITCH | + BM_POWER_CTRL_PSWITCH_IRQ); +#ifndef CONFIG_BATTERY_STMP3XXX + HW_ICOLL_INTERRUPTn_CLR(IRQ_VDD5V, BM_ICOLL_INTERRUPTn_ENABLE); +#endif + stmp3xxx_resume_timer(); + stmp3xxx_dma_resume(); + + local_fiq_enable(); + local_irq_enable(); + + if (cpu_parent) { + clk_set_parent(cpu_clk, cpu_parent); + clk_set_rate(cpu_clk, cpu_rate); + clk_set_rate(hbus_clk, hbus_rate); + } + + clk_put(hbus_clk); + clk_put(pll_clk); + clk_put(osc_clk); + clk_put(cpu_clk); + + /* restoring portion of SRAM that was used by suspend function */ + memcpy((void *)STMP3XXX_OCRAM_VA_BASE, saved_sram, + stmp_standby_alloc_sz); +} + +static u32 clk_regs[] = { + HW_CLKCTRL_PLLCTRL0_ADDR, + HW_CLKCTRL_XTAL_ADDR, + HW_CLKCTRL_PIX_ADDR, + HW_CLKCTRL_SSP_ADDR, + HW_CLKCTRL_GPMI_ADDR, + HW_CLKCTRL_FRAC_ADDR, + HW_CLKCTRL_CLKSEQ_ADDR, +}; + +static noinline void do_mem(void) +{ + void (*stmp37xx_cpu_suspend_ptr) (u32); + struct sleep_data saved_context; + int i; + struct clk *cpu_clk; + struct clk *osc_clk; + struct clk *pll_clk; + struct clk *hbus_clk; + int cpu_rate = 0; + int hbus_rate = 0; + + saved_context.fingerprint = SLEEP_DATA_FINGERPRINT; + + saved_context.old_c00 = __raw_readl(0xC0000000); + saved_context.old_c04 = __raw_readl(0xC0000004); + __raw_writel((u32)&saved_context, (void *)0xC0000000); + + local_irq_disable(); + local_fiq_disable(); + + stmp3xxx_dma_suspend(); + stmp3xxx_suspend_timer(); + + /* clocks */ + for (i = 0; i < ARRAY_SIZE(clk_regs); i++) + saved_context.clks[i] = + __raw_readl(clk_regs[i]); + + /* interrupt collector */ + saved_context.icoll_ctrl = HW_ICOLL_CTRL_RD(); + if (machine_is_stmp37xx()) { +#ifdef CONFIG_MACH_STMP37XX + for (i = 0; i < 16; i++) + saved_context.icoll.prio[i] = HW_ICOLL_PRIORITYn_RD(i); +#endif + } else if (machine_is_stmp378x()) { +#ifdef CONFIG_MACH_STMP378X + for (i = 0; i < 128; i++) + saved_context.icoll.intr[i] = HW_ICOLL_INTERRUPTn_RD(i); +#endif + } + + /* save pinmux state */ + for (i = 0; i < 0x100; i++) + saved_context.pinmux[i] = + __raw_readl(REGS_PINCTRL_BASE + (i<<4)); + + cpu_clk = clk_get(NULL, "cpu"); + osc_clk = clk_get(NULL, "osc_24M"); + pll_clk = clk_get(NULL, "pll"); + hbus_clk = clk_get(NULL, "hclk"); + + cpu_rate = clk_get_rate(cpu_clk); + hbus_rate = clk_get_rate(hbus_clk); + + /* save portion of SRAM to be used by suspend function. */ + memcpy(saved_sram, (void *)STMP3XXX_OCRAM_VA_BASE, stmp_s2ram_alloc_sz); + + /* set the PERSISTENT_SLEEP_BIT for bootloader */ + HW_RTC_PERSISTENT1_SET(1 << 10); /* XXX: temp */ + + /* + * make sure SRAM copy gets physically written into SDRAM. + * SDRAM will be placed into self-refresh during power down + */ + flush_cache_all(); + + /*copy suspend function into SRAM */ + memcpy((void *)STMP3XXX_OCRAM_VA_BASE, stmp37xx_cpu_suspend, + stmp_s2ram_alloc_sz); + + /* do suspend */ + stmp37xx_cpu_suspend_ptr = (void *)STMP3XXX_OCRAM_VA_BASE; + stmp37xx_cpu_suspend_ptr(0); + + saved_sleep_state = 1; /* waking from non-standby state */ + + /* restoring portion of SRAM that was used by suspend function */ + memcpy((void *)STMP3XXX_OCRAM_VA_BASE, saved_sram, stmp_s2ram_alloc_sz); + + /* clocks */ + for (i = 0; i < ARRAY_SIZE(clk_regs); i++) + __raw_writel(saved_context.clks[i], + clk_regs[i]); + + /* interrupt collector */ + HW_ICOLL_CTRL_WR(saved_context.icoll_ctrl); + if (machine_is_stmp37xx()) { +#ifdef CONFIG_MACH_STMP37XX + for (i = 0; i < 16; i++) + HW_ICOLL_PRIORITYn_WR(i, saved_context.icoll.prio[i]); +#endif + } else if (machine_is_stmp378x()) { +#ifdef CONFIG_MACH_STMP378X + for (i = 0; i < 128; i++) + HW_ICOLL_INTERRUPTn_WR(i, saved_context.icoll.intr[i]); +#endif + } + + /* restore pinmux state */ + for (i = 0; i < 0x100; i++) + __raw_writel(saved_context.pinmux[i], + REGS_PINCTRL_BASE + (i<<4)); + + clk_set_parent(cpu_clk, cpu_clk->parent); + clk_set_rate(cpu_clk, cpu_rate); + clk_set_rate(hbus_clk, hbus_rate); + + __raw_writel(saved_context.old_c00, 0xC0000000); + __raw_writel(saved_context.old_c04, 0xC0000004); + + clk_put(hbus_clk); + clk_put(pll_clk); + clk_put(osc_clk); + clk_put(cpu_clk); + + stmp3xxx_resume_timer(); + stmp3xxx_dma_resume(); + + local_fiq_enable(); + local_irq_enable(); +} + +static int stmp37xx_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + do_standby(); + break; + case PM_SUSPEND_MEM: + do_mem(); + break; + } + return 0; +} + +static int stmp37xx_pm_valid(suspend_state_t state) +{ + return (state == PM_SUSPEND_STANDBY) || + (state == PM_SUSPEND_MEM); +} + +static suspend_state_t saved_state; + +static int stmp37xx_pm_begin(suspend_state_t state) +{ + saved_state = state; + return 0; +} + +static void stmp37xx_pm_end(void) +{ + /*XXX: Nothing to do */ +} + +suspend_state_t stmp37xx_pm_get_target(void) +{ + return saved_state; +} +EXPORT_SYMBOL(stmp37xx_pm_get_target); + +/** + * stmp37xx_pm_get_sleep_state - get sleep state we waking from + * + * returns boolean: 0 if waking up from standby, 1 otherwise + */ +int stmp37xx_pm_sleep_was_deep(void) +{ + return saved_sleep_state; +} +EXPORT_SYMBOL(stmp37xx_pm_sleep_was_deep); + +static struct platform_suspend_ops stmp37xx_suspend_ops = { + .enter = stmp37xx_pm_enter, + .valid = stmp37xx_pm_valid, + .begin = stmp37xx_pm_begin, + .end = stmp37xx_pm_end, +}; + +void stmp37xx_pm_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + if (need_resched()) { + local_fiq_enable(); + local_irq_enable(); + return; + } + + HW_CLKCTRL_CPU_SET(1<<12); + __asm__ __volatile__ ("mcr p15, 0, r0, c7, c0, 4"); + + local_fiq_enable(); + local_irq_enable(); +} + +static int __init stmp37xx_pm_init(void) +{ + saved_sram = kmalloc(0x4000, GFP_ATOMIC); + if (!saved_sram) { + printk(KERN_ERR + "PM Suspend: can't allocate memory to save portion of SRAM\n"); + return -ENOMEM; + } + + pm_idle = stmp37xx_pm_idle; + suspend_set_ops(&stmp37xx_suspend_ops); + return 0; +} + +late_initcall(stmp37xx_pm_init); diff --git a/arch/arm/mach-stmp3xxx/power-test.c b/arch/arm/mach-stmp3xxx/power-test.c new file mode 100644 index 000000000000..70e52fc92904 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/power-test.c @@ -0,0 +1,212 @@ +/* + * Power consumption test module + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/sched.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +static struct regulator *reg; +static struct regulator *freg; + +static struct timer_list pt_timer; +static int timer_delay = 5*60*1000; /* 5min */ +static DEFINE_MUTEX(run_mutex); + + +#define REG_GET() do {\ + if (!reg) {\ + reg = regulator_get(NULL, "power-test-1");\ + if (!reg || IS_ERR(reg)) {\ + reg = NULL ; return -ENODEV;\ + } \ + } \ +} while (0); + +static void timer_func(unsigned long data) +{ + regulator_set_current_limit(reg, 0, 0); + mutex_unlock(&run_mutex); +} + +static ssize_t pt_mode_set(struct device *d, struct device_attribute *attr, + const char *buf, size_t size) +{ + REG_GET(); + if (buf[0] == 'f') + regulator_set_mode(reg, REGULATOR_MODE_FAST); + else + regulator_set_mode(reg, REGULATOR_MODE_NORMAL); + return size; +} + +static ssize_t pt_mode_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + REG_GET(); + if (regulator_get_mode(reg) == REGULATOR_MODE_FAST) + return snprintf(buf, 5, "fast\n"); + else + return snprintf(buf, 7, "normal\n"); +} + +static ssize_t pt_val_fset(struct device *d, struct device_attribute *attr, + const char *buf, size_t size) +{ + int i, ret; + ret = sscanf(buf, "%u", &i); + if (ret != 1) + return -EINVAL; + + if (!freg) { + freg = regulator_get(NULL, "stmp3xxx-bl-1"); + if (!freg || IS_ERR(freg)) { + freg = NULL ; return -ENODEV; + } + } + regulator_set_mode(freg, REGULATOR_MODE_NORMAL); + + if (!regulator_set_current_limit(freg, i, i)) + printk(KERN_ERR "got backlight reg\n"); + else + printk(KERN_ERR "failed to get backlight reg"); + + return size; +} + + +static ssize_t pt_val_set(struct device *d, struct device_attribute *attr, + const char *buf, size_t size) +{ + int i, ret; + REG_GET(); + + ret = sscanf(buf, "%u", &i); + if (ret != 1) + return -EINVAL; + + mutex_lock(&run_mutex); + if (!regulator_set_current_limit(reg, i, i)) { + mod_timer(&pt_timer, + jiffies + msecs_to_jiffies(timer_delay)); + return size; + } else { + mutex_unlock(&run_mutex); + return -EPERM; + } + +} + +static ssize_t pt_val_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + REG_GET(); + return sprintf(buf, "%d\n", regulator_get_current_limit(reg)); +} + +static ssize_t pt_timeout_set(struct device *d, struct device_attribute *attr, + const char *buf, size_t size) +{ + int i, ret; + REG_GET(); + + ret = sscanf(buf, "%u", &i); + if (ret != 1) + return -EINVAL; + + mutex_lock(&run_mutex); + timer_delay = 1000*i ; + mutex_unlock(&run_mutex); + + return size; +} + +static ssize_t pt_timeout_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + REG_GET(); + return sprintf(buf, "%d\n", timer_delay); +} + +static DEVICE_ATTR(mode, 0644, pt_mode_show, pt_mode_set); +static DEVICE_ATTR(val, 0644, pt_val_show, pt_val_set); +static DEVICE_ATTR(fval, 0644, pt_val_show, pt_val_fset); +static DEVICE_ATTR(timeout, 0644, pt_timeout_show, pt_timeout_set); + +static int stmp3xxx_power_test_remove(struct platform_device *pdev) +{ + if (reg) + regulator_put(reg); + + device_remove_file(&pdev->dev, &dev_attr_mode); + device_remove_file(&pdev->dev, &dev_attr_val); + device_remove_file(&pdev->dev, &dev_attr_timeout); + device_remove_file(&pdev->dev, &dev_attr_fval); + return 0; +} + +static int stmp3xxx_power_test_probe(struct platform_device *pdev) +{ + init_timer(&pt_timer); + pt_timer.data = 0; + pt_timer.function = timer_func; + + device_create_file(&pdev->dev, &dev_attr_mode); + device_create_file(&pdev->dev, &dev_attr_val); + device_create_file(&pdev->dev, &dev_attr_fval); + device_create_file(&pdev->dev, &dev_attr_timeout); + return 0; +} + +static struct platform_driver stmp3xxx_power_test_driver = { + .probe = stmp3xxx_power_test_probe, + .remove = stmp3xxx_power_test_remove, + .driver = { + .name = "stmp3xxx-power-test", + .owner = THIS_MODULE, + }, +}; + +struct platform_device stmp3xxx_pt = { + .name = "stmp3xxx-power-test", + .id = -1, +}; + +static int __init stmp3xxx_power_test_init(void) +{ + + platform_device_register(&stmp3xxx_pt); + return platform_driver_register(&stmp3xxx_power_test_driver); +} + +static void __exit stmp3xxx_power_test_exit(void) +{ + platform_driver_unregister(&stmp3xxx_power_test_driver); + platform_device_unregister(&stmp3xxx_pt); +} + +MODULE_AUTHOR("<sed@embeddedalley.com>"); +MODULE_DESCRIPTION("Power test driver"); +MODULE_LICENSE("GPL"); + +module_init(stmp3xxx_power_test_init); +module_exit(stmp3xxx_power_test_exit); diff --git a/arch/arm/mach-stmp3xxx/power.c b/arch/arm/mach-stmp3xxx/power.c new file mode 100644 index 000000000000..238b273865d1 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/power.c @@ -0,0 +1,502 @@ +/* + * Freescale STMP378X voltage regulator low-level driver + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG */ + +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <mach/power.h> +#include <mach/regs-power.h> + +static int get_voltage(struct stmp3xxx_regulator *sreg) +{ + struct stmp3xxx_platform_regulator_data *rdata = sreg->rdata; + u32 val = __raw_readl(rdata->control_reg) & 0x1f; + int uv = rdata->min_voltage + val * + (rdata->max_voltage - rdata->min_voltage) / 0x1f; + return uv; +} + +static int get_bo_voltage(struct stmp3xxx_regulator *sreg) +{ + int uv; + int offs; + + if (!sreg->parent) + return -EINVAL; + + uv = get_voltage(sreg->parent); + offs = (__raw_readl(sreg->parent->rdata->control_reg) & ~0x700) >> 8; + return uv - 25000*offs; +} + +static int set_voltage(struct stmp3xxx_regulator *sreg, int uv) +{ + u32 val, reg, i; + + pr_debug("%s: uv %d, min %d, max %d\n", __func__, + uv, sreg->rdata->min_voltage, sreg->rdata->max_voltage); + + if (uv < sreg->rdata->min_voltage || uv > sreg->rdata->max_voltage) + return -EINVAL; + + val = (uv - sreg->rdata->min_voltage) * 0x1f / + (sreg->rdata->max_voltage - sreg->rdata->min_voltage); + reg = (__raw_readl(sreg->rdata->control_reg) & ~0x1f); + pr_debug("%s: calculated val %d\n", __func__, val); + __raw_writel(val | reg, sreg->rdata->control_reg); + for (i = 20; i; i--) { + if (HW_POWER_STS_RD() & BM_POWER_STS_DC_OK) + break; + udelay(1); + } + + if (i) + goto out; + + __raw_writel(val | reg, sreg->rdata->control_reg); + for (i = 40000; i; i--) { + if (HW_POWER_STS_RD() & BM_POWER_STS_DC_OK) + break; + udelay(1); + } + + if (i) + goto out; + + for (i = 40000; i; i--) { + if (HW_POWER_STS_RD() & BM_POWER_STS_DC_OK) + break; + udelay(1); + } + +out: + return !i; +} + +static int set_bo_voltage(struct stmp3xxx_regulator *sreg, int bo_uv) +{ + int uv; + int offs; + u32 reg; + int i; + + if (!sreg->parent) + return -EINVAL; + + uv = get_voltage(sreg->parent); + offs = (uv - bo_uv) / 25000; + if (offs < 0 || offs > 7) + return -EINVAL; + + reg = (__raw_readl(sreg->parent->rdata->control_reg) & ~0x700); + pr_debug("%s: calculated offs %d\n", __func__, offs); + __raw_writel((offs << 8) | reg, sreg->parent->rdata->control_reg); + + for (i = 10000; i; i--) { + if (HW_POWER_STS_RD() & BM_POWER_STS_DC_OK) + break; + udelay(1); + } + + if (i) + goto out; + + for (i = 10000; i; i--) { + if (HW_POWER_STS_RD() & BM_POWER_STS_DC_OK) + break; + udelay(1); + } + +out: + return !i; +} + +static int enable(struct stmp3xxx_regulator *sreg) +{ + /* XXX: TODO */ + return 0; +} + +static int disable(struct stmp3xxx_regulator *sreg) +{ + /* XXX: TODO */ + return 0; +} + +static int is_enabled(struct stmp3xxx_regulator *sreg) +{ + /* XXX: TODO */ + return 1; +} + +static int set_mode(struct stmp3xxx_regulator *sreg, int mode) +{ + int ret = 0; + u32 val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = __raw_readl(sreg->rdata->control_reg); + __raw_writel(val | (1 << 17), sreg->rdata->control_reg); + break; + + case REGULATOR_MODE_NORMAL: + val = __raw_readl(sreg->rdata->control_reg); + __raw_writel(val & ~(1<<17), sreg->rdata->control_reg); + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int get_mode(struct stmp3xxx_regulator *sreg) +{ + u32 val = __raw_readl(sreg->rdata->control_reg) & (1 << 17); + + return val ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static struct regulation_constraints vddd_constraints = { + .name = "vddd", + .min_uV = 800000, + .max_uV = 1575000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .input_uV = 5000000, +}; + +static struct stmp3xxx_platform_regulator_data vddd_data = { + .name = "vddd", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .set_mode = set_mode, + .get_mode = get_mode, + .control_reg = HW_POWER_VDDDCTRL_ADDR, + .min_voltage = 800000, + .max_voltage = 1575000, + .constraints = &vddd_constraints, +}; + +static struct stmp3xxx_platform_regulator_data vdddbo_data = { + .name = "vddd_bo", + .parent_name = "vddd", + .set_voltage = set_bo_voltage, + .get_voltage = get_bo_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .set_mode = set_mode, + .get_mode = get_mode, + .min_voltage = 800000, + .max_voltage = 1575000, + .constraints = &vddd_constraints, +}; + +static struct platform_device vddd_reg = { + .name = "stmp3xxx_reg", + .id = 1, + .dev = { + .platform_data = &vddd_data, + }, +}; + +static struct platform_device vdddbo_reg = { + .name = "stmp3xxx_reg", + .id = 4, + .dev = { + .platform_data = &vdddbo_data, + }, +}; + +static struct regulation_constraints vdda_constraints = { + .name = "vdda", + .min_uV = 1500000, + .max_uV = 2275000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .input_uV = 5000000, +}; + +static struct stmp3xxx_platform_regulator_data vdda_data = { + .name = "vdda", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .set_mode = set_mode, + .get_mode = get_mode, + .control_reg = HW_POWER_VDDACTRL_ADDR, + .min_voltage = 1500000, + .max_voltage = 2275000, + .constraints = &vdda_constraints, +}; + +static struct platform_device vdda_reg = { + .name = "stmp3xxx_reg", + .id = 2, + .dev = { + .platform_data = &vdda_data, + }, +}; + +static struct regulation_constraints vddio_constraints = { + .name = "vddio", + .min_uV = 2800000, + .max_uV = 3575000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .input_uV = 5000000, +}; + +static struct stmp3xxx_platform_regulator_data vddio_data = { + .name = "vddio", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .set_mode = set_mode, + .get_mode = get_mode, + .control_reg = HW_POWER_VDDIOCTRL_ADDR, + .min_voltage = 2800000, + .max_voltage = 3575000, + .constraints = &vddio_constraints, +}; + +static struct platform_device vddio_reg = { + .name = "stmp3xxx_reg", + .id = 3, + .dev = { + .platform_data = &vddio_data, + }, +}; + +/* now the current regulators */ +/* Restriction: .... no set_current call on root regulator */ +static int main_add_current(struct stmp3xxx_regulator *sreg, + int uA) +{ + + pr_debug("%s: enter reg %s, uA=%d\n", + __func__, sreg->regulator.name, uA); + if (uA > 0 && (sreg->cur_current + uA > sreg->rdata->max_current)) + return -EINVAL; + else + sreg->cur_current += uA; + return 0; +} + +static int cur_reg_set_current(struct stmp3xxx_regulator *sreg, int uA) +{ + int ret = 0; + unsigned long flags; + + pr_debug("%s: enter reg %s, uA=%d\n", + __func__, sreg->regulator.name, uA); + + if (sreg->parent) { + spin_lock_irqsave(&sreg->parent->lock, flags); + ret = main_add_current(sreg->parent, uA - sreg->cur_current); + spin_unlock_irqrestore(&sreg->parent->lock, flags); + } + + + if ((!ret) || (!sreg->parent)) + goto out; + + if (sreg->mode == REGULATOR_MODE_FAST) + return ret; + + while (ret) { + wait_event(sreg->parent->wait_q , + (uA - sreg->cur_current < + sreg->parent->rdata->max_current - + sreg->parent->cur_current)); + spin_lock_irqsave(&sreg->parent->lock, flags); + ret = main_add_current(sreg->parent, uA - sreg->cur_current); + spin_unlock_irqrestore(&sreg->parent->lock, flags); + } +out: + if (sreg->parent && (uA - sreg->cur_current < 0)) + wake_up_all(&sreg->parent->wait_q); + sreg->cur_current = uA; + return 0; + +} + +static int cur_reg_get_current(struct stmp3xxx_regulator *sreg) +{ + return sreg->cur_current; +} + +static int enable_cur_reg(struct stmp3xxx_regulator *sreg) +{ + /* XXX: TODO */ + return 0; +} + +static int disable_cur_reg(struct stmp3xxx_regulator *sreg) +{ + /* XXX: TODO */ + return 0; +} + +static int cur_reg_is_enabled(struct stmp3xxx_regulator *sreg) +{ + /* XXX: TODO */ + return 1; +} + +static int cur_reg_set_mode(struct stmp3xxx_regulator *sreg, int mode) +{ + int ret = 0; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + case REGULATOR_MODE_FAST: + sreg->mode = mode; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int cur_reg_get_mode(struct stmp3xxx_regulator *sreg) +{ + return sreg->mode; +} + +static struct regulation_constraints current_constraints = { + .name = "current_constraints", + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT | + REGULATOR_CHANGE_MODE, + .max_uA = 0x7fffffff, + .min_uA = 0x0, +}; + +static struct stmp3xxx_platform_regulator_data overall_cur_data = { + .name = "overall_current", + .set_current = cur_reg_set_current, + .get_current = cur_reg_get_current, + .enable = enable_cur_reg, + .disable = disable_cur_reg, + .is_enabled = cur_reg_is_enabled, + .set_mode = cur_reg_set_mode, + .get_mode = cur_reg_get_mode, + .max_current = 0x7fffffff, + .constraints = ¤t_constraints, +}; + +static struct platform_device overall_cur_reg = { + .name = "stmp3xxx_reg", + .id = 100, + .dev = { + .platform_data = &overall_cur_data, + }, +}; + +static struct stmp3xxx_platform_regulator_data sibling_cur_data = { + .parent_name = "overall_current", + .set_current = cur_reg_set_current, + .get_current = cur_reg_get_current, + .enable = enable_cur_reg, + .disable = disable_cur_reg, + .is_enabled = cur_reg_is_enabled, + .set_mode = cur_reg_set_mode, + .get_mode = cur_reg_get_mode, + .constraints = ¤t_constraints, +}; + +#if 0 +static struct platform_device *sibling_current_devices[100]; +static int sibling_current_devices_num; + +int stmp3xxx_platform_add_regulator(const char *name, int count) +{ + int i; + pr_debug("%s: name %s, count %d\n", __func__, name, count); + for (i = sibling_current_devices_num; + i < sibling_current_devices_num + count; + i++) { + struct platform_device *p = + kzalloc(sizeof(struct platform_device), GFP_KERNEL); + struct stmp3xxx_platform_regulator_data *d = + kzalloc(sizeof(struct stmp3xxx_platform_regulator_data), + GFP_KERNEL); + if (!d || !p) { + int j; + for (j = i-1; j >= sibling_current_devices_num; j--) { + struct platform_device *q = + sibling_current_devices[j]; + kfree(q->dev.platform_data); + kfree(q); + } + return -ENOMEM; + } + p->name = kstrdup("stmp3xxx_reg", GFP_KERNEL); + p->id = 101 + i; + memcpy(d, &sibling_cur_data, sizeof(sibling_cur_data)); + d->parent_name = kstrdup(sibling_cur_data.parent_name, + GFP_KERNEL); + snprintf(d->name, 80, "%s-%d", + name, i - sibling_current_devices_num + 1); + p->dev.platform_data = d; + sibling_current_devices[i] = p; + } + sibling_current_devices_num += count; + return 0; +} +#endif +static struct platform_device *voltage_devices[] = { + &vddd_reg, + &vdda_reg, + &vddio_reg, + &vdddbo_reg, +}; + +static int __init regulators_init(void) +{ + HW_POWER_VDDIOCTRL_WR(0x00022614); + platform_add_devices(voltage_devices, + ARRAY_SIZE(voltage_devices)); + platform_device_register(&overall_cur_reg); + return 0; +// return platform_add_devices(sibling_current_devices, +// sibling_current_devices_num); +} +subsys_initcall(regulators_init); diff --git a/arch/arm/mach-stmp3xxx/rotdec.c b/arch/arm/mach-stmp3xxx/rotdec.c new file mode 100644 index 000000000000..d390102c1559 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/rotdec.c @@ -0,0 +1,39 @@ +/* + * Freescale STMP378X Rotary Encoder module pin multiplexing + * + * Author: Drew Benedetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include <mach/pins.h> +#include "pinmux.h" + +#define TITLE "stmp3xxx-rotdec" + +int rotdec_pinmux_request(void) +{ + return stmp3xxx_request_pin_group(&rotdec_pins, TITLE); +} +EXPORT_SYMBOL_GPL(rotdec_pinmux_request); + +void rotdec_pinmux_free(void) +{ + stmp3xxx_release_pin_group(&spdif_pins, TITLE); +} +EXPORT_SYMBOL_GPL(rotdec_pinmux_free); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>"); diff --git a/arch/arm/mach-stmp3xxx/sleep.S b/arch/arm/mach-stmp3xxx/sleep.S new file mode 100644 index 000000000000..c4bb4a331465 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/sleep.S @@ -0,0 +1,540 @@ +/* + * Freescale STMP37XX/STMP378X low level sleep states support + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <mach/hardware.h> +#include <asm/pgtable-hwdef.h> +#include <mach/regs-power.h> +#include <mach/regs-clkctrl.h> +#include "sleep.h" + +#define HW_DRAM_CTL06 IO_ADDRESS(0x800E0018) +#define HW_DRAM_CTL08 IO_ADDRESS(0x800E0020) +#define HW_EMI_STAT IO_ADDRESS(0x80020010) +#define HW_RTC_PERSISTENT0 \ + IO_ADDRESS(0x8005C060) + +#define PHYS_RAM_START 0x40000000 + +.global cpu_arm926_switch_mm + + .text + +.align 8 +ENTRY(stmp37xx_cpu_standby) + @ save registers on stack + stmfd sp!, {r0 - r9, lr} + + adr r9, __stmp_temp_stack + + @ clean cache + ldr r1, __stmp_flush_cache_addr + mov lr, pc + mov pc, r1 + + @ put DRAM into self refresh + mov r0, #(HW_DRAM_CTL08 & 0x000000FF) + orr r0, r0, #(HW_DRAM_CTL08 & 0x0000FF00) + orr r0, r0, #(HW_DRAM_CTL08 & 0x00FF0000) + orr r0, r0, #(HW_DRAM_CTL08 & 0xFF000000) + ldr r1, [r0] + orr r1, r1, #(1 << 8) + str r1, [r0] + @ wait for it to actually happen + mov r0, #(HW_EMI_STAT & 0x000000FF) + orr r0, r0, #(HW_EMI_STAT & 0x0000FF00) + orr r0, r0, #(HW_EMI_STAT & 0x00FF0000) + orr r0, r0, #(HW_EMI_STAT & 0xFF000000) +1: ldr r1, [r0] + teq r1, #(1 << 1) + beq 1b + nop + nop + nop + nop + nop + +#ifdef CONFIG_STMP378X_RAM_FREQ_SCALING + @ RAM to clk from xtal + mov lr, pc + b stmp3xxx_ram_save_timings + mov lr, pc + b stmp3xxx_ram_24M_set_timings + + mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) + ldr r4, [r0] + mov r1, #(1<<6) + str r1, [r0, #4] +1: ldr r1, [r0] + tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 1b + + @ save RAM divisors + mov r0, #(HW_CLKCTRL_FRAC_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0xFF000000) + ldr r8, [r0] + and r8, r8, #(0x3F << 8) + lsr r8, r8, #8 + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) + ldr r7, [r0] + and r7, r7, #0x3F + + @ shut the PLL down + mov r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0xFF000000) + mov r1, #(1<<16) + str r1, [r0, #0x08] @ clear + + @ set vddd to minimum + mov r0, #(HW_POWER_VDDDCTRL_ADDR & 0x000000FF) + orr r0, r0, #(HW_POWER_VDDDCTRL_ADDR & 0x0000FF00) + orr r0, r0, #(HW_POWER_VDDDCTRL_ADDR & 0x00FF0000) + orr r0, r0, #(HW_POWER_VDDDCTRL_ADDR & 0xFF000000) + ldr r6, [r0] + bic r1, r6, #0xFF + bic r1, r1, #0x30 + orr r1, r1, #0xa + str r1, [r0] + /* now wait 1000 us = 24000 cycles */ + mov r0, #24 << 10 +3: sub r0, r0, #1 + cmp r0, #0 + bne 3b + nop +#endif + + @ do enter standby + mov r0, #(HW_CLKCTRL_CPU_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CPU_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CPU_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CPU_ADDR & 0xFF000000) + mov r1, #(1<<12) + str r1, [r0, #4] + mov r2, #0 + mcr p15, 0, r2, c7, c0, 4 + nop + + @ sleeping now... + + @ remove INTERRUPT_WAIT bit + str r1, [r0, #8] + nop + nop + nop + +#ifdef CONFIG_STMP378X_RAM_FREQ_SCALING + @ restore vddd + mov r0, #(HW_POWER_VDDDCTRL_ADDR & 0x000000FF) + orr r0, r0, #(HW_POWER_VDDDCTRL_ADDR & 0x0000FF00) + orr r0, r0, #(HW_POWER_VDDDCTRL_ADDR & 0x00FF0000) + orr r0, r0, #(HW_POWER_VDDDCTRL_ADDR & 0xFF000000) + ldr r1, [r0] + str r6, [r0] + /* now wait 1000 us = 24000 cycles */ + mov r0, #24 << 10 +12: sub r0, r0, #1 + cmp r0, #0 + bne 12b + nop + + @ put the PLL back up + mov r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_PLLCTRL0_ADDR & 0xFF000000) + mov r1, #(1<<16) + str r1, [r0, #0x04] @ set + /* now wait 10 us = 240 cycles */ + mov r0, #240 +11: sub r0, r0, #1 + cmp r0, #0 + bne 11b + nop + + @ set divisors and switch EMI back to PLL + mov lr, pc + b stmp3xxx_ram_restore_timings + mov lr, pc + b __stmp_emi_set_values + + mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) + mov r1, #(1<<6) + str r1, [r0, #8] + + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) + ldr r1, [r0] + bic r1, #BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE + str r1, [r0] +#endif + + @ restore normal DRAM mode + mov r0, #(HW_DRAM_CTL08 & 0x000000FF) + orr r0, r0, #(HW_DRAM_CTL08 & 0x0000FF00) + orr r0, r0, #(HW_DRAM_CTL08 & 0x00FF0000) + orr r0, r0, #(HW_DRAM_CTL08 & 0xFF000000) + ldr r1, [r0] + bic r1, r1, #(1 << 8) + str r1, [r0] + @ wait for it to actually happen + mov r0, #(HW_EMI_STAT & 0x000000FF) + orr r0, r0, #(HW_EMI_STAT & 0x0000FF00) + orr r0, r0, #(HW_EMI_STAT & 0x00FF0000) + orr r0, r0, #(HW_EMI_STAT & 0xFF000000) +102: ldr r1, [r0] + tst r1, #(1 << 1) + bne 102b + + nop + nop + nop + + @ restore regs and return + ldmfd sp!, {r0 - r9, pc} + + .space 0x100 +__stmp_temp_stack: + .word 0 + +#ifdef CONFIG_STMP378X_RAM_FREQ_SCALING +#include "emi.inc" +#endif + +__stmp_flush_cache_addr: + .word arm926_flush_kern_cache_all + +ENTRY(stmp_standby_alloc_sz) + .word . - stmp37xx_cpu_standby + +ENTRY(stmp37xx_cpu_suspend) + @ save registers on stack + stmfd sp!, {r1 - r12, lr} + + @ save context + mov r0, #0xd3 @ SVC, Interrupts disabled + msr cpsr, r0 + mov r1, #0xC0000000 + ldr r1, [r1] + mrc p15, 0, r0, c1, c0, 0 + str r0, [r1, #MMUCTL_OFFS] + mrc p15, 0, r0, c15, c1, 0 + str r0, [r1, #MMUCPACCESS_OFS] + mrc p15, 0, r0, c2, c0, 0 + str r0, [r1, #MMUTTB_OFFS] + mrc p15, 0, r0, c3, c0, 0 + str r0, [r1, #MMUDOMAIN_OFFS] + mrc p15, 0, r0, c13, c0, 0 + str r0, [r1, #MMUPID_OFFS] + + str sp, [r1, #SVC_SP_OFFS] + mrs r0, spsr + str r0, [r1, #SVC_SPSR_OFFS] + + add r2, r1, #FIQ_SPSR_OFFS + mov r0, #0xd1 @ FIQ, Interrupts disabled + msr cpsr, r0 + mrs r3, spsr + stmia r2!, {r3, r8-r12, sp, lr} + + add r2, r1, #ABT_SPSR_OFFS + mov r0, #0xd7 @ ABT, Interrupts disabled + msr cpsr, r0 + mrs r3, spsr + stmia r2!, {r3, sp, lr} + + add r2, r1, #IRQ_SPSR_OFFS + mov r0, #0xd2 @ IRQ, Interrupts disabled + msr cpsr, r0 + mrs r3, spsr + stmia r2!, {r3, sp, lr} + + add r2, r1, #UND_SPSR_OFFS + mov r0, #0xdb @ UND, Interrupts disabled + msr cpsr, r0 + mrs r3, spsr + stmia r2!, {r3, sp, lr} + + add r2, r1, #SYS_SP_OFFS + mov r0, #0xdf @ SYS, Interrupts disabled + msr cpsr, r0 + stmia r2!, {sp, lr} + + add r2, r1, #SVC_R8_OFFS + mov r0, #0xd3 @ Back to SVC, Interrupts disabled + msr cpsr, r0 + + @ save entry point + sub r1, r1, #(0xC0000000 - PHYS_RAM_START) + mov r0, #0xC0000000 + str r1, [r0] + ldr r1, __stmp_resume_point + sub r1, r1, #(0xC0000000 - PHYS_RAM_START) + str r1, [r0, #4] + mov r0, #0 + + @ clean cache + ldr r1, __stmp_flush_cache_addr2 + mov lr, pc + mov pc, r1 + + @ enable internal xtal + mov r2, #(HW_POWER_MINPWR_ADDR & 0x000000FF) + orr r2, r2, #(HW_POWER_MINPWR_ADDR & 0x0000FF00) + orr r2, r2, #(HW_POWER_MINPWR_ADDR & 0x00FF0000) + orr r2, r2, #(HW_POWER_MINPWR_ADDR & 0xFF000000) + ldr r1, [r2] + orr r1, r1, #(1<<9) + str r1, [r2] + orr r1, r1, #(1<<8) + str r1, [r2] + + @ enable RTC/RAM clocks + mov r0, #(HW_RTC_PERSISTENT0 & 0x000000FF) + orr r0, r0, #(HW_RTC_PERSISTENT0 & 0x0000FF00) + orr r0, r0, #(HW_RTC_PERSISTENT0 & 0x00FF0000) + orr r0, r0, #(HW_RTC_PERSISTENT0 & 0xFF000000) + mov r1, #((1<<4)|(1<<5)|1) + str r1, [r0, #4] + + @ put DRAM into self refresh + mov r0, #(HW_DRAM_CTL08 & 0x000000FF) + orr r0, r0, #(HW_DRAM_CTL08 & 0x0000FF00) + orr r0, r0, #(HW_DRAM_CTL08 & 0x00FF0000) + orr r0, r0, #(HW_DRAM_CTL08 & 0xFF000000) + ldr r1, [r0] + orr r1, r1, #(1 << 8) + str r1, [r0] + @ wait for it to actually happen + mov r0, #(HW_EMI_STAT & 0x000000FF) + orr r0, r0, #(HW_EMI_STAT & 0x0000FF00) + orr r0, r0, #(HW_EMI_STAT & 0x00FF0000) + orr r0, r0, #(HW_EMI_STAT & 0xFF000000) +1: ldr r1, [r0] + teq r1, #(1 << 1) + beq 1b + nop + nop + nop + nop + nop + nop + + @ power off RAM + mov r0, #(HW_DRAM_CTL06 & 0x000000FF) + orr r0, r0, #(HW_DRAM_CTL06 & 0x0000FF00) + orr r0, r0, #(HW_DRAM_CTL06 & 0x00FF0000) + orr r0, r0, #(HW_DRAM_CTL06 & 0xFF000000) + ldr r1, [r0] + orr r1, r1, #(1<<24) + str r1, [r0] + nop + nop + nop + nop + + @ do enter sleep + mov r0, #(HW_POWER_RESET_ADDR & 0x000000FF) + orr r0, r0, #(HW_POWER_RESET_ADDR & 0x0000FF00) + orr r0, r0, #(HW_POWER_RESET_ADDR & 0x00FF0000) + orr r0, r0, #(HW_POWER_RESET_ADDR & 0xFF000000) + mov r1, #0xFF000000 + orr r1, r1, #0x00FF0000 + str r1, [r0, #8] + mov r1, #0x3E000000 + orr r1, r1, #0x00770000 + str r1, [r0, #4] + mov r1, #2 + str r1, [r0, #8] + mov r1, #1 + str r1, [r0, #4] + nop + nop + nop + nop + nop + nop + + @ sleeping now... + +__restore_context: + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer + mcr p15, 0, r0, c8, c7, 0 @ Invalidate TLBs + mcr p15, 0, r0, c7, c7, 0 @ Invalidate I & D cache + nop + nop + + mov r0, #0xd3 + msr cpsr, r0 + + bl __create_temp_page_tables + mov r3, r4 + + mov r1, #PHYS_RAM_START + ldr r1, [r1] + ldr r2, [r1, #MMUDOMAIN_OFFS] + ldr r4, [r1, #MMUCPACCESS_OFS] + ldr r5, [r1, #MMUPID_OFFS] + ldr r6, =__resume_after_mmu + ldr r7, [r1, #MMUCTL_OFFS] + ldr r8, [r1, #MMUTTB_OFFS] + add r1, r1, #(0xC0000000 - PHYS_RAM_START) + mov r0, #0 +@ mcr p15, 0, r4, c15, c1, 0 @ cpaccess + mcr p15, 0, r5, c13, c0, 0 @ pid + mcr p15, 0, r2, c3, c0, 0 @ domain + mcr p15, 0, r3, c2, c0, 0 @ ttb + b 1f + .align 5 +1: mov r0, r0 + mcr p15, 0, r7, c1, c0, 0 @ mmuctl + nop + mrc p15, 0, r0, c3, c0, 0 @ read id + mov r0, r0 + mov r0, r0 + sub pc, r6, r5, lsr #32 + nop + nop + nop +__resume_after_mmu: + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ Invalidate TLBs + mcr p15, 0, r0, c7, c7, 0 @ Invalidate I & D cache + + mov r0, r8 + bl cpu_arm926_switch_mm + + mov r0, #0xd1 @FIQ, Interrupts disabled + ldr r2, [r1, #FIQ_SPSR_OFFS] + add r3, r1, #FIQ_R8_OFFS + msr cpsr, r0 + msr spsr, r2 + ldmia r3!, {r8-r12, sp, lr} + + mov r0, #0xd7 @ABT, Interrupts disabled + ldr r2, [r1, #ABT_SPSR_OFFS] + add r3, r1, #ABT_SP_OFFS + msr cpsr, r0 + msr spsr, r2 + ldmia r3!, {sp, lr} + + mov r0, #0xd2 @IRQ, Interrupts disabled + ldr r2, [r1, #IRQ_SPSR_OFFS] + add r3, r1, #IRQ_SP_OFFS + msr cpsr, r0 + msr spsr, r2 + ldmia r3!, {sp, lr} + + mov r0, #0xdb @UND, Interrupts disabled + ldr r2, [r1, #UND_SPSR_OFFS] + add r3, r1, #UND_SP_OFFS + msr cpsr, r0 + msr spsr, r2 + ldmia r3!, {sp, lr} + + mov r0, #0xdf @SYS, Interrupts disabled + add r3, r1, #SYS_SP_OFFS + msr cpsr, r0 + ldmia r3!, {sp, lr} + + mov r0, #0xd3 @SVC, interrupts disabled + ldr r2, [r1, #SVC_SPSR_OFFS] + ldr r3, [r1, #SVC_SP_OFFS] + msr cpsr, r0 + msr spsr, r2 + mov sp, r3 + +#if 0 + @ select CPU bypass, will be cleared afterwards + ldr r0, =HW_CLKCTRL_CLKSEQ_ADDR + ldr r2, =HW_CLKCTRL_HBUS_ADDR + ldr r4, =HW_CLKCTRL_CPU_ADDR + mov r1, #(1<<7) + ldr r3, [r2] + bic r3, r3, #BM_CLKCTRL_HBUS_DIV + orr r3, r3, #1 + ldr r5, [r4] + bic r5, r5, #BM_CLKCTRL_CPU_DIV_CPU + orr r5, r5, #1 + str r1, [r0, #4] + str r3, [r2] + str r5, [r4] +#endif + @ restore regs and return + ldmfd sp!, {r1 - r12, lr} + mov pc, lr + +__stmp_flush_cache_addr2: + .word arm926_flush_kern_cache_all +__stmp_resume_point: + .word __restore_context +ENTRY(stmp_s2ram_alloc_sz) + .word . - stmp37xx_cpu_suspend + +__create_temp_page_tables: + ldr r4, =(__temp_ttb - 0xC0000000 + PHYS_RAM_START) + + /* + * Clear the 16K level 1 swapper page table + */ + mov r0, r4 + mov r3, #0 + add r6, r0, #0x4000 +1: str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + teq r0, r6 + bne 1b + + /* + * Create identity mapping for the area close to where we are to + * cater for the MMU enable. + */ + mov r6, pc, lsr #20 @ kind of where we are + ldr r7, =(PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ) + + orr r3, r7, r6, lsl #20 @ flags + kernel base + str r3, [r4, r6, lsl #2] @ identity mapping + + mov r6, r6, lsl #20 + add r6, r6, #(0xC0000000-PHYS_RAM_START) + str r3, [r4, r6, lsr #18] + + mov pc, lr + .ltorg + + .section ".sdata", "a" + .align 14 +__temp_ttb: + .space 0x8000 diff --git a/arch/arm/mach-stmp3xxx/sleep.h b/arch/arm/mach-stmp3xxx/sleep.h new file mode 100644 index 000000000000..2d7414382bf0 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/sleep.h @@ -0,0 +1,113 @@ +/* + * Deep Sleep related defines + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __PM_H__ +#define __PM_H__ + +#include <mach/regs-clkctrl.h> + +#define MMUTTB1_MASK 0x00003FE0 +#define MMUTTBC_MASK 0xFFFFFFFC + +#define LINK_OFFS 0x08 +#define MMUCTL_OFFS 0x0C +#define MMUAUXCTL_OFFS 0x10 +#define MMUCPACCESS_OFS 0x14 +#define MMUTTB_OFFS 0x18 +#define MMUPID_OFFS 0x1C +#define MMUDOMAIN_OFFS 0x20 +#define SVC_R8_OFFS 0x2C +#define SVC_SP_OFFS 0x40 +#define SVC_SPSR_OFFS 0x44 +#define FIQ_SPSR_OFFS 0x48 +#define FIQ_R8_OFFS 0x4C +#define FIQ_SP_OFFS 0x60 +#define ABT_R8_OFFS 0x68 +#define ABT_SPSR_OFFS 0x7C +#define ABT_SP_OFFS 0x80 +#define IRQ_R8_OFFS 0x88 +#define IRQ_SPSR_OFFS 0x9C +#define IRQ_SP_OFFS 0xA0 +#define UND_SPSR_OFFS 0xA8 +#define UND_SP_OFFS 0xAC +#define SYS_SPSR_OFFS 0xB4 +#define SYS_SP_OFFS 0xB8 + +#ifndef __ASSEMBLER__ +#define SLEEP_DATA_FINGERPRINT 0xdeadbeef +struct sleep_data { + u32 fingerprint; + u32 wake_addr; + u32 link_addr; + u32 mmuctl; + u32 mmuauxctl; + u32 mmucpaccess; + u32 mmuttb; + u32 mmupid; + u32 mmudomain; + u32 svc_r6; + u32 svc_r7; + u32 svc_r8; + u32 svc_r9; + u32 svc_r10; + u32 svc_r11; + u32 svc_r12; + u32 svc_sp; + u32 svc_spsr; + u32 fiq_spsr; + u32 fiq_r8; + u32 fiq_r9; + u32 fiq_r10; + u32 fiq_r11; + u32 fiq_r12; + u32 fiq_sp; + u32 fiq_lr; + u32 abt_r8; + u32 abt_r9; + u32 abt_r10; + u32 abt_r11; + u32 abt_r12; + u32 abt_spsr; + u32 abt_sp; + u32 abt_lr; + u32 irq_r8; + u32 irq_r9; + u32 irq_r10; + u32 irq_r11; + u32 irq_r12; + u32 irq_spsr; + u32 irq_sp; + u32 irq_lr; + u32 und_spsr; + u32 und_sp; + u32 und_lr; + u32 sys_spsr; + u32 sys_sp; + u32 sys_lr; + u32 pinmux[0x100]; + u32 icoll_ctrl; + union { + u32 prio[0x10]; + u32 intr[0x80]; + } icoll; + u32 clks[16]; + u32 old_c00; + u32 old_c04; +}; + +#endif /* __ASSEMBLER__ */ +#endif /* __PM_H__ */ diff --git a/arch/arm/mach-stmp3xxx/spdif.c b/arch/arm/mach-stmp3xxx/spdif.c new file mode 100644 index 000000000000..4fab7f90d7f4 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/spdif.c @@ -0,0 +1,36 @@ +/* + * Pin multiplexing for SPDIF transmitter on STMP3780 dev. board + * + * Author: Vladimir Barinov <vbarinov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include "common.h" + +int spdif_pinmux_request(void) +{ + return stmp3xxx_request_pin_group(&spdif_pins, "spdif"); +} +EXPORT_SYMBOL_GPL(spdif_pinmux_request); + +void spdif_pinmux_free(void) +{ + stmp3xxx_release_pin_group(&spdif_pins, "spdif"); +} +EXPORT_SYMBOL_GPL(spdif_pinmux_free); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vladimir Barinov <vbarinov@embeddedalley.com>"); diff --git a/arch/arm/mach-stmp3xxx/spi.c b/arch/arm/mach-stmp3xxx/spi.c new file mode 100644 index 000000000000..fb310a8b74bd --- /dev/null +++ b/arch/arm/mach-stmp3xxx/spi.c @@ -0,0 +1,106 @@ +/* + * Freescale STMP37XX/STMP378X SPI module pin multiplexing + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/spi/spi.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <mach/stmp3xxx.h> +#include "common.h" + +/* + These pins are: + SCK (SSPx_SCK) + MOSI (SSPx_CMD) + MISO (SSPx_DATA0) + SSn (SSPx_DATA3) + Please add new pins in the same order, thanks :) +*/ +static struct pin_desc ssp_pins_desc[2][4] = { + [0] = { + { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0, }, + { PINID_SSP1_CMD, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, }, + { PINID_SSP1_DATA0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, }, + { PINID_SSP1_DATA3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, }, + }, + [1] = { +#if defined(CONFIG_ARCH_STMP37XX) + { PINID_GPMI_IRQ, PIN_FUN3, PIN_8MA, PIN_3_3V, 0, }, + { PINID_GPMI_RDY2, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, }, + { PINID_EMI_CE2N, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, }, + { PINID_GPMI_D03, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, }, +#elif defined(CONFIG_ARCH_STMP378X) + { PINID_GPMI_WRN, PIN_FUN3, PIN_8MA, PIN_3_3V, 0, }, + { PINID_GPMI_RDY1, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, }, + { PINID_GPMI_D00, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, }, + { PINID_GPMI_D03, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, }, +#endif + }, +}; + +static struct pin_group ssp_pins[2] = { + [0] = { + .pins = ssp_pins_desc[0], + .nr_pins = ARRAY_SIZE(ssp_pins_desc[0]), + }, + [1] = { + .pins = ssp_pins_desc[1], + .nr_pins = ARRAY_SIZE(ssp_pins_desc[1]), + }, +}; + +int stmp37xx_spi_pins_request(char *id, int ssp) +{ + return stmp3xxx_request_pin_group(&ssp_pins[ssp-1], id); +} +EXPORT_SYMBOL_GPL(stmp37xx_spi_pins_request); + +void stmp37xx_spi_pins_release(char *id, int ssp) +{ + stmp3xxx_release_pin_group(&ssp_pins[ssp-1], id); +} +EXPORT_SYMBOL_GPL(stmp37xx_spi_pins_release); + +int stmp37xx_spi_enc_init(void *spi_dev) +{ + struct spi_device *spi = spi_dev; + struct stmp37xx_spi_platform_data *data = spi->dev.platform_data; + + gpio_request(data->irq_pin, spi->dev.bus_id); + gpio_direction_input(data->irq_pin); + stmp3xxx_configure_irq(data->irq_pin, IRQ_TYPE_EDGE_FALLING); + spi->irq = gpio_to_irq(data->irq_pin); + dev_dbg(&spi->dev, "Assigned IRQ %d(%s)\n", spi->irq, __func__); + return 0; +} + +int stmp37xx_spi_enc_release(void *spi_dev) +{ + struct spi_device *spi = spi_dev; + struct stmp37xx_spi_platform_data *data = spi->dev.platform_data; + + stmp3xxx_configure_irq(data->irq_pin, IRQ_TYPE_NONE); + gpio_free(data->irq_pin); + return 0; +} + +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-stmp3xxx/stmp378x.c b/arch/arm/mach-stmp3xxx/stmp378x.c new file mode 100644 index 000000000000..61eeb46d257e --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp378x.c @@ -0,0 +1,397 @@ +/* + * Freescale STMP378X platform support + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/sysdev.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/input.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <asm/dma.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> + +#include <mach/ocram-malloc.h> + +#include <mach/lcdif.h> +#include <mach/system.h> +#include <mach/platform.h> +#include <mach/regs-icoll.h> +#include <mach/regs-apbh.h> +#include <mach/regs-apbx.h> + +#include "common.h" + +/* + * IRQ handling + */ +static void stmp378x_ack_irq(unsigned int irq) +{ + /* Tell ICOLL to release IRQ line */ + HW_ICOLL_VECTOR_WR(0x0); + + /* ACK current interrupt */ + HW_ICOLL_LEVELACK_WR(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0); + + /* Barrier */ + (void) HW_ICOLL_STAT_RD(); +} + +static void stmp378x_mask_irq(unsigned int irq) +{ + /* IRQ disable */ + HW_ICOLL_INTERRUPTn_CLR(irq, BM_ICOLL_INTERRUPTn_ENABLE); +} + +static void stmp378x_unmask_irq(unsigned int irq) +{ + /* IRQ enable */ + HW_ICOLL_INTERRUPTn_SET(irq, BM_ICOLL_INTERRUPTn_ENABLE); +} + +static struct irq_chip stmp378x_chip = { + .ack = stmp378x_ack_irq, + .mask = stmp378x_mask_irq, + .unmask = stmp378x_unmask_irq, +}; + +static void stmp378x_gpio_ack_irq(unsigned int irq) +{ + stmp3xxx_pin_ack_irq(irq); + stmp378x_ack_irq(irq); +} + +static struct irq_chip stmp378x_gpio_chip = { + .ack = stmp378x_gpio_ack_irq, + .mask = stmp378x_mask_irq, + .unmask = stmp378x_unmask_irq, +}; + +static int stmp378x_irq_is_gpio(int irq) +{ + return irq == IRQ_GPIO0 || irq == IRQ_GPIO1 || irq == IRQ_GPIO2; +} + +void __init stmp378x_init_irq(void) +{ + stmp3xxx_init_irq(&stmp378x_chip, + &stmp378x_gpio_chip, + stmp378x_irq_is_gpio); +} + +/* + * DMA interrupt handling + */ +void stmp3xxx_arch_dma_enable_interrupt(int channel) +{ + int dmabus = channel / 16; + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL1_SET(1 << (16 + (channel % 16))); + HW_APBH_CTRL2_SET(1 << (16 + (channel % 16))); + break; + + case STMP3XXX_BUS_APBX: + HW_APBX_CTRL1_SET(1 << (16 + (channel % 16))); + HW_APBX_CTRL2_SET(1 << (16 + (channel % 16))); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt); + +void stmp3xxx_arch_dma_clear_interrupt(int channel) +{ + int dmabus = channel / 16; + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL1_CLR(1 << (channel % 16)); + HW_APBH_CTRL2_CLR(1 << (channel % 16)); + break; + + case STMP3XXX_BUS_APBX: + HW_APBX_CTRL1_CLR(1 << (channel % 16)); + HW_APBX_CTRL2_CLR(1 << (channel % 16)); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt); + +int stmp3xxx_arch_dma_is_interrupt(int channel) +{ + int dmabus = channel / 16; + int r = 0; + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + r = HW_APBH_CTRL1_RD() & (1 << (channel % 16)); + break; + + case STMP3XXX_BUS_APBX: + r = HW_APBX_CTRL1_RD() & (1 << (channel % 16)); + break; + } + return r; +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt); + +void stmp3xxx_arch_dma_reset_channel(int channel) +{ + int dmabus = channel / 16; + unsigned chbit = 1 << (channel % 16); + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + /* Reset channel and wait for it to complete */ + HW_APBH_CTRL0_SET(chbit << + BP_APBH_CTRL0_RESET_CHANNEL); + while (HW_APBH_CTRL0_RD() & + (chbit << BP_APBH_CTRL0_RESET_CHANNEL)) + continue; + break; + + case STMP3XXX_BUS_APBX: + /* Reset channel and wait for it to complete */ + HW_APBX_CHANNEL_CTRL_SET( + BF_APBX_CHANNEL_CTRL_RESET_CHANNEL(chbit)); + while (HW_APBX_CHANNEL_CTRL_RD() & + BF_APBX_CHANNEL_CTRL_RESET_CHANNEL(chbit)) + continue; + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel); + +void stmp3xxx_arch_dma_freeze(int channel) +{ + int dmabus = channel / 16; + unsigned chbit = 1 << (channel % 16); + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL0_SET(1<<chbit); + break; + case STMP3XXX_BUS_APBX: + HW_APBX_CHANNEL_CTRL_SET(1<<chbit); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze); + +void stmp3xxx_arch_dma_unfreeze(int channel) +{ + int dmabus = channel / 16; + unsigned chbit = 1 << (channel % 16); + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL0_CLR(1<<chbit); + break; + case STMP3XXX_BUS_APBX: + HW_APBX_CHANNEL_CTRL_CLR(1<<chbit); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze); + +/* + * STMP378x dedicated pin groups + */ +static struct pin_desc i2c_pins_desc[] = { + { PINID_I2C_SCL, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_I2C_SDA, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, +}; + +struct pin_group i2c_pins = { + .pins = i2c_pins_desc, + .nr_pins = ARRAY_SIZE(i2c_pins_desc), +}; + +static struct pin_desc gpmi_pins_desc[] = { + { PINID_GPMI_CE0N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_CE1N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GMPI_CE2N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_CLE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_ALE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_WPN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY1, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D00, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D01, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D02, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D03, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D04, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D05, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D06, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D07, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY2, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_WRN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, +}; + +struct pin_group gpmi_pins = { + .pins = gpmi_pins_desc, + .nr_pins = ARRAY_SIZE(gpmi_pins_desc), +}; + +static struct pin_desc lcd_hx8238a_desc[] = { + { PINID_LCD_D00, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D01, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D02, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D03, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D04, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D05, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D06, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D07, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D08, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D09, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D10, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D11, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D12, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D13, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D14, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D15, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D16, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D17, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_RESET, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_VSYNC, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_HSYNC, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_ENABLE, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_DOTCK, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D13, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D12, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D11, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D10, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D09, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D08, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, +}; + +struct pin_group stmp378x_lcd_pins = { + .pins = lcd_hx8238a_desc, + .nr_pins = ARRAY_SIZE(lcd_hx8238a_desc), +}; + +unsigned stmp378x_lcd_spi_pins[] = { + [SPI_MOSI] = PINID_LCD_WR, + [SPI_SCLK] = PINID_LCD_RS, + [SPI_CS] = PINID_LCD_CS, +}; + +struct pin_desc appuart_pins_0[] = { + { PINID_AUART1_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_AUART1_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_AUART1_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_AUART1_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, +}; + +#if 0 /* temporary ? */ +struct pin_desc appuart_pins_1[] = { + { PINID_AUART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_AUART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_AUART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_AUART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, +}; +#endif + +struct pin_group appuart_pins[] = { + [0] = { + .pins = appuart_pins_0, + .nr_pins = ARRAY_SIZE(appuart_pins_0), + }, + [1] = { +#if 0 /* undefined yet. */ + .pins = appuart_pins_1, + .nr_pins = ARRAY_SIZE(appuart_pins_1), +#endif + }, +}; + +struct pin_desc dbguart_pins_0[] = { + { PINID_PWM0, PIN_FUN3, }, + { PINID_PWM1, PIN_FUN3, }, +}; + +struct pin_group dbguart_pins[] = { + [0] = { + .pins = dbguart_pins_0, + .nr_pins = ARRAY_SIZE(dbguart_pins_0), + }, +}; + +static struct pin_desc usb_mux_pins_desc[] = { + { PINID_SSP1_DETECT, PIN_FUN3, }, +}; + +struct pin_group usb_mux_pins = { + .pins = usb_mux_pins_desc, + .nr_pins = ARRAY_SIZE(usb_mux_pins_desc), +}; + +static struct pin_desc spdif_pins_desc[] = { + { PINID_ROTARYA, PIN_FUN3, PIN_4MA, PIN_1_8V, 0, }, +}; + +struct pin_group spdif_pins = { + .pins = spdif_pins_desc, + .nr_pins = ARRAY_SIZE(spdif_pins_desc), +}; + +/* + * The registers are all very closely mapped, so we might as well map them all + * with a single mapping + * + * Logical Physical + * f0000000 80000000 On-chip registers + * f1000000 00000000 256k on-chip SRAM + */ + +static struct map_desc stmp378x_io_desc[] __initdata = { + { + .virtual = IO_ADDRESS(STMP378X_REGS_BASE), + .pfn = __phys_to_pfn(STMP378X_REGS_BASE), + .length = STMP378X_REGS_SIZE, + .type = MT_DEVICE, + }, + { + .virtual = STMP3XXX_OCRAM_VA_BASE, + .pfn = __phys_to_pfn(STMP378X_OCRAM_BASE), + .length = STMP378X_OCRAM_SIZE, + .type = MT_DEVICE, + }, +}; + +void __init stmp378x_map_io(void) +{ + iotable_init(stmp378x_io_desc, ARRAY_SIZE(stmp378x_io_desc)); +} diff --git a/arch/arm/mach-stmp3xxx/stmp378x_devb.c b/arch/arm/mach-stmp3xxx/stmp378x_devb.c new file mode 100644 index 000000000000..99f2530c48b1 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp378x_devb.c @@ -0,0 +1,405 @@ +/* + * Freescale STMP378X development board support + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> + +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include <mach/stmp3xxx.h> +#include <mach/gpmi.h> +#include <mach/power.h> +#include <mach/regs-power.h> +#include <mach/regs-digctl.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-usbphy.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-pwm.h> + +#include "common.h" + +static struct resource stmp378xdb_led_resources[] = { + { + .name = "led0", + .start = 0, + .end = 0, + .flags = IORESOURCE_DISABLED, + }, + { + .name = "led1", + .start = 1, + .end = 1, + .flags = IORESOURCE_DISABLED, + }, + { + .name = "led2", + .start = 2, + .end = 2, + .flags = IORESOURCE_DISABLED, + }, + { + .name = "led3", + .start = 3, + .end = 3, + .flags = IORESOURCE_DISABLED, + }, + { + .name = "led4", + .start = 4, + .end = 4, + .flags = IORESOURCE_DISABLED, + }, +}; + +static struct platform_device stmp378x_leds = { + .name = "stmp378x-pwm-led", + .id = -1, + .num_resources = ARRAY_SIZE(stmp378xdb_led_resources), + .resource = stmp378xdb_led_resources, +}; + +static struct platform_device *devices[] = { + &stmp3xxx_keyboard, + &stmp3xxx_touchscreen, + &stmp3xxx_appuart, + &stmp3xxx_dbguart, + &stmp3xxx_watchdog, + &stmp3xxx_rtc, + &stmp3xxx_framebuffer, + &stmp3xxx_backlight, + &stmp3xxx_rotdec, + &stmp378x_i2c, + &stmp3xxx_persistent, + &stmp3xxx_dcp_bootstream, + &stmp3xxx_dcp, + &stmp3xxx_mtest, + &stmp3xxx_battery, + &stmp3xxx_pxp, +}; + +static struct stmpkbd_keypair keyboard_data[] = { + { 100, KEY_F4 }, + { 306, KEY_F5 }, + { 626, KEY_F6 }, + { 932, KEY_F7 }, + { 1260, KEY_F8 }, + { 1584, KEY_F9 }, + { 1907, KEY_F10 }, + { 2207, KEY_F11 }, + { 2525, KEY_F12 }, + { 2831, KEY_F13}, + { 3134, KEY_F14 }, + { -1, 0 }, +}; +const char *gpmi_part_probes[] = { "cmdlinepart", NULL }; + +#define UID_SIZE SZ_1M +#define UID_OFFSET (20*SZ_1M) + +struct mtd_partition gpmi_partitions_chip0[] = { + [0] = { + .offset = 0, + .size = UID_OFFSET, + .name = "Boot#0", + .mask_flags = 0, + }, + /* there a 1M UID partition here */ +/* + [1] = { + .offset = MTDPART_OFS_APPEND, + .size = 5 * SZ_1M, + .name = "id", + .mask_flags = 0, + }, +*/ + /* This partition is managed by UBI */ + [1] = { + .offset = UID_OFFSET + UID_SIZE, + .size = MTDPART_SIZ_FULL, + .name = "UBI#0", + .mask_flags = 0, + }, +}; + +struct mtd_partition gpmi_partitions_chip1[] = { + [0] = { + .offset = 0, + .size = UID_OFFSET, + .name = "Boot#1", + .mask_flags = 0, + }, + /* This partition is managed by UBI */ + [1] = { + .offset = UID_OFFSET, + .size = MTDPART_SIZ_FULL, + .name = "UBI#1", + .mask_flags = 0, + }, +}; + +static char *gpmi_concat_parts[] = { + [0] = "UBI#0", + [1] = "UBI#1", + [2] = NULL, +}; + +static struct gpmi_platform_data gpmi_partitions = { + .uid_offset = UID_OFFSET, + .uid_size = UID_SIZE, + .io_uA = 70000, + .items = 2, + .concat_name = "UBI", + .concat_parts = gpmi_concat_parts, + .parts = { + [0] = { + .part_probe_types = gpmi_part_probes, + .nr_partitions = ARRAY_SIZE(gpmi_partitions_chip0), + .partitions = gpmi_partitions_chip0, + }, + [1] = { + .part_probe_types = gpmi_part_probes, + .nr_partitions = ARRAY_SIZE(gpmi_partitions_chip1), + .partitions = gpmi_partitions_chip1, + }, + }, +}; + +static void usb_phy_enable(void) +{ + /* + * Set these bits so that we can force the OTG bits high + * so the ARC core operates properly + */ + HW_POWER_CTRL_CLR(BM_POWER_CTRL_CLKGATE); + HW_POWER_DEBUG_SET(BM_POWER_DEBUG_VBUSVALIDPIOLOCK | + BM_POWER_DEBUG_AVALIDPIOLOCK | + BM_POWER_DEBUG_BVALIDPIOLOCK); + HW_POWER_STS_SET(BM_POWER_STS_BVALID | BM_POWER_STS_AVALID | + BM_POWER_STS_VBUSVALID); + + /* Reset USBPHY module */ + HW_USBPHY_CTRL_SET(BM_USBPHY_CTRL_SFTRST); + udelay(10); + + /* Remove CLKGATE and SFTRST */ + HW_USBPHY_CTRL_CLR(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST); + + /* Turn on the USB clocks */ + HW_CLKCTRL_PLLCTRL0_SET(BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS); + HW_DIGCTL_CTRL_CLR(BM_DIGCTL_CTRL_USB_CLKGATE); + + /* Power up the PHY */ + HW_USBPHY_PWD_WR(0); + + /* + * Set precharge bit to cure overshoot problems at the + * start of packets + */ + HW_USBPHY_CTRL_SET(1 /* BM_USBPHY_CTRL_ENHSPRECHARGEXMIT */); + +#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) + /* enable disconnect detector */ + HW_USBPHY_CTRL_SET(BM_USBPHY_CTRL_ENHOSTDISCONDETECT); +#endif +} + +static void usb_hwinit(void) +{ + stmp3xxx_request_pin_group(&usb_mux_pins, "usb"); +} + +static void usb_hwrelease(void) +{ + stmp3xxx_release_pin_group(&usb_mux_pins, "usb"); +} + +static struct stmp37xx_spi_platform_data enc_data = { + .irq_pin = PINID_SSP1_DATA1, + .hw_init = stmp37xx_spi_enc_init, + .hw_release = stmp37xx_spi_enc_release, +}; + +static struct spi_board_info spi_board_info[] __initdata = { +#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE) + { + .modalias = "enc28j60", + .max_speed_hz = 6 * 1000 * 1000, + .bus_num = 1, + .chip_select = 0, + .platform_data = &enc_data, + }, +#endif +}; + +/* + * There are 4 LEDs connected to PWM module available on the STMP378x + * Dev. board: + * PWM0 - shared with Debug UART + * PWM1 - shared with Debug UART + * PWM2 - shared with LCD panel (LMS350) + * PWM3 - shared with SD/MMC card slot + * + * pwm_leds= option allows to choose PWM outputs to be used to control LEDs + * Conflicting kernel modules should be disabled + */ +#define PWM_MAX 4 +static int pwm_leds_enable; + +int __init pwm_leds_setup(char *str) +{ + char tmp[10]; + char *l, *s; + unsigned long pwmn; + int r; + + s = str; + + do { + memset(tmp, 0, sizeof(tmp)); + + l = strchr(s, ','); + + if (l) { + strncpy(tmp, s, min_t(int, l - s, sizeof(tmp) - 1)); + r = strict_strtoul(tmp, 0, &pwmn); + s = ++l; + } else { + r = strict_strtoul(s, 0, &pwmn); + } + + if (r == 0 && pwmn < PWM_MAX) { + stmp378xdb_led_resources[pwmn].flags = 0; + pwm_leds_enable++; + } + } while (l); + + return 0; +} +__setup("pwm_leds=", pwm_leds_setup); + +int __init enc28j60_setup(char *str) +{ + char *cur = str, + *item; + unsigned long bus, cs, irqbank, irqpin; + char tmps[20]; + int r; + + bus = cs = irqbank = irqpin = 0; + /* + we recognize strings like enc28j60=chipselect@bus,irqpin + where + chipselect is 0..4, + bus is 0/1, + irqpin is in format bank:pin + */ + item = strchr(cur, '@'); + if (item) { + memset(tmps, 0, sizeof(tmps)); + strncpy(tmps, cur, min_t(int, item - cur, sizeof(tmps - 1))); + r = strict_strtoul(tmps, 0, &cs); + if (r < 0) + return r; + cur = item + 1; + } + + item = strchr(cur, ','); + if (item) { + memset(tmps, 0, sizeof(tmps)); + strncpy(tmps, cur, min_t(int, item - cur, sizeof(tmps - 1))); + r = strict_strtoul(tmps, 0, &bus); + if (r < 0) + return r; + cur = item + 1; + } + + item = strchr(cur, ':'); + if (item) { + memset(tmps, 0, sizeof(tmps)); + strncpy(tmps, cur, min_t(int, item - cur, sizeof(tmps - 1))); + r = strict_strtoul(tmps, 0, &irqbank); + if (r < 0) + return r; + cur = item + 1; + } + + r = strict_strtoul(cur, 0, &irqpin); + if (r < 0) + return r; + + pr_info("%s: bus = %ld, cs = %ld, irqpin = %ld + %ld\n", + __func__, bus, cs, irqbank, irqpin); + + spi_board_info[0].bus_num = bus; + spi_board_info[0].chip_select = cs; + enc_data.irq_pin = STMP3XXX_PINID(irqbank, irqpin); + return 0; +} +__setup("enc28j60=", enc28j60_setup); + +static struct i2c_board_info __initdata stmp3xxx_i2c_devices[] = { + { I2C_BOARD_INFO("stfm1000", 0xc0), .flags = I2C_M_TEN } +}; + +static void __init stmp378x_devb_init(void) +{ + int i; + + stmp3xxx_init(); + + i2c_register_board_info(0, stmp3xxx_i2c_devices, ARRAY_SIZE(stmp3xxx_i2c_devices)); + + stmp3xxx_set_mmc_data(&stmp3xxx_mmc.dev); + stmp3xxx_gpmi.dev.platform_data = &gpmi_partitions; + stmp3xxx_keyboard.dev.platform_data = &keyboard_data; + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); + stmp3xxx_ssp1_device_register(); /* MMC or SSP */ + stmp3xxx_ssp2_device_register(); /* MMC or SSP */ + platform_add_devices(devices, ARRAY_SIZE(devices)); + if (pwm_leds_enable) + platform_device_register(&stmp378x_leds); +#if 0 + for (i = 0; i < ARRAY_SIZE(devices); i++) { + struct platform_device *p = devices[i]; + stmp3xxx_platform_add_regulator(p->name, 1); + } + stmp3xxx_platform_add_regulator("mmc_ssp", 2); + stmp3xxx_platform_add_regulator("charger", 1); + stmp3xxx_platform_add_regulator("power-test", 1); +#endif +} + +MACHINE_START(STMP378X, "STMP378X") + .phys_io = 0x80000000, + .io_pg_offst = ((0xf0000000) >> 18) & 0xfffc, + .boot_params = 0x40000100, + .map_io = stmp378x_map_io, + .init_irq = stmp378x_init_irq, + .timer = &stmp3xxx_timer, + .init_machine = stmp378x_devb_init, +MACHINE_END diff --git a/arch/arm/mach-stmp3xxx/stmp378x_devb_rotdec.c b/arch/arm/mach-stmp3xxx/stmp378x_devb_rotdec.c new file mode 100644 index 000000000000..0fefe2635501 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp378x_devb_rotdec.c @@ -0,0 +1,47 @@ +/* + * Freescale STMP378X Rotary Encoder module pin multiplexing + * + * Author: Drew Benedetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include <mach/pins.h> +#include "pinmux.h" + +#define ROTARY_FUN PIN_FUN1 + +#define TITLE "stmp3xxx-rotdec" + +int rotdec_pinmux_request(void) +{ + int rc = 0; + + rc |= stmp3xxx_request_pin(PINID_ROTARYA, ROTARY_FUN, TITLE); + rc |= stmp3xxx_request_pin(PINID_ROTARYB, ROTARY_FUN, TITLE); + + return rc; +} +EXPORT_SYMBOL_GPL(rotdec_pinmux_request); + +void rotdec_pinmux_free(void) +{ + stmp3xxx_release_pin(PINID_ROTARYA, TITLE); + stmp3xxx_release_pin(PINID_ROTARYB, TITLE); +} +EXPORT_SYMBOL_GPL(rotdec_pinmux_free); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>"); diff --git a/arch/arm/mach-stmp3xxx/stmp378x_i2c.c b/arch/arm/mach-stmp3xxx/stmp378x_i2c.c new file mode 100644 index 000000000000..d8612055f226 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp378x_i2c.c @@ -0,0 +1,275 @@ +/* + * Freescale STMP378X I2C low-level/dma functions + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> + +#include <linux/dma-mapping.h> +#include <mach/hardware.h> +#include <mach/regs-i2c.h> +#include <mach/regs-apbx.h> +#include <mach/dma.h> +#include <mach/i2c.h> + +#include "common.h" + +static unsigned int dma_channel = + STMP3xxx_DMA(STMP378X_APBX_I2C, STMP3XXX_BUS_APBX); + + +static struct stmp3xxx_dma_descriptor i2c_dma_read[2]; +static struct stmp3xxx_dma_descriptor i2c_dma_write; +static dma_addr_t i2c_buf_phys; +static u8 *i2c_buf_virt; + + +/* + * Select device to read from + */ + +u32 cmd_i2c_select[4] = { + 0, /* Chain to i2c_read */ + + (BF_APBX_CHn_CMD_XFER_COUNT(1) | + /* BM_APBX_CHn_CMD_SEMAPHORE | */ + BF_APBX_CHn_CMD_CMDWORDS(1) | + BM_APBX_CHn_CMD_WAIT4ENDCMD | + BM_APBX_CHn_CMD_CHAIN | + BM_APBX_CHn_CMD_IRQONCMPLT | /* For debug*/ + BF_APBX_CHn_CMD_COMMAND(BV_APBX_CHn_CMD_COMMAND__DMA_READ)), + + 0, /* dma handler */ + + BM_I2C_CTRL0_RETAIN_CLOCK | + BM_I2C_CTRL0_PRE_SEND_START | + BM_I2C_CTRL0_MASTER_MODE | + BM_I2C_CTRL0_DIRECTION | + BF_I2C_CTRL0_XFER_COUNT(1) + +}; + +u32 cmd_i2c_write[4] = { + 0, + + (BM_APBX_CHn_CMD_SEMAPHORE | + BF_APBX_CHn_CMD_CMDWORDS(1) | + BM_APBX_CHn_CMD_WAIT4ENDCMD | + BM_APBX_CHn_CMD_IRQONCMPLT | + BF_APBX_CHn_CMD_COMMAND(BV_APBX_CHn_CMD_COMMAND__DMA_READ)), + + 0, /* dma handler */ + + BM_I2C_CTRL0_PRE_SEND_START | + BM_I2C_CTRL0_MASTER_MODE | +/* BM_I2C_CTRL0_POST_SEND_STOP | */ + BM_I2C_CTRL0_DIRECTION + +}; + + +u32 cmd_i2c_read[4] = { + 0, + + (BM_APBX_CHn_CMD_SEMAPHORE | + BF_APBX_CHn_CMD_CMDWORDS(1) | + BM_APBX_CHn_CMD_WAIT4ENDCMD | + BM_APBX_CHn_CMD_IRQONCMPLT | + BF_APBX_CHn_CMD_COMMAND(BV_APBX_CHn_CMD_COMMAND__DMA_WRITE)), + + 0, /* dma handler */ + + BM_I2C_CTRL0_SEND_NAK_ON_LAST | +/* BM_I2C_CTRL0_POST_SEND_STOP | */ + BM_I2C_CTRL0_MASTER_MODE | + 0 /*BF_I2C_CTRL0_DIRECTION(BV_I2C_CTRL0_DIRECTION__RECEIVE)*/ +}; + + +int hw_i2c_init_dma(struct device *dev) +{ + int ret; + + ret = stmp3xxx_dma_request(dma_channel, dev, "i2c"); + if (ret) { + dev_err(dev, "stmp3xxx_dma_request failed: error %d\n", ret); + return ret; + } + + i2c_buf_virt = + dma_alloc_coherent( + dev, + PAGE_SIZE, + &i2c_buf_phys, + GFP_KERNEL); + + if (i2c_buf_virt == NULL) + return -ENOMEM; + + + stmp3xxx_dma_allocate_command( + dma_channel, + &i2c_dma_read[0]); + + stmp3xxx_dma_allocate_command( + dma_channel, + &i2c_dma_read[1]); + + stmp3xxx_dma_allocate_command( + dma_channel, + &i2c_dma_write); + + stmp3xxx_dma_reset_channel(dma_channel); + stmp3xxx_dma_clear_interrupt(dma_channel); + stmp3xxx_dma_enable_interrupt(dma_channel); + return 0; +}; + +void hw_i2c_free_dma(struct device *dev) +{ + stmp3xxx_dma_free_command( + dma_channel, + &i2c_dma_write); + + stmp3xxx_dma_free_command( + dma_channel, + &i2c_dma_read[1]); + + stmp3xxx_dma_free_command( + dma_channel, + &i2c_dma_read[0]); + + dma_free_coherent( + dev, + PAGE_SIZE, + i2c_buf_virt, + i2c_buf_phys); + + stmp3xxx_dma_release(dma_channel); +} + +void hw_i2c_clear_dma_interrupt(void) +{ + stmp3xxx_dma_clear_interrupt(dma_channel); +} +EXPORT_SYMBOL(hw_i2c_clear_dma_interrupt); + +void hw_i2c_setup_write(u8 addr, void *buff, int len, int flags) +{ + + memcpy(i2c_dma_write.command, &cmd_i2c_write, sizeof(cmd_i2c_write)); + + i2c_dma_write.command->cmd |= + BF_APBX_CHn_CMD_XFER_COUNT(len+1); + + i2c_dma_write.command->pio_words[0] |= + BF_I2C_CTRL0_XFER_COUNT(len+1) | flags; + + i2c_dma_write.command->buf_ptr = i2c_buf_phys; + i2c_buf_virt[0] = addr | I2C_WRITE ; + memcpy(&i2c_buf_virt[1], buff, len); +} +EXPORT_SYMBOL(hw_i2c_setup_write); + +void hw_i2c_finish_read(void *buff, int len) +{ + memcpy(buff, &i2c_buf_virt[1], len); + +} +EXPORT_SYMBOL(hw_i2c_finish_read); + +void hw_i2c_setup_read(u8 addr, void *buff, int len, int flags) +{ + + if (len > (PAGE_SIZE - 4)) + BUG(); + + memcpy(i2c_dma_read[0].command, + &cmd_i2c_select, + sizeof(cmd_i2c_select)); + + memcpy(i2c_dma_read[1].command, + &cmd_i2c_read, + sizeof(cmd_i2c_read)); + + i2c_dma_read[0].command->next = i2c_dma_read[1].handle; + i2c_dma_read[0].command->buf_ptr = i2c_buf_phys ; + i2c_buf_virt[0] = addr | I2C_READ ; + + i2c_dma_read[1].command->cmd |= BF_APBX_CHn_CMD_XFER_COUNT(len); + + i2c_dma_read[1].command->pio_words[0] |= + BF_I2C_CTRL0_XFER_COUNT(len) | flags; + + i2c_dma_read[1].command->buf_ptr = (u32)i2c_buf_phys + 1 ; + memcpy(&i2c_buf_virt[1], buff, len); + +} +EXPORT_SYMBOL(hw_i2c_setup_read); + +void hw_i2c_run(int dir) +{ + if (dir == I2C_WRITE) + stmp3xxx_dma_go(dma_channel, &i2c_dma_write, 1); + else + stmp3xxx_dma_go(dma_channel, &i2c_dma_read[0], 1); +} +EXPORT_SYMBOL(hw_i2c_run); + +void hw_i2c_reset_dma(void) +{ + stmp3xxx_dma_reset_channel(dma_channel); + stmp3xxx_dma_clear_interrupt(dma_channel); +} +EXPORT_SYMBOL(hw_i2c_reset_dma); + + +int hw_i2c_init(struct device *dev) +{ + if (stmp3xxx_request_pin_group(&i2c_pins, "i2c")) + return -1; + + + /* Take controller out of reset */ + HW_I2C_CTRL0_CLR(BM_I2C_CTRL0_SFTRST | BM_I2C_CTRL0_CLKGATE); + udelay(10); + +/* * Set timing + * High time = 120 clks; read bit at 48 for 95Khz/24mhz + * Low time = 128 clks; write bit at 48 for 95khz/24mhz +*/ + +/* + Don't set 400khz by default; stfm1000 needs 100khz at the start. + HW_I2C_TIMING0_WR(0x00780030); + HW_I2C_TIMING1_WR(0x001F000F); + HW_I2C_TIMING2_WR(0x0015000D); +*/ + dev_dbg(dev, "I2C module version %x\n ", HW_I2C_VERSION_RD()); + hw_i2c_init_dma(dev); + return 0; +} +EXPORT_SYMBOL(hw_i2c_init); + +void hw_i2c_stop(struct device *dev) +{ + HW_I2C_CTRL0_SET(BM_I2C_CTRL0_SFTRST); + hw_i2c_reset_dma(); + hw_i2c_free_dma(dev); + stmp3xxx_release_pin_group(&i2c_pins, "i2c"); +} +EXPORT_SYMBOL(hw_i2c_stop); diff --git a/arch/arm/mach-stmp3xxx/stmp378x_lcdif.c b/arch/arm/mach-stmp3xxx/stmp378x_lcdif.c new file mode 100644 index 000000000000..808acbc0861c --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp378x_lcdif.c @@ -0,0 +1,186 @@ +/* + * Freescale STMP378X LCDIF low-level routines + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG */ + +#include <linux/dma-mapping.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <mach/dma.h> +#include <mach/dma.h> +#include <mach/regs-lcdif.h> +#include <mach/regs-pinctrl.h> +#include <mach/lcdif.h> + +#define MAX_CHAIN_LEN 10 + +static struct stmp3xxx_dma_descriptor video_dma_descriptor[MAX_CHAIN_LEN]; +static struct stmp3xxx_lcd_dma_chain_info dma_chain_info[MAX_CHAIN_LEN]; +static unsigned dma_chain_info_pos; + +void stmp3xxx_init_lcdif(void) +{ + /* Reset controller */ + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_SFTRST); + udelay(10); + + /* Take controller out of reset */ + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_SFTRST | BM_LCDIF_CTRL_CLKGATE); + + /* Setup the bus protocol */ + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_MODE86); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_BUSY_ENABLE); + + /* Take display out of reset */ + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_RESET); + + /* VSYNC is an input by default */ + HW_LCDIF_VDCTRL0_SET(BM_LCDIF_VDCTRL0_VSYNC_OEB); + + /* Reset display */ + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_RESET); + udelay(10); + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_RESET); + udelay(10); +} +EXPORT_SYMBOL(stmp3xxx_init_lcdif); + +static int stmp378x_lcd_master = 1; +int stmp3xxx_lcdif_dma_init(struct device *dev, dma_addr_t phys, int memsize, + int lcd_master) +{ + int ret = 0; + + stmp378x_lcd_master = lcd_master; + if (lcd_master) { + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_LCDIF_MASTER); + + HW_LCDIF_CUR_BUF_WR(phys); + HW_LCDIF_NEXT_BUF_WR(phys); + } else { + ret = stmp3xxx_dma_request( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), + dev, + "lcdif"); + if (ret) { + dev_err(dev, + "stmp3xxx_dma_request failed: error %d\n", ret); + goto out; + } + + stmp3xxx_dma_reset_channel( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH)); + + stmp3xxx_dma_clear_interrupt( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH)); + stmp3xxx_dma_enable_interrupt( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH)); + + dotclk_dma_chain_init(memsize, phys, video_dma_descriptor, + dma_chain_info, &dma_chain_info_pos); + } +out: + return ret; +} +EXPORT_SYMBOL(stmp3xxx_lcdif_dma_init); + +void stmp3xxx_lcdif_dma_release(void) +{ + int i; + + if (stmp378x_lcd_master) { + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_LCDIF_MASTER); + return; + } + + for (i = 0; i < dma_chain_info_pos; i++) + stmp3xxx_dma_free_command( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), + &video_dma_descriptor[i]); + stmp3xxx_dma_release(STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH)); + + dma_chain_info_pos = 0; +} +EXPORT_SYMBOL(stmp3xxx_lcdif_dma_release); + +void stmp3xxx_lcdif_run(void) +{ + if (stmp378x_lcd_master) { + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_LCDIF_MASTER); + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_RUN); + } else { + video_dma_descriptor[dma_chain_info_pos - 1].command->cmd &= + ~BM_APBH_CHn_CMD_SEMAPHORE; + stmp3xxx_dma_go( + STMP3xxx_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), + video_dma_descriptor, 1); + } +} +EXPORT_SYMBOL(stmp3xxx_lcdif_run); + +void stmp3xxx_lcdif_stop(void) +{ + if (stmp378x_lcd_master) { + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_RUN); + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_LCDIF_MASTER); + udelay(100); + } else { + video_dma_descriptor[dma_chain_info_pos - 1].command->cmd |= + BM_APBH_CHn_CMD_SEMAPHORE; + udelay(100); + } +} +EXPORT_SYMBOL(stmp3xxx_lcdif_stop); + +int stmp3xxx_lcdif_pan_display(dma_addr_t addr) +{ + if (stmp378x_lcd_master) + HW_LCDIF_NEXT_BUF_WR(addr); + else { + int i; + /* Modify the chain addresses */ + for (i = 0; i < dma_chain_info_pos; ++i) { + *dma_chain_info[i].dma_addr_p = addr + + dma_chain_info[i].offset; + barrier(); + } + } + return 0; +} +EXPORT_SYMBOL(stmp3xxx_lcdif_pan_display); + +static BLOCKING_NOTIFIER_HEAD(lcdif_client_list); + +int stmp3xxx_lcdif_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&lcdif_client_list, nb); +} +EXPORT_SYMBOL(stmp3xxx_lcdif_register_client); + +void stmp3xxx_lcdif_unregister_client(struct notifier_block *nb) +{ + blocking_notifier_chain_unregister(&lcdif_client_list, nb); +} +EXPORT_SYMBOL(stmp3xxx_lcdif_unregister_client); + +void stmp3xxx_lcdif_notify_clients(unsigned long event, + struct stmp3xxx_platform_fb_entry *pentry) +{ + blocking_notifier_call_chain(&lcdif_client_list, event, pentry); +} +EXPORT_SYMBOL(stmp3xxx_lcdif_notify_clients); diff --git a/arch/arm/mach-stmp3xxx/stmp378x_pwm_led.c b/arch/arm/mach-stmp3xxx/stmp378x_pwm_led.c new file mode 100644 index 000000000000..dd8970153357 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp378x_pwm_led.c @@ -0,0 +1,54 @@ +/* + * Freescale STMP378X PWM LEDs pin multiplexing + * + * Author: Drew Bendetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/module.h> +#include "pinmux.h" + +#define PWM_PINID(n) STMP3XXX_PINID(1, 26 + n) + +int pwm_led_pinmux_request(int pwmn, char *title) +{ + int rc = 0; + + /* PIN_FUN1 is PWM for these pins */ + rc = stmp3xxx_request_pin(PWM_PINID(pwmn), PIN_FUN1, title); + if (rc) + return rc; + + stmp3xxx_pin_voltage(PWM_PINID(pwmn), PIN_3_3V, title); + /* pwm0-3 support 4,8,12mA; pwm4 supports 8,16,24mA + * I'm forcing 8 here since it's the only one in common + */ + stmp3xxx_pin_strength(PWM_PINID(pwmn), PIN_8MA, title); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_led_pinmux_request); + +void pwm_led_pinmux_free(int pwmn, char *title) +{ + stmp3xxx_pin_voltage(PWM_PINID(pwmn), PIN_4MA, title); + stmp3xxx_pin_strength(PWM_PINID(pwmn), PIN_1_8V, title); + + stmp3xxx_release_pin(PWM_PINID(pwmn), title); +} +EXPORT_SYMBOL_GPL(pwm_led_pinmux_free); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>"); diff --git a/arch/arm/mach-stmp3xxx/stmp37xx.c b/arch/arm/mach-stmp3xxx/stmp37xx.c new file mode 100644 index 000000000000..e273283478be --- /dev/null +++ b/arch/arm/mach-stmp3xxx/stmp37xx.c @@ -0,0 +1,368 @@ +/* + * Freescale STMP37XX platform support + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/sysdev.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/fsl_devices.h> + +#include <mach/hardware.h> +#include <asm/dma.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> + +#include <mach/stmp3xxx.h> +#include <mach/gpmi.h> +#include <mach/ocram-malloc.h> + +#include <mach/platform.h> +#include <mach/system.h> +#include <mach/lcdif.h> + +#include <mach/regs-icoll.h> +#include <mach/regs-rtc.h> +#include <mach/regs-apbh.h> +#include <mach/regs-apbx.h> +#include <mach/regs-power.h> +#include <mach/regs-usbctrl.h> +#include <mach/regs-usbphy.h> +#include <mach/regs-digctl.h> +#include <mach/regs-ssp.h> + +#include "common.h" + +/* + * IRQ handling + */ +static void stmp37xx_ack_irq(unsigned int irq) +{ + /* Disable IRQ */ + HW_ICOLL_PRIORITYn_CLR(irq / 4, 0x04 << ((irq % 4) * 8)); + + /* ACK current interrupt */ + HW_ICOLL_LEVELACK_WR(1); + + /* Barrier */ + (void) HW_ICOLL_STAT_RD(); +} + +static void stmp37xx_mask_irq(unsigned int irq) +{ + /* IRQ disable */ + HW_ICOLL_PRIORITYn_CLR(irq / 4, 0x04 << ((irq % 4) * 8)); +} + +static void stmp37xx_unmask_irq(unsigned int irq) +{ + /* IRQ enable */ + HW_ICOLL_PRIORITYn_SET(irq / 4, 0x04 << ((irq % 4) * 8)); +} + +static struct irq_chip stmp37xx_chip = { + .ack = stmp37xx_ack_irq, + .mask = stmp37xx_mask_irq, + .unmask = stmp37xx_unmask_irq, +}; + +void __init stmp37xx_init_irq(void) +{ + stmp3xxx_init_irq(&stmp37xx_chip, NULL, NULL); +} + +/* + * DMA interrupt handling + */ +void stmp3xxx_arch_dma_enable_interrupt(int channel) +{ + int dmabus = channel / 16; + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL1_SET(1 << (8 + (channel % 16))); + break; + + case STMP3XXX_BUS_APBX: + HW_APBX_CTRL1_SET(1 << (8 + (channel % 16))); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt); + +void stmp3xxx_arch_dma_clear_interrupt(int channel) +{ + int dmabus = channel / 16; + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL1_CLR(1 << (channel % 16)); + break; + + case STMP3XXX_BUS_APBX: + HW_APBX_CTRL1_CLR(1 << (channel % 16)); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt); + +int stmp3xxx_arch_dma_is_interrupt(int channel) +{ + int r = 0; + + int dmabus = channel / 16; + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + r = HW_APBH_CTRL1_RD() & (1 << (channel % 16)); + break; + + case STMP3XXX_BUS_APBX: + r = HW_APBX_CTRL1_RD() & (1 << (channel % 16)); + break; + } + return r; +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt); + +void stmp3xxx_arch_dma_reset_channel(int channel) +{ + int dmabus = channel / 16; + unsigned chbit = 1 << (channel % 16); + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + /* Reset channel and wait for it to complete */ + HW_APBH_CTRL0_SET(chbit << BP_APBH_CTRL0_RESET_CHANNEL); + while (HW_APBH_CTRL0_RD() & + (chbit << BP_APBH_CTRL0_RESET_CHANNEL)) + continue; + break; + + case STMP3XXX_BUS_APBX: + /* Reset channel and wait for it to complete */ + HW_APBX_CTRL0_SET(chbit << BP_APBX_CTRL0_RESET_CHANNEL); + while (HW_APBX_CTRL0_RD() & + (chbit << BP_APBX_CTRL0_RESET_CHANNEL)) + continue; + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel); + +void stmp3xxx_arch_dma_freeze(int channel) +{ + int dmabus = channel / 16; + unsigned chbit = 1 << (channel % 16); + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL0_SET(1<<chbit); + break; + case STMP3XXX_BUS_APBX: + HW_APBX_CTRL0_SET(1<<chbit); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze); + +void stmp3xxx_arch_dma_unfreeze(int channel) +{ + int dmabus = channel / 16; + unsigned chbit = 1 << (channel % 16); + + switch (dmabus) { + case STMP3XXX_BUS_APBH: + HW_APBH_CTRL0_CLR(1<<chbit); + break; + case STMP3XXX_BUS_APBX: + HW_APBX_CTRL0_CLR(1<<chbit); + break; + } +} +EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze); + +/* + * STMP37xx dedicated pin groups + */ +static struct pin_desc gpmi_pins_desc[] = { + { PINID_GPMI_A0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_A1, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_A2, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RESETN, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_IRQ, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_D00, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D01, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D02, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D03, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D04, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D05, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D06, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_D07, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY2, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDY3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 }, + { PINID_GPMI_WRN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_GPMI_RDN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_EMI_CE3N, PIN_FUN2, PIN_4MA, PIN_3_3V, 0 }, + { PINID_EMI_CE2N, PIN_FUN2, PIN_4MA, PIN_3_3V, 0 }, +}; + +struct pin_group gpmi_pins = { + .pins = gpmi_pins_desc, + .nr_pins = ARRAY_SIZE(gpmi_pins_desc), +}; + +static struct pin_desc lcd_hx8238a_desc[] = { + { PINID_LCD_D00, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D01, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D02, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D03, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D04, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D05, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D06, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D07, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D08, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D09, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D10, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D11, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D12, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D13, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D14, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_D15, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_RESET, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_RS, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 }, + { PINID_LCD_BUSY, PIN_FUN2, PIN_12MA, PIN_3_3V, 0 }, +}; + +struct pin_group stmp37xx_lcd_pins = { + .pins = lcd_hx8238a_desc, + .nr_pins = ARRAY_SIZE(lcd_hx8238a_desc), +}; + +unsigned stmp37xx_lcd_spi_pins[] = { + [SPI_MOSI] = PINID_LCD_WR_RWN, + [SPI_SCLK] = PINID_LCD_RD_E, + [SPI_CS] = PINID_LCD_CS +}; + +/* + * The registers are all very closely mapped, so we might as well map them all + * with a single mapping + * + * Logical Physical + * f0000000 80000000 On-chip registers + * f1000000 00000000 256k on-chip SRAM + */ + +static struct map_desc stmp37xx_io_desc[] __initdata = { + { + .virtual = IO_ADDRESS(STMP37XX_REGS_BASE), + .pfn = __phys_to_pfn(STMP37XX_REGS_BASE), + .length = SZ_1M, + .type = MT_DEVICE + }, + { + .virtual = STMP3XXX_OCRAM_VA_BASE, + .pfn = __phys_to_pfn(STMP37XX_OCRAM_BASE), + .length = STMP37XX_OCRAM_SIZE, + .type = MT_DEVICE, + }, +}; + +void __init stmp37xx_map_io(void) +{ + iotable_init(stmp37xx_io_desc, ARRAY_SIZE(stmp37xx_io_desc)); +} + +/* + * STMP37xx specific devices + */ + +static u64 common_dmamask = (u32)0xffffffffU; +#define COMMON_COHERENT_DMAMASK (u32)0xffffffffU + +struct pin_desc appuart_pins_0[] = { + { PINID_UART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_UART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_UART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, + { PINID_UART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, }, +}; + +struct pin_group appuart_pins[] = { + [0] = { + .pins = appuart_pins_0, + .nr_pins = ARRAY_SIZE(appuart_pins_0), + }, +}; + +struct pin_desc dbguart_pins_0[] = { + { PINID_PWM0, PIN_FUN3, }, + { PINID_PWM1, PIN_FUN3, }, +}; + +struct pin_group dbguart_pins[] = { + [0] = { + .pins = dbguart_pins_0, + .nr_pins = ARRAY_SIZE(dbguart_pins_0), + }, +}; + +/* SPI */ +static struct stmp37xx_spi_platform_data enc_data = { + .irq_pin = PINID_GPMI_D01, + .hw_init = stmp37xx_spi_enc_init, + .hw_release = stmp37xx_spi_enc_release, +}; + +static struct spi_board_info spi_board_info[] __initdata = { +#ifdef CONFIG_ENC28J60 +{ + .modalias = "enc28j60", + .irq = IRQ_RESERVED_59, + .max_speed_hz = 20 * 1000 * 1000, + .bus_num = 2, + .chip_select = 0, + .platform_data = &enc_data, + }, +#endif +}; + +int stmp37xx_add_devices(void) +{ + if (ARRAY_SIZE(spi_board_info)) + spi_register_board_info(spi_board_info, + ARRAY_SIZE(spi_board_info)); + + return 0; +} +EXPORT_SYMBOL(stmp37xx_add_devices); diff --git a/arch/arm/mach-stmp3xxx/timer.c b/arch/arm/mach-stmp3xxx/timer.c new file mode 100644 index 000000000000..07c0ccaefbc6 --- /dev/null +++ b/arch/arm/mach-stmp3xxx/timer.c @@ -0,0 +1,188 @@ +/* + * System timer for Freescale STMP37XX/STMP378X + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/irq.h> + +#include <mach/hardware.h> +#include <asm/system.h> +#include <asm/mach/irq.h> +#include <asm/mach/time.h> + +#include <mach/regs-timrot.h> + +#include "common.h" + +static irqreturn_t +stmp3xxx_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + + if (HW_TIMROT_TIMCTRLn_RD(0) & (1<<15)) { + HW_TIMROT_TIMCTRLn_CLR(0, (1<<15)); + c->event_handler(c); + } else if (HW_TIMROT_TIMCTRLn_RD(1) & (1<<15)) { + HW_TIMROT_TIMCTRLn_CLR(1, (1<<15)); + HW_TIMROT_TIMCTRLn_CLR(1, BM_TIMROT_TIMCTRLn_IRQ_EN); + HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); + } + + return IRQ_HANDLED; +} + +static cycle_t stmp3xxx_clock_read(void) +{ + return ~((HW_TIMROT_TIMCOUNTn_RD(1) & 0xFFFF0000) >> 16); +} + +static int +stmp3xxx_timrot_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + HW_TIMROT_TIMCOUNTn_WR(0, delta); /* reload */ + return 0; +} + +static void +stmp3xxx_timrot_set_mode(enum clock_event_mode mode, + struct clock_event_device *dev) +{ +} + +static struct clock_event_device ckevt_timrot = { + .name = "timrot", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .cpumask = CPU_MASK_CPU0, + .set_next_event = stmp3xxx_timrot_set_next_event, + .set_mode = stmp3xxx_timrot_set_mode, +}; + +static struct clocksource cksrc_stmp3xxx = { + .name = "cksrc_stmp3xxx", + .rating = 250, + .read = stmp3xxx_clock_read, + .mask = CLOCKSOURCE_MASK(16), + .shift = 10, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static struct irqaction stmp3xxx_timer_irq = { + .name = "stmp3xxx_timer", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = stmp3xxx_timer_interrupt, + .dev_id = &ckevt_timrot, +}; + + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +static inline void __init stmp3xxx_time_init(unsigned long reload, + unsigned int ctrl) +{ + cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE, + cksrc_stmp3xxx.shift); + ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, + ckevt_timrot.shift); + ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot); + ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot); + + HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST | + BM_TIMROT_ROTCTRL_CLKGATE); + HW_TIMROT_TIMCOUNTn_WR(0, 0); + HW_TIMROT_TIMCOUNTn_WR(1, 0); + + HW_TIMROT_TIMCTRLn_WR(0, + (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */ + BF_TIMROT_TIMCTRLn_PRESCALE(0) | + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE | + BM_TIMROT_TIMCTRLn_IRQ_EN)); + HW_TIMROT_TIMCTRLn_WR(1, + (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */ + BF_TIMROT_TIMCTRLn_PRESCALE(0) | + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE)); + + HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1); + HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */ + + setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq); + + clocksource_register(&cksrc_stmp3xxx); + clockevents_register_device(&ckevt_timrot); +} + +static void __init stmp3xxx_init_timer(void) +{ + stmp3xxx_time_init(1000 / HZ - 1, 0); +} + +#ifdef CONFIG_PM + +void stmp3xxx_suspend_timer(void) +{ + HW_TIMROT_TIMCTRLn_CLR(0, BM_TIMROT_TIMCTRLn_IRQ_EN); + HW_TIMROT_TIMCTRLn_CLR(0, (1<<15)); + HW_TIMROT_ROTCTRL_SET(BM_TIMROT_ROTCTRL_CLKGATE); +} + +void stmp3xxx_resume_timer(void) +{ + HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST | + BM_TIMROT_ROTCTRL_CLKGATE); + + + HW_TIMROT_TIMCTRLn_WR(0, + (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */ + BF_TIMROT_TIMCTRLn_PRESCALE(0) | + BM_TIMROT_TIMCTRLn_UPDATE | + BM_TIMROT_TIMCTRLn_IRQ_EN)); + HW_TIMROT_TIMCTRLn_WR(1, + (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */ + BF_TIMROT_TIMCTRLn_PRESCALE(0) | + BM_TIMROT_TIMCTRLn_RELOAD | + BM_TIMROT_TIMCTRLn_UPDATE)); + + HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1); + HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */ +} + +#else + +#define stmp3xxx_suspend_timer NULL +#define stmp3xxx_resume_timer NULL + +#endif /* CONFIG_PM */ + +struct sys_timer stmp3xxx_timer = { + .init = stmp3xxx_init_timer, + .suspend = stmp3xxx_suspend_timer, + .resume = stmp3xxx_resume_timer, +}; diff --git a/arch/arm/mach-stmp3xxx/tvenc.c b/arch/arm/mach-stmp3xxx/tvenc.c new file mode 100644 index 000000000000..eb35eb12169b --- /dev/null +++ b/arch/arm/mach-stmp3xxx/tvenc.c @@ -0,0 +1,272 @@ +/* + * Freescale STMP378X dvi panel initialization + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG */ + +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> + +#include <mach/regs-lcdif.h> +#include <mach/regs-lradc.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-pwm.h> +#include <mach/regs-apbh.h> +#include <mach/gpio.h> +#include <mach/pins.h> +#include <mach/lcdif.h> +#include <mach/cpu.h> +#include <mach/stmp3xxx.h> + +#include "pinmux.h" + +#include <mach/regs-tvenc.h> + +enum { + TVENC_MODE_OFF = 0, + TVENC_MODE_NTSC, + TVENC_MODE_PAL, +}; + +/* NTSC 720x480 mode */ +#define NTSC_X_RES 720 +#define NTSC_Y_RES 480 +#define NTSC_H_BLANKING 262 +#define NTSC_V_LINES 525 + +/* PAL 720x576 mode */ +#define PAL_X_RES 720 +#define PAL_Y_RES 576 +#define PAL_H_BLANKING 274 +#define PAL_V_LINES 625 + +/* frame size */ +#define DVI_H_BLANKING(m) (m == TVENC_MODE_NTSC ? \ + NTSC_H_BLANKING : PAL_H_BLANKING) +#define DVI_V_LINES(m) (m == TVENC_MODE_NTSC ? \ + NTSC_V_LINES : PAL_V_LINES) +#define DVI_H_ACTIVE(m) (m == TVENC_MODE_NTSC ? NTSC_X_RES : PAL_X_RES) +#define DVI_V_ACTIVE(m) (m == TVENC_MODE_NTSC ? NTSC_Y_RES : PAL_Y_RES) +/* fileds range */ +#define DVI_F1_START(m) 1 +#define DVI_F1_END(m) (DVI_V_LINES(m) / 2) +#define DVI_F2_START(m) (DVI_F1_END(m) + 1) +#define DVI_F2_END(m) DVI_V_LINES(m) +/* blanking range */ +#define DVI_V1_BLANK_START(m) DVI_F1_END(m) +#define DVI_V1_BLANK_END(m) (DVI_V1_BLANK_START(m) + \ + (DVI_V_LINES(m) - DVI_V_ACTIVE(m)) / 2) +#define DVI_V2_BLANK_START(m) DVI_F2_END(m) +#define DVI_V2_BLANK_END(m) ((DVI_V2_BLANK_START(m) + \ + (DVI_V_LINES(m) - DVI_V_ACTIVE(m)) / 2 - 1) % \ + DVI_V_LINES(m)) + +static struct clk *lcd_clk; +static struct clk *clk_ref_vid; +static struct clk *clk_tv108M_ng; +static struct clk *clk_tv27M; + +static int tvenc_mode; + +static void init_tvenc_hw(int mode) +{ + /* Reset module */ + HW_TVENC_CTRL_SET(BM_TVENC_CTRL_SFTRST); + udelay(10); + + /* Take module out of reset */ + HW_TVENC_CTRL_CLR(BM_TVENC_CTRL_SFTRST | BM_TVENC_CTRL_CLKGATE); + + if (mode == TVENC_MODE_NTSC) { + /* Config NTSC-M mode, 8-bit Y/C in, SYNC out */ + HW_TVENC_CONFIG_CLR(BM_TVENC_CONFIG_SYNC_MODE | + BM_TVENC_CONFIG_PAL_SHAPE | + BM_TVENC_CONFIG_YGAIN_SEL | + BM_TVENC_CONFIG_CGAIN); + HW_TVENC_CONFIG_SET(BM_TVENC_CONFIG_FSYNC_PHS | + BF_TVENC_CONFIG_SYNC_MODE(0x4)); + + /* 859 pixels/line for NTSC */ + HW_TVENC_SYNCOFFSET_WR(857); + + HW_TVENC_COLORSUB0_WR(0x21F07C1F); + HW_TVENC_COLORBURST_CLR(BM_TVENC_COLORBURST_NBA | + BM_TVENC_COLORBURST_PBA); + HW_TVENC_COLORBURST_SET(BF_TVENC_COLORBURST_NBA(0xc8) | + BF_TVENC_COLORBURST_PBA(0)); + } else if (mode == TVENC_MODE_PAL) { + /* Config PAL-B mode, 8-bit Y/C in, SYNC out */ + HW_TVENC_CONFIG_CLR(BM_TVENC_CONFIG_SYNC_MODE | + BM_TVENC_CONFIG_ENCD_MODE | + BM_TVENC_CONFIG_YGAIN_SEL | + BM_TVENC_CONFIG_CGAIN | + BM_TVENC_CONFIG_FSYNC_PHS); + HW_TVENC_CONFIG_SET(BM_TVENC_CONFIG_PAL_SHAPE | + BF_TVENC_CONFIG_YGAIN_SEL(1) | + BF_TVENC_CONFIG_CGAIN(1) | + BF_TVENC_CONFIG_ENCD_MODE(0x1) | + BF_TVENC_CONFIG_SYNC_MODE(0x4)); + + /* 863 pixels/line for PAL */ + HW_TVENC_SYNCOFFSET_WR(863); + + HW_TVENC_COLORSUB0_WR(0x2A098ACB); + HW_TVENC_COLORBURST_CLR(BM_TVENC_COLORBURST_NBA | + BM_TVENC_COLORBURST_PBA); + HW_TVENC_COLORBURST_SET(BF_TVENC_COLORBURST_NBA(0xd6) | + BF_TVENC_COLORBURST_PBA(0x2a)); + } + + /* Power up DAC */ + HW_TVENC_DACCTRL_WR(BM_TVENC_DACCTRL_GAINDN | + BM_TVENC_DACCTRL_GAINUP | + BM_TVENC_DACCTRL_PWRUP1 | + BM_TVENC_DACCTRL_DUMP_TOVDD1 | + BF_TVENC_DACCTRL_RVAL(3)); + + /* set all to zero is a requirement for NTSC */ + HW_TVENC_MACROVISION0_WR(0); + HW_TVENC_MACROVISION1_WR(0); + HW_TVENC_MACROVISION2_WR(0); + HW_TVENC_MACROVISION3_WR(0); + HW_TVENC_MACROVISION4_WR(0); +} + +static int init_panel(struct device *dev, dma_addr_t phys, int memsize, + struct stmp3xxx_platform_fb_entry *pentry) +{ + int ret = 0; + + lcd_clk = clk_get(dev, "lcdif"); + clk_enable(lcd_clk); + clk_set_rate(lcd_clk, 1000000/pentry->cycle_time_ns); /* kHz */ + + clk_ref_vid = clk_get(NULL, "ref_vid"); + clk_tv108M_ng = clk_get(NULL, "tv108M_ng"); + clk_tv27M = clk_get(NULL, "tv27M"); + clk_enable(clk_ref_vid); + clk_enable(clk_tv108M_ng); + clk_enable(clk_tv27M); + + tvenc_mode = pentry->x_res == NTSC_Y_RES ? TVENC_MODE_NTSC : \ + TVENC_MODE_PAL; + + init_tvenc_hw(tvenc_mode); + + setup_dvi_panel(DVI_H_ACTIVE(tvenc_mode), DVI_V_ACTIVE(tvenc_mode), + DVI_H_BLANKING(tvenc_mode), DVI_V_LINES(tvenc_mode), + DVI_V1_BLANK_START(tvenc_mode), + DVI_V1_BLANK_END(tvenc_mode), + DVI_V2_BLANK_START(tvenc_mode), + DVI_V2_BLANK_END(tvenc_mode), + DVI_F1_START(tvenc_mode), DVI_F1_END(tvenc_mode), + DVI_F2_START(tvenc_mode), DVI_F2_END(tvenc_mode)); + + ret = stmp3xxx_lcdif_dma_init(dev, phys, memsize, 1); + + return ret; +} + +static void release_panel(struct device *dev, + struct stmp3xxx_platform_fb_entry *pentry) +{ + release_dvi_panel(); + + stmp3xxx_lcdif_dma_release(); + + clk_disable(clk_ref_vid); + clk_disable(clk_tv108M_ng); + clk_disable(clk_tv27M); + clk_disable(lcd_clk); + clk_put(clk_ref_vid); + clk_put(clk_tv108M_ng); + clk_put(clk_tv27M); + clk_put(lcd_clk); +} + +static int blank_panel(int blank) +{ + int ret = 0, count; + + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + HW_LCDIF_CTRL_CLR(BM_LCDIF_CTRL_BYPASS_COUNT); + + /* Wait until current transfer is complete, max 30ms */ + for (count = 30000; count > 0; count--) { + if (HW_LCDIF_STAT_RD() & BM_LCDIF_STAT_TXFIFO_EMPTY) + break; + udelay(1); + } + break; + + case FB_BLANK_UNBLANK: + HW_LCDIF_CTRL_SET(BM_LCDIF_CTRL_BYPASS_COUNT); + break; + + default: + ret = -EINVAL; + } + return ret; +} + +static struct stmp3xxx_platform_fb_entry ntsc_fb_entry = { + .name = "tvenc_ntsc", + /* x/y swapped */ + .x_res = NTSC_Y_RES, + .y_res = NTSC_X_RES, + .bpp = 32, + /* the pix_clk should be near 27Mhz for proper syncronization */ + .cycle_time_ns = 74, + .lcd_type = STMP3XXX_LCD_PANEL_DVI, + .init_panel = init_panel, + .release_panel = release_panel, + .blank_panel = blank_panel, + .run_panel = stmp3xxx_lcdif_run, + .pan_display = stmp3xxx_lcdif_pan_display, +}; + +static struct stmp3xxx_platform_fb_entry pal_fb_entry = { + .name = "tvenc_pal", + /* x/y swapped */ + .x_res = PAL_Y_RES, + .y_res = PAL_X_RES, + .bpp = 32, + /* the pix_clk should be near 27Mhz for proper syncronization */ + .cycle_time_ns = 74, + .lcd_type = STMP3XXX_LCD_PANEL_DVI, + .init_panel = init_panel, + .release_panel = release_panel, + .blank_panel = blank_panel, + .run_panel = stmp3xxx_lcdif_run, + .pan_display = stmp3xxx_lcdif_pan_display, +}; + +static int __init register_devices(void) +{ + stmp3xxx_lcd_register_entry(&ntsc_fb_entry, + stmp3xxx_framebuffer.dev.platform_data); + stmp3xxx_lcd_register_entry(&pal_fb_entry, + stmp3xxx_framebuffer.dev.platform_data); + + return 0; +} +subsys_initcall(register_devices); diff --git a/arch/arm/mach-stmp3xxx/unique-id.c b/arch/arm/mach-stmp3xxx/unique-id.c new file mode 100644 index 000000000000..207b2287310f --- /dev/null +++ b/arch/arm/mach-stmp3xxx/unique-id.c @@ -0,0 +1,199 @@ +/* + * Unique ID manipulation sysfs access generic functions + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/err.h> +#include <linux/timer.h> +#include <linux/spinlock.h> + +#include <mach/unique-id.h> + +static int unlock; +static spinlock_t u_lock; +static const unsigned long UID_AUTOLOCK_TIMEOUT = HZ * 60 * 3; +static struct timer_list u_timer; + +static void uid_timer_autolock(unsigned long param) +{ + struct timer_list *tmr = (struct timer_list *)param; + + if (spin_trylock(&u_lock)) { + if (unlock) + pr_debug("%s: locked down.\n", __func__); + unlock = 0; + spin_unlock(&u_lock); + } + mod_timer(tmr, jiffies + UID_AUTOLOCK_TIMEOUT); +} + +static LIST_HEAD(uid_provider_list); + +struct uid_provider { + struct kobject *kobj; + struct list_head list; + struct uid_ops *ops; + void *context; +}; + +static struct uid_provider *uid_provider_find(const char *name); + +#define UID_FWD_SYSFS_FILE(var, file, param) \ + static ssize_t var##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + struct uid_provider *p = \ + uid_provider_find(kobject_name(kobj)); \ + ssize_t r; \ + BUG_ON(p == NULL); \ + r = (p->ops && p->ops->file##_show) ? \ + p->ops->file##_show(p->context, buf, param) : 0;\ + return r; \ + } \ + \ + static ssize_t var##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, const char *buf, \ + size_t count) \ + { \ + struct uid_provider *p = \ + uid_provider_find(kobject_name(kobj)); \ + ssize_t r; \ + int ul; \ + BUG_ON(p == NULL); \ + spin_lock(&u_lock); \ + ul = unlock; \ + spin_unlock(&u_lock); \ + if (ul) \ + r = (p->ops && p->ops->file##_store) ? \ + p->ops->file##_store(p->context, buf, count, param) \ + : count; \ + else \ + r = -EACCES; \ + return r; \ + } + +struct kobject *uid_kobj; + +#define UID_ATTR(_name, _varname) \ + static struct kobj_attribute _varname##_attr = \ + __ATTR(_name, 0644, _varname##_show, _varname##_store) + +UID_FWD_SYSFS_FILE(id, id, 1); +UID_FWD_SYSFS_FILE(id_bin, id, 0); +UID_ATTR(id, id); +UID_ATTR(id.bin, id_bin); + +static struct attribute *uid_attrs[] = { + &id_attr.attr, + &id_bin_attr.attr, + NULL +}; + +static struct attribute_group uid_attr_group = { + .attrs = uid_attrs, +}; + +struct kobject *uid_provider_init(const char *name, + struct uid_ops *ops, void *context) +{ + struct uid_provider *new; + int err; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + err = -ENOMEM; + goto out; + } + + new->kobj = kobject_create_and_add(name, uid_kobj); + if (!new->kobj) { + err = -ENOMEM; + goto out; + } + new->ops = ops; + new->context = context; + + err = sysfs_create_group(new->kobj, &uid_attr_group); + if (err) + goto out2; + + list_add_tail(&new->list, &uid_provider_list); + return new->kobj; +out2: + kobject_del(new->kobj); +out: + kfree(new); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(uid_provider_init); + +static struct uid_provider *uid_provider_find(const char *name) +{ + struct uid_provider *p; + + list_for_each_entry(p, &uid_provider_list, list) { + if (strcmp(kobject_name(p->kobj), name) == 0) + return p; + } + return NULL; +} + +void uid_provider_remove(const char *name) +{ + struct uid_provider *p; + + p = uid_provider_find(name); + if (!p) + return; + kobject_del(p->kobj); + list_del(&p->list); + kfree(p); +} +EXPORT_SYMBOL_GPL(uid_provider_remove); + +static int uid_sysfs_init(void) +{ + int error; + + uid_kobj = kobject_create_and_add("uid", NULL); + if (!uid_kobj) { + error = -ENOMEM; + goto out1; + } + + spin_lock_init(&u_lock); + setup_timer(&u_timer, uid_timer_autolock, (unsigned long)&u_timer); + + /* try to lock each 3 minutes */ + mod_timer(&u_timer, jiffies + UID_AUTOLOCK_TIMEOUT); + return 0; + +out1: + printk(KERN_ERR"%s failed, error %d.", __func__, error); + return error; +} + +module_param(unlock, int, 0600) +core_initcall(uid_sysfs_init); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_DESCRIPTION("Unique ID simple framework"); + diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index fd2ab84ae017..d6deaf61325c 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -187,7 +187,8 @@ config CPU_ARM926T ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \ ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \ ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \ - ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2 || ARCH_MXC + ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2 || \ + ARCH_MXC || ARCH_STMP3XXX default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || \ ARCH_OMAP730 || ARCH_OMAP16XX || \ ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || \ diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 53565b5317d1..4cb5691f69c1 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -1721,7 +1721,7 @@ sapphire MACH_SAPPHIRE SAPPHIRE 1729 csb637xo MACH_CSB637XO CSB637XO 1730 evisiong MACH_EVISIONG EVISIONG 1731 stmp37xx MACH_STMP37XX STMP37XX 1732 -stmp378x MACH_STMP38XX STMP38XX 1733 +stmp378x MACH_STMP378X STMP378X 1733 tnt MACH_TNT TNT 1734 tbxt MACH_TBXT TBXT 1735 playmate MACH_PLAYMATE PLAYMATE 1736 diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index e522144cba3a..0d3cdfdbb695 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -200,4 +200,16 @@ config CRYPTO_DEV_IXP4XX help Driver for the IXP4xx NPE crypto engine. +config CRYPTO_DEV_STMP3XXX_DCP + tristate "Support for the STMP3xxx DCP engine" + depends on ARCH_STMP3XXX + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + Say 'Y' here to use the STMP3XXX DCP AES + engine for the CryptoAPI AES algorithm. + + To compile this driver as a module, choose M here: the module + will be called geode-aes. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 73557b2968d3..d4f3bec0d606 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o +obj-$(CONFIG_CRYPTO_DEV_STMP3XXX_DCP) += stmp3xxx_dcp.o diff --git a/drivers/crypto/stmp3xxx_dcp.c b/drivers/crypto/stmp3xxx_dcp.c new file mode 100644 index 000000000000..654dc5bff08c --- /dev/null +++ b/drivers/crypto/stmp3xxx_dcp.c @@ -0,0 +1,1401 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* + * Based on geode-aes.c + * Copyright (C) 2004-2006, Advanced Micro Devices, Inc. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/crypto.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <crypto/algapi.h> +#include <crypto/aes.h> +#include <crypto/sha.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <linux/io.h> +#include <linux/delay.h> + +#include <asm/cacheflush.h> + +#include "stmp3xxx_dcp.h" + +/* SHA1 is busted */ +#define DISABLE_SHA1 + +struct stmp3xxx_dcp { + struct device *dev; + spinlock_t lock; + struct mutex op_mutex[STMP3XXX_DCP_NUM_CHANNELS]; + struct completion op_wait[STMP3XXX_DCP_NUM_CHANNELS]; + int wait[STMP3XXX_DCP_NUM_CHANNELS]; + int dcp_vmi_irq; + int dcp_irq; +}; + +/* cipher flags */ +#define STMP3XXX_DCP_ENC 0x0001 +#define STMP3XXX_DCP_DEC 0x0002 +#define STMP3XXX_DCP_ECB 0x0004 +#define STMP3XXX_DCP_CBC 0x0008 +#define STMP3XXX_DCP_CBC_INIT 0x0010 +#define STMP3XXX_DCP_OTPKEY 0x0020 + +/* hash flags */ +#define STMP3XXX_DCP_INIT 0x0001 +#define STMP3XXX_DCP_UPDATE 0x0002 +#define STMP3XXX_DCP_FINAL 0x0004 + +#define STMP3XXX_DCP_AES 0x1000 +#define STMP3XXX_DCP_SHA1 0x2000 +#define STMP3XXX_DCP_CRC32 0x3000 +#define STMP3XXX_DCP_COPY 0x4000 +#define STMP3XXX_DCP_FILL 0x5000 +#define STMP3XXX_DCP_MODE_MASK 0xf000 + +struct stmp3xxx_dcp_op { + + unsigned int flags; + + void *src; + dma_addr_t src_phys; + + void *dst; + dma_addr_t dst_phys; + + int len; + + /* the key contains the IV for block modes */ + union { + struct { + u8 key[2 * AES_KEYSIZE_128] + __attribute__ ((__aligned__(32))); + dma_addr_t key_phys; + int keylen; + } cipher; + struct { + u8 digest[SHA1_DIGEST_SIZE] + __attribute__ ((__aligned__(32))); + dma_addr_t digest_phys; + int digestlen; + int init; + } hash; + }; + + union { + struct crypto_blkcipher *blk; + struct crypto_cipher *cip; + struct crypto_hash *hash; + } fallback; + + struct stmp3xxx_dcp_hw_packet pkt + __attribute__ ((__aligned__(32))); +}; + +struct stmp3xxx_dcp_hash_coherent_block { + struct stmp3xxx_dcp_hw_packet pkt[2] + __attribute__ ((__aligned__(32))); + u8 digest[SHA1_DIGEST_SIZE] + __attribute__ ((__aligned__(32))); + u8 rembuf[32]; +}; + +struct stmp3xxx_dcp_hash_op { + + unsigned int flags; + + void *src; + dma_addr_t src_phys; + + void *dst; + dma_addr_t dst_phys; + + int len; + + /* the key contains the IV for block modes */ + union { + struct { + u8 key[2 * AES_KEYSIZE_128] + __attribute__ ((__aligned__(32))); + dma_addr_t key_phys; + int keylen; + } cipher; + struct { + u8 digest[SHA1_DIGEST_SIZE] + __attribute__ ((__aligned__(32))); + dma_addr_t digest_phys; + int digestlen; + int init; + } hash; + }; + + union { + struct crypto_blkcipher *blk; + struct crypto_cipher *cip; + struct crypto_hash *hash; + } fallback; + + struct stmp3xxx_dcp_hash_coherent_block *hw; + dma_addr_t hw_phys; +}; + +/* only one */ +static struct stmp3xxx_dcp *global_sdcp; + +static void dcp_perform_op(struct stmp3xxx_dcp_op *op) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct mutex *mutex; + struct stmp3xxx_dcp_hw_packet *pkt; + int chan; + u32 pkt1, pkt2; + unsigned long timeout; + dma_addr_t pkt_phys; + u32 stat; + + pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE | BM_DCP_PACKET1_INTERRUPT; + + switch (op->flags & STMP3XXX_DCP_MODE_MASK) { + + case STMP3XXX_DCP_AES: + + chan = CIPHER_CHAN; + + /* key is at the payload */ + pkt1 |= BM_DCP_PACKET1_ENABLE_CIPHER; + if ((op->flags & STMP3XXX_DCP_OTPKEY) == 0) + pkt1 |= BM_DCP_PACKET1_PAYLOAD_KEY; + if (op->flags & STMP3XXX_DCP_ENC) + pkt1 |= BM_DCP_PACKET1_CIPHER_ENCRYPT; + if (op->flags & STMP3XXX_DCP_CBC_INIT) + pkt1 |= BM_DCP_PACKET1_CIPHER_INIT; + + pkt2 = BF_DCP_PACKET2_CIPHER_CFG(0) | + BF_DCP_PACKET2_KEY_SELECT(0) | + BF_DCP_PACKET2_CIPHER_SELECT( + BV_DCP_PACKET2_CIPHER_SELECT__AES128); + + if (op->flags & STMP3XXX_DCP_ECB) + pkt2 |= BF_DCP_PACKET2_CIPHER_MODE( + BV_DCP_PACKET2_CIPHER_MODE__ECB); + else if (op->flags & STMP3XXX_DCP_CBC) + pkt2 |= BF_DCP_PACKET2_CIPHER_MODE( + BV_DCP_PACKET2_CIPHER_MODE__CBC); + + break; + + case STMP3XXX_DCP_SHA1: + + chan = HASH_CHAN; + + pkt1 |= BM_DCP_PACKET1_ENABLE_HASH; + if (op->flags & STMP3XXX_DCP_INIT) + pkt1 |= BM_DCP_PACKET1_HASH_INIT; + if (op->flags & STMP3XXX_DCP_FINAL) { + pkt1 |= BM_DCP_PACKET1_HASH_TERM; + BUG_ON(op->hash.digest == NULL); + } + + pkt2 = BF_DCP_PACKET2_HASH_SELECT( + BV_DCP_PACKET2_HASH_SELECT__SHA1); + break; + + default: + dev_err(sdcp->dev, "Unsupported mode\n"); + return; + } + + mutex = &sdcp->op_mutex[chan]; + pkt = &op->pkt; + + pkt->pNext = 0; + pkt->pkt1 = pkt1; + pkt->pkt2 = pkt2; + pkt->pSrc = (u32)op->src_phys; + pkt->pDst = (u32)op->dst_phys; + pkt->size = op->len; + pkt->pPayload = chan == CIPHER_CHAN ? + (u32)op->cipher.key_phys : (u32)op->hash.digest_phys; + pkt->stat = 0; + + pkt_phys = dma_map_single(sdcp->dev, pkt, sizeof(*pkt), + DMA_BIDIRECTIONAL); + if (dma_mapping_error(sdcp->dev, pkt_phys)) { + dev_err(sdcp->dev, "Unable to map packet descriptor\n"); + return; + } + + /* submit the work */ + mutex_lock(mutex); + + HW_DCP_CHnSTAT_CLR(chan, -1); + + /* Load the work packet pointer and bump the channel semaphore */ + HW_DCP_CHnCMDPTR_WR(chan, (u32)pkt_phys); + + /* XXX wake from interrupt instead of looping */ + timeout = jiffies + msecs_to_jiffies(1000); + + sdcp->wait[chan] = 0; + HW_DCP_CHnSEMA_WR(chan, BF_DCP_CHnSEMA_INCREMENT(1)); + while (time_before(jiffies, timeout) && sdcp->wait[chan] == 0) + cpu_relax(); + + if (!time_before(jiffies, timeout)) { + dev_err(sdcp->dev, "Timeout while waiting STAT 0x%08x\n", + HW_DCP_STAT_RD()); + goto out; + } + + stat = HW_DCP_CHnSTAT_RD(chan); + if ((stat & 0xff) != 0) + dev_err(sdcp->dev, "Channel stat error 0x%02x\n", + HW_DCP_CHnSTAT_RD(chan) & 0xff); +out: + mutex_unlock(mutex); + + dma_unmap_single(sdcp->dev, pkt_phys, sizeof(*pkt), DMA_TO_DEVICE); +} + +static int dcp_aes_setkey_cip(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + unsigned int ret; + + op->cipher.keylen = len; + + if (len == AES_KEYSIZE_128) { + memcpy(op->cipher.key, key, len); + return 0; + } + + if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { + /* not supported at all */ + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* + * The requested key size is not supported by HW, do a fallback + */ + op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.blk->base.crt_flags |= (tfm->crt_flags & + CRYPTO_TFM_REQ_MASK); + + ret = crypto_cipher_setkey(op->fallback.cip, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (op->fallback.blk->base.crt_flags & + CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static void dcp_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + + if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) { + crypto_cipher_encrypt_one(op->fallback.cip, out, in); + return; + } + + op->src = (void *) in; + op->dst = (void *) out; + op->flags = STMP3XXX_DCP_AES | STMP3XXX_DCP_ENC | STMP3XXX_DCP_ECB; + op->len = AES_KEYSIZE_128; + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, (void *)in, AES_KEYSIZE_128, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dev_err(sdcp->dev, "Unable to map source\n"); + return; + } + + op->dst_phys = dma_map_single(sdcp->dev, out, AES_KEYSIZE_128, + DMA_FROM_DEVICE); + if (dma_mapping_error(sdcp->dev, op->dst_phys)) { + dev_err(sdcp->dev, "Unable to map dest\n"); + goto err_unmap_src; + } + + op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key, + AES_KEYSIZE_128, DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) { + dev_err(sdcp->dev, "Unable to map key\n"); + goto err_unmap_dst; + } + + /* perform the operation */ + dcp_perform_op(op); + + dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128, + DMA_TO_DEVICE); +err_unmap_dst: + dma_unmap_single(sdcp->dev, op->dst_phys, op->len, DMA_FROM_DEVICE); +err_unmap_src: + dma_unmap_single(sdcp->dev, op->src_phys, op->len, DMA_TO_DEVICE); +} + +static void dcp_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + + if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) { + crypto_cipher_decrypt_one(op->fallback.cip, out, in); + return; + } + + op->src = (void *) in; + op->dst = (void *) out; + op->flags = STMP3XXX_DCP_AES | STMP3XXX_DCP_DEC | STMP3XXX_DCP_ECB; + op->len = AES_KEYSIZE_128; + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, (void *)in, AES_KEYSIZE_128, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dev_err(sdcp->dev, "Unable to map source\n"); + return; + } + + op->dst_phys = dma_map_single(sdcp->dev, out, AES_KEYSIZE_128, + DMA_FROM_DEVICE); + if (dma_mapping_error(sdcp->dev, op->dst_phys)) { + dev_err(sdcp->dev, "Unable to map dest\n"); + goto err_unmap_src; + } + + op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key, + AES_KEYSIZE_128, DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) { + dev_err(sdcp->dev, "Unable to map key\n"); + goto err_unmap_dst; + } + + /* perform the operation */ + dcp_perform_op(op); + + dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128, + DMA_TO_DEVICE); +err_unmap_dst: + dma_unmap_single(sdcp->dev, op->dst_phys, op->len, DMA_FROM_DEVICE); +err_unmap_src: + dma_unmap_single(sdcp->dev, op->src_phys, op->len, DMA_TO_DEVICE); +} + +static int fallback_init_cip(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + + op->fallback.cip = crypto_alloc_cipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(op->fallback.cip)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.cip); + } + + return 0; +} + +static void fallback_exit_cip(struct crypto_tfm *tfm) +{ + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + + crypto_free_cipher(op->fallback.cip); + op->fallback.cip = NULL; +} + +static struct crypto_alg dcp_aes_alg = { + .cra_name = "aes", + .cra_driver_name = "dcp-aes", + .cra_priority = 300, + .cra_alignmask = 15, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_cip, + .cra_exit = fallback_exit_cip, + .cra_blocksize = AES_KEYSIZE_128, + .cra_ctxsize = sizeof(struct stmp3xxx_dcp_op), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(dcp_aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = dcp_aes_setkey_cip, + .cia_encrypt = dcp_aes_encrypt, + .cia_decrypt = dcp_aes_decrypt + } + } +}; + +static int dcp_aes_setkey_blk(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + unsigned int ret; + + op->cipher.keylen = len; + + if (len == AES_KEYSIZE_128) { + memcpy(op->cipher.key, key, len); + return 0; + } + + if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { + /* not supported at all */ + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* + * The requested key size is not supported by HW, do a fallback + */ + op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.blk->base.crt_flags |= (tfm->crt_flags & + CRYPTO_TFM_REQ_MASK); + + ret = crypto_blkcipher_setkey(op->fallback.blk, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (op->fallback.blk->base.crt_flags & + CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int fallback_blk_dec(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct stmp3xxx_dcp_op *op = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = op->fallback.blk; + + ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int fallback_blk_enc(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct stmp3xxx_dcp_op *op = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = op->fallback.blk; + + ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int fallback_init_blk(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + + op->fallback.blk = crypto_alloc_blkcipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(op->fallback.blk)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.blk); + } + + return 0; +} + +static void fallback_exit_blk(struct crypto_tfm *tfm) +{ + struct stmp3xxx_dcp_op *op = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(op->fallback.blk); + op->fallback.blk = NULL; +} + +static int +dcp_aes_ecb_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_op *op = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err; + + if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) + return fallback_blk_dec(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + + /* key needs to be mapped only once */ + op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key, + AES_KEYSIZE_128, DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) { + dev_err(sdcp->dev, "Unable to map key\n"); + return -ENOMEM; + } + + err = blkcipher_walk_virt(desc, &walk); + while (err == 0 && (nbytes = walk.nbytes) > 0) { + op->src = walk.src.virt.addr, + op->dst = walk.dst.virt.addr; + op->flags = STMP3XXX_DCP_AES | STMP3XXX_DCP_DEC | + STMP3XXX_DCP_ECB; + op->len = nbytes - (nbytes % AES_KEYSIZE_128); + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, op->src, op->len, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dev_err(sdcp->dev, "Unable to map source\n"); + err = -ENOMEM; + break; + } + + op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(sdcp->dev, op->dst_phys)) { + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + dev_err(sdcp->dev, "Unable to map dest\n"); + err = -ENOMEM; + break; + } + + /* perform! */ + dcp_perform_op(op); + + dma_unmap_single(sdcp->dev, op->dst_phys, op->len, + DMA_FROM_DEVICE); + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + + nbytes -= op->len; + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128, + DMA_TO_DEVICE); + + return err; +} + +static int +dcp_aes_ecb_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_op *op = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err, ret; + + if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) + return fallback_blk_enc(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + + /* key needs to be mapped only once */ + op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key, + AES_KEYSIZE_128, DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) { + dev_err(sdcp->dev, "Unable to map key\n"); + return -ENOMEM; + } + + err = blkcipher_walk_virt(desc, &walk); + + err = 0; + while (err == 0 && (nbytes = walk.nbytes) > 0) { + op->src = walk.src.virt.addr, + op->dst = walk.dst.virt.addr; + op->flags = STMP3XXX_DCP_AES | STMP3XXX_DCP_ENC | + STMP3XXX_DCP_ECB; + op->len = nbytes - (nbytes % AES_KEYSIZE_128); + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, op->src, op->len, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dev_err(sdcp->dev, "Unable to map source\n"); + err = -ENOMEM; + break; + } + + op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(sdcp->dev, op->dst_phys)) { + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + dev_err(sdcp->dev, "Unable to map dest\n"); + err = -ENOMEM; + break; + } + + /* perform! */ + dcp_perform_op(op); + + dma_unmap_single(sdcp->dev, op->dst_phys, op->len, + DMA_FROM_DEVICE); + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + + nbytes -= op->len; + ret = blkcipher_walk_done(desc, &walk, nbytes); + } + + dma_unmap_single(sdcp->dev, op->cipher.key_phys, AES_KEYSIZE_128, + DMA_TO_DEVICE); + + return err; +} + + +static struct crypto_alg dcp_aes_ecb_alg = { + .cra_name = "ecb(aes)", + .cra_driver_name = "dcp-ecb-aes", + .cra_priority = 400, + .cra_alignmask = 15, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, + .cra_blocksize = AES_KEYSIZE_128, + .cra_ctxsize = sizeof(struct stmp3xxx_dcp_op), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(dcp_aes_ecb_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = dcp_aes_setkey_blk, + .encrypt = dcp_aes_ecb_encrypt, + .decrypt = dcp_aes_ecb_decrypt + } + } +}; + +static int +dcp_aes_cbc_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_op *op = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err, blockno; + + if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) + return fallback_blk_dec(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + + blockno = 0; + err = blkcipher_walk_virt(desc, &walk); + while (err == 0 && (nbytes = walk.nbytes) > 0) { + op->src = walk.src.virt.addr, + op->dst = walk.dst.virt.addr; + op->flags = STMP3XXX_DCP_AES | STMP3XXX_DCP_DEC | + STMP3XXX_DCP_CBC; + if (blockno == 0) { + op->flags |= STMP3XXX_DCP_CBC_INIT; + memcpy(op->cipher.key + AES_KEYSIZE_128, walk.iv, + AES_KEYSIZE_128); + } + op->len = nbytes - (nbytes % AES_KEYSIZE_128); + + /* key (+iv) needs to be mapped only once */ + op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) { + dev_err(sdcp->dev, "Unable to map key\n"); + err = -ENOMEM; + break; + } + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, op->src, op->len, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dma_unmap_single(sdcp->dev, op->cipher.key_phys, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + dev_err(sdcp->dev, "Unable to map source\n"); + err = -ENOMEM; + break; + } + + op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(sdcp->dev, op->dst_phys)) { + dma_unmap_single(sdcp->dev, op->cipher.key_phys, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + dev_err(sdcp->dev, "Unable to map dest\n"); + err = -ENOMEM; + break; + } + + /* perform! */ + dcp_perform_op(op); + + dma_unmap_single(sdcp->dev, op->cipher.key_phys, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + dma_unmap_single(sdcp->dev, op->dst_phys, op->len, + DMA_FROM_DEVICE); + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + + nbytes -= op->len; + err = blkcipher_walk_done(desc, &walk, nbytes); + + blockno++; + } + + return err; +} + +static int +dcp_aes_cbc_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_op *op = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + int err, ret, blockno; + + if (unlikely(op->cipher.keylen != AES_KEYSIZE_128)) + return fallback_blk_enc(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + + blockno = 0; + + err = blkcipher_walk_virt(desc, &walk); + while (err == 0 && (nbytes = walk.nbytes) > 0) { + op->src = walk.src.virt.addr, + op->dst = walk.dst.virt.addr; + op->flags = STMP3XXX_DCP_AES | STMP3XXX_DCP_ENC | + STMP3XXX_DCP_CBC; + if (blockno == 0) { + op->flags |= STMP3XXX_DCP_CBC_INIT; + memcpy(op->cipher.key + AES_KEYSIZE_128, walk.iv, + AES_KEYSIZE_128); + } + op->len = nbytes - (nbytes % AES_KEYSIZE_128); + + /* key needs to be mapped only once */ + op->cipher.key_phys = dma_map_single(sdcp->dev, op->cipher.key, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + if (dma_mapping_error(sdcp->dev, op->cipher.key_phys)) { + dev_err(sdcp->dev, "Unable to map key\n"); + return -ENOMEM; + } + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, op->src, op->len, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dma_unmap_single(sdcp->dev, op->cipher.key_phys, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + dev_err(sdcp->dev, "Unable to map source\n"); + err = -ENOMEM; + break; + } + + op->dst_phys = dma_map_single(sdcp->dev, op->dst, op->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(sdcp->dev, op->dst_phys)) { + dma_unmap_single(sdcp->dev, op->cipher.key_phys, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + dev_err(sdcp->dev, "Unable to map dest\n"); + err = -ENOMEM; + break; + } + + /* perform! */ + dcp_perform_op(op); + + dma_unmap_single(sdcp->dev, op->cipher.key_phys, + AES_KEYSIZE_128 * 2, DMA_BIDIRECTIONAL); + dma_unmap_single(sdcp->dev, op->dst_phys, op->len, + DMA_FROM_DEVICE); + dma_unmap_single(sdcp->dev, op->src_phys, op->len, + DMA_TO_DEVICE); + + nbytes -= op->len; + ret = blkcipher_walk_done(desc, &walk, nbytes); + + blockno++; + } + + return err; +} + +static struct crypto_alg dcp_aes_cbc_alg = { + .cra_name = "cbc(aes)", + .cra_driver_name = "dcp-cbc-aes", + .cra_priority = 400, + .cra_alignmask = 15, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, + .cra_blocksize = AES_KEYSIZE_128, + .cra_ctxsize = sizeof(struct stmp3xxx_dcp_op), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(dcp_aes_cbc_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = dcp_aes_setkey_blk, + .encrypt = dcp_aes_cbc_encrypt, + .decrypt = dcp_aes_cbc_decrypt, + .ivsize = AES_KEYSIZE_128, + } + } +}; + +#ifndef DISABLE_SHA1 + +static void dcp_perform_hash_op(struct stmp3xxx_dcp_hash_op *op) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct mutex *mutex; + int chan; + struct stmp3xxx_dcp_hw_packet *pkt; + unsigned long timeout; + u32 stat; + int size1, descno; + + BUG_ON((op->flags & STMP3XXX_DCP_MODE_MASK) != STMP3XXX_DCP_SHA1); + + chan = HASH_CHAN; + + switch (op->flags & (STMP3XXX_DCP_INIT | STMP3XXX_DCP_UPDATE | + STMP3XXX_DCP_FINAL)) { + + case STMP3XXX_DCP_INIT | STMP3XXX_DCP_UPDATE: + + BUG_ON(op->len <= 1); + + pkt = &op->hw->pkt[0]; + pkt->pNext = 0; + pkt->pkt1 = BM_DCP_PACKET1_HASH_INIT | + BM_DCP_PACKET1_DECR_SEMAPHORE | + BM_DCP_PACKET1_INTERRUPT | + BM_DCP_PACKET1_ENABLE_HASH; + pkt->pkt2 = BF_DCP_PACKET2_HASH_SELECT( + BV_DCP_PACKET2_HASH_SELECT__SHA1); + pkt->pSrc = (u32)op->src_phys; + pkt->pDst = 0; + pkt->size = op->len - 1; + pkt->pPayload = 0; + pkt->stat = 0; + + /* save last byte */ + op->hw->rembuf[1] = ((u8 *)op->src)[op->len - 1]; + + descno = 1; + break; + + case STMP3XXX_DCP_UPDATE: + + BUG_ON(op->len <= 1); + + op->hw->rembuf[0] = op->hw->rembuf[1]; + + pkt = &op->hw->pkt[0]; + pkt->pNext = 0; + pkt->pkt1 = BM_DCP_PACKET1_CHAIN_CONTIGUOUS | + BM_DCP_PACKET1_ENABLE_HASH; + pkt->pkt2 = BF_DCP_PACKET2_HASH_SELECT( + BV_DCP_PACKET2_HASH_SELECT__SHA1); + pkt->pSrc = (u32)op->hw_phys + offsetof( + struct stmp3xxx_dcp_hash_coherent_block, rembuf); + pkt->pDst = 0; + pkt->size = 1; + pkt->pPayload = 0; + pkt->stat = 0; + + pkt = &op->hw->pkt[1]; + pkt->pNext = 0; + pkt->pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE | + BM_DCP_PACKET1_INTERRUPT | + BM_DCP_PACKET1_ENABLE_HASH; + pkt->pkt2 = BF_DCP_PACKET2_HASH_SELECT( + BV_DCP_PACKET2_HASH_SELECT__SHA1); + pkt->pSrc = (u32)op->src_phys; + pkt->pDst = 0; + pkt->size = op->len - 1; + pkt->pPayload = 0; + pkt->stat = 0; + + /* save last byte */ + op->hw->rembuf[1] = ((u8 *)op->src)[op->len - 1]; + + descno = 2; + + break; + + case STMP3XXX_DCP_FINAL: + + op->hw->rembuf[0] = op->hw->rembuf[1]; + + pkt = &op->hw->pkt[0]; + pkt->pNext = 0; + pkt->pkt1 = BM_DCP_PACKET1_HASH_TERM | + BM_DCP_PACKET1_DECR_SEMAPHORE | + BM_DCP_PACKET1_INTERRUPT | + BM_DCP_PACKET1_ENABLE_HASH; + pkt->pkt2 = BF_DCP_PACKET2_HASH_SELECT( + BV_DCP_PACKET2_HASH_SELECT__SHA1); + pkt->pSrc = (u32)op->hw_phys + offsetof( + struct stmp3xxx_dcp_hash_coherent_block, rembuf); + pkt->pDst = 0; + pkt->size = 1; + pkt->pPayload = (u32)op->hw_phys + offsetof( + struct stmp3xxx_dcp_hash_coherent_block, digest); + pkt->stat = 0; + + descno = 1; + + break; + + /* all others BUG */ + default: + BUG(); + return; + } + + mutex = &sdcp->op_mutex[chan]; + + /* submit the work */ + mutex_lock(mutex); + + HW_DCP_CHnSTAT_CLR(chan, -1); + + mb(); + /* Load the work packet pointer and bump the channel semaphore */ + HW_DCP_CHnCMDPTR_WR(chan, (u32)op->hw_phys + + offsetof(struct stmp3xxx_dcp_hash_coherent_block, pkt[0])); + + /* XXX wake from interrupt instead of looping */ + timeout = jiffies + msecs_to_jiffies(1000); + + HW_DCP_CHnSEMA_WR(chan, BF_DCP_CHnSEMA_INCREMENT(descno)); + + while (time_before(jiffies, timeout) && + ((HW_DCP_CHnSEMA_RD(chan) >> 16) & 0xff) != 0) + cpu_relax(); + + if (!time_before(jiffies, timeout)) { + dev_err(sdcp->dev, "Timeout while waiting STAT 0x%08x\n", + HW_DCP_STAT_RD()); + goto out; + } + + stat = HW_DCP_CHnSTAT_RD(chan); + if ((stat & 0xff) != 0) + dev_err(sdcp->dev, "Channel stat error 0x%02x\n", + HW_DCP_CHnSTAT_RD(chan) & 0xff); + +out: + mutex_unlock(mutex); + + mdelay(500); +} + +static int fallback_init_hash(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct stmp3xxx_dcp_hash_op *op = crypto_tfm_ctx(tfm); + struct stmp3xxx_dcp *sdcp = global_sdcp; + + op->fallback.hash = crypto_alloc_hash(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(op->fallback.hash)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.hash); + } + + op->hw = dma_alloc_coherent(sdcp->dev, sizeof(*op->hw), &op->hw_phys, + GFP_KERNEL); + if (op->hw == NULL) { + printk(KERN_ERR "Error allocating coherent block for %s\n", + name); + crypto_free_hash(op->fallback.hash); + op->fallback.hash = NULL; + return -ENOMEM; + } + memset(op->hw, 0, sizeof(*op->hw)); + + return 0; +} + +static void fallback_exit_hash(struct crypto_tfm *tfm) +{ + struct stmp3xxx_dcp_hash_op *op = crypto_tfm_ctx(tfm); + struct stmp3xxx_dcp *sdcp = global_sdcp; + + dma_free_coherent(sdcp->dev, sizeof(*op->hw), op->hw, op->hw_phys); + crypto_free_hash(op->fallback.hash); + op->fallback.hash = NULL; +} + +static void dcp_sha1_init(struct crypto_tfm *tfm) +{ + struct stmp3xxx_dcp_hash_op *op = crypto_tfm_ctx(tfm); + + op->hash.init = 1; + memset(op->hw->rembuf, 0, sizeof(op->hw->rembuf)); + memset(op->hw->digest, 0, sizeof(op->hw->digest)); +} + +static void dcp_sha1_update(struct crypto_tfm *tfm, + const uint8_t *data, unsigned int length) +{ + struct stmp3xxx_dcp *sdcp = global_sdcp; + struct stmp3xxx_dcp_hash_op *op = crypto_tfm_ctx(tfm); + + op->src = (void *)data; + op->dst = NULL; + op->flags = STMP3XXX_DCP_SHA1 | STMP3XXX_DCP_UPDATE; + if (op->hash.init) { + op->hash.init = 0; + op->flags |= STMP3XXX_DCP_INIT; + } + op->len = length; + + /* map the data */ + op->src_phys = dma_map_single(sdcp->dev, op->src, op->len, + DMA_TO_DEVICE); + if (dma_mapping_error(sdcp->dev, op->src_phys)) { + dev_err(sdcp->dev, "Unable to map source\n"); + return; + } + op->dst_phys = 0; + + /* perform! */ + dcp_perform_hash_op(op); + + dma_unmap_single(sdcp->dev, op->src_phys, op->len, DMA_TO_DEVICE); +} + +static void dcp_sha1_final(struct crypto_tfm *tfm, uint8_t *out) +{ + struct stmp3xxx_dcp_hash_op *op = crypto_tfm_ctx(tfm); + int i; + const uint8_t *digest; + + op->src = NULL; + op->dst = NULL; + op->flags = STMP3XXX_DCP_SHA1 | STMP3XXX_DCP_FINAL; + op->len = 0; + + /* perform! */ + dcp_perform_hash_op(op); + + /* hardware reverses the digest (for some unexplicable reason) */ + digest = op->hw->digest + SHA1_DIGEST_SIZE; + for (i = 0; i < SHA1_DIGEST_SIZE; i++) + *out++ = *--digest; + memcpy(out, op->hw->digest, SHA1_DIGEST_SIZE); +} + +static struct crypto_alg dcp_sha1_alg = { + .cra_name = "sha1", + .cra_driver_name = "dcp-sha1", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_DIGEST | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct stmp3xxx_dcp_hash_op), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(dcp_sha1_alg.cra_list), + .cra_init = fallback_init_hash, + .cra_exit = fallback_exit_hash, + .cra_u = { + .digest = { + .dia_digestsize = SHA1_DIGEST_SIZE, + .dia_init = dcp_sha1_init, + .dia_update = dcp_sha1_update, + .dia_final = dcp_sha1_final, + } + } +}; +#endif + +static irqreturn_t dcp_common_irq(int irq, void *context) +{ + struct stmp3xxx_dcp *sdcp = context; + u32 msk; + + /* check */ + msk = HW_DCP_STAT_RD() & BF_DCP_STAT_IRQ(0x0f); + if (msk == 0) + return IRQ_NONE; + + /* clear this channel */ + HW_DCP_STAT_CLR(msk); + if (msk & BF_DCP_STAT_IRQ(0x01)) + sdcp->wait[0]++; + if (msk & BF_DCP_STAT_IRQ(0x02)) + sdcp->wait[1]++; + if (msk & BF_DCP_STAT_IRQ(0x04)) + sdcp->wait[2]++; + if (msk & BF_DCP_STAT_IRQ(0x08)) + sdcp->wait[3]++; + return IRQ_HANDLED; +} + +static irqreturn_t dcp_vmi_irq(int irq, void *context) +{ + return dcp_common_irq(irq, context); +} + +static irqreturn_t dcp_irq(int irq, void *context) +{ + return dcp_common_irq(irq, context); +} + +static int stmp3xxx_dcp_probe(struct platform_device *pdev) +{ + struct stmp3xxx_dcp *sdcp = NULL; + struct resource *r; + int i, ret; + + if (global_sdcp != NULL) { + dev_err(&pdev->dev, "Only one instance allowed\n"); + ret = -ENODEV; + goto err; + } + + /* allocate memory */ + sdcp = kzalloc(sizeof(*sdcp), GFP_KERNEL); + if (sdcp == NULL) { + dev_err(&pdev->dev, "Failed to allocate structure\n"); + ret = -ENOMEM; + goto err; + } + + sdcp->dev = &pdev->dev; + spin_lock_init(&sdcp->lock); + + for (i = 0; i < STMP3XXX_DCP_NUM_CHANNELS; i++) { + mutex_init(&sdcp->op_mutex[i]); + init_completion(&sdcp->op_wait[i]); + } + + ret = crypto_register_alg(&dcp_aes_alg); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register aes crypto\n"); + goto err_kfree; + } + + ret = crypto_register_alg(&dcp_aes_ecb_alg); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register aes ecb crypto\n"); + goto err_unregister_aes; + } + + ret = crypto_register_alg(&dcp_aes_cbc_alg); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register aes cbc crypto\n"); + goto err_unregister_aes_ecb; + } + +#ifndef DISABLE_SHA1 + ret = crypto_register_alg(&dcp_sha1_alg); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register aes cbc crypto\n"); + goto err_unregister_aes_cbc; + } +#endif + + platform_set_drvdata(pdev, sdcp); + + /* Soft reset and remove the clock gate */ + HW_DCP_CTRL_SET(BM_DCP_CTRL_SFTRST); + + /* At 24Mhz, it takes no more than 4 clocks (160 ns) Maximum for + * the part to reset, reading the register twice should + * be sufficient to get 4 clks delay. + */ + HW_DCP_CTRL_RD(); + HW_DCP_CTRL_RD(); + + HW_DCP_CTRL_CLR(BM_DCP_CTRL_SFTRST | BM_DCP_CTRL_CLKGATE); + + /* Initialize control registers */ + HW_DCP_CTRL_WR(STMP3XXX_DCP_CTRL_INIT); + HW_DCP_CHANNELCTRL_WR(STMP3XXX_DCP_CHANNELCTRL_INIT); + + /* We do not enable context switching. Give the context + * buffer pointer an illegal address so if context switching is + * inadvertantly enabled, the dcp will return an error instead of + * trashing good memory. The dcp dma cannot access rom, so any rom + * address will do. + */ + HW_DCP_CONTEXT_WR(0xFFFF0000); + + for (i = 0; i < STMP3XXX_DCP_NUM_CHANNELS; i++) + HW_DCP_CHnSTAT_CLR(i, -1); + HW_DCP_STAT_CLR(-1); + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) { + dev_err(&pdev->dev, "can't get IRQ resource (0)\n"); + ret = -EIO; + goto err_unregister_sha1; + } + sdcp->dcp_vmi_irq = r->start; + ret = request_irq(sdcp->dcp_vmi_irq, dcp_vmi_irq, 0, "stmp3xxx-dcp", + sdcp); + if (ret != 0) { + dev_err(&pdev->dev, "can't request_irq (0)\n"); + goto err_unregister_sha1; + } + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!r) { + dev_err(&pdev->dev, "can't get IRQ resource (1)\n"); + ret = -EIO; + goto err_free_irq0; + } + sdcp->dcp_irq = r->start; + ret = request_irq(sdcp->dcp_irq, dcp_irq, 0, "stmp3xxx-dcp", sdcp); + if (ret != 0) { + dev_err(&pdev->dev, "can't request_irq (1)\n"); + goto err_free_irq0; + } + + global_sdcp = sdcp; + + dev_notice(&pdev->dev, "DCP crypto enabled.!\n"); + return 0; + +err_free_irq0: + free_irq(sdcp->dcp_vmi_irq, sdcp); +err_unregister_sha1: +#ifndef DISABLE_SHA1 + crypto_unregister_alg(&dcp_sha1_alg); +#endif +err_unregister_aes_cbc: + crypto_unregister_alg(&dcp_aes_cbc_alg); +err_unregister_aes_ecb: + crypto_unregister_alg(&dcp_aes_ecb_alg); +err_unregister_aes: + crypto_unregister_alg(&dcp_aes_alg); +err_kfree: + kfree(sdcp); +err: + + return ret; +} + +static int stmp3xxx_dcp_remove(struct platform_device *pdev) +{ + struct stmp3xxx_dcp *sdcp; + + sdcp = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + free_irq(sdcp->dcp_irq, sdcp); + free_irq(sdcp->dcp_vmi_irq, sdcp); +#ifndef DISABLE_SHA1 + crypto_unregister_alg(&dcp_sha1_alg); +#endif + crypto_unregister_alg(&dcp_aes_cbc_alg); + crypto_unregister_alg(&dcp_aes_ecb_alg); + crypto_unregister_alg(&dcp_aes_alg); + kfree(sdcp); + global_sdcp = NULL; + + return 0; +} + + +#ifdef CONFIG_PM +static int stmp3xxx_dcp_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return 0; +} + +static int stmp3xxx_dcp_resume(struct platform_device *pdev) +{ + return 0; +} +#else +#define stmp3xxx_dcp_suspend NULL +#define stmp3xxx_dcp_resume NULL +#endif + +static struct platform_driver stmp3xxx_dcp_driver = { + .probe = stmp3xxx_dcp_probe, + .remove = stmp3xxx_dcp_remove, + .suspend = stmp3xxx_dcp_suspend, + .resume = stmp3xxx_dcp_resume, + .driver = { + .name = "stmp3xxx-dcp", + .owner = THIS_MODULE, + }, +}; + +static int __init +stmp3xxx_dcp_init(void) +{ + return platform_driver_register(&stmp3xxx_dcp_driver); +} + +static void __exit +stmp3xxx_dcp_exit(void) +{ + platform_driver_unregister(&stmp3xxx_dcp_driver); +} + +MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>"); +MODULE_DESCRIPTION("STMP3XXX DCP Crypto Driver"); +MODULE_LICENSE("GPL"); + +module_init(stmp3xxx_dcp_init); +module_exit(stmp3xxx_dcp_exit); diff --git a/drivers/crypto/stmp3xxx_dcp.h b/drivers/crypto/stmp3xxx_dcp.h new file mode 100644 index 000000000000..32ae0c704daf --- /dev/null +++ b/drivers/crypto/stmp3xxx_dcp.h @@ -0,0 +1,68 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef _STMP3XXX_DCP_H_ +#define _STMP3XXX_DCP_H_ + +#include <mach/stmp3xxx_regs.h> +#include <mach/stmp3xxx.h> +#include <mach/regs-dcp.h> + +#define CIPHER_CHAN 1 +#define CIPHER_MASK (1 << CIPHER_CHAN) + +#define HASH_CHAN 0 +#define HASH_MASK (1 << HASH_CHAN) + +#define ALL_MASK (CIPHER_MASK | HASH_MASK) + +/* Defines the initialization value for the dcp control register */ +#define STMP3XXX_DCP_CTRL_INIT \ + (BM_DCP_CTRL_GATHER_RESIDUAL_WRITES | \ + BM_DCP_CTRL_ENABLE_CONTEXT_CACHING | \ + BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH0 | \ + BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH1 | \ + BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH2 | \ + BV_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE__CH3) + +/* Defines the initialization value for the dcp channel control register */ +#define STMP3XXX_DCP_CHANNELCTRL_INIT \ + BF_DCP_CHANNELCTRL_ENABLE_CHANNEL(ALL_MASK) + +/* DCP work packet 1 value for encryption */ +#define STMP3XXX_DCP_PKT1_ENCRYPT \ + (BM_DCP_PACKET1_DECR_SEMAPHORE | \ + BM_DCP_PACKET1_ENABLE_CIPHER | \ + BM_DCP_PACKET1_CIPHER_ENCRYPT | \ + BM_DCP_PACKET1_CIPHER_INIT) + +/* DCP work packet 1 value for decryption */ +#define DCP_PKT1_DECRYPT \ + (BM_DCP_PACKET1_DECR_SEMAPHORE | \ + BM_DCP_PACKET1_ENABLE_CIPHER | \ + BM_DCP_PACKET1_CIPHER_INIT) + +/* DCP (decryption) work packet definition */ +struct stmp3xxx_dcp_hw_packet { + uint32_t pNext; /* next dcp work packet address */ + uint32_t pkt1; /* dcp work packet 1 (control 0) */ + uint32_t pkt2; /* dcp work packet 2 (control 1) */ + uint32_t pSrc; /* source buffer address */ + uint32_t pDst; /* destination buffer address */ + uint32_t size; /* buffer size in bytes */ + uint32_t pPayload; /* payload buffer address */ + uint32_t stat; /* dcp status (written by dcp) */ +}; + +#define STMP3XXX_DCP_NUM_CHANNELS 4 + +#endif diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 58cb6a19627f..d469bd3b0050 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -328,6 +328,10 @@ config I2C_DAVINCI config I2C_GPIO tristate "GPIO-based bitbanging I2C" depends on GENERIC_GPIO + +config I2C_PARPORT + tristate "Parallel port adapter" + depends on PARPORT select I2C_ALGOBIT help This is a very simple bitbanging I2C driver utilizing the @@ -409,6 +413,12 @@ config I2C_MXC_HS This driver can also be built as a module. +config I2C_STMP378X + tristate "STMP378x I2C adapter" + depends on MACH_STMP378X + help + TBD + config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index f6612e80569c..39464aa9779d 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o obj-$(CONFIG_I2C_MXC) += mxc_i2c.o obj-$(CONFIG_I2C_MXC_HS) += mxc_i2c_hs.o +obj-$(CONFIG_I2C_STMP378X) += i2c-stmp378x.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/busses/i2c-stmp378x.c b/drivers/i2c/busses/i2c-stmp378x.c new file mode 100644 index 000000000000..4a01b55f5f07 --- /dev/null +++ b/drivers/i2c/busses/i2c-stmp378x.c @@ -0,0 +1,337 @@ +/* + * Freescale STMP378X I2C bus driver + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/completion.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <mach/regs-i2c.h> +#include <mach/regs-apbx.h> +#include <mach/i2c.h> + +static void reset_i2c_module(void) +{ + int count; + count = 1000; + HW_I2C_CTRL0_SET(BM_I2C_CTRL0_SFTRST); + udelay(10); /* Reseting the module can take multiple clocks.*/ + while (--count && (!(HW_I2C_CTRL0_RD() & BM_I2C_CTRL0_CLKGATE))) + udelay(1); + + if (!count) { + printk(KERN_ERR "timeout reseting the module\n"); + BUG(); + } + + /* take controller out of reset */ + HW_I2C_CTRL0_CLR(BM_I2C_CTRL0_SFTRST | BM_I2C_CTRL0_CLKGATE); + udelay(10); + HW_I2C_CTRL1_SET(0x0000FF00); /* Wil catch all error (IRQ mask) */ + +} + +/* + * Low level master read/write transaction. + */ +static int stmp378x_i2c_xfer_msg(struct i2c_adapter *adap, + struct i2c_msg *msg, int stop) +{ + struct stmp378x_i2c_dev *dev = i2c_get_adapdata(adap); + int err; + + init_completion(&dev->cmd_complete); + dev->cmd_err = 0; + + dev_dbg(dev->dev, " Start XFER ===>\n"); + dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", + msg->addr, msg->len, msg->flags, stop); + + if ((msg->len == 0) || (msg->len > (PAGE_SIZE - 1))) + return -EINVAL; + + if (msg->flags & I2C_M_RD) { + hw_i2c_setup_read(msg->addr , + msg->buf , + msg->len, + stop ? BM_I2C_CTRL0_POST_SEND_STOP : 0); + + hw_i2c_run(1); /* read */ + } else { + hw_i2c_setup_write(msg->addr , + msg->buf , + msg->len, + stop ? BM_I2C_CTRL0_POST_SEND_STOP : 0); + + hw_i2c_run(0); /* write */ + } + + err = wait_for_completion_interruptible_timeout( + &dev->cmd_complete, + msecs_to_jiffies(1000) + ); + + if (err < 0) { + dev_dbg(dev->dev, "controler is timed out\n"); + return -ETIMEDOUT; + } + if ((!dev->cmd_err) && (msg->flags & I2C_M_RD)) + hw_i2c_finish_read(msg->buf, msg->len); + + dev_dbg(dev->dev, "<============= Done with err=%d\n", dev->cmd_err); + + + return dev->cmd_err; +} + + +static int +stmp378x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + int i; + int err; + + if (!msgs->len) + return -EINVAL; + + for (i = 0; i < num; i++) { + err = stmp378x_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); + if (err) + break; + } + + if (err == 0) + err = num; + + return err; +} + +static u32 +stmp378x_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +/* + * Debug. Don't need dma_irq for the final version + */ + +static irqreturn_t +stmp378x_i2c_dma_isr(int this_irq, void *dev_id) +{ + hw_i2c_clear_dma_interrupt(); + return IRQ_HANDLED; + +} + +#define I2C_IRQ_MASK 0x000000FF + +static irqreturn_t +stmp378x_i2c_isr(int this_irq, void *dev_id) +{ + struct stmp378x_i2c_dev *dev = dev_id; + u32 stat; + u32 done_mask = + BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | + BM_I2C_CTRL1_BUS_FREE_IRQ ; + + stat = HW_I2C_CTRL1_RD() & I2C_IRQ_MASK; + if (!stat) + return IRQ_NONE; + + if (stat & BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ) { + dev->cmd_err = -EREMOTEIO; + + /* + * Stop DMA + * Clear NAK + */ + HW_I2C_CTRL1_SET(BM_I2C_CTRL1_CLR_GOT_A_NAK); + hw_i2c_reset_dma(); + reset_i2c_module(); + + complete(&dev->cmd_complete); + + goto done; + } + +/* Don't care about BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ */ + if (stat & ( + BM_I2C_CTRL1_EARLY_TERM_IRQ | + BM_I2C_CTRL1_MASTER_LOSS_IRQ | + BM_I2C_CTRL1_SLAVE_STOP_IRQ | + BM_I2C_CTRL1_SLAVE_IRQ + )) { + dev->cmd_err = -EIO; + complete(&dev->cmd_complete); + goto done; + } + if ((stat & done_mask) == done_mask) + complete(&dev->cmd_complete); + + +done: + HW_I2C_CTRL1_CLR(stat); + return IRQ_HANDLED; +} + +static const struct i2c_algorithm stmp378x_i2c_algo = { + .master_xfer = stmp378x_i2c_xfer, + .functionality = stmp378x_i2c_func, +}; + + +static int +stmp378x_i2c_probe(struct platform_device *pdev) +{ + struct stmp378x_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *irq; + int err = 0; + + /* NOTE: driver uses the static register mapping */ + dev = kzalloc(sizeof(struct stmp378x_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "no mem \n"); + return -ENOMEM; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); /* Error */ + if (!irq) { + dev_err(&pdev->dev, "no err_irq resource\n"); + err = -ENODEV; + goto nores; + } + dev->irq_err = irq->start; + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1); /* DMA */ + if (!irq) { + dev_err(&pdev->dev, "no dma_irq resource\n"); + err = -ENODEV; + goto nores; + } + + dev->irq_dma = irq->start; + dev->dev = &pdev->dev; + + err = request_irq(dev->irq_err, stmp378x_i2c_isr, 0, pdev->name, dev); + if (err) { + dev_err(&pdev->dev, "Can't get IRQ\n"); + goto no_err_irq; + } + + err = request_irq(dev->irq_dma, + stmp378x_i2c_dma_isr, + 0, pdev->name, dev); + if (err) { + dev_err(&pdev->dev, "Can't get IRQ\n"); + goto no_dma_irq; + } + + err = hw_i2c_init(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "HW Init failed\n"); + goto init_failed; + } + + HW_I2C_CTRL1_SET(0x0000FF00); /* Will catch all error (IRQ mask) */ + + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + strncpy(adap->name, "378x I2C adapter", sizeof(adap->name)); + adap->algo = &stmp378x_i2c_algo; + adap->dev.parent = &pdev->dev; + + adap->nr = pdev->id; + err = i2c_add_numbered_adapter(adap); + if (err) { + dev_err(&pdev->dev, "Failed to add adapter\n"); + goto no_i2c_adapter; + + } + + return 0; + +no_i2c_adapter: + hw_i2c_stop(dev->dev); +init_failed: + free_irq(dev->irq_dma, dev); +no_dma_irq: + free_irq(dev->irq_err, dev); +no_err_irq: +nores: + kfree(dev); + return err; +} + +static int +stmp378x_i2c_remove(struct platform_device *pdev) +{ + struct stmp378x_i2c_dev *dev = platform_get_drvdata(pdev); + int res; + + res = i2c_del_adapter(&dev->adapter); + if (res) + return -EBUSY; + + hw_i2c_stop(dev->dev); + + platform_set_drvdata(pdev, NULL); + + free_irq(dev->irq_err, dev); + free_irq(dev->irq_dma, dev); + + kfree(dev); + return 0; +} + +static struct platform_driver stmp378x_i2c_driver = { + .probe = stmp378x_i2c_probe, + .remove = __devexit_p(stmp378x_i2c_remove), + .driver = { + .name = "i2c_stmp", + .owner = THIS_MODULE, + }, +}; + +/* I2C may be needed to bring up other drivers */ + +static int __init stmp378x_i2c_init_driver(void) +{ + return platform_driver_register(&stmp378x_i2c_driver); +} +subsys_initcall(stmp378x_i2c_init_driver); + +static void __exit stmp378x_i2c_exit_driver(void) +{ + platform_driver_unregister(&stmp378x_i2c_driver); +} +module_exit(stmp378x_i2c_exit_driver); + +MODULE_AUTHOR("old_chap@embeddedalley.com"); +MODULE_DESCRIPTION("IIC for Freescale STMP378x"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index e770e0c78043..0dedb7c1dc55 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -338,4 +338,11 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. + +config KEYBOARD_STMP3XXX + tristate "STMP3xxx keyboard" + depends on ARCH_STMP3XXX + help + -to be written- + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 0757a3508caa..5a70581944fb 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -19,6 +19,8 @@ obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_MXC) += mxc_keyb.o +obj-$(CONFIG_KEYBOARD_MPR084) += mpr084.o +obj-$(CONFIG_KEYBOARD_STMP3XXX) += stmp3xxx-kbd.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o @@ -27,5 +29,4 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o -obj-$(CONFIG_KEYBOARD_MPR084) += mpr084.o -obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
\ No newline at end of file +obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o diff --git a/drivers/input/keyboard/stmp3xxx-kbd.c b/drivers/input/keyboard/stmp3xxx-kbd.c new file mode 100644 index 000000000000..f70c2f024401 --- /dev/null +++ b/drivers/input/keyboard/stmp3xxx-kbd.c @@ -0,0 +1,300 @@ +/* + * Keypad ladder driver for Freescale STMP37XX/STMP378X boards + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <mach/regs-lradc.h> +#include <mach/lradc.h> +#include <mach/stmp3xxx.h> + +#define BUTTON_PRESS_THRESHOLD 3300 +#define LRADC_NOISE_MARGIN 100 + +/* this value represents the the lradc value at 3.3V ( 3.3V / 0.000879 V/b ) */ +#define TARGET_VDDIO_LRADC_VALUE 3754 + +struct stmpkbd_data { + struct input_dev *input; + int last_button; + int irq; + struct stmpkbd_keypair *keycodes; +}; + +static int delay1 = 500; +static int delay2 = 200; + +static int stmpkbd_open(struct input_dev *dev); +static void stmpkbd_close(struct input_dev *dev); + +static struct stmpkbd_data *stmpkbd_data_alloc(struct platform_device *pdev, + struct stmpkbd_keypair *keys) +{ + struct stmpkbd_data *d = kzalloc(sizeof(*d), GFP_KERNEL); + + if (!d) + return NULL; + + if (!keys) { + dev_err(&pdev->dev, + "No keycodes in platform_data, bailing out.\n"); + kfree(d); + return NULL; + } + d->keycodes = keys; + + d->input = input_allocate_device(); + if (!d->input) { + kfree(d); + return NULL; + } + + d->input->phys = "onboard"; + d->input->uniq = "0000'0000"; + d->input->name = pdev->name; + d->input->id.bustype = BUS_HOST; + d->input->open = stmpkbd_open; + d->input->close = stmpkbd_close; + d->input->dev.parent = &pdev->dev; + + set_bit(EV_KEY, d->input->evbit); + set_bit(EV_REL, d->input->evbit); + set_bit(EV_REP, d->input->evbit); + + + d->last_button = -1; + + while (keys->raw >= 0) { + set_bit(keys->kcode, d->input->keybit); + keys++; + } + + return d; +} + +static inline struct input_dev *GET_INPUT_DEV(struct stmpkbd_data *d) +{ + BUG_ON(!d); + return d->input; +} + +static void stmpkbd_data_free(struct stmpkbd_data *d) +{ + if (!d) + return; + if (d->input) + input_free_device(d->input); + kfree(d); +} + +static unsigned stmpkbd_decode_button(struct stmpkbd_keypair *codes, + int raw_button) + +{ + pr_debug("Decoding %d\n", raw_button); + while (codes->raw != -1) { + if ((raw_button > (codes->raw - LRADC_NOISE_MARGIN)) && + (raw_button < (codes->raw + LRADC_NOISE_MARGIN))) { + pr_debug("matches code 0x%x = %d\n", + codes->kcode, codes->kcode); + return codes->kcode; + } + codes++; + } + return (unsigned)-1; /* invalid key */ +} + + +static irqreturn_t stmpkbd_irq_handler(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct stmpkbd_data *devdata = platform_get_drvdata(pdev); + u16 raw_button, normalized_button, vddio; + unsigned btn; + + raw_button = HW_LRADC_CHn_RD(LRADC_CH0) & BM_LRADC_CHn_VALUE; + vddio = hw_lradc_vddio(); + BUG_ON(vddio == 0); + + normalized_button = (raw_button * TARGET_VDDIO_LRADC_VALUE) / + vddio; + + if (normalized_button < BUTTON_PRESS_THRESHOLD && + devdata->last_button < 0) { + + btn = stmpkbd_decode_button(devdata->keycodes, + normalized_button); + + if (btn < KEY_MAX) { + devdata->last_button = btn; + input_report_key(GET_INPUT_DEV(devdata), + devdata->last_button, !0); + } else + dev_err(&pdev->dev, "Invalid button: raw = %d, " + "normalized = %d, vddio = %d\n", + raw_button, normalized_button, vddio); + } else if (devdata->last_button > 0 && + normalized_button >= BUTTON_PRESS_THRESHOLD) { + + input_report_key(GET_INPUT_DEV(devdata), + devdata->last_button, 0); + devdata->last_button = -1; + + } + + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC0_IRQ); + return IRQ_HANDLED; +} + +static int stmpkbd_open(struct input_dev *dev) +{ + /* enable clock */ + return 0; +} + +static void stmpkbd_close(struct input_dev *dev) +{ + /* disable clock */ +} + +static void stmpkbd_hwinit(struct platform_device *pdev) +{ + hw_lradc_init_ladder(LRADC_CH0, LRADC_DELAY_TRIGGER_BUTTON, 200); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC0_IRQ); + HW_LRADC_CTRL1_SET(BM_LRADC_CTRL1_LRADC0_IRQ_EN); + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_BUTTON, !0); +} + +static int stmpkbd_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef CONFIG_PM + struct input_dev *idev = platform_get_drvdata(pdev); + + hw_lradc_stop_ladder(LRADC_CH0, LRADC_DELAY_TRIGGER_BUTTON); + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_BUTTON, 0); + hw_lradc_unuse_channel(LRADC_CH0); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC0_IRQ_EN); + stmpkbd_close(idev); +#endif + return 0; +} + +static int stmpkbd_resume(struct platform_device *pdev) +{ +#ifdef CONFIG_PM + struct input_dev *idev = platform_get_drvdata(pdev); + + HW_LRADC_CTRL1_SET(BM_LRADC_CTRL1_LRADC0_IRQ_EN); + stmpkbd_open(idev); + hw_lradc_use_channel(LRADC_CH0); + stmpkbd_hwinit(pdev); +#endif + return 0; +} + +static int __devinit stmpkbd_probe(struct platform_device *pdev) +{ + int err = 0; + int irq = platform_get_irq(pdev, 0); + struct stmpkbd_data *d; + + /* Create and register the input driver. */ + d = stmpkbd_data_alloc(pdev, + (struct stmpkbd_keypair *)pdev->dev.platform_data); + if (!d) { + dev_err(&pdev->dev, "Cannot allocate driver structures\n"); + err = -ENOMEM; + goto err_out; + } + + d->irq = irq; + err = request_irq(irq, stmpkbd_irq_handler, + IRQF_DISABLED, pdev->name, pdev); + if (err) { + dev_err(&pdev->dev, "Cannot request keypad IRQ\n"); + goto err_free_dev; + } + + platform_set_drvdata(pdev, d); + + /* Register the input device */ + err = input_register_device(GET_INPUT_DEV(d)); + if (err) + goto err_free_irq; + + /* these two have to be set after registering the input device */ + d->input->rep[REP_DELAY] = delay1; + d->input->rep[REP_PERIOD] = delay2; + + hw_lradc_use_channel(LRADC_CH0); + stmpkbd_hwinit(pdev); + + return 0; + +err_free_irq: + platform_set_drvdata(pdev, NULL); + free_irq(irq, pdev); +err_free_dev: + stmpkbd_data_free(d); +err_out: + return err; +} + +static int __devexit stmpkbd_remove(struct platform_device *pdev) +{ + struct stmpkbd_data *d = platform_get_drvdata(pdev); + + hw_lradc_unuse_channel(LRADC_CH0); + input_unregister_device(GET_INPUT_DEV(d)); + free_irq(d->irq, pdev); + stmpkbd_data_free(d); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver stmpkbd_driver = { + .probe = stmpkbd_probe, + .remove = __devexit_p(stmpkbd_remove), + .suspend = stmpkbd_suspend, + .resume = stmpkbd_resume, + .driver = { + .name = "stmp3xxx-keyboard", + }, +}; + +static int __init stmpkbd_init(void) +{ + return platform_driver_register(&stmpkbd_driver); +} + +static void __exit stmpkbd_exit(void) +{ + platform_driver_unregister(&stmpkbd_driver); +} + +module_init(stmpkbd_init); +module_exit(stmpkbd_exit); +MODULE_DESCRIPTION("Freescale STMP3xxxx keyboard driver"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 199055db5082..a9da8d60394c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -40,6 +40,15 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K +config INPUT_STMP3XXX_ROTDEC + tristate "STMP3xxx Rotary Decoder support" + depends on MACH_STMP378X + select INPUT_POLLDEV + help + Say Y here for support for the rotary decoder on STMP3xxx + + If compiled as a module, it will be called stmp3xxx_rotdec + config INPUT_APANEL tristate "Fujitsu Lifebook Application Panel buttons" depends on X86 && I2C && LEDS_CLASS diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index d7db2aeb8a98..483cf7d6e84b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o +obj-$(CONFIG_INPUT_STMP3XXX_ROTDEC) += stmp3xxx_rotdec.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o diff --git a/drivers/input/misc/stmp3xxx_rotdec.c b/drivers/input/misc/stmp3xxx_rotdec.c new file mode 100644 index 000000000000..505a79b25769 --- /dev/null +++ b/drivers/input/misc/stmp3xxx_rotdec.c @@ -0,0 +1,171 @@ +/* + * Freescale STMP3XXX Rotary Encoder Driver + * + * Author: Drew Benedetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input-polldev.h> +#include <mach/regs-timrot.h> +#include <mach/rotdec.h> + +static int relative; +static unsigned int poll_interval = 500; + +void stmp3xxx_rotdec_flush(struct input_polled_dev *dev) +{ + /* in relative mode, reading the counter resets it */ + if (relative) + HW_TIMROT_ROTCOUNT_RD(); +} + +void stmp3xxx_rotdec_poll(struct input_polled_dev *dev) +{ + s16 cnt = HW_TIMROT_ROTCOUNT_RD() & BM_TIMROT_ROTCOUNT_UPDOWN; + if (relative) + input_report_rel(dev->input, REL_WHEEL, cnt); + else + input_report_abs(dev->input, ABS_WHEEL, cnt); +} + +struct input_polled_dev *rotdec; +static u32 rotctrl; + +static int stmp3xxx_rotdec_probe(struct platform_device *pdev) +{ + int rc = 0; + + /* save original state of HW_TIMROT_ROTCTRL */ + rotctrl = HW_TIMROT_ROTCTRL_RD(); + + if (!(rotctrl & BM_TIMROT_ROTCTRL_ROTARY_PRESENT)) { + dev_info(&pdev->dev, "No rotary decoder present\n"); + rc = -ENODEV; + goto err_rotdec_present; + } else { + /* I had to add some extra line breaks in here + * to avoid lines >80 chars wide + */ + HW_TIMROT_ROTCTRL_WR( + BF_TIMROT_ROTCTRL_DIVIDER(0x0) | /* 32kHz divider - 1 */ + BF_TIMROT_ROTCTRL_OVERSAMPLE( + BV_TIMROT_ROTCTRL_OVERSAMPLE__2X) | + BF_TIMROT_ROTCTRL_SELECT_B( + BV_TIMROT_ROTCTRL_SELECT_B__ROTARYB) | + BF_TIMROT_ROTCTRL_SELECT_A( + BV_TIMROT_ROTCTRL_SELECT_A__ROTARYA) + ); + HW_TIMROT_ROTCTRL_CLR( + BM_TIMROT_ROTCTRL_POLARITY_B | + BM_TIMROT_ROTCTRL_POLARITY_A + ); + + if (relative) + HW_TIMROT_ROTCTRL_SET(BM_TIMROT_ROTCTRL_RELATIVE); + else + HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_RELATIVE); + + rc = rotdec_pinmux_request(); + if (rc) { + dev_err(&pdev->dev, + "Pin request failed (err=%d)\n", rc); + goto err_pinmux; + } + + /* set up input_polled_dev */ + rotdec = input_allocate_polled_device(); + if (!rotdec) { + dev_err(&pdev->dev, + "Unable to allocate polled device\n"); + rc = -ENOMEM; + goto err_alloc_polldev; + } + rotdec->flush = stmp3xxx_rotdec_flush; + rotdec->poll = stmp3xxx_rotdec_poll; + rotdec->poll_interval = poll_interval; /* msec */ + + rotdec->input->name = "stmp3xxx-rotdec"; + if (relative) + input_set_capability(rotdec->input, EV_REL, REL_WHEEL); + else { + input_set_capability(rotdec->input, EV_ABS, ABS_WHEEL); + input_set_abs_params(rotdec->input, ABS_WHEEL, + -32768, 32767, 0, 0); + } + + rc = input_register_polled_device(rotdec); + if (rc) { + dev_err(&pdev->dev, + "Unable to register rotary decoder (err=%d)\n", + rc); + goto err_reg_polldev; + } + } + + return 0; + +err_reg_polldev: + input_free_polled_device(rotdec); +err_alloc_polldev: + rotdec_pinmux_free(); +err_pinmux: + /* restore original register state */ + HW_TIMROT_ROTCTRL_WR(rotctrl); + +err_rotdec_present: + return rc; +} + +static int stmp3xxx_rotdec_remove(struct platform_device *pdev) +{ + input_unregister_polled_device(rotdec); + input_free_polled_device(rotdec); + + rotdec_pinmux_free(); + + /* restore original register state */ + HW_TIMROT_ROTCTRL_WR(rotctrl); + + return 0; +} + +static struct platform_driver stmp3xxx_rotdec_driver = { + .probe = stmp3xxx_rotdec_probe, + .remove = stmp3xxx_rotdec_remove, + .driver = { + .name = "stmp3xxx-rotdec", + }, +}; + +static int __init stmp3xxx_rotdec_init(void) +{ + return platform_driver_register(&stmp3xxx_rotdec_driver); +} + +static void __exit stmp3xxx_rotdec_exit(void) +{ + platform_driver_unregister(&stmp3xxx_rotdec_driver); +} + +module_init(stmp3xxx_rotdec_init); +module_exit(stmp3xxx_rotdec_exit); + +module_param(relative, bool, 0600); +module_param(poll_interval, uint, 0600); + +MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>"); +MODULE_DESCRIPTION("STMP3xxx rotary decoder driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index bf2adea365d8..da98d9ee8959 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -183,6 +183,14 @@ config TOUCHSCREEN_TSC2007 This driver can also be built as a module. If so, the module will be called tsc2007. +config TOUCHSCREEN_STMP3XXX + tristate "STMP3XXX LRADC-based touchscreen" + depends on ARCH_STMP3XXX + select SERIO + help + Say Y here if you want to enable TMP3XXX LRADC-based touchscreen. + module will be called stmp3xxx_ts. + config TOUCHSCREEN_HTCPEN tristate "HTC Shift X9500 touchscreen" depends on ISA diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 35433c83f389..9697a3d9388e 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -34,3 +34,4 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_STMP3XXX) += stmp3xxx_ts.o diff --git a/drivers/input/touchscreen/stmp3xxx_ts.c b/drivers/input/touchscreen/stmp3xxx_ts.c new file mode 100644 index 000000000000..05f787b9d9d4 --- /dev/null +++ b/drivers/input/touchscreen/stmp3xxx_ts.c @@ -0,0 +1,386 @@ +/* + * Freesclae STMP37XX/STMP378X Touchscreen driver + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* #define DEBUG*/ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +#include <mach/lradc.h> +#include <mach/hardware.h> +#include <mach/regs-lradc.h> + +#define TOUCH_DEBOUNCE_TOLERANCE 100 + +struct stmp3xxx_ts_info { + int touch_irq; + int device_irq; + struct input_dev *idev; + enum { + TS_STATE_DISABLED, + TS_STATE_TOUCH_DETECT, + TS_STATE_TOUCH_VERIFY, + TS_STATE_X_PLANE, + TS_STATE_Y_PLANE, + } state; + u16 x; + u16 y; + int sample_count; +}; + +static inline void enter_state_touch_detect(struct stmp3xxx_ts_info *info) +{ + HW_LRADC_CHn_CLR(2, 0xFFFFFFFF); + HW_LRADC_CHn_CLR(3, 0xFFFFFFFF); + HW_LRADC_CHn_CLR(4, 0xFFFFFFFF); + HW_LRADC_CHn_CLR(5, 0xFFFFFFFF); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC5_IRQ); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_TOUCH_DETECT_IRQ); + /* + * turn off the yplus and yminus pullup and pulldown, and turn off touch + * detect (enables yminus, and xplus through a resistor.On a press, + * xplus is pulled down) + */ + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XPLUS_ENABLE); + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE); + + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_TOUCHSCREEN, 0); + info->state = TS_STATE_TOUCH_DETECT; + info->sample_count = 0; +} + +static inline void enter_state_disabled(struct stmp3xxx_ts_info *info) +{ + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE); + + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_TOUCHSCREEN, 0); + info->state = TS_STATE_DISABLED; + info->sample_count = 0; +} + + +static inline void enter_state_x_plane(struct stmp3xxx_ts_info *info) +{ + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_YMINUS_ENABLE); + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_YPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE); + + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_TOUCHSCREEN, 1); + + info->state = TS_STATE_X_PLANE; + info->sample_count = 0; +} + +static inline void enter_state_y_plane(struct stmp3xxx_ts_info *info) +{ + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YPLUS_ENABLE); + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_XMINUS_ENABLE); + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_XPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE); + + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_TOUCHSCREEN, 1); + info->state = TS_STATE_Y_PLANE; + info->sample_count = 0; +} + +static inline void enter_state_touch_verify(struct stmp3xxx_ts_info *info) +{ + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_YPLUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XMINUS_ENABLE); + HW_LRADC_CTRL0_CLR(BM_LRADC_CTRL0_XPLUS_ENABLE); + HW_LRADC_CTRL0_SET(BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE); + + info->state = TS_STATE_TOUCH_VERIFY; + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_TOUCHSCREEN, 1); + info->sample_count = 0; +} + +static void process_lradc(struct stmp3xxx_ts_info *info, u16 x, u16 y, + int pressure) +{ + switch (info->state) { + case TS_STATE_X_PLANE: + pr_debug("%s: x plane state, sample_count %d\n", __func__, + info->sample_count); + if (info->sample_count < 2) { + info->x = x; + info->sample_count++; + } else { + if (abs(info->x - x) > TOUCH_DEBOUNCE_TOLERANCE) + info->sample_count = 1; + else { + u16 x_c = info->x * (info->sample_count - 1); + info->x = (x_c + x) / info->sample_count; + info->sample_count++; + } + } + if (info->sample_count > 4) + enter_state_y_plane(info); + else + hw_lradc_set_delay_trigger_kick( + LRADC_DELAY_TRIGGER_TOUCHSCREEN, 1); + break; + + case TS_STATE_Y_PLANE: + pr_debug("%s: y plane state, sample_count %d\n", __func__, + info->sample_count); + if (info->sample_count < 2) { + info->y = y; + info->sample_count++; + } else { + if (abs(info->y - y) > TOUCH_DEBOUNCE_TOLERANCE) + info->sample_count = 1; + else { + u16 y_c = info->y * (info->sample_count - 1); + info->y = (y_c + y) / info->sample_count; + info->sample_count++; + } + } + if (info->sample_count > 4) + enter_state_touch_verify(info); + else + hw_lradc_set_delay_trigger_kick( + LRADC_DELAY_TRIGGER_TOUCHSCREEN, 1); + break; + + case TS_STATE_TOUCH_VERIFY: + pr_debug("%s: touch verify state, sample_count %d\n", __func__, + info->sample_count); + pr_debug("%s: x %d, y %d\n", __func__, info->x, info->y); + input_report_abs(info->idev, ABS_X, info->x); + input_report_abs(info->idev, ABS_Y, info->y); + input_report_abs(info->idev, ABS_PRESSURE, pressure); + input_sync(info->idev); + /* fall through */ + case TS_STATE_TOUCH_DETECT: + pr_debug("%s: touch detect state, sample_count %d\n", __func__, + info->sample_count); + if (pressure) { + input_report_abs(info->idev, ABS_PRESSURE, pressure); + enter_state_x_plane(info); + hw_lradc_set_delay_trigger_kick( + LRADC_DELAY_TRIGGER_TOUCHSCREEN, 1); + } else + enter_state_touch_detect(info); + break; + + default: + printk(KERN_ERR "%s: unknown touchscreen state %d\n", __func__, + info->state); + } +} + +static irqreturn_t ts_handler(int irq, void *dev_id) +{ + struct stmp3xxx_ts_info *info = dev_id; + u16 x_plus, y_plus; + int pressure = 0; + + if (irq == info->touch_irq) + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_TOUCH_DETECT_IRQ); + else if (irq == info->device_irq) + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC5_IRQ); + + /* get x, y values */ + x_plus = HW_LRADC_CHn_RD(LRADC_TOUCH_X_PLUS) & BM_LRADC_CHn_VALUE; + y_plus = HW_LRADC_CHn_RD(LRADC_TOUCH_Y_PLUS) & BM_LRADC_CHn_VALUE; + + /* pressed? */ + if (HW_LRADC_STATUS_RD() & BM_LRADC_STATUS_TOUCH_DETECT_RAW) + pressure = 1; + + pr_debug("%s: irq %d, x_plus %d, y_plus %d, pressure %d\n", + __func__, irq, x_plus, y_plus, pressure); + + process_lradc(info, x_plus, y_plus, pressure); + + return IRQ_HANDLED; +} + +static int stmp3xxx_ts_probe(struct platform_device *pdev) +{ + struct input_dev *idev; + struct stmp3xxx_ts_info *info; + int ret = 0; + struct resource *res; + + idev = input_allocate_device(); + info = kzalloc(sizeof(struct stmp3xxx_ts_info), GFP_KERNEL); + if (idev == NULL || info == NULL) { + ret = -ENOMEM; + goto out_nomem; + } + + idev->name = "STMP3XXX touchscreen"; + idev->evbit[0] = BIT(EV_ABS); + input_set_abs_params(idev, ABS_X, 0, 0xFFF, 0, 0); + input_set_abs_params(idev, ABS_Y, 0, 0xFFF, 0, 0); + input_set_abs_params(idev, ABS_PRESSURE, 0, 1, 0, 0); + + ret = input_register_device(idev); + if (ret) + goto out_nomem; + + info->idev = idev; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + printk(KERN_ERR "%s: couldn't get IRQ resource\n", __func__); + ret = -ENODEV; + goto out_nodev; + } + info->touch_irq = res->start; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!res) { + printk(KERN_ERR "%s: couldn't get IRQ resource\n", __func__); + ret = -ENODEV; + goto out_nodev; + } + info->device_irq = res->start; + + ret = request_irq(info->touch_irq, ts_handler, IRQF_DISABLED, + "stmp3xxx_ts_touch", info); + if (ret) + goto out_nodev; + + ret = request_irq(info->device_irq, ts_handler, IRQF_DISABLED, + "stmp3xxx_ts_dev", info); + if (ret) { + free_irq(info->touch_irq, info); + goto out_nodev; + } + enter_state_touch_detect(info); + + hw_lradc_use_channel(LRADC_CH2); + hw_lradc_use_channel(LRADC_CH3); + hw_lradc_use_channel(LRADC_CH5); + hw_lradc_configure_channel(LRADC_CH2, 0, 0, 0); + hw_lradc_configure_channel(LRADC_CH3, 0, 0, 0); + hw_lradc_configure_channel(LRADC_CH5, 0, 0, 0); + + /* Clear the accumulator & NUM_SAMPLES for the channels */ + HW_LRADC_CHn_CLR(LRADC_CH2, 0xFFFFFFFF); + HW_LRADC_CHn_CLR(LRADC_CH3, 0xFFFFFFFF); + HW_LRADC_CHn_CLR(LRADC_CH5, 0xFFFFFFFF); + + hw_lradc_set_delay_trigger(LRADC_DELAY_TRIGGER_TOUCHSCREEN, + 0x3c, 0, 0, 8); + + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC5_IRQ); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_TOUCH_DETECT_IRQ); + + HW_LRADC_CTRL1_SET(BM_LRADC_CTRL1_LRADC5_IRQ_EN); + HW_LRADC_CTRL1_SET(BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN); + + platform_set_drvdata(pdev, info); + device_init_wakeup(&pdev->dev, 1); + goto out; + +out_nodev: + input_free_device(idev); +out_nomem: + kfree(idev); + kfree(info); +out: + return ret; +} + +static int stmp3xxx_ts_remove(struct platform_device *pdev) +{ + struct stmp3xxx_ts_info *info = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + hw_lradc_unuse_channel(LRADC_CH2); + hw_lradc_unuse_channel(LRADC_CH3); + hw_lradc_unuse_channel(LRADC_CH5); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC5_IRQ_EN); + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN); + + free_irq(info->device_irq, info); + free_irq(info->touch_irq, info); + input_free_device(info->idev); + + enter_state_disabled(info); + kfree(info->idev); + kfree(info); + return 0; +} + +static int stmp3xxx_ts_suspend(struct platform_device *pdev, + pm_message_t state) +{ +#ifdef CONFIG_PM + if (!device_may_wakeup(&pdev->dev)) { + hw_lradc_unuse_channel(LRADC_CH2); + hw_lradc_unuse_channel(LRADC_CH3); + hw_lradc_unuse_channel(LRADC_CH5); + } +#endif + return 0; +} + +static int stmp3xxx_ts_resume(struct platform_device *pdev) +{ +#ifdef CONFIG_PM + if (!device_may_wakeup(&pdev->dev)) { + hw_lradc_use_channel(LRADC_CH2); + hw_lradc_use_channel(LRADC_CH3); + hw_lradc_use_channel(LRADC_CH5); + } +#endif + return 0; +} + +static struct platform_driver stmp3xxx_ts_driver = { + .probe = stmp3xxx_ts_probe, + .remove = stmp3xxx_ts_remove, + .suspend = stmp3xxx_ts_suspend, + .resume = stmp3xxx_ts_resume, + .driver = { + .name = "stmp3xxx_ts", + }, +}; + +static int __init stmp3xxx_ts_init(void) +{ + return platform_driver_register(&stmp3xxx_ts_driver); +} + +static void __exit stmp3xxx_ts_exit(void) +{ + platform_driver_unregister(&stmp3xxx_ts_driver); +} + +module_init(stmp3xxx_ts_init); +module_exit(stmp3xxx_ts_exit); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index cd8738ad46d3..420fd4f5bf06 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -17,6 +17,14 @@ config LEDS_CLASS comment "LED drivers" +config LEDS_STMP378X + tristate "Support for PWM LEDs on STMP378X" + depends on LEDS_CLASS && MACH_STMP378X + help + This option enables support for the LEDs connected to PWM + outputs on the Freescale STMP378X. + + config LEDS_ATMEL_PWM tristate "LED Support using Atmel PWM outputs" depends on LEDS_CLASS && ATMEL_PWM diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7ac8ccaaf413..a1f521b712ce 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers +obj-$(CONFIG_LEDS_STMP378X) += leds-stmp378x-pwm.o obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_MC13892) += leds-mc13892.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o diff --git a/drivers/leds/leds-stmp378x-pwm.c b/drivers/leds/leds-stmp378x-pwm.c new file mode 100644 index 000000000000..f0865db4eb90 --- /dev/null +++ b/drivers/leds/leds-stmp378x-pwm.c @@ -0,0 +1,190 @@ +/* + * Freescale STMP378X PWM LED driver + * + * Author: Drew Benedetti <drewb@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <mach/hardware.h> +#include <mach/regs-pwm.h> +#include <mach/regs-clkctrl.h> +#include <mach/pwm-led.h> +#include <mach/stmp3xxx.h> + +/* Up to 5 PWM lines are available. */ +#define PWM_MAX 5 + +/* PWM enables are the lowest PWM_MAX bits of HW_PWM_CTRL register */ +#define BM_PWM_CTRL_PWM_ENABLE(n) ((1<<(n)) & ((1<<(PWM_MAX))-1)) +#define BF_PWM_PERIODn_SETTINGS \ + (BF_PWM_PERIODn_CDIV(5) | /* divide by 64 */ \ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ \ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ \ + BF_PWM_PERIODn_PERIOD(LED_FULL)) /* 255 cycles */ + +struct stmp378x_led { + struct led_classdev led_dev; + int in_use; +}; + +static struct stmp378x_led leds[PWM_MAX]; + +static struct clk *pwm_clk; + +static void stmp378x_pwm_led_brightness_set(struct led_classdev *pled, + enum led_brightness value) +{ + unsigned int pwmn; + + pwmn = container_of(pled, struct stmp378x_led, led_dev) - leds; + + if (pwmn < PWM_MAX && leds[pwmn].in_use) { + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM_ENABLE(pwmn)); + HW_PWM_ACTIVEn_WR(pwmn, BF_PWM_ACTIVEn_INACTIVE(value) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(pwmn, BF_PWM_PERIODn_SETTINGS); + HW_PWM_CTRL_SET(BM_PWM_CTRL_PWM_ENABLE(pwmn)); + } +} + +static int stmp378x_pwm_led_probe(struct platform_device *pdev) +{ + struct led_classdev *led; + unsigned int pwmn; + int leds_in_use = 0, rc = 0; + int i; + + stmp3xxx_reset_block(REGS_PWM_BASE, 1); + + pwm_clk = clk_get(&pdev->dev, "pwm"); + if (IS_ERR(pwm_clk)) { + rc = PTR_ERR(pwm_clk); + return rc; + } + + clk_enable(pwm_clk); + + for (i = 0; i < pdev->num_resources; i++) { + + if (pdev->resource[i].flags & IORESOURCE_DISABLED) + continue; + + pwmn = pdev->resource[i].start; + if (pwmn >= PWM_MAX) { + dev_err(&pdev->dev, "PWM %d doesn't exist\n", pwmn); + continue; + } + + rc = pwm_led_pinmux_request(pwmn, "stmp378x_pwm_led"); + if (rc) { + dev_err(&pdev->dev, + "PWM %d is not available (err=%d)\n", + pwmn, rc); + continue; + } + + led = &leds[pwmn].led_dev; + + led->flags = pdev->resource[i].flags; + led->name = pdev->resource[i].name; + led->brightness = LED_HALF; + led->flags = 0; + led->brightness_set = stmp378x_pwm_led_brightness_set; + led->default_trigger = 0; + + rc = led_classdev_register(&pdev->dev, led); + if (rc < 0) { + dev_err(&pdev->dev, + "Unable to register LED device %d (err=%d)\n", + pwmn, rc); + pwm_led_pinmux_free(pwmn, "stmp378x_pwm_led"); + continue; + } + + /* PWM LED is available now */ + leds[pwmn].in_use = !0; + leds_in_use++; + + /* Set default brightness */ + stmp378x_pwm_led_brightness_set(led, LED_HALF); + } + + if (leds_in_use == 0) { + dev_info(&pdev->dev, "No PWM LEDs available\n"); + clk_disable(pwm_clk); + clk_put(pwm_clk); + return -ENODEV; + } + + return 0; +} + +static int stmp378x_pwm_led_remove(struct platform_device *pdev) +{ + unsigned int pwmn; + + for (pwmn = 0; pwmn < PWM_MAX; pwmn++) { + + if (!leds[pwmn].in_use) + continue; + + /* Disable LED */ + HW_PWM_CTRL_CLR(BM_PWM_CTRL_PWM_ENABLE(pwmn)); + HW_PWM_ACTIVEn_WR(pwmn, BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0)); + HW_PWM_PERIODn_WR(pwmn, BF_PWM_PERIODn_SETTINGS); + + led_classdev_unregister(&leds[pwmn].led_dev); + pwm_led_pinmux_free(pwmn, "stmp378x_pwm_led"); + + leds[pwmn].led_dev.name = 0; + leds[pwmn].in_use = 0; + } + + clk_disable(pwm_clk); + clk_put(pwm_clk); + + return 0; +} + + +static struct platform_driver stmp378x_pwm_led_driver = { + .probe = stmp378x_pwm_led_probe, + .remove = stmp378x_pwm_led_remove, + .driver = { + .name = "stmp378x-pwm-led", + }, +}; + +static int __init stmp378x_pwm_led_init(void) +{ + return platform_driver_register(&stmp378x_pwm_led_driver); +} + +static void __exit stmp378x_pwm_led_exit(void) +{ + platform_driver_unregister(&stmp378x_pwm_led_driver); +} + +module_init(stmp378x_pwm_led_init); +module_exit(stmp378x_pwm_led_exit); + +MODULE_AUTHOR("Drew Benedetti <drewb@embeddedalley.com>"); +MODULE_DESCRIPTION("STMP378X PWM LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 5189c4eb439f..92990ac87b39 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -387,4 +387,6 @@ config USB_MR800 To compile this driver as a module, choose M here: the module will be called radio-mr800. +source "drivers/media/radio/stfm1000/Kconfig" + endif # RADIO_ADAPTERS diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 240ec63cdafc..00cf526d8e19 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -20,4 +20,6 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_SI470X) += radio-si470x.o obj-$(CONFIG_USB_MR800) += radio-mr800.o +obj-$(CONFIG_RADIO_STFM1000) += stfm1000/ + EXTRA_CFLAGS += -Isound diff --git a/drivers/media/radio/stfm1000/Kconfig b/drivers/media/radio/stfm1000/Kconfig new file mode 100644 index 000000000000..ef30bf87de0b --- /dev/null +++ b/drivers/media/radio/stfm1000/Kconfig @@ -0,0 +1,26 @@ +config RADIO_STFM1000 + tristate "STFM1000 support" + depends on I2C && VIDEO_V4L2 && ARCH_STMP3XXX + select I2C_ALGOBIT + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called stfm1000. + +config RADIO_STFM1000_ALSA + tristate "STFM1000 audio support" + depends on RADIO_STFM1000 && SND + select SND_PCM + ---help--- + This is a video4linux driver for direct (DMA) audio in + STFM1000 using ALSA + + To compile this driver as a module, choose M here: the + module will be called stfm1000-alsa. diff --git a/drivers/media/radio/stfm1000/Makefile b/drivers/media/radio/stfm1000/Makefile new file mode 100644 index 000000000000..01f354001a64 --- /dev/null +++ b/drivers/media/radio/stfm1000/Makefile @@ -0,0 +1,14 @@ +stfm1000-objs := stfm1000-core.o stfm1000-i2c.o stfm1000-precalc.o stfm1000-filter.o stfm1000-rds.o + +clean-files += stfm1000-precalc.o + +obj-$(CONFIG_RADIO_STFM1000) += stfm1000.o +obj-$(CONFIG_RADIO_STFM1000_ALSA) += stfm1000-alsa.o + +stfm1000-core.o: $(obj)/stfm1000-precalc.h + +hostprogs-$(CONFIG_RADIO_STFM1000) := gen-precalc +$(obj)/stfm1000-precalc.c: $(obj)/gen-precalc $(src)/stfm1000-regs.h + $(obj)/gen-precalc >$@ + +EXTRA_CFLAGS += -Idrivers/media/radio diff --git a/drivers/media/radio/stfm1000/gen-precalc.c b/drivers/media/radio/stfm1000/gen-precalc.c new file mode 100644 index 000000000000..d3797dbef815 --- /dev/null +++ b/drivers/media/radio/stfm1000/gen-precalc.c @@ -0,0 +1,62 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* generate precalculated tables */ +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +#include "stfm1000-regs.h" + +static void generate_tune1(void) +{ + int start, end; + int ndiv; // N Divider in PLL + int incr; // Increment in PLL + int cicosr; // CIC oversampling ratio + int sdnominal; // value to serve pilot/interpolator loop in SD + int i, temp; // used in tuning table construction + + start = STFM1000_FREQUENCY_100KHZ_MIN; + end = start + STFM1000_FREQUENCY_100KHZ_RANGE; + + printf("const struct stfm1000_tune1\n" + "stfm1000_tune1_table[STFM1000_FREQUENCY_100KHZ_RANGE] = {\n"); + + for (i = start; i < end; i++) { + + ndiv = (int)((i+14)/15) - 48; + incr = i - (int)(i/15)*15; + cicosr = (int)(i*2/3.0/16.0 + 0.5); + sdnominal = (int)(i*100.0e3/1.5/(double)cicosr/2.0/2.0*2.0*8.0*256.0/228.0e3*65536); + + temp = 0x00000000; // clear + temp = temp | ((cicosr<<9) & STFM1000_TUNE1_CICOSR); // bits[14:9] 0x00007E00 + temp = temp | ((ndiv<<4) & STFM1000_TUNE1_PLL_DIV); // bits[8:4] 0x000001F0 + temp = temp | ((incr) & STFM1000_TUNE1_PLL_DIV); // bits[3:0] 0x0000000F + + printf("\t[%d - STFM1000_FREQUENCY_100KHZ_MIN] = " + "{ .tune1 = 0x%08x, .sdnom = 0x%08x },\n", + i, temp, sdnominal); + } + printf("};\n"); + +} + +int main(int argc, char *argv[]) +{ + printf("#include \"stfm1000-regs.h\"\n\n"); + + generate_tune1(); + + return 0; +} diff --git a/drivers/media/radio/stfm1000/stfm1000-alsa.c b/drivers/media/radio/stfm1000/stfm1000-alsa.c new file mode 100644 index 000000000000..d1da4475bc07 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-alsa.c @@ -0,0 +1,660 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/math64.h> + +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <mach/regs-dri.h> +#include <mach/regs-apbx.h> +#include <mach/regs-clkctrl.h> + +#include "stfm1000.h" + +#define STFM1000_PERIODS 16 + +static int stfm1000_snd_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; /* two channels */ + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 20; + return 0; +} + +static int stfm1000_snd_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct stfm1000 *stfm1000 = snd_kcontrol_chip(kcontrol); + + (void)stfm1000; + ucontrol->value.integer.value[0] = 0; /* left */ + ucontrol->value.integer.value[1] = 0; /* right */ + return 0; +} + +static int stfm1000_snd_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct stfm1000 *stfm1000 = snd_kcontrol_chip(kcontrol); + int change; + int left, right; + + (void)stfm1000; + + left = ucontrol->value.integer.value[0]; + if (left < 0) + left = 0; + if (left > 20) + left = 20; + right = ucontrol->value.integer.value[1]; + if (right < 0) + right = 0; + if (right > 20) + right = 20; + + change = 1; + return change; +} + +static struct snd_kcontrol_new stfm1000_snd_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Radio Volume", + .index = 0, + .info = stfm1000_snd_volume_info, + .get = stfm1000_snd_volume_get, + .put = stfm1000_snd_volume_put, + .private_value = 0, + }, +}; + +static struct snd_pcm_hardware stfm1000_snd_capture = { + + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .rate_min = 44100, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = SZ_256K, + .period_bytes_min = SZ_4K, + .period_bytes_max = SZ_4K, + .periods_min = STFM1000_PERIODS, + .periods_max = STFM1000_PERIODS, +}; + +static int stfm1000_snd_capture_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stfm1000 *stfm1000 = snd_pcm_substream_chip(substream); + int err; + + /* should never happen, just a sanity check */ + BUG_ON(stfm1000 == NULL); + + mutex_lock(&stfm1000->deffered_work_lock); + stfm1000->read_count = 0; + stfm1000->read_offset = 0; + + stfm1000->substream = substream; + runtime->private_data = stfm1000; + runtime->hw = stfm1000_snd_capture; + + mutex_unlock(&stfm1000->deffered_work_lock); + + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { + printk(KERN_ERR "%s: snd_pcm_hw_constraint_integer " + "SNDRV_PCM_HW_PARAM_PERIODS failed\n", __func__); + return err; + } + + err = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS, 2); + if (err < 0) { + printk(KERN_ERR "%s: snd_pcm_hw_constraint_integer " + "SNDRV_PCM_HW_PARAM_PERIODS failed\n", __func__); + return err; + } + + return 0; +} + +static int stfm1000_snd_capture_close(struct snd_pcm_substream *substream) +{ + struct stfm1000 *stfm1000 = snd_pcm_substream_chip(substream); + + (void)stfm1000; /* nothing */ + return 0; +} + +static int stfm1000_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct stfm1000 *stfm1000 = snd_pcm_substream_chip(substream); + unsigned int period_size, periods; + int ret; + + periods = params_periods(hw_params); + period_size = params_period_bytes(hw_params); + + if (period_size < 0x100 || period_size > 0x10000) + return -EINVAL; + if (periods < STFM1000_PERIODS) + return -EINVAL; + if (period_size * periods > 1024 * 1024) + return -EINVAL; + + stfm1000->blocks = periods; + stfm1000->blksize = period_size; + stfm1000->bufsize = params_buffer_bytes(hw_params); + + ret = snd_pcm_lib_malloc_pages(substream, stfm1000->bufsize); + if (ret < 0) { /* 0 & 1 are valid returns */ + printk(KERN_ERR "%s: snd_pcm_lib_malloc_pages() failed\n", + __func__); + return ret; + } + + /* the dri buffer is twice as large as the audio buffer */ + stfm1000->dri_bufsz = (stfm1000->bufsize / 4) * + sizeof(struct stfm1000_dri_sample); + stfm1000->dri_buf = dma_alloc_coherent(&stfm1000->radio.dev, + stfm1000->dri_bufsz, &stfm1000->dri_phys, GFP_KERNEL); + if (stfm1000->dri_buf == NULL) { + printk(KERN_ERR "%s: dma_alloc_coherent() failed\n", __func__); + snd_pcm_lib_free_pages(substream); + return -ENOMEM; + } + + return ret; +} + +static int stfm1000_snd_hw_free(struct snd_pcm_substream *substream) +{ + struct stfm1000 *stfm1000 = snd_pcm_substream_chip(substream); + + if (stfm1000->dri_buf) { + dma_free_coherent(&stfm1000->radio.dev, + (stfm1000->bufsize / 4) * + sizeof(struct stfm1000_dri_sample), + stfm1000->dri_buf, stfm1000->dri_phys); + stfm1000->dri_buf = NULL; + stfm1000->dri_phys = 0; + } + snd_pcm_lib_free_pages(substream); + return 0; +} + + +static int stfm1000_snd_capture_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stfm1000 *stfm1000 = snd_pcm_substream_chip(substream); + + stfm1000->substream = substream; + + if (snd_pcm_format_width(runtime->format) != 16 || + !snd_pcm_format_signed(runtime->format) || + snd_pcm_format_big_endian(runtime->format)) { + printk(KERN_INFO "STFM1000: ALSA capture_prepare illegal format\n"); + return -EINVAL; + } + + /* really shouldn't happen */ + BUG_ON(stfm1000->blocks > stfm1000->desc_num); + + mutex_lock(&stfm1000->deffered_work_lock); + + if (stfm1000->now_recording != 0) { + printk(KERN_INFO "STFM1000: ALSA capture_prepare still running\n"); + mutex_unlock(&stfm1000->deffered_work_lock); + return -EBUSY; + } + stfm1000->now_recording = 1; + + mutex_unlock(&stfm1000->deffered_work_lock); + + return 0; + +} + +static void stfm1000_snd_capture_trigger_start(struct work_struct *work) +{ + struct stfm1000 *stfm1000; + + stfm1000 = container_of(work, struct stfm1000, + snd_capture_start_work.work); + + mutex_lock(&stfm1000->deffered_work_lock); + + BUG_ON(stfm1000->now_recording != 1); + + stfm1000_bring_up(stfm1000); + + mutex_unlock(&stfm1000->deffered_work_lock); +} + +static void stfm1000_snd_capture_trigger_stop(struct work_struct *work) +{ + struct stfm1000 *stfm1000; + + stfm1000 = container_of(work, struct stfm1000, + snd_capture_stop_work.work); + + mutex_lock(&stfm1000->deffered_work_lock); + + stfm1000->stopping_recording = 1; + + stfm1000_take_down(stfm1000); + + BUG_ON(stfm1000->now_recording != 1); + stfm1000->now_recording = 0; + + stfm1000->stopping_recording = 0; + + mutex_unlock(&stfm1000->deffered_work_lock); +} + +static int execute_non_atomic(work_func_t fn, struct execute_work *ew) +{ + if (!in_atomic() && !in_interrupt()) { + fn(&ew->work); + return 0; + } + + INIT_WORK(&ew->work, fn); + schedule_work(&ew->work); + + return 1; +} + +static int stfm1000_snd_capture_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stfm1000 *stfm1000 = runtime->private_data; + int err = 0; + + (void)stfm1000; + + switch (cmd) { + + case SNDRV_PCM_TRIGGER_START: + execute_non_atomic(stfm1000_snd_capture_trigger_start, + &stfm1000->snd_capture_start_work); + break; + + case SNDRV_PCM_TRIGGER_STOP: + execute_non_atomic(stfm1000_snd_capture_trigger_stop, + &stfm1000->snd_capture_stop_work); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + stmp3xxx_dma_unfreeze(stfm1000->dma_ch); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stmp3xxx_dma_freeze(stfm1000->dma_ch); + break; + + default: + err = -EINVAL; + break; + } + + return err; +} + +static snd_pcm_uframes_t +stfm1000_snd_capture_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stfm1000 *stfm1000 = runtime->private_data; + + if (stfm1000->read_count) { + stfm1000->read_count -= snd_pcm_lib_period_bytes(substream); + stfm1000->read_offset += snd_pcm_lib_period_bytes(substream); + if (stfm1000->read_offset == substream->runtime->dma_bytes) + stfm1000->read_offset = 0; + } + + return bytes_to_frames(runtime, stfm1000->read_offset); +} + +static struct snd_pcm_ops stfm1000_snd_capture_ops = { + .open = stfm1000_snd_capture_open, + .close = stfm1000_snd_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = stfm1000_snd_hw_params, + .hw_free = stfm1000_snd_hw_free, + .prepare = stfm1000_snd_capture_prepare, + .trigger = stfm1000_snd_capture_trigger, + .pointer = stfm1000_snd_capture_pointer, +}; + +static void stfm1000_snd_free(struct snd_card *card) +{ + struct stfm1000 *stfm1000 = card->private_data; + + free_irq(IRQ_DRI_ATTENTION, stfm1000); + free_irq(IRQ_DRI_DMA, stfm1000); +} + +static int stfm1000_alsa_instance_init(struct stfm1000 *stfm1000) +{ + int ret, i; + struct snd_card *card; + struct snd_pcm *pcm; + struct snd_kcontrol *ctl; + + mutex_init(&stfm1000->deffered_work_lock); + + /* request dma channel */ + stfm1000->desc_num = STFM1000_PERIODS; + stfm1000->dma_ch = STMP3xxx_DMA(5, STMP3XXX_BUS_APBX); + ret = stmp3xxx_dma_request(stfm1000->dma_ch, &stfm1000->radio.dev, + "stmp3xxx dri"); + if (ret != 0) { + printk(KERN_ERR "%s: stmp3xxx_dma_request failed\n", __func__); + goto err; + } + + stfm1000->dma = kzalloc(sizeof(*stfm1000->dma) * stfm1000->desc_num, + GFP_KERNEL); + if (stfm1000->dma == NULL) { + printk(KERN_ERR "%s: stmp3xxx_dma_request failed\n", __func__); + ret = -ENOMEM; + goto err_rel_dma; + } + + for (i = 0; i < stfm1000->desc_num; i++) { + ret = stmp3xxx_dma_allocate_command(stfm1000->dma_ch, + &stfm1000->dma[i]); + if (ret != 0) { + printk(KERN_ERR "%s: stmp3xxx_dma_allocate_command " + "failed\n", __func__); + goto err_free_dma; + } + } + + /* allocate ALSA card structure (we only need an extra pointer + * back to stfm1000) */ + card = snd_card_new(-1, NULL, THIS_MODULE, 0); + if (card == NULL) { + ret = -ENOMEM; + printk(KERN_ERR "%s: snd_card_new failed\n", __func__); + goto err_free_dma; + } + stfm1000->card = card; + card->private_data = stfm1000; /* point back */ + + /* mixer controls */ + strcpy(card->driver, "stfm1000"); + card->private_free = stfm1000_snd_free; + + strcpy(card->mixername, "stfm1000 mixer"); + for (i = 0; i < ARRAY_SIZE(stfm1000_snd_controls); i++) { + ctl = snd_ctl_new1(&stfm1000_snd_controls[i], stfm1000); + if (ctl == NULL) { + printk(KERN_ERR "%s: snd_ctl_new1 failed\n", __func__); + goto err_free_controls; + } + ret = snd_ctl_add(card, ctl); + if (ret != 0) { + printk(KERN_ERR "%s: snd_ctl_add failed\n", __func__); + goto err_free_controls; + } + } + + /* PCM */ + ret = snd_pcm_new(card, "STFM1000 PCM", 0, 0, 1, &pcm); + if (ret != 0) { + printk(KERN_ERR "%s: snd_ctl_add failed\n", __func__); + goto err_free_controls; + } + stfm1000->pcm = pcm; + pcm->private_data = stfm1000; /* point back */ + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &stfm1000_snd_capture_ops); + pcm->info_flags = 0; + strcpy(pcm->name, "STFM1000 PCM"); + + snd_card_set_dev(card, &stfm1000->radio.dev); + strcpy(card->shortname, "STFM1000"); + + ret = snd_pcm_lib_preallocate_pages_for_all(stfm1000->pcm, + SNDRV_DMA_TYPE_CONTINUOUS, card->dev, SZ_256K, SZ_256K); + if (ret != 0) { + printk(KERN_ERR "%s: snd_pcm_lib_preallocate_pages_for_all " + "failed\n", __func__); + goto err_free_pcm; + } + + ret = request_irq(IRQ_DRI_DMA, stfm1000_dri_dma_irq, 0, "stfm1000", + stfm1000); + if (ret != 0) { + printk(KERN_ERR "%s: request_irq failed\n", __func__); + goto err_free_prealloc; + } + + ret = request_irq(IRQ_DRI_ATTENTION, stfm1000_dri_attn_irq, 0, + "stfm1000", stfm1000); + if (ret != 0) { + printk(KERN_ERR "%s: request_irq failed\n", __func__); + goto err_rel_irq; + } + + ret = snd_card_register(stfm1000->card); + if (ret != 0) { + printk(KERN_ERR "%s: snd_card_register failed\n", __func__); + goto err_rel_irq2; + } + + /* Enable completion interrupt */ + stmp3xxx_dma_clear_interrupt(stfm1000->dma_ch); + stmp3xxx_dma_enable_interrupt(stfm1000->dma_ch); + + printk(KERN_INFO "%s/alsa: %s registered\n", "STFM1000", + card->longname); + + return 0; + +err_rel_irq2: + free_irq(IRQ_DRI_ATTENTION, stfm1000); + +err_rel_irq: + free_irq(IRQ_DRI_DMA, stfm1000); + +err_free_prealloc: + snd_pcm_lib_preallocate_free_for_all(stfm1000->pcm); + +err_free_pcm: + /* XXX TODO */ + +err_free_controls: + /* XXX TODO */ + +/* err_free_card: */ + snd_card_free(stfm1000->card); + +err_free_dma: + for (i = stfm1000->desc_num - 1; i >= 0; i--) { + if (stfm1000->dma[i].command != NULL) + stmp3xxx_dma_free_command(stfm1000->dma_ch, + &stfm1000->dma[i]); + } + +err_rel_dma: + stmp3xxx_dma_release(stfm1000->dma_ch); +err: + return ret; +} + +static void stfm1000_alsa_instance_release(struct stfm1000 *stfm1000) +{ + int i; + + stmp3xxx_dma_clear_interrupt(stfm1000->dma_ch); + stmp3xxx_arch_dma_reset_channel(stfm1000->dma_ch); + + snd_card_free(stfm1000->card); + + for (i = stfm1000->desc_num - 1; i >= 0; i--) + stmp3xxx_dma_free_command(stfm1000->dma_ch, &stfm1000->dma[i]); + + kfree(stfm1000->dma); + + stmp3xxx_dma_release(stfm1000->dma_ch); +} + +static void stfm1000_alsa_dma_irq(struct stfm1000 *stfm1000) +{ + struct snd_pcm_runtime *runtime; + int desc; + s16 *src, *dst; + + if (stfm1000->stopping_recording) + return; + + if (stfm1000->read_count >= stfm1000->blksize * + (stfm1000->blocks - 2)) { + printk(KERN_ERR "irq: overrun %d - Blocks in %d\n", + stfm1000->read_count, stfm1000->blocks); + return; + } + + /* someone has brutally killed user-space */ + if (stfm1000->substream == NULL || + stfm1000->substream->runtime == NULL) + return; + + BUG_ON(stfm1000->substream == NULL); + BUG_ON(stfm1000->substream->runtime == NULL); + + desc = stfm1000->read_offset / stfm1000->blksize; + runtime = stfm1000->substream->runtime; + + if (runtime->dma_area == NULL) + printk(KERN_INFO "runtime->dma_area = NULL\n"); + BUG_ON(runtime->dma_area == NULL); + if (stfm1000->dri_buf == NULL) + printk(KERN_INFO "stfm1000->dri_buf = NULL\n"); + BUG_ON(stfm1000->dri_buf == NULL); + + if (desc >= stfm1000->blocks) { + printk(KERN_INFO "desc=%d ->blocks=%d\n", + desc, stfm1000->blocks); + printk(KERN_INFO "->read_offset=%x ->blksize=%x\n", + stfm1000->read_offset, stfm1000->blksize); + } + BUG_ON(desc >= stfm1000->blocks); + + src = stfm1000->dri_buf + desc * (stfm1000->blksize * 2); + dst = (void *)runtime->dma_area + desc * stfm1000->blksize; + + /* perform filtering */ + stfm1000_decode_block(stfm1000, src, dst, stfm1000->blksize / 4); + + stfm1000->read_count += stfm1000->blksize; + + if (stfm1000->read_count >= + snd_pcm_lib_period_bytes(stfm1000->substream)) + snd_pcm_period_elapsed(stfm1000->substream); +} + +static void stfm1000_alsa_attn_irq(struct stfm1000 *stfm1000) +{ + /* nothing */ +} + +struct stfm1000_alsa_ops stfm1000_default_alsa_ops = { + .init = stfm1000_alsa_instance_init, + .release = stfm1000_alsa_instance_release, + .dma_irq = stfm1000_alsa_dma_irq, + .attn_irq = stfm1000_alsa_attn_irq, +}; + +static int stfm1000_alsa_init(void) +{ + struct stfm1000 *stfm1000 = NULL; + struct list_head *list; + int ret; + + stfm1000_alsa_ops = &stfm1000_default_alsa_ops; + + list_for_each(list, &stfm1000_devlist) { + stfm1000 = list_entry(list, struct stfm1000, devlist); + ret = (*stfm1000_alsa_ops->init)(stfm1000); + if (ret != 0) { + printk(KERN_ERR "stfm1000 ALSA driver for DMA sound " + "failed init.\n"); + return ret; + } + stfm1000->alsa_initialized = 1; + } + + printk(KERN_INFO "stfm1000 ALSA driver for DMA sound loaded\n"); + + return 0; +} + +static void stfm1000_alsa_exit(void) +{ + struct stfm1000 *stfm1000 = NULL; + struct list_head *list; + + list_for_each(list, &stfm1000_devlist) { + stfm1000 = list_entry(list, struct stfm1000, devlist); + + if (!stfm1000->alsa_initialized) + continue; + + stfm1000_take_down(stfm1000); + (*stfm1000_alsa_ops->release)(stfm1000); + stfm1000->alsa_initialized = 0; + } + + printk(KERN_INFO "stfm1000 ALSA driver for DMA sound unloaded\n"); +} + +/* We initialize this late, to make sure the sound system is up and running */ +late_initcall(stfm1000_alsa_init); +module_exit(stfm1000_alsa_exit); + +MODULE_AUTHOR("Pantelis Antoniou"); +MODULE_DESCRIPTION("An ALSA PCM driver for the STFM1000 chip."); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/stfm1000/stfm1000-core.c b/drivers/media/radio/stfm1000/stfm1000-core.c new file mode 100644 index 000000000000..5086100bb480 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-core.c @@ -0,0 +1,2459 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/math64.h> + +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/device.h> +#include <linux/freezer.h> +#include <linux/kthread.h> +#include <mach/regs-dri.h> +#include <mach/regs-apbx.h> +#include <mach/regs-clkctrl.h> + +#include "stfm1000.h" + +static DEFINE_MUTEX(devlist_lock); +static unsigned int stfm1000_devcount; + +LIST_HEAD(stfm1000_devlist); +EXPORT_SYMBOL(stfm1000_devlist); + +/* alsa interface */ +struct stfm1000_alsa_ops *stfm1000_alsa_ops; +EXPORT_SYMBOL(stfm1000_alsa_ops); + +/* region, 0=US, 1=europe */ +static int georegion = 1; /* default is europe */ +static int rds_enable = 1; /* default is enabled */ + +static int sw_tune(struct stfm1000 *stfm1000, u32 freq); + +static const const char *stfm1000_get_rev_txt(u32 id) +{ + switch (id) { + case 0x01: return "TA1"; + case 0x02: return "TA2"; + case 0x11: return "TB1"; + case 0x12: return "TB2"; + } + return NULL; +} + +static const struct stfm1000_reg stfm1000_tb2_powerup[] = { + STFM1000_REG(REF, 0x00200000), + STFM1000_DELAY(20), + STFM1000_REG(DATAPATH, 0x00010210), + STFM1000_REG(TUNE1, 0x0004CF01), + STFM1000_REG(SDNOMINAL, 0x1C5EBCF0), + STFM1000_REG(PILOTTRACKING, 0x000001B6), + STFM1000_REG(INITIALIZATION1, 0x9fb80008), + STFM1000_REG(INITIALIZATION2, 0x8516e444 | STFM1000_DEEMPH_50_75B), + STFM1000_REG(INITIALIZATION3, 0x1402190b), + STFM1000_REG(INITIALIZATION4, 0x525bf052), + STFM1000_REG(INITIALIZATION5, 0x1000d106), + STFM1000_REG(INITIALIZATION6, 0x000062cb), + STFM1000_REG(AGC_CONTROL1, 0x1BCB2202), + STFM1000_REG(AGC_CONTROL2, 0x000020F0), + STFM1000_REG(CLK1, 0x10000000), + STFM1000_REG(CLK1, 0x20000000), + STFM1000_REG(CLK1, 0x00000000), + STFM1000_REG(CLK2, 0x7f000000), + STFM1000_REG(REF, 0x00B8222D), + STFM1000_REG(CLK1, 0x30000000), + STFM1000_REG(CLK1, 0x30002000), + STFM1000_REG(CLK1, 0x10002000), + STFM1000_REG(LNA, 0x0D080009), + STFM1000_DELAY(10), + STFM1000_REG(MIXFILT, 0x00008000), + STFM1000_REG(MIXFILT, 0x00000000), + STFM1000_REG(MIXFILT, 0x00007205), + STFM1000_REG(ADC, 0x001B3282), + STFM1000_REG(ATTENTION, 0x0000003F), + STFM1000_END, +}; + +static const struct stfm1000_reg stfm1000_ta2_powerup[] = { + STFM1000_REG(REF, 0x00200000), + STFM1000_DELAY(20), + STFM1000_REG(DATAPATH, 0x00010210), + STFM1000_REG(TUNE1, 0x00044F01), + STFM1000_REG(SDNOMINAL, 0x1C5EBCF0), + STFM1000_REG(PILOTTRACKING, 0x000001B6), + STFM1000_REG(INITIALIZATION1, 0x9fb80008), + STFM1000_REG(INITIALIZATION2, 0x8506e444), + STFM1000_REG(INITIALIZATION3, 0x1402190b), + STFM1000_REG(INITIALIZATION4, 0x525bf052), + STFM1000_REG(INITIALIZATION5, 0x7000d106), + STFM1000_REG(INITIALIZATION6, 0x0000c2cb), + STFM1000_REG(AGC_CONTROL1, 0x002c8402), + STFM1000_REG(AGC_CONTROL2, 0x00140050), + STFM1000_REG(CLK1, 0x10000000), + STFM1000_REG(CLK1, 0x20000000), + STFM1000_REG(CLK1, 0x00000000), + STFM1000_REG(CLK2, 0x7f000000), + STFM1000_REG(REF, 0x0030222D), + STFM1000_REG(CLK1, 0x30000000), + STFM1000_REG(CLK1, 0x30002000), + STFM1000_REG(CLK1, 0x10002000), + STFM1000_REG(LNA, 0x05080009), + STFM1000_REG(MIXFILT, 0x00008000), + STFM1000_REG(MIXFILT, 0x00000000), + STFM1000_REG(MIXFILT, 0x00007200), + STFM1000_REG(ADC, 0x00033000), + STFM1000_REG(ATTENTION, 0x0000003F), + STFM1000_END, +}; + +static const struct stfm1000_reg stfm1000_powerdown[] = { + STFM1000_REG(DATAPATH, 0x00010210), + STFM1000_REG(REF, 0), + STFM1000_REG(LNA, 0), + STFM1000_REG(MIXFILT, 0), + STFM1000_REG(CLK1, 0x20000000), + STFM1000_REG(CLK1, 0), + STFM1000_REG(CLK2, 0), + STFM1000_REG(ADC, 0), + STFM1000_REG(TUNE1, 0), + STFM1000_REG(SDNOMINAL, 0), + STFM1000_REG(PILOTTRACKING, 0), + STFM1000_REG(INITIALIZATION1, 0), + STFM1000_REG(INITIALIZATION2, 0), + STFM1000_REG(INITIALIZATION3, 0), + STFM1000_REG(INITIALIZATION4, 0), + STFM1000_REG(INITIALIZATION5, 0), + STFM1000_REG(INITIALIZATION6, 0x00007E00), + STFM1000_REG(AGC_CONTROL1, 0), + STFM1000_REG(AGC_CONTROL2, 0), + STFM1000_REG(DATAPATH, 0x00000200), +}; + +struct stfm1000_tuner_pmi { + u32 min; + u32 max; + u32 freq; + u32 pll_xtal; /* 1 = pll, 0 = xtal */ +}; + +#define PLL 1 +#define XTAL 0 + +static const struct stfm1000_tuner_pmi stfm1000_pmi_lookup[] = { + { .min = 76100, .max = 76500, .freq = 19200, .pll_xtal = PLL }, + { .min = 79700, .max = 79900, .freq = 19200, .pll_xtal = PLL }, + { .min = 80800, .max = 81200, .freq = 19200, .pll_xtal = PLL }, + { .min = 82100, .max = 82600, .freq = 19200, .pll_xtal = PLL }, + { .min = 86800, .max = 87200, .freq = 19200, .pll_xtal = PLL }, + { .min = 88100, .max = 88600, .freq = 19200, .pll_xtal = PLL }, + { .min = 89800, .max = 90500, .freq = 19200, .pll_xtal = PLL }, + { .min = 91400, .max = 91900, .freq = 19200, .pll_xtal = PLL }, + { .min = 92800, .max = 93300, .freq = 19200, .pll_xtal = PLL }, + { .min = 97400, .max = 97900, .freq = 19200, .pll_xtal = PLL }, + { .min = 98800, .max = 99200, .freq = 19200, .pll_xtal = PLL }, + { .min = 100200, .max = 100400, .freq = 19200, .pll_xtal = PLL }, + { .min = 103500, .max = 103900, .freq = 19200, .pll_xtal = PLL }, + { .min = 104800, .max = 105200, .freq = 19200, .pll_xtal = PLL }, + { .min = 106100, .max = 106500, .freq = 19200, .pll_xtal = PLL }, + + { .min = 76600, .max = 77000, .freq = 20000, .pll_xtal = PLL }, + { .min = 77800, .max = 78300, .freq = 20000, .pll_xtal = PLL }, + { .min = 79200, .max = 79600, .freq = 20000, .pll_xtal = PLL }, + { .min = 80600, .max = 80700, .freq = 20000, .pll_xtal = PLL }, + { .min = 83900, .max = 84400, .freq = 20000, .pll_xtal = PLL }, + { .min = 85300, .max = 85800, .freq = 20000, .pll_xtal = PLL }, + { .min = 94200, .max = 94700, .freq = 20000, .pll_xtal = PLL }, + { .min = 95600, .max = 96100, .freq = 20000, .pll_xtal = PLL }, + { .min = 100500, .max = 100800, .freq = 20000, .pll_xtal = PLL }, + { .min = 101800, .max = 102200, .freq = 20000, .pll_xtal = PLL }, + { .min = 103100, .max = 103400, .freq = 20000, .pll_xtal = PLL }, + { .min = 106600, .max = 106900, .freq = 20000, .pll_xtal = PLL }, + { .min = 107800, .max = 108000, .freq = 20000, .pll_xtal = PLL }, + + { .min = 0, .max = 0, .freq = 24000, .pll_xtal = XTAL } +}; + +int stfm1000_power_up(struct stfm1000 *stfm1000) +{ + struct stfm1000_reg *reg, *pwrup_reg; + const struct stfm1000_reg *orig_reg, *treg; + int ret, size; + + mutex_lock(&stfm1000->state_lock); + + /* Enable DRI clock for 24Mhz. */ + HW_CLKCTRL_XTAL_CLR(BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); + + orig_reg = stfm1000->revid == STFM1000_CHIP_REV_TA2 ? + stfm1000_ta2_powerup : stfm1000_tb2_powerup; + + /* find size of the set */ + for (treg = orig_reg; treg->regno != STFM1000_REG_END; treg++) + ; + size = (treg + 1 - orig_reg) * sizeof(*treg); + + /* allocate copy */ + pwrup_reg = kmalloc(size, GFP_KERNEL); + if (pwrup_reg == NULL) { + printk(KERN_ERR "%s: out of memory\n", __func__); + ret = -ENOMEM; + goto out; + } + + /* copy it */ + memcpy(pwrup_reg, orig_reg, size); + + /* fixup region of INITILIZATION2 */ + for (reg = pwrup_reg; reg->regno != STFM1000_REG_END; reg++) { + + /* we only care for INITIALIZATION2 register */ + if (reg->regno != STFM1000_INITIALIZATION2) + continue; + + /* geographic region select */ + if (stfm1000->georegion == 0) /* USA */ + reg->value &= ~STFM1000_DEEMPH_50_75B; + else /* Europe */ + reg->value |= STFM1000_DEEMPH_50_75B; + + /* RDS enabled */ + if (stfm1000->revid == STFM1000_CHIP_REV_TB2) { + if (stfm1000->rds_enable) + reg->value |= STFM1000_RDS_ENABLE; + else + reg->value &= ~STFM1000_RDS_ENABLE; + } + } + + ret = stfm1000_write_regs(stfm1000, pwrup_reg); + + kfree(pwrup_reg); +out: + mutex_unlock(&stfm1000->state_lock); + + return ret; +} + +int stfm1000_power_down(struct stfm1000 *stfm1000) +{ + int ret; + + mutex_lock(&stfm1000->state_lock); + + /* Disable DRI clock for 24Mhz. */ + HW_CLKCTRL_XTAL_CLR(BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); + + ret = stfm1000_write_regs(stfm1000, stfm1000_powerdown); + + /* Disable DRI clock for 24Mhz. */ + /* XXX bug warning, disabling the DRI clock is bad news */ + /* doing so causes noise to be received from the DRI */ + /* interface. Leave it on for now */ + /* HW_CLKCTRL_XTAL_CLR(BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); */ + + mutex_unlock(&stfm1000->state_lock); + + return ret; +} + +int stfm1000_dcdc_update(struct stfm1000 *stfm1000, u32 freq) +{ + const struct stfm1000_tuner_pmi *pmi; + int i; + + /* search for DCDC frequency */ + pmi = stfm1000_pmi_lookup; + for (i = 0; i < ARRAY_SIZE(stfm1000_pmi_lookup); i++, pmi++) { + if (freq >= pmi->min && freq <= pmi->max) + break; + } + if (i >= ARRAY_SIZE(stfm1000_pmi_lookup)) + return -1; + + /* adjust DCDC frequency so that it is out of Tuner PLL range */ + /* XXX there is no adjustment API (os_pmi_SetDcdcFreq)*/ + return 0; +} + +static void Mute_Audio(struct stfm1000 *stfm1000) +{ + stfm1000->mute = 1; +} + +static void Unmute_Audio(struct stfm1000 *stfm1000) +{ + stfm1000->mute = 0; +} + +static const struct stfm1000_reg sd_dp_on_regs[] = { + STFM1000_REG_SETBITS(DATAPATH, STFM1000_DP_EN), + STFM1000_DELAY(3), + STFM1000_REG_SETBITS(DATAPATH, STFM1000_DB_ACCEPT), + STFM1000_REG_CLRBITS(AGC_CONTROL1, STFM1000_B2_BYPASS_AGC_CTL), + STFM1000_REG_CLRBITS(DATAPATH, STFM1000_DB_ACCEPT), + STFM1000_END, +}; + +static int SD_DP_On(struct stfm1000 *stfm1000) +{ + int ret; + + ret = stfm1000_write_regs(stfm1000, sd_dp_on_regs); + if (ret != 0) + return ret; + + return 0; +} + +static const struct stfm1000_reg sd_dp_off_regs[] = { + STFM1000_REG_SETBITS(DATAPATH, STFM1000_DB_ACCEPT), + STFM1000_REG_CLRBITS(DATAPATH, STFM1000_DP_EN), + STFM1000_REG_SETBITS(AGC_CONTROL1, STFM1000_B2_BYPASS_AGC_CTL), + STFM1000_REG_CLRBITS(PILOTTRACKING, STFM1000_B2_PILOTTRACKING_EN), + STFM1000_REG_CLRBITS(DATAPATH, STFM1000_DB_ACCEPT), + STFM1000_END, +}; + +static int SD_DP_Off(struct stfm1000 *stfm1000) +{ + int ret; + + ret = stfm1000_write_regs(stfm1000, sd_dp_off_regs); + if (ret != 0) + return ret; + + return 0; +} + +static int DRI_Start_Stream(struct stfm1000 *stfm1000) +{ + dma_addr_t dma_buffer_phys; + int i, next; + u32 cmd; + + /* we must not be gated */ + BUG_ON(HW_CLKCTRL_XTAL_RD() & BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); + + /* hw_dri_SetReset */ + HW_DRI_CTRL_CLR(BM_DRI_CTRL_SFTRST | BM_DRI_CTRL_CLKGATE); + HW_DRI_CTRL_SET(BM_DRI_CTRL_SFTRST); + while ((HW_DRI_CTRL_RD() & BM_DRI_CTRL_CLKGATE) == 0) + cpu_relax(); + HW_DRI_CTRL_CLR(BM_DRI_CTRL_SFTRST | BM_DRI_CTRL_CLKGATE); + + /* DRI enable/config */ + HW_DRI_TIMING_WR(BF_DRI_TIMING_GAP_DETECTION_INTERVAL(0x10) | + BF_DRI_TIMING_PILOT_REP_RATE(0x08)); + + /* XXX SDK bug */ + /* While the SDK enables the gate here, everytime the stream */ + /* is started, doing so, causes the DRI to input audio noise */ + /* at any subsequent starts */ + /* Enable DRI clock for 24Mhz. */ + /* HW_CLKCTRL_XTAL_CLR(BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); */ + + stmp3xxx_arch_dma_reset_channel(stfm1000->dma_ch); + + dma_buffer_phys = stfm1000->dri_phys; + + for (i = 0; i < stfm1000->blocks; i++) { + next = (i + 1) % stfm1000->blocks; + + /* link */ + stfm1000->dma[i].command->next = stfm1000->dma[next].handle; + stfm1000->dma[i].next_descr = &stfm1000->dma[next]; + + /* receive DRI is 8 bytes per 4 samples */ + cmd = BF_APBX_CHn_CMD_XFER_COUNT(stfm1000->blksize * 2) | + BM_APBX_CHn_CMD_IRQONCMPLT | + BM_APBX_CHn_CMD_CHAIN | + BF_APBX_CHn_CMD_COMMAND( + BV_APBX_CHn_CMD_COMMAND__DMA_WRITE); + + stfm1000->dma[i].command->cmd = cmd; + stfm1000->dma[i].command->buf_ptr = dma_buffer_phys; + stfm1000->dma[i].command->pio_words[0] = + BM_DRI_CTRL_OVERFLOW_IRQ_EN | + BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN | + BM_DRI_CTRL_ATTENTION_IRQ_EN | + /* BM_DRI_CTRL_STOP_ON_OFLOW_ERROR | */ + /* BM_DRI_CTRL_STOP_ON_PILOT_ERROR | */ + BM_DRI_CTRL_ENABLE_INPUTS; + + dma_buffer_phys += stfm1000->blksize * 2; + + } + + /* Enable completion interrupt */ + stmp3xxx_dma_clear_interrupt(stfm1000->dma_ch); + stmp3xxx_dma_enable_interrupt(stfm1000->dma_ch); + + /* clear DRI interrupts pending */ + HW_DRI_CTRL_CLR(BM_DRI_CTRL_OVERFLOW_IRQ | + BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ | + BM_DRI_CTRL_ATTENTION_IRQ); + + /* Stop DRI on error */ + HW_DRI_CTRL_CLR(BM_DRI_CTRL_STOP_ON_OFLOW_ERROR | + BM_DRI_CTRL_STOP_ON_PILOT_ERROR); + + /* Reacquire data stream */ + HW_DRI_CTRL_SET(BM_DRI_CTRL_REACQUIRE_PHASE | + BM_DRI_CTRL_OVERFLOW_IRQ_EN | + BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN | + BM_DRI_CTRL_ATTENTION_IRQ_EN | + BM_DRI_CTRL_ENABLE_INPUTS); + + stmp3xxx_dma_go(stfm1000->dma_ch, stfm1000->dma, 1); + + /* Turn on DRI hardware (don't forget to leave RUN bit ON) */ + HW_DRI_CTRL_SET(BM_DRI_CTRL_RUN); + + return 0; +} + +static int DRI_Stop_Stream(struct stfm1000 *stfm1000) +{ + int desc; + + /* disable interrupts */ + HW_DRI_CTRL_CLR(BM_DRI_CTRL_OVERFLOW_IRQ_EN | + BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN | + BM_DRI_CTRL_ATTENTION_IRQ_EN); + + /* Freeze DMA channel for a moment */ + stmp3xxx_dma_freeze(stfm1000->dma_ch); + + /* all descriptors, set sema bit */ + for (desc = 0; desc < stfm1000->blocks; desc++) + stfm1000->dma[desc].command->cmd |= BM_APBX_CHn_CMD_SEMAPHORE; + + /* Let the current DMA transaction finish */ + stmp3xxx_dma_unfreeze(stfm1000->dma_ch); + msleep(5); + + /* dma shutdown */ + stmp3xxx_arch_dma_reset_channel(stfm1000->dma_ch); + + /* Turn OFF data lines and stop controller */ + HW_DRI_CTRL_CLR(BM_DRI_CTRL_ENABLE_INPUTS | BM_DRI_CTRL_RUN); + + /* hw_dri_SetReset */ + HW_DRI_CTRL_SET(BM_DRI_CTRL_SFTRST | BM_DRI_CTRL_CLKGATE); + + /* XXX SDK bug */ + /* While the SDK enables the gate here, everytime the stream */ + /* is started, doing so, causes the DRI to input audio noise */ + /* at any subsequent starts */ + /* Enable DRI clock for 24Mhz. */ + /* Disable DRI clock for 24Mhz. */ + /* HW_CLKCTRL_XTAL_SET(BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); */ + + return 0; +} + +static int DRI_On(struct stfm1000 *stfm1000) +{ + int ret; + + if (stfm1000->active) + DRI_Start_Stream(stfm1000); + + ret = stfm1000_set_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_SAI_EN); + return ret; +} + +static int DRI_Off(struct stfm1000 *stfm1000) +{ + int ret; + + if (stfm1000->active) + DRI_Stop_Stream(stfm1000); + + ret = stfm1000_clear_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_SAI_EN); + + return 0; +} + +static int SD_Set_Channel_Filter(struct stfm1000 *stfm1000) +{ + int bypass_setting; + int sig_qual; + u32 tmp; + int ret; + + /* + * set channel filter + * + * B2_NEAR_CHAN_MIX_REG_MASK values from T-Spec + * 000 : 0 kHz mix. + * 001 : +100 kHz mix. + * 010 : +200 kHz mix. + * 011 : +300 kHz mix. + * 100 : -400 kHz mix. + * 101 : -300 kHz mix. + * 110 : -200 kHz mix. + * 111 : -100 kHz mix. + */ + + /* get near channel amplitude */ + ret = stfm1000_write_masked(stfm1000, STFM1000_INITIALIZATION3, + STFM1000_B2_NEAR_CHAN_MIX(0x01), + STFM1000_B2_NEAR_CHAN_MIX_MASK); + if (ret != 0) + return ret; + + msleep(10); /* wait for the signal quality to settle */ + + ret = stfm1000_read(stfm1000, STFM1000_SIGNALQUALITY, &tmp); + if (ret != 0) + return ret; + + sig_qual = (tmp & STFM1000_NEAR_CHAN_AMPLITUDE_MASK) >> + STFM1000_NEAR_CHAN_AMPLITUDE_SHIFT; + + bypass_setting = 0; + + /* check near channel amplitude vs threshold */ + if (sig_qual < stfm1000->adj_chan_th) { + /* get near channel amplitude again */ + ret = stfm1000_write_masked(stfm1000, STFM1000_INITIALIZATION3, + STFM1000_B2_NEAR_CHAN_MIX(0x05), + STFM1000_B2_NEAR_CHAN_MIX_MASK); + if (ret != 0) + return ret; + + msleep(10); /* wait for the signal quality to settle */ + + ret = stfm1000_read(stfm1000, STFM1000_SIGNALQUALITY, &tmp); + if (ret != 0) + return ret; + + sig_qual = (tmp & STFM1000_NEAR_CHAN_AMPLITUDE_MASK) >> + STFM1000_NEAR_CHAN_AMPLITUDE_SHIFT; + + if (sig_qual < stfm1000->adj_chan_th) + bypass_setting = 2; + } + + /* set filter settings */ + ret = stfm1000_write_masked(stfm1000, STFM1000_INITIALIZATION1, + STFM1000_B2_BYPASS_FILT(bypass_setting), + STFM1000_B2_BYPASS_FILT_MASK); + if (ret != 0) + return ret; + + return 0; +} + +static int SD_Look_For_Pilot_TA2(struct stfm1000 *stfm1000) +{ + int i; + u32 pilot; + int ret; + + /* assume pilot */ + stfm1000->pilot_present = 1; + + for (i = 0; i < 3; i++) { + + ret = stfm1000_read(stfm1000, STFM1000_PILOTCORRECTION, + &pilot); + if (ret != 0) + return ret; + + pilot &= STFM1000_PILOTEST_TA2_MASK; + pilot >>= STFM1000_PILOTEST_TA2_SHIFT; + + /* out of range? */ + if (pilot < 0xe2 || pilot >= 0xb5) { + stfm1000->pilot_present = 0; + break; + } + } + + return 0; +} + + +static int SD_Look_For_Pilot_TB2(struct stfm1000 *stfm1000) +{ + int i; + u32 pilot; + int ret; + + /* assume pilot */ + stfm1000->pilot_present = 1; + + for (i = 0; i < 3; i++) { + + ret = stfm1000_read(stfm1000, STFM1000_PILOTCORRECTION, + &pilot); + if (ret != 0) + return ret; + + pilot &= STFM1000_PILOTEST_TB2_MASK; + pilot >>= STFM1000_PILOTEST_TB2_SHIFT; + + /* out of range? */ + if (pilot < 0x1e || pilot >= 0x7f) { + stfm1000->pilot_present = 0; + break; + } + } + + return 0; +} + +static int SD_Look_For_Pilot(struct stfm1000 *stfm1000) +{ + int ret; + + if (stfm1000->revid == STFM1000_CHIP_REV_TA2) + ret = SD_Look_For_Pilot_TA2(stfm1000); + else + ret = SD_Look_For_Pilot_TB2(stfm1000); + + if (ret != 0) + return ret; + + if (!stfm1000->pilot_present) { + ret = stfm1000_clear_bits(stfm1000, STFM1000_PILOTTRACKING, + STFM1000_B2_PILOTTRACKING_EN); + if (ret != 0) + return ret; + + /* set force mono parameters for the filter */ + stfm1000->filter_parms.pCoefForcedMono = 1; + + /* yeah, I know, it's stupid */ + stfm1000->rds_state.demod.pCoefForcedMono = + stfm1000->filter_parms.pCoefForcedMono; + } + + return 0; +} + +static int SD_Gear_Shift_Pilot_Tracking(struct stfm1000 *stfm1000) +{ + static const struct { + int delay; + u32 value; + } track_table[] = { + { .delay = 10, .value = 0x81b6 }, + { .delay = 6, .value = 0x82a5 }, + { .delay = 6, .value = 0x8395 }, + { .delay = 8, .value = 0x8474 }, + { .delay = 20, .value = 0x8535 }, + { .delay = 50, .value = 0x8632 }, + { .delay = 0, .value = 0x8810 }, + }; + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(track_table); i++) { + ret = stfm1000_write(stfm1000, STFM1000_PILOTTRACKING, + track_table[i].value); + if (ret != 0) + return ret; + + if (i < ARRAY_SIZE(track_table) - 1) /* last one no delay */ + msleep(track_table[i].delay); + } + + return 0; +} + +static int SD_Optimize_Channel(struct stfm1000 *stfm1000) +{ + int ret; + + ret = stfm1000_set_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_DB_ACCEPT); + if (ret != 0) + return ret; + + ret = stfm1000_write(stfm1000, STFM1000_PILOTTRACKING, + STFM1000_B2_PILOTTRACKING_EN | + STFM1000_B2_PILOTLPF_TIMECONSTANT(0x01) | + STFM1000_B2_PFDSCALE(0x0B) | + STFM1000_B2_PFDFILTER_SPEEDUP(0x06)); /* 0x000081B6 */ + if (ret != 0) + return ret; + + ret = SD_Set_Channel_Filter(stfm1000); + if (ret != 0) + return ret; + + ret = SD_Look_For_Pilot(stfm1000); + if (ret != 0) + return ret; + + if (stfm1000->pilot_present) { + ret = SD_Gear_Shift_Pilot_Tracking(stfm1000); + if (ret != 0) + return ret; + } + + ret = stfm1000_clear_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_DB_ACCEPT); + if (ret != 0) + return ret; + + return 0; +} + +static int Monitor_STFM_Quality(struct stfm1000 *stfm1000) +{ + u32 tmp, rssi_dc_est, tone_data; + u32 lna_rms, bias, agc_out, lna_th, lna, ref; + u16 rssi_mantissa, rssi_exponent, rssi_decoded; + u16 prssi; + s16 mpx_dc; + int rssi_log; + int bypass_filter; + int ret; + + ret = stfm1000_set_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_DB_ACCEPT); + if (ret != 0) + return ret; + + /* Get Rssi register readings from STFM1000 */ + stfm1000_read(stfm1000, STFM1000_RSSI_TONE, &tmp); + rssi_dc_est = tmp & 0xffff; + tone_data = (tmp >> 16) & 0x0fff; + + rssi_mantissa = (rssi_dc_est & 0xffe0) >> 5; /* 11Msb */ + rssi_exponent = rssi_dc_est & 0x001f; /* 5 lsb */ + rssi_decoded = (u32)rssi_mantissa << rssi_exponent; + + /* Convert Rsst to 10log(Rssi) */ + for (prssi = 20; prssi > 0; prssi--) + if (rssi_decoded >= (1 << prssi)) + break; + + rssi_log = (3 * rssi_decoded >> prssi) + (3 * prssi - 3); + /* clamp to positive */ + if (rssi_log < 0) + rssi_log = 0; + /* Compensate for errors in truncation/approximation by adding 1 */ + rssi_log++; + + stfm1000->rssi_dc_est_log = rssi_log; + stfm1000->signal_strength = stfm1000->rssi_dc_est_log; + + /* determine absolute value */ + if (tmp & 0x0800) + mpx_dc = ((tmp >> 16) & 0x0fff) | 0xf000; + else + mpx_dc = (tmp >> 16) & 0x0fff; + stfm1000->mpx_dc = mpx_dc; + mpx_dc = mpx_dc < 0 ? -mpx_dc : mpx_dc; + + if (stfm1000->tuning_grid_50KHz) + stfm1000->is_station = rssi_log > stfm1000->tune_rssi_th; + else + stfm1000->is_station = rssi_log > stfm1000->tune_rssi_th && + mpx_dc > stfm1000->tune_mpx_dc_th; + + /* weak signal? */ + if (stfm1000->rssi_dc_est_log < + (stfm1000->filter_parms.pCoefLmrGaTh - 20)) { + + if (stfm1000->pilot_present) + bypass_filter = 1; /* Filter settings #2 */ + else + bypass_filter = 0; + + /* configure filter for narrow band */ + ret = stfm1000_write_masked(stfm1000, STFM1000_AGC_CONTROL1, + STFM1000_B2_BYPASS_FILT(bypass_filter), + STFM1000_B2_BYPASS_FILT_MASK); + if (ret != 0) + return ret; + + /* Turn off pilot tracking */ + ret = stfm1000_clear_bits(stfm1000, STFM1000_PILOTTRACKING, + STFM1000_B2_PILOTTRACKING_EN); + if (ret != 0) + return ret; + + /* enable "forced mono" in black box */ + stfm1000->filter_parms.pCoefForcedMono = 1; + + /* yeah, I know, it's stupid */ + stfm1000->rds_state.demod.pCoefForcedMono = + stfm1000->filter_parms.pCoefForcedMono; + + /* Set weak signal flag */ + stfm1000->weak_signal = 1; + + if (stfm1000->revid == STFM1000_CHIP_REV_TA2) { + + /* read AGC_STAT register */ + ret = stfm1000_read(stfm1000, STFM1000_AGC_STAT, &tmp); + if (ret != 0) + return ret; + + lna_rms = (tmp & STFM1000_LNA_RMS_MASK) >> + STFM1000_LNA_RMS_SHIFT; + + /* Check the energy level from LNA Power Meter A/D */ + if (lna_rms == 0) + bias = STFM1000_IBIAS2_DN | STFM1000_IBIAS1_UP; + else + bias = STFM1000_IBIAS2_UP | STFM1000_IBIAS1_DN; + + if (lna_rms == 0 || lna_rms > 2) { + ret = stfm1000_write_masked(stfm1000, + STFM1000_LNA, bias, + STFM1000_IBIAS2_UP | + STFM1000_IBIAS2_DN | + STFM1000_IBIAS1_UP | + STFM1000_IBIAS1_DN); + if (ret != 0) + return ret; + } + + } else { + + /* Set LNA bias */ + + /* read AGC_STAT register */ + ret = stfm1000_read(stfm1000, STFM1000_AGC_STAT, &tmp); + if (ret != 0) + return ret; + + agc_out = (tmp & STFM1000_AGCOUT_STAT_MASK) >> + STFM1000_AGCOUT_STAT_SHIFT; + + /* read LNA register (this is a cached register) */ + ret = stfm1000_read(stfm1000, STFM1000_LNA, &lna); + if (ret != 0) + return ret; + + /* read REF register (this is a cached register) */ + ret = stfm1000_read(stfm1000, STFM1000_REF, &ref); + if (ret != 0) + return ret; + +/* work around the 80 line width problem */ +#undef LNADEF +#define LNADEF STFM1000_LNA_AMP1_IMPROVE_DISTORTION + if (agc_out == 31) { + if (rssi_log <= 16) { + if (lna & STFM1000_IBIAS1_DN) + lna &= ~STFM1000_IBIAS1_DN; + else { + lna |= STFM1000_IBIAS1_UP; + ref &= ~LNADEF; + } + } + if (rssi_log >= 26) { + if (lna & STFM1000_IBIAS1_UP) { + lna &= ~STFM1000_IBIAS1_UP; + ref |= LNADEF; + } else + lna |= STFM1000_IBIAS1_DN; + } + } else { + lna &= ~STFM1000_IBIAS1_UP; + lna |= STFM1000_IBIAS1_DN; + ref |= LNADEF; + } +#undef LNADEF + + ret = stfm1000_write_masked(stfm1000, STFM1000_LNA, + lna, STFM1000_IBIAS1_UP | STFM1000_IBIAS1_DN); + if (ret != 0) + return ret; + + ret = stfm1000_write_masked(stfm1000, STFM1000_REF, + ref, STFM1000_LNA_AMP1_IMPROVE_DISTORTION); + if (ret != 0) + return ret; + } + + } else if (stfm1000->rssi_dc_est_log > + (stfm1000->filter_parms.pCoefLmrGaTh - 17)) { + + bias = STFM1000_IBIAS2_UP | STFM1000_IBIAS1_DN; + + ret = stfm1000_write_masked(stfm1000, STFM1000_LNA, + bias, STFM1000_IBIAS2_UP | STFM1000_IBIAS2_DN | + STFM1000_IBIAS1_UP | STFM1000_IBIAS1_DN); + if (ret != 0) + return ret; + + ret = SD_Set_Channel_Filter(stfm1000); + if (ret != 0) + return ret; + + ret = SD_Look_For_Pilot(stfm1000); + if (ret != 0) + return ret; + + if (stfm1000->pilot_present) { + if (stfm1000->prev_pilot_present || + stfm1000->weak_signal) { + + /* gear shift pilot tracking */ + ret = SD_Gear_Shift_Pilot_Tracking( + stfm1000); + if (ret != 0) + return ret; + + /* set force mono parameters for the + * filter */ + stfm1000->filter_parms. + pCoefForcedMono = stfm1000-> + force_mono; + + /* yeah, I know, it's stupid */ + stfm1000->rds_state.demod. + pCoefForcedMono = stfm1000-> + filter_parms. + pCoefForcedMono; + } + } else { + ret = stfm1000_clear_bits(stfm1000, + STFM1000_PILOTTRACKING, + STFM1000_B2_PILOTTRACKING_EN); + if (ret != 0) + return ret; + + /* set force mono parameters for the filter */ + stfm1000->filter_parms.pCoefForcedMono = 1; + + /* yeah, I know, it's stupid */ + stfm1000->rds_state.demod.pCoefForcedMono = + stfm1000->filter_parms.pCoefForcedMono; + } + + /* Reset weak signal flag */ + stfm1000->weak_signal = 0; + stfm1000->prev_pilot_present = stfm1000->pilot_present; + + } else { + + ret = SD_Look_For_Pilot(stfm1000); + if (ret != 0) + return ret; + + if (!stfm1000->pilot_present) { + ret = stfm1000_clear_bits(stfm1000, + STFM1000_PILOTTRACKING, + STFM1000_B2_PILOTTRACKING_EN); + if (ret != 0) + return ret; + + /* set force mono parameters for the filter */ + stfm1000->filter_parms.pCoefForcedMono = 1; + + /* yeah, I know, it's stupid */ + stfm1000->rds_state.demod.pCoefForcedMono = + stfm1000->filter_parms.pCoefForcedMono; + + /* Reset weak signal flag */ + stfm1000->weak_signal = 0; + stfm1000->prev_pilot_present = stfm1000->pilot_present; + } + + } + + if (stfm1000->revid == STFM1000_CHIP_REV_TA2) { + + /* read AGC_STAT register */ + ret = stfm1000_read(stfm1000, STFM1000_AGC_STAT, &tmp); + if (ret != 0) + return ret; + + agc_out = (tmp & STFM1000_AGCOUT_STAT_MASK) >> + STFM1000_AGCOUT_STAT_SHIFT; + lna_rms = (tmp & STFM1000_LNA_RMS_MASK) >> + STFM1000_LNA_RMS_SHIFT; + + ret = stfm1000_read(stfm1000, STFM1000_AGC_CONTROL1, &tmp); + if (ret != 0) + return ret; + + /* extract LNATH */ + lna_th = (tmp & STFM1000_B2_LNATH_MASK) >> + STFM1000_B2_LNATH_SHIFT; + + if (lna_rms > lna_th && agc_out <= 1) { + + ret = stfm1000_write_masked(stfm1000, STFM1000_LNA, + STFM1000_USEATTEN(1), STFM1000_USEATTEN_MASK); + if (ret != 0) + return ret; + + } else if (agc_out > 15) { + + ret = stfm1000_write_masked(stfm1000, STFM1000_LNA, + STFM1000_USEATTEN(0), STFM1000_USEATTEN_MASK); + if (ret != 0) + return ret; + } + } + + /* disable buffered writes */ + ret = stfm1000_clear_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_DB_ACCEPT); + if (ret != 0) + return ret; + + return ret; +} + +static int Is_Station(struct stfm1000 *stfm1000) +{ + u32 tmp, rssi_dc_est, tone_data; + u16 rssi_mantissa, rssi_exponent, rssi_decoded; + u16 prssi; + s16 mpx_dc; + int rssi_log; + + /* Get Rssi register readings from STFM1000 */ + stfm1000_read(stfm1000, STFM1000_RSSI_TONE, &tmp); + rssi_dc_est = tmp & 0xffff; + tone_data = (tmp >> 16) & 0x0fff; + + rssi_mantissa = (rssi_dc_est & 0xffe0) >> 5; /* 11Msb */ + rssi_exponent = rssi_dc_est & 0x001f; /* 5 lsb */ + rssi_decoded = (u32)rssi_mantissa << rssi_exponent; + + /* Convert Rsst to 10log(Rssi) */ + for (prssi = 20; prssi > 0; prssi--) + if (rssi_decoded >= (1 << prssi)) + break; + + rssi_log = (3 * rssi_decoded >> prssi) + (3 * prssi - 3); + /* clamp to positive */ + if (rssi_log < 0) + rssi_log = 0; + /* Compensate for errors in truncation/approximation by adding 1 */ + rssi_log++; + + stfm1000->rssi_dc_est_log = rssi_log; + stfm1000->signal_strength = stfm1000->rssi_dc_est_log; + + /* determine absolute value */ + if (tmp & 0x0800) + mpx_dc = ((tmp >> 16) & 0x0fff) | 0xf000; + else + mpx_dc = (tmp >> 16) & 0x0fff; + stfm1000->mpx_dc = mpx_dc; + mpx_dc = mpx_dc < 0 ? -mpx_dc : mpx_dc; + + if (stfm1000->tuning_grid_50KHz) + stfm1000->is_station = rssi_log > stfm1000->tune_rssi_th; + else + stfm1000->is_station = rssi_log > stfm1000->tune_rssi_th && + mpx_dc > stfm1000->tune_mpx_dc_th; + + return 0; +} + +int Monitor_STFM_AGC(struct stfm1000 *stfm1000) +{ + /* we don't do any AGC for now */ + return 0; +} + +static int Take_Down(struct stfm1000 *stfm1000) +{ + Mute_Audio(stfm1000); + + DRI_Off(stfm1000); + + SD_DP_Off(stfm1000); + + return 0; +} + +static int Bring_Up(struct stfm1000 *stfm1000) +{ + SD_DP_On(stfm1000); + + SD_Optimize_Channel(stfm1000); + + DRI_On(stfm1000); + + Unmute_Audio(stfm1000); + + if (stfm1000->rds_enable) + stfm1000_rds_reset(&stfm1000->rds_state); + + stfm1000->rds_sync = stfm1000->rds_enable; /* force sync (if RDS) */ + stfm1000->rds_demod_running = 0; + stfm1000->rssi_dc_est_log = 0; + stfm1000->signal_strength = 0; + + stfm1000->next_quality_monitor = jiffies + msecs_to_jiffies( + stfm1000->quality_monitor_period); + stfm1000->next_agc_monitor = jiffies + msecs_to_jiffies( + stfm1000->agc_monitor_period); + stfm1000->rds_pkt_bad = 0; + stfm1000->rds_pkt_good = 0; + stfm1000->rds_pkt_recovered = 0; + stfm1000->rds_pkt_lost_sync = 0; + stfm1000->rds_bit_overruns = 0; + + return 0; +} + +/* These are not used yet */ + +static int Lock_Station(struct stfm1000 *stfm1000) +{ + int ret; + + ret = SD_Optimize_Channel(stfm1000); + if (ret != 0) + return ret; + + /* AGC monitor start? */ + + return ret; +} + +static const struct stfm1000_reg sd_unlock_regs[] = { + STFM1000_REG_SETBITS(DATAPATH, STFM1000_DB_ACCEPT), + STFM1000_REG_CLRBITS(PILOTTRACKING, STFM1000_B2_PILOTTRACKING_EN), + STFM1000_REG_CLRBITS(DATAPATH, STFM1000_DB_ACCEPT), + STFM1000_END, +}; + +static int Unlock_Station(struct stfm1000 *stfm1000) +{ + int ret; + + ret = stfm1000_write_regs(stfm1000, sd_unlock_regs); + return ret; +} + +irqreturn_t stfm1000_dri_dma_irq(int irq, void *dev_id) +{ + struct stfm1000 *stfm1000 = dev_id; + u32 err_mask, irq_mask; + u32 ctrl; + int handled = 0; + +#ifdef CONFIG_ARCH_STMP37XX + err_mask = 1 << (16 + stfm1000->dma_ch); +#endif +#ifdef CONFIG_ARCH_STMP378X + err_mask = 1 << stfm1000->dma_ch; +#endif + irq_mask = 1 << stfm1000->dma_ch; + +#ifdef CONFIG_ARCH_STMP37XX + ctrl = HW_APBX_CTRL1_RD(); +#endif +#ifdef CONFIG_ARCH_STMP378X + ctrl = HW_APBX_CTRL2_RD(); +#endif + + if (ctrl & err_mask) { + handled = 1; + printk(KERN_WARNING "%s: DMA audio channel %d error\n", + __func__, stfm1000->dma_ch); +#ifdef CONFIG_ARCH_STMP37XX + HW_APBX_CTRL1_CLR(err_mask); +#endif +#ifdef CONFIG_ARCH_STMP378X + HW_APBX_CTRL2_CLR(err_mask); +#endif + } + + if (HW_APBX_CTRL1_RD() & irq_mask) { + handled = 1; + stmp3xxx_dma_clear_interrupt(stfm1000->dma_ch); + + if (stfm1000->alsa_initialized) { + BUG_ON(stfm1000_alsa_ops->dma_irq == NULL); + (*stfm1000_alsa_ops->dma_irq)(stfm1000); + } + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} +EXPORT_SYMBOL(stfm1000_dri_dma_irq); + +irqreturn_t stfm1000_dri_attn_irq(int irq, void *dev_id) +{ + struct stfm1000 *stfm1000 = dev_id; + int handled = 1; + u32 mask; + + (void)stfm1000; + mask = HW_DRI_CTRL_RD(); + mask &= BM_DRI_CTRL_OVERFLOW_IRQ | BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ | + BM_DRI_CTRL_ATTENTION_IRQ; + + HW_DRI_CTRL_CLR(mask); + + printk(KERN_INFO "DRI_ATTN:%s%s%s\n", + (mask & BM_DRI_CTRL_OVERFLOW_IRQ) ? " OV" : "", + (mask & BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ) ? " SL" : "", + (mask & BM_DRI_CTRL_ATTENTION_IRQ) ? " AT" : ""); + + if (stfm1000->alsa_initialized) { + BUG_ON(stfm1000_alsa_ops->attn_irq == NULL); + (*stfm1000_alsa_ops->attn_irq)(stfm1000); + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} +EXPORT_SYMBOL(stfm1000_dri_attn_irq); + +void stfm1000_decode_block(struct stfm1000 *stfm1000, const s16 *src, s16 *dst, + int count) +{ + int i; + + if (stfm1000->mute) { + memset(dst, 0, count * sizeof(s16) * 2); + return; + + } + + for (i = 0; i < count; i++, dst += 2, src += 4) { + + stfm1000_filter_decode(&stfm1000->filter_parms, + src[0], src[1], src[2]); + + dst[0] = stfm1000_filter_value_left(&stfm1000->filter_parms); + dst[1] = stfm1000_filter_value_right(&stfm1000->filter_parms); + } + + stfm1000->rssi = stfm1000->filter_parms.RssiDecoded; + stfm1000->stereo = stfm1000->pilot_present && + !stfm1000->filter_parms.pCoefForcedMono; + + /* RDS processing */ + if (stfm1000->rds_demod_running) { + /* rewind */ + src -= count * 4; + stfm1000_rds_demod(&stfm1000->rds_state, src, count); + } + +} +EXPORT_SYMBOL(stfm1000_decode_block); + +void stfm1000_take_down(struct stfm1000 *stfm1000) +{ + mutex_lock(&stfm1000->state_lock); + stfm1000->active = 0; + Take_Down(stfm1000); + mutex_unlock(&stfm1000->state_lock); +} +EXPORT_SYMBOL(stfm1000_take_down); + +void stfm1000_bring_up(struct stfm1000 *stfm1000) +{ + mutex_lock(&stfm1000->state_lock); + + stfm1000->active = 1; + + stfm1000_filter_reset(&stfm1000->filter_parms); + + Bring_Up(stfm1000); + + mutex_unlock(&stfm1000->state_lock); +} +EXPORT_SYMBOL(stfm1000_bring_up); + +void stfm1000_tune_current(struct stfm1000 *stfm1000) +{ + mutex_lock(&stfm1000->state_lock); + sw_tune(stfm1000, stfm1000->freq); + mutex_unlock(&stfm1000->state_lock); +} +EXPORT_SYMBOL(stfm1000_tune_current); + +/* Alternate ZIF Tunings to avoid EMI */ +const struct stfm1000_tune1 +stfm1000_board_emi_tuneups[STFM1000_FREQUENCY_100KHZ_RANGE] = { +#undef TUNE_ENTRY +#define TUNE_ENTRY(f, t1, sd) \ + [(f) - STFM1000_FREQUENCY_100KHZ_MIN] = \ + { .tune1 = (t1), .sdnom = (sd) } + TUNE_ENTRY(765, 0x84030, 0x1BF5E50D), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(780, 0x84240, 0x1BA5162F), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(795, 0x84250, 0x1C2D2F39), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(810, 0x84460, 0x1BDD207E), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(825, 0x84470, 0x1C6138CD), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(839, 0xC4680, 0x1C11F704), /* 061215 Jon, IF +100kHz */ + TUNE_ENTRY(840, 0x84680, 0x1c11f704), + TUNE_ENTRY(855, 0x84890, 0x1BC71C71), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(870, 0x848A0, 0x1C43DE10), /* 061215 Jon, IF +0kHz */ + TUNE_ENTRY(885, 0x84AB0, 0x1BF9B021), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(899, 0xC4CC0, 0x1BB369A9), /* 061025 Arthur, IF +100kHz */ + TUNE_ENTRY(900, 0x84CC0, 0x1BB369A9), /* 061025 Arthur, IF 0kHz */ + TUNE_ENTRY(915, 0x84CD0, 0x1C299A5B), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(930, 0x84ee0, 0x1be3e6aa), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(945, 0x84ef0, 0x1c570f8b), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(959, 0xC5100, 0x1c11f704), + TUNE_ENTRY(960, 0x85100, 0x1c11f704), + TUNE_ENTRY(975, 0x85310, 0x1bd03d57), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(990, 0x85320, 0x1c3dc822), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(1005, 0x85530, 0x1bfc93ff), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(1019, 0xC5740, 0x1BBE683C), /* 061025 Arthur, IF +100kHz */ + TUNE_ENTRY(1020, 0x85740, 0x1bbe683c), /* 061025 Arthur, IF +0kHz */ + TUNE_ENTRY(1035, 0x85750, 0x1c26dab6), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(1050, 0x85960, 0x1be922b4), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(1065, 0x85970, 0x1c4f357c), /* 061101 Arthur, IF +0kHz */ + TUNE_ENTRY(1079, 0xC5B80, 0x1c11f704), + TUNE_ENTRY(1080, 0x85B80, 0x1c11f704), +#undef TUNE_ENTRY +}; + +static const struct stfm1000_tune1 *stfm1000_board_emi_tune(int freq100) +{ + const struct stfm1000_tune1 *tune1; + + if ((unsigned int)(freq100 - STFM1000_FREQUENCY_100KHZ_MIN) >= + STFM1000_FREQUENCY_100KHZ_RANGE) + return NULL; + + tune1 = &stfm1000_board_emi_tuneups[freq100 - + STFM1000_FREQUENCY_100KHZ_MIN]; + if (tune1->tune1 == 0 && tune1->sdnom == 0) + return NULL; + return tune1; +} + +/* freq in kHz */ +static int sw_tune(struct stfm1000 *stfm1000, u32 freq) +{ + u32 freq100 = freq / 100; + int tune_cap; + int i2s_clock; + int mix_reg; + int if_freq, fe_freq; + u32 tune1, sdnom, agc1; + const struct stfm1000_tune1 *tp; + int ret; + + if_freq = 0; + mix_reg = 1; + switch (mix_reg) { + case 0: if_freq = -2; break; + case 1: if_freq = -1; break; + case 2: if_freq = 0; break; + case 3: if_freq = 1; break; + case 4: if_freq = 2; break; + } + + /* handle board specific EMI tuning */ + tp = stfm1000_board_emi_tune(freq100); + if (tp != NULL) { + tune1 = tp->tune1; + sdnom = tp->sdnom; + } else { + fe_freq = freq100 + if_freq; + + /* clamp into range */ + if (fe_freq < STFM1000_FREQUENCY_100KHZ_MIN) + fe_freq = STFM1000_FREQUENCY_100KHZ_MIN; + else if (fe_freq > STFM1000_FREQUENCY_100KHZ_MAX) + fe_freq = STFM1000_FREQUENCY_100KHZ_MAX; + + tp = &stfm1000_tune1_table[fe_freq - + STFM1000_FREQUENCY_100KHZ_MIN]; + + /* bits [14:0], [20:18] */ + tune1 = (tp->tune1 & 0x7fff) | (mix_reg << 18); + sdnom = tp->sdnom; + } + + agc1 = stfm1000->revid == STFM1000_CHIP_REV_TA2 ? 0x0400 : 0x2200; + + ret = stfm1000_write_masked(stfm1000, STFM1000_AGC_CONTROL1, + agc1, 0x3f00); + if (ret != 0) + goto err; + + ret = stfm1000_write_masked(stfm1000, STFM1000_TUNE1, tune1, + 0xFFFF7FFF); /* do not set bit-15 */ + if (ret != 0) + goto err; + + /* keep this around */ + stfm1000->sdnominal_pivot = sdnom; + + ret = stfm1000_write(stfm1000, STFM1000_SDNOMINAL, sdnom); + if (ret != 0) + goto err; + + /* fix for seek-not-stopping on alternate tunings */ + ret = stfm1000_set_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_DB_ACCEPT); + if (ret != 0) + goto err; + + ret = stfm1000_clear_bits(stfm1000, STFM1000_DATAPATH, + STFM1000_DB_ACCEPT); + if (ret != 0) + goto err; + + ret = stfm1000_set_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_DRI_CLK_EN); + if (ret != 0) + goto err; + + /* 6MHz spur fix */ + if ((freq100 >= 778 && freq100 <= 782) || + (freq100 >= 838 && freq100 <= 842) || + (freq100 >= 898 && freq100 <= 902) || + (freq100 >= 958 && freq100 <= 962) || + (freq100 >= 1018 && freq100 <= 1022) || + (freq100 >= 1078 && freq100 <= 1080)) + i2s_clock = 5; /* 4.8MHz */ + else + i2s_clock = 4; + + ret = stfm1000_write_masked(stfm1000, STFM1000_DATAPATH, + STFM1000_SAI_CLK_DIV(i2s_clock), STFM1000_SAI_CLK_DIV_MASK); + if (ret != 0) + goto err; + + ret = stfm1000_set_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_DRI_CLK_EN); + if (ret != 0) + goto err; + + if (tune1 & 0xf) + ret = stfm1000_set_bits(stfm1000, STFM1000_CLK1, + STFM1000_ENABLE_TAPDELAYFIX); + else + ret = stfm1000_clear_bits(stfm1000, STFM1000_CLK1, + STFM1000_ENABLE_TAPDELAYFIX); + + if (ret != 0) + goto err; + + tune_cap = (int)(stfm1000->tune_cap_a_f - + stfm1000->tune_cap_b_f * freq100); + if (tune_cap < 4) + tune_cap = 4; + ret = stfm1000_write_masked(stfm1000, STFM1000_LNA, + STFM1000_ANTENNA_TUNECAP(tune_cap), + STFM1000_ANTENNA_TUNECAP_MASK); + if (ret != 0) + goto err; + + /* set signal strenth to 0 */ + /* stfm1000_dcdc_update(); */ + + /* cmp_rds_setRdsStatus(0) */ + /* cmp_rds_ResetGroupCallbacks(); */ + stfm1000->freq = freq; + + return 0; +err: + return -1; +} + +static const struct v4l2_queryctrl radio_qctrl[] = { + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-stfm1000", sizeof(v->driver)); + strlcpy(v->card, "STFM1000 Radio", sizeof(v->card)); + sprintf(v->bus_info, "i2c"); + v->version = KERNEL_VERSION(0, 0, 1); + v->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + u32 tmp, rssi_dc_est, tone_data; + u16 rssi_mantissa, rssi_exponent, rssi_decoded; + u16 prssi; + s16 mpx_dc; + int rssi_log; + int ret; + + if (v->index > 0) + return -EINVAL; + + mutex_lock(&stfm1000->state_lock); + + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; + v->rangelow = (u32)(87.5 * 16000); + v->rangehigh = (u32)(108 * 16000); + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + v->audmode = V4L2_TUNER_MODE_STEREO; + v->signal = 0; /* tr_getsigstr(); */ + + msleep(50); + + ret = stfm1000_read(stfm1000, STFM1000_RSSI_TONE, &tmp); + if (ret != 0) + goto out; + + rssi_dc_est = tmp & 0xffff; + tone_data = (tmp >> 16) & 0x0fff; + + rssi_mantissa = (rssi_dc_est & 0xffe0) >> 5; /* 11Msb */ + rssi_exponent = rssi_dc_est & 0x001f; /* 5 lsb */ + rssi_decoded = (u32)rssi_mantissa << rssi_exponent; + + /* Convert Rsst to 10log(Rssi) */ + for (prssi = 20; prssi > 0; prssi--) + if (rssi_decoded >= (1 << prssi)) + break; + + rssi_log = (3 * rssi_decoded >> prssi) + (3 * prssi - 3); + /* clamp to positive */ + if (rssi_log < 0) + rssi_log = 0; + /* Compensate for errors in truncation/approximation by adding 1 */ + rssi_log++; + + stfm1000->rssi_dc_est_log = rssi_log; + stfm1000->signal_strength = stfm1000->rssi_dc_est_log; + + /* determine absolute value */ + if (tmp & 0x0800) + mpx_dc = ((tmp >> 16) & 0x0fff) | 0xf000; + else + mpx_dc = (tmp >> 16) & 0x0fff; + stfm1000->mpx_dc = mpx_dc; + mpx_dc = mpx_dc < 0 ? -mpx_dc : mpx_dc; + + v->signal = rssi_decoded & 0xffff; + +out: + mutex_unlock(&stfm1000->state_lock); + + return ret; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + (void)stfm1000; + + if (v->index > 0) + return -EINVAL; + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + mutex_lock(&stfm1000->state_lock); + + /* convert from the crazy linux value to our decimal based values */ + stfm1000->freq = (u32)div_u64((u64)(125 * (u64)f->frequency), 2000); + + if (stfm1000->active) + Take_Down(stfm1000); + + sw_tune(stfm1000, stfm1000->freq); + + if (stfm1000->active) + Bring_Up(stfm1000); + + mutex_unlock(&stfm1000->state_lock); + + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + f->type = V4L2_TUNER_RADIO; + f->frequency = stfm1000->freq * 16; + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + int i; + + (void)stfm1000; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &radio_qctrl[i], sizeof(*qc)); + return 0; + } + } + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + switch (ctrl->id) { + + case V4L2_CID_AUDIO_MUTE: + ctrl->value = stfm1000->mute; + return 0; + + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + int ret; + + mutex_lock(&stfm1000->state_lock); + + ret = -EINVAL; + + switch (ctrl->id) { + + case V4L2_CID_AUDIO_MUTE: + stfm1000->mute = ctrl->value; + ret = 0; + break; + } + + mutex_unlock(&stfm1000->state_lock); + + return ret; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + (void)stfm1000; + + if (a->index > 1) + return -EINVAL; + + strcpy(a->name, "Radio"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + (void)stfm1000; + + *i = 0; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + (void)stfm1000; + + if (i != 0) + return -EINVAL; + + return 0; +} + +const struct v4l2_ioctl_ops stfm_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static int stfm1000_open(struct inode *inode, struct file *file) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + mutex_lock(&stfm1000->state_lock); + stfm1000->users = 1; + mutex_unlock(&stfm1000->state_lock); + + return 0; +} +static int stfm1000_close(struct inode *inode, struct file *file) +{ + struct stfm1000 *stfm1000 = stfm1000_from_file(file); + + if (!stfm1000) + return -ENODEV; + + stfm1000->users = 0; + if (stfm1000->removed) + kfree(stfm1000); + return 0; +} + +static const struct file_operations stfm1000_fops = { + .owner = THIS_MODULE, + .open = stfm1000_open, + .release = stfm1000_close, + .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl = v4l_compat_ioctl32, +#endif + .llseek = no_llseek, +}; + +/* sysfs */ + +#define STFM1000_RO_ATTR(var) \ +static ssize_t stfm1000_show_ ## var(struct device *d, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(d); \ + struct stfm1000 *stfm1000 = i2c_get_clientdata(client); \ + return sprintf(buf, "%d\n", stfm1000->var); \ +} \ +static DEVICE_ATTR(var, 0444, stfm1000_show_ ##var, NULL) + +#define STFM1000_RW_ATTR(var) \ +static ssize_t stfm1000_show_ ## var(struct device *d, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(d); \ + struct stfm1000 *stfm1000 = i2c_get_clientdata(client); \ + return sprintf(buf, "%u\n", stfm1000->var); \ +} \ +static ssize_t stfm1000_store_ ## var(struct device *d, \ + struct device_attribute *attr, const char *buf, size_t size) \ +{ \ + struct i2c_client *client = to_i2c_client(d); \ + struct stfm1000 *stfm1000 = i2c_get_clientdata(client); \ + unsigned long v; \ + \ + strict_strtoul(buf, 0, &v); \ + stfm1000_commit_ ## var(stfm1000, v); \ + return size; \ +} \ +static DEVICE_ATTR(var, 0644, stfm1000_show_ ##var, stfm1000_store_ ##var) + +#define STFM1000_RW_ATTR_SIMPLE(var) \ +static void stfm1000_commit_ ## var(struct stfm1000 *stfm1000, \ + unsigned long value) \ +{ \ + stfm1000->var = value; \ +} \ +STFM1000_RW_ATTR(var) + +STFM1000_RO_ATTR(weak_signal); +STFM1000_RO_ATTR(pilot_present); +STFM1000_RO_ATTR(stereo); +STFM1000_RO_ATTR(rssi); +STFM1000_RO_ATTR(mpx_dc); +STFM1000_RO_ATTR(signal_strength); +STFM1000_RW_ATTR_SIMPLE(rds_signal_th); +STFM1000_RO_ATTR(rds_present); +STFM1000_RO_ATTR(is_station); + +static void stfm1000_commit_georegion(struct stfm1000 *stfm1000, + unsigned long value) +{ + /* don't do anything for illegal region */ + if (value != 0 && value != 1) + return; + + mutex_lock(&stfm1000->state_lock); + + stfm1000->georegion = value; + if (stfm1000->georegion == 0) + stfm1000_clear_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_DEEMPH_50_75B); + else + stfm1000_set_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_DEEMPH_50_75B); + + mutex_unlock(&stfm1000->state_lock); +} +STFM1000_RW_ATTR(georegion); + +static void stfm1000_commit_freq(struct stfm1000 *stfm1000, + unsigned long value) +{ + mutex_lock(&stfm1000->state_lock); + + /* clamp */ + if (value < STFM1000_FREQUENCY_100KHZ_MIN * 100) + value = STFM1000_FREQUENCY_100KHZ_MIN * 100; + else if (value > STFM1000_FREQUENCY_100KHZ_MAX * 100) + value = STFM1000_FREQUENCY_100KHZ_MAX * 100; + + stfm1000->freq = value; + + if (stfm1000->active) + Take_Down(stfm1000); + + sw_tune(stfm1000, stfm1000->freq); + + if (stfm1000->active) + Bring_Up(stfm1000); + + mutex_unlock(&stfm1000->state_lock); +} +STFM1000_RW_ATTR(freq); + +static void stfm1000_commit_mute(struct stfm1000 *stfm1000, + unsigned long value) +{ + stfm1000->mute = !!value; +} +STFM1000_RW_ATTR(mute); + +static void stfm1000_commit_force_mono(struct stfm1000 *stfm1000, + unsigned long value) +{ + stfm1000->force_mono = !!value; + /* set force mono parameters for the filter */ + stfm1000->filter_parms.pCoefForcedMono = stfm1000->force_mono; + + /* yeah, I know, it's stupid */ + stfm1000->rds_state.demod.pCoefForcedMono = + stfm1000->filter_parms.pCoefForcedMono; +} +STFM1000_RW_ATTR(force_mono); + +STFM1000_RW_ATTR_SIMPLE(monitor_period); +STFM1000_RW_ATTR_SIMPLE(quality_monitor); +STFM1000_RW_ATTR_SIMPLE(quality_monitor_period); +STFM1000_RW_ATTR_SIMPLE(agc_monitor_period); +STFM1000_RW_ATTR_SIMPLE(tune_rssi_th); +STFM1000_RW_ATTR_SIMPLE(tune_mpx_dc_th); + +static void stfm1000_commit_rds_enable(struct stfm1000 *stfm1000, + unsigned long value) +{ + /* don't do anything for illegal values (or for not TB2) */ + if ((value != 0 && value != 1) || + stfm1000->revid == STFM1000_CHIP_REV_TA2) + return; + + mutex_lock(&stfm1000->state_lock); + + stfm1000->rds_enable = value; + if (stfm1000->rds_enable == 0) + stfm1000_clear_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_RDS_ENABLE); + else + stfm1000_set_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_RDS_ENABLE); + + mutex_unlock(&stfm1000->state_lock); +} +STFM1000_RW_ATTR(rds_enable); + +static void stfm1000_commit_rds_sync(struct stfm1000 *stfm1000, + unsigned long value) +{ + stfm1000->rds_sync = stfm1000->rds_enable && !!value; +} +STFM1000_RW_ATTR(rds_sync); + +STFM1000_RW_ATTR_SIMPLE(rds_pkt_good); +STFM1000_RW_ATTR_SIMPLE(rds_pkt_bad); +STFM1000_RW_ATTR_SIMPLE(rds_pkt_recovered); +STFM1000_RW_ATTR_SIMPLE(rds_pkt_lost_sync); +STFM1000_RW_ATTR_SIMPLE(rds_bit_overruns); +STFM1000_RW_ATTR_SIMPLE(rds_info); + +static void stfm1000_commit_rds_sdnominal_adapt(struct stfm1000 *stfm1000, + unsigned long value) +{ + stfm1000->rds_sdnominal_adapt = !!value; + stfm1000->rds_state.demod.sdnom_adapt = stfm1000->rds_sdnominal_adapt; +} +STFM1000_RW_ATTR(rds_sdnominal_adapt); + +static void stfm1000_commit_rds_phase_pop(struct stfm1000 *stfm1000, + unsigned long value) +{ + stfm1000->rds_phase_pop = !!value; + stfm1000->rds_state.demod.PhasePoppingEnabled = + stfm1000->rds_phase_pop; +} +STFM1000_RW_ATTR(rds_phase_pop); + +STFM1000_RW_ATTR_SIMPLE(tuning_grid_50KHz); + +static ssize_t stfm1000_show_rds_ps(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(d); + struct stfm1000 *stfm1000 = i2c_get_clientdata(client); + char ps[9]; + + if (stfm1000_rds_get_ps(&stfm1000->rds_state, ps, sizeof(ps)) <= 0) + ps[0] = '\0'; + + return sprintf(buf, "%s\n", ps); +} +static DEVICE_ATTR(rds_ps, 0444, stfm1000_show_rds_ps, NULL); + +static ssize_t stfm1000_show_rds_text(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(d); + struct stfm1000 *stfm1000 = i2c_get_clientdata(client); + char text[65]; + + if (stfm1000_rds_get_text(&stfm1000->rds_state, text, + sizeof(text)) <= 0) + text[0] = '\0'; + + return sprintf(buf, "%s\n", text); +} +static DEVICE_ATTR(rds_text, 0444, stfm1000_show_rds_text, NULL); + +static struct device_attribute *stfm1000_attrs[] = { + &dev_attr_agc_monitor_period, + &dev_attr_force_mono, + &dev_attr_freq, + &dev_attr_georegion, + &dev_attr_is_station, + &dev_attr_monitor_period, + &dev_attr_mpx_dc, + &dev_attr_mute, + &dev_attr_pilot_present, + &dev_attr_quality_monitor, + &dev_attr_quality_monitor_period, + &dev_attr_rds_bit_overruns, + &dev_attr_rds_enable, + &dev_attr_rds_info, + &dev_attr_rds_phase_pop, + &dev_attr_rds_pkt_bad, + &dev_attr_rds_pkt_good, + &dev_attr_rds_pkt_lost_sync, + &dev_attr_rds_pkt_recovered, + &dev_attr_rds_present, + &dev_attr_rds_ps, + &dev_attr_rds_sdnominal_adapt, + &dev_attr_rds_signal_th, + &dev_attr_rds_sync, + &dev_attr_rds_text, + &dev_attr_rssi, + &dev_attr_signal_strength, + &dev_attr_stereo, + &dev_attr_tune_mpx_dc_th, + &dev_attr_tune_rssi_th, + &dev_attr_tuning_grid_50KHz, + &dev_attr_weak_signal, + NULL, +}; + +/* monitor thread */ + +static void rds_process(struct stfm1000 *stfm1000) +{ + int count, bit; + int mix_reg, sdnominal_reg; + u32 sdnom, sdnom_new, limit; + u8 buf[8]; + + if (!stfm1000->rds_enable) + return; + + if (stfm1000->rds_sync && + stfm1000->rssi_dc_est_log > stfm1000->rds_signal_th) { + if (stfm1000->rds_info) + printk(KERN_INFO "RDS: sync\n"); + stfm1000_rds_reset(&stfm1000->rds_state); + stfm1000->rds_demod_running = 1; + stfm1000->rds_sync = 0; + } + + if (!stfm1000->rds_demod_running) + return; + + /* process mix reg requests */ + spin_lock_irq(&stfm1000->rds_lock); + mix_reg = stfm1000_rds_mix_msg_get(&stfm1000->rds_state); + spin_unlock_irq(&stfm1000->rds_lock); + + if (mix_reg != -1) { + + if (stfm1000->rds_info) + printk(KERN_INFO "RDS: new RDS_MIXOFFSET %d\n", + mix_reg & 1); + + /* update register */ + if (mix_reg & 1) + stfm1000_set_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_RDS_MIXOFFSET); + else + stfm1000_clear_bits(stfm1000, STFM1000_INITIALIZATION2, + STFM1000_RDS_MIXOFFSET); + + /* signal it's processed */ + spin_lock_irq(&stfm1000->rds_lock); + stfm1000_rds_mix_msg_processed(&stfm1000->rds_state, mix_reg); + spin_unlock_irq(&stfm1000->rds_lock); + } + + /* process sdnominal reg requests */ + spin_lock_irq(&stfm1000->rds_lock); + sdnominal_reg = stfm1000_rds_sdnominal_msg_get(&stfm1000->rds_state); + spin_unlock_irq(&stfm1000->rds_lock); + + /* any change? */ + if (sdnominal_reg != 0) { + + stfm1000_read(stfm1000, STFM1000_SDNOMINAL, &sdnom); + + sdnom_new = sdnom + sdnominal_reg; + + /* Limit SDNOMINAL to within 244 ppm of its ideal value */ + limit = stfm1000->sdnominal_pivot + + (stfm1000->sdnominal_pivot >> 12); + if (sdnom_new > limit) + sdnom_new = limit; + + limit = stfm1000->sdnominal_pivot - + (stfm1000->sdnominal_pivot >> 12); + if (sdnom_new < limit) + sdnom_new = limit; + + /* write the register */ + stfm1000_write(stfm1000, STFM1000_SDNOMINAL, sdnom_new); + + /* signal it's processed */ + spin_lock_irq(&stfm1000->rds_lock); + stfm1000_rds_sdnominal_msg_processed(&stfm1000->rds_state, + sdnominal_reg); + spin_unlock_irq(&stfm1000->rds_lock); + } + + /* pump bits out & pass them to the process function */ + spin_lock_irq(&stfm1000->rds_lock); + while (stfm1000_rds_bits_available(&stfm1000->rds_state) > 128) { + count = 0; + while (count++ < 128 && + (bit = stmf1000_rds_get_bit( + &stfm1000->rds_state)) >= 0) { + spin_unlock_irq(&stfm1000->rds_lock); + + /* push bit for packet processing */ + stfm1000_rds_packet_bit(&stfm1000->rds_state, bit); + + spin_lock_irq(&stfm1000->rds_lock); + } + } + spin_unlock_irq(&stfm1000->rds_lock); + + /* now we're free to process non-interrupt related work */ + while (stfm1000_rds_packet_dequeue(&stfm1000->rds_state, buf) == 0) { + + if (stfm1000->rds_info) + printk(KERN_INFO "RDS-PKT: %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + stfm1000_rds_process_packet(&stfm1000->rds_state, buf); + } + + /* update our own counters */ + stfm1000->rds_pkt_good += stfm1000->rds_state.pkt.good_packets; + stfm1000->rds_pkt_bad += stfm1000->rds_state.pkt.bad_packets; + stfm1000->rds_pkt_recovered += + stfm1000->rds_state.pkt.recovered_packets; + stfm1000->rds_pkt_lost_sync += + stfm1000->rds_state.pkt.sync_lost_packets; + stfm1000->rds_bit_overruns += + stfm1000->rds_state.demod.RdsDemodSkippedBitCnt; + + /* zero them now */ + stfm1000->rds_state.pkt.good_packets = 0; + stfm1000->rds_state.pkt.bad_packets = 0; + stfm1000->rds_state.pkt.recovered_packets = 0; + stfm1000->rds_state.pkt.sync_lost_packets = 0; + stfm1000->rds_state.demod.RdsDemodSkippedBitCnt = 0; + + /* reset requested from RDS handler? */ + if (stfm1000_rds_get_reset_req(&stfm1000->rds_state)) { + if (stfm1000->rds_info) + printk(KERN_INFO "RDS: reset requested\n"); + stfm1000_rds_reset(&stfm1000->rds_state); + + stfm1000->rds_sync = stfm1000->rds_enable; /* force sync (if RDS) */ + stfm1000->rds_demod_running = 0; + stfm1000->rssi_dc_est_log = 0; + stfm1000->signal_strength = 0; + } +} + +void stfm1000_monitor_signal(struct stfm1000 *stfm1000, int bit) +{ + set_bit(bit, &stfm1000->thread_events); + return wake_up_interruptible(&stfm1000->thread_wait); +} + +static int stfm1000_monitor_thread(void *data) +{ + struct stfm1000 *stfm1000 = data; + int ret; + + printk(KERN_INFO "stfm1000: monitor thread started\n"); + + set_freezable(); + + /* Hmm, linux becomes *very* unhappy without this ... */ + while (!kthread_should_stop()) { + + ret = wait_event_interruptible_timeout(stfm1000->thread_wait, + stfm1000->thread_events == 0, + msecs_to_jiffies(stfm1000->monitor_period)); + + stfm1000->thread_events = 0; + + if (kthread_should_stop()) + break; + + try_to_freeze(); + + mutex_lock(&stfm1000->state_lock); + + /* we must be active */ + if (!stfm1000->active) + goto next; + + if (stfm1000->rds_enable) + rds_process(stfm1000); + + /* perform quality monitor */ + if (time_after_eq(jiffies, stfm1000->next_quality_monitor)) { + + /* full quality monitor? */ + if (stfm1000->quality_monitor) + Monitor_STFM_Quality(stfm1000); + else /* simple */ + Is_Station(stfm1000); + + while (time_after_eq(jiffies, + stfm1000->next_quality_monitor)) + stfm1000->next_quality_monitor += + msecs_to_jiffies( + stfm1000->quality_monitor_period); + } + + /* perform AGC monitor (if enabled) */ + if (stfm1000->agc_monitor && time_after_eq(jiffies, + stfm1000->next_agc_monitor)) { + Monitor_STFM_AGC(stfm1000); + while (time_after_eq(jiffies, + stfm1000->next_agc_monitor)) + stfm1000->next_agc_monitor += + msecs_to_jiffies( + stfm1000->agc_monitor_period); + } +next: + mutex_unlock(&stfm1000->state_lock); + } + + printk(KERN_INFO "stfm1000: monitor thread stopped\n"); + + return 0; +} + +static u64 stfm1000_dma_mask = DMA_32BIT_MASK; + +static int stfm1000_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct device *dev; + struct stfm1000 *stfm1000; + struct video_device *vd; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; + u32 id; + const char *idtxt; + int i; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&adapter->dev, + "I2C doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n"); + return -EIO; + } + + /* make sure the dma masks are set correctly */ + dev = &client->dev; + if (!dev->dma_mask) + dev->dma_mask = &stfm1000_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_32BIT_MASK; + + stfm1000 = kzalloc(sizeof(*stfm1000), GFP_KERNEL); + if (!stfm1000) + return -ENOMEM; + + stfm1000->client = client; + i2c_set_clientdata(client, stfm1000); + + mutex_init(&stfm1000->xfer_lock); + mutex_init(&stfm1000->state_lock); + + vd = &stfm1000->radio; + + strcpy(vd->name, "stfm1000"); + vd->vfl_type = VID_TYPE_TUNER; + vd->fops = &stfm1000_fops; + vd->ioctl_ops = &stfm_ioctl_ops; + + /* vd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; */ + + vd->parent = &client->dev; + + ret = video_register_device(vd, VFL_TYPE_RADIO, -1); + if (ret != 0) { + dev_warn(&adapter->dev, + "Cannot register radio device\n"); + goto out; + } + + spin_lock_init(&stfm1000->rds_lock); + + stfm1000_setup_reg_set(stfm1000); + + /* stfm1000->dbgflg |= STFM1000_DBGFLG_I2C; */ + + ret = stfm1000_read(stfm1000, STFM1000_CHIPID, &id); + if (ret < 0) { + dev_warn(&adapter->dev, + "Cannot read ID register\n"); + goto out; + } + stfm1000->revid = id & 0xff; + + /* NOTE: the tables are precalculated */ + stfm1000->tune_rssi_th = 28; + stfm1000->tune_mpx_dc_th = 300; + stfm1000->adj_chan_th = 100; + stfm1000->pilot_est_th = 25; + stfm1000->agc_monitor = 0; /* AGC monitor disabled */ + stfm1000->quality_monitor = 1; + stfm1000->weak_signal = 0; + stfm1000->prev_pilot_present = 0; + stfm1000->tune_cap_a_f = (u32)(72.4 * 65536); + stfm1000->tune_cap_b_f = (u32)(0.07 * 65536); + + /* only TB2 supports RDS */ + stfm1000->rds_enable = stfm1000->revid == STFM1000_CHIP_REV_TB2 && + rds_enable; + stfm1000->rds_present = 0; + stfm1000->rds_signal_th = 33; + + stfm1000->freq = 92600; + + stfm1000->georegion = georegion; + stfm1000->rssi = 0; + stfm1000->stereo = 0; + stfm1000->force_mono = 0; + stfm1000->monitor_period = 100; + stfm1000->quality_monitor_period = 1000; + stfm1000->agc_monitor_period = 200; + + stfm1000->rds_sdnominal_adapt = 0; + stfm1000->rds_phase_pop = 1; + + /* enable info about RDS */ + stfm1000->rds_info = 0; + + ret = stfm1000_power_up(stfm1000); + if (ret != 0) { + printk(KERN_ERR "%s: stfm1000_power_up failed\n", + __func__); + goto out; + } + + if (stfm1000_alsa_ops && stfm1000_alsa_ops->init) { + ret = (*stfm1000_alsa_ops->init)(stfm1000); + if (ret != 0) + goto out; + stfm1000->alsa_initialized = 1; + } + + ret = 0; + for (i = 0; stfm1000_attrs[i]; i++) { + ret = device_create_file(dev, stfm1000_attrs[i]); + if (ret) + break; + } + if (ret) { + while (--i >= 0) + device_remove_file(dev, stfm1000_attrs[i]); + goto out; + } + + /* add it to the list */ + mutex_lock(&devlist_lock); + stfm1000->idx = stfm1000_devcount++; + list_add_tail(&stfm1000->devlist, &stfm1000_devlist); + mutex_unlock(&devlist_lock); + + init_waitqueue_head(&stfm1000->thread_wait); + stfm1000->thread = kthread_run(stfm1000_monitor_thread, stfm1000, + "stfm1000-%d", stfm1000->idx); + if (stfm1000->thread == NULL) { + printk(KERN_ERR "stfm1000: kthread_run failed\n"); + goto out; + } + + idtxt = stfm1000_get_rev_txt(stfm1000->revid); + if (idtxt == NULL) + printk(KERN_INFO "STFM1000: Loaded for unknown revision id " + "0x%02x\n", stfm1000->revid); + else + printk(KERN_INFO "STFM1000: Loaded for revision %s\n", idtxt); + + return 0; + +out: + kfree(stfm1000); + return ret; +} + +static int stfm1000_remove(struct i2c_client *client) +{ + struct stfm1000 *stfm1000 = i2c_get_clientdata(client); + struct device *dev = &client->dev; + int i; + + kthread_stop(stfm1000->thread); + + for (i = 0; stfm1000_attrs[i]; i++) + device_remove_file(dev, stfm1000_attrs[i]); + + if (stfm1000->alsa_initialized) { + BUG_ON(stfm1000_alsa_ops->release == NULL); + (*stfm1000_alsa_ops->release)(stfm1000); + stfm1000->alsa_initialized = 0; + } + + stfm1000_power_down(stfm1000); + + video_unregister_device(&stfm1000->radio); + + mutex_lock(&devlist_lock); + list_del(&stfm1000->devlist); + mutex_unlock(&devlist_lock); + + kfree(stfm1000); + return 0; +} + +static const struct i2c_device_id stfm1000_id[] = { + { "stfm1000", 0xC0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, stfm1000_id); + +static struct i2c_driver stfm1000_i2c_driver = { + .driver = { + .name = "stfm1000", + }, + .probe = stfm1000_probe, + .remove = stfm1000_remove, + .id_table = stfm1000_id, +}; + +static int __init +stfm1000_init(void) +{ + /* pull those in */ + (void)Lock_Station; + (void)Unlock_Station; + return i2c_add_driver(&stfm1000_i2c_driver); +} + +static void __exit +stfm1000_exit(void) +{ + i2c_del_driver(&stfm1000_i2c_driver); + + stfm1000_alsa_ops = NULL; +} + +module_init(stfm1000_init); +module_exit(stfm1000_exit); + +MODULE_AUTHOR("Pantelis Antoniou"); +MODULE_DESCRIPTION("A driver for the STFM1000 chip."); +MODULE_LICENSE("GPL"); + +module_param(georegion, int, 0400); +module_param(rds_enable, int, 0400); diff --git a/drivers/media/radio/stfm1000/stfm1000-filter.c b/drivers/media/radio/stfm1000/stfm1000-filter.c new file mode 100644 index 000000000000..df42524a5da7 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-filter.c @@ -0,0 +1,860 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> + +#include "stfm1000.h" + +void stfm1000_filter_reset(struct stfm1000_filter_parms *sdf) +{ + sdf->Left = 0; + sdf->Right = 0; + sdf->RssiDecoded = 0; + sdf->RssiMant = 0; + sdf->RssiExp = 0; + sdf->RssiLb = 0; + sdf->TrueRssi = 0; + sdf->Prssi = 0; + sdf->RssiLog = 0; + sdf->ScaledTrueRssi = 0; + sdf->FilteredRssi = 0; + sdf->PrevFilteredRssi = 0; + sdf->DecRssi = 0; + sdf->ScaledRssiDecoded = 0; + sdf->ScaledRssiDecodedZ = 0; + sdf->ScaledRssiDecodedZz = 0; + sdf->Echo = 0; + sdf->EchoLb = 0; + sdf->TrueEcho = 0; + sdf->FilteredEchoLpr = 0; + sdf->PrevFilteredEchoLpr = 0; + sdf->FilteredEchoLmr = 0; + sdf->PrevFilteredEchoLmr = 0; + sdf->GatedEcho = 0; + sdf->ControlLpr = 0; + sdf->ControlLmr = 0; + sdf->LprBw = 0; + sdf->LmrBw = 0; + + sdf->LprXz = 0; + sdf->LprXzz = 0; + sdf->LprYz = 0; + sdf->LprYzz = 0; + sdf->LmrXz = 0; + sdf->LmrXzz = 0; + sdf->LmrYz = 0; + sdf->LmrYzz = 0; + sdf->FilteredLpr = 0; + sdf->FilteredLmr = 0; + + sdf->B0B = 0; + sdf->B0S = 0; + sdf->B0M = 0; + sdf->B1over2B = 0; + sdf->B1over2S = 0; + sdf->B1over2M = 0; + sdf->A1over2B = 0; + sdf->A1over2S = 0; + sdf->A1over2M = 0; + sdf->A2B = 0; + sdf->A2S = 0; + sdf->A2M = 0; + + sdf->AdjBw = 0; + + sdf->pCoefLprBwThLo = 20 << 8; + sdf->pCoefLprBwThHi = 30 << 8; + sdf->pCoefLmrBwThLo = 40 << 8; + sdf->pCoefLmrBwThHi = 50 << 8; + sdf->pCoefLprBwSlSc = 4800; /* SDK-2287 */ + sdf->pCoefLprBwSlSh = 10; /* SDK-2287 */ + sdf->pCoefLmrBwSlSc = 4800; /* SDK-2287 */ + sdf->pCoefLmrBwSlSh = 10; /* SDK-2287 */ + sdf->pCoefLprGaSlSc = 0; + sdf->pCoefLprGaSlSh = 0; + + sdf->ScaledControlLmr = 0; + + sdf->LprGa = 32767; + sdf->LmrGa = 32767; + + sdf->pCoefLprGaTh = 20; /* 25 */ + sdf->pCoefLmrGaTh = 55; /* 60 50 */ + + sdf->MuteAudio = 0; + sdf->PrevMuteAudio = 0; + sdf->MuteActionFlag = 0; + sdf->ScaleAudio = 0; + + /* *** Programmable initial setup for stereo path filters */ + sdf->LprB0 = 18806; /* -3dB cutoff = 17 kHz */ + sdf->LprB1over2 = 18812; /* -3dB cutoff = 17 kHz */ + sdf->LprA1over2 = -16079; /* -3dB cutoff = 17 kHz */ + sdf->LprA2 = -11125; /* -3dB cutoff = 17 kHz */ + sdf->LmrB0 = 18806; /* -3dB cutoff = 17 kHz */ + sdf->LmrB1over2 = 18812; /* -3dB cutoff = 17 kHz */ + sdf->LmrA1over2 = -16079; /* -3dB cutoff = 17 kHz */ + sdf->LmrA2 = -11125; /* -3dB cutoff = 17 kHz */ + + sdf->pCoefForceLockLmrBw = 0; /* Force Lock LMR BW = LPR BW + * XXX BUG WARNING - + * This control doesn't work! */ + + sdf->pCoefForcedMono = 0; /* Do not set this = + * Quality Monitor will overwrite it */ + sdf->pCoefBypassBlend = 0; /* BUG WARNING - + * This control doesn't work! */ + sdf->pCoefBypassSoftmute = 0; /* BUG WARNING - + * This control doesn't work! */ + sdf->pCoefBypassBwCtl = 0; /* BUG WARNING - + * This control doesn't work! */ + + /* There's a bug or something in the attack/decay section b/c + * setting these coef's to anything */ + /* higher than 100ms or so causes the RSSI to be artificially low - + * Needs investigation! 15DEC06 */ + sdf->pCoefRssiAttack = 65386; /* changed to 100ms to avoid + * stereo crackling + * 60764 corresponds to 3 */ + sdf->pCoefRssiDecay = 65386; /* changed to 100ms to avoid + * stereo crackling + * 65530 corresponds to 10 */ + sdf->pCoefEchoLprAttack = 52239; /* corresponds to 1 */ + sdf->pCoefEchoLprDecay = 64796; /* corresponds to 20 */ + sdf->pCoefEchoLmrAttack = 52239; /* corresponds to 1 */ + sdf->pCoefEchoLmrDecay = 65520; /* corresponds to 20 */ + sdf->pCoefEchoTh = 100; + sdf->pCoefEchoScLpr = (u16) (0.9999 * 32767.0); + sdf->pCoefEchoScLmr = (u16) (0.9999 * 32767.0); +} + +void stfm1000_filter_decode(struct stfm1000_filter_parms *sdf, s16 Lpr, + s16 Lmr, u16 Rssi) +{ + s16 temp1_reg; /* mimics 16 bit register */ + s16 temp2_reg; /* mimics 16 bit register */ + s16 temp3_reg; /* mimics 16 bit register */ + s16 temp4_reg; /* mimics 16 bit register */ +#ifndef _TUNER_STFM_MUTE + s16 temp5_reg; /* mimics 16 bit register */ +#endif + s32 temp2_reg_32; /*eI 108 27th Feb 06 temp variables. */ + + /* **************************************************************** */ + /* *** Stereo Processing ****************************************** */ + /* **************************************************************** */ + /* *** This block operates at Fs = 44.1kHz */ + /* ******** */ + /* *** LPR path filter (2nd order IIR) */ + + sdf->Acc_signed = sdf->LprB0 * Lpr + 2 * (sdf->LprB1over2 * sdf->LprXz) + + sdf->LprB0 * sdf->LprXzz + 2 * (sdf->LprA1over2 * sdf->LprYz) + + sdf->LprA2 * sdf->LprYzz; + + sdf->FilteredLpr = sdf->Acc_signed >> 15; + + sdf->LprXzz = sdf->LprXz; /* update taps */ + sdf->LprXz = Lpr; + sdf->LprYzz = sdf->LprYz; + sdf->LprYz = sdf->FilteredLpr; + + /* *** LMR path filter (2nd order IIR) */ + sdf->Acc_signed = sdf->LmrB0 * Lmr + 2 * (sdf->LmrB1over2 * sdf->LmrXz) + + sdf->LmrB0 * sdf->LmrXzz + 2 * (sdf->LmrA1over2 * sdf->LmrYz) + + sdf->LmrA2 * sdf->LmrYzz; + + sdf->FilteredLmr = sdf->Acc_signed >> 15; + + sdf->LmrXzz = sdf->LmrXz; /* update taps */ + sdf->LmrXz = Lmr; + sdf->LmrYzz = sdf->LmrYz; + sdf->LmrYz = sdf->FilteredLmr; + + /* *** Stereo Matrix */ + if (0 == sdf->pCoefBypassBlend) + temp1_reg = sdf->LmrGa * sdf->FilteredLmr >> 15; /* Blend */ + else + temp1_reg = sdf->FilteredLmr; + + if (sdf->pCoefForcedMono) /* Forced Mono */ + temp1_reg = 0; + + if (0 == sdf->pCoefBypassSoftmute) { + temp2_reg = sdf->LprGa * sdf->FilteredLpr >> 15; /* LPR */ + temp3_reg = sdf->LprGa * temp1_reg >> 15; /* LMR */ + } else { + temp2_reg = sdf->FilteredLpr; + temp3_reg = temp1_reg; + } + + temp4_reg = (temp2_reg + temp3_reg) / 2; /* Matrix */ + +#ifndef _TUNER_STFM_MUTE + temp5_reg = (temp2_reg - temp3_reg) / 2; +#endif + +#if 0 + /* *** DC Cut Filter (leaky bucket estimate) */ + if (0 == sdf->pCoefBypassDcCut) { + sdf->LeftLb_i32 = + sdf->LeftLb_i32 + temp4_reg - (sdf->LeftLb_i32 >> 8); + temp2_reg = temp4_reg - (sdf->LeftLb_i32 >> 8); /* signal - + dc_estimate */ + + sdf->RightLb_i32 = + sdf->RightLb_i32 + temp5_reg - (sdf->RightLb_i32 >> 8); + temp3_reg = temp5_reg - (sdf->RightLb_i32 >> 8); /* signal - + dc_estimate */ + } else { + temp2_reg = temp4_reg; + temp3_reg = temp5_reg; + } +#endif +#ifdef _TUNER_STFM_MUTE + /* *** Mute Audio */ + if (sdf->MuteAudio != sdf->PrevMuteAudio) /* Mute transition */ + sdf->MuteActionFlag = 1; /* set flag */ + sdf->PrevMuteAudio = sdf->MuteAudio; /* update history */ + + if (sdf->MuteActionFlag) { + if (0 == sdf->MuteAudio) { /* Mute to zero */ + /* gradual mute down */ + sdf->ScaleAudio = sdf->ScaleAudio - sdf->pCoefMuteStep; + + /* eI-117:Oct28:as per C++ code */ + /* if (0 < sdf->ScaleAudio) */ + if (0 > sdf->ScaleAudio) { + sdf->ScaleAudio = 0; /* Minimum scale + * factor */ + sdf->MuteActionFlag = 0; /* End Mute Action */ + } + } else { /* Un-Mute to one */ + /* gradual mute up */ + sdf->ScaleAudio = sdf->ScaleAudio + sdf->pCoefMuteStep; + if (0 > sdf->ScaleAudio) { /* look for rollover + * beyong 32767 */ + sdf->ScaleAudio = 32767; /* Maximum scale + * factor */ + sdf->MuteActionFlag = 0; /* End Mute Action */ + } + } /* end else */ + } /* end if (sdf->MuteActionFlag) */ + +/*! Output Processed Sample */ + + sdf->Left = (temp2_reg * sdf->ScaleAudio) >> 15; /* Scale */ + sdf->Right = (temp3_reg * sdf->ScaleAudio) >> 15; /* Scale */ + +#else /* !_TUNER_STFM_MUTE */ + + sdf->Left = temp4_reg; + sdf->Right = temp5_reg; + +#endif /* !_TUNER_STFM_MUTE */ + + /* *** End Stereo Processing ************************************** */ + /* **************************************************************** */ + + /* **************************************************************** */ + /* *** Signal Quality Indicators ********************************** */ + /* **************************************************************** */ + /* *** This block operates at Fs = 44.1kHz */ + /* ******** */ + /* *** RSSI */ + /* ******** */ + /* Decode Floating Point RSSI data */ + /*! Input RSSI sample */ + sdf->RssiMant = (Rssi & 0xFFE0) >> 5; /* 11 msb's */ + sdf->RssiExp = Rssi & 0x001F; /* 5 lsb's */ + sdf->RssiDecoded = sdf->RssiMant << sdf->RssiExp; + + /* *** Convert RSSI to 10*Log10(RSSI) */ + /* This is easily accomplished in DSP code using the CLZ instruction */ + /* rather than using all these comparisons. */ + /* The basic idea is this: */ + /* if x >= 2^P */ + /* f(x) = 3*x>>P + (3*P-3) */ + /* Approx. is valid over the range of sdf->RssiDecoded in [0, 2^21] */ + /* *** */ + if (sdf->RssiDecoded >= 1048576) + sdf->Prssi = 20; + else if (sdf->RssiDecoded >= 524288) + sdf->Prssi = 19; + else if (sdf->RssiDecoded >= 262144) + sdf->Prssi = 18; + else if (sdf->RssiDecoded >= 131072) + sdf->Prssi = 17; + else if (sdf->RssiDecoded >= 65536) + sdf->Prssi = 16; + else if (sdf->RssiDecoded >= 32768) + sdf->Prssi = 15; + else if (sdf->RssiDecoded >= 16384) + sdf->Prssi = 14; + else if (sdf->RssiDecoded >= 8192) + sdf->Prssi = 13; + else if (sdf->RssiDecoded >= 4096) + sdf->Prssi = 12; + else if (sdf->RssiDecoded >= 2048) + sdf->Prssi = 11; + else if (sdf->RssiDecoded >= 1024) + sdf->Prssi = 10; + else if (sdf->RssiDecoded >= 512) + sdf->Prssi = 9; + else if (sdf->RssiDecoded >= 256) + sdf->Prssi = 8; + else if (sdf->RssiDecoded >= 128) + sdf->Prssi = 7; + else if (sdf->RssiDecoded >= 64) + sdf->Prssi = 6; + else if (sdf->RssiDecoded >= 32) + sdf->Prssi = 5; + else if (sdf->RssiDecoded >= 16) + sdf->Prssi = 4; + else if (sdf->RssiDecoded >= 8) + sdf->Prssi = 3; + else if (sdf->RssiDecoded >= 4) + sdf->Prssi = 2; + else if (sdf->RssiDecoded >= 2) + sdf->Prssi = 1; + else + sdf->Prssi = 0; + sdf->RssiLog = + (3 * sdf->RssiDecoded >> sdf->Prssi) + (3 * sdf->Prssi - 3); + + if (0 > sdf->RssiLog) /* Clamp to positive */ + sdf->RssiLog = 0; + + /* Compensate for errors in truncation/approximation by adding 1 */ + sdf->RssiLog = sdf->RssiLog + 1; + + /* Leaky Bucket Filter DC estimate of RSSI */ + sdf->RssiLb = sdf->RssiLb + sdf->RssiLog - (sdf->RssiLb >> 3); + sdf->TrueRssi = sdf->RssiLb >> 3; + + /* Scale up so we have some room for precision */ + sdf->ScaledTrueRssi = sdf->TrueRssi << 8; + /* ************ */ + /* *** end RSSI */ + /* ************ */ + + /* ******** */ + /* *** Echo */ + /* ******** */ + /* *** Isolate Echo information as higher frequency info */ + /* using [1 -2 1] highpass FIR */ + sdf->ScaledRssiDecoded = sdf->RssiDecoded >> 4; + sdf->Echo = + (s16) ((sdf->ScaledRssiDecoded - + 2 * sdf->ScaledRssiDecodedZ + sdf->ScaledRssiDecodedZz)); + sdf->ScaledRssiDecodedZz = sdf->ScaledRssiDecodedZ; + sdf->ScaledRssiDecodedZ = sdf->ScaledRssiDecoded; + /* ************ */ + /* *** end Echo */ + /* ************ */ + /* *** End Signal Quality Indicators ******************************* */ + /* ***************************************************************** */ + + /* ***************************************************************** */ + /* *** Weak Signal Processing ************************************** */ + /* ***************************************************************** */ + /* *** This block operates at Fs = 44.1/16 = 2.75 Khz + * *eI 108 28th Feb 06 WSP and SM executes at 2.75Khz */ + /* decimate by 16 STFM_FILTER_BLOCK_MULTIPLE is 16 */ + if (0 == sdf->DecRssi) { + /* *** Filter RSSI via attack/decay structure */ + if (sdf->ScaledTrueRssi > sdf->PrevFilteredRssi) + sdf->Acc = + sdf->pCoefRssiAttack * + sdf->PrevFilteredRssi + (65535 - + sdf->pCoefRssiAttack) + * sdf->ScaledTrueRssi; + else + sdf->Acc = + sdf->pCoefRssiDecay * + sdf->PrevFilteredRssi + (65535 - + sdf->pCoefRssiDecay) + * sdf->ScaledTrueRssi; + + sdf->FilteredRssi = sdf->Acc >> 16; + sdf->PrevFilteredRssi = sdf->FilteredRssi; + + /* *** Form Echo "energy" representation */ + if (0 > sdf->Echo) + sdf->Echo = -sdf->Echo; /* ABS() */ + + /* Threshold compare */ + sdf->GatedEcho = (s16) (sdf->Echo - sdf->pCoefEchoTh); + if (0 > sdf->GatedEcho) /* Clamp to (+)ve */ + sdf->GatedEcho = 0; + + /* *** Leaky bucket DC estimate of Echo energy */ + sdf->EchoLb = sdf->EchoLb + sdf->GatedEcho - + (sdf->EchoLb >> 3); + sdf->TrueEcho = sdf->EchoLb >> 3; + + /* *** Filter Echo via attack/decay structure for LPR */ + if (sdf->TrueEcho > sdf->PrevFilteredEchoLpr) + sdf->Acc = + sdf->pCoefEchoLprAttack * + sdf->PrevFilteredEchoLpr + + (65535 - sdf->pCoefEchoLprAttack) * + sdf->TrueEcho; + else + sdf->Acc = + sdf->pCoefEchoLprDecay * + sdf->PrevFilteredEchoLpr + + (65535 - sdf->pCoefEchoLprDecay) * + sdf->TrueEcho; + + sdf->FilteredEchoLpr = sdf->Acc >> 16; + sdf->PrevFilteredEchoLpr = sdf->FilteredEchoLpr; + + /* *** Filter Echo via attack/decay structure for LMR */ + if (sdf->TrueEcho > sdf->PrevFilteredEchoLmr) + sdf->Acc = sdf->pCoefEchoLmrAttack * + sdf->PrevFilteredEchoLmr + + (65535 - sdf->pCoefEchoLmrAttack) + * sdf->TrueEcho; + else + sdf->Acc = + sdf->pCoefEchoLmrDecay * + sdf->PrevFilteredEchoLmr + (65535 - + sdf->pCoefEchoLmrDecay) + * sdf->TrueEcho; + + sdf->FilteredEchoLmr = sdf->Acc >> 16; + sdf->PrevFilteredEchoLmr = sdf->FilteredEchoLmr; + + /* *** Form control variables */ + /* Generically speaking, ctl = f(RSSI, Echo) = + * RSSI - (a*Echo)<<b, where a,b are programmable */ + sdf->ControlLpr = sdf->FilteredRssi - + ((sdf->pCoefEchoScLpr * + sdf->FilteredEchoLpr << sdf->pCoefEchoShLpr) >> 15); + if (0 > sdf->ControlLpr) + sdf->ControlLpr = 0; /* Clamp to positive */ + + sdf->ControlLmr = sdf->FilteredRssi - + ((sdf->pCoefEchoScLmr * + sdf->FilteredEchoLmr << sdf->pCoefEchoShLmr) >> 15); + if (0 > sdf->ControlLmr) + sdf->ControlLmr = 0; /* Clamp to positive */ + + /* *** Define LPR_BW = f(control LPR) */ + /* Assume that 5 kHz and 17 kHz are limits of LPR_BW control */ + if (sdf->ControlLpr <= sdf->pCoefLprBwThLo) + sdf->LprBw = 5000; /* lower limit is 5 kHz */ + else if (sdf->ControlLpr >= sdf->pCoefLprBwThHi) + sdf->LprBw = 17000; /* upper limit is 17 kHz */ + else + sdf->LprBw = 17000 - + ((sdf->pCoefLprBwSlSc * + (sdf->pCoefLprBwThHi - + sdf->ControlLpr)) >> sdf->pCoefLprBwSlSh); + + /* *** Define LMR_BW = f(control LMR) */ + /* Assume that 5 kHz and 17 kHz are limits of LPR_BW control */ + if (0 == sdf->pCoefForceLockLmrBw) { /* only do these calc's + * if LMR BW not + * ForceLocked */ + if (sdf->ControlLmr <= sdf->pCoefLmrBwThLo) + sdf->LmrBw = 5000; /* lower limit is + * 5 kHz */ + else if (sdf->ControlLmr >= sdf->pCoefLmrBwThHi) + sdf->LmrBw = 17000; /* upper limit is + * 17 kHz */ + else + sdf->LmrBw = 17000 - + ((sdf->pCoefLmrBwSlSc * + (sdf->pCoefLmrBwThHi - + sdf->ControlLmr)) >> + sdf->pCoefLmrBwSlSh); + } + /* *** Define LMR_Gain = f(control LMR) + * Assume that Blending occurs across 20 dB range of + * control LMR. For sake of listenability, approximate + * antilog blending curve + * To simplify antilog approx, scale control LMR back into + * "RSSI in dB range" [0,60] */ + sdf->ScaledControlLmr = sdf->ControlLmr >> 8; + + /* how far below blend threshold are we? */ + temp1_reg = sdf->pCoefLmrGaTh - sdf->ScaledControlLmr; + if (0 > temp1_reg) /* We're not below threshold, + * so no blending needed */ + temp1_reg = 0; + temp2_reg = 20 - temp1_reg; /* Blend range = 20 dB */ + if (0 > temp2_reg) + temp2_reg = 0; /* if beyond that range, + * then clamp to 0 */ + + /* We want stereo separation (n dB) to rolloff linearly over + * the 20 dB wide blend region. + * this necessitates a particular rolloff for the blend + * parameter, which is not obvious. + * See sw_audio/log_approx.m for calculation of this rolloff, + * implemented below... + * Note that stereo_separation (in dB) = 20*log10((1+a)/(1-a)), + * where a = blend scaler + * appropriately scaled for 2^15. This relationship sits at + * the heart of why this curve is needed. */ + if (15 <= temp2_reg) + temp3_reg = 264 * temp2_reg + 27487; + else if (10 <= temp2_reg) + temp3_reg = 650 * temp2_reg + 21692; + else if (5 <= temp2_reg) + temp3_reg = 1903 * temp2_reg + 9166; + else + temp3_reg = 3736 * temp2_reg; + + sdf->LmrGa = temp3_reg; + + if (32767 < sdf->LmrGa) + sdf->LmrGa = 32767; /* Clamp to '1' */ + + /* *** Define LPR_Gain = f(control LPR) + * Assume that SoftMuting occurs across 20 dB range of + * control LPR + * For sake of listenability, approximate antilog softmute + * curve To simplify antilog approx, scale control LPR back + * into "RSSI in dB range" [0,60] */ + sdf->ScaledControlLpr = sdf->ControlLpr >> 8; + /* how far below softmute threshold are we? */ + temp1_reg = sdf->pCoefLprGaTh - sdf->ScaledControlLpr; + if (0 > temp1_reg) /* We're not below threshold, + * so no softmute needed */ + temp1_reg = 0; + temp2_reg = 20 - temp1_reg; /* SoftmMute range = 20 dB */ + if (0 > temp2_reg) + temp2_reg = 0; /* if beyond that range, + * then clamp to 0 */ + /* Form 100*10^((temp2_reg-20)/20) approximation (antilog) + * over range [0,20] dB + * approximation in range [0,100], but we only want to + * softmute down to -20 dB, no further */ + if (16 < temp2_reg) + temp3_reg = 9 * temp2_reg - 80; + else if (12 < temp2_reg) + temp3_reg = 6 * temp2_reg - 33; + else if (8 < temp2_reg) + temp3_reg = 4 * temp2_reg - 8; + else + temp3_reg = 2 * temp2_reg + 9; + + sdf->LprGa = 328 * temp3_reg; /* close to 32767*(1/100) */ + + if (32767 < sdf->LprGa) + sdf->LprGa = 32767; /* Clamp to '1' */ + + if (3277 > sdf->LprGa) + sdf->LprGa = 3277; /* Clamp to 0.1*32767 = + * -20 dB min gain */ + + /* *************** Bandwidth Sweep Algorithm ************ */ + /* *** Calculate 2nd order filter coefficients as function + * of desired BW. We do this by constructing piece-wise + * linear filter coef's as f(BW), which is why we break the + * calc's into different BW regions below. + * coef(BW) = S*(M*BW + B) + * For more info, see sw_audio/ws_filter.m checked into CVS */ + if (0 == sdf->pCoefBypassBwCtl) { /* if ==1, then we just go + * with default coef set */ + /* determine if we run thru loop once or twice... */ + if (1 == sdf->pCoefForceLockLmrBw) + temp4_reg = 1; /* run thru once only to calc. + * LPR coef's */ + else + temp4_reg = 2; /* run thru twice to calc. + * LPR and LMR coef's */ + + /* Here's the big coef. calc. loop */ + for (temp1_reg = 0; temp1_reg < temp4_reg; + temp1_reg++) { + + if (0 == temp1_reg) + temp2_reg = (s16) sdf->LprBw; + else + temp2_reg = (s16) sdf->LmrBw; + + + if (6000 > temp2_reg) { + /* interval = [4.4kHz, 6.0kHz) */ + sdf->B0M = 22102; + sdf->B0B = -2209; + sdf->B0S = 1; + + sdf->B1over2M = 22089; + sdf->B1over2B = -2205; + sdf->B1over2S = 1; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = -24664; + sdf->A2B = 11698; + sdf->A2S = 2; + } else if (8000 > temp2_reg) { + /* interval = [6.0kHz, 8.0kHz) */ + sdf->B0M = 22102; + sdf->B0B = -2209; + sdf->B0S = 1; + + sdf->B1over2M = 22089; + sdf->B1over2B = -2205; + sdf->B1over2S = 1; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = -31231; + sdf->A2B = 18468; + sdf->A2S = 1; + } else if (10000 > temp2_reg) { + /* interval = [8.0kHz, 10.0kHz) */ + sdf->B0M = 28433; + sdf->B0B = -4506; + sdf->B0S = 1; + + sdf->B1over2M = 28462; + sdf->B1over2B = -4584; + sdf->B1over2S = 1; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = -14811; + sdf->A2B = 12511; + sdf->A2S = 1; + } else if (12000 > temp2_reg) { + /* interval = [10.0kHz, 12.0kHz) */ + sdf->B0M = 28433; + sdf->B0B = -4506; + sdf->B0S = 1; + + sdf->B1over2M = 28462; + sdf->B1over2B = -4584; + sdf->B1over2S = 1; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = -181; + sdf->A2B = 5875; + sdf->A2S = 1; + } else if (14000 > temp2_reg) { + /* interval = [12.0kHz, 14.0kHz) */ + sdf->B0M = 18291; + sdf->B0B = -4470; + sdf->B0S = 2; + + sdf->B1over2M = 18461; + sdf->B1over2B = -4597; + sdf->B1over2S = 2; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = 14379; + sdf->A2B = -2068; + sdf->A2S = 1; + } else if (16000 > temp2_reg) { + /* interval = [14.0kHz, 16.0kHz) */ + sdf->B0M = 18291; + sdf->B0B = -4470; + sdf->B0S = 2; + + sdf->B1over2M = 18461; + sdf->B1over2B = -4597; + sdf->B1over2S = 2; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = 30815; + sdf->A2B = -12481; + sdf->A2S = 1; + } else if (18000 > temp2_reg) { + /* interval = [16.0kHz, 18.0kHz) */ + sdf->B0M = 24740; + sdf->B0B = -9152; + sdf->B0S = 2; + + sdf->B1over2M = 24730; + sdf->B1over2B = -9142; + sdf->B1over2S = 2; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = 25631; + sdf->A2B = -13661; + sdf->A2S = 2; + } else { + /* interval = [18.0kHz, 19.845kHz) */ + sdf->B0M = 24740; + sdf->B0B = -9152; + sdf->B0S = 2; + + sdf->B1over2M = 24730; + sdf->B1over2B = -9142; + sdf->B1over2S = 2; + + sdf->A1over2M = 31646; + sdf->A1over2B = -15695; + sdf->A1over2S = 2; + + sdf->A2M = 19382; + sdf->A2B = -12183; + sdf->A2S = 4; + } + + if (0 == temp1_reg) { + /* The piece-wise linear eq's are + * based on a scaled version + * (32768/22050) of BW */ + + /* Note 32768/22050 <-> 2*(16384/22050) + * <-> 2*((16384/22050)*32768)>>15 */ + sdf->AdjBw = ((temp2_reg << 1) * + 24348) >> 15; + + /* temp = mx */ + temp3_reg = (sdf->B0M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LprB0 = sdf->B0S * + (temp3_reg + sdf->B0B); + + /* temp = mx */ + temp3_reg = (sdf->B1over2M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LprB1over2 = sdf->B1over2S * + (temp3_reg + sdf->B1over2B); + + /* temp = mx */ + temp3_reg = (sdf->A1over2M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LprA1over2 = -sdf->A1over2S * + (temp3_reg + sdf->A1over2B); + + /* temp = mx */ + temp3_reg = (sdf->A2M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LprA2 = -sdf->A2S * + (temp3_reg + sdf->A2B); + /* *** end LPR channel -- + * LPR coefficients now ready for + * Stereo Path next time */ + } else { + /* The piece-wise linear eq's are + * based on a scaled version + * (32768/22050) of BW */ + + /* Note 32768/22050 <-> 2*(16384/22050) + * <-> 2*((16384/22050)*32768)>>15 */ + sdf->AdjBw = ((temp2_reg << 1) * + 24348) >> 15; + + /* temp = mx */ + temp3_reg = (sdf->B0M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LmrB0 = sdf->B0S * + (temp3_reg + sdf->B0B); + + /* temp = mx */ + temp3_reg = (sdf->B1over2M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LmrB1over2 = sdf->B1over2S * + (temp3_reg + sdf->B1over2B); + + /* temp = mx */ + temp3_reg = (sdf->A1over2M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LmrA1over2 = -sdf->A1over2S * + (temp3_reg + sdf->A1over2B); + + /* temp = mx */ + temp3_reg = (sdf->A2M * + sdf->AdjBw) >> 15; + + /* y = S*(mx + b) */ + sdf->LmrA2 = -sdf->A2S * + (temp3_reg + sdf->A2B); + /* *** end LMR channel -- LMR + * coefficients now ready for Stereo + * Path next time */ + } + } /* end for (temp1_reg=0... */ + if (1 == sdf->pCoefForceLockLmrBw) { + /* if Force Lock LMR BW = LPR BW */ + /* then set LMR coef's = LPR coef's */ + sdf->LmrB0 = sdf->LprB0; + sdf->LmrB1over2 = sdf->LprB1over2; + sdf->LmrA1over2 = sdf->LprA1over2; + sdf->LmrA2 = sdf->LprA2; + } + + } /* end if (0 == sdf->pCoef_BypassBwCtl) */ + /* eI 108 24th Feb 06 Streo Matrix part moved after + * weak signal processing. */ + if (0 == sdf->pCoefBypassBlend) + temp1_reg = sdf->LmrGa; /* Blend */ + else + temp1_reg = 1; + + if (sdf->pCoefForcedMono) /* Forced Mono */ + temp1_reg = 0; + + if (0 == sdf->pCoefBypassSoftmute) { + + /* SoftMute applied to LPR */ + sdf->temp2_reg_sm = sdf->LprGa; + + temp2_reg_32 = sdf->LprGa * temp1_reg; + + /* SoftMute applied to LMR */ + sdf->temp3_reg_sm = (temp2_reg_32) >> 15; + } else { + sdf->temp2_reg_sm = 1; /* eI 108 24th Feb 06 update + * global variable for IIR + * filter. */ + sdf->temp3_reg_sm = temp1_reg; + } + + } /* end if (0 == sdf->DecRssi) */ + + sdf->DecRssi = ((sdf->DecRssi + 1) % 16); /* end decimation + * by 16 */ + + /* *** End Weak Signal Processing ********************************** */ + /* ***************************************************************** */ +} diff --git a/drivers/media/radio/stfm1000/stfm1000-filter.h b/drivers/media/radio/stfm1000/stfm1000-filter.h new file mode 100644 index 000000000000..d24e3e9244b8 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-filter.h @@ -0,0 +1,185 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef STFM1000_FILTER_H +#define STFM1000_FILTER_H + +/* STFM1000 Black Box Filter parameters */ +struct stfm1000_filter_parms { + s16 LprXzz; /* LPR x(n-2) stereo filter */ + s16 LmrXzz; /* LMR x(n-2) stereo filter */ + s16 LprYzz; /* LPR y(n-2) stereo filter */ + s16 LmrYzz; /* LMR y(n-2) stereo filter */ + + s16 LprXz; /* LPR x(n-1) stereo filter */ + s16 LmrXz; /* LMR x(n-1) stereo filter */ + s16 FilteredLpr; /* LPR filter output */ + s16 FilteredLmr; /* LMR filter output */ + + s16 LprB0; /* LPR stereo filter coef */ + s16 LprB1over2; /* LPR stereo filter coef */ + s16 LprA1over2; /* LPR stereo filter coef */ + s16 LprA2; /* LPR stereo filter coef */ + + s16 LmrB0; /* LMR stereo filter coef */ + s16 LmrB1over2; /* LMR stereo filter coef */ + s16 LmrA1over2; /* LMR stereo filter coef */ + s16 LmrA2; /* LMR stereo filter coef */ + + s16 LprYz; /* LPR y(n-1) stereo filter */ + s16 LmrYz; /* LMR y(n-1) stereo filter */ + + s16 Left; /* left channel audio out */ + s16 Right; /* right channel audio out */ + s32 LeftLb; /* left channel dc estimate */ + s32 RightLb; /* right channel dc estimate */ + + u32 RssiDecoded; /* integer decoded RSSI */ + + u16 RssiMant; /* mantissa of float-coded RSSI */ + s16 RssiLog; /* 10log10(decoded RSSI) */ + + u16 RssiExp; /* exponent of float-coded RSSI */ + u16 RssiLb; /* leaky bucket dc of rssi */ + + u16 Prssi; /* power of 2 for RSSI */ + u16 TrueRssi; /* DC estimate of log RSSI */ + + u16 ScaledRssiDecoded; /* scaled log RSSI */ + s16 Echo; /* Echo info from HiPass(RSSI) */ + u16 ScaledRssiDecodedZ; /* history buffer for above */ + u16 ScaledRssiDecodedZz;/* ditto */ + + u16 ScaledTrueRssi; /* scaled version for precision */ + u16 FilteredRssi; /* Attack/Decay filtered RSSI */ + u16 PrevFilteredRssi; /* previous version of above */ + + u16 EchoLb; /* DC estimate of Echo energy */ + u16 TrueEcho; /* scaled version of above */ + u16 FilteredEchoLpr; /* Attack/Decay filt. Echo */ + u16 PrevFilteredEchoLpr;/* previous version of above */ + u16 FilteredEchoLmr; /* Attack/Decay filt. Echo */ + u16 PrevFilteredEchoLmr;/* previous version of above */ + s16 GatedEcho; /* Echo gated by threshold */ + + s16 ControlLpr; /* master control for LPR */ + s16 ControlLmr; /* master control for LMR */ + u16 LprBw; /* LPR Bandwidth desired */ + u16 LmrBw; /* LMR Bandwidth desired */ + u16 LprGa; /* LPR Gain (SoftMute) desired */ + u16 LmrGa; /* LMR Gain (Blend) desired */ + u16 ScaledControlLmr; /* Scaled down version Ctl LMR */ + u16 ScaledControlLpr; /* Scaled down version Ctl LPR */ + + s16 B0M; /* BW ctl B0 coef slope */ + s16 B0B; /* BW ctl B0 coef y-intercept */ + + u16 B0S; /* BW ctl B0 coef scale */ + s16 B1over2M; /* BW ctl B1/2 coef slope */ + + s16 B1over2B; /* BW ctl B1/2 coef y-intercept */ + s16 A1over2B; /* BW ctl A1/2 coef y-intercept */ + + u16 B1over2S; /* BW ctl B1/2 coef scale */ + u16 A1over2S; /* BW ctl A1/2 coef scale */ + + s16 A1over2M; /* BW ctl A1/2 coef slope */ + u16 A2S; /* BW ctl A2 coef scale */ + + s16 A2M; /* BW ctl A2 coef slope */ + s16 A2B; /* BW ctl A2 coef y-intercept */ + + u16 AdjBw; /* Desired Filter BW scaled into range */ + + u16 DecRssi; /*! Decimation modulo counter */ + + s16 ScaleAudio; /*! Scale factor for Audio Mute */ + u8 MuteAudio; /*! Control for muting audio */ + u8 PrevMuteAudio; /*! History of control for muting audio */ + u8 MuteActionFlag; /*! Indicator of when mute ramping occurs */ + + u32 Acc; /* mimics H/W accumulator */ + s32 Acc_signed; + s16 temp1_reg; /* mimics 16 bit register */ + s16 temp2_reg; /* mimics 16 bit register */ + s16 temp3_reg; /* mimics 16 bit register */ + s16 temp4_reg; /* mimics 16 bit register */ + s16 temp5_reg; /* mimics 16 bit register */ + + /* *** Programmable Coefficients */ + u16 pCoefRssiAttack; /* prog coef RSSI attack */ + u16 pCoefRssiDecay; /* prog coef RSSI decay */ + u16 pCoefEchoLprAttack; /* prog coef Echo LPR attack */ + u16 pCoefEchoLprDecay; /* prog coef Echo LPR decay */ + u16 pCoefEchoLmrAttack; /* prog coef Echo LMR attack */ + u16 pCoefEchoLmrDecay; /* prog coef Echo LMR decay */ + + u16 pCoefEchoTh; /* prog coef Echo threshold */ + + u16 pCoefEchoScLpr; /* prog coef scale Echo LPR infl. */ + u16 pCoefEchoScLmr; /* prog coef scale Echo LMR infl. */ + u16 pCoefEchoShLpr; /* prog coef shift Echo LPR infl. */ + u16 pCoefEchoShLmr; /* prog coef shift Echo LMR infl. */ + + u16 pCoefLprBwThLo; /* prog coef Low Th LPR BW */ + u16 pCoefLprBwThHi; /* prog coef High Th LPR BW */ + u16 pCoefLmrBwThLo; /* prog coef Low Th LMR BW */ + u16 pCoefLmrBwThHi; /* prog coef High Th LMR BW */ + + u16 pCoefLprGaTh; /* prog coef Th LPR Gain (SoftMute) */ + u16 pCoefLmrGaTh; /* prog coef Th LMR Gain (Blend) */ + + u16 pCoefLprBwSlSc; /* prog coef Slope scale LPR BW */ + u16 pCoefLprBwSlSh; /* prog coef Slope shift LPR BW */ + u16 pCoefLmrBwSlSc; /* prog coef Slope scale LMR BW */ + u16 pCoefLmrBwSlSh; /* prog coef Slope shift LMR BW */ + u16 pCoefLprGaSlSc; /* prog coef Slope scale LPR Gain */ + u16 pCoefLprGaSlSh; /* prog coef Slope shift LPR Gain */ + + u8 pCoefForcedMono; /* Forced Mono control bit */ + u8 pCoefBypassBlend; /* Forced bypass of stereo blend */ + u8 pCoefBypassSoftmute; /* Forced bypass of softmute */ + u8 pCoefBypassDcCut; /* Forced bypass of audio DC Cut filter */ + + u8 pCoefBypassBwCtl; /* Forced bypass of bandwidth control */ + u8 pCoefForceLockLmrBw; /* prog flag to force LMR BW=LPR BW */ + + /* XXX added here, they were global */ + s16 temp2_reg_sm; + s16 temp3_reg_sm; + +}; + +/* STFM1000 Black Box Filter Function prototypes */ +void stfm1000_filter_reset(struct stfm1000_filter_parms *sdf); +void stfm1000_filter_decode(struct stfm1000_filter_parms *sdf, s16 Lpr, + s16 Lmr, u16 Rssi); + +static inline s16 +stfm1000_filter_value_left(struct stfm1000_filter_parms *sdf) +{ + return sdf->Left; +} + +static inline s16 +stfm1000_filter_value_right(struct stfm1000_filter_parms *sdf) +{ + return sdf->Right; +} + +static inline u32 +stfm1000_filter_value_rssi(struct stfm1000_filter_parms *sdf) +{ + return sdf->RssiDecoded; +} + +#endif diff --git a/drivers/media/radio/stfm1000/stfm1000-i2c.c b/drivers/media/radio/stfm1000/stfm1000-i2c.c new file mode 100644 index 000000000000..50a047ecfda6 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-i2c.c @@ -0,0 +1,453 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/io.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/i2c.h> +#include <linux/delay.h> + +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ + +#include "stfm1000.h" + +#define stfm1000_i2c_debug(p, fmt, arg...) \ + do { \ + if ((p)->dbgflg & STFM1000_DBGFLG_I2C) \ + printk(KERN_INFO "stfm1000: " fmt, ##arg); \ + } while (0) + +static const char *reg_names[STFM1000_NUM_REGS] = { +#undef REGNAME +#define REGNAME(x) \ + [STFM1000_ ## x / 4] = #x "" + + REGNAME(TUNE1), + REGNAME(SDNOMINAL), + REGNAME(PILOTTRACKING), + REGNAME(INITIALIZATION1), + REGNAME(INITIALIZATION2), + REGNAME(INITIALIZATION3), + REGNAME(INITIALIZATION4), + REGNAME(INITIALIZATION5), + REGNAME(INITIALIZATION6), + REGNAME(REF), + REGNAME(LNA), + REGNAME(MIXFILT), + REGNAME(CLK1), + REGNAME(CLK2), + REGNAME(ADC), + REGNAME(AGC_CONTROL1), + REGNAME(AGC_CONTROL2), + REGNAME(DATAPATH), + REGNAME(RMS), + REGNAME(AGC_STAT), + REGNAME(SIGNALQUALITY), + REGNAME(DCEST), + REGNAME(RSSI_TONE), + REGNAME(PILOTCORRECTION), + REGNAME(ATTENTION), + REGNAME(CLK3), + REGNAME(CHIPID), +#undef REGNAME +}; + +static const int stfm1000_rw_regs[] = { + STFM1000_TUNE1, + STFM1000_SDNOMINAL, + STFM1000_PILOTTRACKING, + STFM1000_INITIALIZATION1, + STFM1000_INITIALIZATION2, + STFM1000_INITIALIZATION3, + STFM1000_INITIALIZATION4, + STFM1000_INITIALIZATION5, + STFM1000_INITIALIZATION6, + STFM1000_REF, + STFM1000_LNA, + STFM1000_MIXFILT, + STFM1000_CLK1, + STFM1000_CLK2, + STFM1000_ADC, + STFM1000_AGC_CONTROL1, + STFM1000_AGC_CONTROL2, + STFM1000_DATAPATH, + STFM1000_ATTENTION, /* it's both WR/RD */ +}; + +static const int stfm1000_ra_regs[] = { + STFM1000_RMS, + STFM1000_AGC_STAT, + STFM1000_SIGNALQUALITY, + STFM1000_DCEST, + STFM1000_RSSI_TONE, + STFM1000_PILOTCORRECTION, + STFM1000_ATTENTION, /* it's both WR/RD - always read */ + STFM1000_CLK3, + STFM1000_CHIPID +}; + +static int verify_writes; + +void stfm1000_setup_reg_set(struct stfm1000 *stfm1000) +{ + int i, reg; + + /* set up register sets (read/write) */ + for (i = 0; i < ARRAY_SIZE(stfm1000_rw_regs); i++) { + reg = stfm1000_rw_regs[i] / 4; + stfm1000->reg_rw_set[reg / 32] |= 1U << (reg & 31); + /* printk(KERN_INFO "STFM1000: rw <= %d\n", reg); */ + } + + /* for (i = 0; i < ARRAY_SIZE(stfm1000->reg_rw_set); i++) + printk("RW[%d] = 0x%08x\n", i, stfm1000->reg_rw_set[i]); */ + + /* set up register sets (read only) */ + for (i = 0; i < ARRAY_SIZE(stfm1000_ra_regs); i++) { + reg = stfm1000_ra_regs[i] / 4; + stfm1000->reg_ra_set[reg / 32] |= 1U << (reg & 31); + /* printk(KERN_INFO "STFM1000: rw <= %d\n", reg); */ + } + /* for (i = 0; i < ARRAY_SIZE(stfm1000->reg_ra_set); i++) + printk("RO[%d] = 0x%08x\n", i, stfm1000->reg_ra_set[i]); */ + + /* clear dirty */ + memset(stfm1000->reg_dirty_set, 0, sizeof(stfm1000->reg_dirty_set)); +} + +static int stfm1000_reg_is_rw(struct stfm1000 *stfm1000, int reg) +{ + reg >>= 2; + return !!(stfm1000->reg_rw_set[reg / 32] & (1 << (reg & 31))); +} + +static int stfm1000_reg_is_ra(struct stfm1000 *stfm1000, int reg) +{ + reg >>= 2; + return !!(stfm1000->reg_ra_set[reg / 32] & (1 << (reg & 31))); +} + +static int stfm1000_reg_is_dirty(struct stfm1000 *stfm1000, int reg) +{ + reg >>= 2; + return !!(stfm1000->reg_dirty_set[reg / 32] & (1 << (reg & 31))); +} + +static void stfm1000_reg_set_dirty(struct stfm1000 *stfm1000, int reg) +{ + reg >>= 2; + stfm1000->reg_dirty_set[reg / 32] |= 1 << (reg & 31); +} + +static inline int stfm1000_reg_is_writeable(struct stfm1000 *stfm1000, int reg) +{ + return stfm1000_reg_is_rw(stfm1000, reg); +} + +static inline int stfm1000_reg_is_readable(struct stfm1000 *stfm1000, int reg) +{ + return stfm1000_reg_is_rw(stfm1000, reg) || + stfm1000_reg_is_ra(stfm1000, reg); +} + +/********************************************************/ + +static int write_reg_internal(struct stfm1000 *stfm1000, int reg, u32 value) +{ + u8 values[5]; + int ret; + + stfm1000_i2c_debug(stfm1000, "%s(%s - 0x%02x, 0x%08x)\n", __func__, + reg_names[reg / 4], reg, value); + + values[0] = (u8)reg; + values[1] = (u8)value; + values[2] = (u8)(value >> 8); + values[3] = (u8)(value >> 16); + values[4] = (u8)(value >> 24); + ret = i2c_master_send(stfm1000->client, values, 5); + if (ret < 0) + return ret; + return 0; +} + +static int read_reg_internal(struct stfm1000 *stfm1000, int reg, u32 *value) +{ + u8 regb = reg; + u8 values[4]; + int ret; + + ret = i2c_master_send(stfm1000->client, ®b, 1); + if (ret < 0) + goto out; + ret = i2c_master_recv(stfm1000->client, values, 4); + if (ret < 0) + goto out; + *value = (u32)values[0] | ((u32)values[1] << 8) | + ((u32)values[2] << 16) | ((u32)values[3] << 24); + ret = 0; + + stfm1000_i2c_debug(stfm1000, "%s(%s - 0x%02x, 0x%08x)\n", __func__, + reg_names[reg / 4], reg, *value); +out: + return ret; +} + +int stfm1000_raw_write(struct stfm1000 *stfm1000, int reg, u32 value) +{ + int ret; + + mutex_lock(&stfm1000->xfer_lock); + ret = write_reg_internal(stfm1000, reg, value); + mutex_unlock(&stfm1000->xfer_lock); + + if (ret < 0) + dev_err(&stfm1000->client->dev, "%s: failed", __func__); + + return ret; +} + +int stfm1000_raw_read(struct stfm1000 *stfm1000, int reg, u32 *value) +{ + int ret; + + mutex_lock(&stfm1000->xfer_lock); + ret = read_reg_internal(stfm1000, reg, value); + mutex_unlock(&stfm1000->xfer_lock); + + if (ret < 0) + dev_err(&stfm1000->client->dev, "%s: failed", __func__); + + return ret; +} + +static inline void stfm1000_set_shadow_reg(struct stfm1000 *stfm1000, + int reg, u32 val) +{ + stfm1000->shadow_regs[reg / 4] = val; +} + +static inline u32 stfm1000_get_shadow_reg(struct stfm1000 *stfm1000, int reg) +{ + return stfm1000->shadow_regs[reg / 4]; +} + +int stfm1000_write(struct stfm1000 *stfm1000, int reg, u32 value) +{ + int ret; + + if (!stfm1000_reg_is_writeable(stfm1000, reg)) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&stfm1000->xfer_lock); + + /* same value as last one written? */ + if (stfm1000_reg_is_dirty(stfm1000, reg) && + stfm1000_get_shadow_reg(stfm1000, reg) == value) { + ret = 0; + + stfm1000_i2c_debug(stfm1000, "%s - HIT " + "(%s - 0x%02x, 0x%08x)\n", __func__, + reg_names[reg / 4], reg, value); + + goto out_unlock; + } + + /* actually write the register */ + ret = write_reg_internal(stfm1000, reg, value); + if (ret < 0) + goto out_unlock; + + /* update shadow register & mark it as dirty */ + /* only if register is not read always */ + if (!stfm1000_reg_is_ra(stfm1000, reg)) { + stfm1000_set_shadow_reg(stfm1000, reg, value); + stfm1000_reg_set_dirty(stfm1000, reg); + } + +out_unlock: + mutex_unlock(&stfm1000->xfer_lock); + +out: + if (ret < 0) + dev_err(&stfm1000->client->dev, "%s: failed", __func__); + + if (verify_writes) { + u32 value2 = ~0; + + stfm1000_raw_read(stfm1000, reg, &value2); + + stfm1000_i2c_debug(stfm1000, "%s - VER " + "(%s - 0x%02x, W=0x%08x V=0x%08x) %s\n", __func__, + reg_names[reg / 4], reg, value, value2, + value == value2 ? "OK" : "** differs **"); + } + + return ret; +} + +int stfm1000_read(struct stfm1000 *stfm1000, int reg, u32 *value) +{ + int ret = 0; + + if (!stfm1000_reg_is_readable(stfm1000, reg)) { + ret = -EINVAL; + printk(KERN_INFO "%s: !readable(%d)\n", __func__, reg); + goto out; + } + + mutex_lock(&stfm1000->xfer_lock); + + /* if the register can be written & is dirty, use the shadow */ + if (stfm1000_reg_is_writeable(stfm1000, reg) && + stfm1000_reg_is_dirty(stfm1000, reg)) { + + *value = stfm1000_get_shadow_reg(stfm1000, reg); + ret = 0; + + stfm1000_i2c_debug(stfm1000, "%s - HIT " + "(%s - 0x%02x, 0x%08x)\n", __func__, + reg_names[reg / 4], reg, *value); + + goto out_unlock; + } + + /* register must be read */ + ret = read_reg_internal(stfm1000, reg, value); + if (ret < 0) + goto out; + + /* if the register is writeable, update shadow */ + if (stfm1000_reg_is_writeable(stfm1000, reg)) { + stfm1000_set_shadow_reg(stfm1000, reg, *value); + stfm1000_reg_set_dirty(stfm1000, reg); + } + +out_unlock: + mutex_unlock(&stfm1000->xfer_lock); + +out: + if (ret < 0) + dev_err(&stfm1000->client->dev, "%s: failed", __func__); + + return ret; +} + +int stfm1000_write_masked(struct stfm1000 *stfm1000, int reg, u32 value, + u32 mask) +{ + int ret = 0; + u32 old_value; + + if (!stfm1000_reg_is_writeable(stfm1000, reg)) { + ret = -EINVAL; + printk(KERN_ERR "%s: !writeable(%d)\n", __func__, reg); + goto out; + } + + mutex_lock(&stfm1000->xfer_lock); + + /* if the register wasn't written before, read it */ + if (!stfm1000_reg_is_dirty(stfm1000, reg)) { + ret = read_reg_internal(stfm1000, reg, &old_value); + if (ret != 0) + goto out_unlock; + } else /* register was written, use the last value */ + old_value = stfm1000_get_shadow_reg(stfm1000, reg); + + /* perform masking */ + value = (old_value & ~mask) | (value & mask); + + /* if we write the same value, don't bother */ + if (stfm1000_reg_is_dirty(stfm1000, reg) && value == old_value) { + ret = 0; + + stfm1000_i2c_debug(stfm1000, "%s - HIT " + "(%s - 0x%02x, 0x%08x)\n", __func__, + reg_names[reg / 4], reg, value); + + goto out_unlock; + } + + /* actually write the register to the chip */ + ret = write_reg_internal(stfm1000, reg, value); + if (ret < 0) + goto out_unlock; + + /* if no error, update the shadow register and mark it as dirty */ + stfm1000_set_shadow_reg(stfm1000, reg, value); + stfm1000_reg_set_dirty(stfm1000, reg); + +out_unlock: + mutex_unlock(&stfm1000->xfer_lock); + +out: + if (ret < 0) + dev_err(&stfm1000->client->dev, "%s: failed", __func__); + + if (verify_writes) { + u32 value2 = ~0; + + stfm1000_raw_read(stfm1000, reg, &value2); + + stfm1000_i2c_debug(stfm1000, "%s - VER " + "(%s - 0x%02x, W=0x%08x V=0x%08x) %s\n", __func__, + reg_names[reg / 4], reg, value, value2, + value == value2 ? "OK" : "** differs **"); + } + + return ret; +} + +int stfm1000_set_bits(struct stfm1000 *stfm1000, int reg, u32 value) +{ + return stfm1000_write_masked(stfm1000, reg, value, value); +} + +int stfm1000_clear_bits(struct stfm1000 *stfm1000, int reg, u32 value) +{ + return stfm1000_write_masked(stfm1000, reg, ~value, value); +} + +int stfm1000_write_regs(struct stfm1000 *stfm1000, + const struct stfm1000_reg *reg) +{ + int ret; + + for (; reg && reg->regno != STFM1000_REG_END; reg++) { + + if (reg->regno == STFM1000_REG_DELAY) { + msleep(reg->value); + continue; + } + + if (reg->regno & STFM1000_REG_SET_BITS_MASK) + ret = stfm1000_set_bits(stfm1000, reg->regno & 0xff, + reg->value); + else if (reg->regno & STFM1000_REG_CLEAR_BITS_MASK) + ret = stfm1000_clear_bits(stfm1000, reg->regno & 0xff, + reg->value); + else + ret = stfm1000_write(stfm1000, reg->regno, reg->value); + + if (ret != 0) { + printk(KERN_ERR "%s: failed to write reg 0x%x " + "with 0x%08x\n", + __func__, reg->regno, reg->value); + return ret; + } + } + return 0; +} + diff --git a/drivers/media/radio/stfm1000/stfm1000-rds.c b/drivers/media/radio/stfm1000/stfm1000-rds.c new file mode 100644 index 000000000000..5f63052d00c2 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-rds.c @@ -0,0 +1,1529 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> + +#include "stfm1000.h" + +#include "stfm1000-rds.h" + +#define bitstream_to_rds_state(b) \ + container_of(b, struct stfm1000_rds_state, bitstream) +#define demod_to_rds_state(d) \ + container_of(d, struct stfm1000_rds_state, demod) +#define pkt_to_rds_state(p) \ + container_of(p, struct stfm1000_rds_state, pkt) +#define text_to_rds_state(t) \ + container_of(t, struct stfm1000_rds_state, text) +#define rds_state_to_stfm1000(r) \ + container_of(r, struct stfm1000, rds_state) + +#define TADJSH 8 /*Shifts used in bitslice loop filter */ + +/* Reverse of Matlab's Fquant (see MatchedFilterDecomposition.m), so that */ +/* mixandsum code is easy; Used by rds_bitstream_stfmdemod.arm */ +const s16 u16_rds_basis[2*RDS_BASISLENGTH+8] = { + 14, 24, 34, 43, 50, 56, 60, 62, 62, + 60, 55, 49, 41, 32, 22, 11, 14, 24, + 34, 43, 50, 56, 60, 62, 62, 60, 55, + 49, 41, 32, 22, 11, 14, 24, 34, 43, + 50, 56, 60, 62 +}; + +static int bits_free(struct stfm1000_rds_bitstream *rdsb) +{ + /* Do not show the last one word free. */ + int FreeSpace = rdsb->TailBitCount - rdsb->HeadBitCount - 32; + + if (FreeSpace < 0) + FreeSpace = (RDS_BITBUFSIZE * 32) + FreeSpace; + return FreeSpace; +} + +static void put1bit(struct stfm1000_rds_bitstream *rdsb, int bit) +{ + int index = (rdsb->HeadBitCount >> 5); + u32 CurBit = (rdsb->HeadBitCount & 0x1f); + u32 CurWord = rdsb->buf[index]; + + if (CurBit == 0) + CurWord = 0; + + CurWord = CurWord | (((u32)bit & 1) << CurBit); + rdsb->buf[index] = CurWord; + rdsb->HeadBitCount++; + if (rdsb->HeadBitCount >= RDS_BITBUFSIZE * 32) + rdsb->HeadBitCount = 0; +} + +static int get1bit(struct stfm1000_rds_bitstream *rdsb) +{ + int Bit = 0; + int index = (rdsb->TailBitCount >> 5); + int CurBit = (rdsb->TailBitCount & 0x1f); + u32 CurWord = rdsb->buf[index]; + + Bit = (CurWord >> CurBit) & 1; + rdsb->TailBitCount++; + if (rdsb->TailBitCount == RDS_BITBUFSIZE*32) + rdsb->TailBitCount = 0; + + return Bit; +} + +static int bits_filled(struct stfm1000_rds_bitstream *rdsb) +{ + int FilledSpace = rdsb->HeadBitCount - rdsb->TailBitCount; + + if (FilledSpace < 0) + FilledSpace = (RDS_BITBUFSIZE * 32) + FilledSpace; + return FilledSpace; +} + +static void rds_mix_msg(struct stfm1000_rds_demod *rdsd, u8 MixSetting) +{ + if (rdsd->mix_msg_pending) + rdsd->mix_msg_overrun++; + rdsd->mix_msg = MixSetting; + rdsd->mix_msg_pending = 1; + + /* signal monitor thread */ + stfm1000_monitor_signal( + rds_state_to_stfm1000(demod_to_rds_state(rdsd)), + EVENT_RDS_MIXFILT); +} + +/* call with interrupts disabled please */ +int stfm1000_rds_mix_msg_get(struct stfm1000_rds_state *rds) +{ + struct stfm1000_rds_demod *rdsd = &rds->demod; + + if (!rdsd->mix_msg_pending) + return -1; + + return rdsd->mix_msg; +} + +/* call with interrupts disabled please */ +int stfm1000_rds_mix_msg_processed(struct stfm1000_rds_state *rds, int mix_msg) +{ + struct stfm1000_rds_demod *rdsd = &rds->demod; + + if (!rdsd->mix_msg_pending) + return -1; + + rdsd->mix_msg_pending = 0; + + /* update the completion indication bit */ + if ((mix_msg & 0x8) == 0) + rdsd->MixPopDone = 1; + + /* this is reflected off the hardware register */ + rdsd->rds_mix_offset = mix_msg & 1; + + if (rdsd->mix_msg != mix_msg) { + rdsd->mix_msg_processed_changed++; + return -1; + } + return 0; +} + +static void rds_sdnominal_msg(struct stfm1000_rds_demod *rdsd, int sdnominal) +{ + if (rdsd->sdnominal_msg_pending) + rdsd->sdnominal_msg_overrun++; + rdsd->sdnominal_msg = sdnominal; + rdsd->sdnominal_msg_pending = 1; + + /* signal monitor thread */ + stfm1000_monitor_signal( + rds_state_to_stfm1000(demod_to_rds_state(rdsd)), + EVENT_RDS_SDNOMINAL); +} + +/* call with interrupts disabled please */ +int stfm1000_rds_sdnominal_msg_get(struct stfm1000_rds_state *rds) +{ + struct stfm1000_rds_demod *rdsd = &rds->demod; + + if (!rdsd->sdnominal_msg_pending) + return 0; + + return rdsd->sdnominal_msg; +} + +/* call with interrupts disabled please */ +int stfm1000_rds_sdnominal_msg_processed(struct stfm1000_rds_state *rds, + int sdnominal_msg) +{ + struct stfm1000_rds_demod *rdsd = &rds->demod; + + if (!rdsd->sdnominal_msg_pending) + return -1; + + rdsd->sdnominal_msg_pending = 0; + return 0; +} + +void demod_loop(struct stfm1000_rds_bitstream *rdsb, + struct stfm1000_rds_demod *rdsd) +{ + s32 filter_out; + u32 freeSpace; + s32 decomp_hist_pp; + u8 phase; + + /* Check if we're at a half-basis point */ + if ((rdsd->i & (RDS_BASISLENGTH/2 - 1)) != 0) + return; /* Nope, return */ + + /* Yes, time to do our work */ + /* Rotate the length 3 history buffer */ + decomp_hist_pp = rdsd->decomp_hist_p; + rdsd->decomp_hist_p = rdsd->decomp_hist; + if ((rdsd->i & (RDS_BASISLENGTH-1)) == 0) { + rdsd->decomp_hist = rdsd->mixandsum1>>9; /* Grab output of + * mixandsum1/512 */ + rdsd->mixandsum1 = 0; /* Reset mixandsum #1 */ + } else { + rdsd->decomp_hist = rdsd->mixandsum2>>9; /*Grab output of + * mixandsum2/512 */ + rdsd->mixandsum2 = 0; /* Reset mixandsum #2 */ + } + + /* Form correlator/decimator output by convolving with the + * decomposition coefficients, DecompQuant from Matlab work. */ + filter_out = (-58*rdsd->decomp_hist + 59*decomp_hist_pp)>>7; + + /*Figure out which half-basis we are in (out of a bit-length cycle) */ + phase = rdsd->i*2/RDS_BASISLENGTH; + /*Now what we do depends on the phase variable */ + /*Phase 0: Bitslice and do timing alignment */ + /*others (1-3): Keep value for timing alignment */ + + if (phase == 0) { /*Main processing (bitslice) */ + u32 Ph; + u8 OldBit = rdsd->sliced_data; /* Save the previous value */ + + rdsd->return_num = 1; + if (filter_out >= 0) { /*This bit is "1" */ + /*return value is XOR of previous bit (still in + * sliced_data) w/ this */ + /* bit (1), which equals (NOT of the previous bit) */ + rdsd->return_rdsdemod = !OldBit; + rdsd->sliced_data = 1; /*Newest bit value is 1 */ + } else { /*This bit is "0" */ + /*return value is XOR of previous bit (still in + * sliced_data) w/ this */ + /* bit (0), which equals the previous bit */ + rdsd->return_rdsdemod = OldBit; + rdsd->sliced_data = 0; /*Newest bit value is 0 */ + } + + freeSpace = bits_free(rdsb); + + if (freeSpace > 0) + put1bit(rdsb, rdsd->return_rdsdemod); + else + rdsd->RdsDemodSkippedBitCnt++; + + /*Increment bits received counter */ + rdsd->BitAlignmentCounter++; + /*If mixer phase determination hasn't been done, start it */ + if ((rdsd->MixPhaseState == 0) && (!rdsd->MixPhaseDetInProg)) { + rdsd->MixPhaseDetInProg = 1; + /*Go to first mixer setting (0) */ + rds_mix_msg(rdsd, 0); + } + + /* Do bit-slicing time adaption after the mixer phase + * determination */ + if (!(rdsd->MixPhaseDetInProg) && !(rdsd->Synchronous)) { + + /* Bitslice Timing Adjust Code (runs after + * MixPhaseDetInProg and if RDS is not synchronous to + * the FM pilot. */ + + u8 BigPh2; /* Expecting a large value in + * PhaseValue[2] */ + u32 MaxRMS = 0; /*Largest phase RMS */ + s8 MaxPh = 0; /*Index of largest phase RMS */ + s32 zerocross; + + /* Locate the largest phase RMS + * (should be at phase zero) */ + for (Ph = 0; Ph < 4; Ph++) + if (rdsd->Ph_RMS[Ph] > MaxRMS) { + MaxRMS = rdsd->Ph_RMS[Ph]; + MaxPh = Ph; + } + + /* During each bit time we expect the four phases to + * take one of the following patterns, where 1 + * corresponds to maximum modulation: + * 1, 0, -1, 0 Case I + * -1, 0, 1, 0 Case II + * 1, 1/2, 0, -1/2 Case III + * -1, -1/2, 0, 1/2 Case IV + * We need to distinguish between cases in order to do + * the timing adjustment. Below we compare the + * correlation of the samples with Case I and Case III + * to see which has a bigger abs(correlation). Thus + * BigPh2, if set, means that we decided on Case I or + * Case II; if BigPh2 clear, we decided Case III or IV. + */ + BigPh2 = abs(rdsd->PhaseValue[0]-rdsd->PhaseValue[2]) > + abs(rdsd->PhaseValue[0] + + ((rdsd->PhaseValue[1]- + rdsd->PhaseValue[3])>>1)); + /* If BigPh2, use the difference between phase 1 value + * (downgoing for Case I, upgoing for Case II) and + * phase 3 value (upgoing for Case I, downgoing for + * Case II, thus the subtraction) to indicate timing + * error. If not BigPh2, use the sum of the phase 1 + * value (downgoing for Case III, upgoing for Case IV) + * and phase 3 value (downgoing for Case III, upgoing + * for Case IV, thus the addition) to indicate timing + * error. If BigPh2, the slopes at phase 1 & phase 3 + * are approximately double that if not BigPh2. + * Since we are trying to measure timing, scale + * by 1/2 in the BigPh2 case. */ + if (BigPh2) + zerocross = (rdsd->PhaseValue[1]- + rdsd->PhaseValue[3])>>1; + else + zerocross = rdsd->PhaseValue[1]+ + rdsd->PhaseValue[3]; + /* Now if the prev bit was a "1", then the first zero + * crossing (phase 1 if BigPh2, phase 2 if !BigPh2) + * was a falling one, and if we were late then + * zerocross should be negative. If the prev bit was a + * "0", then the first zero crossing was a rising one, + * and if we were late then zerocross would be + * positive. If we are "late" it means that we need to + * do a shorter cycle of, say, 15 samples instead of + * 16, to "catch up" so that in the future we will be + * sampling earlier. We shorten the cycle by adding + * to i, so "late" is going to mean "increment i". + * Therefore "late" should be positive, which is done + * here by inverting zerocross if the previous bit was + * 1. You could say that this step reflects cases I + * and III into II and IV, respectively. */ + if (OldBit) + zerocross = -zerocross; + if (!rdsd->DisablePushing) { + /*The algorithm so far has a stable operating + * point 17 phases away from the correct one. + * The following code is experimental and may + * be deleterious in low SNR conditions, but is + * an attempt to move off of the incorrect + * operating point. */ + + if (MaxPh != 0) { + /* If it isn't the same MaxPh as the + * last non-zero one, clear the counter + */ + if (MaxPh != rdsd->PushLastMaxPh) { + /*Reset the counter */ + rdsd->PushCounter = 0; + /*Record which phase we're now + * counting */ + rdsd->PushLastMaxPh = MaxPh; + } + /* If the Max RMS is on the same + * non-zero phase, count up */ + rdsd->PushCounter++; + } + /* Once every 128 bits, check and then reset + * PushCounter */ + if (!(rdsd->BitAlignmentCounter & 0x0FF)) { + /*If 90% of the time the max phase has + * been from the same non-zero phase, + * decide that we are latched onto a 0 + * lock point. Do a large push of the + * timing. */ + if (rdsd->PushCounter > 230) { + s32 pshiph; + /*Convert from phase number to + * the number of filter + * output samples that we need + * to shift */ + if (rdsd->PushLastMaxPh >= 2) + pshiph = + 4 - (s8)rdsd-> + PushLastMaxPh; + else + pshiph = + -(s8)rdsd-> + PushLastMaxPh; + /* Scale by the number of i- + * phases per output sample */ + pshiph <<= + RDS_BASISSHIFTS-1; + /* Perform big pop to get near + * correct timing */ + rdsd->i += (RDS_BASISLENGTH<<1) + + pshiph; + /* Set status indicating big + * pop was needed. Reset all + * leaky-bucket and summation + * variables because the big + * timing shift has invalidated + * them. Ph_RMS values don't + * need to be reset because + * they will shift over to + * reasonable values again + * before their erroneous + * values could have effect. */ + rdsd->rds_big_timeshift = 1; + /*rdsd->Ph_RMS[0] = 0; */ + /*rdsd->Ph_RMS[1] = 0; */ + /*rdsd->Ph_RMS[2] = 0; */ + /*rdsd->Ph_RMS[3] = 0; */ + rdsd->mixandsum1 = 0; + rdsd->mixandsum2 = 0; + rdsd->SkipsAccum += + pshiph; + + /* Make adjustments in other + * values because of the push + * (they wouldn't otherwise be + * able to use the information + * that a push was needed in + * their future control + * decisions). */ + if (rdsd->PushLastMaxPh != 2) { + /* If we weren't + * pushing from phase + * two, accumulate (for + * use in adapting + * SDNOMINAL) the + * phases moved by + * pushing. Phase two + * pushes are not used; + * the push direction + * is arbitrary since + * Phase 2 is 180 + * degrees out. Also, + * phase 2 pushes don't + * result from + * reasonable slippage. + * */ + + if (rdsd->sdnom_adapt) + rdsd->SdnomSk + += pshiph; + + /* Modify timing_adj to + * account for half of + * the DC response that + * would have occurred + * in timing_adj if + * that control loop + * had seen the push + * happen. (Why half? + * Because the loop has + * already seen a + * history of zerocross + * values that heads it + * in the same + * direction as this + * adjustment, but may + * have seen as few as + * half of what it + * should have.) */ + rdsd->timing_adj += + pshiph << + (TADJSH+1); + } + /*Set countdown timer that will + * prevent any mixer popping + * until the Ph_RMS variables + * have had enough time to + * stabilize */ + + /* 2.5 time constants */ + rdsd->PushSafetyZone = 5; + } + /*Reset the push counter */ + rdsd->PushCounter = 0; + } /*end once every 128 bits */ + } /*end if !DisablePushing */ + + /* Further possible additions: + * + * 1. Pushes modify timing_adj to decrease convergence + * time. + * 2. Separate timing_adj into pilottracking and non-pt + * cases (avoids convergence time after stereo/mono + * transitions) + * + * Old loop filter was a leaky bucket integrator, and + * it always lagged behind if the FM station had RDS + * asynchronous to the pilot, because the control loop + * needs another integrator to converge on a frequency + * error. + * New loop filter = 1/(1-1/z) * (a-1/z) * k, + * where a = 1+1/256 and k = 1/1024. + * You can narrow the loop bandwidth by making "a" + * twice as close to 1 and halving k, e.g. a = 1+1/512 + * and k = 1/2048. + * (The way implemented, that narrowing loop BW by + * a factor of 2 can be done by incrementing TADJSH.) + * + * TGR 8/31/2007 */ + + /*Integrator, 1/(1-1/z) */ + rdsd->timing_adj += zerocross; + /*Limit to 1 phase every 8 samples */ + if (rdsd->SkipSafetyZone) { + rdsd->SkipSafetyZone--; + rdsd->sampskip = 0; + } else { + /*sampskip of non-zero is allowed, + * calculate what it really is */ + + /*Saturate timing_adj to 2's comp + * (2*TADJSH+4)-bit range. */ + if (rdsd->timing_adj > (1<<(2*TADJSH+3))-1) + rdsd->timing_adj = (1<<(2*TADJSH+3))-1; + if (rdsd->timing_adj < -(1<<(2*TADJSH+3))) + rdsd->timing_adj = -(1<<(2*TADJSH+3)); + + /* Zero, implemented after the integrator + * output. + * (a-1/z) = (1+1/256) - 1/z = (1-1/z) + 1/256. + * But (1 - 1/z) is timing_adj- + * prev_timing_adj = zerocross. */ + rdsd->sampskip = zerocross /* 1 - 1/z */ + /* 1/256 (with rounding) */ + + ((rdsd->timing_adj + + (1<<(TADJSH-1)))>>TADJSH); + /*Round and apply k */ + rdsd->sampskip += (1<<(TADJSH+1)); + rdsd->sampskip >>= (TADJSH+2); + /*Limit to [-1,+1] inclusive */ + if (rdsd->sampskip > 1) + rdsd->sampskip = 1; + if (rdsd->sampskip < -1) + rdsd->sampskip = -1; + /* If non-zero, start the skip safety zone, + * which excludes more sample skipping for a + * while. Note that the safety zone only + * applies to the skips -- pushes can still + * happen inside a SkipSafetyZone. */ + if (rdsd->sampskip) + rdsd->SkipSafetyZone = 8-1; + } + /********************************************** + * End Timing Adjust Code + **********************************************/ + + /********************************************** + * Begin Phase Popper Code + **********************************************/ + /* If Phase Popping is enabled and 1/2 of a + * time constant has gone by... */ + if (rdsd->PhasePoppingEnabled && + !(rdsd->BitAlignmentCounter & + ((1<<(RMSALPHASHIFTS-1))-1))) { + + u8 ForcePop = 0; /* Used to force a pop */ + + /*Record the maximum of the envelope */ + if (MaxRMS > rdsd->PhasePopMaxRMS) + rdsd->PhasePopMaxRMS = MaxRMS; + /* Also track MaxRMS into MixPhase0/1Mag, so + * that we can see what the largest RMS on each + * of those phases is. On synchronous stations + * (meaning the RDS carrier and bit rate are + * synchronized with the pilot), the right mix + * phase will always be big and the wrong phase + * small. On asynchronous stations (and + * stations without RDS), both phases will at + * some time or other have about the + * same amplitude on each of the phases. */ + if (rdsd->rds_mix_offset) { + if (MaxRMS > rdsd->MixPhase1Mag) + rdsd->MixPhase1Mag = MaxRMS; + } else { + if (MaxRMS > rdsd->MixPhase0Mag) + rdsd->MixPhase0Mag = MaxRMS; + } + /* Update PopSafetyZone and PushSafetyZone + * counters. With RMSALPHASHIFTS = 5, each + * tick is 16/1187.5 =~ 13.5 ms. */ + if (rdsd->PopSafetyZone) { + rdsd->PopSafetyZone--; + /* If safety zone just ended and this + * mix phase is giving smaller RMS than + * before the pop, then the pop was a + * mistake. Go back to previous mixer + * phase */ + if (!(rdsd->PopSafetyZone) + && (rdsd->PhasePopMaxRMS < + rdsd->PrePopRMS)) + ForcePop = 1; + } + /* If there is no recent push, and Phase 0 has + * the maximum RMS, and at least 1/7th of a + * second has passed since the last phase pop, + * and ((the RMS is less than 1/2 of + * PhasePopMaxRMS) or (the RMS is less than + * 100)), then try a phase pop. */ + if (/* (rdsd->Ph_RMS[0] == MaxRMS) && + * Phase 0 has maximum RMS */ + !(rdsd->PopSafetyZone)) { + /* and Long enough since last + * phase pop */ + + /* Eligible for a pop, see if one of + * the pop conditions is met */ + if ((MaxRMS<<1) < + rdsd->PhasePopMaxRMS) { + /*RMS decline from its peak */ + ForcePop = 1; + } else if ((MaxRMS>>RMSALPHASHIFTS) + < 50) { + /*RMS too small to receive, + * either there's no RDS or + * this is the wrong phase */ + ForcePop = 1; + } + } + if (ForcePop) { + + /*Pop to opposite setting */ + rds_mix_msg(rdsd, 0x8 | + !rdsd->rds_mix_offset); + + /*Save the pre-pop RMS so that later we + * can see if the pop was actually + * effective */ + rdsd->PrePopRMS = MaxRMS; + /*Reset the PhasePopMaxRMS. We rely on + * the PopSafetyZone to give time to + * get a new valid max RMS before we're + * eligible for the next phase pop. If + * there were no reset we'd be forever + * incrementing PhasePopMaxRMS due + * to just happenstance large-noise + * samples and it might eventually get + * some freakish large value causing + * frequent erroneous pops. */ + rdsd->PhasePopMaxRMS = 0; + /* Pop Safety zone length is decided by + * how much of an asynchronous + * frequency can be supported. Allowing + * 50 ppm of transmitter error (error + * between their own pilot, that we + * should be locked to, and their RDS + * carrier (which by RDS spec should be + * locked to their pilot, but we've + * recently found frequently isn't). + * 50ppm * 57kHz = 2.85Hz. + * (2.85 cycles/sec)(4 pops/cycle) + * = 11.4 pops/second. + * Safety zone = (1/11.4) seconds =~ 104 + * bits, round down to 96 bits which + * yields 6 ticks if RMSALPHASHIFTS = 5. + * */ + rdsd->PopSafetyZone = 96>> + (RMSALPHASHIFTS-1); + } + } + /****************************************************** + * End Phase Popper Code + ******************************************************/ + + /* SDNOMINAL adaption */ + if (rdsd->sdnom_adapt) { + rdsd->SdnomSk += rdsd->sampskip; + if (rdsd->pCoefForcedMono && + (rdsd->BitAlignmentCounter & 0xFFF) == + 0x800) { + + rds_sdnominal_msg(rdsd, + -(rdsd->SdnomSk<<9)); + + /*Reset skips counter */ + rdsd->SdnomSk = 0; + } + } + + rdsd->SkipsAccum += rdsd->sampskip; + /* Once per 3.45 seconds, print out signal strength, + * skips and pops. Then reset the variables totalling + * those occurrences */ + if (!(rdsd->BitAlignmentCounter & 0xFFF)) { + /* During very noisy input (or if no RDS, or no + * station present), timing_adj can go crazy, + * since it is the integral of noise. Although + * it is a saturated value (earlier, in the + * timing adjust code), the level at which we + * can saturate still leaves room for + * timing_adj to get too big. A large value of + * timing_adj is a persistent pathology because + * the phase is shifting so quickly that the + * push detector (which relies on stable + * phase-RMS values) never triggers, thus there + * is no implemented rescue besides this + * clearing that restores proper function. */ + if (abs(rdsd->SkipsAccum) > 300) + rdsd->timing_adj = 0; + /*Reset the accumulations. */ + rdsd->SkipsAccum = 0; + } + } /*End of bit timing adaption */ + + /* If mixer phase determination in progress, + * perform actions at certain times */ + if (rdsd->MixPhaseDetInProg) { + /*~10ms settling time after mixer phase change */ + #define MIXPHASE_STARTMEAS 12 + /*~20ms measurement window */ + #define MIXPHASE_ENDMEAS (MIXPHASE_STARTMEAS+24) + if (rdsd->BitAlignmentCounter == MIXPHASE_STARTMEAS) { + /*Reset the RMS variables */ + rdsd->Ph_RMS[0] = 0; + rdsd->Ph_RMS[1] = 0; + rdsd->Ph_RMS[2] = 0; + rdsd->Ph_RMS[3] = 0; + /* Don't reset mixandsum values because at + * least they have filtered continuously. All + * we really need for the mixer phase decision + * is a constant measurement window. */ + } else if (rdsd->BitAlignmentCounter == + MIXPHASE_ENDMEAS) { + /*Measurement = mean of RMS values */ + u32 Ndx, MeasVal = 0; + for (Ndx = 0; Ndx < 4; + MeasVal += rdsd->Ph_RMS[Ndx++]>>2); + /*Store measurement in correct place */ + if (rdsd->MixPhaseState == 1) { + rdsd->MixPhase0Mag = MeasVal; + /*Go to next mixer setting */ + rds_mix_msg(rdsd, 1); + } else if (rdsd->MixPhaseState == 2) { + u8 NextMixSetting; + rdsd->MixPhase1Mag = MeasVal; + /* Both measurements done now, see what + * mixer setting we need to use. + * 0 if MixPhase0Mag > MixPhase1Mag, + * 1 otherwise. */ + NextMixSetting = (rdsd->MixPhase0Mag + <= rdsd->MixPhase1Mag); + /* If the mixer setting needed is 1, + * that is already the current setting. + * Terminate mixer phase determination. + * Otherwise send message to switch the + * mixer phase setting. */ + if (NextMixSetting) { + rdsd->MixPhaseState = 3; + rdsd->MixPhaseDetInProg = 0; + } else + rds_mix_msg(rdsd, 0); + } + } + /* Reset BitAlignmentCounter if the Mixer just popped + * Change state, if required. States are: + * 0: Initial state, send msg causing RDS_MIXOFFSET=>0 + * 1: Measure with RDS_MIXOFFSET = 0. + * Lasts just over 30 ms. + * 2: Measure with RDS_MIXOFFSET = 1. + * Lasts just over 30 ms. + * 3: At final RDS_MIXOFFSET value. + * Lasts as long as RDS continues. */ + if (rdsd->MixPopDone) { + rdsd->MixPopDone = 0; + rdsd->BitAlignmentCounter = 0; + rdsd->MixPhaseState++; /*Go to next state */ + /* If we got to state 3, turn off mixer phase + * determination code */ + if (rdsd->MixPhaseState == 3) + rdsd->MixPhaseDetInProg = 0; + } + } + + /* Update status variables */ + rdsd->RDS_BIT_AMP_STAT_REG9 = rdsd->Ph_RMS[0]>>RMSALPHASHIFTS; + /*Saturate */ + if (rdsd->RDS_BIT_AMP_STAT_REG9 > 511) + rdsd->RDS_BIT_AMP_STAT_REG9 = 511; + } /*End phase 0 code */ + + /*************************************************** + * Actions common to all phases + ***************************************************/ + + /* Save the output of each phase for possible + * calculations during phase 0 */ + rdsd->PhaseValue[phase] = filter_out; + + /*So that we can measure signal amplitude and/or determine what (if */ + /* any) big jump is needed, maintain the RMS of each phase. Phase */ + /* 0 RMS is already in Ph_RMS[0] (see bitslicing code, earlier). */ + rdsd->Ph_RMS[phase] += abs(filter_out) - + (rdsd->Ph_RMS[phase]>>RMSALPHASHIFTS); +} + +#if defined(CONFIG_ARM) + +/* assembly version for ARM */ +#define RDS_MAC(_acc, _x, _y) \ + __asm__ __volatile__ ( \ + "smlabb %0, %1, %2, %0\n" \ + : "=&r" (_acc) \ + : "r" (_x), "r" (_y) \ + : "cc") + +#else + +/* all others, use standard C */ +#define RDS_MAC(_acc, _x, _y) \ + do { \ + (_acc) += (s16)(_x) * (s16)(_y); \ + } while (0) + +#endif + +static void rds_demod(const u16 *data, struct stfm1000_rds_demod *rdsd, + struct stfm1000_rds_bitstream *rbit, int total) +{ + register const s16 *basis0; + register const s16 *basis1; + register s16 val; + register int i; + register int sampskip; + register s32 acc1; + register s32 acc2; + + /* point to the table */ + basis0 = u16_rds_basis; + basis1 = basis0 + 8; + + rdsd->return_num = 0; + + /* restore state */ + i = rdsd->i; + acc1 = rdsd->mixandsum1; + acc2 = rdsd->mixandsum2; /* 64 bit */ + sampskip = rdsd->sampskip; + + while (total-- > 0) { + + val = data[3]; /* load RDS data */ + data += 4; + if (val == 0x7fff) /* illegal RDS sample */ + continue; + + RDS_MAC(acc1, val, basis0[i]); + RDS_MAC(acc2, val, basis1[i]); + + if (i == 4) { + i += sampskip; + sampskip = 0; + } + + if ((i & (RDS_BASISLENGTH / 2 - 1)) == 0) { + + /* save state */ + rdsd->mixandsum1 = acc1; + rdsd->mixandsum2 = acc2; + rdsd->i = i; + rdsd->sampskip = sampskip; + + demod_loop(rbit, rdsd); + + /* restore state */ + acc1 = rdsd->mixandsum1; + acc2 = rdsd->mixandsum2; + i = rdsd->i; + sampskip = rdsd->sampskip; + } + i = (i + 1) & 31; + } + + /* save state */ + rdsd->mixandsum1 = acc1; + rdsd->mixandsum2 = acc2; + rdsd->i = i; + rdsd->sampskip = sampskip; +} + +void stfm1000_rds_demod(struct stfm1000_rds_state *rds, const u16 *dri_data, + int total) +{ + rds_demod(dri_data, &rds->demod, &rds->bitstream, total); + + /* signal only when we have enough */ + if (bits_filled(&rds->bitstream) > 128) + stfm1000_monitor_signal(rds_state_to_stfm1000(rds), + EVENT_RDS_BITS); +} + +static void bitstream_reset(struct stfm1000_rds_bitstream *rdsb) +{ + memset(rdsb, 0, sizeof(*rdsb)); +} + +static void demod_reset(struct stfm1000_rds_demod *rdsd) +{ + memset(rdsd, 0, sizeof(*rdsd)); + rdsd->sdnom_adapt = 0; /* XXX this doesn't really work right */ + /* it causes underruns at ALSA */ + rdsd->PhasePoppingEnabled = 1; /* does this? */ +} + +static void packet_reset(struct stfm1000_rds_pkt *rdsp) +{ + memset(rdsp, 0, sizeof(*rdsp)); + rdsp->state = SYNC_OFFSET_A; +} + +static void text_reset(struct stfm1000_rds_text *rdst) +{ + memset(rdst, 0, sizeof(*rdst)); +} + +void stfm1000_rds_reset(struct stfm1000_rds_state *rds) +{ + bitstream_reset(&rds->bitstream); + demod_reset(&rds->demod); + packet_reset(&rds->pkt); + text_reset(&rds->text); + rds->reset_req = 0; +} + +int stfm1000_rds_bits_available(struct stfm1000_rds_state *rds) +{ + return bits_filled(&rds->bitstream); +} + +int stmf1000_rds_get_bit(struct stfm1000_rds_state *rds) +{ + if (bits_filled(&rds->bitstream) == 0) + return -1; + return get1bit(&rds->bitstream); +} + +int stmf1000_rds_avail_bits(struct stfm1000_rds_state *rds) +{ + return bits_filled(&rds->bitstream); +} + +static const u32 rds_ParityCheck[] = { + 0x31B, 0x38F, 0x2A7, 0x0F7, 0x1EE, + 0x3DC, 0x201, 0x1BB, 0x376, 0x355, + 0x313, 0x39F, 0x287, 0x0B7, 0x16E, + 0x2DC, 0x001, 0x002, 0x004, 0x008, + 0x010, 0x020, 0x040, 0x080, 0x100, + 0x200 +}; + +static int calc_syndrome(u32 rdscrc) +{ + int i; + u32 syndrome = 0; + int word = 0x1; + + for (i = 0; i < 26; i++) { + if (rdscrc & word) + syndrome ^= rds_ParityCheck[i]; + word <<= 1; + } + return syndrome; +} + +static u32 ecc_table[1024]; +static int ecc_table_generated; + +static void generate_ecc_table(void) +{ + int i, j, size; + u32 syndrome, word; + + for (i = 0; i < ECC_TBL_SIZE; i++) + ecc_table[i] = 0xFFFFFFFF; + ecc_table[0] = 0x0; + + for (j = 0; j < 5; j++) { + word = (1 << (j + 1)) - 1; /* 0x01 0x03 0x07 0x0f 0x1f */ + size = 26 - j; /* 26, 25, 24, 23, 22 */ + syndrome = 0; + for (i = 0; i < size; i++) { + syndrome = calc_syndrome(word); + ecc_table[syndrome] = word; + word <<= 1; + } + } +} + +static u32 ecc_correct(u32 rdsBits, int *recovered) +{ + u32 syndrome; + u32 errorBits; + + if (recovered) + *recovered = 0; + + /* Calculate Syndrome on Received Packet */ + syndrome = calc_syndrome(rdsBits); + + if (syndrome == 0) + return rdsBits; /* block is clean */ + + /* generate table first time we get here */ + if (!ecc_table_generated) { + generate_ecc_table(); + ecc_table_generated = 1; + } + + /* Attempt to recover block */ + errorBits = ecc_table[syndrome]; + if (errorBits == UNRECOVERABLE_RDS_BLOCK) + return UNRECOVERABLE_RDS_BLOCK; /* Block can not be recovered. + * it is bad packet */ + + rdsBits = rdsBits ^ errorBits; + if (recovered) + (*recovered)++; + return rdsBits; /* ECC correct */ +} + +/* The following table lists the RDS and RBDS Program Type codes + * and their meanings: + * PTY code RDS Program type RBDS Program type */ +static const struct stfm1000_rds_pty stc_tss_pty_tab[] = { + { 0, "No program type", "No program type"}, + { 1, "News", "News"}, + { 2, "Current affairs", "Information"}, + { 3, "Information", "Sports"}, + { 4, "Sports", "Talk"}, + { 5, "Education", "Rock"}, + { 6, "Drama", "Classic Rock"}, + { 7, "Culture", "Adult Hits"}, + { 8, "Science", "Soft Rock"}, + { 9, "Varied", "Top 40"}, + { 10, "Pop", "Music Country"}, + { 11, "Rock", "Music Oldies"}, + { 12, "M.O.R.", "Music Soft"}, + { 13, "Light classical", "Nostalgia"}, + { 14, "Serious", "Classical Jazz"}, + { 15, "Other Music", "Classical"}, + { 16, "Weather", "Rhythm and Blues"}, + { 17, "Finance", "Soft Rhythm and Blues"}, + { 18, "Children's programs", "Language"}, + { 19, "Social Affairs", "Religious Music"}, + { 20, "Religion", "Religious Talk"}, + { 21, "Phone In", "Personality"}, + { 22, "Travel", "Public"}, + { 23, "Leisure", "College"}, + { 24, "Jazz Music", "Unassigned"}, + { 25, "Country Music", "Unassigned"}, + { 26, "National Music", "Unassigned"}, + { 27, "Oldies Music", "Unassigned"}, + { 28, "Folk Music", "Unassigned"}, + { 29, "Documentary", "Weather"}, + { 30, "Alarm Test", "Emergency Test"}, + { 31, "Alarm", "Emergency"}, +}; + +#if 0 +static const char *rds_group_txt[] = { + [RDS_GROUP_TYPE_0A] = "Basic tuning and switching information (0A)", + [RDS_GROUP_TYPE_0B] = "Basic tuning and switching information (0B)", + [RDS_GROUP_TYPE_1A] = "Program item number and slow labeling codes", + [RDS_GROUP_TYPE_1B] = "Program item number", + [RDS_GROUP_TYPE_2A] = "Radio Text (2A)", + [RDS_GROUP_TYPE_2B] = "Radio Text (2B)", + [RDS_GROUP_TYPE_3A] = "Application identification for ODA only", + [RDS_GROUP_TYPE_3B] = "Open data applications", + [RDS_GROUP_TYPE_4A] = "Clock-time and date", + [RDS_GROUP_TYPE_4B] = "Open data applications", + [RDS_GROUP_TYPE_5A] = "Transparent Data Channels (32 ch.) or ODA (5A)", + [RDS_GROUP_TYPE_5B] = "Transparent Data Channels (32 ch.) or ODA (5B)", + [RDS_GROUP_TYPE_6A] = "In House Applications or ODA (6A)", + [RDS_GROUP_TYPE_6B] = "In House Applications or ODA (6B)", + [RDS_GROUP_TYPE_7A] = "Radio Paging or ODA", + [RDS_GROUP_TYPE_7B] = "Open Data Applications", + [RDS_GROUP_TYPE_8A] = "Traffic Message Channel or ODA", + [RDS_GROUP_TYPE_8B] = "Open Data Applications", + [RDS_GROUP_TYPE_9A] = "Emergency warning system or ODA", + [RDS_GROUP_TYPE_9B] = "Open Data Applications", + [RDS_GROUP_TYPE_10A] = "Program Type Name", + [RDS_GROUP_TYPE_10B] = "Open Data Applications (10B)", + [RDS_GROUP_TYPE_11A] = "Open Data Applications (11A)", + [RDS_GROUP_TYPE_11B] = "Open Data Applications (11B)", + [RDS_GROUP_TYPE_12A] = "Open Data Applications (12A)", + [RDS_GROUP_TYPE_12B] = "Open Data Applications (12B)", + [RDS_GROUP_TYPE_13A] = "Enhanced Radio Paging or ODA", + [RDS_GROUP_TYPE_13B] = "Open Data Applications", + [RDS_GROUP_TYPE_14A] = "Enhanced Other Networks information (14A)", + [RDS_GROUP_TYPE_14B] = "Enhanced Other Networks information (14B)", + [RDS_GROUP_TYPE_15A] = "Defined in RBDS", + [RDS_GROUP_TYPE_15B] = "Fast switching information", +}; +#endif + +static void dump_rds_packet(u8 *buf) +{ + u16 pi, offb; + + pi = (u16)(buf[0] << 8) | buf[1]; + offb = (u16)(buf[1] << 8) | buf[2]; + + printk(KERN_INFO "GRP: " + "PI=0x%04x " + "GT=%2d VER=%d TP=%d PTY=%2d " + "PS_SEG=%2d RT_AB=%2d RT_SEG=%2d\n", pi, + RDS_GROUP_TYPE(offb), RDS_VERSION(offb), RDS_TP(offb), + RDS_PTY(offb), + RDS_PS_SEG(offb), RDS_RT_AB(offb), RDS_RT_SEG(offb)); +} + +void stfm1000_rds_process_packet(struct stfm1000_rds_state *rds, u8 *buffer) +{ + struct stfm1000_rds_text *rdst = &rds->text; + /* char tempCallLetters[5] = {0}; */ + struct rds_group_data grp; + int grpno; + u32 offset; + char tps[9]; + int i, seg, idx; + + grp.piCode = ((u16)buffer[0] << 8) | buffer[1]; + grp.offsetB = ((u16)buffer[2] << 8) | buffer[3]; + grp.offsetC = ((u16)buffer[4] << 8) | buffer[5]; + grp.offsetD = ((u16)buffer[6] << 8) | buffer[7]; + + grpno = (grp.offsetB >> (8 + 3)) & 0x1f; + + if (rds_state_to_stfm1000(rds)->rds_info) + dump_rds_packet(buffer); + + /* Is this the first time through? */ + if (!rdst->bRds_detected) { + rdst->pi = grp.piCode; + rdst->tp = RDS_TP(grp.offsetB); + rdst->version = RDS_VERSION(grp.offsetB); + rdst->pty.id = RDS_PTY(grp.offsetB); + rdst->pty.pRds = stc_tss_pty_tab[rdst->pty.id].pRds; + rdst->pty.pRdbs = stc_tss_pty_tab[rdst->pty.id].pRdbs; + rdst->bRds_detected = 1; + } + + /* Have we process too many PI errors? */ + if (grp.piCode != rdst->pi) { + if (rdst->mismatch++ > 10) { + + /* requested reset of RDS */ + rds->reset_req = 1; + + /* signal monitor thread */ + stfm1000_monitor_signal(rds_state_to_stfm1000(rds), + EVENT_RDS_RESET); + + if (rds_state_to_stfm1000(rds)->rds_info) + printk(KERN_INFO "RDS: RESET!!!\n"); + + text_reset(rdst); + } + rdst->consecutiveGood = 0; + return; + } + + if (rdst->consecutiveGood++ > 10) + rdst->mismatch = 0; /* reset bad count */ + + if (rdst->consecutiveGood > rdst->consecutiveGoodMax) + rdst->consecutiveGoodMax = rdst->consecutiveGood; + + switch (grpno) { + case RDS_GROUP_TYPE_0A: + case RDS_GROUP_TYPE_0B: + /* Extract Service Name information */ + offset = RDS_PS_SEG(grp.offsetB) * 2; + rdst->wk_ps[offset] = buffer[6]; /* better */ + rdst->wk_ps[offset + 1] = buffer[7]; + rdst->wk_ps_mask |= 1 << RDS_PS_SEG(grp.offsetB); + + if (rds_state_to_stfm1000(rds)->rds_info) { + for (i = 0; i < 8; i++) { + if (rdst->wk_ps_mask & (1 << i)) { + tps[i * 2] = + rdst->wk_ps[i * 2]; + tps[i * 2 + 1] = + rdst->wk_ps[i * 2 + 1]; + } else { + tps[i * 2] = '_'; + tps[i * 2 + 1] = '_'; + } + } + tps[ARRAY_SIZE(tps) - 1] = '\0'; + if (rds_state_to_stfm1000(rds)->rds_info) + printk(KERN_INFO "RDS-PS (curr): %s\n", tps); + } + + if (rdst->wk_ps_mask != ALL_SEGMENT_BITS) + break; + + if (rdst->ps_valid) { + if (memcmp(rdst->ps, rdst->wk_ps, 8) != 0) { + memset(rdst->cp_ps, 0, 8); + memset(rdst->wk_ps, 0, 8); + rdst->wk_ps_mask = 0; + } + + memset(rdst->ps, 0, 8); + rdst->ps_valid = 0; + break; + } + + /* does working buffer == compare buffer */ + if (memcmp(rdst->cp_ps, rdst->wk_ps, 8) != 0) { + /* just copy from working to compare buffer */ + memcpy(rdst->cp_ps, rdst->wk_ps, 8); + rdst->wk_ps_mask = 0; + break; + } + + /* working buffer matches compare buffer, send to UI */ + memcpy(rdst->ps, rdst->cp_ps, 8); + rdst->ps_valid = 1; + + if (rds_state_to_stfm1000(rds)->rds_info) + printk(KERN_INFO "RDS: PS '%s'\n", rdst->ps); + + /* clear working mask-only */ + rdst->wk_ps_mask = 0; + break; + + case RDS_GROUP_TYPE_2A: + + /* Clear buffer */ + if (rdst->textAB_flag != RDS_RT_AB(grp.offsetB)) { + memset(rdst->wk_text, 0, 64); + rdst->wk_text_mask = 0; + rdst->textAB_flag = RDS_RT_AB(grp.offsetB); + } + + /* Extract Text */ + seg = RDS_RT_SEG(grp.offsetB); + idx = seg * 4; + + #define CNVT_EOT(x) ((x) != RDS_EOT ? (x) : 0) + rdst->wk_text[idx++] = CNVT_EOT(buffer[4]); + rdst->wk_text[idx++] = CNVT_EOT(buffer[5]); + rdst->wk_text[idx++] = CNVT_EOT(buffer[6]); + rdst->wk_text[idx++] = CNVT_EOT(buffer[7]); + + rdst->wk_text_mask |= 1 << seg; + /* scan msg data for EOT. If found set all higher + * mask bits */ + for (idx = 0; idx < 4; idx++) { + if (rdst->text[idx] == RDS_EOT) + break; + } + if (idx < 4) { + /* set current and all higher bits */ + for (idx = RDS_RT_SEG(grp.offsetB); idx < 16; + idx++) + rdst->wk_text_mask |= 1 << idx; + } + + /* Process buffer when filled */ + if (rdst->wk_text_mask != ALL_TEXT_BITS) + break; + + if (!rdst->text_valid) + rdst->text_valid = 1; + else if (memcmp(rdst->text, rdst->wk_text, 64) == 0) + break; + + memcpy(rdst->text, rdst->wk_text, 64); + + if (rds_state_to_stfm1000(rds)->rds_info) + printk(KERN_INFO "RDS: TEXT '%s'\n", rdst->text); + + memset(rdst->wk_text, 0, 64); + rdst->wk_text_mask = 0; + break; + + default: + break; + } +} + +int stfm1000_rds_packet_dequeue(struct stfm1000_rds_state *rds, u8 *buf) +{ + struct stfm1000_rds_pkt *pkt = &rds->pkt; + + if (pkt->buf_cnt == 0) + return -1; + + memcpy(buf, &pkt->buf_queue[pkt->buf_tail][0], 8); + if (++pkt->buf_tail >= RDS_PKT_QUEUE) + pkt->buf_tail = 0; + pkt->buf_cnt--; + + return 0; +} + +void stfm1000_rds_packet_bit(struct stfm1000_rds_state *rds, int bit) +{ + struct stfm1000_rds_pkt *pkt = &rds->pkt; + u32 rdsdata, rdscrc, rdscrc_c, rdscrc_cp; + int correct, correct2, recovered, recovered2; + int RetVal; + + /* Stick into shift register */ + pkt->rdsstream = ((pkt->rdsstream << 1) | bit) & 0x03ffffff; + pkt->bitsinfifo++; + pkt->bitcount++; + + /* wait for 26 bits of block */ + if (pkt->bitsinfifo < 26) + return; + + rdsdata = pkt->rdsstream & 0x03fffc00; /* 16 bits of Info. word */ + rdscrc = pkt->rdsstream & 0x3ff; /* 10 bits of Checkword */ + + switch (pkt->state) { + case SYNC_OFFSET_A: + + RetVal = calc_syndrome(pkt->rdsstream); + + switch (RetVal) { + case RDS_SYNDROME_OFFSETA: + pkt->state = OFFSET_B; + break; + case RDS_SYNDROME_OFFSETB: + pkt->state = OFFSET_C_CP; + break; + case RDS_SYNDROME_OFFSETC: + pkt->state = OFFSET_D; + break; + case RDS_SYNDROME_OFFSETCP: + pkt->state = OFFSET_D; + break; + case RDS_SYNDROME_OFFSETD: + pkt->state = OFFSET_A; + break; + default: + pkt->state = SYNC_OFFSET_A; + break; + } + if (pkt->state == SYNC_OFFSET_A) { + pkt->sync_lost_packets++; + /* XXX send info? */ + break; + } + + pkt->good_packets++; + + rdsdata = pkt->rdsstream & 0x03fffc00; + + /* Save type A packet in buffer */ + rdsdata >>= 10; + pkt->buffer[0] = (rdsdata >> 8); + pkt->buffer[1] = (rdsdata & 0xff); + pkt->bitsinfifo = 0; + + /* We found a block with zero errors, but it is not at the + * start of the group. */ + if (pkt->state == OFFSET_B) + pkt->discardpacket = 0; + else + pkt->discardpacket = 1; + break; + + case OFFSET_A: /* Type A: we are in sync now */ + rdscrc ^= RDS_OFFSETA; + correct = ecc_correct(rdsdata | rdscrc, &recovered); + if (correct == UNRECOVERABLE_RDS_BLOCK) { + pkt->bad_packets++; + pkt->discardpacket++; + pkt->state++; + pkt->bitsinfifo = 0; + break; + } + + if (recovered) + pkt->recovered_packets++; + pkt->good_packets++; + + /* Attempt to see, if we can get the entire group. + * Don't discard. */ + pkt->discardpacket = 0; + rdsdata = correct & 0x03fffc00; + + /* Save type A packet in buffer */ + rdsdata >>= 10; + pkt->buffer[0] = (rdsdata >> 8); + pkt->buffer[1] = (rdsdata & 0xff); + pkt->bitsinfifo = 0; + pkt->state++; + break; + + case OFFSET_B: /* Waiting for type B */ + rdscrc ^= RDS_OFFSETB; + correct = ecc_correct(rdsdata | rdscrc, &recovered); + if (correct == UNRECOVERABLE_RDS_BLOCK) { + pkt->bad_packets++; + pkt->discardpacket++; + pkt->state++; + pkt->bitsinfifo = 0; + break; + } + if (recovered) + pkt->recovered_packets++; + pkt->good_packets++; + + rdsdata = correct & 0x03fffc00; + + /* Save type B packet in buffer */ + rdsdata >>= 10; + pkt->buffer[2] = (rdsdata >> 8); + pkt->buffer[3] = (rdsdata & 0xff); + pkt->bitsinfifo = 0; + pkt->state++; + break; + + case OFFSET_C_CP: /* Waiting for type C or C' */ + rdscrc_c = rdscrc ^ RDS_OFFSETC; + rdscrc_cp = rdscrc ^ RDS_OFFSETCP; + correct = ecc_correct(rdsdata | rdscrc_c, &recovered); + correct2 = ecc_correct(rdsdata | rdscrc_cp, &recovered2); + if (correct == UNRECOVERABLE_RDS_BLOCK + && correct2 == UNRECOVERABLE_RDS_BLOCK) { + pkt->bad_packets++; + pkt->discardpacket++; + pkt->state++; + pkt->bitsinfifo = 0; + break; + } + + if (recovered || recovered2) + pkt->recovered_packets++; + pkt->good_packets++; + + if (correct == UNRECOVERABLE_RDS_BLOCK) + correct = correct2; + + rdsdata = correct & 0x03fffc00; + + /* Save type C packet in buffer */ + rdsdata >>= 10; + pkt->buffer[4] = (rdsdata >> 8); + pkt->buffer[5] = (rdsdata & 0xff); + pkt->bitsinfifo = 0; + pkt->state++; + break; + + case OFFSET_D: /* Waiting for type D */ + rdscrc ^= RDS_OFFSETD; + correct = ecc_correct(rdsdata | rdscrc, &recovered); + if (correct == UNRECOVERABLE_RDS_BLOCK) { + pkt->bad_packets++; + pkt->discardpacket++; + pkt->state = OFFSET_A; + pkt->bitsinfifo = 0; + break; + } + + if (recovered) + pkt->recovered_packets++; + pkt->good_packets++; + + rdsdata = correct & 0x03fffc00; + + /* Save type D packet in buffer */ + rdsdata >>= 10; + pkt->buffer[6] = (rdsdata >> 8); + pkt->buffer[7] = (rdsdata & 0xff); + + /* buffer it if all segments were ok */ + if (pkt->discardpacket) { + /* We're still in sync, so back to state 1 */ + pkt->state = OFFSET_A; + pkt->bitsinfifo = 0; + pkt->discardpacket = 0; + break; + } + + pkt->state++; + /* fall-through */ + + case PACKET_OUT: + pkt->GroupDropOnce = 1; + + /* queue packet */ + if (pkt->buf_cnt < RDS_PKT_QUEUE) { + memcpy(&pkt->buf_queue[pkt->buf_head][0], + pkt->buffer, 8); + if (++pkt->buf_head >= RDS_PKT_QUEUE) + pkt->buf_head = 0; + pkt->buf_cnt++; + } else + pkt->buf_overruns++; + + /* We're still in sync, so back to state 1 */ + pkt->state = OFFSET_A; + pkt->bitsinfifo = 0; + pkt->discardpacket = 0; + break; + + } + + /* Lots of errors? If so, go back to resync mode */ + if (pkt->discardpacket >= 10) { + pkt->state = SYNC_OFFSET_A; /* reset sync state */ + pkt->bitsinfifo = 26; /* resync a bit faster */ + } +} + +/* GROUP_TYPE 0A-0B (buffer must have enough space for 9 bytes) */ +int stfm1000_rds_get_ps(struct stfm1000_rds_state *rds, u8 *buffer, + int bufsize) +{ + struct stfm1000_rds_text *rdst = &rds->text; + + if (bufsize < 9) + return -1; + + if (!rdst->ps_valid) + return -1; + + memcpy(buffer, rdst->ps, 8); + buffer[8] = '\0'; + + return 8; +} + +/* GROUP_TYPE 2A (buffer must have enough space for 65 bytes) */ +int stfm1000_rds_get_text(struct stfm1000_rds_state *rds, u8 *buffer, + int bufsize) +{ + struct stfm1000_rds_text *rdst = &rds->text; + + if (bufsize < 9) + return -1; + + if (!rdst->text_valid) + return -1; + + memcpy(buffer, rdst->text, 64); + buffer[64] = '\0'; + + return 64; +} diff --git a/drivers/media/radio/stfm1000/stfm1000-rds.h b/drivers/media/radio/stfm1000/stfm1000-rds.h new file mode 100644 index 000000000000..44b9a610f86e --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-rds.h @@ -0,0 +1,364 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef STFM1000_RDS_H +#define STFM1000_RDS_H + +#include <linux/types.h> + +/* log2(number of samples in a filter basis) */ +#define RDS_BASISSHIFTS 4 + +/* number of samples in a filter basis */ +#define RDS_BASISLENGTH (1 << RDS_BASISSHIFTS) + +#define TIME_ADAPT_OVER 100 + +/* 2^(-this) is the RMS leaky bucket time constant */ +#define RMSALPHASHIFTS 5 + +#define PROCESS_RDS_BITS 128 + +#define RDS_BITBUFSIZE 1024 /* was 128 */ +struct stfm1000_rds_bitstream { + u32 buf[RDS_BITBUFSIZE]; /* bit buffer */ + int HeadBitCount; /* bit buffer head counter */ + int TailBitCount; /* bit buffer tail counter */ +}; + +struct stfm1000_rds_demod { + u32 mixandsum1; /* Accumulator for first + * basis filter */ + u32 mixandsum2; /* Accumulator for 2nd + * basis filter */ + u32 i; /* Phase Index, 32 phases per + * RDS bit */ + u32 return_num; /* Set if there is a new RDS bit */ + u32 BitAlignmentCounter; /* Counts bits for timing purposes */ + int sampskip; /* Requested timing shift (on i) */ + + int DisablePushing; /* Disables phase push algorithm + * (phase push happens when Ph_RMS[x], + * x != 0, is consistently the maximum + * Ph_RMS) */ + int MixPopDone; /* Last mixer phase set request is + * done */ + u8 rds_big_timeshift; /* If set, indicates a push or large + * timing shift occurred */ + int return_rdsdemod; /* Output, (most recent bit) XOR + * (prev bit) */ + u32 RDS_BIT_AMP_STAT_REG9; /* Size of bit (RMS of RDS signal at + * bitslicing instant, typically 220 + * to 270) */ + s32 decomp_hist; /* Most recent basis filter output */ + s32 decomp_hist_p; /* Previous basis filter output */ + s32 PhaseValue[4]; /* Half-basis phase samples over the + * most recent bit */ + u32 Ph_RMS[4]; /* RMS of the four half-basis phases */ + s32 timing_adj; /* Timing loop leaky-bucket + * accumulator */ + u32 MixPhase0Mag; /* Magnitude of RDS signal with RDS + * mixer phase 0 (from mixer phase + * determination) */ + u32 MixPhase1Mag; /* Magnitude of RDS signal with RDS + * mixer phase 1 (from mixer phase + * determination) */ + u32 PhasePopMaxRMS; /* Maximum RMS observed since last + * phase pop */ + u32 PrePopRMS; /* Max of Ph_RMS array right before the + * most recent phase pop */ + u8 MixPhaseState; /* State of RDS mixer phase + * determination state machine */ + int MixPhaseDetInProg; /* Set if RDS mix phase determination + * is in progress */ + int sliced_data; /* The most recent bit decision */ + u8 PopSafetyZone; /* Countdown timer, holds off next + * phase pop after a recent one */ + u8 PushSafetyZone; /* Countdown timer, holds off next + * phase pop after a timing push (b/c + * timing push resets Ph_RMS vars) */ + u8 SkipSafetyZone; /* Countdown timer, holds off next + * phase skip (small timing adj) */ + int Synchronous; /* RDS has been determined to be + * synchronous to pilot */ + u8 PushLastMaxPh; /* The index at which Ph_RMS is + * maximum ("x" in the above two + * comments) */ + s32 PushCounter; /* Counts instances of Ph_RMS[x], x!=0, + * being the maximum Ph_RMS */ + s32 SkipsAccum; /* Accumulation of all timing skips + * since RDS demod started */ + s32 SdnomSk; /* Skips counter used for SDNOMINAL + * adaption */ + + /* update this everytime it's changed & put it here */ + unsigned int rds_mix_offset : 1; + + unsigned int sdnom_adapt : 1; + unsigned int pCoefForcedMono : 1; /* copy of filter parameter */ + unsigned int PhasePoppingEnabled : 1; + + unsigned int mix_msg_pending : 1; + u8 mix_msg; + unsigned int mix_msg_overrun; + unsigned int mix_msg_processed_changed; + + unsigned int sdnominal_msg_pending : 1; + int sdnominal_msg; + unsigned int sdnominal_msg_overrun; + + u32 RdsDemodSkippedBitCnt; /* bit skipped by RDS demodulator due + * to unavailable space in buf[] + * (bit buffer) */ +}; + +#define RDS_OFFSETA 0x0fc +#define RDS_OFFSETB 0x198 +#define RDS_OFFSETC 0x168 +#define RDS_OFFSETCP 0x350 +#define RDS_OFFSETD 0x1b4 + +#define RDS_SYNDROME_OFFSETA 0x3d8 +#define RDS_SYNDROME_OFFSETB 0x3d4 +#define RDS_SYNDROME_OFFSETC 0x25c +#define RDS_SYNDROME_OFFSETCP 0x3cc +#define RDS_SYNDROME_OFFSETD 0x258 + +#define SYNC_OFFSET_A 0 /* default state */ +#define OFFSET_A 1 +#define OFFSET_B 2 +#define OFFSET_C_CP 3 +#define OFFSET_D 4 +#define PACKET_OUT 5 + +#define ECC_TBL_SIZE 1024 +#define UNRECOVERABLE_RDS_BLOCK 0xffffffff + +#define RDS_PKT_QUEUE 16 + +struct stfm1000_rds_pkt { + int state; /* Current state */ + u32 rdsstream; /* Current RDS data */ + u8 buffer[8]; /* temporary storage of RDS data */ + int discardpacket; /* discard packet count */ + int sync_lost_packets; /* sync lost */ + int good_packets; /* good packet */ + int bad_packets; /* bad packet */ + int recovered_packets; /* recovered packet */ + int bitsinfifo; /* bits count */ + int GroupDropOnce; /* Send Group Drop Message once */ + int bitcount; /* Counter for Number of Bits read */ + + /* queue the packets here */ + int buf_overruns; + int buf_head; + int buf_tail; + int buf_cnt; + int buf_queue[RDS_PKT_QUEUE][8]; +}; + +#define AUDIT 0 +#define ALL_SEGMENT_BITS 0xF +#define ALL_TEXT_BITS 0xFFFF + +struct stfm1000_rds_pty { + u8 id; /* Program Type ID */ + u8 *pRds; /* RDS description */ + u8 *pRdbs; /* RDBS description */ +}; + +struct stfm1000_rds_text { + u8 bRds_detected; /* Has the first packet come in yet? */ + u16 pi; /* Program Identification Code (PI) */ + struct stfm1000_rds_pty pty; /* Program Type (PTY)) */ + u8 tp; /* Traffic Program (TP) identification + * code */ + u8 ps[9]; /* Program Service Name Sent to UI */ + u8 altFreq[2]; /* Alternate frequency (AF) */ + u8 callLetters[5]; /* For US, stations call letters */ + + u8 text[65]; /* Radio Text A */ + + unsigned int version : 1; /* Is station broadcasting version + * A or B (B0) */ + unsigned int ps_valid : 1; /* station name is valid */ + unsigned int text_valid : 1; /* Text is valid */ + unsigned int textAB_flag : 1; /* Current flag setting, reset if flag + * changes */ + + /*------------------Working area--------------------------- */ + u8 cp_ps[8]; /* Compare buffer for PS */ + u8 wk_ps[8]; /* Program Service buffer */ + u8 wk_ps_mask; /* lower 4 bits must be set + * before copy */ + u8 wk_text[64]; /* Radio Text buffer */ + u16 wk_text_mask; /* all bits must be set before copy */ + + /*-------------------Counters------------------------------ */ + u32 messages; /* total number of messages recieved */ + u32 unsupported; /* call to unsupported group type */ + u32 mismatch; /* Mismatched values */ + u32 consecutiveGood; /* Consecutive good will clear bad */ + u32 consecutiveGoodMax; /* Max counter for paramaters */ +}; + +/* Maximum number of RDS groups described in the U.S. RBDS Standard. */ +#define MAX_RDS_GROUPS_SUPPORTED 32 + +/* Common Constants */ +#define RDS_LINE_FEED 0xA +#define RDS_EOT 0xD + +/* Offsets into OFFSETB */ +#define RDS_GROUP_TYPE(x) (((x) >> 12) & 0xF) +#define RDS_VERSION(x) (((x) >> 11) & 0x1) +#define RDS_TP(x) (((x) >> 10) & 0x1) +#define RDS_PTY(x) (((x) >> 5) & 0x1F) +#define RDS_PS_SEG(x) ((x) & 0x3) +#define RDS_RT_AB(x) (((x) >> 4) & 0x1) +#define RDS_RT_SEG(x) ((x) & 0xF) + +/* This values corresond to the Group Types defined */ +/* In the U.S. RBDS standard. */ +#define RDS_GROUP_TYPE_0A 0 /* Basic tuning and switching information */ +#define RDS_GROUP_TYPE_0B 1 /* Basic tuning and switching information */ +#define RDS_GROUP_TYPE_1A 2 /* Program item number and slow labeling + * codes */ +#define RDS_GROUP_TYPE_1B 3 /* Program item number */ +#define RDS_GROUP_TYPE_2A 4 /* Radio Text */ +#define RDS_GROUP_TYPE_2B 5 /* Radio Text */ +#define RDS_GROUP_TYPE_3A 6 /* Application identification for ODA + * only */ +#define RDS_GROUP_TYPE_3B 7 /* Open data applications */ +#define RDS_GROUP_TYPE_4A 8 /* Clock-time and date */ +#define RDS_GROUP_TYPE_4B 9 /* Open data applications */ +#define RDS_GROUP_TYPE_5A 10 /* Transparent Data Channels (32 channels) + * or ODA */ +#define RDS_GROUP_TYPE_5B 11 /* Transparent Data Channels (32 channels) + * or ODA */ +#define RDS_GROUP_TYPE_6A 12 /* In House Applications or ODA */ +#define RDS_GROUP_TYPE_6B 13 /* In House Applications or ODA */ +#define RDS_GROUP_TYPE_7A 14 /* Radio Paging or ODA */ +#define RDS_GROUP_TYPE_7B 15 /* Open Data Applications */ +#define RDS_GROUP_TYPE_8A 16 /* Traffic Message Channel or ODA */ +#define RDS_GROUP_TYPE_8B 17 /* Open Data Applications */ +#define RDS_GROUP_TYPE_9A 18 /* Emergency warning system or ODA */ +#define RDS_GROUP_TYPE_9B 19 /* Open Data Applications */ +#define RDS_GROUP_TYPE_10A 20 /* Program Type Name */ +#define RDS_GROUP_TYPE_10B 21 /* Open Data Applications */ +#define RDS_GROUP_TYPE_11A 22 /* Open Data Applications */ +#define RDS_GROUP_TYPE_11B 23 /* Open Data Applications */ +#define RDS_GROUP_TYPE_12A 24 /* Open Data Applications */ +#define RDS_GROUP_TYPE_12B 25 /* Open Data Applications */ +#define RDS_GROUP_TYPE_13A 26 /* Enhanced Radio Paging or ODA */ +#define RDS_GROUP_TYPE_13B 27 /* Open Data Applications */ +#define RDS_GROUP_TYPE_14A 28 /* Enhanced Other Networks information */ +#define RDS_GROUP_TYPE_14B 29 /* Enhanced Other Networks information */ +#define RDS_GROUP_TYPE_15A 30 /* Defined in RBDS */ +#define RDS_GROUP_TYPE_15B 31 /* Fast switching information */ +#define NUM_DEFINED_RDS_GROUPS 32 /* Number of groups defined in RBDS + * standard */ + +/* Structure representing Generic packet of 64 bits. */ +struct rds_group_data { + u16 piCode; /* * Program ID */ + u16 offsetB; /* subject to group type */ + u16 offsetC; /* subject to group type */ + u16 offsetD; /* subject to group type */ +}; + +/* Structure representing Group 0A (Service Name) */ +struct rds_group0A { + u16 piCode; /* * Program ID */ + u16 offsetB; /* subject to group type */ + u8 freq[2]; /* alt frequency 0=1 */ + u8 text[2]; /* Name segment */ +}; + +/* Structure representing Group 0B (Service Name) */ +struct rds_group0B { + u16 piCode; /* * Program ID */ + u16 offsetB; /* subject to group type */ + u16 piCode_dup; /* Duplicate PI Code */ + u8 text[2]; /* station text */ +}; + +/* Structure representing Group 2A (Radio Text) (64 char) */ +struct rds_group2A { + u16 piCode; /* * Program ID */ + u16 offsetB; /* subject to group type */ + u8 text[4]; +}; + +/* Structure representing Group 2B (Radio Text) (32 char) */ +struct rds_group2B { + u16 piCode; /* * Program ID */ + u16 offsetB; /* subject to group type */ + u16 piCode_dup; /* Duplicate PI Code */ + u8 text[2]; +}; + +/* Structure representing all groups */ +union rds_msg { + struct rds_group2B gt2B; + struct rds_group2A gt2A; + struct rds_group0B gt0B; + struct rds_group0A gt0A; + struct rds_group_data gt00; +}; + +struct stfm1000_rds_state { + struct stfm1000_rds_bitstream bitstream; + struct stfm1000_rds_demod demod; + struct stfm1000_rds_pkt pkt; + struct stfm1000_rds_text text; + unsigned int reset_req : 1; +}; + +/* callback from rds etc. */ +void stfm1000_rds_reset(struct stfm1000_rds_state *rds); +void stfm1000_rds_start(struct stfm1000_rds_state *rds); +void stfm1000_rds_stop(struct stfm1000_rds_state *rds); + +/* call these from the monitor thread, but with interrupts disabled */ +int stfm1000_rds_mix_msg_get(struct stfm1000_rds_state *rds); +int stfm1000_rds_mix_msg_processed(struct stfm1000_rds_state *rds, + int mix_msg); +int stfm1000_rds_sdnominal_msg_get(struct stfm1000_rds_state *rds); +int stfm1000_rds_sdnominal_msg_processed(struct stfm1000_rds_state *rds, + int sdnominal_msg); +int stfm1000_rds_bits_available(struct stfm1000_rds_state *rds); +int stmf1000_rds_get_bit(struct stfm1000_rds_state *rds); + +/* called from audio handler (interrupt) */ +void stfm1000_rds_demod(struct stfm1000_rds_state *rds, const u16 *dri_data, + int total); + +/* call these from monitor thread, interrupts enabled */ +void stfm1000_rds_packet_bit(struct stfm1000_rds_state *rds, int bit); +int stfm1000_rds_packet_dequeue(struct stfm1000_rds_state *rds, u8 *buf); +void stfm1000_rds_process_packet(struct stfm1000_rds_state *rds, u8 *buffer); + +static inline int stfm1000_rds_get_reset_req(struct stfm1000_rds_state *rds) +{ + return rds->reset_req; +} + +/* GROUP_TYPE 0A-0B */ +int stfm1000_rds_get_ps(struct stfm1000_rds_state *rds, u8 *buffer, + int bufsize); + +/* GROUP_TYPE 2A */ +int stfm1000_rds_get_text(struct stfm1000_rds_state *rds, u8 *buffer, + int bufsize); + +#endif diff --git a/drivers/media/radio/stfm1000/stfm1000-regs.h b/drivers/media/radio/stfm1000/stfm1000-regs.h new file mode 100644 index 000000000000..c9476b7d67e1 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000-regs.h @@ -0,0 +1,165 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef STFM1000_REGS_H +#define STFM1000_REGS_H + +/* registers */ +#define STFM1000_TUNE1 0x00 +#define STFM1000_SDNOMINAL 0x04 +#define STFM1000_PILOTTRACKING 0x08 +#define STFM1000_INITIALIZATION1 0x10 +#define STFM1000_INITIALIZATION2 0x14 +#define STFM1000_INITIALIZATION3 0x18 +#define STFM1000_INITIALIZATION4 0x1C +#define STFM1000_INITIALIZATION5 0x20 +#define STFM1000_INITIALIZATION6 0x24 +#define STFM1000_REF 0x28 +#define STFM1000_LNA 0x2C +#define STFM1000_MIXFILT 0x30 +#define STFM1000_CLK1 0x34 +#define STFM1000_CLK2 0x38 +#define STFM1000_ADC 0x3C +#define STFM1000_AGC_CONTROL1 0x44 +#define STFM1000_AGC_CONTROL2 0x48 +#define STFM1000_DATAPATH 0x5C +#define STFM1000_RMS 0x60 +#define STFM1000_AGC_STAT 0x64 +#define STFM1000_SIGNALQUALITY 0x68 +#define STFM1000_DCEST 0x6C +#define STFM1000_RSSI_TONE 0x70 +#define STFM1000_PILOTCORRECTION 0x74 +#define STFM1000_ATTENTION 0x78 +#define STFM1000_CLK3 0x7C +#define STFM1000_CHIPID 0x80 + +/* number of registers */ +#define STFM1000_NUM_REGS ((0x80 + 4) / 4) + +#define STFM1000_FREQUENCY_100KHZ_MIN 758 +#define STFM1000_FREQUENCY_100KHZ_RANGE 325 +#define STFM1000_FREQUENCY_100KHZ_MAX (STFM1000_FREQUENCY_100KHZ_MIN + \ + STFM1000_FREQUENCY_100KHZ_RANGE) + +#define STFM1000_TUNE1_B2_MIX 0x001C0000 +#define STFM1000_TUNE1_CICOSR 0x00007E00 +#define STFM1000_TUNE1_PLL_DIV 0x000001FF + +#define STFM1000_CHIP_REV_TA1 0x00000001 +#define STFM1000_CHIP_REV_TA2 0x00000002 +#define STFM1000_CHIP_REV_TB1 0x00000011 +#define STFM1000_CHIP_REV_TB2 0x00000012 + +/* DATAPATH bits we use */ +#define STFM1000_DP_EN 0x01000000 +#define STFM1000_DB_ACCEPT 0x00010000 +#define STFM1000_SAI_CLK_DIV_MASK 0x7c +#define STFM1000_SAI_CLK_DIV_SHIFT 2 +#define STFM1000_SAI_CLK_DIV(x) \ + (((x) << STFM1000_SAI_CLK_DIV_SHIFT) & STFM1000_SAI_CLK_DIV_MASK) +#define STFM1000_SAI_EN 0x00000001 + +/* AGC_CONTROL1 bits we use */ +#define STFM1000_B2_BYPASS_AGC_CTL 0x00004000 +#define STFM1000_B2_BYPASS_FILT_MASK 0x0000000C +#define STFM1000_B2_BYPASS_FILT_SHIFT 2 +#define STFM1000_B2_BYPASS_FILT(x) \ + (((x) << STFM1000_B2_BYPASS_FILT_SHIFT) & STFM1000_B2_BYPASS_FILT_MASK) +#define STFM1000_B2_LNATH_MASK 0x001F0000 +#define STFM1000_B2_LNATH_SHIFT 16 +#define STFM1000_B2_LNATH(x) \ + (((x) << STFM1000_B2_LNATH_SHIFT) & STFM1000_B2_LNATH_MASK) + +/* AGC_STAT bits we use */ +#define STFM1000_AGCOUT_STAT_MASK 0x1F000000 +#define STFM1000_AGCOUT_STAT_SHIFT 24 +#define STFM1000_LNA_RMS_MASK 0x00001F00 +#define STFM1000_LNA_RMS_SHIFT 8 + +/* PILOTTRACKING bits we use */ +#define STFM1000_B2_PILOTTRACKING_EN 0x00008000 +#define STFM1000_B2_PILOTLPF_TIMECONSTANT_MASK 0x00000f00 +#define STFM1000_B2_PILOTLPF_TIMECONSTANT_SHIFT 8 +#define STFM1000_B2_PILOTLPF_TIMECONSTANT(x) \ + (((x) << STFM1000_B2_PILOTLPF_TIMECONSTANT_SHIFT) & \ + STFM1000_B2_PILOTLPF_TIMECONSTANT_MASK) +#define STFM1000_B2_PFDSCALE_MASK 0x000000f0 +#define STFM1000_B2_PFDSCALE_SHIFT 4 +#define STFM1000_B2_PFDSCALE(x) \ + (((x) << STFM1000_B2_PFDSCALE_SHIFT) & STFM1000_B2_PFDSCALE_MASK) +#define STFM1000_B2_PFDFILTER_SPEEDUP_MASK 0x0000000f +#define STFM1000_B2_PFDFILTER_SPEEDUP_SHIFT 0 +#define STFM1000_B2_PFDFILTER_SPEEDUP(x) \ + (((x) << STFM1000_B2_PFDFILTER_SPEEDUP_SHIFT) & \ + STFM1000_B2_PFDFILTER_SPEEDUP_MASK) + +/* PILOTCORRECTION bits we use */ +#define STFM1000_PILOTEST_TA2_MASK 0xff000000 +#define STFM1000_PILOTEST_TA2_SHIFT 24 +#define STFM1000_PILOTEST_TB2_MASK 0xfe000000 +#define STFM1000_PILOTEST_TB2_SHIFT 25 + +/* INITIALIZATION1 bits we use */ +#define STFM1000_B2_BYPASS_FILT_MASK 0x0000000C +#define STFM1000_B2_BYPASS_FILT_SHIFT 2 +#define STFM1000_B2_BYPASS_FILT(x) \ + (((x) << STFM1000_B2_BYPASS_FILT_SHIFT) & STFM1000_B2_BYPASS_FILT_MASK) + +/* INITIALIZATION2 bits we use */ +#define STFM1000_DRI_CLK_EN 0x80000000 +#define STFM1000_DEEMPH_50_75B 0x00000100 +#define STFM1000_RDS_ENABLE 0x00100000 +#define STFM1000_RDS_MIXOFFSET 0x00200000 + +/* INITIALIZATION3 bits we use */ +#define STFM1000_B2_NEAR_CHAN_MIX_MASK 0x1c000000 +#define STFM1000_B2_NEAR_CHAN_MIX_SHIFT 26 +#define STFM1000_B2_NEAR_CHAN_MIX(x) \ + (((x) << STFM1000_B2_NEAR_CHAN_MIX_SHIFT) & \ + STFM1000_B2_NEAR_CHAN_MIX_MASK) + +/* CLK1 bits we use */ +#define STFM1000_ENABLE_TAPDELAYFIX 0x00000020 + +/* REF bits we use */ +#define STFM1000_LNA_AMP1_IMPROVE_DISTORTION 0x08000000 + +/* LNA bits we use */ +#define STFM1000_AMP2_IMPROVE_DISTORTION 0x08000000 +#define STFM1000_ANTENNA_TUNECAP_MASK 0x001F0000 +#define STFM1000_ANTENNA_TUNECAP_SHIFT 16 +#define STFM1000_ANTENNA_TUNECAP(x) \ + (((x) << STFM1000_ANTENNA_TUNECAP_SHIFT) & \ + STFM1000_ANTENNA_TUNECAP_MASK) +#define STFM1000_IBIAS2_UP 0x00000008 +#define STFM1000_IBIAS2_DN 0x00000004 +#define STFM1000_IBIAS1_UP 0x00000002 +#define STFM1000_IBIAS1_DN 0x00000001 +#define STFM1000_USEATTEN_MASK 0x00600000 +#define STFM1000_USEATTEN_SHIFT 21 +#define STFM1000_USEATTEN(x) \ + (((x) << STFM1000_USEATTEN_SHIFT) & STFM1000_USEATTEN_MASK) + +/* SIGNALQUALITY bits we use */ +#define STFM1000_NEAR_CHAN_AMPLITUDE_MASK 0x0000007F +#define STFM1000_NEAR_CHAN_AMPLITUDE_SHIFT 0 +#define STFM1000_NEAR_CHAN_AMPLITUDE(x) \ + (((x) << STFM1000_NEAR_CHAN_AMPLITUDE_SHIFT) & \ + STFM1000_NEAR_CHAN_AMPLITUDE_MASK) + +/* precalc tables elements */ +struct stfm1000_tune1 { + unsigned int tune1; /* at least 32 bit */ + unsigned int sdnom; +}; + +#endif diff --git a/drivers/media/radio/stfm1000/stfm1000.h b/drivers/media/radio/stfm1000/stfm1000.h new file mode 100644 index 000000000000..5ae6f38db3b0 --- /dev/null +++ b/drivers/media/radio/stfm1000/stfm1000.h @@ -0,0 +1,254 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef STFM1000_H +#define STFM1000_H + +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/i2c.h> +#include <linux/list.h> +#include <linux/wait.h> +#include <linux/irq.h> +#include <media/videobuf-dma-sg.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <mach/dma.h> + +#include "stfm1000-regs.h" + +#include "stfm1000-filter.h" +#include "stfm1000-rds.h" + +struct stfm1000 { + struct list_head devlist; + int idx; + + struct i2c_client *client; + struct video_device radio; + + /* alsa */ + struct snd_card *card; + struct snd_pcm *pcm; + struct snd_pcm_substream *substream; + struct stmp3xxx_dma_descriptor *dma; + int desc_num; + int dma_ch; + int dma_irq; + int attn_irq; + + struct mutex state_lock; + int read_count; + int read_offset; + int blocks; + int blksize; + int bufsize; + + struct mutex deffered_work_lock; + struct execute_work snd_capture_start_work; + struct execute_work snd_capture_stop_work; + + int now_recording; + int alsa_initialized; + int stopping_recording; + + /* actual DRI buffer */ + dma_addr_t dri_phys; + void *dri_buf; + int dri_bufsz; + + /* various */ + u16 curvol; + int users; + int removed; + struct mutex xfer_lock; + u8 revid; + + unsigned int dbgflg; + + /* shadow registers */ + u32 shadow_regs[STFM1000_NUM_REGS]; + u32 reg_rw_set[(STFM1000_NUM_REGS + 31) / 32]; + u32 reg_ra_set[(STFM1000_NUM_REGS + 31) / 32]; + u32 reg_dirty_set[(STFM1000_NUM_REGS + 31) / 32]; + + /* tuning parameters (not everything is used for now) */ + u16 tune_rssi_th; /* sd_ctl_TuneRssiTh_u16 */ + u16 tune_mpx_dc_th; /* sd_ctl_TuneMpxDcTh_u16 */ + u16 adj_chan_th; /* sd_ctl_AdjChanTh_u16 */ + u16 pilot_est_th; /* sd_ctl_PilotEstTh_u16 */ + u16 coef_lna_turn_off_th; /* sd_ctl_pCoefLnaTurnOffTh_u16 */ + u16 coef_lna_turn_on_th; /* sd_ctl_pCoefLnaTurnOnTh_u16 */ + u16 reg_agc_ref_lna_off; /* sd_ctl_pRegAgcRefLnaOff_u16 */ + u16 reg_agc_ref_lna_on; /* sd_ctl_pRegAgcRefLnaOn_u16 */ + + u32 sdnominal_pivot; /* sd_ctl_SdnominalData_u32 */ + + /* jiffies of the next monitor cycle */ + unsigned long next_quality_monitor; + unsigned long next_agc_monitor; + + unsigned int mute : 1; /* XXX */ + unsigned int lna_driving : 1; /* sd_ctl_LnaDriving_u1 */ + unsigned int weak_signal : 1; /* sd_ctl_WeakSignal_u1 */ + unsigned int is_station : 1; /* XXX */ + unsigned int force_mono : 1; /* XXX */ + unsigned int signal_indicator : 1; /* XXX */ + unsigned int stereo_indicator : 1; /* XXX */ + unsigned int agc_monitor : 1; /* XXX */ + unsigned int quality_monitor : 1; /* XXX */ + unsigned int pilot_present : 1; /* sd_ctl_PilotPresent_u1 */ + unsigned int prev_pilot_present : 1; /* XXX */ + unsigned int stereo : 1; + unsigned int active : 1; /* set when audio enabled */ + unsigned int rds_enable : 1; /* set when rds is enabled */ + unsigned int rds_present : 1; /* RDS info present */ + unsigned int rds_sync : 1; /* RDS force sync */ + unsigned int rds_demod_running : 1; /* RDS demod is running ATM */ + unsigned int rds_sdnominal_adapt : 1; /* adapt for better recept. */ + unsigned int rds_phase_pop : 1; /* enable phase pop */ + unsigned int rds_info : 1; /* print debugging info RDS */ + unsigned int tuning_grid_50KHz : 1; /* tuning grid of 50Khz */ + u32 rssi; /* rssi last decoded frame */ + u16 rssi_dc_est_log; + u16 signal_strength; /* is rssi_dc_est_log */ + u16 rds_signal_th; /* RDS threshold */ + s16 mpx_dc; /* sd_ctl_ShadowToneData_i16 */ + + u32 tune_cap_a_f; /* float! sd_ctl_TuneCapA_f */ + u32 tune_cap_b_f; /* float! sd_ctl_TuneCapB_f */ + + int monitor_period; /* period of the monitor */ + int quality_monitor_period; /* update period in ms */ + int agc_monitor_period; /* update period in ms */ + + int georegion; /* current graphical region */ + + /* last tuned frequency */ + int freq; /* 88.0 = 8800 */ + + /* weak signal processing filter state */ + struct stfm1000_filter_parms filter_parms; + + /* state of rds */ + spinlock_t rds_lock; + struct stfm1000_rds_state rds_state; + unsigned int rds_pkt_bad; + unsigned int rds_pkt_good; + unsigned int rds_pkt_recovered; + unsigned int rds_pkt_lost_sync; + unsigned int rds_bit_overruns; + + /* monitor thread */ + wait_queue_head_t thread_wait; + unsigned long thread_events; + struct task_struct *thread; +}; + +#define EVENT_RDS_BITS 0 +#define EVENT_RDS_MIXFILT 1 +#define EVENT_RDS_SDNOMINAL 2 +#define EVENT_RDS_RESET 3 + +#define STFM1000_DBGFLG_I2C (1 << 0) + +static inline struct stfm1000 *stfm1000_from_file(struct file *file) +{ + return container_of(video_devdata(file), struct stfm1000, radio); +} + +/* in stfm1000-i2c.c */ + +/* setup reg set */ +void stfm1000_setup_reg_set(struct stfm1000 *stfm1000); + +/* direct access to registers bypassing the shadow register set */ +int stfm1000_raw_read(struct stfm1000 *stfm1000, int reg, u32 *value); +int stfm1000_raw_write(struct stfm1000 *stfm1000, int reg, u32 value); + +/* access using the shadow register set */ +int stfm1000_write(struct stfm1000 *stfm1000, int reg, u32 value); +int stfm1000_read(struct stfm1000 *stfm1000, int reg, u32 *value); +int stfm1000_write_masked(struct stfm1000 *stfm1000, int reg, u32 value, + u32 mask); +int stfm1000_set_bits(struct stfm1000 *stfm1000, int reg, u32 value); +int stfm1000_clear_bits(struct stfm1000 *stfm1000, int reg, u32 value); + +struct stfm1000_reg { + unsigned int regno; + u32 value; +}; + +#define STFM1000_REG_END -1 +#define STFM1000_REG_DELAY -2 + +#define STFM1000_REG_SET_BITS_MASK 0x1000 +#define STFM1000_REG_CLEAR_BITS_MASK 0x2000 + +#define STFM1000_REG(r, v) \ + { .regno = STFM1000_ ## r , .value = (v) } + +#define STFM1000_END \ + { .regno = STFM1000_REG_END } + +#define STFM1000_DELAY(x) \ + { .regno = STFM1000_REG_DELAY, .value = (x) } + +#define STFM1000_REG_SETBITS(r, v) \ + { .regno = STFM1000_ ## r | STFM1000_REG_SET_BITS_MASK, \ + .value = (v) } + +#define STFM1000_REG_CLRBITS(r, v) \ + { .regno = STFM1000_ ## r | STFM1000_REG_CLEAR_BITS_MASK, \ + .value = (v) } + +int stfm1000_write_regs(struct stfm1000 *stfm1000, + const struct stfm1000_reg *reg); + +/* in stfm1000-precalc.c */ +extern const struct stfm1000_tune1 +stfm1000_tune1_table[STFM1000_FREQUENCY_100KHZ_RANGE]; + +/* exported for use by alsa driver */ + +struct stfm1000_dri_sample { + /* L+R */ + u16 l_plus_r; + /* L-R */ + u16 l_minus_r; + /* Rx signal strength channel */ + u16 rssi; + /* Radio data service channel */ + u16 rds; +}; + +struct stfm1000_alsa_ops { + int (*init)(struct stfm1000 *stfm1000); + void (*release)(struct stfm1000 *stfm1000); + void (*dma_irq)(struct stfm1000 *stfm1000); + void (*attn_irq)(struct stfm1000 *stfm1000); +}; + +extern struct list_head stfm1000_devlist; +extern struct stfm1000_alsa_ops *stfm1000_alsa_ops; + +/* needed for setting the interrupt handlers from alsa */ +irqreturn_t stfm1000_dri_attn_irq(int irq, void *dev_id); +irqreturn_t stfm1000_dri_dma_irq(int irq, void *dev_id); +void stfm1000_decode_block(struct stfm1000 *stfm1000, const s16 *src, s16 *dst, int count); +void stfm1000_take_down(struct stfm1000 *stfm1000); +void stfm1000_bring_up(struct stfm1000 *stfm1000); +void stfm1000_tune_current(struct stfm1000 *stfm1000); + +void stfm1000_monitor_signal(struct stfm1000 *stfm1000, int bit); + +#endif diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 33d03d92bf03..3e1feb550e4b 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -549,6 +549,18 @@ config VIDEO_MXC_OUTPUT source "drivers/media/video/mxc/output/Kconfig" +config VIDEO_PXP + tristate "STMP3xxx PxP" + depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_STMP3XXX + select VIDEOBUF_DMA_CONTIG + ---help--- + This is a video4linux driver for the Freescale PxP + (Pixel Pipeline). This module supports output overlay of + the STMP3xxx framebuffer on a video stream. + + To compile this driver as a module, choose M here: the + module will be called pxp. + config VIDEO_MXC_OPL tristate depends on VIDEO_DEV && ARCH_MXC diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ca57b213c445..878f39c9f574 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc/output/ obj-$(CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT) += mxc/output/ obj-$(CONFIG_VIDEO_MXC_EMMA_OUTPUT) += mxc/output/ obj-$(CONFIG_VIDEO_MXC_OPL) += mxc/opl/ +obj-$(CONFIG_VIDEO_PXP) += pxp.o obj-$(CONFIG_VIDEO_CPIA) += cpia.o obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o diff --git a/drivers/media/video/pxp.c b/drivers/media/video/pxp.c new file mode 100644 index 000000000000..0ffe0f68c542 --- /dev/null +++ b/drivers/media/video/pxp.c @@ -0,0 +1,1225 @@ +/* + * Freescale STMP378X PxP driver + * + * Author: Matt Porter <mporter@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/dma-mapping.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/vmalloc.h> + +#include <media/videobuf-dma-contig.h> +#include <media/v4l2-common.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ioctl.h> + +#include <mach/stmp3xxx_regs.h> +#include <mach/regs-pxp.h> + +#include "pxp.h" + +#define PXP_DRIVER_NAME "stmp3xxx-pxp" +#define PXP_DRIVER_MAJOR 1 +#define PXP_DRIVER_MINOR 0 + +#define PXP_DEF_BUFS 2 +#define PXP_MIN_PIX 8 + +#define V4L2_OUTPUT_TYPE_INTERNAL 4 + +static struct pxp_data_format pxp_s0_formats[] = { + { + .name = "24-bit RGB", + .bpp = 4, + .fourcc = V4L2_PIX_FMT_RGB24, + .colorspace = V4L2_COLORSPACE_SRGB, + .ctrl_s0_fmt = BV_PXP_CTRL_S0_FORMAT__RGB888, + }, { + .name = "16-bit RGB 5:6:5", + .bpp = 2, + .fourcc = V4L2_PIX_FMT_RGB565, + .colorspace = V4L2_COLORSPACE_SRGB, + .ctrl_s0_fmt = BV_PXP_CTRL_S0_FORMAT__RGB565, + }, { + .name = "16-bit RGB 5:5:5", + .bpp = 2, + .fourcc = V4L2_PIX_FMT_RGB555, + .colorspace = V4L2_COLORSPACE_SRGB, + .ctrl_s0_fmt = BV_PXP_CTRL_S0_FORMAT__RGB555, + }, { + .name = "YUV 4:2:0 Planar", + .bpp = 2, + .fourcc = V4L2_PIX_FMT_YUV420, + .colorspace = V4L2_COLORSPACE_JPEG, + .ctrl_s0_fmt = BV_PXP_CTRL_S0_FORMAT__YUV420, + }, { + .name = "YUV 4:2:2 Planar", + .bpp = 2, + .fourcc = V4L2_PIX_FMT_YUV422P, + .colorspace = V4L2_COLORSPACE_JPEG, + .ctrl_s0_fmt = BV_PXP_CTRL_S0_FORMAT__YUV422, + }, +}; + +struct v4l2_queryctrl pxp_controls[] = { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical Flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Rotation", + .minimum = 0, + .maximum = 270, + .step = 90, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_PRIVATE_BASE + 1, + .name = "Background Color", + .minimum = 0, + .maximum = 0xFFFFFF, + .step = 1, + .default_value = 0, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_PRIVATE_BASE + 2, + .name = "YUV Colorspace", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, +}; + +static void pxp_set_ctrl(struct pxps *pxp) +{ + u32 ctrl; + + ctrl = BF_PXP_CTRL_S0_FORMAT(pxp->s0_fmt->ctrl_s0_fmt); + ctrl |= + BF_PXP_CTRL_OUTPUT_RGB_FORMAT(BV_PXP_CTRL_OUTPUT_RGB_FORMAT__RGB888); + ctrl |= BM_PXP_CTRL_CROP; + + if (pxp->scaling) + ctrl |= BM_PXP_CTRL_SCALE; + if (pxp->vflip) + ctrl |= BM_PXP_CTRL_VFLIP; + if (pxp->hflip) + ctrl |= BM_PXP_CTRL_HFLIP; + if (pxp->rotate) + ctrl |= BF_PXP_CTRL_ROTATE(pxp->rotate/90); + + ctrl |= BM_PXP_CTRL_IRQ_ENABLE; + if (pxp->active) + ctrl |= BM_PXP_CTRL_ENABLE; + + HW_PXP_CTRL_WR(ctrl); +} + +static void pxp_set_rgbbuf(struct pxps *pxp) +{ + HW_PXP_RGBBUF_WR(pxp->outb_phys); + /* Always equal to the FB size */ + HW_PXP_RGBSIZE_WR(BF_PXP_RGBSIZE_WIDTH(pxp->fb.fmt.width) | + BF_PXP_RGBSIZE_HEIGHT(pxp->fb.fmt.height)); +} + +static void pxp_set_colorkey(struct pxps *pxp) +{ + /* Low and high are set equal. V4L does not allow a chromakey range */ + HW_PXP_S0COLORKEYLOW_WR(pxp->chromakey); + HW_PXP_S0COLORKEYHIGH_WR(pxp->chromakey); +} + +static void pxp_set_oln(struct pxps *pxp) +{ + HW_PXP_OLn_WR(0, (u32)pxp->fb.base); + HW_PXP_OLnSIZE_WR(0, BF_PXP_OLnSIZE_WIDTH(pxp->fb.fmt.width >> 3) | + BF_PXP_OLnSIZE_HEIGHT(pxp->fb.fmt.height >> 3)); +} + +static void pxp_set_olparam(struct pxps *pxp) +{ + u32 olparam; + struct v4l2_pix_format *fmt = &pxp->fb.fmt; + + olparam = BF_PXP_OLnPARAM_ALPHA(pxp->global_alpha); + if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) + olparam |= + BF_PXP_OLnPARAM_FORMAT(BV_PXP_OLnPARAM_FORMAT__RGB888); + else + olparam |= + BF_PXP_OLnPARAM_FORMAT(BV_PXP_OLnPARAM_FORMAT__RGB565); + if (pxp->global_alpha_state) + olparam |= BF_PXP_OLnPARAM_ALPHA_CNTL( + BV_PXP_OLnPARAM_ALPHA_CNTL__Override); + if (pxp->chromakey_state) + olparam |= BM_PXP_OLnPARAM_ENABLE_COLORKEY; + if (pxp->overlay_state) + olparam |= BM_PXP_OLnPARAM_ENABLE; + HW_PXP_OLnPARAM_WR(0, olparam); +} + +static void pxp_set_s0param(struct pxps *pxp) +{ + u32 s0param; + + s0param = BF_PXP_S0PARAM_XBASE(pxp->drect.left >> 3); + s0param |= BF_PXP_S0PARAM_YBASE(pxp->drect.top >> 3); + s0param |= BF_PXP_S0PARAM_WIDTH(pxp->srect.width >> 3); + s0param |= BF_PXP_S0PARAM_HEIGHT(pxp->srect.height >> 3); + HW_PXP_S0PARAM_WR(s0param); +} + +static void pxp_set_s0crop(struct pxps *pxp) +{ + u32 s0crop; + + s0crop = BF_PXP_S0CROP_XBASE(pxp->srect.left >> 3); + s0crop |= BF_PXP_S0CROP_YBASE(pxp->srect.top >> 3); + s0crop |= BF_PXP_S0CROP_WIDTH(pxp->drect.width >> 3); + s0crop |= BF_PXP_S0CROP_HEIGHT(pxp->drect.height >> 3); + HW_PXP_S0CROP_WR(s0crop); +} + +static int pxp_set_scaling(struct pxps *pxp) +{ + int ret = 0; + u32 xscale, yscale, s0scale; + + if ((pxp->s0_fmt->fourcc != V4L2_PIX_FMT_YUV420) && + (pxp->s0_fmt->fourcc != V4L2_PIX_FMT_YUV422P)) { + pxp->scaling = 0; + ret = -EINVAL; + goto out; + } + + if ((pxp->srect.width == pxp->drect.width) && + (pxp->srect.height == pxp->drect.height)) { + pxp->scaling = 0; + goto out; + } + + pxp->scaling = 1; + xscale = pxp->srect.width * 0x1000 / pxp->drect.width; + yscale = pxp->srect.height * 0x1000 / pxp->drect.height; + s0scale = BF_PXP_S0SCALE_YSCALE(yscale) | + BF_PXP_S0SCALE_XSCALE(xscale); + HW_PXP_S0SCALE_WR(s0scale); + +out: + pxp_set_ctrl(pxp); + + return ret; +} + +static int pxp_set_fbinfo(struct pxps *pxp) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct v4l2_framebuffer *fb = &pxp->fb; + int err; + + err = stmp3xxxfb_get_info(&var, &fix); + + fb->fmt.width = var.xres; + fb->fmt.height = var.yres; + if (var.bits_per_pixel == 16) + fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565; + else + fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24; + fb->base = (void *)fix.smem_start; + return err; +} + +static void pxp_set_s0bg(struct pxps *pxp) +{ + HW_PXP_S0BACKGROUND_WR(pxp->s0_bgcolor); +} + +static void pxp_set_csc(struct pxps *pxp) +{ + if (pxp->yuv) { + /* YUV colorspace */ + HW_PXP_CSCCOEFF0_WR(0x04030000); + HW_PXP_CSCCOEFF1_WR(0x01230208); + HW_PXP_CSCCOEFF2_WR(0x076b079c); + } else { + /* YCrCb colorspace */ + HW_PXP_CSCCOEFF0_WR(0x84ab01f0); + HW_PXP_CSCCOEFF1_WR(0x01230204); + HW_PXP_CSCCOEFF2_WR(0x0730079c); + } +} + +static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc) +{ + + if (vc->id == V4L2_CID_HFLIP) + pxp->hflip = vc->value; + else if (vc->id == V4L2_CID_VFLIP) + pxp->vflip = vc->value; + else if (vc->id == V4L2_CID_PRIVATE_BASE) { + if (vc->value % 90) + return -ERANGE; + pxp->rotate = vc->value; + } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) { + pxp->s0_bgcolor = vc->value; + pxp_set_s0bg(pxp); + } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) { + pxp->yuv = vc->value; + pxp_set_csc(pxp); + } + + pxp_set_ctrl(pxp); + + return 0; +} + +static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc) +{ + if (vc->id == V4L2_CID_HFLIP) + vc->value = pxp->hflip; + else if (vc->id == V4L2_CID_VFLIP) + vc->value = pxp->vflip; + else if (vc->id == V4L2_CID_PRIVATE_BASE) + vc->value = pxp->rotate; + else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) + vc->value = pxp->s0_bgcolor; + else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) + vc->value = pxp->yuv; + + return 0; +} + +static int pxp_enumoutput(struct file *file, void *fh, + struct v4l2_output *o) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + if ((o->index < 0) || (o->index > 1)) + return -EINVAL; + + memset(o, 0, sizeof(struct v4l2_output)); + if (o->index == 0) { + strcpy(o->name, "PxP Display Output"); + pxp->output = 0; + } else { + strcpy(o->name, "PxP Virtual Output"); + pxp->output = 1; + } + o->type = V4L2_OUTPUT_TYPE_INTERNAL; + o->std = 0; + o->reserved[0] = pxp->outb_phys; + + return 0; +} + +static int pxp_g_output(struct file *file, void *fh, + unsigned int *i) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + *i = pxp->output; + + return 0; +} + +static int pxp_s_output(struct file *file, void *fh, + unsigned int i) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + struct v4l2_pix_format *fmt = &pxp->fb.fmt; + int bpp; + + if ((i < 0) || (i > 1)) + return -EINVAL; + + if (pxp->outb) + goto out; + + /* Output buffer is same format as fbdev */ + if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) + bpp = 4; + else + bpp = 2; + + pxp->outb = kmalloc(fmt->width * fmt->height * bpp, GFP_KERNEL); + pxp->outb_phys = virt_to_phys(pxp->outb); + dma_map_single(NULL, pxp->outb, + fmt->width * fmt->height * bpp, DMA_TO_DEVICE); + +out: + pxp_set_rgbbuf(pxp); + + return 0; +} + +static int pxp_enum_fmt_video_output(struct file *file, void *fh, + struct v4l2_fmtdesc *fmt) +{ + enum v4l2_buf_type type = fmt->type; + int index = fmt->index; + + if ((fmt->index < 0) || (fmt->index >= ARRAY_SIZE(pxp_s0_formats))) + return -EINVAL; + + memset(fmt, 0, sizeof(struct v4l2_fmtdesc)); + fmt->index = index; + fmt->type = type; + fmt->pixelformat = pxp_s0_formats[index].fourcc; + strcpy(fmt->description, pxp_s0_formats[index].name); + + return 0; +} + +static int pxp_g_fmt_video_output(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct v4l2_pix_format *pf = &f->fmt.pix; + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + struct pxp_data_format *fmt = pxp->s0_fmt; + + pf->width = pxp->srect.width; + pf->height = pxp->srect.height; + pf->pixelformat = fmt->fourcc; + pf->field = V4L2_FIELD_NONE; + pf->bytesperline = fmt->bpp * pf->width; + pf->sizeimage = pf->bytesperline * pf->height; + pf->colorspace = fmt->colorspace; + pf->priv = 0; + + return 0; +} + +static struct pxp_data_format *pxp_get_format(struct v4l2_format *f) +{ + struct pxp_data_format *fmt; + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) { + fmt = &pxp_s0_formats[i]; + if (fmt->fourcc == f->fmt.pix.pixelformat) + break; + } + + if (i == ARRAY_SIZE(pxp_s0_formats)) + return NULL; + + return &pxp_s0_formats[i]; +} + +static int pxp_try_fmt_video_output(struct file *file, void *fh, + struct v4l2_format *f) +{ + int w = f->fmt.pix.width; + int h = f->fmt.pix.height; + struct pxp_data_format *fmt = pxp_get_format(f); + + if (!fmt) + return -EINVAL; + + w = min(w, 2040); + w = max(w, 8); + h = min(h, 2040); + h = max(h, 8); + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.width = w; + f->fmt.pix.height = h; + f->fmt.pix.pixelformat = fmt->fourcc; + + return 0; +} + +static int pxp_s_fmt_video_output(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + struct v4l2_pix_format *pf = &f->fmt.pix; + int ret = pxp_try_fmt_video_output(file, fh, f); + + if (ret == 0) { + pxp->s0_fmt = pxp_get_format(f); + pxp->srect.width = pf->width; + pxp->srect.height = pf->height; + pxp_set_ctrl(pxp); + pxp_set_s0param(pxp); + } + + return ret; +} + +static int pxp_g_fmt_output_overlay(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + struct v4l2_window *wf = &f->fmt.win; + + memset(wf, 0, sizeof(struct v4l2_window)); + wf->chromakey = pxp->chromakey; + wf->global_alpha = pxp->global_alpha; + wf->field = V4L2_FIELD_NONE; + wf->clips = NULL; + wf->clipcount = 0; + wf->bitmap = NULL; + wf->w.left = pxp->srect.left; + wf->w.top = pxp->srect.top; + wf->w.width = pxp->srect.width; + wf->w.height = pxp->srect.height; + + return 0; +} + +static int pxp_try_fmt_output_overlay(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + struct v4l2_window *wf = &f->fmt.win; + u32 chromakey = wf->chromakey; + u8 global_alpha = wf->global_alpha; + + pxp_g_fmt_output_overlay(file, fh, f); + + wf->chromakey = chromakey; + wf->global_alpha = global_alpha; + + /* Constrain parameters to the input buffer */ + wf->w.left = pxp->srect.left; + wf->w.top = pxp->srect.top; + wf->w.width = pxp->srect.width; + wf->w.height = pxp->srect.height; + + return 0; +} + +static int pxp_s_fmt_output_overlay(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + struct v4l2_window *wf = &f->fmt.win; + int ret = pxp_try_fmt_output_overlay(file, fh, f); + + if (ret == 0) { + pxp->srect.left = wf->w.left; + pxp->srect.top = wf->w.top; + pxp->srect.width = wf->w.width; + pxp->srect.height = wf->w.height; + pxp->global_alpha = wf->global_alpha; + pxp->chromakey = wf->chromakey; + pxp_set_s0param(pxp); + pxp_set_s0crop(pxp); + pxp_set_scaling(pxp); + pxp_set_olparam(pxp); + pxp_set_colorkey(pxp); + } + + return ret; +} + +static int pxp_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *r) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + return videobuf_reqbufs(&pxp->s0_vbq, r); +} + +static int pxp_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + return videobuf_querybuf(&pxp->s0_vbq, b); +} + +static int pxp_qbuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + return videobuf_qbuf(&pxp->s0_vbq, b); +} + +static int pxp_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK); +} + +static int pxp_streamon(struct file *file, void *priv, + enum v4l2_buf_type t) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + int ret = 0; + + if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT)) + return -EINVAL; + + ret = videobuf_streamon(&pxp->s0_vbq); + + if (!ret && (pxp->output == 0)) + stmp3xxxfb_cfg_pxp(1, pxp->outb_phys); + + return ret; +} + +static int pxp_streamoff(struct file *file, void *priv, + enum v4l2_buf_type t) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + int ret = 0; + + if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT)) + return -EINVAL; + + ret = videobuf_streamoff(&pxp->s0_vbq); + + if (!ret) + stmp3xxxfb_cfg_pxp(0, 0); + + return ret; +} + +static int pxp_buf_setup(struct videobuf_queue *q, + unsigned int *count, unsigned *size) +{ + struct pxps *pxp = q->priv_data; + + *size = pxp->srect.width * pxp->srect.height * pxp->s0_fmt->bpp; + + if (0 == *count) + *count = PXP_DEF_BUFS; + + return 0; +} + +static void pxp_buf_free(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + if (in_interrupt()) + BUG(); + + videobuf_dma_contig_free(q, vb); + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static int pxp_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct pxps *pxp = q->priv_data; + int ret = 0; + + vb->width = pxp->srect.width; + vb->height = pxp->srect.height; + vb->size = vb->width * vb->height * pxp->s0_fmt->bpp; + vb->field = V4L2_FIELD_NONE; + vb->state = VIDEOBUF_NEEDS_INIT; + + + ret = videobuf_iolock(q, vb, NULL); + if (ret) + goto fail; + vb->state = VIDEOBUF_PREPARED; + + return 0; + +fail: + pxp_buf_free(q, vb); + return ret; +} + +static void pxp_buf_output(struct pxps *pxp) +{ + dma_addr_t Y, U, V; + + if (pxp->active) { + pxp->active->state = VIDEOBUF_ACTIVE; + Y = videobuf_to_dma_contig(pxp->active); + HW_PXP_S0BUF_WR(Y); + if ((pxp->s0_fmt->fourcc == V4L2_PIX_FMT_YUV420) || + (pxp->s0_fmt->fourcc == V4L2_PIX_FMT_YUV422P)) { + int s = 1; /* default to YUV 4:2:2 */ + if (pxp->s0_fmt->fourcc == V4L2_PIX_FMT_YUV420) + s = 2; + U = Y + (pxp->srect.width * pxp->srect.height); + V = U + ((pxp->srect.width * pxp->srect.height) >> s); + HW_PXP_S0UBUF_WR(U); + HW_PXP_S0VBUF_WR(V); + } + HW_PXP_CTRL_SET(BM_PXP_CTRL_ENABLE); + } +} + +static void pxp_buf_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct pxps *pxp = q->priv_data; + unsigned long flags; + + spin_lock_irqsave(&pxp->lock, flags); + + list_add_tail(&vb->queue, &pxp->outq); + vb->state = VIDEOBUF_QUEUED; + + if (!pxp->active) { + pxp->active = vb; + pxp_buf_output(pxp); + } + + spin_unlock_irqrestore(&pxp->lock, flags); +} + +static void pxp_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + pxp_buf_free(q, vb); +} + +static struct videobuf_queue_ops pxp_vbq_ops = { + .buf_setup = pxp_buf_setup, + .buf_prepare = pxp_buf_prepare, + .buf_queue = pxp_buf_queue, + .buf_release = pxp_buf_release, +}; + +static int pxp_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + memset(cap, 0, sizeof(*cap)); + strcpy(cap->driver, "pxp"); + strcpy(cap->card, "pxp"); + strlcpy(cap->bus_info, pxp->pdev->dev.bus_id, sizeof(cap->bus_info)); + + cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR; + + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY | + V4L2_CAP_STREAMING; + + return 0; +} + +static int pxp_g_fbuf(struct file *file, void *priv, + struct v4l2_framebuffer *fb) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + memset(fb, 0, sizeof(*fb)); + + fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | + V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_LOCAL_ALPHA | + V4L2_FBUF_CAP_GLOBAL_ALPHA; + + if (pxp->global_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + if (pxp->local_alpha_state) + fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; + if (pxp->chromakey_state) + fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; + + return 0; +} + +static int pxp_s_fbuf(struct file *file, void *priv, + struct v4l2_framebuffer *fb) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + pxp->overlay_state = + (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; + pxp->global_alpha_state = + (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; + pxp->local_alpha_state = + (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; + /* Global alpha overrides local alpha if both are requested */ + if (pxp->global_alpha_state && pxp->local_alpha_state) + pxp->local_alpha_state = 0; + pxp->chromakey_state = + (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; + + pxp_set_olparam(pxp); + pxp_set_s0crop(pxp); + pxp_set_scaling(pxp); + + return 0; +} + +static int pxp_g_crop(struct file *file, void *fh, + struct v4l2_crop *c) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) + return -EINVAL; + + c->c.left = pxp->drect.left; + c->c.top = pxp->drect.top; + c->c.width = pxp->drect.width; + c->c.height = pxp->drect.height; + + return 0; +} + +static int pxp_s_crop(struct file *file, void *fh, + struct v4l2_crop *c) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + int l = c->c.left; + int t = c->c.top; + int w = c->c.width; + int h = c->c.height; + int fbw = pxp->fb.fmt.width; + int fbh = pxp->fb.fmt.height; + + if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) + return -EINVAL; + + /* Constrain parameters to FB limits */ + w = min(w, fbw); + w = max(w, PXP_MIN_PIX); + h = min(h, fbh); + h = max(h, PXP_MIN_PIX); + if ((l + w) > fbw) + l = 0; + if ((t + h) > fbh) + t = 0; + + /* Round up values to PxP pixel block */ + l = roundup(l, PXP_MIN_PIX); + t = roundup(t, PXP_MIN_PIX); + w = roundup(w, PXP_MIN_PIX); + h = roundup(h, PXP_MIN_PIX); + + pxp->drect.left = l; + pxp->drect.top = t; + pxp->drect.width = w; + pxp->drect.height = h; + + pxp_set_s0param(pxp); + pxp_set_s0crop(pxp); + pxp_set_scaling(pxp); + + return 0; +} + +static int pxp_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (qc->id && qc->id == pxp_controls[i].id) { + memcpy(qc, &(pxp_controls[i]), sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + +static int pxp_g_ctrl(struct file *file, void *priv, + struct v4l2_control *vc) +{ + int i; + + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (vc->id == pxp_controls[i].id) + return pxp_get_cstate(pxp, vc); + + return -EINVAL; +} + +static int pxp_s_ctrl(struct file *file, void *priv, + struct v4l2_control *vc) +{ + int i; + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) + if (vc->id == pxp_controls[i].id) { + if (vc->value < pxp_controls[i].minimum || + vc->value > pxp_controls[i].maximum) + return -ERANGE; + return pxp_set_cstate(pxp, vc); + } + + return -EINVAL; +} + +void pxp_release(struct video_device *vfd) +{ + struct pxps *pxp = video_get_drvdata(vfd); + + spin_lock(&pxp->lock); + video_device_release(vfd); + spin_unlock(&pxp->lock); +} + +static int pxp_hw_init(struct pxps *pxp) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + int err; + + err = stmp3xxxfb_get_info(&var, &fix); + if (err) + return err; + + /* Pull PxP out of reset */ + HW_PXP_CTRL_WR(0); + + /* Config defaults */ + pxp->active = NULL; + + pxp->s0_fmt = &pxp_s0_formats[0]; + pxp->drect.left = pxp->srect.left = 0; + pxp->drect.top = pxp->srect.top = 0; + pxp->drect.width = pxp->srect.width = var.xres; + pxp->drect.height = pxp->srect.height = var.yres; + pxp->s0_bgcolor = 0; + + pxp->output = 0; + err = pxp_set_fbinfo(pxp); + if (err) + return err; + + pxp->scaling = 0; + pxp->hflip = 0; + pxp->vflip = 0; + pxp->rotate = 0; + pxp->yuv = 0; + + pxp->overlay_state = 0; + pxp->global_alpha_state = 0; + pxp->global_alpha = 0; + pxp->local_alpha_state = 0; + pxp->chromakey_state = 0; + pxp->chromakey = 0; + + /* Write default h/w config */ + pxp_set_ctrl(pxp); + pxp_set_s0param(pxp); + pxp_set_s0crop(pxp); + pxp_set_oln(pxp); + pxp_set_olparam(pxp); + pxp_set_colorkey(pxp); + pxp_set_csc(pxp); + + return 0; +} + +static int pxp_open(struct inode *inode, struct file *file) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + int ret = 0; + + mutex_lock(&pxp->mutex); + pxp->users++; + + if (pxp->users > 1) { + pxp->users--; + ret = -EBUSY; + goto out; + } + +out: + mutex_unlock(&pxp->mutex); + if (ret) + return ret; + + videobuf_queue_dma_contig_init(&pxp->s0_vbq, + &pxp_vbq_ops, + &pxp->pdev->dev, + &pxp->lock, + V4L2_BUF_TYPE_VIDEO_OUTPUT, + V4L2_FIELD_NONE, + sizeof(struct videobuf_buffer), + pxp); + + return 0; +} + +static int pxp_close(struct inode *inode, struct file *file) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + + videobuf_stop(&pxp->s0_vbq); + videobuf_mmap_free(&pxp->s0_vbq); + + mutex_lock(&pxp->mutex); + pxp->users--; + mutex_unlock(&pxp->mutex); + + return 0; +} + +static int pxp_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct pxps *pxp = video_get_drvdata(video_devdata(file)); + int ret; + + ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma); + + return ret; +} + +static const struct file_operations pxp_fops = { + .owner = THIS_MODULE, + .open = pxp_open, + .release = pxp_close, + .ioctl = video_ioctl2, + .mmap = pxp_mmap, +}; + +static const struct v4l2_ioctl_ops pxp_ioctl_ops = { + .vidioc_querycap = pxp_querycap, + + .vidioc_reqbufs = pxp_reqbufs, + .vidioc_querybuf = pxp_querybuf, + .vidioc_qbuf = pxp_qbuf, + .vidioc_dqbuf = pxp_dqbuf, + + .vidioc_streamon = pxp_streamon, + .vidioc_streamoff = pxp_streamoff, + + .vidioc_enum_output = pxp_enumoutput, + .vidioc_g_output = pxp_g_output, + .vidioc_s_output = pxp_s_output, + + .vidioc_enum_fmt_vid_out = pxp_enum_fmt_video_output, + .vidioc_try_fmt_vid_out = pxp_try_fmt_video_output, + .vidioc_g_fmt_vid_out = pxp_g_fmt_video_output, + .vidioc_s_fmt_vid_out = pxp_s_fmt_video_output, + + .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay, + .vidioc_g_fmt_vid_out_overlay = pxp_g_fmt_output_overlay, + .vidioc_s_fmt_vid_out_overlay = pxp_s_fmt_output_overlay, + + .vidioc_g_fbuf = pxp_g_fbuf, + .vidioc_s_fbuf = pxp_s_fbuf, + + .vidioc_g_crop = pxp_g_crop, + .vidioc_s_crop = pxp_s_crop, + + .vidioc_queryctrl = pxp_queryctrl, + .vidioc_g_ctrl = pxp_g_ctrl, + .vidioc_s_ctrl = pxp_s_ctrl, +}; + +static const struct video_device pxp_template = { + .name = "PxP", + .vfl_type = VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | + VID_TYPE_SCALES, + .fops = &pxp_fops, + .release = pxp_release, + .minor = -1, + .ioctl_ops = &pxp_ioctl_ops, +}; + +static irqreturn_t pxp_irq(int irq, void *dev_id) +{ + struct pxps *pxp = (struct pxps *)dev_id; + struct videobuf_buffer *vb; + unsigned long flags; + + spin_lock_irqsave(&pxp->lock, flags); + + HW_PXP_STAT_CLR(BM_PXP_STAT_IRQ); + + vb = pxp->active; + vb->state = VIDEOBUF_DONE; + do_gettimeofday(&vb->ts); + vb->field_count++; + + list_del_init(&vb->queue); + + if (list_empty(&pxp->outq)) { + pxp->active = NULL; + goto out; + } + + pxp->active = list_entry(pxp->outq.next, + struct videobuf_buffer, + queue); + + pxp_buf_output(pxp); + +out: + wake_up(&vb->done); + + spin_unlock_irqrestore(&pxp->lock, flags); + + return IRQ_HANDLED; +} + +static int pxp_probe(struct platform_device *pdev) +{ + struct pxps *pxp; + struct resource *res; + int irq; + int err = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || irq < 0) { + err = -ENODEV; + goto exit; + } + + pxp = kzalloc(sizeof(*pxp), GFP_KERNEL); + if (!pxp) { + dev_err(&pdev->dev, "failed to allocate control object\n"); + err = -ENOMEM; + goto exit; + } + + dev_set_drvdata(&pdev->dev, pxp); + pxp->res = res; + pxp->irq = irq; + + INIT_LIST_HEAD(&pxp->outq); + spin_lock_init(&pxp->lock); + mutex_init(&pxp->mutex); + + if (!request_mem_region(res->start, res->end - res->start + 1, + PXP_DRIVER_NAME)) { + err = -EBUSY; + goto freepxp; + } + + pxp->regs = (void __iomem *)res->start; /* it is already ioremapped */ + pxp->pdev = pdev; + + err = request_irq(pxp->irq, pxp_irq, 0, PXP_DRIVER_NAME, pxp); + + if (err) { + dev_err(&pdev->dev, "interrupt register failed\n"); + goto release; + } + + pxp->vdev = video_device_alloc(); + if (!pxp->vdev) { + dev_err(&pdev->dev, "video_device_alloc() failed\n"); + err = -ENOMEM; + goto freeirq; + } + + memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template)); + video_set_drvdata(pxp->vdev, pxp); + + err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, 0); + if (err) { + dev_err(&pdev->dev, "failed to register video device\n"); + goto freevdev; + } + + err = pxp_hw_init(pxp); + if (err) { + dev_err(&pdev->dev, "failed to initialize hardware\n"); + goto freevdev; + } + + dev_info(&pdev->dev, "initialized\n"); + +exit: + return err; + +freevdev: + video_device_release(pxp->vdev); + +freeirq: + free_irq(pxp->irq, pxp); + +release: + release_mem_region(res->start, res->end - res->start + 1); + +freepxp: + kfree(pxp); + + return err; +} + +static int __devexit pxp_remove(struct platform_device *pdev) +{ + struct pxps *pxp = platform_get_drvdata(pdev); + + video_unregister_device(pxp->vdev); + video_device_release(pxp->vdev); + + kfree(pxp->outb); + kfree(pxp); + + return 0; +} + +static struct platform_driver pxp_driver = { + .driver = { + .name = PXP_DRIVER_NAME, + }, + .probe = pxp_probe, + .remove = __exit_p(pxp_remove), +}; + + +static int __devinit pxp_init(void) +{ + return platform_driver_register(&pxp_driver); +} + +static void __exit pxp_exit(void) +{ + platform_driver_unregister(&pxp_driver); +} + +module_init(pxp_init); +module_exit(pxp_exit); + +MODULE_DESCRIPTION("STMP37xx PxP driver"); +MODULE_AUTHOR("Matt Porter <mporter@embeddedalley.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/pxp.h b/drivers/media/video/pxp.h new file mode 100644 index 000000000000..fc4335705d87 --- /dev/null +++ b/drivers/media/video/pxp.h @@ -0,0 +1,73 @@ +/* + * Freescale STMP378X PxP driver + * + * Author: Matt Porter <mporter@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +struct pxps { + struct platform_device *pdev; + struct resource *res; + int irq; + void __iomem *regs; + + spinlock_t lock; + struct mutex mutex; + int users; + + struct video_device *vdev; + + struct videobuf_queue s0_vbq; + struct videobuf_buffer *active; + struct list_head outq; + + int output; + u32 *outb; + dma_addr_t outb_phys; + + /* Current S0 configuration */ + struct pxp_data_format *s0_fmt; + u32 s0_bgcolor; + + struct v4l2_framebuffer fb; + struct v4l2_rect drect; + struct v4l2_rect srect; + + /* Transformation support */ + int scaling; + int hflip; + int vflip; + int rotate; + int yuv; + + /* Output overlay support */ + int overlay_state; + int global_alpha_state; + u8 global_alpha; + int local_alpha_state; + int chromakey_state; + u32 chromakey; +}; + +struct pxp_data_format { + char *name; + unsigned int bpp; + u32 fourcc; + enum v4l2_colorspace colorspace; + u32 ctrl_s0_fmt; +}; + +extern int stmp3xxxfb_get_info(struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix); +extern void stmp3xxxfb_cfg_pxp(int enable, dma_addr_t pxp_phys); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index c00b5ffcab67..6c7d3823619f 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -202,6 +202,14 @@ config MMC_IMX_ESDHCI_PIO_MODE If unsure, say N. +config MMC_STMP3XXX + tristate "STMP37xx/378x MMC support" + depends on MMC && ARCH_STMP3XXX + help + Select Y if you would like to access STMP37xx/378x MMC support. + + If unsure, say N. + config MMC_S3C tristate "Samsung S3C SD/MMC Card Interface support" depends on ARCH_S3C2410 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 8ef573985221..016a5d0e778b 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o obj-$(CONFIG_MMC_IMX_ESDHCI) += mx_sdhci.o obj-$(CONFIG_MMC_MXC) += mxc_mmc.o +obj-$(CONFIG_MMC_STMP3XXX) += stmp3xxx_mmc.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o diff --git a/drivers/mmc/host/stmp3xxx_mmc.c b/drivers/mmc/host/stmp3xxx_mmc.c new file mode 100644 index 000000000000..6e2e749fbf10 --- /dev/null +++ b/drivers/mmc/host/stmp3xxx_mmc.c @@ -0,0 +1,1071 @@ +/* + * Copyright (C) 2007 SigmaTel, Inc., Ioannis Kappas <ikappas@sigmatel.com> + * + * Portions copyright (C) 2003 Russell King, PXA MMCI Driver + * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/highmem.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/completion.h> +#include <linux/mmc/host.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> +#include <mach/hardware.h> +#include <mach/dma.h> +#include <mach/regs-apbh.h> +#include <mach/regs-ssp.h> +#include <mach/regs-clkctrl.h> +#include <mach/stmp3xxx.h> + +#define DRIVER_NAME "stmp3xxx-mmc" + +#define CLOCKRATE_MIN 400000 +#define CLOCKRATE_MAX 48000000 + +/* + * Card detect polling timeout + */ +#define STMP37XX_MMC_DETECT_TIMEOUT (HZ/2) + +/* Max value supported for XFER_COUNT */ +#define SSP_BUFFER_SIZE (65536 - 512) + +struct stmp3xxx_mmc_host { + struct device *dev; + struct mmc_host *mmc; + + struct clk *clk; + unsigned int clkrt; + + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + + /* Whether the card is capable of 4-bit data */ + int bus_width_4:1; + + /* Whether SD card is present */ + unsigned present:1; + + /* Polling timer */ + struct timer_list timer; + + /* SSP interface which MMC/SD card slot is attached to */ + u32 ssp_base; + + /* DMA channel used for this host */ + unsigned int dmach; + + /* IRQs */ + int dmairq, errirq; + + /* DMA descriptor to transfer data over SSP interface */ + struct stmp3xxx_dma_descriptor dma_desc; + + /* DMA buffer */ + dma_addr_t dma_buf_phys; + char *dma_buf; + + struct completion dma_done; + /* status on last interrupt */ + u32 status; + int read_uA, write_uA; + struct regulator *regulator; +}; + +/* Return read only state of card */ +static int stmp3xxx_mmc_get_ro(struct mmc_host *mmc) +{ + struct stmp3xxx_mmc_host *host = mmc_priv(mmc); + struct stmp3xxxmmc_platform_data *pdata = host->dev->platform_data; + + if (pdata && pdata->get_wp) + return pdata->get_wp(); + + return 0; +} + +/* Detect if card is plugged */ +static inline int stmp3xxx_mmc_is_plugged(struct stmp3xxx_mmc_host *host) +{ + u32 status = HW_SSP_STATUS_RD_NB(host->ssp_base); + return !(status & BM_SSP_STATUS_CARD_DETECT); +} + +/* Card detection polling function */ +static void stmp3xxx_mmc_detect_poll(unsigned long arg) +{ + struct stmp3xxx_mmc_host *host = (struct stmp3xxx_mmc_host *)arg; + int card_status; + + card_status = stmp3xxx_mmc_is_plugged(host); + if (card_status != host->present) { + host->present = card_status; + mmc_detect_change(host->mmc, 0); + } + + mod_timer(&host->timer, jiffies + STMP37XX_MMC_DETECT_TIMEOUT); +} + +#define STMP3XXX_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \ + BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) + +/* SSP DMA interrupt handler */ +static irqreturn_t mmc_irq_handler(int irq, void *dev_id) +{ + struct stmp3xxx_mmc_host *host = dev_id; + u32 c1; + + c1 = HW_SSP_CTRL1_RD_NB(host->ssp_base); + HW_SSP_CTRL1_CLR_NB(host->ssp_base, c1 & STMP3XXX_MMC_IRQ_BITS); + if (irq == host->dmairq) + stmp3xxx_dma_clear_interrupt(host->dmach); + host->status = HW_SSP_STATUS_RD_NB(host->ssp_base); + + if (host->cmd) /* else it is a bogus interrupt */ + complete(&host->dma_done); + + return IRQ_HANDLED; +} + +/* + * Check for MMC command errors + * Returns error code or zerro if no errors + */ +static inline int stmp3xxx_mmc_cmd_error(u32 status) +{ + int err = 0; + + if (status & BM_SSP_STATUS_TIMEOUT) + err = -ETIMEDOUT; + else if (status & BM_SSP_STATUS_RESP_TIMEOUT) + err = -ETIMEDOUT; + else if (status & BM_SSP_STATUS_RESP_CRC_ERR) + err = -EILSEQ; + else if (status & BM_SSP_STATUS_RESP_ERR) + err = -EIO; + + return err; +} + +/* Send the BC command to the device */ +static void stmp3xxx_mmc_bc(struct stmp3xxx_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc; + + dma_desc->command->cmd = + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_SEMAPHORE | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_XFER_COUNT(0) | + BF_APBH_CHn_CMD_CMDWORDS(3) | + BF_APBH_CHn_CMD_COMMAND(0); /* NO_DMA_XFER */ + + dma_desc->command->pio_words[0] = BM_SSP_CTRL0_ENABLE | + BM_SSP_CTRL0_IGNORE_CRC; + dma_desc->command->pio_words[1] = BF_SSP_CMD0_CMD(cmd->opcode) | + BM_SSP_CMD0_APPEND_8CYC; + dma_desc->command->pio_words[2] = BF_SSP_CMD1_CMD_ARG(cmd->arg); + + init_completion(&host->dma_done); + stmp3xxx_dma_reset_channel(host->dmach); + stmp3xxx_dma_go(host->dmach, dma_desc, 1); + wait_for_completion(&host->dma_done); + + cmd->error = stmp3xxx_mmc_cmd_error(host->status); + + if (stmp3xxx_dma_running(host->dmach)) + dev_dbg(host->dev, "DMA command not finished\n"); + + if (cmd->error) { + dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); + stmp3xxx_dma_reset_channel(host->dmach); + } +} + +/* Send the ac command to the device */ +static void stmp3xxx_mmc_ac(struct stmp3xxx_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc; + u32 ignore_crc, resp, long_resp; + u32 ssp_ctrl0; + u32 ssp_cmd0; + u32 ssp_cmd1; + + ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? + 0 : BM_SSP_CTRL0_IGNORE_CRC; + resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? + BM_SSP_CTRL0_GET_RESP : 0; + long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? + BM_SSP_CTRL0_LONG_RESP : 0; + + dma_desc->command->cmd = + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_SEMAPHORE | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_XFER_COUNT(0) | + BF_APBH_CHn_CMD_CMDWORDS(3) | + BF_APBH_CHn_CMD_COMMAND(0); + + ssp_ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | long_resp | resp; + ssp_cmd0 = BF_SSP_CMD0_CMD(cmd->opcode); + ssp_cmd1 = BF_SSP_CMD1_CMD_ARG(cmd->arg); + + dma_desc->command->pio_words[0] = ssp_ctrl0; + dma_desc->command->pio_words[1] = ssp_cmd0; + dma_desc->command->pio_words[2] = ssp_cmd1; + + stmp3xxx_dma_reset_channel(host->dmach); + init_completion(&host->dma_done); + stmp3xxx_dma_go(host->dmach, dma_desc, 1); + wait_for_completion(&host->dma_done); + + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + while (HW_SSP_CTRL0_RD_NB(host->ssp_base) & BM_SSP_CTRL0_RUN) + continue; + break; + case MMC_RSP_R1: + case MMC_RSP_R1B: + case MMC_RSP_R3: + cmd->resp[0] = HW_SSP_SDRESP0_RD_NB(host->ssp_base); + break; + case MMC_RSP_R2: + cmd->resp[3] = HW_SSP_SDRESP0_RD_NB(host->ssp_base); + cmd->resp[2] = HW_SSP_SDRESP1_RD_NB(host->ssp_base); + cmd->resp[1] = HW_SSP_SDRESP2_RD_NB(host->ssp_base); + cmd->resp[0] = HW_SSP_SDRESP3_RD_NB(host->ssp_base); + break; + default: + dev_warn(host->dev, "Unsupported response type 0x%x\n", + mmc_resp_type(cmd)); + BUG(); + break; + } + + cmd->error = stmp3xxx_mmc_cmd_error(host->status); + + if (stmp3xxx_dma_running(host->dmach)) + dev_dbg(host->dev, "DMA command not finished\n"); + + if (cmd->error) { + dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); + stmp3xxx_dma_reset_channel(host->dmach); + } +} + +/* Copy data between sg list and dma buffer */ +static unsigned int stmp3xxx_sg_dma_copy(struct stmp3xxx_mmc_host *host, + unsigned int size, int to_dma) +{ + struct mmc_data *data = host->cmd->data; + unsigned int copy_size, bytes_copied = 0; + struct scatterlist *sg; + char *dmabuf = host->dma_buf; + char *sgbuf; + int len, i; + + sg = data->sg; + len = data->sg_len; + + /* + * Just loop through all entries. Size might not + * be the entire list though so make sure that + * we do not transfer too much. + */ + for (i = 0; i < len; i++) { + sgbuf = kmap_atomic(sg_page(&sg[i]), KM_BIO_SRC_IRQ) + + sg[i].offset; + copy_size = size < sg[i].length ? size : sg[i].length; + if (to_dma) + memcpy(dmabuf, sgbuf, copy_size); + else + memcpy(sgbuf, dmabuf, copy_size); + kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ); + + dmabuf += sg[i].length; + + bytes_copied += copy_size; + size -= copy_size; + + if (size == 0) + break; + } + + return bytes_copied; +} + +/* Convert ns to tick count according to the current sclk speed */ +static unsigned short stmp3xxx_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns) +{ + const unsigned int ssp_timeout_mul = 4096; + /* + * Calculate ticks in ms since ns are large numbers + * and might overflow + */ + const unsigned int clock_per_ms = clock_rate / 1000; + const unsigned int ms = ns / 1000; + const unsigned int ticks = ms * clock_per_ms; + const unsigned int ssp_ticks = ticks / ssp_timeout_mul; + + BUG_ON(ssp_ticks == 0); + return ssp_ticks; +} + +static void __init_reg(struct device *dev, struct regulator **pp_reg) +{ + struct regulator *reg = *pp_reg; + + if (!reg) { + reg = regulator_get(NULL, "mmc_ssp-1"); + if (reg && !IS_ERR(reg)) + regulator_set_mode(reg, REGULATOR_MODE_NORMAL); + else + reg = NULL; + *pp_reg = reg; + } +} + +/* Send adtc command to the card */ +static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc; + int ignore_crc, resp, long_resp; + int is_reading = 0; + unsigned int copy_size; + + u32 ssp_ctrl0; + u32 ssp_cmd0; + u32 ssp_cmd1; + u32 timeout; + + u32 data_size = cmd->data->blksz * cmd->data->blocks; + u32 log2_block_size; + + ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1; + resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0; + long_resp = mmc_resp_type(cmd) & MMC_RSP_136 ? 1 : 0; + + dev_dbg(host->dev, "ADTC command:\n" + "response: %d, ignore crc: %d\n" + "data list: %u, blocksz: %u, blocks: %u, timeout: %uns %uclks, " + "flags: 0x%x\n", resp, ignore_crc, cmd->data->sg_len, + cmd->data->blksz, cmd->data->blocks, cmd->data->timeout_ns, + cmd->data->timeout_clks, cmd->data->flags); + + if (cmd->data->flags & MMC_DATA_WRITE) { + dev_dbg(host->dev, "Data Write\n"); + copy_size = stmp3xxx_sg_dma_copy(host, data_size, 1); + BUG_ON(copy_size < data_size); + is_reading = 0; + if (!host->regulator) + __init_reg(host->dev, &host->regulator); + if (host->regulator) + regulator_set_current_limit(host->regulator, host->write_uA, host->write_uA); + } else if (cmd->data->flags & MMC_DATA_READ) { + dev_dbg(host->dev, "Data Read\n"); + is_reading = 1; + if (!host->regulator) + __init_reg(host->dev, &host->regulator); + if (host->regulator) + regulator_set_current_limit(host->regulator, host->read_uA, host->read_uA); + } else { + dev_warn(host->dev, "Unsuspported data mode, 0x%x\n", + cmd->data->flags); + BUG(); + } + + BUG_ON(cmd->data->flags & MMC_DATA_STREAM); + BUG_ON((data_size % 8) > 0); + + dma_desc->command->cmd = + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_SEMAPHORE | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_XFER_COUNT(data_size) | + BF_APBH_CHn_CMD_CMDWORDS(3); + + /* when is_reading is set, DMA controller performs WRITE operation. */ + dma_desc->command->cmd |= + BF_APBH_CHn_CMD_COMMAND( + is_reading ? BV_APBH_CHn_CMD_COMMAND__DMA_WRITE : + BV_APBH_CHn_CMD_COMMAND__DMA_READ); + ssp_ctrl0 = + (ignore_crc ? BM_SSP_CTRL0_IGNORE_CRC : 0) | + (resp ? BM_SSP_CTRL0_GET_RESP : 0) | + (long_resp ? BM_SSP_CTRL0_LONG_RESP : 0) | + (is_reading ? BM_SSP_CTRL0_READ : 0) | + BM_SSP_CTRL0_DATA_XFER | + BM_SSP_CTRL0_WAIT_FOR_IRQ | + BM_SSP_CTRL0_ENABLE | + BF_SSP_CTRL0_XFER_COUNT(data_size) | + BF_SSP_CTRL0_BUS_WIDTH(host->bus_width_4 ? + BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT : + BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT); + + /* + * We need to set the hardware register to the logarithm to base 2 of + * the block size. + */ + log2_block_size = ilog2(cmd->data->blksz); + + ssp_cmd0 = + BF_SSP_CMD0_BLOCK_SIZE(log2_block_size) | + BF_SSP_CMD0_CMD(cmd->opcode) | + BF_SSP_CMD0_BLOCK_COUNT(cmd->data->blocks - 1); + + if (cmd->opcode == 12) + ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC; + + ssp_cmd1 = BF_SSP_CMD1_CMD_ARG(cmd->arg); + + dma_desc->command->pio_words[0] = ssp_ctrl0; + dma_desc->command->pio_words[1] = ssp_cmd0; + dma_desc->command->pio_words[2] = ssp_cmd1; + + /* Set the timeout count */ + timeout = stmp3xxx_ns_to_ssp_ticks(host->clkrt, cmd->data->timeout_ns); + HW_SSP_TIMING_CLR_NB(host->ssp_base, BM_SSP_TIMING_TIMEOUT); + HW_SSP_TIMING_SET_NB(host->ssp_base, BF_SSP_TIMING_TIMEOUT(timeout)); + + init_completion(&host->dma_done); + stmp3xxx_dma_reset_channel(host->dmach); + stmp3xxx_dma_go(host->dmach, dma_desc, 1); + wait_for_completion(&host->dma_done); + if (host->regulator) + regulator_set_current_limit(host->regulator, 0, 0); + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + break; + case MMC_RSP_R1: + case MMC_RSP_R3: + cmd->resp[0] = HW_SSP_SDRESP0_RD_NB(host->ssp_base); + break; + case MMC_RSP_R2: + cmd->resp[3] = HW_SSP_SDRESP0_RD_NB(host->ssp_base); + cmd->resp[2] = HW_SSP_SDRESP1_RD_NB(host->ssp_base); + cmd->resp[1] = HW_SSP_SDRESP2_RD_NB(host->ssp_base); + cmd->resp[0] = HW_SSP_SDRESP3_RD_NB(host->ssp_base); + break; + default: + dev_warn(host->dev, "Unsupported response type 0x%x\n", + mmc_resp_type(cmd)); + BUG(); + break; + } + + cmd->error = stmp3xxx_mmc_cmd_error(host->status); + + if (stmp3xxx_dma_running(host->dmach)) + dev_dbg(host->dev, "DMA command not finished\n"); + + if (cmd->error) { + dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); + stmp3xxx_dma_reset_channel(host->dmach); + } else { + if (is_reading) + cmd->data->bytes_xfered = + stmp3xxx_sg_dma_copy(host, data_size, 0); + else + cmd->data->bytes_xfered = data_size; + + dev_dbg(host->dev, "Transferred %u bytes\n", + cmd->data->bytes_xfered); + } +} + +/* Begin sedning a command to the card */ +static void stmp3xxx_mmc_start_cmd(struct stmp3xxx_mmc_host *host, + struct mmc_command *cmd) +{ + dev_dbg(host->dev, "MMC command:\n" + "type: 0x%x opcode: %u, arg: %u, flags 0x%x retries: %u\n", + mmc_cmd_type(cmd), cmd->opcode, cmd->arg, cmd->flags, + cmd->retries); + + host->cmd = cmd; + + switch (mmc_cmd_type(cmd)) { + case MMC_CMD_BC: + stmp3xxx_mmc_bc(host); + break; + case MMC_CMD_BCR: + stmp3xxx_mmc_ac(host); + break; + case MMC_CMD_AC: + stmp3xxx_mmc_ac(host); + break; + case MMC_CMD_ADTC: + stmp3xxx_mmc_adtc(host); + break; + default: + dev_warn(host->dev, "Unknown MMC command\n"); + BUG(); + break; + } + + dev_dbg(host->dev, "response: %u %u %u %u errors: %u\n", + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], + cmd->error); +} + +/* Handle MMC request */ +static void stmp3xxx_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct stmp3xxx_mmc_host *host = mmc_priv(mmc); + + dev_dbg(host->dev, "MMC request\n"); + + host->mrq = mrq; + + stmp3xxx_mmc_start_cmd(host, mrq->cmd); + + if (mrq->data && mrq->data->stop) { + dev_dbg(host->dev, "Stop opcode is %u\n", + mrq->data->stop->opcode); + stmp3xxx_mmc_start_cmd(host, mrq->data->stop); + } + + host->mrq = NULL; + mmc_request_done(mmc, mrq); +} + +/* + * Change divisors to reflect the rate of 'hz'. Note that we should not + * play with clock rate, because the same source is used to clock both + * SSP ports. + */ +static void +stmp3xxx_set_sclk_speed(struct stmp3xxx_mmc_host *host, unsigned int hz) +{ + unsigned long ssp; + u32 div1, div2; + struct stmp3xxxmmc_platform_data *pdata = host->dev->platform_data; + + if (pdata && pdata->setclock) { + /* + if the SSP is buggy and platform provides callback... + well, let it be. + */ + host->clkrt = pdata->setclock(hz); + return; + } + + /* + ...but the RightIdea(tm) is to set divisors to match + the requested clock. + */ + hz /= 1000; + + ssp = clk_get_rate(host->clk); + + for (div1 = 2; div1 < 254; div1 += 2) { + div2 = ssp / hz / div1; + if (div2 < 0x100) + break; + } + if (div1 >= 254) { + dev_err(host->dev, "Cannot set clock to %dkHz\n", hz); + return; + } + + dev_dbg(host->dev, "Setting clock rate to %ld kHz [%x+%x] " + "(requested %d), source %ldk\n", + ssp/div1/div2, div1, div2, hz, ssp); + HW_SSP_TIMING_CLR_NB(host->ssp_base, + BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); + HW_SSP_TIMING_SET_NB(host->ssp_base, + BF_SSP_TIMING_CLOCK_DIVIDE(div1) | + BF_SSP_TIMING_CLOCK_RATE(div2 - 1)); + host->clkrt = ssp/div1/div2 * 1000; +} + +/* Configure card */ +static void stmp3xxx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct stmp3xxx_mmc_host *host = mmc_priv(mmc); + struct stmp3xxxmmc_platform_data *pdata; + + dev_dbg(host->dev, "MMC set ios:\n" + "Clock %u, vdd %u, bus_mode %u, chip_select %u, " + "power mode %u, bus_width %u\n", ios->clock, ios->vdd, + ios->bus_mode, ios->chip_select, ios->power_mode, + ios->bus_width); + + pdata = host->dev->platform_data; + + if (pdata->cmd_pullup) { + if (ios->bus_mode == MMC_BUSMODE_PUSHPULL) + pdata->cmd_pullup(0); + else + pdata->cmd_pullup(1); + } else + dev_warn(host->dev, + "Platform does not support CMD pin pullup control\n"); + + if (ios->bus_width == MMC_BUS_WIDTH_4) + host->bus_width_4 = 1; + else + host->bus_width_4 = 0; + + if (ios->clock > 0) + stmp3xxx_set_sclk_speed(host, ios->clock); +} + +static const struct mmc_host_ops stmp3xxx_mmc_ops = { + .request = stmp3xxx_mmc_request, + .get_ro = stmp3xxx_mmc_get_ro, + .set_ios = stmp3xxx_mmc_set_ios, +}; + + +/* + * STMP37XX MMC/SD driver initialization + */ + +/* Reset ssp peripheral to default values */ +static void stmp3xxx_mmc_reset(struct stmp3xxx_mmc_host *host) +{ + u32 ssp_ctrl0; + u32 ssp_ctrl1; + + stmp3xxx_reset_block(host->ssp_base, 0); + + /* Configure SSP Control Register 0 */ + ssp_ctrl0 = + BM_SSP_CTRL0_IGNORE_CRC | + BF_SSP_CTRL0_BUS_WIDTH(BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT); + + /* Configure SSP Control Register 1 */ + ssp_ctrl1 = + BM_SSP_CTRL1_DMA_ENABLE | + BM_SSP_CTRL1_POLARITY | + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_DATA_CRC_IRQ_EN | + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_ERR_IRQ_EN | + BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | + BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SD_MMC); + + HW_SSP_TIMING_WR(BF_SSP_TIMING_TIMEOUT(0xFFFF) | + BF_SSP_TIMING_CLOCK_DIVIDE(2) | + BF_SSP_TIMING_CLOCK_RATE(0)); + + /* Write the SSP Control Register 0 and 1 values out to the interface */ + HW_SSP_CTRL0_WR_NB(host->ssp_base, ssp_ctrl0); + HW_SSP_CTRL1_WR_NB(host->ssp_base, ssp_ctrl1); +} + +static void stmp3xxx_mmc_irq_release(struct stmp3xxx_mmc_host *host) +{ + free_irq(host->dmairq, host); + free_irq(host->errirq, host); +} + +static int __init stmp3xxx_mmc_irq_init(struct stmp3xxx_mmc_host *host) +{ + int ret; + + ret = request_irq(host->dmairq, mmc_irq_handler, 0, + DRIVER_NAME" dma", host); + if (ret) { + dev_err(host->dev, "Unable to set up DMA irq handler\n"); + goto out0; + } + + ret = request_irq(host->errirq, mmc_irq_handler, IRQF_SHARED, + DRIVER_NAME" error", host); + if (ret) { + dev_err(host->dev, "Unable to set up SSP error irq handler\n"); + goto out1; + } + return 0; + +out1: + free_irq(host->dmairq, host); +out0: + return ret; +} + + +/* Allocate and initialise the DMA chains */ +static int stmp3xxx_mmc_dma_init(struct stmp3xxx_mmc_host *host, int reset) +{ + int ret; + + if (!reset) { + /* Allocate DMA channel */ + ret = stmp3xxx_dma_request(host->dmach, + host->dev, "STMP37XX MMC/SD"); + if (ret) { + dev_err(host->dev, "Unable to request DMA channel\n"); + return ret; + } + + host->dma_buf = dma_alloc_coherent(host->dev, SSP_BUFFER_SIZE, + &host->dma_buf_phys, GFP_DMA); + if (host->dma_buf == NULL) { + dev_err(host->dev, "Unable to allocate DMA memory\n"); + ret = -ENOMEM; + goto out_mem; + } + + ret = stmp3xxx_dma_allocate_command(host->dmach, + &host->dma_desc); + if (ret) { + dev_err(host->dev, + "Unable to allocate DMA descriptor\n"); + goto out_cmd; + } + + host->dma_desc.command->next = (u32)host->dma_desc.handle; + host->dma_desc.command->buf_ptr = (u32)host->dma_buf_phys; + host->dma_desc.virtual_buf_ptr = host->dma_buf; + } + + /* Reset DMA channel */ + stmp3xxx_dma_reset_channel(host->dmach); + + /* Enable DMA interrupt */ + stmp3xxx_dma_clear_interrupt(host->dmach); + stmp3xxx_dma_enable_interrupt(host->dmach); + + return 0; + +out_cmd: + dma_free_coherent(host->dev, SSP_BUFFER_SIZE, host->dma_buf, + host->dma_buf_phys); +out_mem: + stmp3xxx_dma_release(host->dmach); + + return ret; +} + +static void stmp3xxx_mmc_dma_release(struct stmp3xxx_mmc_host *host) +{ + stmp3xxx_dma_reset_channel(host->dmach); + + dma_free_coherent(host->dev, SSP_BUFFER_SIZE, host->dma_buf, + host->dma_buf_phys); + + stmp3xxx_dma_free_command(host->dmach, &host->dma_desc); + stmp3xxx_dma_release(host->dmach); +} + +/* Probe peripheral for connected cards */ +static int __init stmp3xxx_mmc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct stmp3xxxmmc_platform_data *mmc_data; + struct stmp3xxx_mmc_host *host; + struct mmc_host *mmc; + struct resource *r; + int err = 0; + + mmc_data = dev->platform_data; + if (mmc_data == NULL) { + err = -EINVAL; + dev_err(dev, "Missing platform data\n"); + goto out; + } + + /* Allocate main MMC host structure */ + mmc = mmc_alloc_host(sizeof(struct stmp3xxx_mmc_host), dev); + if (!mmc) { + dev_err(dev, "Unable to allocate MMC host\n"); + err = -ENOMEM; + goto out; + } + host = mmc_priv(mmc); + + host->read_uA = mmc_data->read_uA; + host->write_uA = mmc_data->write_uA; + host->regulator = regulator_get(NULL, "mmc_ssp-1"); + if (host->regulator && !IS_ERR(host->regulator)) + regulator_set_mode(host->regulator, REGULATOR_MODE_NORMAL); + else + host->regulator = NULL; + + /* get resources: */ + + /* + * 1. io memory + */ + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "failed to get IORESOURCE_MEM\n"); + err = -ENXIO; + goto out_res; + } + host->ssp_base = r->start; /* it is already ioremapped */ + + /* + * 2. DMA channel + */ + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) { + dev_err(&pdev->dev, "failed to get IORESOURCE_DMA\n"); + err = -ENXIO; + goto out_res; + } + host->dmach = r->start; + + /* + * 3. two IRQs + */ + host->dmairq = platform_get_irq(pdev, 0); + if (host->dmairq < 0) { + dev_err(&pdev->dev, "failed to get IORESOURCE_IRQ/0\n"); + err = host->dmairq; + goto out_res; + } + + host->errirq = platform_get_irq(pdev, 1); + if (host->errirq < 0) { + dev_err(&pdev->dev, "failed to get IORESOURCE_IRQ/1\n"); + err = host->errirq; + goto out_res; + } + + /* Set up MMC pins */ + if (mmc_data->hw_init) { + err = mmc_data->hw_init(); + if (err) { + dev_err(dev, "MMC HW configuration failed\n"); + goto out_res; + } + } + + host->mmc = mmc; + host->dev = dev; + + /* Set minimal clock rate */ + host->clk = clk_get(dev, "ssp"); + if (IS_ERR(host->clk)) { + err = PTR_ERR(host->clk); + dev_err(dev, "Clocks initialization failed\n"); + goto out_clk; + } + + clk_enable(host->clk); + stmp3xxx_set_sclk_speed(host, CLOCKRATE_MIN); + + /* Reset MMC block */ + stmp3xxx_mmc_reset(host); + + /* Enable DMA */ + err = stmp3xxx_mmc_dma_init(host, 0); + if (err) { + dev_err(dev, "DMA init failed\n"); + goto out_dma; + } + + /* Set up interrupt handlers */ + err = stmp3xxx_mmc_irq_init(host); + if (err) { + dev_err(dev, "IRQ initialization failed\n"); + goto out_irq; + } + + /* Get current card status for further cnanges tracking */ + host->present = stmp3xxx_mmc_is_plugged(host); + + /* Add a card detection polling timer */ + init_timer(&host->timer); + host->timer.function = stmp3xxx_mmc_detect_poll; + host->timer.data = (unsigned long)host; + host->timer.expires = jiffies + STMP37XX_MMC_DETECT_TIMEOUT; + add_timer(&host->timer); + + mmc->ops = &stmp3xxx_mmc_ops; + mmc->f_min = CLOCKRATE_MIN; + mmc->f_max = CLOCKRATE_MAX; + mmc->caps = MMC_CAP_4_BIT_DATA; + + /* Maximum block count requests. */ + mmc->max_blk_size = 512; + mmc->max_blk_count = SSP_BUFFER_SIZE / 512; + mmc->max_hw_segs = SSP_BUFFER_SIZE / 512; + mmc->max_phys_segs = SSP_BUFFER_SIZE / 512; + mmc->max_req_size = SSP_BUFFER_SIZE; + mmc->max_seg_size = SSP_BUFFER_SIZE; + + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + platform_set_drvdata(pdev, mmc); + + err = mmc_add_host(mmc); + if (err) { + dev_err(dev, "Oh God. mmc_add_host failed\n"); + goto out_all; + } + + return err; + +out_all: + +out_irq: + stmp3xxx_mmc_dma_release(host); +out_dma: + clk_disable(host->clk); +out_clk: + if (mmc_data->hw_release) + mmc_data->hw_release(); +out_res: + mmc_free_host(mmc); +out: + return err; +} + +static int __exit stmp3xxx_mmc_remove(struct platform_device *pdev) +{ + struct stmp3xxx_mmc_host *host; + struct stmp3xxxmmc_platform_data *mmc_data; + struct mmc_host *mmc; + + dev_info(&pdev->dev, "Removing\n"); + + mmc_data = pdev->dev.platform_data; + mmc = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + host = mmc_priv(mmc); + mmc_remove_host(mmc); + + /* Disable SSP clock */ + clk_disable(host->clk); + clk_put(host->clk); + + /* Release IRQs */ + stmp3xxx_mmc_irq_release(host); + + /* Delete card detection timer */ + del_timer(&host->timer); + + /* Release DMA */ + stmp3xxx_mmc_dma_release(host); + if (host->regulator) + regulator_put(host->regulator); + + mmc_free_host(mmc); + + if (mmc_data->hw_release) + mmc_data->hw_release(); + + return 0; +} + +#ifdef CONFIG_PM +static int stmp3xxx_mmc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct stmp3xxx_mmc_host *host; + struct stmp3xxxmmc_platform_data *mmc_data; + struct mmc_host *mmc; + int ret = 0; + + dev_dbg(&pdev->dev, "Suspending\n"); + + mmc_data = pdev->dev.platform_data; + mmc = platform_get_drvdata(pdev); + host = mmc_priv(mmc); + + ret = mmc_suspend_host(mmc, state); + if (!ret) { + if (mmc_data && mmc_data->hw_release) + mmc_data->hw_release(); + clk_disable(host->clk); + } + return ret; +} + +static int stmp3xxx_mmc_resume(struct platform_device *pdev) +{ + struct stmp3xxx_mmc_host *host; + struct stmp3xxxmmc_platform_data *mmc_data; + struct mmc_host *mmc; + + dev_dbg(&pdev->dev, "Resuming\n"); + + mmc_data = pdev->dev.platform_data; + mmc = platform_get_drvdata(pdev); + host = mmc_priv(mmc); + + clk_enable(host->clk); + + if (mmc_data->hw_init) + mmc_data->hw_init(); + stmp3xxx_mmc_reset(host); + stmp3xxx_mmc_dma_init(host, 1); + + return mmc_resume_host(mmc); +} +#else +#define stmp3xxx_mmc_suspend NULL +#define stmp3xxx_mmc_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver stmp3xxx_mmc_driver = { + .probe = stmp3xxx_mmc_probe, + .remove = __exit_p(stmp3xxx_mmc_remove), + .suspend = stmp3xxx_mmc_suspend, + .resume = stmp3xxx_mmc_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxx_mmc_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&stmp3xxx_mmc_driver); + if (ret < 0) + return ret; + + return ret; +} + +static void __exit stmp3xxx_mmc_exit(void) +{ + platform_driver_unregister(&stmp3xxx_mmc_driver); +} + +module_init(stmp3xxx_mmc_init); +module_exit(stmp3xxx_mmc_exit); + +MODULE_DESCRIPTION("STMP37xx/378x MMC peripheral"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 933639f5f3a5..3a3762f7c455 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -415,6 +415,46 @@ config MXC_NAND_LOW_LEVEL_ERASE This enables the erase of whole NAND flash. By default low level erase operation is disabled. +config MTD_NAND_GPMI_LBA + tristate "GPMI LBA NAND driver" + depends on MTD_NAND && ARCH_STMP3XXX + help + Enables support of LBA devices on GPMI on 37xx/378x SigmaTel + boards + +config MTD_NAND_GPMI + tristate "GPMI NAND driver" + depends on MTD_NAND && ARCH_STMP3XXX && !MTD_NAND_GPMI_LBA + help + Enables support of NAND devices on GPMI on 37xx/378x SigmaTel + boards + +config MTD_NAND_GPMI_SYSFS_ENTRIES + bool "Create /sys entries for GPMI device" + depends on MTD_NAND_GPMI + help + Check this to enable /sys entries for GPMI devices + +config MTD_NAND_GPMI_BCH + bool "Enable BCH HWECC" + depends on MTD_NAND_GPMI + depends on ARCH_STMP378X + default y + help + Check this to enable /sys entries for GPMI devices + +config MTD_NAND_GPMI_TA1 + bool "Support for TA1 NCB format (Hamming code 22,16)" + depends on MTD_NAND_GPMI + depends on ARCH_STMP378X + default y + +config MTD_NAND_GPMI_TA3 + bool "Support for TA3 NCB format (Hamming code 13,8)" + depends on MTD_NAND_GPMI + depends on ARCH_STMP378X + default y + config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" depends on MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index accba30acb47..6a32928769b7 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,6 +27,8 @@ obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nd.o obj-$(CONFIG_MTD_NAND_MXC_V2) += mxc_nd2.o obj-$(CONFIG_MTD_NAND_MXC_V3) += mxc_nd2.o +obj-$(CONFIG_MTD_NAND_GPMI) += gpmi/ +obj-$(CONFIG_MTD_NAND_GPMI_LBA) += lba/ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o diff --git a/drivers/mtd/nand/gpmi/Makefile b/drivers/mtd/nand/gpmi/Makefile new file mode 100644 index 000000000000..4a4b50d294fa --- /dev/null +++ b/drivers/mtd/nand/gpmi/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_MTD_NAND_GPMI) += gpmi.o +gpmi-objs += gpmi-base.o gpmi-bbt.o +gpmi-objs += gpmi-hamming-22-16.o +gpmi-objs += gpmi-hamming-13-8.o +gpmi-objs += gpmi-bch.o +gpmi-objs += gpmi-ecc8.o diff --git a/drivers/mtd/nand/gpmi/gpmi-base.c b/drivers/mtd/nand/gpmi/gpmi-base.c new file mode 100644 index 000000000000..36107f26ad0b --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-base.c @@ -0,0 +1,1973 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/concat.h> +#include <linux/dma-mapping.h> +#include <linux/ctype.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> + +#include <mach/stmp3xxx.h> +#include <mach/regs-ecc8.h> +#include <mach/dma.h> +#include "gpmi.h" + +static int debug; +static int copies; +static int map_buffers = true; +static int ff_writes; +static int raw_mode; +static int add_mtd_entire; +static int add_mtd_chip; +static int ignorebad; +static int max_chips = 4; +static long clk = -1; +static int bch /* = 0 */; + +static int gpmi_nand_init_hw(struct platform_device *pdev, int request_pins); +static void gpmi_nand_release_hw(struct platform_device *pdev); +static int gpmi_dma_exchange(struct gpmi_nand_data *g, + struct stmp3xxx_dma_descriptor *dma); +static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len); + +struct gpmi_nand_timing gpmi_safe_timing = { + .address_setup = 25, + .data_setup = 80, + .data_hold = 60, + .dsample_time = 6, +}; + +/* + * define OOB placement schemes for 4k and 2k page devices + */ +static struct nand_ecclayout gpmi_oob_128 = { + .oobfree = { + { + .offset = 2, + .length = 56, + }, { + .length = 0, + }, + }, +}; + +static struct nand_ecclayout gpmi_oob_64 = { + .oobfree = { + { + .offset = 2, + .length = 16, + }, { + .length = 0, + }, + }, +}; + +static inline u32 gpmi_cycles_ceil(u32 ntime, u32 period) +{ + int k; + + k = (ntime + period - 1) / period; + if (k == 0) + k++; + return k; +} + +/** + * gpmi_timer_expiry - timer expiry handling + */ +static void gpmi_timer_expiry(unsigned long d) +{ +#ifdef CONFIG_PM + struct gpmi_nand_data *g = (struct gpmi_nand_data *)d; + + pr_debug("%s: timer expired\n", __func__); + del_timer_sync(&g->timer); + + if (g->use_count || + HW_GPMI_CTRL0_RD() & BM_GPMI_CTRL0_RUN) { + g->timer.expires = jiffies + 4*HZ; + add_timer(&g->timer); + } else { + HW_GPMI_CTRL0_SET(BM_GPMI_CTRL0_CLKGATE); + clk_disable(g->clk); + g->self_suspended = 1; + } +#endif +} + +/** + * gpmi_self_wakeup - wakeup from self-pm light suspend + */ +static void gpmi_self_wakeup(struct gpmi_nand_data *g) +{ +#ifdef CONFIG_PM + int i = 1000; + clk_enable(g->clk); + HW_GPMI_CTRL0_CLR(BM_GPMI_CTRL0_CLKGATE); + while (i-- && HW_GPMI_CTRL0_RD() & BM_GPMI_CTRL0_CLKGATE); + + pr_debug("%s: i stopped at %d, data %p\n", __func__, i, g); + g->self_suspended = 0; + g->timer.expires = jiffies + 4*HZ; + add_timer(&g->timer); +#endif +} + +/** + * gpmi_set_timings - set GPMI timings + * @pdev: pointer to GPMI platform device + * @tm: pointer to structure &gpmi_nand_timing with new timings + * + * During initialization, GPMI uses safe sub-optimal timings, which + * can be changed after reading boot control blocks + */ +void gpmi_set_timings(struct platform_device *pdev, struct gpmi_nand_timing *tm) +{ + struct gpmi_nand_data *g = platform_get_drvdata(pdev); + u32 period_ns = 1000000 / clk_get_rate(g->clk) + 1; + u32 address_cycles, data_setup_cycles; + u32 data_hold_cycles, data_sample_cycles; + u32 busy_timeout; + u32 t0; + + if (g->self_suspended) + gpmi_self_wakeup(g); + g->use_count++; + + g->timing = *tm; + + address_cycles = gpmi_cycles_ceil(tm->address_setup, period_ns); + data_setup_cycles = gpmi_cycles_ceil(tm->data_setup, period_ns); + data_hold_cycles = gpmi_cycles_ceil(tm->data_hold, period_ns); + data_sample_cycles = gpmi_cycles_ceil(tm->dsample_time + period_ns / 4, + period_ns / 2); + busy_timeout = gpmi_cycles_ceil(10000000 / 4096, period_ns); + + dev_dbg(&pdev->dev, + "%s: ADDR %u, DSETUP %u, DH %u, DSAMPLE %u, BTO %u\n", + __func__, + address_cycles, data_setup_cycles, data_hold_cycles, + data_sample_cycles, busy_timeout); + + t0 = BF_GPMI_TIMING0_ADDRESS_SETUP(address_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles); + HW_GPMI_TIMING0_WR(t0); + + HW_GPMI_TIMING1_WR(BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(busy_timeout)); + +#ifdef CONFIG_ARCH_STMP378X + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_RDN_DELAY); + HW_GPMI_CTRL1_SET(BF_GPMI_CTRL1_RDN_DELAY(data_sample_cycles)); +#else + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_DSAMPLE_TIME); + HW_GPMI_CTRL1_SET(BF_GPMI_CTRL1_DSAMPLE_TIME(data_sample_cycles)); +#endif + + g->use_count--; +} + +static inline u32 bch_mode(void) +{ + u32 c1 = 0; + +#ifdef CONFIG_MTD_NAND_GPMI_BCH + if (bch) + c1 |= BM_GPMI_CTRL1_BCH_MODE; +#endif + return c1; +} +/** + * gpmi_nand_init_hw - initialize the hardware + * @pdev: pointer to platform device + * + * Initialize GPMI hardware and set default (safe) timings for NAND access. + * Returns error code or 0 on success + */ +static int gpmi_nand_init_hw(struct platform_device *pdev, int request_pins) +{ + struct gpmi_nand_data *g = platform_get_drvdata(pdev); + char *devname = pdev->dev.bus_id; + int err = 0; + + g->clk = clk_get(NULL, "gpmi"); + if (IS_ERR(g->clk)) { + err = PTR_ERR(g->clk); + dev_err(&pdev->dev, "cannot set failsafe clockrate\n"); + goto out; + } + clk_enable(g->clk); + if (clk <= 0) + clk = 24000; /* safe setting, some chips do not work on + speeds >= 24kHz */ + clk_set_rate(g->clk, clk); + + clk = clk_get_rate(g->clk); + + if (request_pins) + gpmi_pinmux_request(devname); + + stmp3xxx_reset_block(HW_GPMI_CTRL0_OFFSET + REGS_GPMI_BASE, 1); + + /* this CLEARS reset, despite of its name */ + HW_GPMI_CTRL1_SET(BM_GPMI_CTRL1_DEV_RESET); + + /* IRQ polarity */ + HW_GPMI_CTRL1_SET(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY); + + /* ...and ECC module */ + HW_GPMI_CTRL1_SET(bch_mode()); + + /* choose NAND mode (1 means ATA, 0 - NAND */ + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_GPMI_MODE); + +out: + return err; +} + +/** + * gpmi_nand_release_hw - free the hardware + * @pdev: pointer to platform device + * + * In opposite to gpmi_nand_init_hw, release all acquired resources + */ +static void gpmi_nand_release_hw(struct platform_device *pdev) +{ + struct gpmi_nand_data *g = platform_get_drvdata(pdev); + + HW_GPMI_CTRL0_SET(BM_GPMI_CTRL0_SFTRST); + + clk_disable(g->clk); + clk_put(g->clk); + gpmi_pinmux_free(pdev->dev.bus_id); +} + +static int gpmi_dma_is_error(struct gpmi_nand_data *g) +{ + /* u32 n = HW_APBH_CHn_NXTCMDAR_RD(g->dma_ch); */ + + /* CURrent DMA command */ + u32 c = HW_APBH_CHn_NXTCMDAR_RD(g->cchip->dma_ch); + + if (c == g->cchip->error.handle) { + pr_debug("%s: dma chain has reached error terminator\n", + __func__); + return -EIO; + } + return 0; +} + +/** + * gpmi_dma_exchange - run DMA to exchange with NAND chip + * + * @g: structure associated with NAND chip + * + * Run DMA and wait for completion + */ +static int gpmi_dma_exchange(struct gpmi_nand_data *g, + struct stmp3xxx_dma_descriptor *d) +{ + struct platform_device *pdev = g->dev; + unsigned long timeout; + int err; + + if (g->self_suspended) + gpmi_self_wakeup(g); + g->use_count++; + + if (!g->regulator) { + g->regulator = regulator_get(&pdev->dev, "mmc_ssp-2"); + if (g->regulator && !IS_ERR(g->regulator)) + regulator_set_mode( + g->regulator, + REGULATOR_MODE_NORMAL); + else + g->regulator = NULL; + } + + if (g->regulator) + regulator_set_current_limit(g->regulator, g->reg_uA, g->reg_uA); + + init_completion(&g->done); + stmp3xxx_dma_enable_interrupt(g->cchip->dma_ch); + stmp3xxx_dma_go(g->cchip->dma_ch, d ? d : g->cchip->d, 1); + + timeout = wait_for_completion_timeout(&g->done, msecs_to_jiffies(1000)); + err = (timeout <= 0) ? -ETIMEDOUT : gpmi_dma_is_error(g); + + if (err) + printk(KERN_ERR"%s: error %d, CS = %d, channel %d\n", + __func__, err, g->cchip->cs, g->cchip->dma_ch); + + stmp3xxx_dma_reset_channel(g->cchip->dma_ch); + stmp3xxx_dma_clear_interrupt(g->cchip->dma_ch); + + if (g->regulator) + regulator_set_current_limit(g->regulator, 0, 0); + + mod_timer(&g->timer, jiffies + 4*HZ); + g->use_count--; + + return err; +} + +/** + * gpmi_ecc_read_page - replacement for nand_read_page + * + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + */ +static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + struct gpmi_nand_data *g = chip->priv; + struct mtd_ecc_stats stats; + dma_addr_t bufphys, oobphys; + int err; + + bufphys = oobphys = ~0; + + if (map_buffers && virt_addr_valid(buf)) + bufphys = dma_map_single(&g->dev->dev, buf, + mtd->writesize, DMA_FROM_DEVICE); + if (dma_mapping_error(&g->dev->dev, bufphys)) + bufphys = g->data_buffer_handle; + + if (map_buffers) + oobphys = dma_map_single(&g->dev->dev, chip->oob_poi, + mtd->oobsize, DMA_FROM_DEVICE); + if (dma_mapping_error(&g->dev->dev, oobphys)) + oobphys = g->oob_buffer_handle; + + /* ECC read */ + (void)g->hc->read(g->hc, g->selected_chip, g->cchip->d, + g->cchip->error.handle, + bufphys, oobphys); + + err = gpmi_dma_exchange(g, NULL); + + g->hc->stat(g->hc, g->selected_chip, &stats); + + if (stats.failed || stats.corrected) { + + pr_debug("%s: ECC failed=%d, corrected=%d\n", + __func__, stats.failed, stats.corrected); + + g->mtd.ecc_stats.failed += stats.failed; + g->mtd.ecc_stats.corrected += stats.corrected; + } + + + if (!dma_mapping_error(&g->dev->dev, oobphys)) { + if (oobphys != g->oob_buffer_handle) + dma_unmap_single(&g->dev->dev, oobphys, + mtd->oobsize, DMA_FROM_DEVICE); + else { + memcpy(chip->oob_poi, g->oob_buffer, mtd->oobsize); + copies++; + } + } + + if (!dma_mapping_error(&g->dev->dev, bufphys)) { + if (bufphys != g->data_buffer_handle) + dma_unmap_single(&g->dev->dev, bufphys, + mtd->writesize, DMA_FROM_DEVICE); + else { + memcpy(buf, g->data_buffer, mtd->writesize); + copies++; + } + } + + /* always fill the (possible ECC bytes with FF) */ + memset(chip->oob_poi + g->oob_free, 0xff, mtd->oobsize - g->oob_free); + + return err; +} + +static inline int is_ff(const u8 *buffer, size_t size) +{ + while (size--) { + if (*buffer++ != 0xff) + return 0; + } + return 1; +} + +/** + * gpmi_ecc_write_page - replacement for nand_write_page + * + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + */ +static void gpmi_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + struct gpmi_nand_data *g = chip->priv; + dma_addr_t bufphys, oobphys; + int err; + + /* if we can't map it, copy it */ + bufphys = oobphys = ~0; + + if (map_buffers && virt_addr_valid(buf)) + bufphys = dma_map_single(&g->dev->dev, + (void *)buf, mtd->writesize, DMA_TO_DEVICE); + if (dma_mapping_error(&g->dev->dev, bufphys)) { + bufphys = g->data_buffer_handle; + memcpy(g->data_buffer, buf, mtd->writesize); + copies++; + } + + /* if OOB is all FF, leave it as such */ + if (!is_ff(chip->oob_poi, mtd->oobsize)) { + if (map_buffers) + oobphys = dma_map_single(&g->dev->dev, chip->oob_poi, + mtd->oobsize, DMA_TO_DEVICE); + if (dma_mapping_error(&g->dev->dev, oobphys)) { + oobphys = g->oob_buffer_handle; + memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize); + copies++; + } + } else + ff_writes++; + + /* call ECC */ + g->hc->write(g->hc, g->selected_chip, g->cchip->d, + g->cchip->error.handle, + bufphys, oobphys); + + err = gpmi_dma_exchange(g, NULL); + if (err < 0) + printk(KERN_ERR"%s: dma error\n", __func__); + + if (!dma_mapping_error(&g->dev->dev, oobphys)) { + if (oobphys != g->oob_buffer_handle) + dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize, + DMA_TO_DEVICE); + } + + if (bufphys != g->data_buffer_handle) + dma_unmap_single(&g->dev->dev, bufphys, mtd->writesize, + DMA_TO_DEVICE); +} + +/** + * gpmi_write_buf - replacement for nand_write_buf + * + * @mtd: MTD device + * @buf: data buffer + * @len: length of the data buffer + */ +static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + struct stmp3xxx_dma_descriptor *chain = g->cchip->d; + dma_addr_t phys; + int err; + + BUG_ON(len > mtd->writesize); + + phys = ~0; + + if (map_buffers && virt_addr_valid(buf)) + phys = dma_map_single(&g->dev->dev, + (void *)buf, len, DMA_TO_DEVICE); + if (dma_mapping_error(&g->dev->dev, phys)) { + phys = g->write_buffer_handle; + memcpy(g->write_buffer, buf, len); + copies++; + } + + /* write plain data */ + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(len) | + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__DMA_READ); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(g->selected_chip) | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_XFER_COUNT(len); + + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->pio_words[3] = 0; + chain->command->buf_ptr = phys; + + err = gpmi_dma_exchange(g, NULL); + if (err) + printk(KERN_ERR"%s: dma error\n", __func__); + + if (phys != g->write_buffer_handle) + dma_unmap_single(&g->dev->dev, phys, len, DMA_TO_DEVICE); + + if (debug >= 2) + print_hex_dump_bytes("WBUF ", DUMP_PREFIX_OFFSET, buf, len); +} + +/** + * gpmi_read_buf - replacement for nand_read_buf + * + * @mtd: MTD device + * @buf: pointer to the buffer + * @len: size of the buffer + */ +static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + struct stmp3xxx_dma_descriptor *chain; + dma_addr_t phys; + int err; + + phys = ~0; + + if (map_buffers && virt_addr_valid(buf)) + phys = dma_map_single(&g->dev->dev, + buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(&g->dev->dev, phys)) + phys = g->read_buffer_handle; + + chain = g->cchip->d; + + /* read data */ + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(len) | + BF_APBH_CHn_CMD_CMDWORDS(1) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__DMA_WRITE); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(g->selected_chip) | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_XFER_COUNT(len); + chain->command->buf_ptr = phys; + chain++; + + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(g->selected_chip); + chain->command->pio_words[1] = + chain->command->pio_words[2] = + chain->command->pio_words[3] = 0; + chain->command->buf_ptr = 0; + + err = gpmi_dma_exchange(g, NULL); + if (err) + printk(KERN_ERR"%s: dma error\n", __func__); + + if (phys != g->read_buffer_handle) + dma_unmap_single(&g->dev->dev, phys, len, DMA_FROM_DEVICE); + else { + memcpy(buf, g->read_buffer, len); + copies++; + } + + if (debug >= 2) + print_hex_dump_bytes("RBUF ", DUMP_PREFIX_OFFSET, buf, len); +} + +/** + * gpmi_read_byte - replacement for nand_read_byte + * @mtd: MTD device + * + * Uses gpmi_read_buf to read 1 byte from device + */ +static u8 gpmi_read_byte(struct mtd_info *mtd) +{ + u8 b; + + gpmi_read_buf(mtd, (uint8_t *)&b, 1); + return b; +} + +/** + * gpmi_read_word - replacement for nand_read_word + * @mtd: MTD device + * + * Uses gpmi_read_buf to read 2 bytes from device + */ +static u16 gpmi_read_word(struct mtd_info *mtd) +{ + u16 w; + + gpmi_read_buf(mtd, (uint8_t *)&w, sizeof(u16)); + return w; +} + +/** + * gpmi_erase - erase a block and update BBT table + * + * @mtd: MTD device + * @instr: erase instruction + */ +int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + int rc; + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + struct gpmi_nand_data *data = platform_get_drvdata(g->dev); + + if (g->self_suspended) + gpmi_self_wakeup(data); + g->use_count++; + + rc = nand_erase_nand(mtd, instr, 0); + + if (rc == -EIO) /* block cannot be erased */ + gpmi_block_mark_as(chip, + (instr->addr >> chip->bbt_erase_shift), + 0x01); + + mod_timer(&g->timer, jiffies + 4*HZ); + g->use_count--; + return rc; +} + +/** + * gpmi_dev_ready - poll the RDY pin + * + * @mtd: MTD device + */ +static int gpmi_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + struct stmp3xxx_dma_descriptor *chain = g->cchip->d; + int ret; + + /* wait for ready */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND( + BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_ADDRESS( + BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_CS(g->selected_chip); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->pio_words[3] = 0; + chain->command->buf_ptr = 0; + chain++; + + ret = gpmi_dma_exchange(g, NULL); + if (ret != 0) + printk(KERN_ERR "gpmi: gpmi_dma_exchange() timeout!\n"); + return ret == 0; +} + +/** + * gpmi_hwcontrol - set command/address byte to the device + * + * @mtd: MTD device + * @cmd: command byte + * @ctrl: control flags + */ +static void gpmi_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + struct stmp3xxx_dma_descriptor *chain = g->cchip->d; + int ret; + + if ((ctrl & (NAND_ALE | NAND_CLE))) { + if (cmd != NAND_CMD_NONE) + g->cmd_buffer[g->cmd_buffer_sz++] = cmd; + return; + } + + if (g->cmd_buffer_sz == 0) + return; + + /* output command */ + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(g->cmd_buffer_sz) | + BF_APBH_CHn_CMD_CMDWORDS(3) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__DMA_READ); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(g->selected_chip) | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) | + BF_GPMI_CTRL0_XFER_COUNT(g->cmd_buffer_sz); + if (g->cmd_buffer_sz > 0) + chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT; + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->buf_ptr = g->cmd_buffer_handle; + chain++; + + /* emit IRQ */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(0) | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER) | + BM_APBH_CHn_CMD_WAIT4ENDCMD; + chain++; + + /* last in chain get the irq bit set */ + chain[-1].command->cmd |= BM_APBH_CHn_CMD_IRQONCMPLT; + + if (debug >= 3) + print_hex_dump(KERN_INFO, "CMD ", DUMP_PREFIX_OFFSET, 16, 1, + g->cmd_buffer, g->cmd_buffer_sz, 1); + + ret = gpmi_dma_exchange(g, NULL); + if (ret != 0) { + printk(KERN_ERR"%s: chip %d, dma error %d on the command:\n", + __func__, g->selected_chip, ret); + print_hex_dump(KERN_INFO, "CMD ", DUMP_PREFIX_OFFSET, 16, 1, + g->cmd_buffer, g->cmd_buffer_sz, 1); + } + + gpmi_dev_ready(mtd); + + g->cmd_buffer_sz = 0; +} + +/** + * gpmi_alloc_buffers - allocate DMA buffers for one chip + * + * @pdev: GPMI platform device + * @g: pointer to structure associated with NAND chip + * + * Allocate buffer using dma_alloc_coherent + */ +static int gpmi_alloc_buffers(struct platform_device *pdev, + struct gpmi_nand_data *g) +{ + g->cmd_buffer = dma_alloc_coherent(&pdev->dev, + g->cmd_buffer_size, + &g->cmd_buffer_handle, GFP_DMA); + if (!g->cmd_buffer) + goto out1; + + g->write_buffer = dma_alloc_coherent(&pdev->dev, + g->write_buffer_size * 2, + &g->write_buffer_handle, GFP_DMA); + if (!g->write_buffer) + goto out2; + + g->read_buffer = g->write_buffer + g->write_buffer_size; + g->read_buffer_handle = g->write_buffer_handle + g->write_buffer_size; + + g->data_buffer = dma_alloc_coherent(&pdev->dev, + g->data_buffer_size, + &g->data_buffer_handle, GFP_DMA); + if (!g->data_buffer) + goto out3; + + g->oob_buffer = dma_alloc_coherent(&pdev->dev, + g->oob_buffer_size, + &g->oob_buffer_handle, GFP_DMA); + if (!g->oob_buffer) + goto out4; + + g->verify_buffer = kzalloc(2 * (g->data_buffer_size + + g->oob_buffer_size), GFP_KERNEL); + if (!g->verify_buffer) + goto out5; + + return 0; + +out5: + dma_free_coherent(&pdev->dev, g->oob_buffer_size, + g->oob_buffer, g->oob_buffer_handle); +out4: + dma_free_coherent(&pdev->dev, g->data_buffer_size, + g->data_buffer, g->data_buffer_handle); +out3: + dma_free_coherent(&pdev->dev, g->write_buffer_size * 2, + g->write_buffer, g->write_buffer_handle); +out2: + dma_free_coherent(&pdev->dev, g->cmd_buffer_size, + g->cmd_buffer, g->cmd_buffer_handle); +out1: + return -ENOMEM; +} + +/** + * gpmi_free_buffers - free buffers allocated by gpmi_alloc_buffers + * + * @pdev: platform device + * @g: pointer to structure associated with NAND chip + * + * Deallocate buffers on exit + */ +static void gpmi_free_buffers(struct platform_device *pdev, + struct gpmi_nand_data *g) +{ + kfree(g->verify_buffer); + dma_free_coherent(&pdev->dev, g->oob_buffer_size, + g->oob_buffer, g->oob_buffer_handle); + dma_free_coherent(&pdev->dev, g->write_buffer_size * 2, + g->write_buffer, g->write_buffer_handle); + dma_free_coherent(&pdev->dev, g->cmd_buffer_size, + g->cmd_buffer, g->cmd_buffer_handle); + dma_free_coherent(&pdev->dev, g->data_buffer_size, + g->data_buffer, g->data_buffer_handle); +} + +/* only used in SW-ECC or NO-ECC cases */ +static int gpmi_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + + chip->read_buf(mtd, g->verify_buffer, len); + + if (memcmp(buf, g->verify_buffer, len)) + return -EFAULT; + + return 0; +} + +/** + * gpmi_ecc_read_oob - replacement for nand_read_oob + * + * @mtd: MTD device + * @chip: mtd->priv + * @page: page address + * @sndcmd: flag indicates that command should be sent + */ +int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + struct gpmi_nand_data *g = chip->priv; + loff_t oob_offset; + struct mtd_ecc_stats stats; + dma_addr_t oobphys; + int ecc; + int ret; + + ecc = g->raw_oob_mode == 0 && raw_mode == 0; + + if (sndcmd) { + oob_offset = mtd->writesize; + if (likely(ecc)) + oob_offset += chip->ecc.bytes * chip->ecc.steps; + chip->cmdfunc(mtd, NAND_CMD_READ0, oob_offset, page); + sndcmd = 0; + } + + if (unlikely(!ecc)) { + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return 1; + } + + oobphys = ~0; + + if (map_buffers) + oobphys = dma_map_single(&g->dev->dev, chip->oob_poi, + mtd->oobsize, DMA_FROM_DEVICE); + if (dma_mapping_error(&g->dev->dev, oobphys)) + oobphys = g->oob_buffer_handle; + + /* ECC read */ + (void)g->hc->read(g->hc, g->selected_chip, g->cchip->d, + g->cchip->error.handle, ~0, oobphys); + + ret = gpmi_dma_exchange(g, NULL); + + g->hc->stat(g->hc, g->selected_chip, &stats); + + if (stats.failed || stats.corrected) { + + printk(KERN_DEBUG "%s: ECC failed=%d, corrected=%d\n", + __func__, stats.failed, stats.corrected); + + g->mtd.ecc_stats.failed += stats.failed; + g->mtd.ecc_stats.corrected += stats.corrected; + } + + if (oobphys != g->oob_buffer_handle) + dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize, + DMA_FROM_DEVICE); + else { + memcpy(chip->oob_poi, g->oob_buffer, mtd->oobsize); + copies++; + } + + /* fill rest with ff */ + memset(chip->oob_poi + g->oob_free, 0xff, mtd->oobsize - g->oob_free); + + return ret ? ret : 1; +} + +/** + * gpmi_ecc_write_oob - replacement for nand_write_oob + * + * @mtd: MTD device + * @chip: mtd->priv + * @page: page address + */ +static int gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0; + struct gpmi_nand_data *g = chip->priv; + loff_t oob_offset; + dma_addr_t oobphys; + int ecc; + int err = 0; + + /* if OOB is all FF, leave it as such */ + if (is_ff(chip->oob_poi, mtd->oobsize)) { + ff_writes++; + + pr_debug("%s: Skipping an empty page 0x%x (0x%x)\n", + __func__, + page, page << chip->page_shift); + return 0; + } + + ecc = g->raw_oob_mode == 0 && raw_mode == 0; + + /* Send command to start input data */ + oob_offset = mtd->writesize; + if (likely(ecc)) { + oob_offset += chip->ecc.bytes * chip->ecc.steps; + memset(chip->oob_poi + g->oob_free, 0xff, + mtd->oobsize - g->oob_free); + } + chip->cmdfunc(mtd, NAND_CMD_SEQIN, oob_offset, page); + + /* call ECC */ + if (likely(ecc)) { + + oobphys = ~0; + + if (map_buffers) + oobphys = dma_map_single(&g->dev->dev, chip->oob_poi, + mtd->oobsize, DMA_TO_DEVICE); + if (dma_mapping_error(&g->dev->dev, oobphys)) { + oobphys = g->oob_buffer_handle; + memcpy(g->oob_buffer, chip->oob_poi, mtd->oobsize); + copies++; + } + + g->hc->write(g->hc, g->selected_chip, g->cchip->d, + g->cchip->error.handle, ~0, oobphys); + + err = gpmi_dma_exchange(g, NULL); + } else + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + /* ..and wait for result */ + status = chip->waitfunc(mtd, chip); + + if (likely(ecc)) { + if (oobphys != g->oob_buffer_handle) + dma_unmap_single(&g->dev->dev, oobphys, mtd->oobsize, + DMA_TO_DEVICE); + } + + if (status & NAND_STATUS_FAIL) { + pr_debug("%s: NAND_STATUS_FAIL\n", __func__); + return -EIO; + } + + return err; +} + +/** + * gpmi_irq - IRQ handler + * + * @irq: irq no + * @context: IRQ context, pointer to gpmi_nand_data + */ +static irqreturn_t gpmi_irq(int irq, void *context) +{ + struct gpmi_nand_data *g = context; + + if (stmp3xxx_dma_is_interrupt(g->cchip->dma_ch)) { + stmp3xxx_dma_clear_interrupt(g->cchip->dma_ch); + complete(&g->done); + } + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_DEV_IRQ | BM_GPMI_CTRL1_TIMEOUT_IRQ); + return IRQ_HANDLED; +} + +static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + + if (chipnr == g->selected_chip) + return; + + g->selected_chip = chipnr; + g->cchip = NULL; + + if (chipnr == -1) + return; + + g->cchip = g->chips + chipnr; +} + +static void gpmi_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + + g->saved_command(mtd, command, column, page_addr); +} + +static int gpmi_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + register struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + int ret; + + g->raw_oob_mode = ops->mode == MTD_OOB_RAW; + ret = g->saved_read_oob(mtd, from, ops); + g->raw_oob_mode = 0; + return ret; +} + +static int gpmi_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + register struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *g = chip->priv; + int ret; + + g->raw_oob_mode = ops->mode == MTD_OOB_RAW; + ret = g->saved_write_oob(mtd, to, ops); + g->raw_oob_mode = 0; + return ret; +} + +/** + * perform the needed steps between nand_scan_ident and nand_scan_tail + */ +static int gpmi_scan_middle(struct gpmi_nand_data *g) +{ + int oobsize = 0; + + g->ecc_oob_bytes = 9; + switch (g->mtd.writesize) { + case 2048: /* 2K page */ + g->chip.ecc.layout = &gpmi_oob_64; + g->chip.ecc.bytes = 9; + g->oob_free = 19; + g->hwecc_type_read = GPMI_ECC4_RD; + g->hwecc_type_write = GPMI_ECC4_WR; + oobsize = 64; + break; + case 4096: + g->chip.ecc.layout = &gpmi_oob_128; + g->chip.ecc.bytes = 18; + g->oob_free = 65; + g->hwecc_type_read = GPMI_ECC8_RD; + g->hwecc_type_write = GPMI_ECC8_WR; + oobsize = 218; + break; + default: + printk(KERN_ERR "Unsupported write_size %d.", + g->mtd.writesize); + break; + } + + g->mtd.ecclayout = g->chip.ecc.layout; + /* sanity check */ + if (oobsize > NAND_MAX_OOBSIZE || + g->mtd.writesize > NAND_MAX_PAGESIZE) { + printk(KERN_ERR "Internal error. Either page size " + "(%d) > max (%d) " + "or oob size (%d) > max(%d). Sorry.\n", + oobsize, NAND_MAX_OOBSIZE, + g->mtd.writesize, NAND_MAX_PAGESIZE); + return -ERANGE; + } + + g->saved_command = g->chip.cmdfunc; + g->chip.cmdfunc = gpmi_command; + + if (oobsize > 0) { + g->mtd.oobsize = oobsize; + /* otherwise error; oobsize should be set + in valid cases */ + g->hc = gpmi_hwecc_chip_find("ecc8"); + g->hc->setup(g->hc, 0, g->mtd.writesize, g->mtd.oobsize); + return 0; + } + + return -ENXIO; +} + +/** + * gpmi_write_page - [REPLACEABLE] write one page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page + */ +static int gpmi_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int page, int cached, int raw) +{ + struct gpmi_nand_data *g = chip->priv; + int status, empty_data, empty_oob; + int oobsz; +#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) + void *vbuf, *obuf; +#if 0 + void *voob, *ooob; +#endif +#endif + + oobsz = likely(g->raw_oob_mode == 0 && raw_mode == 0) ? + g->oob_free : mtd->oobsize; + + empty_data = is_ff(buf, mtd->writesize); + empty_oob = is_ff(buf, oobsz); + + if (empty_data && empty_oob) { + ff_writes++; + + pr_debug("%s: Skipping an empty page 0x%x (0x%x)\n", + __func__, + page, page << chip->page_shift); + return 0; + } + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + + if (likely(raw == 0)) + chip->ecc.write_page(mtd, chip, buf); + else + chip->ecc.write_page_raw(mtd, chip, buf); + + /* + * Cached progamming disabled for now, Not sure if its worth the + * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + */ + cached = 0; + + if (!cached || !(chip->options & NAND_CACHEPRG)) { + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + + /* + * See if operation failed and additional status checks are + * available + */ + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) + status = chip->errstat(mtd, chip, FL_WRITING, status, + page); + + if (status & NAND_STATUS_FAIL) { + pr_debug("%s: NAND_STATUS_FAIL\n", __func__); + return -EIO; + } + } else { + chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + } + +#if defined(CONFIG_MTD_NAND_VERIFY_WRITE) + if (empty_data) + return 0; + + obuf = g->verify_buffer; +#if 1 /* make vbuf aligned by mtd->writesize */ + vbuf = obuf + mtd->writesize; +#else + ooob = obuf + mtd->writesize; + vbuf = ooob + mtd->oobsize; + voob = vbuf + mtd->writesize; +#endif + + /* keep data around */ + memcpy(obuf, buf, mtd->writesize); +#if 0 + memcpy(ooob, chip->oob_poi, oobsz); +#endif + /* Send command to read back the data */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + if (likely(raw == 0)) + chip->ecc.read_page(mtd, chip, vbuf); + else + chip->ecc.read_page_raw(mtd, chip, vbuf); + +#if 0 + memcpy(voob, chip->oob_poi, oobsz); +#endif + + if (!empty_data && memcmp(obuf, vbuf, mtd->writesize) != 0) + return -EIO; +#endif + + return 0; +} + +/** + * gpmi_read_page_raw - [Intern] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + */ +static int gpmi_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +/** + * gpmi_write_page_raw - [Intern] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + */ +static void gpmi_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf) +{ + chip->write_buf(mtd, buf, mtd->writesize); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +} + +static int gpmi_init_chip(struct platform_device *pdev, + struct gpmi_nand_data *g, int n, unsigned dma_ch) +{ + int err; + + g->chips[n].dma_ch = dma_ch; + g->chips[n].cs = n; + + err = stmp3xxx_dma_request(dma_ch, NULL, pdev->dev.bus_id); + if (err) { + dev_err(&pdev->dev, + "can't request DMA channel 0x%x\n", dma_ch); + goto out_all; + } + + err = stmp3xxx_dma_make_chain( + dma_ch, + &g->chips[n].chain, + g->chips[n].d, ARRAY_SIZE(g->chips[n].d)); + if (err) { + dev_err(&pdev->dev, "can't setup DMA chain\n"); + goto out_all; + } + + err = stmp3xxx_dma_allocate_command( + dma_ch, + &g->chips[n].error); + if (err) { + dev_err(&pdev->dev, "can't setup DMA chain\n"); + goto out_all; + } + + g->chips[n].error.command->cmd = + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); +out_all: + return err; +} + +static void gpmi_deinit_chip(struct platform_device *pdev, + struct gpmi_nand_data *g, int n) +{ + int dma_ch; + + if (n < 0) { + for (n = 0; n < ARRAY_SIZE(g->chips); n++) + gpmi_deinit_chip(pdev, g, n); + return; + } + + if (g->chips[n].dma_ch <= 0) + return; + + dma_ch = g->chips[n].dma_ch; + + stmp3xxx_dma_free_command(dma_ch, &g->chips[n].error); + stmp3xxx_dma_free_chain(&g->chips[n].chain); + stmp3xxx_dma_release(dma_ch); +} + +static int gpmi_to_concat(struct mtd_partition *part, char **list) +{ + while (list && *list) { + if (strcmp(part->name, *list) == 0) { + pr_debug("Partition '%s' will be concatenated\n", + part->name); + return true; + } + list++; + } + pr_debug("Partition '%s' is left as-is", part->name); + return false; +} + +static void gpmi_create_partitions(struct gpmi_nand_data *g, + struct gpmi_platform_data *gpd, uint64_t chipsize) +{ +#ifdef CONFIG_MTD_PARTITIONS + int chip, p; + char chipname[20]; + + if (g->numchips == 1) + g->masters[0] = &g->mtd; + else { + for (chip = 0; chip < g->numchips; chip++) { + memset(g->chip_partitions + chip, + 0, sizeof(g->chip_partitions[chip])); + snprintf(chipname, sizeof(chipname), + "gpmi-chip-%d", chip); + g->chip_partitions[chip].name = + kstrdup(chipname, GFP_KERNEL); + g->chip_partitions[chip].size = chipsize; + g->chip_partitions[chip].offset = chipsize * chip; + g->chip_partitions[chip].mask_flags = 0; + g->chip_partitions[chip].mtdp = &g->masters[chip]; + } + add_mtd_partitions(&g->mtd, g->chip_partitions, g->numchips); + } + g->n_concat = 0; + memset(g->concat, 0, sizeof(g->concat)); + for (chip = 0; chip < g->numchips; chip++) { + if (add_mtd_chip) { + printk(KERN_NOTICE"Adding MTD for the chip %d\n", chip); + add_mtd_device(g->masters[chip]); + } + if (chip >= gpd->items) + continue; + for (p = 0; p < gpd->parts[chip].nr_partitions; p++) { + if (gpmi_to_concat(&gpd->parts[chip].partitions[p], + gpd->concat_parts)) + gpd->parts[chip].partitions[p].mtdp = + &g->concat[g->n_concat++]; + } + add_mtd_partitions(g->masters[chip], + gpd->parts[chip].partitions, + gpd->parts[chip].nr_partitions); + } + if (g->n_concat > 0) { +#ifdef CONFIG_MTD_CONCAT + if (g->n_concat == 1) +#endif + for (p = 0; p < g->n_concat; p++) + add_mtd_device(g->concat[p]); +#ifdef CONFIG_MTD_CONCAT + if (g->n_concat > 1) { + g->concat_mtd = mtd_concat_create(g->concat, + g->n_concat, gpd->concat_name); + if (g->concat_mtd) + add_mtd_device(g->concat_mtd); + } +#endif + } + g->custom_partitions = true; +#endif +} + +static void gpmi_delete_partitions(struct gpmi_nand_data *g) +{ +#ifdef CONFIG_MTD_PARTITIONS + int chip, p; + + if (!g->custom_partitions) + return; +#ifdef CONFIG_MTD_CONCAT + if (g->concat_mtd) + del_mtd_device(g->concat_mtd); + if (g->n_concat == 1) +#endif + for (p = 0; p < g->n_concat; p++) + del_mtd_device(g->concat[p]); + + for (chip = 0; chip < g->numchips; chip++) { + del_mtd_partitions(g->masters[chip]); + if (add_mtd_chip) + del_mtd_device(g->masters[chip]); + kfree(g->chip_partitions[chip].name); + } +#endif +} +/** + * gpmi_nand_probe - probe for the GPMI device + * + * Probe for GPMI device and discover NAND chips + */ +static int __init gpmi_nand_probe(struct platform_device *pdev) +{ + struct gpmi_nand_data *g; + struct gpmi_platform_data *gpd; + const char *part_type = 0; + int err = 0; + struct resource *r; + int dma; + unsigned long long chipsize; + + /* Allocate memory for the device structure (and zero it) */ + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) { + dev_err(&pdev->dev, "failed to allocate gpmi_nand_data\n"); + err = -ENOMEM; + goto out1; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "failed to get resource\n"); + err = -ENXIO; + goto out2; + } + g->io_base = ioremap(r->start, r->end - r->start + 1); + if (!g->io_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -EIO; + goto out2; + } + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) { + err = -EIO; + dev_err(&pdev->dev, "can't get IRQ resource\n"); + goto out3; + } + + gpd = (struct gpmi_platform_data *)pdev->dev.platform_data; + platform_set_drvdata(pdev, g); + err = gpmi_nand_init_hw(pdev, 1); + if (err) + goto out3; + + init_timer(&g->timer); + g->timer.data = (unsigned long)g; + g->timer.function = gpmi_timer_expiry; + g->timer.expires = jiffies + 4*HZ; + add_timer(&g->timer); + dev_dbg(&pdev->dev, "%s: timer set to %ld\n", + __func__, jiffies + 4*HZ); + + g->reg_uA = gpd->io_uA; + g->regulator = regulator_get(&pdev->dev, "mmc_ssp-2"); + if (g->regulator && !IS_ERR(g->regulator)) { + regulator_set_mode( + g->regulator, + REGULATOR_MODE_NORMAL); + } else + g->regulator = NULL; + + gpmi_set_timings(pdev, &gpmi_safe_timing); + + g->irq = r->start; + err = request_irq(g->irq, + gpmi_irq, 0, pdev->dev.bus_id, g); + if (err) { + dev_err(&pdev->dev, "can't request GPMI IRQ\n"); + goto out4; + } + + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) { + dev_err(&pdev->dev, "can't get DMA resource\n"); + goto out5; + } + + if (r->end - r->start > GPMI_MAX_CHIPS) + dev_info(&pdev->dev, "too spread resource: max %d chips\n", + GPMI_MAX_CHIPS); + + for (dma = r->start; + dma < min_t(int, r->end, r->start + GPMI_MAX_CHIPS); + dma++) { + err = gpmi_init_chip(pdev, g, dma - r->start, dma); + if (err) + goto out6; + } + + g->cmd_buffer_size = GPMI_CMD_BUF_SZ; + g->write_buffer_size = GPMI_WRITE_BUF_SZ; + g->data_buffer_size = GPMI_DATA_BUF_SZ; + g->oob_buffer_size = GPMI_OOB_BUF_SZ; + + err = gpmi_alloc_buffers(pdev, g); + if (err) { + dev_err(&pdev->dev, "can't setup buffers\n"); + goto out6; + } + + g->dev = pdev; + g->chip.priv = g; + g->timing = gpmi_safe_timing; + g->selected_chip = -1; + g->ignorebad = ignorebad; /* copy global setting */ + + g->mtd.priv = &g->chip; + g->mtd.name = pdev->dev.bus_id; + g->mtd.owner = THIS_MODULE; + + g->chip.cmd_ctrl = gpmi_hwcontrol; + g->chip.read_word = gpmi_read_word; + g->chip.read_byte = gpmi_read_byte; + g->chip.read_buf = gpmi_read_buf; + g->chip.write_buf = gpmi_write_buf; + g->chip.select_chip = gpmi_select_chip; + g->chip.verify_buf = gpmi_verify_buf; + g->chip.dev_ready = gpmi_dev_ready; + + g->chip.ecc.mode = NAND_ECC_HW_SYNDROME; + g->chip.ecc.write_oob = gpmi_ecc_write_oob; + g->chip.ecc.read_oob = gpmi_ecc_read_oob; + g->chip.ecc.write_page = gpmi_ecc_write_page; + g->chip.ecc.read_page = gpmi_ecc_read_page; + g->chip.ecc.read_page_raw = gpmi_read_page_raw; + g->chip.ecc.write_page_raw = gpmi_write_page_raw; + g->chip.ecc.size = 512; + + g->chip.write_page = gpmi_write_page; + + g->chip.scan_bbt = gpmi_scan_bbt; + g->chip.block_bad = gpmi_block_bad; + + g->cmd_buffer_sz = 0; + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(&g->mtd, max_chips) + || gpmi_scan_middle(g) + || nand_scan_tail(&g->mtd)) { + dev_err(&pdev->dev, "No NAND found\n"); + /* errors found on some step */ + goto out7; + } + + g->chip.options |= NAND_NO_SUBPAGE_WRITE; + g->chip.subpagesize = g->mtd.writesize; + g->mtd.subpage_sft = 0; + + g->mtd.erase = gpmi_erase; + + g->saved_read_oob = g->mtd.read_oob; + g->saved_write_oob = g->mtd.write_oob; + g->mtd.read_oob = gpmi_read_oob; + g->mtd.write_oob = gpmi_write_oob; + +#ifdef CONFIG_MTD_PARTITIONS + if (gpd == NULL) + goto out_all; + + if (gpd->parts[0].part_probe_types) { + g->nr_parts = parse_mtd_partitions(&g->mtd, + gpd->parts[0].part_probe_types, + &g->parts, 0); + if (g->nr_parts > 0) + part_type = "command line"; + else + g->nr_parts = 0; + } + + if (g->nr_parts == 0 && gpd->parts[0].partitions) { + g->parts = gpd->parts[0].partitions; + g->nr_parts = gpd->parts[0].nr_partitions; + part_type = "static"; + } + + if (g->nr_parts == 0) { + dev_err(&pdev->dev, "Neither part_probe_types nor " + "partitions was specified in platform_data"); + goto out_all; + } + + dev_info(&pdev->dev, "Using %s partition definition\n", + part_type); + + g->numchips = g->chip.numchips; + chipsize = g->mtd.size; + do_div(chipsize, (unsigned long)g->numchips); + + if (!strcmp(part_type, "command line")) + add_mtd_partitions(&g->mtd, g->parts, g->nr_parts); + else + gpmi_create_partitions(g, gpd, chipsize); + + if (add_mtd_entire) { + printk(KERN_NOTICE "Adding MTD covering the whole flash\n"); + add_mtd_device(&g->mtd); + } +#else + add_mtd_device(&g->mtd); +#endif + gpmi_uid_init("nand", + &g->mtd, gpd->uid_offset, gpd->uid_size); + +#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES + gpmi_sysfs(pdev, true); +#endif + return 0; + +out_all: + ecc8_exit(); + bch_exit(); +out7: + nand_release(&g->mtd); + gpmi_free_buffers(pdev, g); +out6: + gpmi_deinit_chip(pdev, g, -1); +out5: + free_irq(g->irq, g); +out4: + del_timer_sync(&g->timer); + gpmi_nand_release_hw(pdev); +out3: + platform_set_drvdata(pdev, NULL); + iounmap(g->io_base); +out2: + kfree(g); +out1: + return err; +} + +/** + * gpmi_nand_remove - remove a GPMI device + * + */ +static int __devexit gpmi_nand_remove(struct platform_device *pdev) +{ + struct gpmi_nand_data *g = platform_get_drvdata(pdev); + int i = 0; +#ifdef CONFIG_MTD_PARTITIONS + struct gpmi_platform_data *gpd = pdev->dev.platform_data; + struct mtd_partition *platf_parts; +#endif + + gpmi_delete_partitions(g); + del_timer_sync(&g->timer); + gpmi_uid_remove("nand"); +#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES + gpmi_sysfs(pdev, false); +#endif + nand_release(&g->mtd); + gpmi_free_buffers(pdev, g); + gpmi_deinit_chip(pdev, g, -1); + gpmi_nand_release_hw(pdev); + free_irq(g->irq, g); + if (g->regulator) + regulator_put(g->regulator); + +#ifdef CONFIG_MTD_PARTITIONS + if (i < gpd->items && gpd->parts[i].partitions) + platf_parts = gpd->parts[i].partitions; + else + platf_parts = NULL; + if (g->parts && g->parts != platf_parts) + kfree(g->parts); +#endif + iounmap(g->io_base); + kfree(g); + + return 0; +} + +#ifdef CONFIG_PM +static int gpmi_nand_suspend(struct platform_device *pdev, pm_message_t pm) +{ + struct gpmi_nand_data *g = platform_get_drvdata(pdev); + int r = 0; + + if (g->self_suspended) + gpmi_self_wakeup(g); + del_timer_sync(&g->timer); + + r = g->mtd.suspend(&g->mtd); + if (r == 0) + gpmi_nand_release_hw(pdev); + + return r; +} + +static int gpmi_nand_resume(struct platform_device *pdev) +{ + struct gpmi_nand_data *g = platform_get_drvdata(pdev); + int r; + + r = gpmi_nand_init_hw(pdev, 1); + gpmi_set_timings(pdev, &g->timing); + g->mtd.resume(&g->mtd); + g->timer.expires = jiffies + 4*HZ; + add_timer(&g->timer); + return r; +} +#else +#define gpmi_nand_suspend NULL +#define gpmi_nand_resume NULL +#endif + +#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES +static ssize_t show_timings(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct gpmi_nand_timing *ptm; + struct gpmi_nand_data *g = dev_get_drvdata(d); + + ptm = &g->timing; + return sprintf(buf, "DATA_SETUP %d, DATA_HOLD %d, " + "ADDR_SETUP %d, DSAMPLE_TIME %d\n", + ptm->data_setup, ptm->data_hold, + ptm->address_setup, + ptm->dsample_time); +} + +static ssize_t store_timings(struct device *d, struct device_attribute *attr, + const char *buf, size_t size) +{ + const char *p, *end; + struct gpmi_nand_timing t; + struct gpmi_nand_data *g = dev_get_drvdata(d); + char tmps[20]; + u8 *timings[] = { + &t.data_setup, + &t.data_hold, + &t.address_setup, + &t.dsample_time, + NULL, + }; + u8 **timing = timings; + + p = buf; + + /* parse values */ + while (*timing != NULL) { + unsigned long t_long; + + end = strchr(p, ','); + memset(tmps, 0, sizeof(tmps)); + if (end) + strncpy(tmps, p, min_t(int, sizeof(tmps) - 1, end - p)); + else + strncpy(tmps, p, sizeof(tmps) - 1); + + if (strict_strtoul(tmps, 0, &t_long) < 0) + return -EINVAL; + + if (t_long > 255) + return -EINVAL; + + **timing = (u8)t_long; + timing++; + + if (!end && *timing) + return -EINVAL; + p = end + 1; + } + + gpmi_set_timings(g->dev, &t); + + return size; +} + +static ssize_t show_stat(struct device *d, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "copies\t\t%dff pages\t%d\n", copies, ff_writes); +} + +static ssize_t show_chips(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct gpmi_nand_data *g = dev_get_drvdata(d); + return sprintf(buf, "%d\n", g->numchips); +} + + +static ssize_t show_ignorebad(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct gpmi_nand_data *g = dev_get_drvdata(d); + + return sprintf(buf, "%d\n", g->ignorebad); +} + +static ssize_t store_ignorebad(struct device *d, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct gpmi_nand_data *g = dev_get_drvdata(d); + const char *p = buf; + unsigned long v; + + if (strict_strtoul(p, 0, &v) < 0) + return size; + if (v > 0) + v = 1; + if (v != g->ignorebad) { + if (v) { + g->bbt = g->chip.bbt; + g->chip.bbt = NULL; + g->ignorebad = 1; + } else { + g->chip.bbt = g->bbt; + g->ignorebad = 0; + } + } + return size; +} + +static DEVICE_ATTR(timings, 0644, show_timings, store_timings); +static DEVICE_ATTR(stat, 0444, show_stat, NULL); +static DEVICE_ATTR(ignorebad, 0644, show_ignorebad, store_ignorebad); +static DEVICE_ATTR(numchips, 0444, show_chips, NULL); + +static struct device_attribute *gpmi_attrs[] = { + &dev_attr_timings, + &dev_attr_stat, + &dev_attr_ignorebad, + &dev_attr_numchips, + NULL, +}; + +int gpmi_sysfs(struct platform_device *pdev, int create) +{ + int err = 0; + int i; + + if (create) { + for (i = 0; gpmi_attrs[i]; i++) { + err = device_create_file(&pdev->dev, gpmi_attrs[i]); + if (err) + break; + } + if (err) + while (--i >= 0) + device_remove_file(&pdev->dev, gpmi_attrs[i]); + } else { + for (i = 0; gpmi_attrs[i]; i++) + device_remove_file(&pdev->dev, gpmi_attrs[i]); + } + return err; +} +#endif + +static struct platform_driver gpmi_nand_driver = { + .probe = gpmi_nand_probe, + .remove = __devexit_p(gpmi_nand_remove), + .driver = { + .name = "gpmi", + .owner = THIS_MODULE, + }, + .suspend = gpmi_nand_suspend, + .resume = gpmi_nand_resume, +}; + +static LIST_HEAD(gpmi_hwecc_chips); + +void gpmi_hwecc_chip_add(struct gpmi_hwecc_chip *chip) +{ + list_add(&chip->list, &gpmi_hwecc_chips); +} +EXPORT_SYMBOL_GPL(gpmi_hwecc_chip_add); + +void gpmi_hwecc_chip_remove(struct gpmi_hwecc_chip *chip) +{ + list_del(&chip->list); +} +EXPORT_SYMBOL_GPL(gpmi_hwecc_chip_remove); + +struct gpmi_hwecc_chip *gpmi_hwecc_chip_find(char *name) +{ + struct gpmi_hwecc_chip *c; + + list_for_each_entry(c, &gpmi_hwecc_chips, list) + if (strncmp(c->name, name, sizeof(c->name)) == 0) + return c; + return NULL; +} +EXPORT_SYMBOL_GPL(gpmi_hwecc_chip_find); + +static int __init gpmi_nand_init(void) +{ + bch_init(); + ecc8_init(); + return platform_driver_register(&gpmi_nand_driver); +} + +static void __exit gpmi_nand_exit(void) +{ + platform_driver_unregister(&gpmi_nand_driver); +} + +module_init(gpmi_nand_init); +module_exit(gpmi_nand_exit); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPMI NAND driver"); +module_param(max_chips, int, 0400); +module_param(clk, long, 0400); +module_param(bch, int, 0600); +module_param(map_buffers, int, 0600); +module_param(raw_mode, int, 0600); +module_param(debug, int, 0600); +module_param(add_mtd_entire, int, 0400); +module_param(add_mtd_chip, int, 0400); +module_param(ignorebad, int, 0400); diff --git a/drivers/mtd/nand/gpmi/gpmi-bbt.c b/drivers/mtd/nand/gpmi/gpmi-bbt.c new file mode 100644 index 000000000000..54755f870440 --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-bbt.c @@ -0,0 +1,565 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/dma-mapping.h> +#include <linux/ctype.h> +#include <mach/dma.h> +#include <mach/unique-id.h> +#include "gpmi.h" + +static int boot_search_count; +static int stride = 64; +static int ncb_version = 3; +module_param(boot_search_count, int, 0400); +module_param(ncb_version, int, 0400); + +void *gpmi_read_page(struct mtd_info *mtd, loff_t start, void *data, int raw) +{ + int ret; + struct mtd_oob_ops ops; + + if (!data) + data = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!data) + return NULL; + + if (raw) + ops.mode = MTD_OOB_RAW; + else + ops.mode = MTD_OOB_PLACE; + ops.datbuf = data; + ops.len = mtd->writesize; + ops.oobbuf = data + mtd->writesize; + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; + ret = nand_do_read_ops(mtd, start, &ops); + + if (ret) + return NULL; + return data; +} + +int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b) +{ + struct gpmi_ncb *ncb = NULL, *unencoded_ncb = NULL; + struct nand_chip *chip = mtd->priv; + int err; + loff_t start = 0; + struct mtd_oob_ops ops; + struct erase_info instr; + int ncb_count; + + ncb = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!ncb) { + err = -ENOMEM; + goto out; + } + unencoded_ncb = kzalloc(mtd->writesize, GFP_KERNEL); + if (!unencoded_ncb) { + err = -ENOMEM; + goto out; + } + ops.mode = -1; /* if the value is not set in switch below, + this will cause BUG. Take care. */ + if (b && b->pre_ncb) + memcpy(unencoded_ncb, b->pre_ncb, b->pre_ncb_size); + else { + memcpy(&unencoded_ncb->fingerprint1, SIG1, sizeof(u32)); + memcpy(&unencoded_ncb->fingerprint2, SIG_NCB, sizeof(u32)); + if (b) + unencoded_ncb->timing = b->timing; + } + + switch (ncb_version) { + case 0: + ops.mode = MTD_OOB_AUTO; + memcpy(ncb, unencoded_ncb, sizeof(*unencoded_ncb)); + break; +#ifdef CONFIG_MTD_NAND_GPMI_TA1 + case 1: + ops.mode = MTD_OOB_RAW; + gpmi_encode_hamming_ncb_22_16(unencoded_ncb, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES, + ncb, mtd->writesize + mtd->oobsize); + break; +#endif +#ifdef CONFIG_MTD_NAND_GPMI_TA3 + case 3: + ops.mode = MTD_OOB_RAW; + gpmi_encode_hamming_ncb_13_8(unencoded_ncb, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES, + ncb, mtd->writesize + mtd->oobsize); + break; +#endif + + default: + printk(KERN_ERR"Incorrect ncb_version = %d\n", ncb_version); + err = -EINVAL; + goto out; + } + + ops.datbuf = (u8 *)ncb; + ops.len = mtd->writesize; + ops.oobbuf = (u8 *)ncb + mtd->writesize; + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; + + ncb_count = 0; + do { + printk(KERN_NOTICE"GPMI: Trying to store NCB at addr %lx\n", + (unsigned long)start); + memset(&instr, 0, sizeof(instr)); + instr.mtd = mtd; + instr.addr = start; + instr.len = (1 << chip->phys_erase_shift); + err = nand_erase_nand(mtd, &instr, 0); + if (err == 0) { + printk(KERN_NOTICE"GPMI: Erased, storing\n"); + err = nand_do_write_ops(mtd, start, &ops); + printk(KERN_NOTICE"GPMI: NCB update %s (%d).\n", + err ? "failed" : "succeeded", err); + } + start += (1 << chip->phys_erase_shift); + ncb_count++; + } while (err != 0 && ncb_count < 100); + + if (b) + b->ncbblock = start >> chip->bbt_erase_shift; + +out: + kfree(ncb); + kfree(unencoded_ncb); + + return 0; +} + +static int gpmi_redundancy_check_one(u8 *pg, int dsize, int esize, int offset, + int o1, int o2) +{ + int r; + + if (o1 == o2) + return 0; + + r = memcmp(pg + o1 * dsize, pg + o2 * dsize, dsize); + if (r) { + pr_debug("DATA copies %d and %d are different: %d\n", + o1, o2, r); + return r; + } + + r = memcmp(pg + o1 * esize + offset, + pg + o2 * esize + offset, esize); + if (r) { + pr_debug("ECC copies %d and %d are different: %d\n", o1, o2, r); + return r; + } + pr_debug("Both DATA and ECC copies %d and %d are identical\n", o1, o2); + return r; +} + +static int gpmi_redundancy_check(u8 *pg, int dsize, int esize, int ecc_offset) +{ + if (gpmi_redundancy_check_one(pg, dsize, esize, ecc_offset, 0, 1) == 0) + return 0; + if (gpmi_redundancy_check_one(pg, dsize, esize, ecc_offset, 0, 2) == 0) + return 0; + if (gpmi_redundancy_check_one(pg, dsize, esize, ecc_offset, 1, 2) == 0) + return 1; + return -1; +} + +static inline int gpmi_ncb1_redundancy_check(u8 *pg) +{ + return gpmi_redundancy_check(pg, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES, + NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES, + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY); +} + +static int gpmi_scan_sigmatel_bbt( + struct mtd_info *mtd, struct gpmi_bcb_info *nfo) +{ + int page, r; + u8 *pg; + struct gpmi_ncb *result = NULL; + + if (boot_search_count == 0) + boot_search_count = 1; + if (nfo == NULL) + return -EINVAL; + + pg = NULL; + printk(KERN_NOTICE"Scanning for NCB...\n"); + for (page = 0; page < (1<<boot_search_count); page += stride) { + pg = gpmi_read_page(mtd, page * mtd->writesize, + pg, ncb_version != 0); + + printk(KERN_NOTICE"GPMI: Checking page 0x%08X\n", page); + + if (ncb_version == 0) { + if (memcmp(pg, SIG1, SIG_SIZE) != 0) + continue; + printk(KERN_NOTICE"GPMI: Signature found at 0x%08X\n", + page); + result = (struct gpmi_ncb *)pg; + } + +#ifdef CONFIG_MTD_NAND_GPMI_TA1 + if (ncb_version == 1) { + void *dptr, *eccptr; + + if (memcmp(pg, SIG1, SIG_SIZE) != 0) + continue; + printk(KERN_NOTICE"GPMI: Signature found at 0x%08X\n", + page); + + r = gpmi_ncb1_redundancy_check(pg); + + if (r < 0) { + printk(KERN_ERR"GPMI: Oops. All three " + "copies of NCB are differrent!\n"); + continue; + } + + dptr = pg + r * NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES; + eccptr = pg + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY + + r * NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES; + + if (gpmi_verify_hamming_22_16(dptr, eccptr, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) < 0) { + printk(KERN_ERR"Verification failed.\n"); + continue; + } + result = (struct gpmi_ncb *)pg; + } +#endif + +#ifdef CONFIG_MTD_NAND_GPMI_TA3 + if (ncb_version == 3) { + + if (memcmp(pg + 12, SIG1, SIG_SIZE) != 0) + continue; + + printk(KERN_NOTICE"GPMI: Signature found at 0x%08X\n", + page); + + if (gpmi_verify_hamming_13_8( + pg + 12, + pg + 524, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) < 0) { + printk(KERN_ERR"Verification failed.\n"); + continue; + } + result = (struct gpmi_ncb *)(pg + 12); + } +#endif + if (result) { + printk(KERN_NOTICE"GPMI: Valid NCB found " + "at 0x%08x\n", page); + nfo->timing = result->timing; + nfo->ncbblock = page * mtd->writesize; + break; + } + } + kfree(pg); + + return result != NULL; +} + +int gpmi_scan_bbt(struct mtd_info *mtd) +{ + struct gpmi_bcb_info stmp_bbt; + struct nand_chip *this = mtd->priv; + struct gpmi_nand_data *g = this->priv; + int r; + int numblocks, from, i, ign; + + memset(&stmp_bbt, 0, sizeof(stmp_bbt)); + g->transcribe_bbmark = 0; + + /* + Since NCB uses the full page, including BB pattern bits, + driver has to ignore result of gpmi_block_bad when reading + these pages. + */ + ign = g->ignorebad; + + g->ignorebad = true; /* strictly speaking, I'd have to hide + * the BBT too. + * But we still scanning it :) */ + r = gpmi_scan_sigmatel_bbt(mtd, &stmp_bbt); + + /* and then, driver has to restore the setting */ + g->ignorebad = ign; + + if (r) { + printk(KERN_NOTICE"Setting discovered timings: %d:%d:%d:%d\n", + stmp_bbt.timing.data_setup, + stmp_bbt.timing.data_hold, + stmp_bbt.timing.address_setup, + stmp_bbt.timing.dsample_time); + + gpmi_set_timings(g->dev, &stmp_bbt.timing); + g->timing = stmp_bbt.timing; + + } else { + g->transcribe_bbmark = !0; + numblocks = this->chipsize >> this->bbt_erase_shift; + from = 0; + printk(KERN_NOTICE"Checking BB on common-formatted flash\n"); + for (i = stmp_bbt.ncbblock + 1; i < numblocks; i++) { + /* check the block and transcribe the bb if needed */ + gpmi_block_bad(mtd, from, 0); + from += (1 << this->bbt_erase_shift); + } + } + + r = nand_default_bbt(mtd); + + if (g->transcribe_bbmark) { + /* NCB has been not found, so create NCB now */ + g->transcribe_bbmark = 0; + + stmp_bbt.timing = gpmi_safe_timing; + r = gpmi_write_ncb(mtd, &stmp_bbt); + } else { + /* NCB found, and its block should be marked as "good" */ + gpmi_block_mark_as(this, stmp_bbt.ncbblock, 0x00); + } + + return r; +} + +int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) + +{ + int page, res = 0; + struct nand_chip *chip = mtd->priv; + u16 bad; + struct gpmi_nand_data *g = chip->priv; + int chipnr; + + /* badblockpos is an offset in OOB area */ + int badblockpos = chip->ecc.steps * chip->ecc.bytes; + + if (g->ignorebad) + return 0; + + page = (int)(ofs >> chip->page_shift) & chip->pagemask; + + chipnr = (int)(ofs >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + if (g->transcribe_bbmark) + /* bad block marks still are on first byte of OOB */ + badblockpos = 0; + + if (chip->options & NAND_BUSWIDTH_16) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, badblockpos & 0xFE, + page); + bad = cpu_to_le16(chip->read_word(mtd)); + if (badblockpos & 0x1) + bad >>= 8; + if ((bad & 0xFF) != 0xff) + res = 1; + } else { + chip->cmdfunc(mtd, NAND_CMD_READOOB, badblockpos, page); + if (chip->read_byte(mtd) != 0xff) + res = 1; + } + + if (g->transcribe_bbmark && res) + chip->block_markbad(mtd, ofs); + + chip->select_chip(mtd, -1); + + return res; +} + +#if defined(CONFIG_STMP3XXX_UNIQUE_ID) +/* + * UID on NAND support + */ +const int uid_size = 256; + +struct gpmi_uid_context { + struct mtd_info *mtd; + struct nand_chip *nand; + u_int32_t start; + u_int32_t size; +}; + +static int gpmi_read_uid(struct gpmi_uid_context *ctx, void *result) +{ + void *pg = NULL; + int page, o; + int status = -ENOENT; + int h_size = gpmi_hamming_ecc_size_22_16(uid_size); + + for (page = ctx->start >> ctx->nand->page_shift; + page < (ctx->start + ctx->size) >> ctx->nand->page_shift;) { + pr_debug("%s: reading page 0x%x\n", __func__, page); + if (gpmi_block_bad(ctx->mtd, page * ctx->mtd->writesize, 0)) { + pr_debug("%s: bad block %x, skipping it\n", + __func__, page * ctx->mtd->writesize); + page += (1 << ctx->nand->phys_erase_shift) + >> ctx->nand->page_shift; + continue; + } + pg = gpmi_read_page(ctx->mtd, page * ctx->mtd->writesize, + pg, 0); + if (pg) + break; + page++; + } + + if (!pg) + return status; + + o = gpmi_redundancy_check(pg, uid_size, h_size, 3 * uid_size); + if (o >= 0) { + if (gpmi_verify_hamming_22_16( + pg + o * uid_size, + pg + 3 * uid_size + h_size, uid_size) >= 0) { + memcpy(result, pg + o * uid_size, uid_size); + status = 0; + } + } + kfree(pg); + return status; +} + +static int gpmi_write_uid(struct gpmi_uid_context *ctx, void *src) +{ + struct mtd_oob_ops ops; + struct erase_info instr; + u8 *data = kzalloc(ctx->mtd->writesize + ctx->mtd->oobsize, GFP_KERNEL); + int h_size = gpmi_hamming_ecc_size_22_16(uid_size); + char ecc[h_size]; + u_int32_t start; + int i; + int err; + + if (!data) + return -ENOMEM; + + gpmi_encode_hamming_22_16(src, uid_size, ecc, h_size); + for (i = 0; i < 3; i++) { + memcpy(data + i * uid_size, src, uid_size); + memcpy(data + 3 * uid_size + i * h_size, ecc, h_size); + } + + ops.mode = MTD_OOB_AUTO; + ops.datbuf = data; + ops.len = ctx->mtd->writesize; + ops.oobbuf = NULL; + ops.ooblen = ctx->mtd->oobsize; + ops.ooboffs = 0; + + start = ctx->start; + + do { + memset(&instr, 0, sizeof(instr)); + instr.mtd = ctx->mtd; + instr.addr = start; + instr.len = (1 << ctx->nand->phys_erase_shift); + err = nand_erase_nand(ctx->mtd, &instr, 0); + if (err == 0) + err = nand_do_write_ops(ctx->mtd, start, &ops); + start += (1 << ctx->nand->phys_erase_shift); + if (start > ctx->start + ctx->size) + break; + } while (err != 0); + + return err; +} + +static ssize_t gpmi_uid_store(void *context, const char *page, + size_t count, int ascii) +{ + u8 data[uid_size]; + + memset(data, 0, sizeof(data)); + memcpy(data, page, uid_size < count ? uid_size : count); + gpmi_write_uid(context, data); + return count; +} + +static ssize_t gpmi_uid_show(void *context, char *page, int ascii) +{ + u8 result[uid_size]; + int i; + char *p = page; + int r; + + r = gpmi_read_uid(context, result); + if (r < 0) + return r; + + if (ascii) { + for (i = 0; i < uid_size; i++) { + if (i % 16 == 0) { + if (i) + *p++ = '\n'; + sprintf(p, "%04X: ", i); + p += strlen(p); + } + sprintf(p, "%02X ", result[i]); + p += strlen(p); + } + *p++ = '\n'; + return p - page; + + } else { + memcpy(page, result, uid_size); + return uid_size; + } +} + +static struct uid_ops gpmi_uid_ops = { + .id_show = gpmi_uid_show, + .id_store = gpmi_uid_store, +}; + +static struct gpmi_uid_context gpmi_uid_context; + +int __init gpmi_uid_init(const char *name, struct mtd_info *mtd, + u_int32_t start, u_int32_t size) +{ + gpmi_uid_context.mtd = mtd; + gpmi_uid_context.nand = mtd->priv; + gpmi_uid_context.start = start; + gpmi_uid_context.size = size; + return uid_provider_init(name, &gpmi_uid_ops, &gpmi_uid_context) ? + 0 : -EFAULT; +} + +void gpmi_uid_remove(const char *name) +{ + uid_provider_remove(name); +} +#endif diff --git a/drivers/mtd/nand/gpmi/gpmi-bch.c b/drivers/mtd/nand/gpmi/gpmi-bch.c new file mode 100644 index 000000000000..58f7354bcd18 --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-bch.c @@ -0,0 +1,289 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * STMP378X BCH hardware ECC engine + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/dma-mapping.h> + +#include <asm/dma.h> +#include <mach/stmp3xxx.h> +#include <mach/irqs.h> +#include "gpmi.h" + +#define BCH_MAX_NANDS 4 + +static int bch_available(void *context); +static int bch_setup(void *context, int index, int writesize, int oobsize); +static int bch_read(void *context, + int index, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob); +static int bch_stat(void *ctx, int index, struct mtd_ecc_stats *r); +static int bch_reset(void *context, int index); + +struct bch_state_t { + struct gpmi_hwecc_chip chip; + struct { + struct mtd_ecc_stats stat; + struct completion done; + u32 writesize, oobsize; + } nands[BCH_MAX_NANDS]; +}; + +static struct bch_state_t state = { + .chip = { + .name = "bch", + .setup = bch_setup, + .stat = bch_stat, + .read = bch_read, + .reset = bch_reset, + }, +}; + +static int bch_reset(void *context, int index) +{ + stmp3xxx_reset_block(REGS_BCH_BASE, true); + HW_BCH_CTRL_SET(BM_BCH_CTRL_COMPLETE_IRQ_EN); + return 0; +} + +static int bch_stat(void *context, int index, struct mtd_ecc_stats *r) +{ + struct bch_state_t *state = context; + + *r = state->nands[index].stat; + state->nands[index].stat.failed = 0; + state->nands[index].stat.corrected = 0; + return 0; +} + +static irqreturn_t bch_irq(int irq, void *context) +{ + u32 b0, s0; + struct mtd_ecc_stats stat; + int r; + struct bch_state_t *state = context; + + s0 = HW_BCH_STATUS0_RD(); + r = (s0 & BM_BCH_STATUS0_COMPLETED_CE) >> 16; + + stat.corrected = stat.failed = 0; + + b0 = (s0 & BM_BCH_STATUS0_STATUS_BLK0) >> 8; + if (b0 <= 4) + stat.corrected += b0; + if (b0 == 0xFE) + stat.failed++; + + if (s0 & BM_BCH_STATUS0_CORRECTED) + stat.corrected += (s0 & BM_BCH_STATUS0_CORRECTED); + if (s0 & BM_BCH_STATUS0_UNCORRECTABLE) + stat.failed++; + + HW_BCH_CTRL_CLR(BM_BCH_CTRL_COMPLETE_IRQ); + + pr_debug("%s: chip %d, failed %d, corrected %d\n", + __func__, r, + state->nands[r].stat.failed, + state->nands[r].stat.corrected); + state->nands[r].stat.corrected += stat.corrected; + state->nands[r].stat.failed += stat.failed; + complete(&state->nands[r].done); + + return IRQ_HANDLED; +} + +static int bch_available(void *context) +{ + stmp3xxx_reset_block(REGS_BCH_BASE, 0); + return HW_BCH_BLOCKNAME_RD() == 0x20484342; +} + +static int bch_setup(void *context, int index, int writesize, int oobsize) +{ + struct bch_state_t *state = context; + u32 layout = (REGS_BCH_BASE + 0x80 /* HW_BCH_FLASH0LAYOUT0_ADDR */) + + index * 0x20; + u32 ecc0, eccN; + int meta; + + switch (writesize) { + case 2048: + ecc0 = 4; + eccN = 4; + meta = 5; + break; + case 4096: + ecc0 = 16; + eccN = 14; + meta = 10; + break; + default: + printk(KERN_ERR"%s: cannot tune BCH for page size %d\n", + __func__, writesize); + return -EINVAL; + } + + state->nands[index].oobsize = oobsize; + state->nands[index].writesize = writesize; + + __raw_writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(writesize/512) | + BF_BCH_FLASH0LAYOUT0_META_SIZE(oobsize) | + BF_BCH_FLASH0LAYOUT0_ECC0(ecc0 >> 1) | /* for oob */ + BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(0x00), layout); + __raw_writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(writesize + oobsize) | + BF_BCH_FLASH0LAYOUT1_ECCN(eccN >> 1) | /* for dblock */ + BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(512), layout + 0x10); + + /* + * since driver only supports CS 0..3, layouts are mapped 1:1 : + * FLASHnLAYOUT[1,2] => LAYOUTSELECT[n*2:n2*+1] + */ + HW_BCH_LAYOUTSELECT_CLR(0x03 << (index * 2)); + HW_BCH_LAYOUTSELECT_SET(index << (index * 2)); + + bch_reset(context, index); + + printk(KERN_DEBUG"%s: CS = %d, LAYOUT = 0x%08X, layout_reg = " + "0x%08x+0x%08x: 0x%08x+0x%08x\n", + __func__, + index, HW_BCH_LAYOUTSELECT_RD(), + layout, layout + 0x10, + __raw_readl(layout), + __raw_readl(layout+0x10)); + return 0; +} + +static int bch_read(void *context, + int index, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob) +{ + unsigned long readsize = 0; + u32 bufmask = 0; + struct bch_state_t *state = context; + + if (!dma_mapping_error(NULL, oob)) { + bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + readsize += state->nands[index].oobsize; + } + if (!dma_mapping_error(NULL, page)) { + bufmask |= (BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE + & ~BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY); + readsize += state->nands[index].writesize; + } + + printk(KERN_DEBUG"readsize = %ld, bufmask = 0x%X\n", readsize, bufmask); + bch_reset(context, index); + + /* wait for ready */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(1) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_CS(index); + chain->command->alternate = 0; + chain++; + + /* enable BCH and read NAND data */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(6) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_CS(index) | + BF_GPMI_CTRL0_XFER_COUNT(readsize); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = + BM_GPMI_ECCCTRL_ENABLE_ECC | + BF_GPMI_ECCCTRL_ECC_CMD(0x02) | + BF_GPMI_ECCCTRL_BUFFER_MASK(bufmask); + chain->command->pio_words[3] = readsize; + chain->command->pio_words[4] = !dma_mapping_error(NULL, page) ? page : 0; + chain->command->pio_words[5] = !dma_mapping_error(NULL, oob) ? oob : 0; + chain->command->alternate = 0; + chain++; + + /* disable BCH block */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(3) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_CS(index) | + BF_GPMI_CTRL0_XFER_COUNT(readsize); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->alternate = 0; + chain++; + + /* and deassert nand lock */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(0) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->alternate = 0; + + return 0; +} + +int __init bch_init(void) +{ + int err; + + if (!bch_available(&state.chip)) + return -ENXIO; + gpmi_hwecc_chip_add(&state.chip); + err = request_irq(IRQ_BCH, bch_irq, 0, state.chip.name, &state); + if (err) + return err; + + printk(KERN_DEBUG"%s: initialized\n", __func__); + return 0; +} + +void bch_exit(void) +{ + free_irq(IRQ_BCH, &state); + gpmi_hwecc_chip_remove(&state.chip); +} diff --git a/drivers/mtd/nand/gpmi/gpmi-ecc8.c b/drivers/mtd/nand/gpmi/gpmi-ecc8.c new file mode 100644 index 000000000000..dad14c3809fc --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-ecc8.c @@ -0,0 +1,382 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * STMP37XX/STMP378X ECC8 hardware ECC engine + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/dma-mapping.h> + +#include <asm/dma.h> +#include <mach/stmp3xxx.h> +#include <mach/irqs.h> +#include "gpmi.h" + +#define ECC8_MAX_NANDS 4 + +static int ecc8_available(void *context); +static int ecc8_setup(void *context, int index, int writesize, int oobsize); +static int ecc8_read(void *context, int index, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob); +static int ecc8_write(void *context, int index, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob); +static int ecc8_stat(void *ctx, int index, struct mtd_ecc_stats *r); +static int ecc8_reset(void *context, int index); + +struct ecc8_nand { +}; + +struct ecc8_state_t { + struct gpmi_hwecc_chip chip; + struct completion done; + struct mtd_ecc_stats stat; + u32 writesize, oobsize; + u32 ecc_page, ecc_oob, oob_free; + u32 r, w; + int bits; + u32 s0_mask, s1_mask; +}; + +static struct ecc8_state_t state = { + .chip = { + .name = "ecc8", + .setup = ecc8_setup, + .stat = ecc8_stat, + .read = ecc8_read, + .write = ecc8_write, + .reset = ecc8_reset, + }, +}; + +static int ecc8_reset(void *context, int index) +{ + stmp3xxx_reset_block(REGS_ECC8_BASE, false); + while (HW_ECC8_CTRL_RD() & BM_ECC8_CTRL_AHBM_SFTRST) + HW_ECC8_CTRL_CLR(BM_ECC8_CTRL_AHBM_SFTRST); + HW_ECC8_CTRL_SET(BM_ECC8_CTRL_COMPLETE_IRQ_EN); + return 0; +} + +static int ecc8_stat(void *context, int index, struct mtd_ecc_stats *r) +{ + struct ecc8_state_t *state = context; + + wait_for_completion(&state->done); + + *r = state->stat; + state->stat.failed = 0; + state->stat.corrected = 0; + return 0; +} + +static irqreturn_t ecc8_irq(int irq, void *context) +{ + int r; + struct mtd_ecc_stats ecc_stats; + struct ecc8_state_t *state = context; + u32 corr; + u32 s0 = HW_ECC8_STATUS0_RD(), s1 = HW_ECC8_STATUS1_RD(); + + r = (s0 & BM_ECC8_STATUS0_COMPLETED_CE) >> 16; + + if (s0 & BM_ECC8_STATUS0_CORRECTED || + s0 & BM_ECC8_STATUS0_UNCORRECTABLE) { + + ecc_stats.failed = 0; + ecc_stats.corrected = 0; + + s0 = (s0 & BM_ECC8_STATUS0_STATUS_AUX) >> 8; + if (s0 <= 4) + ecc_stats.corrected += s0; + if (s0 == 0xE) + ecc_stats.failed++; + + for ( ; s1 != 0; s1 >>= 4) { + corr = s1 & 0xF; + if (corr == 0x0C) + continue; + if (corr == 0xE) + ecc_stats.failed++; + if (corr <= 8) + ecc_stats.corrected += corr; + s1 >>= 4; + } + state->stat.corrected += ecc_stats.corrected; + state->stat.failed += ecc_stats.failed; + } + + complete(&state->done); + + HW_ECC8_CTRL_CLR(BM_ECC8_CTRL_COMPLETE_IRQ); + return IRQ_HANDLED; +} + +static int ecc8_available(void *context) +{ + return 1; +} + +static int ecc8_setup(void *context, int index, int writesize, int oobsize) +{ + struct ecc8_state_t *state = context; + + switch (writesize) { + case 2048: + state->ecc_page = 9; + state->ecc_oob = 9; + state->bits = 4; + state->r = BF_GPMI_ECCCTRL_ECC_CMD( + BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT); + state->w = BF_GPMI_ECCCTRL_ECC_CMD( + BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT); + break; + case 4096: + state->ecc_page = 18; + state->ecc_oob = 9; + state->bits = 8; + state->r = BF_GPMI_ECCCTRL_ECC_CMD( + BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT); + state->w = BF_GPMI_ECCCTRL_ECC_CMD( + BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT); + break; + default: + return -ENOTSUPP; + } + + state->oob_free = oobsize - + (state->bits * state->ecc_page) - state->ecc_oob; + state->oobsize = oobsize; + state->writesize = writesize; + + ecc8_reset(context, index); + + return 0; +} + +/** + * ecc8_read - create dma chain to read nand page + * + * @context: context data, pointer to ecc8_state + * @index: CS of nand to read + * @chain: dma chain to be filled + * @page: (physical) address of page data to be read to + * @oob: (physical) address of OOB data to be read to + * + * Return: status of operation -- 0 on success + */ +static int ecc8_read(void *context, int cs, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob) +{ + unsigned long readsize = 0; + u32 bufmask = 0; + struct ecc8_state_t *state = context; + + ecc8_reset(context, cs); + + state->s0_mask = state->s1_mask = 0; + + if (!dma_mapping_error(NULL, page)) { + bufmask |= (1 << state->bits) - 1; + readsize += (state->bits * state->ecc_page); + readsize += state->writesize; + } + if (!dma_mapping_error(NULL, oob)) { + bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY; + readsize += state->oob_free + state->ecc_oob; + state->s0_mask = BM_ECC8_STATUS0_STATUS_AUX; + if (dma_mapping_error(NULL, page)) + page = oob; + } + + + /* wait for ready */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(1) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_CS(cs); + chain->command->buf_ptr = 0; + chain++; + + /* enable ECC and read NAND data */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(6) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_CS(cs) | + BF_GPMI_CTRL0_XFER_COUNT(readsize); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = + BM_GPMI_ECCCTRL_ENABLE_ECC | + state->r | + BF_GPMI_ECCCTRL_BUFFER_MASK(bufmask); + chain->command->pio_words[3] = readsize; + chain->command->pio_words[4] = !dma_mapping_error(NULL, page) ? page : 0; + chain->command->pio_words[5] = !dma_mapping_error(NULL, oob) ? oob : 0; + chain->command->buf_ptr = 0; + chain++; + + /* disable ECC block */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(3) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_CS(cs); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->buf_ptr = 0; + chain++; + + /* and deassert nand lock */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(0) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->buf_ptr = 0; + + init_completion(&state->done); + + return 0; +} + +static int ecc8_write(void *context, int cs, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob) +{ + u32 bufmask = 0; + struct ecc8_state_t *state = context; + u32 data_w, data_w_ecc, + oob_w, oob_w_ecc; + + ecc8_reset(context, cs); + + data_w = data_w_ecc = oob_w = oob_w_ecc = 0; + + if (!dma_mapping_error(NULL, oob)) { + bufmask |= BV_GPMI_ECCCTRL_BUFFER_MASK__AUXILIARY; + oob_w = state->oob_free; + oob_w_ecc = oob_w + state->ecc_oob; + } + if (!dma_mapping_error(NULL, page)) { + bufmask |= (1 << state->bits) - 1; + data_w = state->bits * 512; + data_w_ecc = data_w + state->bits * state->ecc_page; + } + + /* enable ECC and send NAND data (page only) */ + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(data_w ? data_w : oob_w) | + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__DMA_READ); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(cs) | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_XFER_COUNT(data_w + oob_w); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = + BM_GPMI_ECCCTRL_ENABLE_ECC | + state->w | + BF_GPMI_ECCCTRL_BUFFER_MASK(bufmask); + chain->command->pio_words[3] = + data_w_ecc + oob_w_ecc; + if (!dma_mapping_error(NULL, page)) + chain->command->buf_ptr = page; + else + chain->command->buf_ptr = oob; + chain++; + + if (!dma_mapping_error(NULL, page) && !dma_mapping_error(NULL, oob)) { + /* send NAND data (OOB only) */ + chain->command->cmd = + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_XFER_COUNT(oob_w) | + BF_APBH_CHn_CMD_CMDWORDS(0) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BF_APBH_CHn_CMD_COMMAND( + BV_APBH_CHn_CMD_COMMAND__DMA_READ); + chain->command->buf_ptr = oob; /* never dma_mapping_error() */ + chain++; + } + /* emit IRQ */ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(0) | + BF_APBH_CHn_CMD_COMMAND( + BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_IRQONCMPLT; + + return 0; +} + +int __init ecc8_init(void) +{ + int err; + + if (!ecc8_available(&state)) + return -ENXIO; + + gpmi_hwecc_chip_add(&state.chip); + err = request_irq(IRQ_ECC8_IRQ, ecc8_irq, 0, state.chip.name, &state); + if (err) + return err; + + printk(KERN_INFO"%s: initialized\n", __func__); + return 0; +} + +void ecc8_exit(void) +{ + free_irq(IRQ_ECC8_IRQ, &state); + gpmi_hwecc_chip_remove(&state.chip); +} diff --git a/drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c b/drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c new file mode 100644 index 000000000000..c48d70b38bc0 --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-hamming-13-8.c @@ -0,0 +1,131 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * NCB software ECC Hamming code + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <mach/dma.h> +#include "gpmi.h" + +#define BIT_VAL(v, n) (((v) >> (n)) & 0x1) +#define B(n) (BIT_VAL(d, n)) + +static u8 calculate_parity(u8 d) +{ + u8 p = 0; + + if (d == 0 || d == 0xFF) + return 0; /* optimization :) */ + + p |= (B(6) ^ B(5) ^ B(3) ^ B(2)) << 0; + p |= (B(7) ^ B(5) ^ B(4) ^ B(2) ^ B(1)) << 1; + p |= (B(7) ^ B(6) ^ B(5) ^ B(1) ^ B(0)) << 2; + p |= (B(7) ^ B(4) ^ B(3) ^ B(0)) << 3; + p |= (B(6) ^ B(4) ^ B(3) ^ B(2) ^ B(1) ^ B(0)) << 4; + return p; +} + +static inline int even_number_of_1s(u8 byte) +{ + int even = 1; + + while (byte > 0) { + even ^= (byte & 0x1); + byte >>= 1; + } + return even; +} + +static int lookup_single_error(u8 syndrome) +{ + int i; + u8 syndrome_table[] = { + 0x1C, 0x16, 0x13, 0x19, + 0x1A, 0x07, 0x15, 0x0E, + 0x01, 0x02, 0x04, 0x08, + 0x10, + }; + + for (i = 0; i < ARRAY_SIZE(syndrome_table); i++) + if (syndrome_table[i] == syndrome) + return i; + return -ENOENT; +} + +int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size) +{ + int i; + u8 *pdata = data; + int bit_to_flip; + u8 np, syndrome; + int errors = 0; + + for (i = 0; i < size; i ++, pdata++) { + np = calculate_parity(*pdata); + syndrome = np ^ parity[i]; + if (syndrome == 0) /* cool */ { + continue; + } + + if (even_number_of_1s(syndrome)) + return -i; /* can't recover */ + + bit_to_flip = lookup_single_error(syndrome); + if (bit_to_flip < 0) + return -i; /* can't fix the error */ + + if (bit_to_flip < 8) { + *pdata ^= (1 << bit_to_flip); + errors++; + } + } + return errors; +} + +void gpmi_encode_hamming_13_8(void *source_block, size_t src_size, + void *source_ecc, size_t ecc_size) +{ + int i; + u8 *src = source_block; + u8 *ecc = source_ecc; + + for (i = 0; i < src_size && i < ecc_size; i++) + ecc[i] = calculate_parity(src[i]); +} + +void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size, + void *target_block, size_t target_size) +{ + if (target_size < 12 + 2 * NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) + return; + memset(target_block, 0xFF, target_size); + memcpy((u8 *)target_block + 12, source_block, source_size); + gpmi_encode_hamming_13_8(source_block, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES, + (u8 *)target_block + 12 + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES); +} + +unsigned gpmi_hamming_ecc_size_13_8(int block_size) +{ + return block_size; +} + diff --git a/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c b/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c new file mode 100644 index 000000000000..8d3975efbc6e --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.c @@ -0,0 +1,196 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * NCB software ECC Hamming code + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <mach/dma.h> +#include "gpmi.h" +#include "gpmi-hamming-22-16.h" + +#define BIT_VAL(v, n) (((v) >> (n)) & 0x1) +#define B(n) (BIT_VAL(d, n)) +#define BSEQ(a1, a2, a3, a4, a5, a6, a7, a8) \ + (B(a1) ^ B(a2) ^ B(a3) ^ B(a4) ^ B(a5) ^ B(a6) ^ B(a7) ^ B(a8)) +static u8 calculate_parity(u16 d) +{ + u8 p = 0; + + if (d == 0 || d == 0xFFFF) + return 0; /* optimization :) */ + + p |= BSEQ(15, 12, 11, 8, 5, 4, 3, 2) << 0; + p |= BSEQ(13, 12, 11, 10, 9, 7, 3, 1) << 1; + p |= BSEQ(15, 14, 13, 11, 10, 9, 6, 5) << 2; + p |= BSEQ(15, 14, 13, 8, 7, 6, 4, 0) << 3; + p |= BSEQ(12, 9, 8, 7, 6, 2, 1, 0) << 4; + p |= BSEQ(14, 10, 5, 4, 3, 2, 1, 0) << 5; + return p; +} + +static inline int even_number_of_1s(u8 byte) +{ + int even = 1; + + while (byte > 0) { + even ^= (byte & 0x1); + byte >>= 1; + } + return even; +} + +static int lookup_single_error(u8 syndrome) +{ + int i; + u8 syndrome_table[] = { + 0x38, 0x32, 0x31, 0x23, 0x29, 0x25, 0x1C, 0x1A, + 0x19, 0x16, 0x26, 0x07, 0x13, 0x0E, 0x2C, 0x0D, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, + }; + + for (i = 0; i < ARRAY_SIZE(syndrome_table); i++) + if (syndrome_table[i] == syndrome) + return i; + return -ENOENT; +} + +int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size) +{ + int i, j; + int bit_index, bit_to_flip; + u16 *pdata = data; + u8 p = 0, np, syndrome; + int errors = 0; + + for (bit_index = i = j = 0; + i < size / sizeof(u16); + i ++, pdata++) { + + switch (bit_index) { + + case 0: + p = parity[j] & 0x3F; + break; + case 2: + p = (parity[j++] & 0xC0) >> 6; + p |= (parity[j] & 0x0F) << 2; + break; + case 4: + p = (parity[j++] & 0xF0) >> 4; + p |= (parity[j] & 0x03) << 4; + break; + case 6: + p = (parity[j++] & 0xFC) >> 2; + break; + default: + BUG(); /* how did you get this ?! */ + break; + } + bit_index = (bit_index + 2) % 8; + + np = calculate_parity(*pdata); + syndrome = np ^ p; + if (syndrome == 0) /* cool */ { + continue; + } + + if (even_number_of_1s(syndrome)) + return -i; /* can't recover */ + + bit_to_flip = lookup_single_error(syndrome); + if (bit_to_flip < 0) + return -i; /* can't fix the error */ + + if (bit_to_flip < 16) { + *pdata ^= (1 << bit_to_flip); + errors++; + } + } + return errors; +} + +void gpmi_encode_hamming_22_16(void *source_block, size_t src_size, + void *source_ecc, size_t ecc_size) +{ + int i, j, bit_index; + u16 *src = source_block; + u8 *ecc = source_ecc; + u8 np; + + for (bit_index = j = i = 0; + j < src_size/sizeof(u16) && i < ecc_size; + j++) { + + np = calculate_parity(src[j]); + + switch (bit_index) { + + case 0: + ecc[i] = np & 0x3F; + break; + case 2: + ecc[i++] |= (np & 0x03) << 6; + ecc[i] = (np & 0x3C) >> 2; + break; + case 4: + ecc[i++] |= (np & 0x0F) << 4; + ecc[i] = (np & 0x30) >> 4; + break; + case 6: + ecc[i++] |= (np & 0x3F) << 2; + break; + } + bit_index = (bit_index + 2) % 8; + } + +} + +void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size, + void *target_block, size_t target_size) +{ + u8 *dst = target_block; + u8 ecc[NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES]; + + gpmi_encode_hamming_22_16(source_block, + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES, + ecc, + NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES); + /* create THREE copies of source block */ + memcpy(dst + NAND_HC_ECC_OFFSET_FIRST_DATA_COPY, + source_block, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES); + memcpy(dst + NAND_HC_ECC_OFFSET_SECOND_DATA_COPY, + source_block, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES); + memcpy(dst + NAND_HC_ECC_OFFSET_THIRD_DATA_COPY, + source_block, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES); + /* ..and three copies of ECC block */ + memcpy(dst + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY, + ecc, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES); + memcpy(dst + NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY, + ecc, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES); + memcpy(dst + NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY, + ecc, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES); +} + +unsigned gpmi_hamming_ecc_size_22_16(int block_size) +{ + return (((block_size * 8) / 16) * 6) / 8; +} + diff --git a/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h b/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h new file mode 100644 index 000000000000..6959bf3c599e --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi-hamming-22-16.h @@ -0,0 +1,43 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * NCB software ECC Hamming code + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __LINUX_GPMI_H +#define __LINUX_GPMI_H + +#define NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES (512) +#define NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES \ + ((((NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES*8)/16)*6)/8) +#define NAND_HC_ECC_OFFSET_FIRST_DATA_COPY (0) +#define NAND_HC_ECC_OFFSET_SECOND_DATA_COPY \ + (NAND_HC_ECC_OFFSET_FIRST_DATA_COPY + \ + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_THIRD_DATA_COPY \ + (NAND_HC_ECC_OFFSET_SECOND_DATA_COPY + \ + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY \ + (NAND_HC_ECC_OFFSET_THIRD_DATA_COPY + \ + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY \ + (NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY + \ + NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES) +#define NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY \ + (NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY + \ + NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES) + +#endif diff --git a/drivers/mtd/nand/gpmi/gpmi.h b/drivers/mtd/nand/gpmi/gpmi.h new file mode 100644 index 000000000000..99c26988f370 --- /dev/null +++ b/drivers/mtd/nand/gpmi/gpmi.h @@ -0,0 +1,291 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __DRIVERS_GPMI_H +#define __DRIVERS_GPMI_H + +#include <linux/mtd/partitions.h> +#include <mach/gpmi.h> +#include <mach/regs-gpmi.h> +#include <mach/regs-apbh.h> +#ifdef CONFIG_MTD_NAND_GPMI_BCH +#include <mach/regs-bch.h> +#endif +#include <mach/regs-ecc8.h> + +#include "gpmi-hamming-22-16.h" + +#define GPMI_ECC4_WR \ + (BM_GPMI_ECCCTRL_ENABLE_ECC | \ + BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT)) +#define GPMI_ECC4_RD \ + (BM_GPMI_ECCCTRL_ENABLE_ECC | \ + BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT)) +#define GPMI_ECC8_WR \ + (BM_GPMI_ECCCTRL_ENABLE_ECC | \ + BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT)) +#define GPMI_ECC8_RD \ + (BM_GPMI_ECCCTRL_ENABLE_ECC | \ + BF_GPMI_ECCCTRL_ECC_CMD(BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT)) + +/* fingerprints of BCB that can be found on STMP-formatted flash */ +#define SIG1 "STMP" +#define SIG_NCB "NCB " +#define SIG_LDLB "LDLB" +#define SIG_DBBT "DBBT" +#define SIG_SIZE 4 + +struct gpmi_nand_timing { + u8 data_setup; + u8 data_hold; + u8 address_setup; + u8 dsample_time; +}; + +struct gpmi_bcb_info { + struct gpmi_nand_timing timing; + loff_t ncbblock; + const void *pre_ncb; + size_t pre_ncb_size; +}; + +struct gpmi_ncb; + +int gpmi_erase(struct mtd_info *mtd, struct erase_info *instr); +int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs); +int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip); +int gpmi_scan_bbt(struct mtd_info *mtd); +int gpmi_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip); +#ifdef CONFIG_MTD_NAND_GPMI_SYSFS_ENTRIES +int gpmi_sysfs(struct platform_device *p, int create); +#endif +int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd); +void gpmi_set_timings(struct platform_device *pdev, + struct gpmi_nand_timing *tm); +int gpmi_write_ncb(struct mtd_info *mtd, struct gpmi_bcb_info *b); + +unsigned gpmi_hamming_ecc_size_22_16(int block_size); +void gpmi_encode_hamming_ncb_22_16(void *source_block, size_t source_size, + void *target_block, size_t target_size); +void gpmi_encode_hamming_22_16(void *source_block, size_t src_size, + void *source_ecc, size_t ecc_size); +int gpmi_verify_hamming_22_16(void *data, u8 *parity, size_t size); + +unsigned gpmi_hamming_ecc_size_13_8(int block_size); +void gpmi_encode_hamming_ncb_13_8(void *source_block, size_t source_size, + void *target_block, size_t target_size); +void gpmi_encode_hamming_13_8(void *source_block, size_t src_size, + void *source_ecc, size_t ecc_size); +int gpmi_verify_hamming_13_8(void *data, u8 *parity, size_t size); + +#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */ + +/* + * Sizes of data buffers to exchange commands/data with NAND chip + * Default values cover 4K NAND page (4096 data bytes + 218 bytes OOB) + */ +#define GPMI_CMD_BUF_SZ 10 +#define GPMI_DATA_BUF_SZ NAND_MAX_PAGESIZE +#define GPMI_WRITE_BUF_SZ NAND_MAX_PAGESIZE +#define GPMI_OOB_BUF_SZ NAND_MAX_OOBSIZE + +#define GPMI_MAX_CHIPS 10 + +struct gpmi_hwecc_chip { + char name[40]; + struct list_head list; + int (*setup)(void *ctx, int index, int writesize, int oobsize); + int (*reset)(void *ctx, int index); + int (*read)(void *ctx, int index, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob); + int (*write)(void *ctx, int index, + struct stmp3xxx_dma_descriptor *chain, + dma_addr_t error, + dma_addr_t page, dma_addr_t oob); + int (*stat)(void *ctx, int index, struct mtd_ecc_stats *r); +}; + +/* HWECC chips */ +struct gpmi_hwecc_chip *gpmi_hwecc_chip_find(char *name); +void gpmi_hwecc_chip_add(struct gpmi_hwecc_chip *chip); +void gpmi_hwecc_chip_remove(struct gpmi_hwecc_chip *chip); +int bch_init(void); +int ecc8_init(void); +void bch_exit(void); +void ecc8_exit(void); + + +struct gpmi_nand_data { + void __iomem *io_base; + struct clk *clk; + int irq; + struct timer_list timer; + int self_suspended; + int use_count; + struct regulator *regulator; + int reg_uA; + + int ignorebad; + void *bbt; + + struct nand_chip chip; + struct mtd_info mtd; + struct platform_device *dev; + +#ifdef CONFIG_MTD_PARTITIONS + int nr_parts; + struct mtd_partition + *parts; +#endif + + struct completion done; + + u8 *cmd_buffer; + dma_addr_t cmd_buffer_handle; + int cmd_buffer_size, cmd_buffer_sz; + + u8 *write_buffer; + dma_addr_t write_buffer_handle; + int write_buffer_size; + u8 *read_buffer; /* point in write_buffer */ + dma_addr_t read_buffer_handle; + + u8 *data_buffer; + dma_addr_t data_buffer_handle; + int data_buffer_size; + + u8 *oob_buffer; + dma_addr_t oob_buffer_handle; + int oob_buffer_size; + + void *verify_buffer; + + struct nchip { + unsigned dma_ch; + struct stmp37xx_circ_dma_chain chain; + struct stmp3xxx_dma_descriptor d[GPMI_DMA_MAX_CHAIN]; + struct stmp3xxx_dma_descriptor error; + int cs; + } chips[GPMI_MAX_CHIPS]; + struct nchip *cchip; + int selected_chip; + + unsigned hwecc_type_read, hwecc_type_write; + int hwecc; + + int ecc_oob_bytes, oob_free; + + int transcribe_bbmark; + struct gpmi_nand_timing timing; + + void (*saved_command)(struct mtd_info *mtd, unsigned int command, + int column, int page_addr); + + int raw_oob_mode; + int (*saved_read_oob)(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops); + int (*saved_write_oob)(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops); + + struct gpmi_hwecc_chip *hc; + + int numchips; + int custom_partitions; + struct mtd_info *masters[GPMI_MAX_CHIPS]; + struct mtd_partition chip_partitions[GPMI_MAX_CHIPS]; + int n_concat; + struct mtd_info *concat[GPMI_MAX_CHIPS]; + struct mtd_info *concat_mtd; +}; + +extern struct gpmi_nand_timing gpmi_safe_timing; + +struct gpmi_ncb { + u32 fingerprint1; + struct gpmi_nand_timing timing; + u32 pagesize; + u32 page_plus_oob_size; + u32 sectors_per_block; + u32 sector_in_page_mask; + u32 sector_to_page_shift; + u32 num_nands; + u32 reserved[3]; + u32 fingerprint2; /* offset 0x2C */ +}; + +struct gpmi_ldlb { + u32 fingerprint1; + u16 major, minor, sub, reserved; + u32 nand_bitmap; + u32 reserved1[7]; + u32 fingerprint2; + struct { + u32 fw_starting_nand; + u32 fw_starting_sector; + u32 fw_sector_stride; + u32 fw_sectors_total; + } fw[2]; + u16 fw_major, fw_minor, fw_sub, fw_reserved; + u32 bbt_blk; + u32 bbt_blk_backup; +}; + +static inline void gpmi_block_mark_as(struct nand_chip *chip, + int block, int mark) +{ + u32 o; + int shift = (block & 0x03) << 1, + index = block >> 2; + + if (chip->bbt) { + mark &= 0x03; + + o = chip->bbt[index]; + o &= ~(0x03 << shift); + o |= (mark << shift); + chip->bbt[index] = o; + } +} + +static inline int gpmi_block_badness(struct nand_chip *chip, + int block) +{ + u32 o; + int shift = (block & 0x03) << 1, + index = block >> 2; + + if (chip->bbt) { + o = (chip->bbt[index] >> shift) & 0x03; + pr_debug("%s: block = %d, o = %d\n", __func__, block, o); + return o; + } + return -1; +} + +#ifdef CONFIG_STMP3XXX_UNIQUE_ID +int __init gpmi_uid_init(const char *name, struct mtd_info *mtd, + u_int32_t start, u_int32_t size); +void gpmi_uid_remove(const char *name); +#else +#define gpmi_uid_init(name, mtd, start, size) +#define gpmi_uid_remove(name) +#endif + +#endif diff --git a/drivers/mtd/nand/lba/Makefile b/drivers/mtd/nand/lba/Makefile new file mode 100644 index 000000000000..0e576bfa856d --- /dev/null +++ b/drivers/mtd/nand/lba/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MTD_NAND_GPMI_LBA) += gpmi_lba.o +gpmi_lba-objs += gpmi-transport.o lba-core.o lba-blk.o diff --git a/drivers/mtd/nand/lba/gpmi-transport.c b/drivers/mtd/nand/lba/gpmi-transport.c new file mode 100644 index 000000000000..4a2f9301e756 --- /dev/null +++ b/drivers/mtd/nand/lba/gpmi-transport.c @@ -0,0 +1,828 @@ +/* + * Freescale STMP37XX/STMP378X GPMI transport layer for LBA driver + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * Clock settings and hw init comes from + * gpmi driver by Dmitry Pervushin. + * + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/ctype.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <asm/div64.h> +#include <mach/stmp3xxx.h> +#include <mach/dma.h> +#include "gpmi.h" +#include "lba.h" + +struct lba_data *g_data; +static int max_chips = 1; +static long clk = -1; + +struct gpmi_nand_timing gpmi_safe_timing = { + .address_setup = 25, + .data_setup = 80, + .data_hold = 60, + .dsample_time = 6, +}; + +/****************************************************************************** + * HW init part + ******************************************************************************/ + +/** + * gpmi_irq - IRQ handler + * + * @irq: irq no + * @context: IRQ context, pointer to gpmi_nand_data + */ +static irqreturn_t gpmi_irq(int irq, void *context) +{ + struct lba_data *data = context; + int i; + + for (i = 0; i < max_chips; i++) { + if (stmp3xxx_dma_is_interrupt(data->nand[i].dma_ch)) { + stmp3xxx_dma_clear_interrupt(data->nand[i].dma_ch); + complete(&data->nand[i].done); + } + + } + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_DEV_IRQ | BM_GPMI_CTRL1_TIMEOUT_IRQ); + return IRQ_HANDLED; +} + +static inline u32 gpmi_cycles_ceil(u32 ntime, u32 period) +{ + int k; + + k = (ntime + period - 1) / period; + if (k == 0) + k++; + return k ; +} + + +/** + * gpmi_set_timings - set GPMI timings + * @pdev: pointer to GPMI platform device + * @tm: pointer to structure &gpmi_nand_timing with new timings + * + * During initialization, GPMI uses safe sub-optimal timings, which + * can be changed after reading boot control blocks + */ +void gpmi_set_timings(struct lba_data *data, struct gpmi_nand_timing *tm) +{ + u32 period_ns = 1000000 / clk_get_rate(data->clk) + 1; + u32 address_cycles, data_setup_cycles; + u32 data_hold_cycles, data_sample_cycles; + u32 busy_timeout; + u32 t0; + + address_cycles = gpmi_cycles_ceil(tm->address_setup, period_ns); + data_setup_cycles = gpmi_cycles_ceil(tm->data_setup, period_ns); + data_hold_cycles = gpmi_cycles_ceil(tm->data_hold, period_ns); + data_sample_cycles = gpmi_cycles_ceil(tm->dsample_time + period_ns / 4, + period_ns / 2); + busy_timeout = gpmi_cycles_ceil(10000000 / 4096, period_ns); + + t0 = BF_GPMI_TIMING0_ADDRESS_SETUP(address_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(data_setup_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles); + HW_GPMI_TIMING0_WR(t0); + + HW_GPMI_TIMING1_WR(BF_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT(busy_timeout)); + +#ifdef CONFIG_ARCH_STMP378X + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_RDN_DELAY); + HW_GPMI_CTRL1_SET(BF_GPMI_CTRL1_RDN_DELAY(data_sample_cycles)); +#else + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_DSAMPLE_TIME); + HW_GPMI_CTRL1_SET(BF_GPMI_CTRL1_DSAMPLE_TIME(data_sample_cycles)); +#endif + +} + +void queue_plug(struct lba_data *data) +{ + clk_enable(data->clk); + if (clk <= 0) + clk = 24000; /* safe setting, some chips do not work on + speeds >= 24kHz */ + clk_set_rate(data->clk, clk); + + clk = clk_get_rate(data->clk); + + + stmp3xxx_reset_block(HW_GPMI_CTRL0_OFFSET + REGS_GPMI_BASE, 1); + + /* write protection OFF */ + HW_GPMI_CTRL1_SET(BM_GPMI_CTRL1_DEV_RESET); + + /* IRQ polarity */ + HW_GPMI_CTRL1_SET(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY); + + /* ...and ECC module */ + /*HW_GPMI_CTRL1_SET(bch_mode());*/ + + /* choose NAND mode (1 means ATA, 0 - NAND */ + HW_GPMI_CTRL1_CLR(BM_GPMI_CTRL1_GPMI_MODE); + + gpmi_set_timings(data, &gpmi_safe_timing); +} + +void queue_release(struct lba_data *data) +{ + HW_GPMI_CTRL0_SET(BM_GPMI_CTRL0_SFTRST); + + clk_disable(data->clk); +} + + +/** + * gpmi_init_hw - initialize the hardware + * @pdev: pointer to platform device + * + * Initialize GPMI hardware and set default (safe) timings for NAND access. + * Returns error code or 0 on success + */ +static int gpmi_init_hw(struct platform_device *pdev, int request_pins) +{ + struct lba_data *data = platform_get_drvdata(pdev); + char *devname = pdev->dev.bus_id; + int err = 0; + + data->clk = clk_get(NULL, "gpmi"); + if (IS_ERR(data->clk)) { + err = PTR_ERR(data->clk); + dev_err(&pdev->dev, "cannot set failsafe clockrate\n"); + goto out; + } + if (request_pins) + gpmi_pinmux_request(devname); + + queue_plug(data); + +out: + return err; +} +/** + * gpmi_release_hw - free the hardware + * @pdev: pointer to platform device + * + * In opposite to gpmi_init_hw, release all acquired resources + */ +static void gpmi_release_hw(struct platform_device *pdev) +{ + struct lba_data *data = platform_get_drvdata(pdev); + + queue_release(data); + clk_put(data->clk); + gpmi_pinmux_free(pdev->dev.bus_id); +} + + +/** + * gpmi_alloc_buffers - allocate DMA buffers for one chip + * + * @pdev: GPMI platform device + * @g: pointer to structure associated with NAND chip + * + * Allocate buffer using dma_alloc_coherent + */ +static int gpmi_alloc_buffers(struct platform_device *pdev, + struct gpmi_perchip_data *g) +{ + g->cmd_buffer = dma_alloc_coherent(&pdev->dev, + g->cmd_buffer_size, + &g->cmd_buffer_handle, GFP_DMA); + if (!g->cmd_buffer) + goto out1; + + g->write_buffer = dma_alloc_coherent(&pdev->dev, + g->write_buffer_size, + &g->write_buffer_handle, GFP_DMA); + if (!g->write_buffer) + goto out2; + + g->data_buffer = dma_alloc_coherent(&pdev->dev, + g->data_buffer_size, + &g->data_buffer_handle, GFP_DMA); + if (!g->data_buffer) + goto out3; + + g->oob_buffer = dma_alloc_coherent(&pdev->dev, + g->oob_buffer_size, + &g->oob_buffer_handle, GFP_DMA); + if (!g->oob_buffer) + goto out4; + + g->cmdtail_buffer = dma_alloc_coherent(&pdev->dev, + g->cmdtail_buffer_size, + &g->cmdtail_buffer_handle, GFP_DMA); + if (!g->oob_buffer) + goto out5; + + return 0; + +out5: + dma_free_coherent(&pdev->dev, g->oob_buffer_size, + g->oob_buffer, g->oob_buffer_handle); + +out4: + dma_free_coherent(&pdev->dev, g->data_buffer_size, + g->data_buffer, g->data_buffer_handle); +out3: + dma_free_coherent(&pdev->dev, g->write_buffer_size, + g->write_buffer, g->write_buffer_handle); +out2: + dma_free_coherent(&pdev->dev, g->cmd_buffer_size, + g->cmd_buffer, g->cmd_buffer_handle); +out1: + return -ENOMEM; +} + +/** + * gpmi_free_buffers - free buffers allocated by gpmi_alloc_buffers + * + * @pdev: platform device + * @g: pointer to structure associated with NAND chip + * + * Deallocate buffers on exit + */ +static void gpmi_free_buffers(struct platform_device *pdev, + struct gpmi_perchip_data *g) +{ + dma_free_coherent(&pdev->dev, g->oob_buffer_size, + g->oob_buffer, g->oob_buffer_handle); + dma_free_coherent(&pdev->dev, g->write_buffer_size, + g->write_buffer, g->write_buffer_handle); + dma_free_coherent(&pdev->dev, g->cmd_buffer_size, + g->cmd_buffer, g->cmd_buffer_handle); + dma_free_coherent(&pdev->dev, g->cmdtail_buffer_size, + g->cmdtail_buffer, g->cmdtail_buffer_handle); + dma_free_coherent(&pdev->dev, g->data_buffer_size, + g->data_buffer, g->data_buffer_handle); +} + + +/****************************************************************************** + * Arch specific chain_* callbaks + ******************************************************************************/ + +/** + * chain_w4r - Initialize descriptor to perform W4R operation + * + * @chain: Descriptor to use + * @cs: CS for this operation + * + * Due to HW bug we have to put W4R into separate desc. + */ +static void chain_w4r(struct stmp3xxx_dma_descriptor *chain, int cs) +{ + chain->command->cmd = + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDWAIT4READY | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND( + BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY) | + BM_GPMI_CTRL0_WORD_LENGTH | + BF_GPMI_CTRL0_ADDRESS( + BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_CS(cs); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->pio_words[3] = 0; + chain->command->buf_ptr = 0; +} + +/** + * chain_cmd - Initialize descriptor to push CMD to the bus + * + * @chain: Descriptor to use + * @cmd_handle: dma_addr_t pointer that holds the command + * @lba_cmd: flags and lenghth of this command. + * @cs: CS for this operation + * + * CLE || CLE+ALE + */ +static void chain_cmd(struct stmp3xxx_dma_descriptor *chain, + dma_addr_t cmd_handle, + struct lba_cmd *lba_cmd, + int cs) +{ + /* output command */ + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(lba_cmd->len) | + BF_APBH_CHn_CMD_CMDWORDS(3) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BF_APBH_CHn_CMD_COMMAND(BV_APBH_CHn_CMD_COMMAND__DMA_READ); + chain->command->cmd |= BM_APBH_CHn_CMD_CHAIN; + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(cs) | + BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) | + BF_GPMI_CTRL0_XFER_COUNT(lba_cmd->len); + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->buf_ptr = cmd_handle; + + if (lba_cmd->flag & FE_CMD_INC) + chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT; +/*BUG if (lba_cmd->flag & FE_W4R) */ +/* chain->command->cmd |= BM_APBH_CHn_CMD_NANDWAIT4READY; */ +} + +/** + * chain_cmd - Initialize descriptor to read data from the bus + * + * @chain: Descriptor to use + * @data_handle: dma_addr_t pointer to buffer to store data + * @data_len: the size of the data buffer to read + * @cmd_handle: dma_addr_t pointer that holds the command + * @lba_cmd: flags and lenghth of this command. + * @cs: CS for this operation + */ +static void chain_read_data(struct stmp3xxx_dma_descriptor *chain, + dma_addr_t data_handle, + dma_addr_t data_len, + struct lba_cmd *lba_cmd, + int cs) +{ + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(data_len) | + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND( + BV_APBH_CHn_CMD_COMMAND__DMA_WRITE); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__READ) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(cs) | + BF_GPMI_CTRL0_ADDRESS( + BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_XFER_COUNT(data_len); + + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->pio_words[3] = 0; + chain->command->buf_ptr = data_handle; + + if (lba_cmd->flag & FE_CMD_INC) + chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT; +/*BUG if (lba_cmd->flag & FE_W4R) */ +/* chain->command->cmd |= BM_APBH_CHn_CMD_NANDWAIT4READY; */ + +} + +/** + * chain_cmd - Initialize descriptor to read data from the bus + * + * @chain: Descriptor to use + * @data_handle: dma_addr_t pointer to buffer to read data from + * @data_len: the size of the data buffer to write + * @cmd_handle: dma_addr_t pointer that holds the command + * @lba_cmd: flags and lenghth of this command. + * @cs: CS for this operation + */ +static void chain_write_data(struct stmp3xxx_dma_descriptor *chain, + dma_addr_t data_handle, + int data_len, + struct lba_cmd *lba_cmd, + int cs) +{ + + chain->command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(data_len) | + BF_APBH_CHn_CMD_CMDWORDS(4) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN | + BF_APBH_CHn_CMD_COMMAND( + BV_APBH_CHn_CMD_COMMAND__DMA_READ); + chain->command->pio_words[0] = + BF_GPMI_CTRL0_COMMAND_MODE( + BV_GPMI_CTRL0_COMMAND_MODE__WRITE) | + BM_GPMI_CTRL0_WORD_LENGTH | + BM_GPMI_CTRL0_LOCK_CS | + BF_GPMI_CTRL0_CS(cs) | + BF_GPMI_CTRL0_ADDRESS( + BV_GPMI_CTRL0_ADDRESS__NAND_DATA) | + BF_GPMI_CTRL0_XFER_COUNT(data_len); + + chain->command->pio_words[1] = 0; + chain->command->pio_words[2] = 0; + chain->command->pio_words[3] = 0; + chain->command->buf_ptr = data_handle; + + if (lba_cmd->flag & FE_CMD_INC) + chain->command->pio_words[0] |= BM_GPMI_CTRL0_ADDRESS_INCREMENT; +/*BUG if (lba_cmd->flag & FE_W4R) */ +/* chain->command->cmd |= BM_APBH_CHn_CMD_NANDWAIT4READY; */ + +} + + +/****************************************************************************** + * Interface to arch independent part + ******************************************************************************/ +/** + * queue_cmd - Setup a chain of descriptors + * + * @priv: private data passed + * @cmd_buf: pointer to command buffer (to be removed) + * @cmd_handle: dma_addr_t pointer that holds the command + * @cmd_len: the size of the command buffer (to be removed) + * @data_handle: dma_addr_t pointer to a data buffer + * @data_len: the size of the data buffer + * @cmd_flags: commands flags + */ +int queue_cmd(void *priv, + uint8_t *cmd_buf, dma_addr_t cmd_handle, int cmd_len, + dma_addr_t data, int data_len, + struct lba_cmd *cmd_flags) +{ + + struct gpmi_perchip_data *g = priv; + unsigned long flags; + int idx; + int ret = 0; + struct stmp3xxx_dma_descriptor *chain ; + int i; + + if (!g || !(cmd_buf || cmd_handle)) + BUG(); + + spin_lock_irqsave(&g->lock, flags); + + /* Keep it for debug purpose */ + chain = g->d; + for (i = g->d_tail; i < GPMI_DMA_MAX_CHAIN; i++) { + chain[i].command->cmd = 0; + chain[i].command->buf_ptr = 0; + } + /* End */ + + if (!cmd_handle) { + if (!cmd_buf) + BUG(); + memcpy(g->cmd_buffer, cmd_buf, cmd_len); + cmd_handle = g->cmd_buffer_handle; + } + + idx = g->d_tail; + chain = &g->d[idx]; + + do { + if (!cmd_flags) + BUG(); + + if (cmd_flags->flag & FE_W4R) { + /* there seems to be HW BUG with W4R flag. + * IRQ controller hangs forever when it's combined + * with real operation. + */ + chain_w4r(chain, g->cs); + chain++; idx++; + } + + + switch (cmd_flags->flag & F_MASK) { + + case F_CMD: + chain_cmd(chain, cmd_handle, cmd_flags, g->cs); + break; + case F_DATA_READ: + chain_read_data(chain, data, data_len, + cmd_flags, g->cs); + break; + case F_DATA_WRITE: + chain_write_data(chain, data, data_len, + cmd_flags, g->cs); + break; + default:{ + if (cmd_flags->flag & FE_END) + goto out; + else{ + printk(KERN_ERR "uknown cmd\n"); + BUG(); + } + } + } + + + chain++; idx++; + cmd_handle += cmd_flags->len; + + if (idx >= GPMI_DMA_MAX_CHAIN) { + printk(KERN_ERR "to many chains; idx is 0x%x\n", idx); + BUG(); + } + + } while (!((cmd_flags++)->flag & FE_END)); + +out: + if (idx < GPMI_DMA_MAX_CHAIN) { + ret = idx; + g->d_tail = idx; + } + spin_unlock_irqrestore(g->lock, flags); + + return ret; + +} + +dma_addr_t queue_get_cmd_handle(void *priv) +{ + struct gpmi_perchip_data *g = priv; + return g->cmd_buffer_handle; +} + +uint8_t *queue_get_cmd_ptr(void *priv) +{ + struct gpmi_perchip_data *g = priv; + return g->cmd_buffer; +} + +dma_addr_t queue_get_data_handle(void *priv) +{ + struct gpmi_perchip_data *g = priv; + return g->data_buffer_handle; +} + +uint8_t *queue_get_data_ptr(void *priv) +{ + struct gpmi_perchip_data *g = priv; + return g->data_buffer; +} + + +/** + * queue_run - run the chain + * + * @priv: private data. + */ +int queue_run(void *priv) +{ + struct gpmi_perchip_data *g = priv; + + if (!g->d_tail) + return 0; + stmp3xxx_dma_reset_channel(g->dma_ch); + stmp3xxx_dma_clear_interrupt(g->dma_ch); + stmp3xxx_dma_enable_interrupt(g->dma_ch); + + g->d[g->d_tail-1].command->cmd &= ~(BM_APBH_CHn_CMD_NANDLOCK | + BM_APBH_CHn_CMD_CHAIN); + g->d[g->d_tail-1].command->cmd |= BM_APBH_CHn_CMD_IRQONCMPLT ; + + g->d[g->d_tail-1].command->pio_words[0] &= ~BM_GPMI_CTRL0_LOCK_CS; + +#ifdef DEBUG + /*stmp37cc_dma_print_chain(&g->chain);*/ +#endif + + init_completion(&g->done); + stmp3xxx_dma_go(g->dma_ch, g->d, 1); + wait_for_completion(&g->done); + + g->d_tail = 0; + + return 0; + +} + +/****************************************************************************** + * Platform specific part / chard driver and misc functions + ******************************************************************************/ + + + +static int __init lba_probe(struct platform_device *pdev) +{ + struct lba_data *data; + struct resource *r; + struct gpmi_perchip_data *g; + int err; + + /* Allocate memory for the device structure (and zero it) */ + data = kzalloc(sizeof(*data) + sizeof(struct gpmi_perchip_data), + GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate gpmi_nand_data\n"); + err = -ENOMEM; + goto out1; + } + g_data = data; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "failed to get resource\n"); + err = -ENXIO; + goto out2; + } + data->io_base = ioremap(r->start, r->end - r->start + 1); + if (!data->io_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -EIO; + goto out2; + } + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) { + err = -EIO; + dev_err(&pdev->dev, "can't get IRQ resource\n"); + goto out3; + } + data->irq = r->start; + + platform_set_drvdata(pdev, data); + err = gpmi_init_hw(pdev, 1); + if (err) + goto out3; + + + err = request_irq(data->irq, + gpmi_irq, 0, pdev->dev.bus_id, data); + if (err) { + dev_err(&pdev->dev, "can't request GPMI IRQ\n"); + goto out4; + } + + g = data->nand; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) { + dev_err(&pdev->dev, "can't get DMA resource\n"); + goto out_res; + } + g->cs = 0; + g->dma_ch = r->start; + + err = stmp3xxx_dma_request(g->dma_ch, NULL, pdev->dev.bus_id); + if (err) { + dev_err(&pdev->dev, "can't request DMA channel 0x%x\n", + g->dma_ch); + goto out_res; + } + + err = stmp3xxx_dma_make_chain(g->dma_ch, &g->chain, + g->d, ARRAY_SIZE(g->d)); + if (err) { + dev_err(&pdev->dev, "can't setup DMA chain\n"); + stmp3xxx_dma_release(g->dma_ch); + goto out_res; + } + + g->cmd_buffer_size = GPMI_CMD_BUF_SZ; + g->cmdtail_buffer_size = GPMI_CMD_BUF_SZ; + g->write_buffer_size = GPMI_WRITE_BUF_SZ; + g->data_buffer_size = GPMI_DATA_BUF_SZ; + g->oob_buffer_size = GPMI_OOB_BUF_SZ; + + err = gpmi_alloc_buffers(pdev, g); + if (err) { + dev_err(&pdev->dev, "can't setup buffers\n"); + stmp3xxx_dma_free_chain(&g->chain); + stmp3xxx_dma_release(g->dma_ch); + goto out_res; + } + + g->dev = pdev; + g->chip.priv = g; + g->index = 0; + g->timing = gpmi_safe_timing; + + g->cmd_buffer_sz = + g->write_buffer_sz = + g->data_buffer_sz = + 0; + g->valid = !0; /* mark the data as valid */ + + + lba_core_init(data); + + return 0; + +out_res: + free_irq(data->irq, data); +out4: + gpmi_release_hw(pdev); +out3: + platform_set_drvdata(pdev, NULL); + iounmap(data->io_base); +out2: + kfree(data); +out1: + return err; +} + +static int gpmi_suspend(struct platform_device *pdev, pm_message_t pm) +{ + struct lba_data *data = platform_get_drvdata(pdev); + int err; + + printk(KERN_INFO "%s: %d\n", __func__, __LINE__); + err = lba_core_suspend(pdev, data); + if (!err) + gpmi_release_hw(pdev); + + return err; +} + +static int gpmi_resume(struct platform_device *pdev) +{ + struct lba_data *data = platform_get_drvdata(pdev); + int r; + + printk(KERN_INFO "%s: %d\n", __func__, __LINE__); + r = gpmi_init_hw(pdev, 1); + lba_core_resume(pdev, data); + return r; +} + +/** + * gpmi_nand_remove - remove a GPMI device + * + */ +static int __devexit lba_remove(struct platform_device *pdev) +{ + struct lba_data *data = platform_get_drvdata(pdev); + int i; + + lba_core_remove(data); + gpmi_release_hw(pdev); + free_irq(data->irq, data); + + for (i = 0; i < max_chips; i++) { + if (!data->nand[i].valid) + continue; + gpmi_free_buffers(pdev, &data->nand[i]); + stmp3xxx_dma_free_chain(&data->nand[i].chain); + stmp3xxx_dma_release(data->nand[i].dma_ch); + } + iounmap(data->io_base); + kfree(data); + + return 0; +} + +static struct platform_driver lba_driver = { + .probe = lba_probe, + .remove = __devexit_p(lba_remove), + .driver = { + .name = "gpmi", + .owner = THIS_MODULE, + }, + .suspend = gpmi_suspend, + .resume = gpmi_resume, + +}; + + +static int __init lba_init(void) +{ + return platform_driver_register(&lba_driver); +} + +static void lba_exit(void) +{ + platform_driver_unregister(&lba_driver); +} + +module_init(lba_init); +module_exit(lba_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/lba/gpmi.h b/drivers/mtd/nand/lba/gpmi.h new file mode 100644 index 000000000000..a647c948040f --- /dev/null +++ b/drivers/mtd/nand/lba/gpmi.h @@ -0,0 +1,103 @@ +/* + * Freescale STMP37XX/STMP378X GPMI (General-Purpose-Media-Interface) + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __DRIVERS_GPMI_H +#define __DRIVERS_GPMI_H + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <mach/stmp3xxx.h> +#include <mach/dma.h> + +#include <mach/gpmi.h> +#include <mach/regs-gpmi.h> +#include <mach/regs-apbh.h> +#ifdef CONFIG_MTD_NAND_GPMI_BCH +#include <mach/regs-bch.h> +#endif + + +struct gpmi_nand_timing { + u8 data_setup; + u8 data_hold; + u8 address_setup; + u8 dsample_time; +}; + +#define GPMI_DMA_MAX_CHAIN 20 /* max DMA commands in chain */ + +#define GPMI_CMD_BUF_SZ 10 +#define GPMI_DATA_BUF_SZ 4096 +#define GPMI_WRITE_BUF_SZ 4096 +#define GPMI_OOB_BUF_SZ 218 + + +struct gpmi_perchip_data { + int valid; + struct nand_chip chip; + struct platform_device *dev; + int index; + + spinlock_t lock; /* protect chain operations */ + struct stmp37xx_circ_dma_chain chain; + struct stmp3xxx_dma_descriptor d[GPMI_DMA_MAX_CHAIN]; + int d_tail; + + struct completion done; + + u8 *cmd_buffer; + dma_addr_t cmd_buffer_handle; + int cmd_buffer_size, cmd_buffer_sz; + + u8 *cmdtail_buffer; + dma_addr_t cmdtail_buffer_handle; + int cmdtail_buffer_size, cmdtail_buffer_sz; + + u8 *write_buffer; + dma_addr_t write_buffer_handle; + int write_buffer_size, write_buffer_sz; + + u8 *data_buffer; + dma_addr_t data_buffer_handle; + u8 *data_buffer_cptr; + int data_buffer_size, data_buffer_sz, bytes2read; + + u8 *oob_buffer; + dma_addr_t oob_buffer_handle; + int oob_buffer_size; + + int cs; + unsigned dma_ch; + + int ecc_oob_bytes, oob_free; + + struct gpmi_nand_timing timing; + + void *p2w, *oob2w, *p2r, *oob2r; + size_t p2w_size, oob2w_size, p2r_size, oob2r_size; + dma_addr_t p2w_dma, oob2w_dma, p2r_dma, oob2r_dma; + unsigned read_memcpy:1, write_memcpy:1, + read_oob_memcpy:1, write_oob_memcpy:1; +}; + + +extern struct gpmi_nand_timing gpmi_safe_timing; + + +#endif diff --git a/drivers/mtd/nand/lba/lba-blk.c b/drivers/mtd/nand/lba/lba-blk.c new file mode 100644 index 000000000000..1991fad4f05d --- /dev/null +++ b/drivers/mtd/nand/lba/lba-blk.c @@ -0,0 +1,345 @@ +/* + * Freescale STMP37XX/STMP378X LBA/block driver + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> + +#include <linux/sched.h> +#include <linux/kernel.h> /* printk() */ +#include <linux/slab.h> /* kmalloc() */ +#include <linux/fs.h> /* everything... */ +#include <linux/errno.h> /* error codes */ +#include <linux/kthread.h> +#include <linux/timer.h> +#include <linux/types.h> /* size_t */ +#include <linux/fcntl.h> /* O_ACCMODE */ +#include <linux/hdreg.h> /* HDIO_GETGEO */ +#include <linux/kdev_t.h> +#include <linux/vmalloc.h> +#include <linux/genhd.h> +#include <linux/blkdev.h> +#include <linux/buffer_head.h> /* invalidate_bdev */ +#include <linux/bio.h> +#include <linux/dma-mapping.h> +#include <linux/hdreg.h> +#include <linux/blkdev.h> +#include "lba.h" + +static int lba_major; + +#define LBA_NAME "lba" + +#if 0 +#define TAG() printk(KERNE_ERR "%s: %d\n", __func__, __LINE__) +#else +#define TAG() +#endif + +/* + * The internal representation of our device. + */ +struct lba_blk_dev { + int size; /* Device size in sectors */ + spinlock_t lock; /* For mutual exclusion */ + int users; + struct request_queue *queue; /* The device request queue */ + struct gendisk *gd; /* The gendisk structure */ + struct lba_data *data; /* pointer from lba core */ + + struct task_struct *thread; + struct bio *bio_head; + struct bio *bio_tail; + wait_queue_head_t wait_q; + struct semaphore busy; + +}; + +static struct lba_blk_dev *g_lba_blk; + +static void blk_add_bio(struct lba_blk_dev *dev, struct bio *bio); + + +/* + * Transfer a single BIO. + */ +static int lba_blk_xfer_bio(struct lba_blk_dev *dev, struct bio *bio) +{ + int i; + struct bio_vec *bvec; + sector_t sector = bio->bi_sector; + enum dma_data_direction dir; + int status = 0; + int (*lba_xfer)(void *priv, + unsigned int sector, + unsigned int count, + void *buffer, + dma_addr_t handle); + + if (bio_data_dir(bio) == WRITE) { + lba_xfer = lba_write_sectors; + dir = DMA_TO_DEVICE; + } else { + lba_xfer = lba_read_sectors; + dir = DMA_FROM_DEVICE; + } + + /* Fixme: merge segments */ + bio_for_each_segment(bvec, bio, i) { + void *buffer = page_address(bvec->bv_page); + dma_addr_t handle ; + if (!buffer) + BUG(); + buffer += bvec->bv_offset; + handle = dma_map_single(&dev->data->nand->dev->dev, + buffer, + bvec->bv_len, + dir); + status = lba_xfer(dev->data->nand, sector, + bvec->bv_len >> 9, + buffer, + handle); + + dma_unmap_single(&dev->data->nand->dev->dev, + handle, + bvec->bv_len, + dir); + if (status) + break; + + sector += bio_cur_sectors(bio); + } + + return status; +} + + +/* + * The direct make request version. + */ +static int lba_make_request(struct request_queue *q, struct bio *bio) +{ + struct lba_blk_dev *dev = q->queuedata; + + blk_add_bio(dev, bio); + return 0; +} + +/* + * Open and close. + */ + +static int lba_blk_open(struct block_device *bdev, fmode_t mode) +{ + struct lba_blk_dev *dev = bdev->bd_disk->private_data; + + TAG(); + + spin_lock_irq(&dev->lock); + dev->users++; + spin_unlock_irq(&dev->lock); + return 0; +} + + +static int lba_blk_release(struct gendisk *gd, fmode_t mode) +{ + struct lba_blk_dev *dev = gd->private_data; + + spin_lock(&dev->lock); + dev->users--; + spin_unlock(&dev->lock); + + return 0; +} + +static int lba_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + /* + * get geometry: we have to fake one... trim the size to a + * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, + * whatever cylinders. + */ + geo->heads = 1 << 6; + geo->sectors = 1 << 5; + geo->cylinders = get_capacity(bdev->bd_disk) >> 11; + return 0; +} + +/* + * Add bio to back of pending list + */ +static void blk_add_bio(struct lba_blk_dev *dev, struct bio *bio) +{ + unsigned long flags; + spin_lock_irqsave(&dev->lock, flags); + if (dev->bio_tail) { + dev->bio_tail->bi_next = bio; + dev->bio_tail = bio; + } else + dev->bio_head = dev->bio_tail = bio; + wake_up(&dev->wait_q); + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* + * Grab first pending buffer + */ +static struct bio *blk_get_bio(struct lba_blk_dev *dev) +{ + struct bio *bio; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + bio = dev->bio_head; + if (bio) { + if (bio == dev->bio_tail) { + dev->bio_tail = NULL; + dev->bio_head = NULL; + } + dev->bio_head = bio->bi_next; + bio->bi_next = NULL; + } + spin_unlock_irqrestore(&dev->lock, flags); + + return bio; +} + +static int lba_thread(void *data) +{ + struct lba_blk_dev *dev = data; + struct bio *bio; + int status; + + set_user_nice(current, -20); + + while (!kthread_should_stop() || dev->bio_head) { + + wait_event_interruptible(dev->wait_q, + dev->bio_head || kthread_should_stop()); + + if (!dev->bio_head) + continue; + + if (lba_core_lock_mode(dev->data, LBA_MODE_MDP)) + continue; + + bio = blk_get_bio(dev); + status = lba_blk_xfer_bio(dev, bio); + bio_endio(bio, status); + + lba_core_unlock_mode(dev->data); + } + + return 0; +} + + + +/* + * The device operations structure. + */ +static struct block_device_operations lba_blk_ops = { + .owner = THIS_MODULE, + .open = lba_blk_open, + .release = lba_blk_release, + .getgeo = lba_getgeo, +}; + + +int lba_blk_init(struct lba_data *data) +{ + + struct lba_blk_dev *dev; + int err; + if (!data) + BUG(); + + printk(KERN_INFO "LBA block driver v0.1\n"); + lba_major = LBA_MAJOR; + dev = g_lba_blk = kzalloc(sizeof(struct lba_blk_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->data = data; + register_blkdev(lba_major, "lba"); + + spin_lock_init(&dev->lock); + init_waitqueue_head(&dev->wait_q); + sema_init(&dev->busy, 1); + + dev->queue = blk_alloc_queue(GFP_KERNEL); + if (!dev->queue) + goto out2; + blk_queue_make_request(dev->queue, lba_make_request); + /*dev->queue->unplug_fn = lba_unplug_device;*/ + blk_queue_hardsect_size(dev->queue, 512); + + dev->queue->queuedata = dev; + dev->gd = alloc_disk(32); + if (!dev->gd) { + printk(KERN_ERR "failed to alloc disk\n"); + goto out3; + } + dev->size = data->mdp_size ; + printk(KERN_INFO "%s: set capacity of the device to 0x%x\n", + __func__, dev->size); + dev->gd->major = lba_major; + dev->gd->first_minor = 0; + dev->gd->fops = &lba_blk_ops; + dev->gd->queue = dev->queue; + dev->gd->private_data = dev; + snprintf(dev->gd->disk_name, 8, LBA_NAME); + set_capacity(dev->gd, dev->size); + + dev->thread = kthread_create(lba_thread, dev, "lba-%d", 1); + if (IS_ERR(dev->thread)) { + err = PTR_ERR(dev->thread); + goto out3; + } + wake_up_process(dev->thread); + + add_disk(dev->gd); + + + TAG(); + + return 0; +out3: +out2: + unregister_blkdev(lba_major, "lba"); + return -ENOMEM; +} + +int lba_blk_remove(struct lba_data *data) +{ + + struct lba_blk_dev *dev = g_lba_blk; + + del_gendisk(dev->gd); + kthread_stop(dev->thread); + blk_cleanup_queue(dev->queue); + put_disk(dev->gd); + + unregister_blkdev(lba_major, LBA_NAME); + kfree(dev); + return 0; +} + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_BLOCKDEV_MAJOR(254); diff --git a/drivers/mtd/nand/lba/lba-core.c b/drivers/mtd/nand/lba/lba-core.c new file mode 100644 index 000000000000..cdf28ca42b2a --- /dev/null +++ b/drivers/mtd/nand/lba/lba-core.c @@ -0,0 +1,619 @@ +/* + * Freescale STMP37XX/STMP378X LBA/core driver + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/dma-mapping.h> +#include <linux/ctype.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <mach/stmp3xxx.h> +#include <mach/dma.h> +#include "gpmi.h" +#include "lba.h" + +#define LBA_SELFPM_TIMEOUT 2000 /* msecs */ +dma_addr_t g_cmd_handle; +dma_addr_t g_data_handle; +uint8_t *g_data_buffer; +uint8_t *g_cmd_buffer; + +uint8_t lba_get_status1(void *priv) +{ + uint8_t cmd_buf[] = { 0x70 } ; + struct lba_cmd lba_flags[] = { + {1 , F_CMD | FE_W4R}, + {0, F_DATA_READ | FE_END}, + }; + *g_data_buffer = 0; + queue_cmd(priv, cmd_buf, 0, 1, g_data_handle, 1, lba_flags); + queue_run(priv); + return *g_data_buffer; +} + + +int lba_wait_for_ready(void *priv) +{ + int stat; + unsigned long j_start = jiffies; + + stat = lba_get_status1(priv); + if ((stat & 0x60) != 0x60) { + while (((stat & 0x60) != 0x60) && + (jiffies - j_start < msecs_to_jiffies(2000))) { + schedule(); + stat = lba_get_status1(priv); + } + } + if (stat != 0x60) + return stat; + + return 0; +} + +int lba_write_sectors(void *priv, unsigned int sector, unsigned int count, + void *buffer, dma_addr_t handle) +{ + uint8_t cmd_buf[] = { + 0x80, + count & 0xff, (count >> 8) & 0xff, /* Count */ + (sector & 0xff), (sector >> 8) & 0xff, /* Address */ + (sector >> 16) & 0xff, (sector >> 24) & 0xff, /* Addres */ + /* Data goes here */ + 0x10 + }; + + struct lba_cmd flags_t1[] = { /* Transmition mode 1/A */ + {7 , F_CMD | FE_CMD_INC | FE_W4R}, + {0, F_DATA_WRITE}, + {1 , F_CMD | FE_END} + }; + + if (count > 8) + return -EINVAL; + + if (lba_wait_for_ready(priv)) + return -EIO; + + while (count) { + int cnt = (count < 8) ? count : 8; + int data_len = cnt * 512; + + queue_cmd(priv, cmd_buf, 0, 8, + handle, data_len, flags_t1); + + handle += data_len; + count -= cnt; + + } + + queue_run(priv); + + return count; + +} + +int lba_read_sectors(void *priv, unsigned int sector, unsigned int count, + void *buffer, dma_addr_t handle) +{ + + int data_len; + int cnt; + uint8_t cmd_buf[] = { + 0x00, + count & 0xff, (count >> 8) & 0xff, /* Count */ + (sector & 0xff), (sector >> 8) & 0xff, /* Addr */ + (sector >> 16) & 0xff, (sector >> 24) & 0xff, /* Addr */ + 0x30 + /* Data goes here <data> */ + + }; + + struct lba_cmd flags_r3[] = { /* Read mode 3/A */ + {7 , F_CMD | FE_CMD_INC | FE_W4R}, + {1 , F_CMD }, + {0 , F_DATA_READ | FE_W4R | FE_END }, + }; + struct lba_cmd flags_r3c[] = { /* Read mode 3/A */ + {0 , F_DATA_READ | FE_W4R | FE_END }, + }; + struct lba_cmd *flags = flags_r3; + int flags_len = 8; + + if (count > 8) + return -EINVAL; + + if (lba_wait_for_ready(priv)) + return -EIO; + + while (count) { + cnt = (count < 8) ? count : 8; + data_len = cnt * 512; + queue_cmd(priv, cmd_buf, 0, flags_len, handle, data_len, flags); + handle += data_len; + count -= cnt; + flags = flags_r3c; + flags_len = 0; + } + + queue_run(priv); + + return count; + +} + + +uint8_t lba_get_id1(void *priv, uint8_t *ret_buffer) +{ + uint8_t cmd_buf[] = { 0x90 , 0x00, /* Data read 5bytes*/ }; + struct lba_cmd lba_flags[] = { + {2 , F_CMD | FE_CMD_INC | FE_W4R}, + {0, F_DATA_READ | FE_END}, + }; + + queue_cmd(priv, cmd_buf, 0, 2, g_data_handle, 5, lba_flags); + queue_run(priv); + memcpy(ret_buffer, g_data_buffer, 5); + + return 0; +} + +uint8_t lba_get_id2(void *priv, uint8_t *ret_buffer) +{ + uint8_t cmd_buf[] = { 0x92 , 0x00, /* Data read 5bytes*/ }; + struct lba_cmd lba_flags[] = { + {2 , F_CMD | FE_CMD_INC | FE_W4R}, + {0, F_DATA_READ | FE_END}, + }; + + queue_cmd(priv, cmd_buf, 0, 2, g_data_handle, 5, lba_flags); + queue_run(priv); + memcpy(ret_buffer, g_data_buffer, 5); + return 0; +} + +uint8_t lba_get_status2(void *priv) +{ + uint8_t cmd_buf[] = { 0x71 }; + struct lba_cmd lba_flags[] = { + {1 , F_CMD | FE_CMD_INC | FE_W4R}, + {0 , F_DATA_READ | FE_END}, + }; + *g_data_buffer = 0; + queue_cmd(priv, cmd_buf, 0, 1, g_data_handle, 1, lba_flags); + queue_run(priv); + return *g_data_buffer; +} + +static uint8_t lba_parse_status2(void *priv) +{ + uint8_t stat; + + stat = lba_get_status2(priv); + printk(KERN_INFO "Status2:|"); + if (stat & 0x40) + printk(" C.PAR.ERR |"); /* no KERN_ here */ + if (stat & 0x20) + printk(" NO spare |"); + if (stat & 0x10) + printk(" ADDR OoRange |"); + if (stat & 0x8) + printk(" high speed |"); + if ((stat & 0x6) == 6) + printk(" MDP |"); + if ((stat & 0x6) == 4) + printk(" VFP |"); + if ((stat & 0x6) == 2) + printk(" PNP |"); + if (stat & 1) + printk(" PSW |"); + + printk("\n"); + return 0; +} + + +int lba_2mdp(void *priv) +{ + uint8_t cmd_buf[] = { 0xFC }; + struct lba_cmd lba_flags[] = { + {1 , F_CMD | FE_W4R | FE_END} + }; + + queue_cmd(priv, cmd_buf, 0, 1, 0, 0, lba_flags); + queue_run(priv); + return 0; +} + +void _lba_misc_cmd_set(void *priv, uint8_t *cmd_buf) +{ + struct lba_cmd lba_flags[] = { + {6 , F_CMD | FE_CMD_INC | FE_W4R }, + {1 , F_CMD | FE_END }, + }; + + queue_cmd(priv, cmd_buf, 0, 7, 0, 0, lba_flags); + queue_run(priv); +} + +uint8_t _lba_misc_cmd_get(void *priv, uint8_t *cmd_buf) +{ + struct lba_cmd lba_flags[] = { + {6 , F_CMD | FE_CMD_INC | FE_W4R }, + {1 , F_CMD }, + {0 , F_DATA_READ | FE_W4R | FE_END} + }; + + queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 1, lba_flags); + queue_run(priv); + return *g_data_buffer; +} +void lba_mdp2vfp(void *priv, uint8_t pass[2]) +{ + uint8_t cmd_buf[] = { 0x0, 0xbe, pass[0], pass[1], 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} + +void lba_bcm2vfp(void *priv, uint8_t pass[2]) +{ + lba_mdp2vfp(priv, pass); +} + +void lba_powersave_enable(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xba, 0, 0, 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} +void lba_powersave_disable(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xbb, 0, 0, 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} + +void lba_highspeed_enable(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xbc, 0, 0, 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} + +void lba_highspeed_disable(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xbd, 0, 0, 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} + +void lba_prot1_set(void *priv, uint8_t mode) +{ + uint8_t cmd_buf[] = { 0x0, 0xa2, mode, 0, 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} + +void lba_prot2_set(void *priv, uint8_t mode) +{ + uint8_t cmd_buf[] = { 0x0, 0xa3, mode, 0, 0, 0, 0x57 }; + _lba_misc_cmd_set(priv, cmd_buf); +} + +uint8_t lba_prot1_get(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xb2, 0, 0, 0, 0, 0x57 }; + return _lba_misc_cmd_get(priv, cmd_buf); +} + +uint8_t lba_prot2_get(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xb3, 0, 0, 0, 0, 0x57 }; + return _lba_misc_cmd_get(priv, cmd_buf); +} + +uint64_t lba_mdp_size_get(void *priv) +{ + uint8_t cmd_buf[] = { 0x0, 0xb0, 0, 0, 0, 0, 0x57 }; + struct lba_cmd lba_flags[] = { + {6 , F_CMD | FE_CMD_INC | FE_W4R }, + {1 , F_CMD }, + {0 , F_DATA_READ | FE_W4R | FE_END} + }; + + memset((void *)g_data_buffer, 0, 8); + queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 5, lba_flags); + queue_run(priv); + return le64_to_cpu(*(long long *)g_data_buffer); +} + +void lba_cache_flush(void *priv) +{ + uint8_t cmd_buf[] = { 0xF9 }; + struct lba_cmd lba_flags[] = { + {1 , F_CMD | FE_W4R }, + {0 , FE_W4R | FE_END} + }; + + queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 5, lba_flags); + queue_run(priv); +} + +void lba_reboot(void *priv) +{ + uint8_t cmd_buf[] = { 0xFD }; + struct lba_cmd lba_flags[] = { + {1 , F_CMD | FE_W4R }, + {0 , FE_W4R | FE_END} + }; + + queue_cmd(priv, cmd_buf, 0, 7, g_data_handle, 5, lba_flags); + queue_run(priv); +} + +void lba_def_state(void *priv) +{ + lba_wait_for_ready(priv); + lba_reboot(priv); + + lba_wait_for_ready(priv); + lba_parse_status2(priv); + + lba_wait_for_ready(priv); + lba_2mdp(priv); + + lba_wait_for_ready(priv); + lba_prot1_set(priv, LBA_T_SIZE8); /* 512 * 8 */ + + lba_wait_for_ready(priv); +/* Type C read; Type A write; */ + lba_prot2_set(priv, LBA_P_WRITE_A | LBA_P_READ_C); +} + +/* + * Should be called with mode locked + */ +void lba_core_setvfp_passwd(struct lba_data *data, uint8_t pass[2]) +{ + memcpy(data->pass, pass, 2); +} + +int lba_core_lock_mode(struct lba_data *data, int mode) +{ + void *priv = &data->nand; + + if (down_interruptible(&data->mode_lock)) + return -EAGAIN; + /* + * MDP and VFP are the only supported + * modes for now. + */ + if ((mode != LBA_MODE_MDP) && + (mode != LBA_MODE_VFP)) { + up(&data->mode_lock); + return -EINVAL; + } + + while ((data->mode & LBA_MODE_MASK) == LBA_MODE_SUSP) { + up(&data->mode_lock); + + if (wait_event_interruptible( + data->suspend_q, + (data->mode & LBA_MODE_MASK) != LBA_MODE_SUSP)) + return -EAGAIN; + + if (down_interruptible(&data->mode_lock)) + return -EAGAIN; + + data->last_access = jiffies; + } + + if (data->mode & LBA_MODE_SELFPM) { + queue_plug(data); + data->mode &= ~LBA_MODE_SELFPM; + } + + if (mode == data->mode) + return 0; + + /* + * mode = VFP || MDP only + * Revisit when more modes are added + */ + switch (data->mode) { + case LBA_MODE_RST: + case LBA_MODE_PNR: + case LBA_MODE_BCM: + lba_def_state(priv); + if (mode == LBA_MODE_MDP) { + data->mode = LBA_MODE_MDP; + break; + } + /*no break -> fall down to set VFP mode*/ + case LBA_MODE_MDP: + lba_wait_for_ready(priv); + lba_mdp2vfp(priv, data->pass); + data->mode = LBA_MODE_VFP; + break; + case LBA_MODE_VFP: + lba_wait_for_ready(priv); + lba_2mdp(priv); + data->mode = LBA_MODE_MDP; + break; + default: + up(&data->mode_lock); + return -EINVAL; + } + + return 0; +} + +int lba_core_unlock_mode(struct lba_data *data) +{ + data->last_access = jiffies; + up(&data->mode_lock); + wake_up(&data->selfpm_q); + return 0; +} + +static int selfpm_timeout_expired(struct lba_data *data) +{ + return jiffies_to_msecs(jiffies - data->last_access) > 2000; +} + +static int lba_selfpm_thread(void *d) +{ + struct lba_data *data = d; + + set_user_nice(current, -5); + + while (!kthread_should_stop()) { + + if (wait_event_interruptible(data->selfpm_q, + kthread_should_stop() || + !(data->mode & LBA_MODE_SELFPM))) + continue; + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(LBA_SELFPM_TIMEOUT)); + + if (down_trylock(&data->mode_lock)) + continue; + + if (!selfpm_timeout_expired(data)) { + up(&data->mode_lock); + continue; + } + data->mode |= LBA_MODE_SELFPM; + lba_wait_for_ready((void *)data->nand); + lba_cache_flush((void *)data->nand); + queue_release(data); + up(&data->mode_lock); + + } + + return 0; +} + +int lba_core_init(struct lba_data *data) +{ + uint8_t id_buf[5]; + uint8_t capacity; + uint8_t id1_template[5] = {0x98, 0xDC, 0x00, 0x15, 0x00}; + uint8_t id2_template[5] = {0x98, 0x21, 0x00, 0x55, 0xAA}; + void *priv = (void *)data->nand; + + + g_data = data; + g_cmd_handle = queue_get_cmd_handle(priv); + g_data_handle = queue_get_data_handle(priv); + g_data_buffer = queue_get_data_ptr(priv); + g_cmd_buffer = queue_get_cmd_ptr(priv); + + spin_lock_init(&data->lock); + sema_init(&data->mode_lock, 1); + init_waitqueue_head(&data->suspend_q); + init_waitqueue_head(&data->selfpm_q); + + + lba_get_id1(data->nand, id_buf); + if (!memcmp(id_buf, id1_template, 5)) + printk(KERN_INFO + "LBA: Found LBA/SLC NAND emulated ID\n"); + else + return -ENODEV; + + lba_get_id2(data->nand, id_buf); + capacity = id_buf[2]; + id_buf[2] = 0; + + if (memcmp(id_buf, id2_template, 5)) { + printk(KERN_INFO + "LBA: Uknown LBA device\n"); + return -ENODEV; + } + printk(KERN_INFO + "LBA: Found %dGbytes LBA NAND device\n", + 1 << capacity); + + lba_wait_for_ready(priv); + lba_parse_status2(priv); + + lba_def_state(priv); + data->mode = LBA_MODE_MDP; + + g_data->pnp_size = 0xff; + g_data->vfp_size = 16384; + + lba_wait_for_ready(priv); + g_data->mdp_size = lba_mdp_size_get(priv); + + lba_wait_for_ready(priv); + /*lba_powersave_enable(priv);*/ + /*lba_highspeed_enable(priv);*/ + + lba_wait_for_ready(priv); + lba_parse_status2(priv); + + data->thread = kthread_create(lba_selfpm_thread, + data, "lba-selfpm-%d", 1); + if (IS_ERR(data->thread)) + return PTR_ERR(data->thread); + + lba_blk_init(g_data); + + wake_up_process(data->thread); + return 0; + +}; + +int lba_core_remove(struct lba_data *data) +{ + kthread_stop(data->thread); + lba_blk_remove(data); + lba_wait_for_ready((void *)data->nand); + lba_cache_flush((void *)data->nand); + return 0; +} + +int lba_core_suspend(struct platform_device *pdev, struct lba_data *data) +{ + BUG_ON((data->mode & 0xffff) == LBA_MODE_SUSP); + if (down_interruptible(&data->mode_lock)) + return -EAGAIN; + if (data->mode & LBA_MODE_SELFPM) + queue_plug(data); + + data->mode = LBA_MODE_SUSP | LBA_MODE_SELFPM; + up(&data->mode_lock); + lba_wait_for_ready((void *)data->nand); + lba_cache_flush((void *)data->nand); + return 0; +} + +int lba_core_resume(struct platform_device *pdev, struct lba_data *data) +{ + BUG_ON((data->mode & 0xffff) != LBA_MODE_SUSP); + lba_def_state((void *)data->nand); + data->last_access = jiffies; + data->mode = LBA_MODE_MDP; + wake_up(&data->suspend_q); + return 0; +} diff --git a/drivers/mtd/nand/lba/lba.h b/drivers/mtd/nand/lba/lba.h new file mode 100644 index 000000000000..4ad37ecbc44f --- /dev/null +++ b/drivers/mtd/nand/lba/lba.h @@ -0,0 +1,141 @@ +/* + * Freescale STMP37XX/STMP378X LBA interface + * + * Author: Dmitrij Frasenyak <sed@embeddedalley.com> + * + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __INCLUDE_LBA_H__ +#define __INCLUDE_LBA_H__ + + +#include <linux/spinlock.h> +#include <linux/kthread.h> +#include "gpmi.h" + +struct lba_cmd { + uint8_t len; +#define F_MASK 0x0f +#define F_ALE 0x01 +#define F_CMD 0x02 +#define F_DATA_READ 0x04 +#define F_DATA_WRITE 0x08 + +#define FE_W4R 0x10 +#define FE_CMD_INC 0x20 +#define FE_END 0x40 + + uint8_t flag; +}; + +#define LBA_P_READ_A 0 +#define LBA_P_READ_B 2 +#define LBA_P_READ_C 3 +#define LBA_P_WRITE_A 0 +#define LBA_P_WRITE_B 4 +#define LBA_T_SIZE1 1 +#define LBA_T_SIZE4 2 +#define LBA_T_SIZE8 4 +#define LBA_T_CRC (1 << 6) +#define LBA_T_ECC_CHECK (2 << 6) +#define LBA_T_ECC_CORRECT (3 << 6) + +struct lba_data { + void __iomem *io_base; + struct clk *clk; + int irq; + + spinlock_t lock; + int use_count; + int mode; + struct semaphore mode_lock; +#define LBA_MODE_MASK 0x0000ffff +#define LBA_FLAG_MASK 0xffff0000 +#define LBA_MODE_RST 0 +#define LBA_MODE_PNR 1 +#define LBA_MODE_BCM 2 +#define LBA_MODE_MDP 3 +#define LBA_MODE_VFP 4 +#define LBA_MODE_SUSP 5 +#define LBA_MODE_SELFPM 0x80000000 + wait_queue_head_t suspend_q; + wait_queue_head_t selfpm_q; + struct task_struct *thread; + long long last_access; + /* PNR specific */ + /* BCM specific */ + /* VFP specific */ + uint8_t pass[2]; + + /* Size of the partiotions: pages for PNP; sectors for others */ + unsigned int pnp_size; + unsigned int vfp_size; + long long mdp_size; + void *priv; + /*should be last*/ + struct gpmi_perchip_data nand[0]; + +}; + +extern struct lba_data *g_data; + +void stmp37cc_dma_print_chain(struct stmp37xx_circ_dma_chain *chain); + +int lba_blk_init(struct lba_data *data); +int lba_blk_remove(struct lba_data *data); +int lba_blk_suspend(struct platform_device *pdev, struct lba_data *data); +int lba_blk_resume(struct platform_device *pdev, struct lba_data *data); + + +int lba_core_init(struct lba_data *data); +int lba_core_remove(struct lba_data *data); +int lba_core_suspend(struct platform_device *pdev, struct lba_data *data); +int lba_core_resume(struct platform_device *pdev, struct lba_data *data); +int lba_core_lock_mode(struct lba_data *data, int mode); +int lba_core_unlock_mode(struct lba_data *data); + +int lba_write_sectors(void *priv, unsigned int sector, unsigned int count, + void *buffer, dma_addr_t handle); +int lba_read_sectors(void *priv, unsigned int sector, unsigned int count, + void *buffer, dma_addr_t handle); +void lba_protocol1_set(void *priv, uint8_t param); +uint8_t lba_protocol1_get(void *priv); +uint8_t lba_get_status1(void *priv); +uint8_t lba_get_status2(void *priv); + +uint8_t lba_get_id1(void *priv, uint8_t *ret_buffer); +uint8_t lba_get_id2(void *priv, uint8_t *); + + +int queue_cmd(void *priv, + uint8_t *cmd_buf, dma_addr_t cmd_handle, int cmd_len, + dma_addr_t data, int data_len, + struct lba_cmd *cmd_flags); + +int queue_run(void *priv); + +dma_addr_t queue_get_cmd_handle(void *priv); + +uint8_t *queue_get_cmd_ptr(void *priv); + +dma_addr_t queue_get_data_handle(void *priv); + +uint8_t *queue_get_data_ptr(void *priv); + +void queue_plug(struct lba_data *data); +void queue_release(struct lba_data *data); + + +#endif + diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 36cb6e95b465..97699ea9d65e 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -36,6 +36,7 @@ #define DRV_VERSION "1.01" #define SPI_OPLEN 1 +#define MAX_ENC_CARDS 1 #define ENC28J60_MSG_DEFAULT \ (NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK) @@ -81,6 +82,42 @@ static struct { u32 msg_enable; } debug = { -1 }; +static int random_mac; /* = 0 */ +static char *mac[MAX_ENC_CARDS]; + +static int enc28j60_get_mac(unsigned char *dev_addr, int idx) +{ + int i, r; + char *p, *item; + unsigned long v; + unsigned char sv[10]; + + if (idx < 0) + idx = 0; + if (idx > MAX_ENC_CARDS) + return false; + + if (!mac[idx]) + return false; + + item = mac[idx]; + for (i = 0; i < MAX_ADDR_LEN; i++) { + p = strchr(item, ':'); + if (!p) + sprintf(sv, "0x%s", item); + else + sprintf(sv, "0x%*.*s", p - item, p-item, item); + r = strict_strtoul(sv, 0, &v); + dev_addr[i] = v; + if (p) + item = p + 1; + else + break; + if (r < 0) + return false; + } + return true; +} /* * SPI read buffer * wait for the SPI transfer and copy received data to destination @@ -196,16 +233,32 @@ static void enc28j60_soft_reset(struct enc28j60_net *priv) */ static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr) { - if ((addr & BANK_MASK) != priv->bank) { - u8 b = (addr & BANK_MASK) >> 5; + u8 b = (addr & BANK_MASK) >> 5; + + /* These registers (EIE, EIR, ESTAT, ECON2, ECON1) + * are present in all banks, no need to switch bank + */ + if (addr >= EIE && addr <= ECON1) + return; - if (b != (ECON1_BSEL1 | ECON1_BSEL0)) + /* Clear or set each bank selection bit as needed */ + if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) { + if (b & ECON1_BSEL0) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, + ECON1_BSEL0); + else + spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, + ECON1_BSEL0); + } + if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) { + if (b & ECON1_BSEL1) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, + ECON1_BSEL1); + else spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, - ECON1_BSEL1 | ECON1_BSEL0); - if (b != 0) - spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b); - priv->bank = (addr & BANK_MASK); + ECON1_BSEL1); } + priv->bank = b; } /* @@ -930,7 +983,7 @@ static void enc28j60_hw_rx(struct net_device *ndev) if (netif_msg_rx_status(priv)) enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat); - if (!RSV_GETBIT(rxstat, RSV_RXOK)) { + if (!RSV_GETBIT(rxstat, RSV_RXOK) || len > MAX_FRAMELEN) { if (netif_msg_rx_err(priv)) dev_err(&ndev->dev, "Rx Error (%04x)\n", rxstat); ndev->stats.rx_errors++; @@ -938,6 +991,8 @@ static void enc28j60_hw_rx(struct net_device *ndev) ndev->stats.rx_crc_errors++; if (RSV_GETBIT(rxstat, RSV_LENCHECKERR)) ndev->stats.rx_frame_errors++; + if (len > MAX_FRAMELEN) + ndev->stats.rx_over_errors++; } else { skb = dev_alloc_skb(len + NET_IP_ALIGN); if (!skb) { @@ -1093,8 +1148,24 @@ static int enc28j60_rx_interrupt(struct net_device *ndev) priv->max_pk_counter); } ret = pk_counter; - while (pk_counter-- > 0) + while (pk_counter-- > 0) { + if (!priv->full_duplex) { + /* + * This works only in HALF DUPLEX mode: + * when more than 2 packets are available, start + * transmission of 11111.. frame by setting + * FCON0 (0x01) in EFLOCON + * + * This bit can be cleared either explicitly, or by + * trasmitting the packet in enc28j60_hw_tx. + */ + if (pk_counter > 2) + locked_reg_bfset(priv, EFLOCON, 0x01); + if (pk_counter == 1) + locked_reg_bfclr(priv, EFLOCON, 0x01); + } enc28j60_hw_rx(ndev); + } return ret; } @@ -1220,6 +1291,11 @@ static void enc28j60_irq_work_handler(struct work_struct *work) */ static void enc28j60_hw_tx(struct enc28j60_net *priv) { + if (!priv->tx_skb) { + enc28j60_tx_clear(priv->netdev, false); + return; + } + if (netif_msg_tx_queued(priv)) printk(KERN_DEBUG DRV_NAME ": Tx Packet Len:%d\n", priv->tx_skb->len); @@ -1523,6 +1599,7 @@ static int __devinit enc28j60_probe(struct spi_device *spi) struct net_device *dev; struct enc28j60_net *priv; int ret = 0; + int set; if (netif_msg_drv(&debug)) dev_info(&spi->dev, DRV_NAME " Ethernet driver %s loaded\n", @@ -1556,7 +1633,11 @@ static int __devinit enc28j60_probe(struct spi_device *spi) ret = -EIO; goto error_irq; } - random_ether_addr(dev->dev_addr); + + /* need a counter here, to count instances of enc28j60 devices */ + set = enc28j60_get_mac(dev->dev_addr, -1); + if (!set || random_mac) + random_ether_addr(dev->dev_addr); enc28j60_set_hw_macaddr(dev); /* Board setup must set the relevant edge trigger type; @@ -1616,6 +1697,40 @@ static int __devexit enc28j60_remove(struct spi_device *spi) return 0; } +#ifdef CONFIG_PM +static int +enc28j60_suspend(struct spi_device *spi, pm_message_t state) +{ + struct enc28j60_net *priv = dev_get_drvdata(&spi->dev); + struct net_device *net_dev = priv ? priv->netdev : NULL; + + if (net_dev && netif_running(net_dev)) { + netif_stop_queue(net_dev); + netif_device_detach(net_dev); + disable_irq(spi->irq); + } + return 0; +} + +static int +enc28j60_resume(struct spi_device *spi) +{ + struct enc28j60_net *priv = dev_get_drvdata(&spi->dev); + struct net_device *net_dev = priv ? priv->netdev : NULL; + + if (net_dev && netif_running(net_dev)) { + enable_irq(spi->irq); + netif_device_attach(net_dev); + netif_start_queue(net_dev); + schedule_work(&priv->restart_work); + } + return 0; +} +#else +#define enc28j60_resume NULL +#define enc28j60_suspend NULL +#endif + static struct spi_driver enc28j60_driver = { .driver = { .name = DRV_NAME, @@ -1623,6 +1738,8 @@ static struct spi_driver enc28j60_driver = { }, .probe = enc28j60_probe, .remove = __devexit_p(enc28j60_remove), + .suspend = enc28j60_suspend, + .resume = enc28j60_resume, }; static int __init enc28j60_init(void) @@ -1645,4 +1762,6 @@ MODULE_DESCRIPTION(DRV_NAME " ethernet driver"); MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>"); MODULE_LICENSE("GPL"); module_param_named(debug, debug.msg_enable, int, 0); +module_param(random_mac, int, 0444); +module_param_array(mac, charp, NULL, 0); MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., ffff=all)"); diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 8e0c2b47803c..f1eb6b3f9cab 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -68,4 +68,11 @@ config BATTERY_BQ27x00 help Say Y here to enable support for batteries with BQ27200(I2C) chip. +config BATTERY_STMP3XXX + tristate "Sigmatel STMP3xxx SoC battery charger driver" + depends on ARCH_STMP3XXX + help + Say Y to enable support for the battery charger state machine + for the Sigmatel STMP3xxx based SoC's. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index e8f1ecec5d8f..588e7d70f20f 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o +obj-$(CONFIG_BATTERY_STMP3XXX) += stmp37xx/ diff --git a/drivers/power/stmp37xx/Makefile b/drivers/power/stmp37xx/Makefile new file mode 100644 index 000000000000..0d4f16e78ddf --- /dev/null +++ b/drivers/power/stmp37xx/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the STMP3xxx battery charger driver +# + +obj-$(CONFIG_BATTERY_STMP3XXX) += stmp3xxx-battery.o + +stmp3xxx-battery-objs := ddi_bc_api.o ddi_bc_hw.o ddi_bc_init.o \ + ddi_bc_ramp.o ddi_bc_sm.o ddi_power_battery.o linux.o + diff --git a/drivers/power/stmp37xx/ddi_bc_api.c b/drivers/power/stmp37xx/ddi_bc_api.c new file mode 100644 index 000000000000..5fd062ec4eb9 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_api.c @@ -0,0 +1,566 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_api.c +//! \brief Contains the Battery Charger API. +//! \date 06/2005 +//! +//! This file contains Battery Charger API. +//! +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////////////////// + +#include "ddi_bc_internal.h" + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +//! This structure holds the current Battery Charger configuration. + +ddi_bc_Cfg_t g_ddi_bc_Configuration; + +extern uint32_t g_ddi_bc_u32StateTimer; +extern ddi_bc_BrokenReason_t ddi_bc_gBrokenReason; +extern bool bRestartChargeCycle; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the Battery Charger configuration. +//! +//! \fntype Function +//! +//! This function reports the Battery Charger configuration. +//! +//! Note that, if the Battery Charger has not yet been initialized, the data +//! returned by this function is unknown. +//! +//! \param[in,out] pCfg A pointer to a structure that will receive the data. +//! +//////////////////////////////////////////////////////////////////////////////// +void ddi_bc_QueryCfg(ddi_bc_Cfg_t * pCfg) +{ + + //-------------------------------------------------------------------------- + // Return the current configuration. + //-------------------------------------------------------------------------- + + *pCfg = g_ddi_bc_Configuration; + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Shut down the Battery Charger. +//! +//! \fntype Function +//! +//! This function immediately shuts down the Battery Charger hardware and +//! returns the state machine to the Uninitialized state. Use this function to +//! safely “mummify” the battery charger before retiring it from memory. +//! +//////////////////////////////////////////////////////////////////////////////// +void ddi_bc_ShutDown() +{ + + //-------------------------------------------------------------------------- + // Reset the current ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Move to the Uninitialized state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_UNINITIALIZED; + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Advances the state machine. +//! +//! \fntype Function +//! +//! This function advances the state machine. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! \retval DDI_BC_STATUS_BROKEN If the battery violated a time-out +//! and has been declared broken. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_StateMachine() +{ + + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + //-------------------------------------------------------------------------- + // Execute the function for the current state. + //-------------------------------------------------------------------------- + + return (stateFunctionTable[g_ddi_bc_State] ()); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Get the Battery Charger's current state. +//! +//! \fntype Function +//! +//! This function returns the current state. +//! +//! \retval The current state. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_State_t ddi_bc_GetState() +{ + //-------------------------------------------------------------------------- + // Return the current state. + //-------------------------------------------------------------------------- + + return (g_ddi_bc_State); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Disable the Battery Charger. +//! +//! \fntype Function +//! +//! This function forces the Battery Charger into the Disabled state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_SetDisable() +{ + + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_BROKEN) { + return (DDI_BC_STATUS_BROKEN); + } + //-------------------------------------------------------------------------- + // Reset the current ramp. This will jam the current to zero and power off + // the charging hardware. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Move to the Disabled state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_DISABLED; + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Enable the Battery Charger. +//! +//! \fntype Function +//! +//! If the Battery Charger is in the Disabled state, this function moves it to +//! the Waiting to Charge state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! \retval DDI_BC_STATUS_NOT_DISABLED If the Battery Charger is not +//! disabled. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_SetEnable() +{ + + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + //-------------------------------------------------------------------------- + // If we're not in the Disabled state, this is pointless. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State != DDI_BC_STATE_DISABLED) { + return (DDI_BC_STATUS_NOT_DISABLED); + } + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + //-------------------------------------------------------------------------- + // Move to the Waiting to Charge state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_WAITING_TO_CHARGE; + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Declare the battery to be broken. +//! +//! \fntype Function +//! +//! This function forces the Battery Charger into the Broken state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_SetBroken() +{ + + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + //-------------------------------------------------------------------------- + // Reset the current ramp. This will jam the current to zero and power off + // the charging hardware. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Move to the Broken state. + //-------------------------------------------------------------------------- + + ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT; + + g_ddi_bc_State = DDI_BC_STATE_BROKEN; + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Declare the battery to be fixed. +//! +//! \fntype Function +//! +//! If the Battery Charger is in the Broken state, this function moves it to +//! the Disabled state. +//! +//! \retval DDI_BC_STATUS_SUCCESS If all goes well +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! \retval DDI_BC_STATUS_NOT_BROKEN If the Battery Charger is not broken. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_SetFixed() +{ + + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + //-------------------------------------------------------------------------- + // If we're not in the Broken state, this is pointless. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State != DDI_BC_STATE_BROKEN) { + return (DDI_BC_STATUS_NOT_BROKEN); + } + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Unitialize the Broken Reason + //-------------------------------------------------------------------------- + + ddi_bc_gBrokenReason = DDI_BC_BROKEN_UNINITIALIZED; + + //-------------------------------------------------------------------------- + // Move to the Disabled state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_DISABLED; + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the current limit. +//! +//! \fntype Function +//! +//! This function applies a limit to the current that the Battery Charger can +//! draw. +//! +//! \param[in] u16Limit The maximum current the Battery Charger can draw +//! (in mA). +//! +//! \retval The expressible version of the limit. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_SetCurrentLimit(uint16_t u16Limit) +{ + + //-------------------------------------------------------------------------- + // Set the limit and return what is actually expressible. + //-------------------------------------------------------------------------- + + return (ddi_bc_RampSetLimit(u16Limit)); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the current limit. +//! +//! \fntype Function +//! +//! This function reports the limit to the current that the Battery Charger can +//! draw. +//! +//! \retval The current limit. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_GetCurrentLimit(void) +{ + + //-------------------------------------------------------------------------- + // Set the limit and return what is actually expressible. + //-------------------------------------------------------------------------- + + return (ddi_bc_RampGetLimit()); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the battery charger state machine period. +//! +//! \fntype Function +//! +//! This function sets a new state machine period. The Period and Slope should +//! be coordinated to achieve the minimal ramp step current which will minimize +//! transients on the system. +//! +//! \param[in] u32StateMachinePeriod (in milliseconds) +//! \param[in] u16CurrentRampSlope (in mA/s) +//! +//! \retval SUCCESS If all goes well +//! \retval ERROR_DDI_BCM_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_SetNewPeriodAndSlope(uint32_t u32StateMachinePeriod, + uint16_t u16CurrentRampSlope) +{ + //-------------------------------------------------------------------------- + // Check if we've been initialized yet. + //-------------------------------------------------------------------------- + bool bDisableRequired; + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + + if (g_ddi_bc_State == DDI_BC_STATE_DISABLED) + bDisableRequired = false; + else { + bDisableRequired = true; + ddi_bc_SetDisable(); + } + + // Looking at the code, changing the period while the battery charger is running + // doesn't seem to have a negative affect. One could wrap this in the mutex + // or implement further coordination if it did. + g_ddi_bc_Configuration.u32StateMachinePeriod = u32StateMachinePeriod; + g_ddi_bc_Configuration.u16CurrentRampSlope = u16CurrentRampSlope; + + if (bDisableRequired) + ddi_bc_SetEnable(); + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the state machine period. +//! +//! \fntype Function +//! +//! This function reports the battery charger period. +//! +//! \retval The battery charger period (in milliseconds). +//! +//////////////////////////////////////////////////////////////////////////////// +uint32_t ddi_bc_GetStateMachinePeriod() +{ + return (g_ddi_bc_Configuration.u32StateMachinePeriod); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the current ramp slope. +//! +//! \fntype Function +//! +//! This function reports the current ramp slope. +//! +//! \retval The current ramp slope (in mA/s). +//! +//////////////////////////////////////////////////////////////////////////////// +uint32_t ddi_bc_GetCurrentRampSlope() +{ + return (g_ddi_bc_Configuration.u16CurrentRampSlope); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the time spent in the present state (milliseconds) +//! +//! \fntype Function +//! +//! This function reports the time spent in the present charging state. Note that +//! for the states that actually charge the battery, this time does not include the +//! time spent under alarm conditions such as die termperature alarm or battery +//! temperature alarm. +//! +//! \retval The time spent in the current state in milliseconds. +//! +//////////////////////////////////////////////////////////////////////////////// +uint32_t ddi_bc_GetStateTime(void) +{ + return g_ddi_bc_u32StateTimer; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the reason for being in the broken state +//! +//! \fntype Function +//! +//! +//! \retval ddi_bc_BrokenReason_t enumeration +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_BrokenReason_t ddi_bc_GetBrokenReason(void) +{ + return ddi_bc_gBrokenReason; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Restart the charge cycle +//! +//! \fntype Function +//! +//! +//! \retval SUCCESS +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_ForceChargingToStart(void) +{ + static int16_t restarts = 0; + + if (restarts < DDI_BC_MAX_RESTART_CYCLES) { + restarts++; + bRestartChargeCycle = true; + } + + return (DDI_BC_STATUS_SUCCESS); +} + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_hw.c b/drivers/power/stmp37xx/ddi_bc_hw.c new file mode 100644 index 000000000000..fab82a738b01 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_hw.c @@ -0,0 +1,474 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "ddi_bc_internal.h" + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_hw.c +//! \brief Contains the Battery Charger hardware operations. +//! \date 06/2005 +//! +//! This file contains Battery Charger hardware operations. +//! +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Includes and external references +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report if the battery charging hardware is available. +//! +//! \fntype Function +//! +//! This function reports if the battery charging hardware is available by +//! reading the corresponding laser fuse bit. +//! +//! \retval Zero if the battery charging hardware is not available. Non-zero +//! otherwise. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_hwBatteryChargerIsEnabled(void) +{ + //TODO: replace ddi_bc_hwBatteryChargerIsEnabled with the function below in the code + return (int)ddi_power_GetBatteryChargerEnabled(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the battery configuration. +//! +//! \fntype Function +//! +//! This function reports the hardware battery configuration. +//! +//! \retval A value that indicates the battery configuration. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_BatteryMode_t ddi_bc_hwGetBatteryMode(void) +{ + //TODO: replace ddi_bc_hwGetBatteryMode() with the function below. + return (ddi_bc_BatteryMode_t) ddi_power_GetBatteryMode(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the bias current source. +//! +//! \fntype Function +//! +//! This function Battery Charger. +//! +//! \retval A value that indicates the current bias current source. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_BiasCurrentSource_t ddi_bc_hwGetBiasCurrentSource(void) +{ + // TODO: replace ddi_bc_BiasCurrentSource_t() with the function below. + return (ddi_bc_BiasCurrentSource_t) ddi_power_GetBiasCurrentSource(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Sets the bias current source. +//! +//! \fntype Function +//! +//! This function sets the bias current source used by the battery charger +//! hardware. The battery charger is usually configured to use an externally +//! generated bias current, which is expected to be quite precise. To reduce +//! component count, for example, it can be configured to generate a lesser- +//! quality bias current internally. +//! +//! \param[in] source Indicates the source of the bias current. +//! +//! \retval DDI_BC_STATUS_SUCCESS If the operation succeeded. +//! \retval DDI_BC_STATUS_BAD_ARGUMENT If the given source argument isn't one +//! of the expected values. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_hwSetBiasCurrentSource(ddi_bc_BiasCurrentSource_t source) +{ + ddi_power_BiasCurrentSource_t eSource = + (ddi_power_BiasCurrentSource_t) source; + + //-------------------------------------------------------------------------- + // In the following code, there are two points that can be confusing. Both + // of these problems derive from silliness in the data sheet. + // + // The field of interest here is HW_POWER_BATTCHRG.USE_EXTERN_R. This is + // poorly named for two reasons: + // + // 1) What we're really doing is selecting the source of the bias current. + // If the application chooses to use an external bias current, then + // there will, of course, be a resistor involved (apparently, a good- + // quality one at about 620 Ohms). + // + // 2) If the bit is SET, that tells the hardware to use the INTERNAL bias + // current. If this bit is CLEAR, that tells the hardware to use the + // EXTERNAL bias current. Thus, the actual logic for this bit is + // reversed from the sense indicated by its name. + //-------------------------------------------------------------------------- + + // TODO: replace all ddi_bc_hwSetBiasCurrentSource() with function below. + return (ddi_bc_Status_t) ddi_power_SetBiasCurrentSource(eSource); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the voltage across the battery. +//! +//! \fntype Function +//! +//! This function reports the voltage across the battery. +//! +//! \retval The voltage across the battery, in mV. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwGetBatteryVoltage(void) +{ + //TODO: replace ddi_bc_hwGetBattery with function below + return ddi_power_GetBattery(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report on the presence of the power supply. +//! +//! \fntype Function +//! +//! This function repots on whether or not the 5V power supply is present. +//! +//! \retval Zero if the power supply is not present. Non-zero otherwise. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_hwPowerSupplyIsPresent(void) +{ + // TODO: replace ddi_bc_hwPowerSupplyIsPresent with the functino below. + return (int)ddi_power_Get5vPresentFlag(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the maximum charging current. +//! +//! \fntype Function +//! +//! This function reports the maximum charging current that will be offered to +//! the battery, as currently set in the hardware. +//! +//! \retval The maximum current setting in the hardware. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwGetMaxCurrent(void) +{ + // TODO: replace ddi_bc_hwGetMaxCurrent() with the below function + return (uint16_t) ddi_power_GetMaxBatteryChargeCurrent(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the maximum charging current. +//! +//! \fntype Function +//! +//! This function sets the maximum charging current that will be offered to the +//! battery. +//! +//! Note that the hardware has a minimum resolution of 10mA and a maximum +//! expressible value of 780mA (see the data sheet for details). If the given +//! current cannot be expressed exactly, then the largest expressible smaller +//! value will be used. The return reports the actual value that was effected. +//! +//! \param[in] u16Limit The maximum charging current, in mA. +//! +//! \retval The actual value that was effected. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwSetMaxCurrent(uint16_t u16Limit) +{ + //TODO: replace ddi_bc_hwSetMaxChargeCurrent + return ddi_power_SetMaxBatteryChargeCurrent(u16Limit); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the charging current threshold. +//! +//! \fntype Function +//! +//! This function sets the charging current threshold. When the actual current +//! flow to the battery is less than this threshold, the HW_POWER_STS.CHRGSTS +//! flag is clear. +//! +//! Note that the hardware has a minimum resolution of 10mA and a maximum +//! expressible value of 180mA (see the data sheet for details). If the given +//! current cannot be expressed exactly, then the largest expressible smaller +//! value will be used. The return reports the actual value that was effected. +//! +//! \param[in] u16Threshold The charging current threshold, in mA. +//! +//! \retval The actual value that was effected. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwSetCurrentThreshold(uint16_t u16Threshold) +{ + //TODO: replace calls to ddi_bc_hwSetCurrentThreshold with the one below + return ddi_power_SetBatteryChargeCurrentThreshold(u16Threshold); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the charging current threshold. +//! +//! \fntype Function +//! +//! This function reports the charging current threshold. When the actual +//! current flow to the battery is less than this threshold, the +//! HW_POWER_STS.CHRGSTS flag is clear. +//! +//! Note that the hardware has a minimum resolution of 10mA and a maximum +//! expressible value of 180mA (see the data sheet for details). +//! +//! \retval The charging current threshold, in mA. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwGetCurrentThreshold(void) +{ + //TODO: replace calls to ddi_bc_hwGetCurrentThreshold with function below + return ddi_power_GetBatteryChargeCurrentThreshold(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report if the charger hardware power is on. +//! +//! \fntype Function +//! +//! This function reports if the charger hardware power is on. +//! +//! \retval Zero if the charger hardware is not powered. Non-zero otherwise. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_hwChargerPowerIsOn(void) +{ + + //-------------------------------------------------------------------------- + // Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD" + // stands for "power down". Thus, when the bit is set, the battery charger + // hardware is POWERED DOWN. + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // Read the register and return the result. + //-------------------------------------------------------------------------- + + //TODO: replace ddi_bc_hwChargerPowerIsOn with function below + return ddi_power_GetChargerPowered(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Turn the charging hardware on or off. +//! +//! \fntype Function +//! +//! This function turns the charging hardware on or off. +//! +//! \param[in] on Indicates whether the charging hardware should be on or off. +//! +//////////////////////////////////////////////////////////////////////////////// +void ddi_bc_hwSetChargerPower(int on) +{ + + //-------------------------------------------------------------------------- + // Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD" + // stands for "power down". Thus, when the bit is set, the battery charger + // hardware is POWERED DOWN. + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // Hit the power switch. + //-------------------------------------------------------------------------- + + //TODO: replace ddi_bc_hwSetChargerPower with functino below + ddi_power_SetChargerPowered(on); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Reports if the charging current has fallen below the threshold. +//! +//! \fntype Function +//! +//! This function reports if the charging current that the battery is accepting +//! has fallen below the threshold. +//! +//! Note that this bit is regarded by the hardware guys as very slightly +//! unreliable. They recommend that you don't believe a value of zero until +//! you've sampled it twice. +//! +//! \retval Zero if the battery is accepting less current than indicated by the +//! charging threshold. Non-zero otherwise. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_hwGetChargeStatus(void) +{ + return ddi_power_GetChargeStatus(); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report on the die temperature. +//! +//! \fntype Function +//! +//! This function reports on the die temperature. +//! +//! \param[out] pLow The low end of the temperature range. +//! \param[out] pHigh The high end of the temperature range. +//! +//////////////////////////////////////////////////////////////////////////////// +void ddi_bc_hwGetDieTemp(int16_t * pLow, int16_t * pHigh) +{ + // TODO: replace ddi_bc_hwGetDieTemp with function below + ddi_power_GetDieTemp(pLow, pHigh); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the battery temperature reading. +//! +//! \fntype Function +//! +//! This function examines the configured LRADC channel and reports the battery +//! temperature reading. +//! +//! \param[out] pReading A pointer to a variable that will receive the +//! temperature reading. +//! +//! \retval DDI_BC_STATUS_SUCCESS If the operation succeeded. +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_hwGetBatteryTemp(uint16_t * pReading) +{ + return (ddi_bc_Status_t)DDI_BC_STATUS_HARDWARE_DISABLED; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Convert a current in mA to a hardware setting. +//! +//! \fntype Function +//! +//! This function converts a current measurement in mA to a hardware setting +//! used by HW_POWER_BATTCHRG.STOP_ILIMIT or HW_POWER_BATTCHRG.BATTCHRG_I. +//! +//! Note that the hardware has a minimum resolution of 10mA and a maximum +//! expressible value of 780mA (see the data sheet for details). If the given +//! current cannot be expressed exactly, then the largest expressible smaller +//! value will be used. +//! +//! \param[in] u16Current The current of interest. +//! +//! \retval The corresponding setting. +//! +//////////////////////////////////////////////////////////////////////////////// +uint8_t ddi_bc_hwCurrentToSetting(uint16_t u16Current) +{ + return ddi_power_convert_current_to_setting(u16Current); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Convert a hardware current setting to a value in mA. +//! +//! \fntype Function +//! +//! This function converts a setting used by HW_POWER_BATTCHRG.STOP_ILIMIT or +//! HW_POWER_BATTCHRG.BATTCHRG_I into an actual current measurement in mA. +//! +//! Note that the hardware current fields are 6 bits wide. The higher bits in +//! the 8-bit input parameter are ignored. +//! +//! \param[in] u8Setting A hardware current setting. +//! +//! \retval The corresponding current in mA. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwSettingToCurrent(uint8_t u8Setting) +{ + return ddi_power_convert_setting_to_current(u8Setting); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Compute the actual current expressible in the hardware. +//! +//! \fntype Function +//! +//! Given a desired current, this function computes the actual current +//! expressible in the hardware. +//! +//! Note that the hardware has a minimum resolution of 10mA and a maximum +//! expressible value of 780mA (see the data sheet for details). If the given +//! current cannot be expressed exactly, then the largest expressible smaller +//! value will be used. +//! +//! \param[in] u16Current The current of interest. +//! +//! \retval The corresponding current in mA. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_hwExpressibleCurrent(uint16_t u16Current) +{ + //TODO: replace the bc function with this one + return ddi_power_ExpressibleCurrent(u16Current); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Checks to see if the DCDC has been manually enabled +//! +//! \fntype Function +//! +//! \retval true if DCDC is ON, false if DCDC is OFF. +//! +//////////////////////////////////////////////////////////////////////////////// +bool ddi_bc_hwIsDcdcOn(void) +{ + return ddi_power_IsDcdcOn(); +} + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_hw.h b/drivers/power/stmp37xx/ddi_bc_hw.h new file mode 100644 index 000000000000..68ef98aa4303 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_hw.h @@ -0,0 +1,93 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_hw.h +//! \brief Internal header file for Battery Charger hardware operations. +//! \date 06/2005 +//! +//! This file contains internal declarations for Battery Charger hardware +//! operations. +//! +//! \see ddi_bc.c and related files. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _DDI_BC_HW_H +#define _DDI_BC_HW_H + +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +//! The enumeration of battery modes. + +typedef enum _ddi_bc_BatteryMode { + DDI_BC_BATTERY_MODE_LI_ION_2_CELLS = 0, + DDI_BC_BATTERY_MODE_LI_ION_1_CELL = 1, + DDI_BC_BATTERY_MODE_2_CELLS = 2, + DDI_BC_BATTERY_MODE_1_CELL = 3 +} ddi_bc_BatteryMode_t; + +//! The enumeration of bias current sources. + +typedef enum _ddi_bc_BiasCurrentSource { + DDI_BC_EXTERNAL_BIAS_CURRENT = 0, + DDI_BC_INTERNAL_BIAS_CURRENT = 1, +} ddi_bc_BiasCurrentSource_t; + +//////////////////////////////////////////////////////////////////////////////// +// Prototypes +//////////////////////////////////////////////////////////////////////////////// + +extern int ddi_bc_hwBatteryChargerIsEnabled(void); +extern ddi_bc_BatteryMode_t ddi_bc_hwGetBatteryMode(void); +extern ddi_bc_BiasCurrentSource_t ddi_bc_hwGetBiasCurrentSource(void); +extern ddi_bc_Status_t +ddi_bc_hwSetBiasCurrentSource(ddi_bc_BiasCurrentSource_t); +extern ddi_bc_Status_t ddi_bc_hwSetChargingVoltage(uint16_t); +extern uint16_t ddi_bc_hwGetBatteryVoltage(void); +extern int ddi_bc_hwPowerSupplyIsPresent(void); +extern uint16_t ddi_bc_hwSetMaxCurrent(uint16_t); +extern uint16_t ddi_bc_hwGetMaxCurrent(void); +extern uint16_t ddi_bc_hwSetCurrentThreshold(uint16_t); +extern uint16_t ddi_bc_hwGetCurrentThreshold(void); +extern int ddi_bc_hwChargerPowerIsOn(void); +extern void ddi_bc_hwSetChargerPower(int); +extern int ddi_bc_hwGetChargeStatus(void); +extern void ddi_bc_hwGetDieTemp(int16_t *, int16_t *); +extern ddi_bc_Status_t ddi_bc_hwGetBatteryTemp(uint16_t *); +uint8_t ddi_bc_hwCurrentToSetting(uint16_t); +uint16_t ddi_bc_hwSettingToCurrent(uint8_t); +uint16_t ddi_bc_hwExpressibleCurrent(uint16_t); + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Checks to see if the DCDC has been manually enabled +//! +//! \fntype Function +//! +//! \retval true if DCDC is ON, false if DCDC is OFF. +//! +//////////////////////////////////////////////////////////////////////////////// +bool ddi_bc_hwIsDcdcOn(void); + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +#endif // _DDI_BC_H +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_init.c b/drivers/power/stmp37xx/ddi_bc_init.c new file mode 100644 index 000000000000..ef323b33b74f --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_init.c @@ -0,0 +1,204 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include "ddi_bc_internal.h" + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_init.c +//! \brief Contains the Battery Charger initialization function. +//! \date 06/2005 +//! +//! This file contains Battery Charger initialization function. +//! +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Includes and external references +//////////////////////////////////////////////////////////////////////////////// +#include <mach/ddi_bc.h> +#include "ddi_bc_internal.h" + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! \brief Initialize the Battery Charger. +//! +//! \fntype Function +//! +//! This function initializes the Battery Charger. +//! +//! \param[in] pCfg A pointer to the new configuration. +//! +//! \retval DDI_BC_STATUS_SUCCESS +//! If the operation succeeded. +//! \retval DDI_BC_STATUS_ALREADY_INITIALIZED +//! If the Battery Charger is already initialized. +//! \retval DDI_BC_STATUS_HARDWARE_DISABLED +//! If the Battery Charger hardware is disabled by a laser fuse. +//! \retval DDI_BC_STATUS_BAD_BATTERY_MODE +//! If the power supply is set up for a non-rechargeable battery. +//! \retval DDI_BC_STATUS_CLOCK_GATE_CLOSED +//! If the clock gate for the power supply registers is closed. +//! \retval DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE +//! If the charging voltage is not either 4100 or 4200. +//! \retval DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL +//! If the LRADC channel number for monitoring battery temperature +//! is bad. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_Init(ddi_bc_Cfg_t * pCfg) +{ + + //-------------------------------------------------------------------------- + // We can only be initialized if we're in the Uninitialized state. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State != DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_ALREADY_INITIALIZED); + } + //-------------------------------------------------------------------------- + // Check if the battery charger hardware has been disabled by laser fuse. + //-------------------------------------------------------------------------- + + if (!ddi_power_GetBatteryChargerEnabled()) + return (DDI_BC_STATUS_HARDWARE_DISABLED); + + //-------------------------------------------------------------------------- + // Check if the power supply has been set up for a non-rechargeable battery. + //-------------------------------------------------------------------------- + + switch (ddi_power_GetBatteryMode()) { + + case DDI_POWER_BATT_MODE_LIION: + break; + + // TODO: we'll need to do NiMH also + default: + return (DDI_BC_STATUS_BAD_BATTERY_MODE); + //break; + + } + + //-------------------------------------------------------------------------- + // Make sure that the clock gate has been opened for the power supply + // registers. If not, then none of our writes to those registers will + // succeed, which will kind of slow us down... + //-------------------------------------------------------------------------- + + if (ddi_power_GetPowerClkGate()) { + return (DDI_BC_STATUS_CLOCK_GATE_CLOSED); + } + //-------------------------------------------------------------------------- + // Check the incoming configuration for nonsense. + //-------------------------------------------------------------------------- + + // + // Only permitted charging voltage: 4200mV. + // + + if (pCfg->u16ChargingVoltage != DDI_BC_LIION_CHARGING_VOLTAGE) { + return (DDI_BC_STATUS_CFG_BAD_CHARGING_VOLTAGE); + } + // + // There are 8 LRADC channels. + // + + if (pCfg->u8BatteryTempChannel > 7) { + return (DDI_BC_STATUS_CFG_BAD_BATTERY_TEMP_CHANNEL); + } + //-------------------------------------------------------------------------- + // Accept the configuration. + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // ddi_bc_Cfg_t.u16ChargingThresholdCurrent is destined for the + // register field HW_POWER_BATTCHRG.STOP_ILIMIT. This 4-bit field + // is unevenly quantized to provide a useful range of currents. A + // side effect of the quantization is that the field can only be + // set to certain unevenly-spaced values. + // + // Here, we use the two functions that manipulate the register field + // to adjust u16ChargingThresholdCurrent to match the quantized value. + //-------------------------------------------------------------------------- + pCfg->u16ChargingThresholdCurrent = + ddi_power_ExpressibleCurrent(pCfg->u16ChargingThresholdCurrent); + + //-------------------------------------------------------------------------- + // ...similar situation with ddi_bc_Cfg_t.u16BatteryTempSafeCurrent and + // u16DieTempSafeCurrent. + //-------------------------------------------------------------------------- + pCfg->u16BatteryTempSafeCurrent = + ddi_power_ExpressibleCurrent(pCfg->u16BatteryTempSafeCurrent); + pCfg->u16DieTempSafeCurrent = + ddi_power_ExpressibleCurrent(pCfg->u16DieTempSafeCurrent); + + g_ddi_bc_Configuration = *pCfg; + + //-------------------------------------------------------------------------- + // Set the bias current source. + //-------------------------------------------------------------------------- + + { + ddi_power_BiasCurrentSource_t Flag; + + Flag = + g_ddi_bc_Configuration.useInternalBias ? + DDI_POWER_INTERNAL_BIAS_CURRENT : + DDI_POWER_EXTERNAL_BIAS_CURRENT; + + ddi_power_SetBiasCurrentSource(Flag); + + } + + //-------------------------------------------------------------------------- + // Turn the charger hardware off. This is a very important initial condition + // because we only flip the power switch on the hardware when we make + // transitions. Baseline, it needs to be off. + //-------------------------------------------------------------------------- + + ddi_power_SetChargerPowered(0); + + //-------------------------------------------------------------------------- + // Reset the current ramp. This will jam the current to zero and power off + // the charging hardware. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Move to the Disabled state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_DISABLED; + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("%s: success\n", __func__); +#endif + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_internal.h b/drivers/power/stmp37xx/ddi_bc_internal.h new file mode 100644 index 000000000000..c1fb1b20f271 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_internal.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_internal.h +//! \brief Internal header file for the Battery Charger device driver. +//! \date 06/2005 +//! +//! This file contains internal declarations for the Battery Charger device +//! driver. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _DDI_BC_INTERNAL_H +#define _DDI_BC_INTERNAL_H + +//////////////////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////////////////// + +#include <mach/ddi_bc.h> +#include "ddi_bc_hw.h" +#include "ddi_bc_ramp.h" +#include "ddi_bc_sm.h" +#include "ddi_power_battery.h" + +//////////////////////////////////////////////////////////////////////////////// +// Externs +//////////////////////////////////////////////////////////////////////////////// + +extern bool g_ddi_bc_Configured; +extern ddi_bc_Cfg_t g_ddi_bc_Configuration; + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +#endif // _DDI_BC_H +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_ramp.c b/drivers/power/stmp37xx/ddi_bc_ramp.c new file mode 100644 index 000000000000..1de3a53259f8 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_ramp.c @@ -0,0 +1,724 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_ramp.c +//! \brief Contains the Battery Charger current ramp controller. +//! \date 06/2005 +//! +//! This file contains Battery Charger current ramp controller. +//! +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Includes and external references +//////////////////////////////////////////////////////////////////////////////// + +#include <mach/ddi_bc.h> +#include "ddi_bc_internal.h" + +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +//! This is the control structure for the current ramp. + +typedef struct _ddi_bc_RampControl { + + uint32_t u32AccumulatedTime; + + //!< The accumulated time since we last changed the actual + //!< current setting in the hardware. If the time between + //!< steps is quite short, we may have to wait for several steps + //!< before we can actually change the hardware setting. + + uint16_t u16Target; + + //!< The target current, regardless of expressibility. + + uint16_t u16Limit; + + //!< The current limit, regardless of expressibility. + + uint8_t dieTempAlarm:1; + + //!< Indicates if we are operating under a die temperature + //!< alarm. + + uint8_t batteryTempAlarm:1; + + //!< Indicates if we are operating under a battery temperature + //!< alarm. + + uint8_t ambientTempAlarm:1; + + //!< Indicates if we are operating under an ambient temperature + //!< alarm. + +} ddi_bc_RampControl_t; + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +//! This structure contains control information for the current ramp. + +static ddi_bc_RampControl_t g_RampControl; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Reset the current ramp. +//! +//! \fntype Function +//! +//! This function resets the current ramp. +//! +//! Note that this function does NOT reset the temperature alarms or the current +//! limit. Those can only be changed explicitly. +//! +//////////////////////////////////////////////////////////////////////////////// +void ddi_bc_RampReset() +{ + + //-------------------------------------------------------------------------- + // Reset the control structure. + //-------------------------------------------------------------------------- + + g_RampControl.u32AccumulatedTime = 0; + g_RampControl.u16Target = 0; + + //-------------------------------------------------------------------------- + // Step the ramp. Note that we don't care if this function returns an error. + // We're stepping the ramp to make sure it takes immediate effect, if + // possible. But, for example, if the Battery Charger is not yet + // initialized, it doesn't matter. + //-------------------------------------------------------------------------- + + ddi_bc_RampStep(0); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the target current. +//! +//! \fntype Function +//! +//! This function sets the target current and implements it immediately. +//! +//! Note that this function does NOT reset the temperature alarms. Those can +//! only be reset explicitly. +//! +//! \param[in] u16Target The target current. +//! +//! \retval The expressible version of the target. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_RampSetTarget(uint16_t u16Target) +{ + + //-------------------------------------------------------------------------- + // Set the target. + //-------------------------------------------------------------------------- + + g_RampControl.u16Target = u16Target; + + //-------------------------------------------------------------------------- + // Step the ramp. Note that we don't care if this function returns an error. + // We're stepping the ramp to make sure it takes immediate effect, if + // possible. But, for example, if the Battery Charger is not yet + // initialized, it doesn't matter. + //-------------------------------------------------------------------------- + + ddi_bc_RampStep(0); + + //-------------------------------------------------------------------------- + // Compute and return the expressible target. + //-------------------------------------------------------------------------- + + return (ddi_bc_hwExpressibleCurrent(u16Target)); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the target. +//! +//! \fntype Function +//! +//! This function reports the target. +//! +//! \retval The target. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_RampGetTarget(void) +{ + + //-------------------------------------------------------------------------- + // Return the target. + //-------------------------------------------------------------------------- + + return (g_RampControl.u16Target); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set the current limit. +//! +//! \fntype Function +//! +//! This function sets the current limit and implements it immediately. +//! +//! \param[in] u16Limit The current limit. +//! +//! \retval The expressible version of the limit. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_RampSetLimit(uint16_t u16Limit) +{ + + //-------------------------------------------------------------------------- + // Set the limit. + //-------------------------------------------------------------------------- + + g_RampControl.u16Limit = u16Limit; + + //-------------------------------------------------------------------------- + // Step the ramp. Note that we don't care if this function returns an error. + // We're stepping the ramp to make sure it takes immediate effect, if + // possible. But, for example, if the Battery Charger is not yet + // initialized, it doesn't matter. + //-------------------------------------------------------------------------- + + ddi_bc_RampStep(0); + + //-------------------------------------------------------------------------- + // Compute and return the expressible limit. + //-------------------------------------------------------------------------- + + return (ddi_bc_hwExpressibleCurrent(u16Limit)); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the current limit. +//! +//! \fntype Function +//! +//! This function reports the current limit. +//! +//! \retval The current limit. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_bc_RampGetLimit(void) +{ + + //-------------------------------------------------------------------------- + // Return the current limit. + //-------------------------------------------------------------------------- + + return (g_RampControl.u16Limit); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Update alarms. +//! +//! \fntype Function +//! +//! This function checks for all alarms and updates the current ramp +//! accordingly. +//! +//////////////////////////////////////////////////////////////////////////////// +void ddi_bc_RampUpdateAlarms() +{ + + // Set to true if something changed and we need to step the ramp right away. + + int iStepTheRamp = 0; + + //-------------------------------------------------------------------------- + // Are we monitoring die temperature? + //-------------------------------------------------------------------------- + + if (g_ddi_bc_Configuration.monitorDieTemp) { + + //---------------------------------------------------------------------- + // Get the die temperature range. + //---------------------------------------------------------------------- + + int16_t i16Low; + int16_t i16High; + + ddi_bc_hwGetDieTemp(&i16Low, &i16High); + + //---------------------------------------------------------------------- + // Now we need to decide if it's time to raise or lower the alarm. The + // first question to ask is: Were we already under an alarm? + //---------------------------------------------------------------------- + + if (g_RampControl.dieTempAlarm) { + + //------------------------------------------------------------------ + // If control arrives here, we were already under an alarm. We'll + // change that if the high end of the temperature range drops below + // the low temperature mark. + //------------------------------------------------------------------ + + if (i16High < g_ddi_bc_Configuration.u8DieTempLow) { + + //-------------------------------------------------------------- + // If control arrives here, we're safe now. Drop the alarm. + //-------------------------------------------------------------- + + g_RampControl.dieTempAlarm = 0; + + iStepTheRamp = !0; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: releasing " + "die temp alarm: [%d, %d] < %d\r\n", + (int32_t) i16Low, (int32_t) i16High, + (int32_t) g_ddi_bc_Configuration. + u8DieTempLow); +#endif + + } + + } else { + + //------------------------------------------------------------------ + // If control arrives here, we were not under an alarm. We'll change + // that if the high end of the temperature range rises above the + // high temperature mark. + //------------------------------------------------------------------ + + if (i16High >= g_ddi_bc_Configuration.u8DieTempHigh) { + + //-------------------------------------------------------------- + // If control arrives here, we're running too hot. Raise the + // alarm. + //-------------------------------------------------------------- + + g_RampControl.dieTempAlarm = 1; + + iStepTheRamp = !0; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: declaring " + "die temp alarm: [%d, %d] >= %d\r\n", + (int32_t) i16Low, (int32_t) i16High, + (int32_t) g_ddi_bc_Configuration. + u8DieTempLow); +#endif + } + + } + + } + //-------------------------------------------------------------------------- + // Are we monitoring battery temperature? + //-------------------------------------------------------------------------- + + if (g_ddi_bc_Configuration.monitorBatteryTemp) { + + ddi_bc_Status_t status; + + //---------------------------------------------------------------------- + // Get the battery temperature reading. + //---------------------------------------------------------------------- + + uint16_t u16Reading; + + status = ddi_bc_hwGetBatteryTemp(&u16Reading); + + //---------------------------------------------------------------------- + // If there was a problem, then we ignore the reading. Otherwise, let's + // have a look. + //---------------------------------------------------------------------- + + if (status == DDI_BC_STATUS_SUCCESS) { + + //------------------------------------------------------------------ + // Now we need to decide if it's time to raise or lower the alarm. + // The first question to ask is: Were we already under an alarm? + //------------------------------------------------------------------ + + if (g_RampControl.batteryTempAlarm) { + + //-------------------------------------------------------------- + // If control arrives here, we were already under an alarm. + // We'll change that if the reading drops below the low mark. + //-------------------------------------------------------------- + + if (u16Reading < + g_ddi_bc_Configuration.u16BatteryTempLow) { + + //---------------------------------------------------------- + // If control arrives here, we're safe now. Drop the alarm. + //---------------------------------------------------------- + + g_RampControl.batteryTempAlarm = 0; + + iStepTheRamp = !0; + + } + + } else { + + //-------------------------------------------------------------- + // If control arrives here, we were not under an alarm. We'll + // change that if the reading rises above the high mark. + //-------------------------------------------------------------- + + if (u16Reading >= + g_ddi_bc_Configuration.u16BatteryTempHigh) { + + //---------------------------------------------------------- + // If control arrives here, we're running too hot. Raise the + // alarm. + //---------------------------------------------------------- + + g_RampControl.batteryTempAlarm = 1; + + iStepTheRamp = !0; + + } + + } + + } + + } + //-------------------------------------------------------------------------- + // Do we need to step the ramp? + //-------------------------------------------------------------------------- + + if (iStepTheRamp) + ddi_bc_RampStep(0); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Reports the state of the die temperature alarm. +//! +//! \fntype Function +//! +//! This function reports the state of the die temperature alarm. +//! +//! \retval The state of the die temperature alarm. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_RampGetDieTempAlarm(void) +{ + return (g_RampControl.dieTempAlarm); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Reports the state of the battery temperature alarm. +//! +//! \fntype Function +//! +//! This function reports the state of the battery temperature alarm. +//! +//! \retval The state of the battery temperature alarm. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_RampGetBatteryTempAlarm(void) +{ + return (g_RampControl.batteryTempAlarm); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Reports the state of the ambient temperature alarm. +//! +//! \fntype Function +//! +//! This function reports the state of the ambient temperature alarm. +//! +//! \retval The state of the ambient temperature alarm. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_bc_RampGetAmbientTempAlarm(void) +{ + return (g_RampControl.ambientTempAlarm); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Step the current ramp. +//! +//! \fntype Function +//! +//! This function steps the current ramp forward through the given amount of time. +//! +//! \param[in] u32Time The time increment to add. +//! +//! \retval DDI_BC_STATUS_SUCCESS If the operation succeeded. +//! \retval DDI_BC_STATUS_NOT_INITIALIZED If the Battery Charger is not yet +//! initialized. +//! +//////////////////////////////////////////////////////////////////////////////// +ddi_bc_Status_t ddi_bc_RampStep(uint32_t u32Time) +{ + + uint16_t u16MaxNow; + uint16_t u16Target; + uint16_t u16Cart; + int32_t i32Delta; + + //-------------------------------------------------------------------------- + // Make sure the Battery Charger is initialized. + //-------------------------------------------------------------------------- + + if (g_ddi_bc_State == DDI_BC_STATE_UNINITIALIZED) { + return (DDI_BC_STATUS_NOT_INITIALIZED); + } + //-------------------------------------------------------------------------- + // Figure out how much current the hardware is set to draw right now. + //-------------------------------------------------------------------------- + + u16MaxNow = ddi_bc_hwGetMaxCurrent(); + + //-------------------------------------------------------------------------- + // Start with the target. + //-------------------------------------------------------------------------- + + u16Target = g_RampControl.u16Target; + + //-------------------------------------------------------------------------- + // Check the target against the hard limit. + //-------------------------------------------------------------------------- + + if (u16Target > g_RampControl.u16Limit) + u16Target = g_RampControl.u16Limit; + + //-------------------------------------------------------------------------- + // Check if the die temperature alarm is active. + //-------------------------------------------------------------------------- + + if (g_RampControl.dieTempAlarm) { + + //---------------------------------------------------------------------- + // If control arrives here, we are under a die temperature alarm. Clamp + // the target current. + //---------------------------------------------------------------------- + + if (u16Target > g_ddi_bc_Configuration.u16DieTempSafeCurrent) { + u16Target = + g_ddi_bc_Configuration.u16DieTempSafeCurrent; + } + + } + //-------------------------------------------------------------------------- + // Check if the battery temperature alarm is active. + //-------------------------------------------------------------------------- + + if (g_RampControl.batteryTempAlarm) { + + //---------------------------------------------------------------------- + // If control arrives here, we are under a battery temperature alarm. + // Clamp the target current. + //---------------------------------------------------------------------- + + if (u16Target > + g_ddi_bc_Configuration.u16BatteryTempSafeCurrent) { + u16Target = + g_ddi_bc_Configuration.u16BatteryTempSafeCurrent; + } + + } + //-------------------------------------------------------------------------- + // Now we know the target current. Figure out what is actually expressible + // in the hardware. + //-------------------------------------------------------------------------- + + u16Target = ddi_bc_hwExpressibleCurrent(u16Target); + + //-------------------------------------------------------------------------- + // Compute the difference between the expressible target and what's actually + // set in the hardware right now. + //-------------------------------------------------------------------------- + + i32Delta = ((int32_t) u16Target) - ((int32_t) u16MaxNow); + + //-------------------------------------------------------------------------- + // Check if the delta is zero. + //-------------------------------------------------------------------------- + + if (i32Delta == 0) { + + //---------------------------------------------------------------------- + // If control arrives here, there is no difference between what we want + // and what's set in the hardware. + // + // Before we leave, though, we don't want to leave any accumulated time + // laying around for the next ramp up. Zero it out. + //---------------------------------------------------------------------- + + g_RampControl.u32AccumulatedTime = 0; + + //---------------------------------------------------------------------- + // Return success. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + + } + //-------------------------------------------------------------------------- + // Check if the delta is negative. + //-------------------------------------------------------------------------- + + if (i32Delta < 0) { + + //---------------------------------------------------------------------- + // If control arrives here, the new target is lower than what's + // currently set in the hardware. Since that means we're *reducing* the + // current draw, we can do it right now. Just gimme a sec here... + //---------------------------------------------------------------------- + + ddi_bc_hwSetMaxCurrent(u16Target); + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: setting max charge " + "current to: %hdmA\r\n", u16Target); +#endif + + //---------------------------------------------------------------------- + // Flip the power switch on the charging hardware according to the new + // current setting. + //---------------------------------------------------------------------- + + ddi_bc_hwSetChargerPower(u16Target != 0); + + //---------------------------------------------------------------------- + // We don't want to leave any accumulated time laying around for the + // next ramp up. Zero it out. + //---------------------------------------------------------------------- + + g_RampControl.u32AccumulatedTime = 0; + + //---------------------------------------------------------------------- + // Return success. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + + } + //-------------------------------------------------------------------------- + // If control arrives here, the target current is higher than what's set in + // the hardware right now. That means we're going to ramp it up. To do that, + // we're going to "buy" more milliamps by "spending" milliseconds of time. + // Add the time we've "banked" to the time we've been credited in this call. + //-------------------------------------------------------------------------- + + u32Time += g_RampControl.u32AccumulatedTime; + + //-------------------------------------------------------------------------- + // Now we know how much we can spend. How much current will it buy? + //-------------------------------------------------------------------------- + + u16Cart = (g_ddi_bc_Configuration.u16CurrentRampSlope * u32Time) / 1000; + + //-------------------------------------------------------------------------- + // Check how the current we can afford stacks up against the target we want. + //-------------------------------------------------------------------------- + + if ((u16MaxNow + u16Cart) < u16Target) { + + //---------------------------------------------------------------------- + // If control arrives here, we can't afford to buy all the current we + // want. Compute the maximum we can afford, and then figure out what we + // can actually express in the hardware. + //---------------------------------------------------------------------- + + u16Target = ddi_bc_hwExpressibleCurrent(u16MaxNow + u16Cart); + + //---------------------------------------------------------------------- + // Check if the result isn't actually different from what's set in the + // the hardware right now. + //---------------------------------------------------------------------- + + if (u16Target == u16MaxNow) { + + //------------------------------------------------------------------ + // If control arrives here, we are so poor that we can't yet afford + // to buy enough current to make a change in the expressible + // hardware setting. Since we didn't spend any of our time, put the + // new balance back in the bank. + //------------------------------------------------------------------ + + g_RampControl.u32AccumulatedTime = u32Time; + + //------------------------------------------------------------------ + // Leave dispiritedly. + //------------------------------------------------------------------ + + return (DDI_BC_STATUS_SUCCESS); + + } + + } + //-------------------------------------------------------------------------- + // If control arrives here, we can afford to buy enough current to get us + // all the way to the target. Set it. + //-------------------------------------------------------------------------- + + ddi_bc_hwSetMaxCurrent(u16Target); + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: setting max charge" + "current to: %hdmA\r\n", u16Target); +#endif + + //-------------------------------------------------------------------------- + // Flip the power switch on the charging hardware according to the new + // current setting. + //-------------------------------------------------------------------------- + + ddi_bc_hwSetChargerPower(u16Target != 0); + + //-------------------------------------------------------------------------- + // We're at the target, so we're finished buying current. Zero out the + // account. + //-------------------------------------------------------------------------- + + g_RampControl.u32AccumulatedTime = 0; + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_ramp.h b/drivers/power/stmp37xx/ddi_bc_ramp.h new file mode 100644 index 000000000000..5111a5496fcf --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_ramp.h @@ -0,0 +1,50 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_ramp.h +//! \brief Internal header file for Battery Charger current ramp controller. +//! \date 06/2005 +//! +//! This file contains internal declarations for Battery current ramp +//! controller. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _DDI_BC_RAMP_H +#define _DDI_BC_RAMP_H + +//////////////////////////////////////////////////////////////////////////////// +// Prototypes +//////////////////////////////////////////////////////////////////////////////// + +extern void ddi_bc_RampReset(void); +extern uint16_t ddi_bc_RampSetTarget(uint16_t); +extern uint16_t ddi_bc_RampGetTarget(void); +extern uint16_t ddi_bc_RampSetLimit(uint16_t); +extern uint16_t ddi_bc_RampGetLimit(void); +extern void ddi_bc_RampUpdateAlarms(void); +extern int ddi_bc_RampGetDieTempAlarm(void); +extern int ddi_bc_RampGetBatteryTempAlarm(void); +extern int ddi_bc_RampGetAmbientTempAlarm(void); +extern ddi_bc_Status_t ddi_bc_RampStep(uint32_t); + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +#endif // _DDI_BC_H +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_sm.c b/drivers/power/stmp37xx/ddi_bc_sm.c new file mode 100644 index 000000000000..8bd8d2cbb58b --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_sm.c @@ -0,0 +1,1122 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_sm.c +//! \brief Contains the Battery Charger state machine. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////////////////// + +#include <mach/ddi_bc.h> +#include "ddi_bc_internal.h" + +#include <linux/delay.h> + +//////////////////////////////////////////////////////////////////////////////// +// Definitions +//////////////////////////////////////////////////////////////////////////////// + +// This is the minimum time we must charge before we transition from +// the charging state to the topping off. If we reach the +// u16ChargingThresholdCurrent charge curent before then, the battery was +// already full so we can avoid the risk of charging it past .1C for +// too long. + +#define TRANSITION_TO_TOPOFF_MINIMUM_CHARGE_TIME_mS 1 * 60 * 1000 // 1 minute + +// If DCDCs are active, we can't complete the charging cycle. Once +// they are stay off for this amount of time, we will restart the +// charge cycle. +#define DCDC_INACTIVITY_TIMER_THRESHOLD 1 * 60 * 1000 // 1 minute + +//////////////////////////////////////////////////////////////////////////////// +// Variables +//////////////////////////////////////////////////////////////////////////////// + +// The current state. + +ddi_bc_State_t g_ddi_bc_State = DDI_BC_STATE_UNINITIALIZED; + +// This table contains pointers to the functions that implement states. The +// table is indexed by state. Note that it's critically important for this +// table to agree with the state enumeration in ddi_bc.h. + +static ddi_bc_Status_t ddi_bc_Uninitialized(void); +static ddi_bc_Status_t ddi_bc_Broken(void); +static ddi_bc_Status_t ddi_bc_Disabled(void); +static ddi_bc_Status_t ddi_bc_WaitingToCharge(void); +static ddi_bc_Status_t ddi_bc_Conditioning(void); +static ddi_bc_Status_t ddi_bc_Charging(void); +static ddi_bc_Status_t ddi_bc_ToppingOff(void); +static ddi_bc_Status_t ddi_bc_DcdcModeWaitingToCharge(void); + +ddi_bc_Status_t(*const (stateFunctionTable[])) (void) = { +ddi_bc_Uninitialized, + ddi_bc_Broken, + ddi_bc_Disabled, + ddi_bc_WaitingToCharge, + ddi_bc_Conditioning, + ddi_bc_Charging, ddi_bc_ToppingOff, ddi_bc_DcdcModeWaitingToCharge}; + +// Used by states that need to watch the time. +uint32_t g_ddi_bc_u32StateTimer = 0; + +// If DCDCs are active, we can't complete the charging cycle. Once +// they are stay off for this amount of time, we will restart the +// charge cycle. +static uint32_t DcdcInactityTimer = DCDC_INACTIVITY_TIMER_THRESHOLD; + +// Always attempt to charge on first 5V connection even if DCDCs are ON. +bool bRestartChargeCycle = true; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG +static uint16_t u16ExternalBatteryPowerVoltageCheck = 0; +#endif + +ddi_bc_BrokenReason_t ddi_bc_gBrokenReason = DDI_BC_BROKEN_UNINITIALIZED; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the DCDC mode Waiting to Charge state. +//! +//! \fntype Function +//! +//! This function implements the transition to the DCDC Mode Waiting +//! to Charge state. +//! +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the DCDC mode Waiting to Charge state. +//! +//! \fntype Function +//! +//! This function implements the transition to the DCDC Mode Waiting +//! to Charge state. +//! +//////////////////////////////////////////////////////////////////////////////// +static void TransitionToDcdcModeWaitingToCharge(void) +{ + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Reset the current ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Move to the Waiting to Charge state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_DCDC_MODE_WAITING_TO_CHARGE; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: now waiting to charge (DCDC Mode)\n"); +#endif + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the Waiting to Charge state. +//! +//! \fntype Function +//! +//! This function implements the transition to the Waiting to Charge state. +//! +//////////////////////////////////////////////////////////////////////////////// +static void TransitionToWaitingToCharge(void) +{ + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Reset the current ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Move to the Waiting to Charge state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_WAITING_TO_CHARGE; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: now waiting to charge\n"); +#endif + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the Conditioning state. +//! +//! \fntype Function +//! +//! This function implements the transition to the Conditioning state. +//! +//////////////////////////////////////////////////////////////////////////////// +static void TransitionToConditioning(void) +{ + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Set up the current ramp for conditioning. + //-------------------------------------------------------------------------- + + ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ConditioningCurrent); + + //-------------------------------------------------------------------------- + // Move to the Conditioning state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_CONDITIONING; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: now conditioning\n"); +#endif + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the Charging state. +//! +//! \fntype Function +//! +//! This function implements the transition to the Charging state. +//! +//////////////////////////////////////////////////////////////////////////////// +static void TransitionToCharging(void) +{ + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Set up the current ramp for charging. + //-------------------------------------------------------------------------- + + ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ChargingCurrent); + + //-------------------------------------------------------------------------- + // We'll be finished charging when the current flow drops below this level. + //-------------------------------------------------------------------------- + + ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration. + u16ChargingThresholdCurrent); + + //-------------------------------------------------------------------------- + // Move to the Charging state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_CHARGING; +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: now charging\n"); +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the Topping Off state. +//! +//! \fntype Function +//! +//! This function implements the transition to the Topping Off state. +//! +//////////////////////////////////////////////////////////////////////////////// +static void TransitionToToppingOff(void) +{ + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Set up the current ramp for topping off. + //-------------------------------------------------------------------------- + + ddi_bc_RampSetTarget(g_ddi_bc_Configuration.u16ChargingCurrent); + + //-------------------------------------------------------------------------- + // Move to the Topping Off state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_TOPPING_OFF; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: now topping off\n"); +#endif + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Transition to the Broken state. +//! +//! \fntype Function +//! +//! This function implements the transition to the Broken state. +//! +//////////////////////////////////////////////////////////////////////////////// +static void TransitionToBroken(void) +{ + + //-------------------------------------------------------------------------- + // Reset the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer = 0; + + //-------------------------------------------------------------------------- + // Reset the current ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampReset(); + + //-------------------------------------------------------------------------- + // Move to the Broken state. + //-------------------------------------------------------------------------- + + g_ddi_bc_State = DDI_BC_STATE_BROKEN; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + printk("Battery charger: declaring a broken battery\n"); +#endif + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Uninitialized state function. +//! +//! \fntype Function +//! +//! This function implements the Uninitialized state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_Uninitialized(void) +{ + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // Increment the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod; + + //-------------------------------------------------------------------------- + // The only way to leave this state is with a call to ddi_bc_Initialize. So, + // calling this state function does nothing. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Broken state function. +//! +//! \fntype Function +//! +//! This function implements the Broken state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_Broken(void) +{ + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // Increment the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod; + + //-------------------------------------------------------------------------- + // The only way to leave this state is with a call to ddi_bc_SetFixed. So, + // calling this state function does nothing. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Disabled state function. +//! +//! \fntype Function +//! +//! This function implements the Disabled state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_Disabled(void) +{ + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // Increment the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod; + + //-------------------------------------------------------------------------- + // The only way to leave this state is with a call to ddi_bc_SetEnable. So, + // calling this state function does nothing. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Waitin to Charge state function. +//! +//! \fntype Function +//! +//! This function implements the Waiting to Charge state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_DcdcModeWaitingToCharge(void) +{ + + uint16_t u16BatteryVoltage; + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // Increment the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod; + + //-------------------------------------------------------------------------- + // Check if the power supply is present. If not, we're not going anywhere. + //-------------------------------------------------------------------------- + + if (!ddi_bc_hwPowerSupplyIsPresent()) { + TransitionToCharging(); + return (DDI_BC_STATUS_SUCCESS); + } + //-------------------------------------------------------------------------- + // If control arrives here, we're connected to a power supply. Have a look + // at the battery voltage. + //-------------------------------------------------------------------------- + + u16BatteryVoltage = ddi_bc_hwGetBatteryVoltage(); + + //-------------------------------------------------------------------------- + // If topping off has not yet occurred, we do not care if DCDCs are on or not. + // If we have already topped off at least once, then we want to delay so that + // we give the battery a chance to discharge some instead of constantly topping + // it off. + //-------------------------------------------------------------------------- + + if (ddi_bc_hwIsDcdcOn()) { + + //-------------------------------------------------------------------------- + // If DCDCs have turned on, restert the DCDCInactivityTimer; + //-------------------------------------------------------------------------- + DcdcInactityTimer = 0; + + //-------------------------------------------------------------------------- + // If the battery voltage measurement is at or below the LowDcdcBatteryVoltage + // level, we should definetly start charging the battery. The + // LowDcdcBatteryVoltage value should be low enough to account for IR voltage + // drop from the battery under heavy DCDC load. + //-------------------------------------------------------------------------- + + if (u16BatteryVoltage < + g_ddi_bc_Configuration.u16LowDcdcBatteryVoltage_mv) { + bRestartChargeCycle = true; + + } else { + return (DDI_BC_STATUS_SUCCESS); + } + } else if (DcdcInactityTimer < DCDC_INACTIVITY_TIMER_THRESHOLD) { + DcdcInactityTimer += + g_ddi_bc_Configuration.u32StateMachinePeriod; + if (DcdcInactityTimer >= DCDC_INACTIVITY_TIMER_THRESHOLD) { + bRestartChargeCycle = true; + } + } + + if (bRestartChargeCycle) { + bRestartChargeCycle = false; + // start charging + if (u16BatteryVoltage < + g_ddi_bc_Configuration.u16ConditioningThresholdVoltage) { + + //---------------------------------------------------------------------- + // If control arrives here, the battery is very low and it needs to be + // conditioned. + //---------------------------------------------------------------------- + + TransitionToConditioning(); + } else { + + //---------------------------------------------------------------------- + // If control arrives here, the battery isn't too terribly low. + //---------------------------------------------------------------------- + + TransitionToCharging(); + } + + } + + return (DDI_BC_STATUS_SUCCESS); +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Waitin to Charge state function. +//! +//! \fntype Function +//! +//! This function implements the Waiting to Charge state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_WaitingToCharge(void) +{ + uint16_t u16BatteryVoltage; + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // Increment the state timer. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod; + + //-------------------------------------------------------------------------- + // Check if the power supply is present. If not, we're not going anywhere. + //-------------------------------------------------------------------------- + + if (!ddi_bc_hwPowerSupplyIsPresent()) { +#ifdef CONFIG_POWER_SUPPLY_DEBUG + u16ExternalBatteryPowerVoltageCheck = 0; +#endif + return (DDI_BC_STATUS_SUCCESS); + } + //-------------------------------------------------------------------------- + // If control arrives here, we're connected to a power supply. Have a look + // at the battery voltage. + //-------------------------------------------------------------------------- + + u16BatteryVoltage = ddi_bc_hwGetBatteryVoltage(); + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + if (u16ExternalBatteryPowerVoltageCheck) { + if ((u16ExternalBatteryPowerVoltageCheck - u16BatteryVoltage) > + 300) { + //---------------------------------------------------------------------- + // If control arrives here, battery voltage has dropped too quickly after + // the first charge cycle. We think an external voltage regulator is + // connected. If the DCDCs are on and this voltage drops too quickly, + // it will cause large droops and possible brownouts so we disable + // charging. + //---------------------------------------------------------------------- + + ddi_bc_gBrokenReason = + DDI_BC_BROKEN_EXTERNAL_BATTERY_VOLTAGE_DETECTED; + + TransitionToBroken(); + + //---------------------------------------------------------------------- + // Tell our caller the battery appears to be broken. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_BROKEN); + } else { + // reset this check + u16ExternalBatteryPowerVoltageCheck = 0; + } + + } +#endif + + //-------------------------------------------------------------------------- + // In addition to 5V, is DCDC on also? If so, swith to DCDC Mode Waiting + // to Charge state. + //-------------------------------------------------------------------------- + + if (ddi_bc_hwIsDcdcOn()) { + TransitionToDcdcModeWaitingToCharge(); + return (DDI_BC_STATUS_SUCCESS); + } + + //-------------------------------------------------------------------------- + // If the battery voltage isn't low, we don't need to be charging it. We + // use a 5% margin to decide. + //-------------------------------------------------------------------------- + + if (!bRestartChargeCycle) { + uint16_t x; + + x = u16BatteryVoltage + (u16BatteryVoltage / 20); + + if (x >= g_ddi_bc_Configuration.u16ChargingVoltage) + return (DDI_BC_STATUS_SUCCESS); + + } + + bRestartChargeCycle = false; + //-------------------------------------------------------------------------- + // If control arrives here, the battery is low. How low? + //-------------------------------------------------------------------------- + + if (u16BatteryVoltage < + g_ddi_bc_Configuration.u16ConditioningThresholdVoltage) { + + //---------------------------------------------------------------------- + // If control arrives here, the battery is very low and it needs to be + // conditioned. + //---------------------------------------------------------------------- + + TransitionToConditioning(); + + } else { + + //---------------------------------------------------------------------- + // If control arrives here, the battery isn't too terribly low. + //---------------------------------------------------------------------- + + TransitionToCharging(); + + } + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Conditioning state function. +//! +//! \fntype Function +//! +//! This function implements the Conditioning state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_Conditioning(void) +{ + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // If we're not under an alarm, increment the state timer. + //-------------------------------------------------------------------------- + + if (!ddi_bc_RampGetDieTempAlarm() && !ddi_bc_RampGetBatteryTempAlarm()) { + g_ddi_bc_u32StateTimer += + g_ddi_bc_Configuration.u32StateMachinePeriod; + } + //-------------------------------------------------------------------------- + // Check if the power supply is still around. + //-------------------------------------------------------------------------- + + if (!ddi_bc_hwPowerSupplyIsPresent()) { + + //---------------------------------------------------------------------- + // If control arrives here, the power supply has been removed. Go back + // and wait. + //---------------------------------------------------------------------- + + TransitionToWaitingToCharge(); + + //---------------------------------------------------------------------- + // Return success. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + + } + + //-------------------------------------------------------------------------- + // If control arrives here, we're still connected to a power supply. + // Check if a battery is connected. If the voltage rises to high with only + // conditioning charge current, we determine that a battery is not connected. + // If that is not the case and a battery is connected, check + // if the battery voltage indicates it still needs conditioning. + //-------------------------------------------------------------------------- + +// if (ddi_bc_hwGetBatteryVoltage() >= 3900) { + if ((ddi_bc_hwGetBatteryVoltage() > + g_ddi_bc_Configuration.u16ConditioningMaxVoltage) && + (ddi_power_GetMaxBatteryChargeCurrent() < + g_ddi_bc_Configuration.u16ConditioningCurrent)) { + //---------------------------------------------------------------------- + // If control arrives here, voltage has risen too quickly for so + // little charge being applied so their must be no battery connected. + //---------------------------------------------------------------------- + + ddi_bc_gBrokenReason = DDI_BC_BROKEN_NO_BATTERY_DETECTED; + + TransitionToBroken(); + + //---------------------------------------------------------------------- + // Tell our caller the battery appears to be broken. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_BROKEN); + + } + + if (ddi_bc_hwGetBatteryVoltage() >= + g_ddi_bc_Configuration.u16ConditioningMaxVoltage) { + + //---------------------------------------------------------------------- + // If control arrives here, this battery no longer needs conditioning. + //---------------------------------------------------------------------- + + TransitionToCharging(); + + //---------------------------------------------------------------------- + // Return success. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + + } + //-------------------------------------------------------------------------- + // Have we been in this state too long? + //-------------------------------------------------------------------------- + + if (g_ddi_bc_u32StateTimer >= + g_ddi_bc_Configuration.u32ConditioningTimeout) { + + //---------------------------------------------------------------------- + // If control arrives here, we've been here too long. + //---------------------------------------------------------------------- + + ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT; + + TransitionToBroken(); + + //---------------------------------------------------------------------- + // Tell our caller the battery appears to be broken. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_BROKEN); + + } + //-------------------------------------------------------------------------- + // If control arrives here, we're staying in this state. Step the current + // ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod); + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Charging state function. +//! +//! \fntype Function +//! +//! This function implements the Charging state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_Charging(void) +{ + + //-------------------------------------------------------------------------- + // This variable counts the number of times we've seen the charging status + // bit cleared. + //-------------------------------------------------------------------------- + + static int iStatusCount = 0; + bool bIsDcdcOn; + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // If we're not under an alarm, increment the state timer. + //-------------------------------------------------------------------------- + + if (!ddi_bc_RampGetDieTempAlarm() && !ddi_bc_RampGetBatteryTempAlarm()) { + g_ddi_bc_u32StateTimer += + g_ddi_bc_Configuration.u32StateMachinePeriod; + } + //-------------------------------------------------------------------------- + // Check if the power supply is still around. + //-------------------------------------------------------------------------- + + if (!ddi_bc_hwPowerSupplyIsPresent()) { + + //---------------------------------------------------------------------- + // If control arrives here, the power supply has been removed. Go back + // and wait. + //---------------------------------------------------------------------- + + TransitionToWaitingToCharge(); + + //---------------------------------------------------------------------- + // Return success. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + + } + //-------------------------------------------------------------------------- + // If control arrives here, we're still connected to a power supply. We need + // to decide now if the battery is still charging, or if it's nearly full. + // If it's still charging, we'll stay in this state. Otherwise, we'll move + // to the Topping Off state. + // + // Most of the time, we decide that the battery is still charging simply by + // checking if the the actual current flow is above the charging threshold + // current (as indicated by the charge status bit). However, if we're + // still ramping up to full charging current, the hardware may still be set + // to deliver an amount that's less than the threshold. In that case, the + // charging status bit would *definitely* show a low charging current, but + // that doesn't mean the battery is ready for topping off. + // + // So, in summary, we will move to the Topping Off state if both of the + // following are true: + // + // 1) The maximum current set in the hardware is greater than the charging + // threshold. + // -AND- + // 2) The actual current flow is also higher than the threshold (as + // indicated by the charge status bit). + // + //-------------------------------------------------------------------------- + + bIsDcdcOn = ddi_bc_hwIsDcdcOn(); + if (bIsDcdcOn) { + ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration. + u16DdcdModeChargingThresholdCurrent); + } else { + ddi_bc_hwSetCurrentThreshold(g_ddi_bc_Configuration. + u16ChargingThresholdCurrent); + } + + { + uint16_t u16ActualProgrammedCurrent = ddi_bc_hwGetMaxCurrent(); + + //---------------------------------------------------------------------- + // Get the Maximum current that we will ramp to. + //---------------------------------------------------------------------- + + //---------------------------------------------------------------------- + // Not all possible values are expressible by the BATTCHRG_I bitfield. + // The following coverts the max current value into the the closest hardware + // expressible bitmask equivalent. Then, it converts this back to the actual + // decimal current value that this bitmask represents. + //---------------------------------------------------------------------- + + uint16_t u16CurrentRampTarget = ddi_bc_RampGetTarget(); + + if (u16CurrentRampTarget > ddi_bc_RampGetLimit()) + u16CurrentRampTarget = ddi_bc_RampGetLimit(); + + //---------------------------------------------------------------------- + // Not all possible values are expressible by the BATTCHRG_I bitfield. + // The following coverts the max current value into the the closest hardware + // expressible bitmask equivalent. Then, it converts this back to the actual + // decimal current value that this bitmask represents. + //---------------------------------------------------------------------- + + u16CurrentRampTarget = + ddi_bc_hwExpressibleCurrent(u16CurrentRampTarget); + + //---------------------------------------------------------------------- + // We want to wait before we check the charge status bit until the ramping + // up is complete. Because the charge status bit is noisy, we want to + // disregard it until the programmed charge currint in BATTCHRG_I is well + // beyond the STOP_ILIMIT value. + //---------------------------------------------------------------------- + if ((u16ActualProgrammedCurrent >= u16CurrentRampTarget) && + !ddi_bc_hwGetChargeStatus()) { + uint8_t u8IlimitThresholdLimit; + //---------------------------------------------------------------------- + // If control arrives here, the hardware flag is telling us that the + // charging current has fallen below the threshold. We need to see this + // happen twice consecutively before we believe it. Increment the count. + //---------------------------------------------------------------------- + + iStatusCount++; + + //---------------------------------------------------------------------- + // If we are in DCDC operting mode, we only need this criteria to be true + // once before we advance to topping off. In 5V only mode, we want 10 + // consecutive times before advancing to topping off. + //---------------------------------------------------------------------- + + if (bIsDcdcOn) + u8IlimitThresholdLimit = 1; + else + u8IlimitThresholdLimit = 10; + + //---------------------------------------------------------------------- + // How many times in a row have we seen this status bit low? + //---------------------------------------------------------------------- + + if (iStatusCount >= u8IlimitThresholdLimit) { + + //------------------------------------------------------------------ + // If control arrives here, we've seen the CHRGSTS bit low too many + // times. This means it's time to move back to the waiting to charge + // state if DCDCs are present or move to the Topping Off state if + // no DCDCs are present. Because we can't measure only the current + // going to the battery when the DCDCs are active, we don't know when + // to start topping off or how long to top off. + // + // First, reset the status count for the next time we're in this + // state. + //------------------------------------------------------------------ + + iStatusCount = 0; + +#ifdef CONFIG_POWER_SUPPLY_DEBUG + u16ExternalBatteryPowerVoltageCheck = + ddi_bc_hwGetBatteryVoltage(); +#endif + + if (bIsDcdcOn) { + // We will restart the charge cycle once the DCDCs are no + // longer present. + DcdcInactityTimer = 0; + + TransitionToWaitingToCharge(); + } else if (g_ddi_bc_u32StateTimer <= + TRANSITION_TO_TOPOFF_MINIMUM_CHARGE_TIME_mS) + { + //------------------------------------------------------------------ + // If we haven't actually didn't have to charge very long + // then the battery was already full. In this case, we do + // not top off so that we do not needlessly overcharge the + // battery. + //------------------------------------------------------------------ + TransitionToWaitingToCharge(); + } else { + + //------------------------------------------------------------------ + // Move to the Topping Off state. + //------------------------------------------------------------------ + + TransitionToToppingOff(); + } + //------------------------------------------------------------------ + // Return success. + //------------------------------------------------------------------ + + return (DDI_BC_STATUS_SUCCESS); + + } + + } else { + + //---------------------------------------------------------------------- + // If control arrives here, the battery is still charging. Clear the + // status count. + //---------------------------------------------------------------------- + + iStatusCount = 0; + + } + + } + + //-------------------------------------------------------------------------- + // Have we been in this state too long? + //-------------------------------------------------------------------------- + + if (g_ddi_bc_u32StateTimer >= g_ddi_bc_Configuration.u32ChargingTimeout) { + + //---------------------------------------------------------------------- + // If control arrives here, we've been here too long. + //---------------------------------------------------------------------- + + ddi_bc_gBrokenReason = DDI_BC_BROKEN_CHARGING_TIMEOUT; + + TransitionToBroken(); + + //---------------------------------------------------------------------- + // Tell our caller the battery appears to be broken. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_BROKEN); + + } + //-------------------------------------------------------------------------- + // If control arrives here, we're staying in this state. Step the current + // ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod); + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Topping Off state function. +//! +//! \fntype Function +//! +//! This function implements the Topping Off state. +//! +//////////////////////////////////////////////////////////////////////////////// +static ddi_bc_Status_t ddi_bc_ToppingOff(void) +{ + + //-------------------------------------------------------------------------- + // The first order of business is to update alarms. + + //-------------------------------------------------------------------------- + + ddi_bc_RampUpdateAlarms(); + + //-------------------------------------------------------------------------- + // Increment the state timer. Notice that, unlike other states, we increment + // the state timer whether or not we're under an alarm. + //-------------------------------------------------------------------------- + + g_ddi_bc_u32StateTimer += g_ddi_bc_Configuration.u32StateMachinePeriod; + + //-------------------------------------------------------------------------- + // Check if the power supply is still around. + //-------------------------------------------------------------------------- + + if (!ddi_bc_hwPowerSupplyIsPresent()) { + + //---------------------------------------------------------------------- + // If control arrives here, the power supply has been removed. Go back + // and wait. + //--------------------------------------------------------------------- + + TransitionToWaitingToCharge(); + + //---------------------------------------------------------------------- + // Return success. + //---------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + + } + + //-------------------------------------------------------------------------- + // Are we done topping off? + //-------------------------------------------------------------------------- + if (g_ddi_bc_u32StateTimer >= g_ddi_bc_Configuration.u32TopOffPeriod) { + + //---------------------------------------------------------------------- + // If control arrives here, we're done topping off. + //---------------------------------------------------------------------- + + TransitionToWaitingToCharge(); + + } + //-------------------------------------------------------------------------- + // If control arrives here, we're staying in this state. Step the current + // ramp. + //-------------------------------------------------------------------------- + + ddi_bc_RampStep(g_ddi_bc_Configuration.u32StateMachinePeriod); + + //-------------------------------------------------------------------------- + // Return success. + //-------------------------------------------------------------------------- + + return (DDI_BC_STATUS_SUCCESS); + +} + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +//! @} diff --git a/drivers/power/stmp37xx/ddi_bc_sm.h b/drivers/power/stmp37xx/ddi_bc_sm.h new file mode 100644 index 000000000000..0e5fd8a1f144 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_bc_sm.h @@ -0,0 +1,46 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_bc +//! @{ +// +// Copyright (c) 2004-2005 SigmaTel, Inc. +// +//! \file ddi_bc_sm.h +//! \brief Header file for the Battery Charger state machine. +//! \date 06/2005 +//! +//! This file contains declarations for the Battery Charger state machine. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _DDI_BC_SM_H +#define _DDI_BC_SM_H + +//////////////////////////////////////////////////////////////////////////////// +// Externs +//////////////////////////////////////////////////////////////////////////////// + +//! The current state. + +extern ddi_bc_State_t g_ddi_bc_State; + +//! The state function table. + +extern ddi_bc_Status_t(*const (stateFunctionTable[])) (void); + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +#endif // _DDI_BC_H +//! @} diff --git a/drivers/power/stmp37xx/ddi_power_battery.c b/drivers/power/stmp37xx/ddi_power_battery.c new file mode 100644 index 000000000000..f1b5a81d6667 --- /dev/null +++ b/drivers/power/stmp37xx/ddi_power_battery.c @@ -0,0 +1,944 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//////////////////////////////////////////////////////////////////////////////// +//! \addtogroup ddi_power +//! @{ +// +// Copyright(C) 2005 SigmaTel, Inc. +// +//! \file ddi_power_battery.c +//! \brief Implementation file for the power driver battery charger. +//! +//////////////////////////////////////////////////////////////////////////////// +// Includes and external references +//////////////////////////////////////////////////////////////////////////////// +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <asm/processor.h> /* cpu_relax */ +#include <mach/hardware.h> +#include <mach/ddi_bc.h> +#include <mach/lradc.h> +#include <mach/regs-power.h> +#include <mach/regs-lradc.h> +#include "ddi_bc_internal.h" + +//! \brief Base voltage to start battery calculations for LiIon +#define BATT_BRWNOUT_LIION_BASE_MV 2800 +//! \brief Constant to help with determining whether to round up or +//! not during calculation +#define BATT_BRWNOUT_LIION_CEILING_OFFSET_MV 39 +//! \brief Number of mV to add if rounding up in LiIon mode +#define BATT_BRWNOUT_LIION_LEVEL_STEP_MV 40 +//! \brief Constant value to be calculated by preprocessing +#define BATT_BRWNOUT_LIION_EQN_CONST \ + (BATT_BRWNOUT_LIION_BASE_MV - BATT_BRWNOUT_LIION_CEILING_OFFSET_MV) +//! \brief Base voltage to start battery calculations for Alkaline/NiMH +#define BATT_BRWNOUT_ALKAL_BASE_MV 800 +//! \brief Constant to help with determining whether to round up or +//! not during calculation +#define BATT_BRWNOUT_ALKAL_CEILING_OFFSET_MV 19 +//! \brief Number of mV to add if rounding up in Alkaline/NiMH mode +#define BATT_BRWNOUT_ALKAL_LEVEL_STEP_MV 20 +//! \brief Constant value to be calculated by preprocessing +#define BATT_BRWNOUT_ALKAL_EQN_CONST \ + (BATT_BRWNOUT_ALKAL_BASE_MV - BATT_BRWNOUT_ALKAL_CEILING_OFFSET_MV) + +#define GAIN_CORRECTION 1012 // 1.012 + +/* NOTE: the below define is different for 37xx and 378x */ +#define VBUSVALID_THRESH_4_30V 0x4 +#define LINREG_OFFSET_STEP_BELOW 0x2 +#define BP_POWER_BATTMONITOR_BATT_VAL 16 +#define BP_POWER_CHARGE_BATTCHRG_I 0 +#define BP_POWER_CHARGE_STOP_ILIMIT 8 + +//////////////////////////////////////////////////////////////////////////////// +// Globals & Variables +//////////////////////////////////////////////////////////////////////////////// + +// FIXME +/* We cant use VBUSVALID signal for VDD5V detection, since setting in + * USB driver POWER_DEBUG.VBUSVALIDPIOLOCK bit locks the POWER_STS.VBUSVALID to + * active state for all power states (even if the 5v went away). The + * POWER_CTRL.VBUSVALID_IRQ is also affected and it's impossible to get + * valid information about 5v presence. + */ +static ddi_power_5vDetection_t DetectionMethod = DDI_POWER_5V_VDD5V_GT_VDDIO; +//static ddi_power_5vDetection_t DetectionMethod = DDI_POWER_5V_VBUSVALID; + +//////////////////////////////////////////////////////////////////////////////// +// Code +//////////////////////////////////////////////////////////////////////////////// + +#if 0 +static void dump_regs(void) +{ + printk("HW_POWER_CHARGE 0x%08x\n", HW_POWER_CHARGE_RD()); + printk("HW_POWER_STS 0x%08x\n", HW_POWER_STS_RD()); + printk("HW_POWER_BATTMONITOR 0x%08x\n", HW_POWER_BATTMONITOR_RD()); +} +#endif + +//! This array maps bit numbers to current increments, as used in the register +//! fields HW_POWER_CHARGE.STOP_ILIMIT and HW_POWER_CHARGE.BATTCHRG_I. +static const uint16_t currentPerBit[] = { 10, 20, 50, 100, 200, 400 }; + +uint16_t ddi_power_convert_current_to_setting(uint16_t u16Current) +{ + int i; + uint16_t u16Mask; + uint16_t u16Setting = 0; + + // Scan across the bit field, adding in current increments. + u16Mask = (0x1 << 5); + + for (i = 5; (i >= 0) && (u16Current > 0); i--, u16Mask >>= 1) { + if (u16Current >= currentPerBit[i]) { + u16Current -= currentPerBit[i]; + u16Setting |= u16Mask; + } + } + + // Return the result. + return(u16Setting); +} + +//////////////////////////////////////////////////////////////////////////////// +//! See hw_power.h for details. +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_convert_setting_to_current(uint16_t u16Setting) +{ + int i; + uint16_t u16Mask; + uint16_t u16Current = 0; + + // Scan across the bit field, adding in current increments. + u16Mask = (0x1 << 5); + + for (i = 5; i >= 0; i--, u16Mask >>= 1) { + if (u16Setting & u16Mask) u16Current += currentPerBit[i]; + } + + // Return the result. + return(u16Current); +} + +void ddi_power_Enable5vDetection(void) +{ + // Disable hardware power down when 5V is inserted or removed + HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_PWDN_5VBRNOUT); + + /* + * Prepare the hardware for the detection method. We used to set + * and clear the VBUSVALID_5VDETECT bit, but that is also used for + * the DCDC 5V detection. It is sufficient to just check the status + * bits to see if 5V is present. + * + * Use VBUSVALID for DCDC 5V detection. The DCDC's detection is + * different than the USB/5V detection used to switch profiles. This + * is used to determine when a handoff should occur. + */ + HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_VBUSVALID_5VDETECT); + + // Set 5V detection threshold to 4.3V for VBUSVALID. + HW_POWER_5VCTRL_SET( + BF_POWER_5VCTRL_VBUSVALID_TRSH(VBUSVALID_THRESH_4_30V)); + + // gotta set LINREG_OFFSET to STEP_BELOW according to manual + HW_POWER_VDDIOCTRL_SET( + BF_POWER_VDDIOCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + HW_POWER_VDDACTRL_SET( + BF_POWER_VDDACTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + HW_POWER_VDDDCTRL_SET( + BF_POWER_VDDDCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + + /* Clear vbusvalid interrupt flag */ +// HW_POWER_CTRL_CLR(BM_POWER_CTRL_VBUSVALID_IRQ); + HW_POWER_CTRL_CLR(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ); + /* enable vbusvalid irq */ +// HW_POWER_CTRL_SET(BM_POWER_CTRL_ENIRQ_VBUS_VALID); + HW_POWER_CTRL_SET(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO); +} + +/* + * This function prepares the hardware for a 5V-to-battery handoff. It assumes + * the current configuration is using 5V as the power source. The 5V + * interrupt will be set up for a 5V removal. + */ +void ddi_power_enable_5v_to_battery_handoff(void) +{ + /* Clear vbusvalid interrupt flag */ +// HW_POWER_CTRL_CLR(BM_POWER_CTRL_VBUSVALID_IRQ); + HW_POWER_CTRL_CLR(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ); + + /* detect 5v unplug */ +// HW_POWER_CTRL_CLR(BM_POWER_CTRL_POLARITY_VBUSVALID); + HW_POWER_CTRL_CLR(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO); + + // Enable automatic transition to DCDC + HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_DCDC_XFER); +} + +/* + * This function will handle all the power rail transitions necesarry to power + * the chip from the battery when it was previously powered from the 5V power + * source. + */ +void ddi_power_execute_5v_to_battery_handoff(void) +{ + // VDDD has different configurations depending on the battery type + // and battery level. + + // For LiIon battery, we will use the DCDC to power VDDD. + // Use LinReg offset for DCDC mode. + HW_POWER_VDDDCTRL_SET( + BF_POWER_VDDDCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + // Turn on the VDDD DCDC output and turn off the VDDD LinReg output. + HW_POWER_VDDDCTRL_CLR(BM_POWER_VDDDCTRL_DISABLE_FET); + HW_POWER_VDDDCTRL_CLR(BM_POWER_VDDDCTRL_ENABLE_LINREG); + // Make sure stepping is enabled when using DCDC. + HW_POWER_VDDDCTRL_CLR(BM_POWER_VDDDCTRL_DISABLE_STEPPING); + + // Power VDDA and VDDIO from the DCDC. + + // Use LinReg offset for DCDC mode. + HW_POWER_VDDACTRL_SET( + BF_POWER_VDDACTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + // Turn on the VDDA DCDC converter output and turn off LinReg output. + HW_POWER_VDDACTRL_CLR(BM_POWER_VDDACTRL_DISABLE_FET); + HW_POWER_VDDACTRL_CLR(BM_POWER_VDDACTRL_ENABLE_LINREG); + // Make sure stepping is enabled when using DCDC. + HW_POWER_VDDACTRL_CLR(BM_POWER_VDDACTRL_DISABLE_STEPPING); + + // Use LinReg offset for DCDC mode. + HW_POWER_VDDIOCTRL_SET( + BF_POWER_VDDIOCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + // Turn on the VDDIO DCDC output and turn on the LinReg output. + HW_POWER_VDDIOCTRL_CLR(BM_POWER_VDDIOCTRL_DISABLE_FET); + HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO); + // Make sure stepping is enabled when using DCDC. + HW_POWER_VDDIOCTRL_CLR(BM_POWER_VDDIOCTRL_DISABLE_STEPPING); +} + +/* + * This function sets up battery-to-5V handoff. The power switch from + * battery to 5V is automatic. This funtion enables the 5V present detection + * such that the 5V interrupt can be generated if it is enabled. (The interrupt + * handler can inform software the 5V present event.) To deal with noise or + * a high current, this function enables DCDC1/2 based on the battery mode. + */ +void ddi_power_enable_battery_to_5v_handoff(void) +{ + /* Clear vbusvalid interrupt flag */ +// HW_POWER_CTRL_CLR(BM_POWER_CTRL_VBUSVALID_IRQ); + HW_POWER_CTRL_CLR(BM_POWER_CTRL_VDD5V_GT_VDDIO_IRQ); + + /* detect 5v plug-in */ +// HW_POWER_CTRL_SET(BM_POWER_CTRL_POLARITY_VBUSVALID); + HW_POWER_CTRL_SET(BM_POWER_CTRL_POLARITY_VDD5V_GT_VDDIO); + + // Force current from 5V to be zero by disabling its entry source. + HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO); + + // Allow DCDC be to active when 5V is present. + HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_ENABLE_DCDC); +} + +/* This function handles the transitions on each of the power rails necessary + * to power the chip from the 5V power supply when it was previously powered + * from the battery power supply. + */ +void ddi_power_execute_battery_to_5v_handoff(void) +{ + // Disable the DCDC during 5V connections. + HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_ENABLE_DCDC); + + // Power the VDDD/VDDA/VDDIO rail from the linear regulator. The DCDC + // is ready to automatically power the chip when 5V is removed. + // Use this configuration when powering from 5V + + // Use LinReg offset for LinReg mode + HW_POWER_VDDDCTRL_SET( + BF_POWER_VDDDCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + // Turn on the VDDD LinReg and turn on the VDDD DCDC output. The + // ENABLE_DCDC must be cleared to avoid LinReg and DCDC conflict. + HW_POWER_VDDDCTRL_SET(BM_POWER_VDDDCTRL_ENABLE_LINREG); + HW_POWER_VDDDCTRL_CLR(BM_POWER_VDDDCTRL_DISABLE_FET); + // Make sure stepping is disabled when using linear regulators + HW_POWER_VDDDCTRL_SET(BM_POWER_VDDDCTRL_DISABLE_STEPPING); + + // Use LinReg offset for LinReg mode + HW_POWER_VDDACTRL_SET( + BF_POWER_VDDACTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + // Turn on the VDDA LinReg output and prepare the DCDC for transfer. + // ENABLE_DCDC must be clear to avoid DCDC and LinReg conflict. + HW_POWER_VDDACTRL_SET(BM_POWER_VDDACTRL_ENABLE_LINREG); + HW_POWER_VDDACTRL_CLR(BM_POWER_VDDACTRL_DISABLE_FET); + // Make sure stepping is disabled when using linear regulators + HW_POWER_VDDACTRL_SET(BM_POWER_VDDACTRL_DISABLE_STEPPING); + + // Use LinReg offset for LinReg mode. + HW_POWER_VDDIOCTRL_SET( + BF_POWER_VDDIOCTRL_LINREG_OFFSET(LINREG_OFFSET_STEP_BELOW)); + // Turn on the VDDIO LinReg output and prepare the VDDIO DCDC output. + // ENABLE_DCDC must be cleared to prevent DCDC and LinReg conflict. + HW_POWER_VDDIOCTRL_CLR(BM_POWER_VDDIOCTRL_DISABLE_FET); + HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_ILIMIT_EQ_ZERO); + // Make sure stepping is disabled when using DCDC. + HW_POWER_VDDIOCTRL_SET(BM_POWER_VDDIOCTRL_DISABLE_STEPPING); +} + +void ddi_power_init_handoff(void) +{ + /* + * The following settings give optimal power supply capability and + * efficiency. Extreme loads will need HALF_FETS cleared and + * possibly DOUBLE_FETS set. The below setting are probably also + * the best for alkaline mode also but more characterization is + * needed to know for sure. + */ + // Increase the RCSCALE_THRESHOLD + HW_POWER_LOOPCTRL_SET(BM_POWER_LOOPCTRL_RCSCALE_THRESH); + // Increase the RCSCALE level for quick DCDC response to dynamic load + HW_POWER_LOOPCTRL_SET(BF_POWER_LOOPCTRL_EN_RCSCALE(3)); // 8x + + // Enable half fets for increase efficiency. + HW_POWER_MINPWR_SET(BM_POWER_MINPWR_HALF_FETS); + + // enable 5v presence detection + ddi_power_Enable5vDetection(); + + if (ddi_power_Get5vPresentFlag()) + /* It's 5V mode, enable 5V-to-battery handoff */ + ddi_power_enable_5v_to_battery_handoff(); + else + /* It's battery mode, enable battery-to-5V handoff */ + ddi_power_enable_battery_to_5v_handoff(); + + // Finally enable the battery adjust + HW_POWER_BATTMONITOR_SET(BM_POWER_BATTMONITOR_EN_BATADJ); +} + +int ddi_power_init_battery(void) +{ + int ret; + + // Init LRADC channel 7 + ret = hw_lradc_init_ladder(BATTERY_VOLTAGE_CH, + LRADC_DELAY_TRIGGER_BATTERY, + 200); + if (ret) { + printk(KERN_ERR "%s: hw_lradc_init_ladder failed\n", __func__); + return ret; + } + + HW_LRADC_CONVERSION_SET(BM_LRADC_CONVERSION_AUTOMATIC); + + // Set li-ion mode + HW_LRADC_CONVERSION_SET(BF_LRADC_CONVERSION_SCALE_FACTOR(2)); + + // Turn off divide-by-two - we already have a divide-by-four + // as part of the hardware + HW_LRADC_CTRL2_CLR( + BF_LRADC_CTRL2_DIVIDE_BY_TWO(1 << BATTERY_VOLTAGE_CH)); + + HW_POWER_CHARGE_SET(BM_POWER_CHARGE_ENABLE_FAULT_DETECT); + + // kick off the trigger + hw_lradc_set_delay_trigger_kick(LRADC_DELAY_TRIGGER_BATTERY, 1); + + /* prepare handoff */ + ddi_power_init_handoff(); + + return 0; +} + +/* + * Use the the lradc7 channel dedicated for battery voltage measurement to + * get the die temperature from on-chip sensor. + */ +uint16_t MeasureInternalDieTemperature(void) +{ + uint32_t ch8Value, ch9Value; + + /* power up internal tep sensor block */ + HW_LRADC_CTRL2_CLR(BM_LRADC_CTRL2_TEMPSENSE_PWD); + + /* mux to the lradc 8th temp channel */ + HW_LRADC_CTRL4_CLR(BF_LRADC_CTRL4_LRADC7SELECT(0xF)); + HW_LRADC_CTRL4_SET(BF_LRADC_CTRL4_LRADC7SELECT(8)); + + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC7_IRQ); + HW_LRADC_CTRL0_SET(BF_LRADC_CTRL0_SCHEDULE(1 << BATTERY_VOLTAGE_CH)); + // Wait for conversion complete + while (!(HW_LRADC_CTRL1_RD() & BM_LRADC_CTRL1_LRADC7_IRQ)) + cpu_relax(); + /* Clear the interrupt flag again */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC7_IRQ); + // read temperature value and clr lradc + ch8Value = HW_LRADC_CHn_RD(BATTERY_VOLTAGE_CH) & BM_LRADC_CHn_VALUE; + HW_LRADC_CHn_CLR(BATTERY_VOLTAGE_CH, BM_LRADC_CHn_VALUE); + + /* mux to the lradc 9th temp channel */ + HW_LRADC_CTRL4_CLR(BF_LRADC_CTRL4_LRADC7SELECT(0xF)); + HW_LRADC_CTRL4_SET(BF_LRADC_CTRL4_LRADC7SELECT(9)); + + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC7_IRQ); + HW_LRADC_CTRL0_SET(BF_LRADC_CTRL0_SCHEDULE(1 << BATTERY_VOLTAGE_CH)); + // Wait for conversion complete + while (!(HW_LRADC_CTRL1_RD() & BM_LRADC_CTRL1_LRADC7_IRQ)) + cpu_relax(); + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC7_IRQ); + // read temperature value + ch9Value = HW_LRADC_CHn_RD(BATTERY_VOLTAGE_CH) & BM_LRADC_CHn_VALUE; + HW_LRADC_CHn_CLR(BATTERY_VOLTAGE_CH, BM_LRADC_CHn_VALUE); + + /* power down temp sensor block */ + HW_LRADC_CTRL2_SET(BM_LRADC_CTRL2_TEMPSENSE_PWD); + + /* mux back to the lradc 7th battery voltage channel */ + HW_LRADC_CTRL4_CLR(BF_LRADC_CTRL4_LRADC7SELECT(0xF)); + HW_LRADC_CTRL4_SET(BF_LRADC_CTRL4_LRADC7SELECT(7)); + + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC7_IRQ); + HW_LRADC_CTRL0_SET(BF_LRADC_CTRL0_SCHEDULE(1 << BATTERY_VOLTAGE_CH)); + // Wait for conversion complete + while (!(HW_LRADC_CTRL1_RD() & BM_LRADC_CTRL1_LRADC7_IRQ)) + cpu_relax(); + /* Clear the interrupt flag */ + HW_LRADC_CTRL1_CLR(BM_LRADC_CTRL1_LRADC7_IRQ); + + return (uint16_t)((ch9Value-ch8Value)*GAIN_CORRECTION/4000); +} + + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_GetBatteryMode +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +ddi_power_BatteryMode_t ddi_power_GetBatteryMode(void) +{ +#if 0 + return (HW_POWER_STS_RD() & BM_POWER_STS_MODE) ? + DDI_POWER_BATT_MODE_ALKALINE_NIMH : + DDI_POWER_BATT_MODE_LIION; +#endif + return DDI_POWER_BATT_MODE_LIION; +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_GetBatteryChargerEnabled +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +bool ddi_power_GetBatteryChargerEnabled(void) +{ +#if 0 + return (HW_POWER_STS_RD() & BM_POWER_STS_BATT_CHRG_PRESENT) ? 1 : 0; +#endif + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report if the charger hardware power is on. +//! +//! \fntype Function +//! +//! This function reports if the charger hardware power is on. +//! +//! \retval Zero if the charger hardware is not powered. Non-zero otherwise. +//! +//! Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD" +//! stands for "power down". Thus, when the bit is set, the battery charger +//! hardware is POWERED DOWN. +//////////////////////////////////////////////////////////////////////////////// +bool ddi_power_GetChargerPowered(void) +{ + return (HW_POWER_CHARGE_RD() & BM_POWER_CHARGE_PWD_BATTCHRG) ? 0 : 1; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Turn the charging hardware on or off. +//! +//! \fntype Function +//! +//! This function turns the charging hardware on or off. +//! +//! \param[in] on Indicates whether the charging hardware should be on or off. +//! +//! Note that the bit we're looking at is named PWD_BATTCHRG. The "PWD" +//! stands for "power down". Thus, when the bit is set, the battery charger +//! hardware is POWERED DOWN. +//////////////////////////////////////////////////////////////////////////////// +void ddi_power_SetChargerPowered(bool bPowerOn) +{ + // Hit the battery charge power switch. + if (bPowerOn) { + HW_POWER_CHARGE_CLR(BM_POWER_CHARGE_PWD_BATTCHRG); + HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_PWD_CHARGE_4P2); + } else { + HW_POWER_CHARGE_SET(BM_POWER_CHARGE_PWD_BATTCHRG); + HW_POWER_5VCTRL_SET(BM_POWER_5VCTRL_PWD_CHARGE_4P2); + } + +//#ifdef CONFIG_POWER_SUPPLY_DEBUG +#if 0 + printk("Battery charger: charger %s\n", bPowerOn ? "ON!" : "OFF"); + dump_regs(); +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Reports if the charging current has fallen below the threshold. +//! +//! \fntype Function +//! +//! This function reports if the charging current that the battery is accepting +//! has fallen below the threshold. +//! +//! Note that this bit is regarded by the hardware guys as very slightly +//! unreliable. They recommend that you don't believe a value of zero until +//! you've sampled it twice. +//! +//! \retval Zero if the battery is accepting less current than indicated by the +//! charging threshold. Non-zero otherwise. +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_power_GetChargeStatus(void) +{ + return (HW_POWER_STS_RD() & BM_POWER_STS_CHRGSTS) ? 1 : 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// Battery Voltage +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the voltage across the battery. +//! +//! \fntype Function +//! +//! This function reports the voltage across the battery. Should return a +//! value in range ~3000 - 4200 mV. +//! +//! \retval The voltage across the battery, in mV. +//! +//////////////////////////////////////////////////////////////////////////////// + +//! \brief Constant value for 8mV steps used in battery translation +#define BATT_VOLTAGE_8_MV 8 + +uint16_t ddi_power_GetBattery(void) +{ + uint32_t u16BattVolt; + + // Get the raw result of battery measurement + u16BattVolt = HW_POWER_BATTMONITOR_RD(); + u16BattVolt &= BM_POWER_BATTMONITOR_BATT_VAL; + u16BattVolt >>= BP_POWER_BATTMONITOR_BATT_VAL; + + // Adjust for 8-mV LSB resolution and return + u16BattVolt *= BATT_VOLTAGE_8_MV; + +//#ifdef CONFIG_POWER_SUPPLY_DEBUG +#if 0 + printk("Battery charger: %u mV\n", u16BattVolt); +#endif + + return u16BattVolt; +} + +#if 0 +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report the voltage across the battery. +//! +//! \fntype Function +//! +//! This function reports the voltage across the battery. +//! +//! \retval The voltage across the battery, in mV. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_GetBatteryBrownout(void) +{ + uint32_t u16BatteryBrownoutLevel; + + // Get battery brownout level + u16BatteryBrownoutLevel = HW_POWER_BATTMONITOR_RD(); + u16BatteryBrownoutLevel &= BM_POWER_BATTMONITOR_BRWNOUT_LVL; + u16BatteryBrownoutLevel >>= BP_POWER_BATTMONITOR_BRWNOUT_LVL; + + // Calculate battery brownout level + switch (ddi_power_GetBatteryMode()) { + case DDI_POWER_BATT_MODE_LIION: + u16BatteryBrownoutLevel *= BATT_BRWNOUT_LIION_LEVEL_STEP_MV; + u16BatteryBrownoutLevel += BATT_BRWNOUT_LIION_BASE_MV; + break; + case DDI_POWER_BATT_MODE_ALKALINE_NIMH: + u16BatteryBrownoutLevel *= BATT_BRWNOUT_ALKAL_LEVEL_STEP_MV; + u16BatteryBrownoutLevel += BATT_BRWNOUT_ALKAL_BASE_MV; + break; + default: + u16BatteryBrownoutLevel = 0; + break; + } + return u16BatteryBrownoutLevel; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Set battery brownout level +//! +//! \fntype Reentrant Function +//! +//! This function sets the battery brownout level in millivolt. It transforms the +//! input brownout value from millivolts to the hardware register bit field value +//! taking the ceiling value in the calculation. +//! +//! \param[in] u16BattBrownout_mV Battery battery brownout level in mV +//! +//! \return SUCCESS +//! +//////////////////////////////////////////////////////////////////////////////// +int ddi_power_SetBatteryBrownout(uint16_t u16BattBrownout_mV) +{ + int16_t i16BrownoutLevel; + int ret = 0; + + // Calculate battery brownout level + switch (ddi_power_GetBatteryMode()) { + case DDI_POWER_BATT_MODE_LIION: + i16BrownoutLevel = u16BattBrownout_mV - + BATT_BRWNOUT_LIION_EQN_CONST; + i16BrownoutLevel /= BATT_BRWNOUT_LIION_LEVEL_STEP_MV; + break; + case DDI_POWER_BATT_MODE_ALKALINE_NIMH: + i16BrownoutLevel = u16BattBrownout_mV - + BATT_BRWNOUT_ALKAL_EQN_CONST; + i16BrownoutLevel /= BATT_BRWNOUT_ALKAL_LEVEL_STEP_MV; + break; + default: + return -EINVAL; + } + + // Do a check to make sure nothing went wrong. + if (i16BrownoutLevel <= 0x0f) { + //Write the battery brownout level + HW_POWER_BATTMONITOR_SET( + BF_POWER_BATTMONITOR_BRWNOUT_LVL(i16BrownoutLevel)); + } else + ret = -EINVAL; + + return ret; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Currents +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_SetBiasCurrentSource +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +int ddi_power_SetBiasCurrentSource(ddi_power_BiasCurrentSource_t eSource) +{ + switch (eSource) { + case DDI_POWER_INTERNAL_BIAS_CURRENT: + HW_POWER_CHARGE_SET(BM_POWER_CHARGE_USE_EXTERN_R); + break; + case DDI_POWER_EXTERNAL_BIAS_CURRENT: + HW_POWER_CHARGE_CLR(BM_POWER_CHARGE_USE_EXTERN_R); + break; + default: + return -EINVAL; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_GetBiasCurrentSource +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +ddi_power_BiasCurrentSource_t ddi_power_GetBiasCurrentSource(void) +{ + return (HW_POWER_CHARGE_RD() & BM_POWER_CHARGE_USE_EXTERN_R) ? + DDI_POWER_INTERNAL_BIAS_CURRENT : + DDI_POWER_EXTERNAL_BIAS_CURRENT; +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_SetMaxBatteryChargeCurrent +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_SetMaxBatteryChargeCurrent(uint16_t u16MaxCur) +{ + uint32_t u16OldSetting; + uint32_t u16NewSetting; + uint32_t u16ToggleMask; + + // Get the old setting. + u16OldSetting = (HW_POWER_CHARGE_RD() & BM_POWER_CHARGE_BATTCHRG_I) >> + BP_POWER_CHARGE_BATTCHRG_I; + + // Convert the new threshold into a setting. + u16NewSetting = ddi_power_convert_current_to_setting(u16MaxCur); + + // Compute the toggle mask. + u16ToggleMask = u16OldSetting ^ u16NewSetting; + + // Write to the toggle register. + HW_POWER_CHARGE_TOG(u16ToggleMask << BP_POWER_CHARGE_BATTCHRG_I); + + // Tell the caller what current we're set at now. + return ddi_power_convert_setting_to_current(u16NewSetting); +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_GetMaxBatteryChargeCurrent +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_GetMaxBatteryChargeCurrent(void) +{ + uint32_t u8Bits; + + // Get the raw data from register + u8Bits = (HW_POWER_CHARGE_RD() & BM_POWER_CHARGE_BATTCHRG_I) >> + BP_POWER_CHARGE_BATTCHRG_I; + + // Translate raw data to current (in mA) and return it + return ddi_power_convert_setting_to_current(u8Bits); +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_GetMaxChargeCurrent +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_SetBatteryChargeCurrentThreshold(uint16_t u16Thresh) +{ + uint32_t u16OldSetting; + uint32_t u16NewSetting; + uint32_t u16ToggleMask; + + //------------------------------------------------------------------- + // See ddi_power_SetMaxBatteryChargeCurrent for an explanation of + // why we're using the toggle register here. + // + // Since this function doesn't have any major hardware effect, + // we could use the usual macros for writing to this bit field. But, + // for the sake of parallel construction and any potentially odd + // effects on the status bit, we use the toggle register in the same + // way as ddi_bc_hwSetMaxCurrent. + //------------------------------------------------------------------- + + //------------------------------------------------------------------- + // The threshold hardware can't express as large a range as the max + // current setting, but we can use the same functions as long as we + // add an extra check here. + // + // Thresholds larger than 180mA can't be expressed. + //------------------------------------------------------------------- + + if (u16Thresh > 180) + u16Thresh = 180; + + //////////////////////////////////////// + // Create the mask + //////////////////////////////////////// + + // Get the old setting. + u16OldSetting = (HW_POWER_CHARGE_RD() & BM_POWER_CHARGE_STOP_ILIMIT) >> + BP_POWER_CHARGE_STOP_ILIMIT; + + // Convert the new threshold into a setting. + u16NewSetting = ddi_power_convert_current_to_setting(u16Thresh); + + // Compute the toggle mask. + u16ToggleMask = u16OldSetting ^ u16NewSetting; + + ///////////////////////////////////////// + // Write to the register + ///////////////////////////////////////// + + // Write to the toggle register. + HW_POWER_CHARGE_TOG(BF_POWER_CHARGE_STOP_ILIMIT(u16ToggleMask)); + + // Tell the caller what current we're set at now. + return ddi_power_convert_setting_to_current(u16NewSetting); +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_GetBatteryChargeCurrentThreshold +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_GetBatteryChargeCurrentThreshold(void) +{ + uint32_t u16Threshold; + + u16Threshold = (HW_POWER_CHARGE_RD() & BM_POWER_CHARGE_STOP_ILIMIT) >> + BP_POWER_CHARGE_STOP_ILIMIT; + + return ddi_power_convert_setting_to_current(u16Threshold); +} + +//////////////////////////////////////////////////////////////////////////////// +// Conversion +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Compute the actual current expressible in the hardware. +//! +//! \fntype Function +//! +//! Given a desired current, this function computes the actual current +//! expressible in the hardware. +//! +//! Note that the hardware has a minimum resolution of 10mA and a maximum +//! expressible value of 780mA (see the data sheet for details). If the given +//! current cannot be expressed exactly, then the largest expressible smaller +//! value will be used. +//! +//! \param[in] u16Current The current of interest. +//! +//! \retval The corresponding current in mA. +//! +//////////////////////////////////////////////////////////////////////////////// +uint16_t ddi_power_ExpressibleCurrent(uint16_t u16Current) +{ + return ddi_power_convert_setting_to_current( + ddi_power_convert_current_to_setting(u16Current)); +} + +//////////////////////////////////////////////////////////////////////////////// +//! Name: ddi_power_Get5VPresent +//! +//! \brief +//////////////////////////////////////////////////////////////////////////////// +bool ddi_power_Get5vPresentFlag(void) +{ + switch (DetectionMethod) { + case DDI_POWER_5V_VBUSVALID: + // Check VBUSVALID for 5V present + return ((HW_POWER_STS_RD() & BM_POWER_STS_VBUSVALID) != 0); + case DDI_POWER_5V_VDD5V_GT_VDDIO: + // Check VDD5V_GT_VDDIO for 5V present + return ((HW_POWER_STS_RD() & BM_POWER_STS_VDD5V_GT_VDDIO) != 0); + default: + break; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Report on the die temperature. +//! +//! \fntype Function +//! +//! This function reports on the die temperature. +//! +//! \param[out] pLow The low end of the temperature range. +//! \param[out] pHigh The high end of the temperature range. +//! +//////////////////////////////////////////////////////////////////////////////// +// Temperature constant +#define TEMP_READING_ERROR_MARGIN 5 +#define KELVIN_TO_CELSIUS_CONST 273 + +void ddi_power_GetDieTemp(int16_t * pLow, int16_t * pHigh) +{ + int16_t i16High, i16Low; + uint16_t u16Reading; + + // Get the reading in Kelvins + u16Reading = MeasureInternalDieTemperature(); + + // Adjust for error margin + i16High = u16Reading + TEMP_READING_ERROR_MARGIN; + i16Low = u16Reading - TEMP_READING_ERROR_MARGIN; + + // Convert to Celsius + i16High -= KELVIN_TO_CELSIUS_CONST; + i16Low -= KELVIN_TO_CELSIUS_CONST; + +//#ifdef CONFIG_POWER_SUPPLY_DEBUG +#if 0 + printk("Battery charger: Die temp %d to %d C\n", i16Low, i16High); +#endif + // Return the results + *pHigh = i16High; + *pLow = i16Low; +} + +/////////////////////////////////////////////////////////////////////////////// +//! +//! \brief Checks to see if the DCDC has been manually enabled +//! +//! \fntype Function +//! +//! \retval true if DCDC is ON, false if DCDC is OFF. +//! +//////////////////////////////////////////////////////////////////////////////// +bool ddi_power_IsDcdcOn(void) +{ + return (HW_POWER_5VCTRL_RD() & BM_POWER_5VCTRL_ENABLE_DCDC) ? 1 : 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +//! See hw_power.h for details. +//////////////////////////////////////////////////////////////////////////////// +void ddi_power_SetPowerClkGate(bool bGate) +{ + // Gate/Ungate the clock to the power block + if (bGate) { + HW_POWER_CTRL_SET(BM_POWER_CTRL_CLKGATE); + } else { + HW_POWER_CTRL_CLR(BM_POWER_CTRL_CLKGATE); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//! See hw_power.h for details. +//////////////////////////////////////////////////////////////////////////////// +bool ddi_power_GetPowerClkGate(void) +{ + return (HW_POWER_CTRL_RD() & BM_POWER_CTRL_CLKGATE) ? 1 : 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +// End of file +//////////////////////////////////////////////////////////////////////////////// +//! @} diff --git a/drivers/power/stmp37xx/ddi_power_battery.h b/drivers/power/stmp37xx/ddi_power_battery.h new file mode 100644 index 000000000000..2d7c1a5411ad --- /dev/null +++ b/drivers/power/stmp37xx/ddi_power_battery.h @@ -0,0 +1,67 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +//! \brief Battery modes +typedef enum { + // 37xx battery modes + //! \brief LiIon battery powers the player + DDI_POWER_BATT_MODE_LIION = 0, + //! \brief Alkaline/NiMH battery powers the player + DDI_POWER_BATT_MODE_ALKALINE_NIMH = 1, +} ddi_power_BatteryMode_t; + + +//! \brief Available sources for bias currents +typedef enum { + //! \brief Use external resistor to generate bias current + DDI_POWER_EXTERNAL_BIAS_CURRENT = 0x0, + //! \brief Use internal resistor to generate bias current + DDI_POWER_INTERNAL_BIAS_CURRENT = 0x1 +} ddi_power_BiasCurrentSource_t; + +//! \brief Possible 5V detection methods +typedef enum { + //! \brief Use VBUSVALID comparator for detection + DDI_POWER_5V_VBUSVALID, + //! \brief Use VDD5V_GT_VDDIO comparison for detection + DDI_POWER_5V_VDD5V_GT_VDDIO +} ddi_power_5vDetection_t; + + +uint16_t ddi_power_convert_current_to_setting(uint16_t u16Current); +uint16_t ddi_power_convert_setting_to_current(uint16_t u16Setting); +void ddi_power_enable_5v_to_battery_handoff(void); +void ddi_power_execute_5v_to_battery_handoff(void); +void ddi_power_enable_battery_to_5v_handoff(void); +void ddi_power_execute_battery_to_5v_handoff(void); +int ddi_power_init_battery(void); +ddi_power_BatteryMode_t ddi_power_GetBatteryMode(void); +bool ddi_power_GetBatteryChargerEnabled(void); +bool ddi_power_GetChargerPowered(void); +void ddi_power_SetChargerPowered(bool bPowerOn); +int ddi_power_GetChargeStatus(void); +uint16_t ddi_power_GetBattery(void); +uint16_t ddi_power_GetBatteryBrownout(void); +int ddi_power_SetBatteryBrownout(uint16_t u16BattBrownout_mV); +int ddi_power_SetBiasCurrentSource(ddi_power_BiasCurrentSource_t eSource); +ddi_power_BiasCurrentSource_t ddi_power_GetBiasCurrentSource(void); +uint16_t ddi_power_SetMaxBatteryChargeCurrent(uint16_t u16MaxCur); +uint16_t ddi_power_GetMaxBatteryChargeCurrent(void); +uint16_t ddi_power_SetBatteryChargeCurrentThreshold(uint16_t u16Thresh); +uint16_t ddi_power_GetBatteryChargeCurrentThreshold(void); +uint16_t ddi_power_ExpressibleCurrent(uint16_t u16Current); +bool ddi_power_Get5vPresentFlag(void); +void ddi_power_GetDieTemp(int16_t * pLow, int16_t * pHigh); +bool ddi_power_IsDcdcOn(void); +void ddi_power_SetPowerClkGate(bool bGate); +bool ddi_power_GetPowerClkGate(void); diff --git a/drivers/power/stmp37xx/linux.c b/drivers/power/stmp37xx/linux.c new file mode 100644 index 000000000000..68056e523769 --- /dev/null +++ b/drivers/power/stmp37xx/linux.c @@ -0,0 +1,622 @@ +/* + * Linux glue to STMP3xxx battery state machine. + * + * Author: Steve Longerbeam <stevel@embeddedalley.com> + * + * Copyright (C) 2008 EmbeddedAlley Solutions Inc. + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/jiffies.h> +#include <linux/sched.h> +#include <mach/ddi_bc.h> +#include "ddi_bc_internal.h" +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <mach/regulator.h> +#include <mach/regs-power.h> +#include <mach/regs-usbphy.h> +#include <linux/delay.h> + +#include <linux/interrupt.h> + + +struct stmp3xxx_info { + struct device *dev; + struct regulator *regulator; + + struct power_supply bat; + struct power_supply ac; + struct power_supply usb; + + ddi_bc_Cfg_t *sm_cfg; + struct mutex sm_lock; + struct timer_list sm_timer; + struct work_struct sm_work; + struct resource *vdd5v_irq; + int is_ac_online; +#define USB_ONLINE 0x01 +#define USB_REG_SET 0x02 +#define USB_SM_RESTART 0x04 +#define USB_SHUTDOWN 0x08 +#define USB_N_SEND 0x10 + int is_usb_online; +}; + +#define to_stmp3xxx_info(x) container_of((x), struct stmp3xxx_info, bat) + +/* There is no direct way to detect wall power presence, so assume the AC + * power source is valid if 5V presents and USB device is disconnected. + * If USB device is connected then assume that AC is offline and USB power + * is online. + */ +#define is_usb_plugged()(HW_USBPHY_STATUS_RD() & \ + BM_USBPHY_STATUS_DEVPLUGIN_STATUS) +#define is_ac_online() \ + (ddi_power_Get5vPresentFlag() ? (!is_usb_plugged()) : 0) +#define is_usb_online() \ + (ddi_power_Get5vPresentFlag() ? (!!is_usb_plugged()) : 0) + +/* + * Power properties + */ +static enum power_supply_property stmp3xxx_power_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int stmp3xxx_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_MAINS) + /* ac online */ + val->intval = is_ac_online(); + else + /* usb online */ + val->intval = is_usb_online(); + break; + default: + return -EINVAL; + } + + return 0; +} +/* + * Battery properties + */ +static enum power_supply_property stmp3xxx_bat_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TEMP, +}; + +static int stmp3xxx_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct stmp3xxx_info *info = to_stmp3xxx_info(psy); + ddi_bc_State_t state; + ddi_bc_BrokenReason_t reason; + int temp_alarm; + int16_t temp_lo, temp_hi; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + state = ddi_bc_GetState(); + switch (state) { + case DDI_BC_STATE_CONDITIONING: + case DDI_BC_STATE_CHARGING: + case DDI_BC_STATE_TOPPING_OFF: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case DDI_BC_STATE_DISABLED: + val->intval = ddi_power_Get5vPresentFlag() ? + POWER_SUPPLY_STATUS_NOT_CHARGING : + POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + /* TODO: detect full */ + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + } + break; + case POWER_SUPPLY_PROP_PRESENT: + /* is battery present */ + state = ddi_bc_GetState(); + switch (state) { + case DDI_BC_STATE_WAITING_TO_CHARGE: + case DDI_BC_STATE_DCDC_MODE_WAITING_TO_CHARGE: + case DDI_BC_STATE_CONDITIONING: + case DDI_BC_STATE_CHARGING: + case DDI_BC_STATE_TOPPING_OFF: + case DDI_BC_STATE_DISABLED: + val->intval = 1; + break; + case DDI_BC_STATE_BROKEN: + val->intval = !(ddi_bc_GetBrokenReason() == + DDI_BC_BROKEN_NO_BATTERY_DETECTED); + break; + default: + val->intval = 0; + break; + } + break; + case POWER_SUPPLY_PROP_HEALTH: + temp_alarm = ddi_bc_RampGetDieTempAlarm(); + if (temp_alarm) { + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + } else { + state = ddi_bc_GetState(); + switch (state) { + case DDI_BC_STATE_BROKEN: + reason = ddi_bc_GetBrokenReason(); + val->intval = + (reason == DDI_BC_BROKEN_CHARGING_TIMEOUT) ? + POWER_SUPPLY_HEALTH_DEAD : + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + break; + case DDI_BC_STATE_UNINITIALIZED: + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + default: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + } + } + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + /* uV */ + val->intval = ddi_power_GetBattery() * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + /* uA */ + val->intval = ddi_power_GetMaxBatteryChargeCurrent() * 1000; + break; + case POWER_SUPPLY_PROP_TEMP: + mutex_lock(&info->sm_lock); + ddi_power_GetDieTemp(&temp_lo, &temp_hi); + mutex_unlock(&info->sm_lock); + val->intval = temp_lo + (temp_hi - temp_lo) / 2; + + break; + default: + return -EINVAL; + } + + return 0; +} + +static void state_machine_timer(unsigned long data) +{ + struct stmp3xxx_info *info = (struct stmp3xxx_info *)data; + ddi_bc_Cfg_t *cfg = info->sm_cfg; + int ret; + + /* schedule next call to state machine */ + mod_timer(&info->sm_timer, + jiffies + msecs_to_jiffies(cfg->u32StateMachinePeriod)); + + ret = schedule_work(&info->sm_work); + if (!ret) + dev_dbg(info->dev, "state machine failed to schedule\n"); + +} +/* + * Assumtion: + * AC power can't be switched to USB w/o system reboot + * and vice-versa + */ +static void state_machine_work(struct work_struct *work) +{ + struct stmp3xxx_info *info = + container_of(work, struct stmp3xxx_info, sm_work); + + mutex_lock(&info->sm_lock); + + if (info->is_usb_online & USB_SHUTDOWN) { + info->is_usb_online = 0; + if (!info->regulator) + goto out; + regulator_set_current_limit(info->regulator, 0, 0); + goto out; + } + + if (is_ac_online()) { + if (info->is_ac_online) + goto done; + + /* ac supply connected */ + dev_info(info->dev, "changed power connection to ac/5v \n"); + + info->is_ac_online = 1; + info->is_usb_online = 0; + ddi_bc_SetCurrentLimit(600 /*mA*/); + ddi_power_execute_battery_to_5v_handoff(); + ddi_power_enable_5v_to_battery_handoff(); + goto done; + } + + if (!is_usb_online()) + goto out; + + if (info->is_usb_online & USB_REG_SET) + goto done; + + info->is_ac_online = 0; + info->is_usb_online |= USB_ONLINE; + + if (!info->regulator) { + info->regulator = regulator_get(NULL, "charger-1"); + if (!info->regulator || IS_ERR(info->regulator)) { + dev_err(info->dev, + "%s: failed to get regulator\n", __func__); + info->regulator = NULL; + ddi_bc_SetCurrentLimit(350 /*mA*/); + ddi_power_execute_battery_to_5v_handoff(); + ddi_power_enable_5v_to_battery_handoff(); + goto done; + } else + regulator_set_mode(info->regulator, + REGULATOR_MODE_FAST); + } + + if (!(info->is_usb_online & USB_N_SEND)) { + info->is_usb_online |= USB_N_SEND; + } + + if (regulator_set_current_limit(info->regulator, 150000, 150000)) { + dev_err(info->dev, "reg_set_current(150000) failed\n"); + + ddi_bc_SetCurrentLimit(0 /*mA*/); + dev_dbg(info->dev, "charge current set to 0\n"); + mod_timer(&info->sm_timer, jiffies + msecs_to_jiffies(1000)); + goto done; + } + + dev_dbg(info->dev, "%s: charge current set to 100mA\n", __func__); + ddi_bc_SetCurrentLimit(100 /*mA*/); + regulator_set_current_limit(info->regulator, 100000, 100000); + if (info->is_usb_online & USB_SM_RESTART) { + info->is_usb_online &= ~USB_SM_RESTART; + ddi_bc_SetEnable(); + } + + info->is_usb_online |= USB_REG_SET; + + dev_info(info->dev, "changed power connection to usb/5v present\n"); + ddi_power_execute_battery_to_5v_handoff(); + ddi_power_enable_5v_to_battery_handoff(); + ddi_bc_SetEnable(); + +done: + ddi_bc_StateMachine(); +out: + mutex_unlock(&info->sm_lock); +} + +static int bc_sm_restart(struct stmp3xxx_info *info) +{ + ddi_bc_Status_t bcret; + int ret = 0; + + mutex_lock(&info->sm_lock); + + /* ungate power clk */ + ddi_power_SetPowerClkGate(0); + + /* + * config battery charger state machine and move it to the Disabled + * state. This must be done before starting the state machine. + */ + bcret = ddi_bc_Init(info->sm_cfg); + if (bcret != DDI_BC_STATUS_SUCCESS) { + dev_err(info->dev, "state machine init failed: %d\n", bcret); + ret = -EIO; + goto out; + } + + /* + * Check what power supply options we have right now. If + * we're able to do any battery charging, then set the + * appropriate current limit and enable. Otherwise, leave + * the battery charger disabled. + */ + if (is_ac_online()) { + /* ac supply connected */ + dev_info(info->dev, "ac/5v present, enabling state machine\n"); + + info->is_ac_online = 1; + info->is_usb_online = 0; + ddi_bc_SetCurrentLimit(600 /*mA*/); + ddi_bc_SetEnable(); + } else if (is_usb_online()) { + /* usb supply connected */ + dev_info(info->dev, "usb/5v present, enabling state machine\n"); + + info->is_ac_online = 0; + info->is_usb_online = USB_ONLINE | USB_SM_RESTART; + } else { + /* not powered */ + dev_info(info->dev, "%s: 5v not present\n", __func__); + + info->is_ac_online = 0; + info->is_usb_online = 0; + ddi_bc_SetDisable(); + } + + /* schedule first call to state machine */ + mod_timer(&info->sm_timer, jiffies + 1); +out: + mutex_unlock(&info->sm_lock); + return ret; +} + +static irqreturn_t stmp3xxx_vdd5v_irq(int irq, void *cookie) +{ + struct stmp3xxx_info *info = (struct stmp3xxx_info *)cookie; + + if (ddi_power_Get5vPresentFlag()) { + dev_info(info->dev, "5v present, reenable state machine\n"); + + ddi_bc_SetEnable(); + + /* + * We only ack/negate the interrupt here, + * as we can't decide yet if we really can + * switch to 5V (USB bits not ready) + */ + ddi_power_enable_5v_to_battery_handoff(); + } else { + dev_info(info->dev, "5v went away, disabling state machine\n"); + + ddi_bc_SetDisable(); + + info->is_ac_online = 0; + if (info->is_usb_online) + info->is_usb_online = USB_SHUTDOWN; + + ddi_power_execute_5v_to_battery_handoff(); + ddi_power_enable_battery_to_5v_handoff(); + mod_timer(&info->sm_timer, jiffies + 1); + + } + + return IRQ_HANDLED; +} + +static int stmp3xxx_bat_probe(struct platform_device *pdev) +{ + struct stmp3xxx_info *info; + int ret = 0; + + if (!pdev->dev.platform_data) { + printk(KERN_ERR "%s: missing platform data\n", __func__); + return -ENODEV; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->vdd5v_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (info->vdd5v_irq == NULL) { + printk(KERN_ERR "%s: failed to get irq resouce\n", __func__); + goto free_info; + } + + platform_set_drvdata(pdev, info); + + info->dev = &pdev->dev; + info->sm_cfg = pdev->dev.platform_data; + + /* initialize bat power_supply struct */ + info->bat.name = "battery"; + info->bat.type = POWER_SUPPLY_TYPE_BATTERY; + info->bat.properties = stmp3xxx_bat_props; + info->bat.num_properties = ARRAY_SIZE(stmp3xxx_bat_props); + info->bat.get_property = stmp3xxx_bat_get_property; + + /* initialize ac power_supply struct */ + info->ac.name = "ac"; + info->ac.type = POWER_SUPPLY_TYPE_MAINS; + info->ac.properties = stmp3xxx_power_props; + info->ac.num_properties = ARRAY_SIZE(stmp3xxx_power_props); + info->ac.get_property = stmp3xxx_power_get_property; + + /* initialize usb power_supply struct */ + info->usb.name = "usb"; + info->usb.type = POWER_SUPPLY_TYPE_USB; + info->usb.properties = stmp3xxx_power_props; + info->usb.num_properties = ARRAY_SIZE(stmp3xxx_power_props); + info->usb.get_property = stmp3xxx_power_get_property; + + init_timer(&info->sm_timer); + info->sm_timer.data = (unsigned long)info; + info->sm_timer.function = state_machine_timer; + + mutex_init(&info->sm_lock); + INIT_WORK(&info->sm_work, state_machine_work); + + /* init LRADC channels to measure battery voltage and die temp */ + ddi_power_init_battery(); + HW_POWER_5VCTRL_CLR(BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT); + + ret = bc_sm_restart(info); + if (ret) + goto free_info; + + ret = request_irq(info->vdd5v_irq->start, + stmp3xxx_vdd5v_irq, IRQF_DISABLED, + pdev->name, info); + if (ret) { + dev_err(info->dev, "failed to request irq\n"); + goto stop_sm; + } + + ret = power_supply_register(&pdev->dev, &info->bat); + if (ret) { + dev_err(info->dev, "failed to register battery\n"); + goto free_irq; + } + + ret = power_supply_register(&pdev->dev, &info->ac); + if (ret) { + dev_err(info->dev, "failed to register ac power supply\n"); + goto unregister_bat; + } + + ret = power_supply_register(&pdev->dev, &info->usb); + if (ret) { + dev_err(info->dev, "failed to register usb power supply\n"); + goto unregister_ac; + } + + /* enable usb device presence detection */ + HW_USBPHY_CTRL_SET(BM_USBPHY_CTRL_ENDEVPLUGINDETECT); + + return 0; + +unregister_ac: + power_supply_unregister(&info->ac); +unregister_bat: + power_supply_unregister(&info->bat); +free_irq: + free_irq(info->vdd5v_irq->start, pdev); +stop_sm: + ddi_bc_ShutDown(); +free_info: + kfree(info); + return ret; +} + +static int stmp3xxx_bat_remove(struct platform_device *pdev) +{ + struct stmp3xxx_info *info = platform_get_drvdata(pdev); + + if (info->regulator) + regulator_put(info->regulator); + free_irq(info->vdd5v_irq->start, pdev); + ddi_bc_ShutDown(); + power_supply_unregister(&info->usb); + power_supply_unregister(&info->ac); + power_supply_unregister(&info->bat); + return 0; +} + +static void stmp3xxx_bat_shutdown(struct platform_device *pdev) +{ + ddi_bc_ShutDown(); +} + + +#ifdef CONFIG_PM + +static int stmp3xxx_bat_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct stmp3xxx_info *info = platform_get_drvdata(pdev); + + mutex_lock(&info->sm_lock); + + /* disable 5v irq */ + HW_POWER_CTRL_CLR(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO); + + ddi_bc_SetDisable(); + /* cancel state machine timer */ + del_timer_sync(&info->sm_timer); + + mutex_unlock(&info->sm_lock); + return 0; +} + +static int stmp3xxx_bat_resume(struct platform_device *pdev) +{ + struct stmp3xxx_info *info = platform_get_drvdata(pdev); + ddi_bc_Cfg_t *cfg = info->sm_cfg; + + mutex_lock(&info->sm_lock); + + if (is_ac_online()) { + /* ac supply connected */ + dev_info(info->dev, "ac/5v present, enabling state machine\n"); + + info->is_ac_online = 1; + info->is_usb_online = 0; + ddi_bc_SetCurrentLimit(600 /*mA*/); + ddi_bc_SetEnable(); + } else if (is_usb_online()) { + /* usb supply connected */ + dev_info(info->dev, "usb/5v present, enabling state machine\n"); + + info->is_ac_online = 0; + info->is_usb_online = 1; + ddi_bc_SetCurrentLimit(350 /*mA*/); + ddi_bc_SetEnable(); + } else { + /* not powered */ + dev_info(info->dev, "%s: 5v not present\n", __func__); + + info->is_ac_online = 0; + info->is_usb_online = 0; + } + + /* enable 5v irq */ + HW_POWER_CTRL_SET(BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO); + + /* reschedule calls to state machine */ + mod_timer(&info->sm_timer, + jiffies + msecs_to_jiffies(cfg->u32StateMachinePeriod)); + + mutex_unlock(&info->sm_lock); + return 0; +} + +#else +#define stmp3xxx_bat_suspend NULL +#define stmp3xxx_bat_resume NULL +#endif + +static struct platform_driver stmp3xxx_batdrv = { + .probe = stmp3xxx_bat_probe, + .remove = stmp3xxx_bat_remove, + .shutdown = stmp3xxx_bat_shutdown, + .suspend = stmp3xxx_bat_suspend, + .resume = stmp3xxx_bat_resume, + .driver = { + .name = "stmp3xxx-battery", + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxx_bat_init(void) +{ + return platform_driver_register(&stmp3xxx_batdrv); +} + +static void __exit stmp3xxx_bat_exit(void) +{ + platform_driver_unregister(&stmp3xxx_batdrv); +} + +module_init(stmp3xxx_bat_init); +module_exit(stmp3xxx_bat_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steve Longerbeam <stevel@embeddedalley.com>"); +MODULE_DESCRIPTION("Linux glue to STMP3xxx battery state machine"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 16959699a77a..7c5e7287de6c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -85,6 +85,12 @@ config REGULATOR_MC13783 depends on MXC_PMIC_MC13783 default y +config REGULATOR_STMP3XXX + tristate "STMP3xxx Regulator Support" + depends on REGULATOR + depends on ARCH_STMP3XXX + default y + config REGULATOR_MC9S08DZ60 tristate "mc9s08dz60 Regulator Support" depends on REGULATOR diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 0ec269132327..b5dfd971b427 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_MC13892) += reg-mc13892.o obj-$(CONFIG_REGULATOR_MC13783) += reg-mc13783.o +obj-$(CONFIG_REGULATOR_STMP3XXX) += stmp3xxx.o obj-$(CONFIG_REGULATOR_MC9S08DZ60) += reg-mc9s08dz60.o diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index bb04680a432e..0444baec3ad1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -522,6 +522,17 @@ config RTC_DRV_S3C This driver can also be build as a module. If so, the module will be called rtc-s3c. +config RTC_DRV_STMP3XXX + tristate "Sigmatel STMP3xxx series SoC RTC" + depends on ARCH_STMP3XXX && RTC_CLASS + help + Say Y here to get support for the real-time clock peripheral + on Sigmatel STMP3xxx series SoCs (tested on STMP3700). + + This driver can also be build as a module. If so, the module + will be called rtc-stmp3xxx. + + config RTC_DRV_EP93XX tristate "Cirrus Logic EP93XX" depends on ARCH_EP93XX diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 71f69eb2dec3..9b513bf50051 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o +obj-$(CONFIG_RTC_DRV_STMP3XXX) += rtc-stmp3xxx.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c new file mode 100644 index 000000000000..51499cd0ba81 --- /dev/null +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -0,0 +1,277 @@ +/* + * Freescale STMP37XX/STMP378X Real Time Clock driver + * + * Copyright (c) 2007 Sigmatel, Inc. + * Peter Hartley, <peter.hartley@sigmatel.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/uaccess.h> + +#include <mach/stmp3xxx.h> +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/regs-rtc.h> + +struct stmp3xxx_rtc_data { + struct rtc_device *rtc; + unsigned irq_count; +}; + +/* Time read/write */ +static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +{ + while (HW_RTC_STAT_RD() & BF_RTC_STAT_STALE_REGS(0x80)) + cpu_relax(); + + rtc_time_to_tm(HW_RTC_SECONDS_RD(), rtc_tm); + return 0; +} + +static int stmp3xxx_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) +{ + unsigned long t; + int rc = rtc_tm_to_time(rtc_tm, &t); + + if (rc == 0) { + HW_RTC_SECONDS_WR(t); + + /* The datasheet doesn't say which way round the + * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, + * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS, + */ + while (HW_RTC_STAT_RD() & BF_RTC_STAT_NEW_REGS(0x80)) + cpu_relax(); + } + return rc; +} + +static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct stmp3xxx_rtc_data *data = platform_get_drvdata(pdev); + u32 status; + u32 events = 0; + + status = HW_RTC_CTRL_RD() & + (BM_RTC_CTRL_ALARM_IRQ | BM_RTC_CTRL_ONEMSEC_IRQ); + if (status & BM_RTC_CTRL_ALARM_IRQ) { + HW_RTC_CTRL_CLR(BM_RTC_CTRL_ALARM_IRQ); + events |= RTC_AF | RTC_IRQF; + } + if (status & BM_RTC_CTRL_ONEMSEC_IRQ) { + HW_RTC_CTRL_CLR(BM_RTC_CTRL_ONEMSEC_IRQ); + if (++data->irq_count % 1000 == 0) { + events |= RTC_UF | RTC_IRQF; + data->irq_count = 0; + } + } + + if (events) + rtc_update_irq(data->rtc, 1, events); + + return IRQ_HANDLED; +} + +static int stmp3xxx_rtc_open(struct device *dev) +{ + int r; + + r = request_irq(IRQ_RTC_ALARM, stmp3xxx_rtc_interrupt, + IRQF_DISABLED, "RTC alarm", dev); + if (r) { + dev_err(dev, "Cannot claim IRQ%d\n", IRQ_RTC_ALARM); + goto fail_1; + } + r = request_irq(IRQ_RTC_1MSEC, stmp3xxx_rtc_interrupt, + IRQF_DISABLED, "RTC tick", dev); + if (r) { + dev_err(dev, "Cannot claim IRQ%d\n", IRQ_RTC_1MSEC); + goto fail_2; + } + + return 0; +fail_2: + free_irq(IRQ_RTC_ALARM, dev); +fail_1: + return r; +} + +static void stmp3xxx_rtc_release(struct device *dev) +{ + HW_RTC_CTRL_CLR(BM_RTC_CTRL_ALARM_IRQ_EN | BM_RTC_CTRL_ONEMSEC_IRQ_EN); + free_irq(IRQ_RTC_ALARM, dev); + free_irq(IRQ_RTC_1MSEC, dev); +} + +static int stmp3xxx_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct stmp3xxx_rtc_data *data = dev_get_drvdata(dev); + + switch (cmd) { + case RTC_AIE_OFF: + HW_RTC_PERSISTENT0_CLR(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN); + HW_RTC_CTRL_CLR(BM_RTC_CTRL_ALARM_IRQ_EN); + break; + case RTC_AIE_ON: + HW_RTC_PERSISTENT0_SET(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN); + HW_RTC_CTRL_SET(BM_RTC_CTRL_ALARM_IRQ_EN); + break; + case RTC_UIE_ON: + data->irq_count = 0; + HW_RTC_CTRL_SET(BM_RTC_CTRL_ONEMSEC_IRQ_EN); + break; + case RTC_UIE_OFF: + HW_RTC_CTRL_CLR(BM_RTC_CTRL_ONEMSEC_IRQ_EN); + break; + default: + return -ENOIOCTLCMD; + } + + return 0; +} +static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + u32 t = HW_RTC_ALARM_RD(); + + rtc_time_to_tm(t, &alm->time); + + return 0; +} + +static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned long t; + + rtc_tm_to_time(&alm->time, &t); + HW_RTC_ALARM_WR(t); + return 0; +} + +static struct rtc_class_ops stmp3xxx_rtc_ops = { + .open = stmp3xxx_rtc_open, + .release = stmp3xxx_rtc_release, + .ioctl = stmp3xxx_rtc_ioctl, + .read_time = stmp3xxx_rtc_gettime, + .set_time = stmp3xxx_rtc_settime, + .read_alarm = stmp3xxx_rtc_read_alarm, + .set_alarm = stmp3xxx_rtc_set_alarm, +}; + +static int stmp3xxx_rtc_remove(struct platform_device *dev) +{ + struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); + + if (rtc_data) { + rtc_device_unregister(rtc_data->rtc); + kfree(rtc_data); + } + + return 0; +} + +static int stmp3xxx_rtc_probe(struct platform_device *pdev) +{ + u32 hwversion = HW_RTC_VERSION_RD(); + u32 rtc_stat = HW_RTC_STAT_RD(); + struct stmp3xxx_rtc_data *rtc_data = kzalloc(sizeof *rtc_data, + GFP_KERNEL); + + if ((rtc_stat & BM_RTC_STAT_RTC_PRESENT) == 0) + return -ENODEV; + if (!rtc_data) + return -ENOMEM; + + stmp3xxx_reset_block(REGS_RTC_BASE, 1); + + HW_RTC_PERSISTENT0_CLR(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE); + + printk(KERN_INFO "STMP3xxx RTC driver v1.0 hardware v%u.%u.%u\n", + (hwversion >> 24), + (hwversion >> 16) & 0xFF, + hwversion & 0xFFFF); + + rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, + &stmp3xxx_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc_data->rtc)) { + kfree(rtc_data); + return PTR_ERR(rtc_data->rtc); + } + + platform_set_drvdata(pdev, rtc_data); + + return 0; +} + +#ifdef CONFIG_PM +static int stmp3xxx_rtc_suspend(struct platform_device *dev, pm_message_t state) +{ + return 0; +} + +static int stmp3xxx_rtc_resume(struct platform_device *dev) +{ + stmp3xxx_reset_block(REGS_RTC_BASE, 1); + HW_RTC_PERSISTENT0_CLR(BM_RTC_PERSISTENT0_ALARM_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE_EN | + BM_RTC_PERSISTENT0_ALARM_WAKE); + return 0; +} +#else +#define stmp3xxx_rtc_suspend NULL +#define stmp3xxx_rtc_resume NULL +#endif + +static struct platform_driver stmp3xxx_rtcdrv = { + .probe = stmp3xxx_rtc_probe, + .remove = stmp3xxx_rtc_remove, + .suspend = stmp3xxx_rtc_suspend, + .resume = stmp3xxx_rtc_resume, + .driver = { + .name = "stmp3xxx-rtc", + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxx_rtc_init(void) +{ + return platform_driver_register(&stmp3xxx_rtcdrv); +} + +static void __exit stmp3xxx_rtc_exit(void) +{ + platform_driver_unregister(&stmp3xxx_rtcdrv); +} + +module_init(stmp3xxx_rtc_init); +module_exit(stmp3xxx_rtc_exit); + +MODULE_DESCRIPTION("STMP3xxx RTC Driver"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 39e90ee659eb..76f25be49fa2 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1397,4 +1397,35 @@ config SPORT_BAUD_RATE default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) +config SERIAL_STMP_DBG + tristate "STMP debug serial port support" + depends on ARCH_STMP3XXX + select SERIAL_CORE + help + Driver for Sigmatel 36XX/37XX internal debug serial port + +config SERIAL_STMP_DBG_CONSOLE + bool "Support for console on STMP37XX DBG serial port" + depends on SERIAL_STMP_DBG=y + select SERIAL_CORE_CONSOLE + ---help--- + Say Y here if you wish to use the STMP36XX/37XX debug serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyAM0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +config SERIAL_STMP_APP + tristate "STMP app serial port support" + depends on ARCH_STMP3XXX + select SERIAL_CORE + help + Driver for Sigmatel 36XX/37XX internal application serial port + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 14a8c2fa49ad..3130d6c429fa 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -75,3 +75,5 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o +obj-$(CONFIG_SERIAL_STMP_DBG) += stmp-dbg.o +obj-$(CONFIG_SERIAL_STMP_APP) += stmp-app.o diff --git a/drivers/serial/stmp-app.c b/drivers/serial/stmp-app.c new file mode 100644 index 000000000000..6a56c444cf20 --- /dev/null +++ b/drivers/serial/stmp-app.c @@ -0,0 +1,1064 @@ +/* + * Freescale STMP37XX/STMP378X Application UART driver + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/wait.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/uaccess.h> + +#include <asm/cacheflush.h> +#include <mach/hardware.h> +#include <mach/regs-apbx.h> +#include <mach/regs-uartapp.h> +#include <mach/regs-pinctrl.h> +#include <mach/stmp3xxx.h> + +#include <asm/mach-types.h> + +#include "stmp-app.h" + +static int pio_mode /* = 0 */; /* PIO mode = 1, DMA mode = 0 */ + +static struct platform_driver stmp_appuart_driver = { + .probe = stmp_appuart_probe, + .remove = __devexit_p(stmp_appuart_remove), + .suspend = stmp_appuart_suspend, + .resume = stmp_appuart_resume, + .driver = { + .name = "stmp37xx-appuart", + .owner = THIS_MODULE, + }, +}; + +static struct uart_driver stmp_appuart_uart = { + .owner = THIS_MODULE, + .driver_name = "appuart", + .dev_name = "ttySP", + .major = 242, + .minor = 0, + .nr = 1, +}; + +static inline struct stmp_appuart_port *to_appuart(struct uart_port *u) +{ + return container_of(u, struct stmp_appuart_port, port); +} + +static struct uart_ops stmp_appuart_ops = { + .tx_empty = stmp_appuart_tx_empty, + .start_tx = stmp_appuart_start_tx, + .stop_tx = stmp_appuart_stop_tx, + .stop_rx = stmp_appuart_stop_rx, + .enable_ms = stmp_appuart_enable_ms, + .break_ctl = stmp_appuart_break_ctl, + .set_mctrl = stmp_appuart_set_mctrl, + .get_mctrl = stmp_appuart_get_mctrl, + .startup = stmp_appuart_startup, + .shutdown = stmp_appuart_shutdown, + .set_termios = stmp_appuart_settermios, + .type = stmp_appuart_type, + .release_port = stmp_appuart_release_port, + .request_port = stmp_appuart_request_port, + .config_port = stmp_appuart_config_port, + .verify_port = stmp_appuart_verify_port, +}; + +static inline int chr(int c) +{ + if (c < 0x20 || c > 0x7F) + return '#'; + return c; +} + +/* Allocate and initialize rx and tx DMA chains */ +static inline int stmp_appuart_dma_init(struct stmp_appuart_port *s) +{ + int err = 0; + struct stmp3xxx_dma_descriptor *t = &s->tx_desc; +#ifndef RX_CHAIN + struct stmp3xxx_dma_descriptor *r = &s->rx_desc; +#else + int i; +#endif + + err = stmp3xxx_dma_request(s->dma_rx, s->dev, s->dev->bus_id); + if (err) + goto out; + err = stmp3xxx_dma_request(s->dma_tx, s->dev, s->dev->bus_id); + if (err) + goto out1; + +#ifndef RX_CHAIN + err = stmp3xxx_dma_allocate_command(s->dma_rx, r); + if (err) + goto out2; +#endif + err = stmp3xxx_dma_allocate_command(s->dma_tx, t); + if (err) + goto out3; + t->virtual_buf_ptr = dma_alloc_coherent(s->dev, + TX_BUFFER_SIZE, + &t->command->buf_ptr, + GFP_DMA); + if (!t->virtual_buf_ptr) + goto out4; +#ifdef DEBUG + memset(t->virtual_buf_ptr, 0x4B, TX_BUFFER_SIZE); +#endif + +#ifndef RX_CHAIN + r->virtual_buf_ptr = dma_alloc_coherent(s->dev, + RX_BUFFER_SIZE, + &r->command->buf_ptr, + GFP_DMA); + if (!r->virtual_buf_ptr) + goto out5; +#ifdef DEBUG + memset(r->virtual_buf_ptr, 0x4C, RX_BUFFER_SIZE); +#endif +#else + stmp3xxx_dma_make_chain(s->dma_rx, &s->rx_chain, s->rxd, RX_CHAIN); + for (i = 0; i < RX_CHAIN; i++) { + struct stmp3xxx_dma_descriptor *r = s->rxd + i; + + r->command->cmd = + BF_APBX_CHn_CMD_XFER_COUNT(RX_BUFFER_SIZE) | + BF_APBX_CHn_CMD_CMDWORDS(1) | + BM_APBX_CHn_CMD_WAIT4ENDCMD | + BM_APBX_CHn_CMD_SEMAPHORE | + BM_APBX_CHn_CMD_IRQONCMPLT | + BM_APBX_CHn_CMD_CHAIN | + BF_APBX_CHn_CMD_COMMAND( + BV_APBX_CHn_CMD_COMMAND__DMA_WRITE); + r->virtual_buf_ptr = dma_alloc_coherent(s->dev, + RX_BUFFER_SIZE, + &r->command->buf_ptr, + GFP_DMA); + r->command->pio_words[0] = /* BM_UARTAPP_CTRL0_RUN | */ + BF_UARTAPP_CTRL0_XFER_COUNT(RX_BUFFER_SIZE)| + BM_UARTAPP_CTRL0_RXTO_ENABLE | + BF_UARTAPP_CTRL0_RXTIMEOUT(3); + } +#endif + return 0; + + /* + * would be necessary on other error paths + + dma_free_coherent( s->dev, RX_BUFFER_SIZE, r->virtual_buf_ptr, + r->command->buf_ptr); + */ +out5: + dma_free_coherent(s->dev, TX_BUFFER_SIZE, t->virtual_buf_ptr, + t->command->buf_ptr); +out4: + stmp3xxx_dma_free_command(s->dma_tx, t); +out3: +#ifndef RX_CHAIN + stmp3xxx_dma_free_command(s->dma_rx, r); +#endif +out2: + stmp3xxx_dma_release(s->dma_tx); +out1: + stmp3xxx_dma_release(s->dma_rx); +out: + WARN_ON(err); + return err; +} + + +static void stmp_appuart_on(struct platform_device *dev) +{ + struct stmp_appuart_port *s = platform_get_drvdata(dev); + + if (!pio_mode) { + /* + Tell DMA to select UART. + Both DMA channels are shared between app UART and IrDA. + Target id of 0 means UART, 1 means IrDA + */ + stmp3xxx_dma_set_alt_target(s->dma_rx, 0); + stmp3xxx_dma_set_alt_target(s->dma_tx, 0); + /* + Reset DMA channels + */ + stmp3xxx_dma_reset_channel(s->dma_rx); + stmp3xxx_dma_reset_channel(s->dma_tx); + stmp3xxx_dma_enable_interrupt(s->dma_rx); + stmp3xxx_dma_enable_interrupt(s->dma_tx); + } +} + +#ifdef CONFIG_CPU_FREQ +static int stmp_appuart_updateclk(struct device *dev, void *clkdata) +{ + struct stmp_appuart_port *s = dev_get_drvdata(dev); + + if (s) { + s->port.uartclk = clk_get_rate(s->clk) * 1000; + /* FIXME: perform actual update */ + } + return 0; +} + +static int stmp_appuart_notifier(struct notifier_block *self, + unsigned long phase, void *p) +{ + int r = 0; + + if ((phase == CPUFREQ_POSTCHANGE) || + (phase == CPUFREQ_RESUMECHANGE)) { + /* get new uartclock and setspeed */ + r = driver_for_each_device( + &stmp_appuart_driver.driver, + NULL, p, + stmp_appuart_updateclk); + } + return (r == 0) ? NOTIFY_OK : NOTIFY_DONE; +} + +static struct notifier_block stmp_appuart_nb = { + .notifier_call = &stmp_appuart_notifier, +}; +#endif /* CONFIG_CPU_FREQ */ + +static int __devinit stmp_appuart_probe(struct platform_device *device) +{ + struct stmp_appuart_port *s; + int err = 0; + struct resource *r; + int i; + u32 version; + int (*pinctl)(int req, int id); + + s = kzalloc(sizeof(struct stmp_appuart_port), GFP_KERNEL); + if (!s) { + err = -ENOMEM; + goto out; + } + + spin_lock_init(&s->lock); + + s->clk = clk_get(NULL, "uart"); + if (IS_ERR(s->clk)) { + err = PTR_ERR(s->clk); + goto out_free; + } + clk_enable(s->clk); + r = platform_get_resource(device, IORESOURCE_MEM, 0); + if (!r) { + err = -ENXIO; + goto out_free_clk; + } + s->port.mapbase = r->start; + s->port.irq = platform_get_irq(device, 0); + s->port.ops = &stmp_appuart_ops; + s->port.iotype = UPIO_MEM; + s->port.line = device->id < 0 ? 0 : device->id; + s->port.fifosize = 16; + s->port.timeout = HZ/10; + s->port.uartclk = clk_get_rate(s->clk) * 1000; + s->port.type = PORT_STMP37xx; + s->port.dev = s->dev = get_device(&device->dev); + s->ctrl = 0; + s->keep_irq = 0; + + r = platform_get_resource(device, IORESOURCE_MEM, 0); + if (!r) { + err = -ENXIO; + goto out_free_clk; + } + + dev_dbg(s->dev, "%s\n", __func__); + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { + s->irq[i] = platform_get_irq(device, i); + dev_dbg(s->dev, "Resources: irq[%d] = %d\n", i, s->irq[i]); + if (s->irq[i] < 0) { + err = s->irq[i]; + goto out_free_clk; + } + } + + r = platform_get_resource(device, IORESOURCE_DMA, 0); + if (!r) { + err = -ENXIO; + goto out_free; + } + s->dma_rx = r->start; + + r = platform_get_resource(device, IORESOURCE_DMA, 1); + if (!r) { + err = -ENXIO; + goto out_free; + } + s->dma_tx = r->start; + + r = platform_get_resource(device, IORESOURCE_MEM, 0); + if (!r) { + err = -ENXIO; + goto out_free; + } + s->mem = r->start; + s->memsize = r->end - r->start; + + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&stmp_appuart_nb, + CPUFREQ_TRANSITION_NOTIFIER); +#endif + platform_set_drvdata(device, s); + + device_init_wakeup(&device->dev, 1); + + stmp_appuart_dma_init(s); + stmp_appuart_on(device); + + pinctl = device->dev.platform_data; + if (pinctl) { + err = pinctl(1, device->id); + if (err) + goto out_free_clk; + } + + err = uart_add_one_port(&stmp_appuart_uart, &s->port); + if (err) + goto out_free_pins; + + version = HW_UARTAPP_VERSION_RD(); + printk(KERN_INFO"Found APPUART %d.%d.%d\n", + (version >> 24) & 0xFF, + (version >> 16) & 0xFF, + version & 0xFFFF); + return 0; + +out_free_pins: + if (pinctl) + pinctl(0, device->id); +out_free_clk: + clk_put(s->clk); +out_free: + platform_set_drvdata(device, NULL); + kfree(s); +out: + return err; +} + +static int __devexit stmp_appuart_remove(struct platform_device *device) +{ + struct stmp_appuart_port *s; + void (*pinctl)(int req, int id); + + s = platform_get_drvdata(device); + if (s) { + pinctl = device->dev.platform_data; + put_device(s->dev); + clk_disable(s->clk); + clk_put(s->clk); + uart_remove_one_port(&stmp_appuart_uart, &s->port); + if (pinctl) + pinctl(0, device->id); + kfree(s); + platform_set_drvdata(device, NULL); + } + + return 0; +} + +static int stmp_appuart_suspend(struct platform_device *device, + pm_message_t state) +{ +#ifdef CONFIG_PM + struct stmp_appuart_port *s = platform_get_drvdata(device); + + if (!s) + return 0; + s->keep_irq = device_may_wakeup(&device->dev); + uart_suspend_port(&stmp_appuart_uart, &s->port); + if (!s->keep_irq) + clk_disable(s->clk); +#endif + return 0; +} + +static int stmp_appuart_resume(struct platform_device *device) +{ +#ifdef CONFIG_PM + struct stmp_appuart_port *s = platform_get_drvdata(device); + + if (!s) + return 0; + + if (!s->keep_irq) + clk_enable(s->clk); + stmp_appuart_on(device); + uart_resume_port(&stmp_appuart_uart, &s->port); + s->keep_irq = 0; +#endif + return 0; +} + +static int __init stmp_appuart_init() +{ + int r; + + r = uart_register_driver(&stmp_appuart_uart); + if (r) + goto out; + r = platform_driver_register(&stmp_appuart_driver); + if (r) + goto out_err; + return 0; +out_err: + uart_unregister_driver(&stmp_appuart_uart); +out: + return r; +} + +static void __exit stmp_appuart_exit() +{ + platform_driver_unregister(&stmp_appuart_driver); + uart_unregister_driver(&stmp_appuart_uart); +} + +module_init(stmp_appuart_init) +module_exit(stmp_appuart_exit) + +static void stmp_appuart_stop_rx(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s\n", __func__); + HW_UARTAPP_CTRL2_CLR_NB(s->mem, BM_UARTAPP_CTRL2_RXE); +} + +static void stmp_appuart_break_ctl(struct uart_port *u, int ctl) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s: break = %s\n", __func__, ctl ? "on" : "off"); + if (ctl) + HW_UARTAPP_LINECTRL_SET_NB(s->mem, BM_UARTAPP_LINECTRL_BRK); + else + HW_UARTAPP_LINECTRL_CLR_NB(s->mem, BM_UARTAPP_LINECTRL_BRK); +} + +static void stmp_appuart_enable_ms(struct uart_port *port) +{ + /* just empty */ +} + +static void stmp_appuart_set_mctrl(struct uart_port *u, unsigned mctrl) +{ + struct stmp_appuart_port *s = to_appuart(u); + + u32 ctrl = HW_UARTAPP_CTRL2_RD_NB(s->mem); + + dev_dbg(s->dev, "%s (%x)\n", __func__, mctrl); + ctrl &= ~BM_UARTAPP_CTRL2_RTS; + if (mctrl & TIOCM_RTS) { + dev_dbg(s->dev, "...RTS\n"); + ctrl |= BM_UARTAPP_CTRL2_RTS; + } + s->ctrl = mctrl; + dev_dbg(s->dev, "...%x; ctrl = %x\n", s->ctrl, ctrl); + HW_UARTAPP_CTRL2_WR_NB(s->mem, ctrl); +} + +static u32 stmp_appuart_get_mctrl(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + u32 stat = HW_UARTAPP_STAT_RD_NB(s->mem); + int ctrl2 = HW_UARTAPP_CTRL2_RD_NB(s->mem); + u32 mctrl = s->ctrl; + + dev_dbg(s->dev, "%s:\n", __func__); + mctrl &= ~TIOCM_CTS; + if (stat & BM_UARTAPP_STAT_CTS) { + dev_dbg(s->dev, "CTS"); + mctrl |= TIOCM_CTS; + } + if (ctrl2 & BM_UARTAPP_CTRL2_RTS) { + dev_dbg(s->dev, "RTS"); + mctrl |= TIOCM_RTS; + } + dev_dbg(s->dev, "...%x\n", mctrl); + return mctrl; +} + +static int stmp_appuart_request_port(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + int err = 0; + + if (!request_mem_region(s->mem, s->memsize, s->dev->bus_id)) + err = -ENXIO; + return err; + +} + +static void stmp_appuart_release_port(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + + release_mem_region(s->mem, s->memsize); +} + +static int stmp_appuart_verify_port(struct uart_port *u, + struct serial_struct *ser) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s\n", __func__); + return 0; +} + +static void stmp_appuart_config_port(struct uart_port *u, int flags) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s\n", __func__); +} + + +static const char *stmp_appuart_type(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s\n", __func__); + return s->dev->bus_id; +} + +static void stmp_appuart_settermios(struct uart_port *u, + struct ktermios *nw, struct ktermios *old) +{ + static struct ktermios saved; + struct stmp_appuart_port *s = to_appuart(u); + unsigned int cflag; + u32 bm, ctrl, ctrl2, div; + int err = 0; + unsigned baud; + + dev_dbg(s->dev, "%s\n", __func__); + + if (nw) + memcpy(&saved, nw, sizeof *nw); + else + nw = old = &saved; + + cflag = nw->c_cflag; + + ctrl = BM_UARTAPP_LINECTRL_FEN; + ctrl2 = HW_UARTAPP_CTRL2_RD_NB(s->mem); + + /* byte size */ + switch (cflag & CSIZE) { + case CS5: bm = 0; break; + case CS6: bm = 1; break; + case CS7: bm = 2; break; + case CS8: bm = 3; break; + default: err = -EINVAL; break; + } + if (err) + goto out; + + dev_dbg(s->dev, "Byte size %d bytes, mask %x\n", + bm + 5, BF_UARTAPP_LINECTRL_WLEN(bm)); + ctrl |= BF_UARTAPP_LINECTRL_WLEN(bm); + + /* parity */ + if (cflag & PARENB) { + dev_dbg(s->dev, "Parity check enabled\n"); + ctrl |= BM_UARTAPP_LINECTRL_PEN | BM_UARTAPP_LINECTRL_SPS; + if ((cflag & PARODD) == 0) { + dev_dbg(s->dev, "(Even) mask = %x\n", + BM_UARTAPP_LINECTRL_PEN | + BM_UARTAPP_LINECTRL_SPS | + BM_UARTAPP_LINECTRL_EPS); + ctrl |= BM_UARTAPP_LINECTRL_EPS; + } else + dev_dbg(s->dev, "(Odd) mask = %x\n", + BM_UARTAPP_LINECTRL_PEN | + BM_UARTAPP_LINECTRL_SPS); + } else + dev_dbg(s->dev, "Parity check disabled.\n"); + + /* figure out the stop bits requested */ + if (cflag & CSTOPB) { + dev_dbg(s->dev, "Stop bits, mask = %x\n", + BM_UARTAPP_LINECTRL_STP2); + ctrl |= BM_UARTAPP_LINECTRL_STP2; + } else + dev_dbg(s->dev, "No stop bits\n"); + + /* figure out the hardware flow control settings */ + if (cflag & CRTSCTS) { + dev_dbg(s->dev, "RTS/CTS flow control\n"); + ctrl2 |= BM_UARTAPP_CTRL2_CTSEN /* | BM_UARTAPP_CTRL2_RTSEN */; + } else { + dev_dbg(s->dev, "RTS/CTS disabled\n"); + ctrl2 &= ~BM_UARTAPP_CTRL2_CTSEN; + } + + /* set baud rate */ + baud = uart_get_baud_rate(u, nw, old, 0, u->uartclk); + dev_dbg(s->dev, "Baud rate requested: %d (clk = %d)\n", + baud, u->uartclk); + div = u->uartclk * 32 / baud; + ctrl |= BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(div & 0x3F); + ctrl |= BF_UARTAPP_LINECTRL_BAUD_DIVINT(div >> 6); + + if ((cflag & CREAD) != 0) { + dev_dbg(s->dev, "RX started\n"); + ctrl2 |= BM_UARTAPP_CTRL2_RXE | BM_UARTAPP_CTRL2_RXDMAE; + } + + if (!err) { + dev_dbg(s->dev, "CTRLS = %x + %x\n", ctrl, ctrl2); + HW_UARTAPP_LINECTRL_WR_NB(s->mem, ctrl); + HW_UARTAPP_CTRL2_WR_NB(s->mem, ctrl2); + } +out: + return /* err */; +} + +static int stmp_appuart_free_irqs(struct stmp_appuart_port *s) +{ + int irqn = 0; + + if (s->keep_irq) { + dev_dbg(s->dev, "keep_irq != 0, ignoring\n"); + return 0; + } + for (irqn = 0; irqn < ARRAY_SIZE(s->irq); irqn++) + free_irq(s->irq[irqn], s); + return 0; +} + +void stmp_appuart_rx(struct stmp_appuart_port *s, u8 *rx_buffer, int count) +{ + u8 c; + int flag; + struct tty_struct *tty = s->port.info->port.tty; + u32 stat; + + spin_lock(&s->lock); + stat = HW_UARTAPP_STAT_RD_NB(s->mem); + + if (count < 0) { + count = HW_UARTAPP_STAT_RD_NB(s->mem) & BM_UARTAPP_STAT_RXCOUNT; + dev_dbg(s->dev, "count = %d\n", count); + } + + for (;;) { + if (!rx_buffer) { + if (stat & BM_UARTAPP_STAT_RXFE) + break; + c = HW_UARTAPP_DATA_RD_NB(s->mem) & 0xFF; + } else { + if (count-- <= 0) + break; + c = *rx_buffer++; + dev_dbg(s->dev, "Received: %x(%c)\n", c, chr(c)); + } + + flag = TTY_NORMAL; + if (stat & BM_UARTAPP_STAT_BERR) { + stat &= ~BM_UARTAPP_STAT_BERR; + s->port.icount.brk++; + if (uart_handle_break(&s->port)) + goto ignore; + flag = TTY_BREAK; + } else if (stat & BM_UARTAPP_STAT_PERR) { + stat &= ~BM_UARTAPP_STAT_PERR; + s->port.icount.parity++; + flag = TTY_PARITY; + } else if (stat & BM_UARTAPP_STAT_FERR) { + stat &= ~BM_UARTAPP_STAT_FERR; + s->port.icount.frame++; + flag = TTY_FRAME; + } + + if (stat & BM_UARTAPP_STAT_OERR) + s->port.icount.overrun++; + + if (uart_handle_sysrq_char(&s->port, c)) + goto ignore; + + uart_insert_char(&s->port, stat, + BM_UARTAPP_STAT_OERR, c, flag); +ignore: + if (pio_mode) { + HW_UARTAPP_STAT_WR_NB(s->mem, stat); + stat = HW_UARTAPP_STAT_RD_NB(s->mem); + } + } + + HW_UARTAPP_STAT_WR_NB(s->mem, stat); + tty_flip_buffer_push(tty); + spin_unlock(&s->lock); +} + +static inline void stmp_appuart_submit_rx(struct stmp_appuart_port *s) +{ +#ifndef RX_CHAIN + struct stmp3xxx_dma_descriptor *r = &s->rx_desc; + + dev_dbg(s->dev, "Submitting RX DMA request\n"); + r->command->cmd = + BM_APBX_CHn_CMD_HALTONTERMINATE | + BF_APBX_CHn_CMD_XFER_COUNT(RX_BUFFER_SIZE) | + BF_APBX_CHn_CMD_CMDWORDS(1) | + BM_APBX_CHn_CMD_WAIT4ENDCMD | + BM_APBX_CHn_CMD_SEMAPHORE | + BM_APBX_CHn_CMD_IRQONCMPLT | + BF_APBX_CHn_CMD_COMMAND( + BV_APBX_CHn_CMD_COMMAND__DMA_WRITE); + r->command->pio_words[0] = HW_UARTAPP_CTRL0_RD() | + BF_UARTAPP_CTRL0_XFER_COUNT(RX_BUFFER_SIZE)| + BM_UARTAPP_CTRL0_RXTO_ENABLE | + BF_UARTAPP_CTRL0_RXTIMEOUT(3); + r->command->pio_words[0] &= ~BM_UARTAPP_CTRL0_RUN; + + stmp3xxx_dma_reset_channel(s->dma_rx); + stmp3xxx_dma_go(s->dma_rx, r, 1); +#endif +} + +static irqreturn_t stmp_appuart_irq_int(int irq, void *context) +{ + u32 istatus; + struct stmp_appuart_port *s = context; + u32 stat = HW_UARTAPP_STAT_RD_NB(s->mem); + + istatus = HW_UARTAPP_INTR_RD_NB(s->mem); + dev_dbg(s->dev, "IRQ: int(%d), status = %08X\n", irq, istatus); + + if (istatus & BM_UARTAPP_INTR_CTSMIS) { + uart_handle_cts_change(&s->port, stat & BM_UARTAPP_STAT_CTS); + dev_dbg(s->dev, "CTS change: %x\n", stat & BM_UARTAPP_STAT_CTS); + HW_UARTAPP_INTR_CLR_NB(s->mem, BM_UARTAPP_INTR_CTSMIS); + } + + else if (istatus & BM_UARTAPP_INTR_RTIS) { + dev_dbg(s->dev, "RX timeout, draining out\n"); + stmp_appuart_submit_rx(s); + } + + else + dev_info(s->dev, "Unhandled status %x\n", istatus); + + HW_UARTAPP_INTR_CLR_NB(s->mem, istatus & 0xFFFF); + + return IRQ_HANDLED; +} + + +static irqreturn_t stmp_appuart_irq_rx(int irq, void *context) +{ + struct stmp_appuart_port *s = context; + int count = -1; + + stmp3xxx_dma_clear_interrupt(s->dma_rx); + dev_dbg(s->dev, "%s(%d), count = %d\n", __func__, irq, count); + +#ifndef RX_CHAIN + stmp_appuart_rx(s, s->rx_desc.virtual_buf_ptr, count); + stmp_appuart_submit_rx(s); +#else + if (circ_advance_cooked(&s->rx_chain) == 0) { + BUG(); + return IRQ_HANDLED; + } + + circ_advance_active(&s->rx_chain, 1); + while (s->rx_chain.cooked_count) { + stmp_appuart_rx(s, + stmp3xxx_dma_circ_get_cooked_head(&s->rx_chain)-> + virtual_buf_ptr, -1); + circ_advance_free(&s->rx_chain, 1); + } +#endif + return IRQ_HANDLED; +} + +static void stmp_appuart_submit_tx(struct stmp_appuart_port *s, int size) +{ + struct stmp3xxx_dma_descriptor *d = &s->tx_desc; + + dev_dbg(s->dev, "Submitting TX DMA request, %d bytes\n", size); + d->command->pio_words[0] = + /* BM_UARTAPP_CTRL1_RUN | */ BF_UARTAPP_CTRL1_XFER_COUNT(size); + d->command->cmd = BF_APBX_CHn_CMD_XFER_COUNT(size) | + BF_APBX_CHn_CMD_CMDWORDS(1) | + BM_APBX_CHn_CMD_WAIT4ENDCMD | + BM_APBX_CHn_CMD_SEMAPHORE | + BM_APBX_CHn_CMD_IRQONCMPLT | + BF_APBX_CHn_CMD_COMMAND(BV_APBX_CHn_CMD_COMMAND__DMA_READ); + stmp3xxx_dma_go(s->dma_tx, d, 1); +} + +static irqreturn_t stmp_appuart_irq_tx(int irq, void *context) +{ + struct stmp_appuart_port *s = context; + struct uart_port *u = &s->port; + int bytes; + + stmp3xxx_dma_clear_interrupt(s->dma_tx); + dev_dbg(s->dev, "%s(%d)\n", __func__, irq); + + bytes = stmp_appuart_copy_tx(u, s->tx_desc.virtual_buf_ptr, + TX_BUFFER_SIZE); + if (bytes > 0) { + dev_dbg(s->dev, "Sending %d bytes\n", bytes); + stmp_appuart_submit_tx(s, bytes); + } + return IRQ_HANDLED; +} + +static int stmp_appuart_request_irqs(struct stmp_appuart_port *s) +{ + int err = 0; + + /* + * order counts. resources should be listed in the same order + */ + irq_handler_t handlers[] = { + stmp_appuart_irq_int, + stmp_appuart_irq_rx, + stmp_appuart_irq_tx, + }; + char *handlers_names[] = { + "appuart internal", + "appuart rx", + "appuart tx", + }; + int irqn; + + if (s->keep_irq) { + dev_dbg(s->dev, "keep_irq is set, skipping request_irq"); + return 0; + } + for (irqn = 0; irqn < ARRAY_SIZE(handlers); irqn++) { + err = request_irq(s->irq[irqn], handlers[irqn], + 0, handlers_names[irqn], s); + dev_dbg(s->dev, "Requested IRQ %d with status %d\n", + s->irq[irqn], err); + if (err) + goto out; + } + return 0; +out: + stmp_appuart_free_irqs(s); + return err; +} + +static struct timer_list timer_task; + +static void stmp_appuart_check_rx(unsigned long data) +{ + stmp_appuart_rx((struct stmp_appuart_port *)data, NULL, -1); + mod_timer(&timer_task, jiffies + 2 * HZ); +} + +static int stmp_appuart_startup(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + int err; + + dev_dbg(s->dev, "%s\n", __func__); + + s->tx_buffer_index = 0; + + err = stmp_appuart_request_irqs(s); + if (err) + goto out; + + if (!s->keep_irq) + /* Release the block from reset and start the clocks. */ + stmp3xxx_reset_block(s->mem, 0); + + HW_UARTAPP_CTRL2_SET_NB(s->mem, BM_UARTAPP_CTRL2_UARTEN); + /* Enable the Application UART DMA bits. */ + if (!pio_mode) { + HW_UARTAPP_CTRL2_SET_NB(s->mem, + BM_UARTAPP_CTRL2_TXDMAE | BM_UARTAPP_CTRL2_RXDMAE | + BM_UARTAPP_CTRL2_DMAONERR); + /* clear any pending interrupts */ + HW_UARTAPP_INTR_WR_NB(s->mem, 0); + + /* reset all dma channels */ + stmp3xxx_dma_reset_channel(s->dma_tx); + stmp3xxx_dma_reset_channel(s->dma_rx); + } else { + HW_UARTAPP_INTR_WR_NB(s->mem, BM_UARTAPP_INTR_RXIEN | + BM_UARTAPP_INTR_RTIEN); + } + HW_UARTAPP_INTR_SET_NB(s->mem, BM_UARTAPP_INTR_CTSMIEN); + + /* + * Enable fifo so all four bytes of a DMA word are written to + * output (otherwise, only the LSB is written, ie. 1 in 4 bytes) + */ + HW_UARTAPP_LINECTRL_SET_NB(s->mem, BM_UARTAPP_LINECTRL_FEN); + + if (!pio_mode) { +#ifndef RX_CHAIN + stmp_appuart_submit_rx(s); +#else + circ_clear_chain(&s->rx_chain); + stmp3xxx_dma_go(s->dma_rx, &s->rxd[0], 0); + circ_advance_active(&s->rx_chain, 1); +#endif + } else { + init_timer(&timer_task); + timer_task.function = stmp_appuart_check_rx; + timer_task.expires = jiffies + HZ; + timer_task.data = (unsigned long)s; + add_timer(&timer_task); + } + +out: + return err; +} + +static void stmp_appuart_shutdown(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s\n", __func__); + + if (!s->keep_irq) + /* set the IP block to RESET; this should disable clock too. */ + HW_UARTAPP_CTRL0_SET_NB(s->mem, BM_UARTAPP_CTRL0_SFTRST); + + if (!pio_mode) { + /* reset all dma channels */ + stmp3xxx_dma_reset_channel(s->dma_tx); + stmp3xxx_dma_reset_channel(s->dma_rx); + } else { + del_timer(&timer_task); + } + stmp_appuart_free_irqs(s); +} + +static unsigned int stmp_appuart_tx_empty(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + + if (pio_mode) + if (HW_UARTAPP_STAT_RD_NB(s->mem) & BM_UARTAPP_STAT_TXFE) + return TIOCSER_TEMT; + else + return 0; + else + return stmp3xxx_dma_running(s->dma_tx) ? 0: TIOCSER_TEMT; +} + +static void stmp_appuart_start_tx(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + int bytes; + + dev_dbg(s->dev, "%s\n", __func__); + + /* enable transmitter */ + HW_UARTAPP_CTRL2_SET_NB(s->mem, BM_UARTAPP_CTRL2_TXE); + + if (!pio_mode) { + if (stmp3xxx_dma_running(s->dma_tx)) + return; + bytes = stmp_appuart_copy_tx(u, s->tx_desc.virtual_buf_ptr, + TX_BUFFER_SIZE); + if (bytes <= 0) + return; + + dev_dbg(s->dev, "Started DMA transfer with descriptor %p, " + "command %p, %d bytes long\n", + &s->tx_desc, s->tx_desc.command, bytes); + stmp_appuart_submit_tx(s, bytes); + } else { + int count = 0; + u8 c; + + while (!(HW_UARTAPP_STAT_RD_NB(s->mem) & + BM_UARTAPP_STAT_TXFF)) { + if (stmp_appuart_copy_tx(u, &c, 1) <= 0) + break; + dev_dbg(s->dev, "%d: '%c'/%x\n", + ++count, chr(c), c); + HW_UARTAPP_DATA_WR_NB(s->mem, c); + } + } +} + +static void stmp_appuart_stop_tx(struct uart_port *u) +{ + struct stmp_appuart_port *s = to_appuart(u); + + dev_dbg(s->dev, "%s\n", __func__); + HW_UARTAPP_CTRL2_CLR_NB(s->mem, BM_UARTAPP_CTRL2_TXE); +} + +static int stmp_appuart_copy_tx(struct uart_port *u, u8 *target, + int tx_buffer_size) +{ + int last = 0, portion; + struct circ_buf *xmit = &u->info->xmit; + + while (last < tx_buffer_size) { /* let's fill the only descriptor */ + if (u->x_char) { + target[last++] = u->x_char; + u->x_char = 0; + } else if (!uart_circ_empty(xmit) && !uart_tx_stopped(u)) { + portion = min((u32)tx_buffer_size, + (u32)uart_circ_chars_pending(xmit)); + portion = min((u32)portion, + (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail, + UART_XMIT_SIZE)); + memcpy(target + last, &xmit->buf[xmit->tail], portion); + xmit->tail = (xmit->tail + portion) & + (UART_XMIT_SIZE - 1); + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(u); + last += portion; + } else { /* All tx data copied into buffer */ + return last; + } + } + return last; +} + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("stmp3xxx app uart driver"); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +module_param(pio_mode, int, 0); diff --git a/drivers/serial/stmp-app.h b/drivers/serial/stmp-app.h new file mode 100644 index 000000000000..a4fee4217bba --- /dev/null +++ b/drivers/serial/stmp-app.h @@ -0,0 +1,81 @@ +/* + * Freescale STMP37XX/STMP378X Application UART driver + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __STMP_APPUART_H +#define __STMP_APPUART_H + +#define RX_BUFFER_SIZE 4 +#define TX_BUFFER_SIZE 0xFFF0 + +#include <mach/dma.h> + +/* #define RX_CHAIN 2 */ + +struct stmp_appuart_port { + int keep_irq; + int irq[3]; + u32 mem, memsize; + int dma_rx, dma_tx; + struct clk *clk; + struct device *dev; + struct uart_port port; + unsigned tx_buffer_index; + struct stmp3xxx_dma_descriptor tx_desc; +#ifndef RX_CHAIN + struct stmp3xxx_dma_descriptor rx_desc; +#else + struct stmp3xxx_dma_descriptor rxd[RX_CHAIN]; + struct stmp37xx_circ_dma_chain rx_chain; +#endif + + u32 ctrl; + u8 running; + spinlock_t lock; /* protects irq handler */ +}; + +#ifdef CONFIG_CPU_FREQ +static int stmp_appuart_updateclk(struct device *dev, void *clkdata); +static int stmp_appuart_notifier(struct notifier_block *self, + unsigned long phase, void *p); +#endif /* CONFIG_CPU_FREQ */ +static int __init stmp_appuart_probe(struct platform_device *device); +static int stmp_appuart_remove(struct platform_device *device); +static int stmp_appuart_suspend(struct platform_device *device, + pm_message_t state); +static int stmp_appuart_resume(struct platform_device *device); +static int __init stmp_appuart_init(void); +static void __exit stmp_appuart_exit(void); +static int stmp_appuart_request_port(struct uart_port *u); +static void stmp_appuart_release_port(struct uart_port *u); +static int stmp_appuart_verify_port(struct uart_port *u, + struct serial_struct *); +static void stmp_appuart_config_port(struct uart_port *u, int flags); +static const char *stmp_appuart_type(struct uart_port *u); +static void stmp_appuart_settermios(struct uart_port *u, + struct ktermios *nw, struct ktermios *old); +static void stmp_appuart_shutdown(struct uart_port *u); +static int stmp_appuart_startup(struct uart_port *u); +static u32 stmp_appuart_get_mctrl(struct uart_port *u); +static void stmp_appuart_set_mctrl(struct uart_port *u, unsigned mctrl); +static void stmp_appuart_enable_ms(struct uart_port *port); +static void stmp_appuart_break_ctl(struct uart_port *port, int ctl); +static unsigned int stmp_appuart_tx_empty(struct uart_port *u); +static void stmp_appuart_stop_rx(struct uart_port *u); +static void stmp_appuart_start_tx(struct uart_port *u); +static void stmp_appuart_stop_tx(struct uart_port *u); +static int stmp_appuart_copy_tx(struct uart_port *u, u8 *target, int size); +#endif diff --git a/drivers/serial/stmp-dbg.c b/drivers/serial/stmp-dbg.c new file mode 100644 index 000000000000..2848bb88ea7c --- /dev/null +++ b/drivers/serial/stmp-dbg.c @@ -0,0 +1,839 @@ +/* + * Freescale STMP37XX/STMP378X Debug UART driver + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Modifications for STMP36XX Debug Serial (c) 2005 Sigmatel Inc + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/autoconf.h> + +#if defined(CONFIG_SERIAL_STMP_DBG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include <mach/regs-uartdbg.h> + +#include <mach/stmp3xxx.h> + +#include "stmp-dbg.h" + +/* treated as variable unless submitted to open-source */ +#define PORT_STMPDBG 100 +#define UART_NR 1 +#define SERIAL_STMPDBG_MAJOR 204 +#define SERIAL_STMPDBG_MINOR 16 + +#define ISR_PASS_LIMIT 256 + +#define STMPDBG_DEVID "Debug UART" + + +static int force_cd = 1; + +static struct uart_driver stmpdbg_reg; + +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_stmpdbg_port { + struct uart_port port; + struct clk *clk; + unsigned int im; /* interrupt mask */ + unsigned int old_status; + int suspended; +}; + + +static void stmpdbg_stop_tx(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + + uap->im &= ~UART011_TXIM; + __raw_writel(uap->im, uap->port.membase + UART011_IMSC); +} + +static void stmpdbg_start_tx(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + + uap->im |= UART011_TXIM; + __raw_writel(uap->im, uap->port.membase + UART011_IMSC); +} + +static void stmpdbg_stop_rx(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + + uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| + UART011_PEIM|UART011_BEIM|UART011_OEIM); + __raw_writel(uap->im, uap->port.membase + UART011_IMSC); +} + +static void stmpdbg_enable_ms(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + + uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; + __raw_writel(uap->im, uap->port.membase + UART011_IMSC); +} + +static void stmpdbg_rx_chars(struct uart_stmpdbg_port *uap) +{ + struct tty_struct *tty = uap->port.info->port.tty; + unsigned int status, ch, flag, rsr, max_count = 256; + + status = __raw_readl(uap->port.membase + UART01x_FR); + while ((status & UART01x_FR_RXFE) == 0 && max_count--) { +#if 0 + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + if (tty->low_latency) + tty_flip_buffer_push(tty); + /* + * If this failed then we will throw away the + * bytes but must do so to clear interrupts + */ + } +#endif + + ch = __raw_readl(uap->port.membase + UART01x_DR); + flag = TTY_NORMAL; + uap->port.icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + rsr = __raw_readl(uap->port.membase + UART01x_RSR) + | UART_DUMMY_RSR_RX; + if (unlikely(rsr & UART01x_RSR_ANY)) { + if (rsr & UART01x_RSR_BE) { + rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); + uap->port.icount.brk++; + if (uart_handle_break(&uap->port)) + goto ignore_char; + } else if (rsr & UART01x_RSR_PE) + uap->port.icount.parity++; + else if (rsr & UART01x_RSR_FE) + uap->port.icount.frame++; + if (rsr & UART01x_RSR_OE) + uap->port.icount.overrun++; + + rsr &= uap->port.read_status_mask; + + if (rsr & UART01x_RSR_BE) + flag = TTY_BREAK; + else if (rsr & UART01x_RSR_PE) + flag = TTY_PARITY; + else if (rsr & UART01x_RSR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(&uap->port, ch)) + goto ignore_char; + + uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); + +ignore_char: + status = __raw_readl(uap->port.membase + UART01x_FR); + } + tty_flip_buffer_push(tty); + return; +} + +static void stmpdbg_tx_chars(struct uart_stmpdbg_port *uap) +{ + struct circ_buf *xmit = &uap->port.info->xmit; + int count; + + if (uap->port.x_char) { + __raw_writel(uap->port.x_char, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + uap->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + stmpdbg_stop_tx(&uap->port); + return; + } + + count = uap->port.fifosize >> 1; + do { + __raw_writel(xmit->buf[xmit->tail], + uap->port.membase + UART01x_DR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + uap->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + + if (uart_circ_empty(xmit)) + stmpdbg_stop_tx(&uap->port); +} + +static void stmpdbg_modem_status(struct uart_stmpdbg_port *uap) +{ + unsigned int status, delta; + + status = __raw_readl(uap->port.membase + UART01x_FR) & + UART01x_FR_MODEM_ANY; + + delta = status ^ uap->old_status; + uap->old_status = status; + + if (!delta) + return; + + if (delta & UART01x_FR_DCD) + uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); + + if (delta & UART01x_FR_DSR) + uap->port.icount.dsr++; + + if (delta & UART01x_FR_CTS) + uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + + wake_up_interruptible(&uap->port.info->delta_msr_wait); +} + +static irqreturn_t stmpdbg_int(int irq, void *dev_id) +{ + struct uart_stmpdbg_port *uap = dev_id; + unsigned int status, pass_counter = ISR_PASS_LIMIT; + int handled = 0; + + spin_lock(&uap->port.lock); + + status = __raw_readl(uap->port.membase + UART011_MIS); + if (status) { + do { + __raw_writel(status & ~(UART011_TXIS|UART011_RTIS| + UART011_RXIS), + uap->port.membase + UART011_ICR); + + if (status & (UART011_RTIS|UART011_RXIS)) + stmpdbg_rx_chars(uap); + if (status & (UART011_DSRMIS|UART011_DCDMIS| + UART011_CTSMIS|UART011_RIMIS)) + stmpdbg_modem_status(uap); + if (status & UART011_TXIS) + stmpdbg_tx_chars(uap); + + if (pass_counter-- == 0) + break; + + status = __raw_readl(uap->port.membase + UART011_MIS); + } while (status != 0); + handled = 1; + } + + spin_unlock(&uap->port.lock); + + return IRQ_RETVAL(handled); +} + +static unsigned int stmpdbg_tx_empty(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + unsigned int status = __raw_readl(uap->port.membase + UART01x_FR); + return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; +} + +static unsigned int stmpdbg_get_mctrl(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + unsigned int result = 0; + unsigned int status = __raw_readl(uap->port.membase + UART01x_FR); + +#define TEST_AND_SET_BIT(uartbit, tiocmbit) do { \ + if (status & uartbit) \ + result |= tiocmbit; \ + } while (0) + + TEST_AND_SET_BIT(UART01x_FR_DCD, TIOCM_CAR); + TEST_AND_SET_BIT(UART01x_FR_DSR, TIOCM_DSR); + TEST_AND_SET_BIT(UART01x_FR_CTS, TIOCM_CTS); + TEST_AND_SET_BIT(UART011_FR_RI, TIOCM_RNG); +#undef TEST_AND_SET_BIT + if (force_cd) + result |= TIOCM_CAR; + return result; +} + +static void stmpdbg_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + unsigned int cr; + + cr = __raw_readl(uap->port.membase + UART011_CR); + +#define TEST_AND_SET_BIT(tiocmbit, uartbit) do { \ + if (mctrl & tiocmbit) \ + cr |= uartbit; \ + else \ + cr &= ~uartbit; \ + } while (0) + + TEST_AND_SET_BIT(TIOCM_RTS, UART011_CR_RTS); + TEST_AND_SET_BIT(TIOCM_DTR, UART011_CR_DTR); + TEST_AND_SET_BIT(TIOCM_OUT1, UART011_CR_OUT1); + TEST_AND_SET_BIT(TIOCM_OUT2, UART011_CR_OUT2); + TEST_AND_SET_BIT(TIOCM_LOOP, UART011_CR_LBE); +#undef TEST_AND_SET_BIT + + __raw_writel(cr, uap->port.membase + UART011_CR); +} + +static void stmpdbg_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + unsigned long flags; + unsigned int lcr_h; + + spin_lock_irqsave(&uap->port.lock, flags); + lcr_h = __raw_readl(uap->port.membase + UART011_LCRH); + if (break_state == -1) + lcr_h |= UART01x_LCRH_BRK; + else + lcr_h &= ~UART01x_LCRH_BRK; + __raw_writel(lcr_h, uap->port.membase + UART011_LCRH); + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +static int stmpdbg_startup(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + u32 cr, lcr; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(uap->port.irq, stmpdbg_int, 0, STMPDBG_DEVID, uap); + if (retval) + return retval; + + __raw_writel(0, uap->port.membase + UART01x_DR); /* wake up the UART */ + + __raw_writel(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + uap->port.membase + UART011_IFLS); + + /* + * Provoke TX FIFO interrupt into asserting. + */ + cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; + __raw_writel(cr, uap->port.membase + UART011_CR); + + lcr = __raw_readl(uap->port.membase + UART011_LCRH); + lcr |= UART01x_LCRH_FEN; + __raw_writel(lcr, uap->port.membase + UART011_LCRH); + + /* + * initialise the old status of the modem signals + */ + uap->old_status = __raw_readl(uap->port.membase + UART01x_FR) & + UART01x_FR_MODEM_ANY; + + /* + * Finally, enable interrupts + */ + spin_lock_irq(&uap->port.lock); + uap->im = UART011_RXIM | UART011_RTIM; + __raw_writel(uap->im, uap->port.membase + UART011_IMSC); + spin_unlock_irq(&uap->port.lock); + + return 0; +} + +static void stmpdbg_shutdown(struct uart_port *port) +{ + struct uart_stmpdbg_port *uap = (struct uart_stmpdbg_port *)port; + unsigned long val; + + /* + * disable all interrupts + */ + spin_lock_irq(&uap->port.lock); + uap->im = 0; + __raw_writel(uap->im, uap->port.membase + UART011_IMSC); + __raw_writel(0xffff, uap->port.membase + UART011_ICR); + spin_unlock_irq(&uap->port.lock); + + free_irq(uap->port.irq, uap); + + /* + * disable the port + */ + __raw_writel(UART01x_CR_UARTEN | UART011_CR_TXE, + uap->port.membase + UART011_CR); + + /* + * disable break condition and fifos + */ + val = __raw_readl(uap->port.membase + UART011_LCRH); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + __raw_writel(val, uap->port.membase + UART011_LCRH); +} + +static void +stmpdbg_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int lcr_h, old_cr; + unsigned long flags; + unsigned int baud, quot; + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + quot = port->uartclk * 4 / baud; + + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr_h = UART01x_LCRH_WLEN_5; + break; + case CS6: + lcr_h = UART01x_LCRH_WLEN_6; + break; + case CS7: + lcr_h = UART01x_LCRH_WLEN_7; + break; + default: /* CS8 */ + lcr_h = UART01x_LCRH_WLEN_8; + break; + } + if (termios->c_cflag & CSTOPB) + lcr_h |= UART01x_LCRH_STP2; + if (termios->c_cflag & PARENB) { + lcr_h |= UART01x_LCRH_PEN; + if (!(termios->c_cflag & PARODD)) + lcr_h |= UART01x_LCRH_EPS; + } + lcr_h |= UART01x_LCRH_FEN; + + spin_lock_irqsave(&port->lock, flags); + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UART01x_RSR_OE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART01x_RSR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART01x_RSR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART01x_RSR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_RSR_RX; + + if (UART_ENABLE_MS(port, termios->c_cflag)) + stmpdbg_enable_ms(port); + + /* first, disable everything */ + old_cr = __raw_readl(port->membase + UART011_CR); + __raw_writel(0, port->membase + UART011_CR); + + /* Set baud rate */ + __raw_writel(quot & 0x3f, port->membase + UART011_FBRD); + __raw_writel(quot >> 6, port->membase + UART011_IBRD); + + /* + * ----------v----------v----------v----------v----- + * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * ----------^----------^----------^----------^----- + */ + __raw_writel(lcr_h, port->membase + UART011_LCRH); + __raw_writel(old_cr, port->membase + UART011_CR); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *stmpdbg_type(struct uart_port *port) +{ + return port->type == PORT_STMPDBG ? STMPDBG_DEVID : NULL; +} + + +/* + * Release the memory region(s) being used by 'port' + */ +static void stmpdbg_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int stmpdbg_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, STMPDBG_DEVID) + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void stmpdbg_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_STMPDBG; + stmpdbg_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int stmpdbg_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_STMPDBG) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops stmpdbg_pops = { + .tx_empty = stmpdbg_tx_empty, + .set_mctrl = stmpdbg_set_mctrl, + .get_mctrl = stmpdbg_get_mctrl, + .stop_tx = stmpdbg_stop_tx, + .start_tx = stmpdbg_start_tx, + .stop_rx = stmpdbg_stop_rx, + .enable_ms = stmpdbg_enable_ms, + .break_ctl = stmpdbg_break_ctl, + .startup = stmpdbg_startup, + .shutdown = stmpdbg_shutdown, + .set_termios = stmpdbg_set_termios, + .type = stmpdbg_type, + .release_port = stmpdbg_release_port, + .request_port = stmpdbg_request_port, + .config_port = stmpdbg_config_port, + .verify_port = stmpdbg_verify_port, +}; + +static struct uart_stmpdbg_port stmpdbg_ports[UART_NR] = { + { + .port = { + /* This *is* the virtual address */ + .membase = (void *)HW_UARTDBGDR_ADDR, + .mapbase = HW_UARTDBGDR_ADDR, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_DEBUG_UART, + .fifosize = 16, + .ops = &stmpdbg_pops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + .uartclk = 24000000, + }, + } +}; + +#ifdef CONFIG_SERIAL_STMP_DBG_CONSOLE + +static void +stmpdbg_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &stmpdbg_ports[co->index].port; + unsigned int status, old_cr; + int i; + + /* + * First save the CR then disable the interrupts + */ + old_cr = UART_GET_CR(port); + UART_PUT_CR(port, UART01x_CR_UARTEN); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = UART_GET_FR(port); + } while (status & UART01x_FR_BUSY); + UART_PUT_CR(port, old_cr); +} + +static void __init +stmpdbg_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (UART_GET_CR(port) & UART01x_CR_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = UART_GET_LCRH(port); + + *parity = 'n'; + if (lcr_h & UART01x_LCRH_PEN) { + if (lcr_h & UART01x_LCRH_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7) + *bits = 7; + else + *bits = 8; + + quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8; + *baud = port->uartclk / (16 * (quot + 1)); + } +} + +static int __init stmpdbg_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &stmpdbg_ports[co->index].port; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + stmpdbg_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + + +static struct console stmpdbg_console = { + .name = "ttyAM", + .write = stmpdbg_console_write, + .device = uart_console_device, + .setup = stmpdbg_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &stmpdbg_reg, +}; + +static int __init stmpdbg_console_init(void) +{ + /* + * All port initializations are done statically + */ + register_console(&stmpdbg_console); + return 0; +} +console_initcall(stmpdbg_console_init); + +static int __init stmpdbg_late_console_init(void) +{ + if (!(stmpdbg_console.flags & CON_ENABLED)) + register_console(&stmpdbg_console); + return 0; +} +late_initcall(stmpdbg_late_console_init); + +#endif + +static struct uart_driver stmpdbg_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyAM", + .dev_name = "ttyAM", + .major = SERIAL_STMPDBG_MAJOR, + .minor = SERIAL_STMPDBG_MINOR, + .nr = UART_NR, +#ifdef CONFIG_SERIAL_STMP_DBG_CONSOLE + .cons = &stmpdbg_console, +#endif +}; + +static int __devinit stmpdbguart_probe(struct platform_device *device) +{ + int ret = 0; + int i; + void (*cfg)(int request, int port) = NULL; + + if (device->dev.platform_data) + cfg = device->dev.platform_data; + + device_init_wakeup(&device->dev, 1); + + for (i = 0; i < UART_NR; i++) { + stmpdbg_ports[i].clk = clk_get(NULL, "uart"); + if (IS_ERR(stmpdbg_ports[i].clk)) + continue; + stmpdbg_ports[i].suspended = 0; + stmpdbg_ports[i].port.dev = &device->dev; + stmpdbg_ports[i].port.uartclk = + clk_get_rate(stmpdbg_ports[i].clk) * 1000; + if (cfg) + (*cfg)(1, i); + uart_add_one_port(&stmpdbg_reg, &stmpdbg_ports[i].port); + } + return ret; +} + +static int __devexit stmpdbguart_remove(struct platform_device *device) +{ + int i; + void (*cfg)(int request, int port) = NULL; + + if (device->dev.platform_data) + cfg = device->dev.platform_data; + for (i = 0; i < UART_NR; i++) { + clk_put(stmpdbg_ports[i].clk); + uart_remove_one_port(&stmpdbg_reg, &stmpdbg_ports[0].port); + if (cfg) + (*cfg)(0, i); + } + return 0; +} + +static int stmpdbguart_suspend(struct platform_device *device, + pm_message_t state) +{ +#ifdef CONFIG_PM + int i; + int deep_sleep = (stmp37xx_pm_get_target() != PM_SUSPEND_STANDBY); + + for (i = 0; i < UART_NR; i++) { + if (deep_sleep) { + uart_suspend_port(&stmpdbg_reg, + &stmpdbg_ports[i].port); + clk_disable(stmpdbg_ports[i].clk); + stmpdbg_ports[i].suspended = 1; + } + } +#endif + return 0; +} + +static int stmpdbguart_resume(struct platform_device *device) +{ + int ret = 0; +#ifdef CONFIG_PM + int i; + + for (i = 0; i < UART_NR; i++) { + if (stmpdbg_ports[i].suspended) { + clk_enable(stmpdbg_ports[i].clk); + uart_resume_port(&stmpdbg_reg, &stmpdbg_ports[i].port); + } + stmpdbg_ports[i].suspended = 0; + } +#endif + return ret; +} + +static struct platform_driver stmpdbguart_driver = { + .probe = stmpdbguart_probe, + .remove = __devexit_p(stmpdbguart_remove), + .suspend = stmpdbguart_suspend, + .resume = stmpdbguart_resume, + .driver = { + .name = "stmp37xx-dbguart", + .owner = THIS_MODULE, + }, +}; + +static int __init stmpdbg_init(void) +{ + int ret; + + ret = uart_register_driver(&stmpdbg_reg); + if (ret) + goto out; + + ret = platform_driver_register(&stmpdbguart_driver); + if (ret) + uart_unregister_driver(&stmpdbg_reg); +out: + return ret; +} + +static void __exit stmpdbg_exit(void) +{ + platform_driver_unregister(&stmpdbguart_driver); + uart_unregister_driver(&stmpdbg_reg); +} + +module_init(stmpdbg_init); +module_exit(stmpdbg_exit); +module_param(force_cd, int, 0644); +MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd/Sigmatel Inc"); +MODULE_DESCRIPTION("STMP37xx debug uart"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/stmp-dbg.h b/drivers/serial/stmp-dbg.h new file mode 100644 index 000000000000..38f3e6747fb3 --- /dev/null +++ b/drivers/serial/stmp-dbg.h @@ -0,0 +1,180 @@ +/* + * Freescale STMP37XX/STMP378X Debug UART driver + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __STMP_DBG_H +#define __STMP_DBG_H +/* + * UART register offsets + */ +#define UART01x_DR 0x00 /* Data read or written */ +#define UART01x_RSR 0x04 /* Receive status register */ +#define UART01x_ECR 0x04 /* Error clear register (write) */ +#define UART010_LCRH 0x08 /* Line control register, MSB */ +#define UART010_LCRM 0x0C /* Line control register, */ +#define UART010_LCRL 0x10 /* Line control register, LSB */ +#define UART010_CR 0x14 /* Control register. */ +#define UART01x_FR 0x18 /* Flag register (Read only). */ +#define UART010_IIR 0x1C /* Interrupt identification */ +#define UART010_ICR 0x1C /* Interrupt clear register */ +#define UART01x_ILPR 0x20 /* IrDA low power counter */ +#define UART011_IBRD 0x24 /* Integer baud rate divisor */ +#define UART011_FBRD 0x28 /* Fractional baud rate divisor */ +#define UART011_LCRH 0x2c /* Line control */ +#define UART011_CR 0x30 /* Control */ +#define UART011_IFLS 0x34 /* Interrupt fifo level select */ +#define UART011_IMSC 0x38 /* Interrupt mask */ +#define UART011_RIS 0x3c /* Raw */ +#define UART011_MIS 0x40 /* Masked */ +#define UART011_ICR 0x44 /* Interrupt clear register */ +#define UART011_DMACR 0x48 /* DMA control register */ + +#define UART011_DR_OE (1 << 11) +#define UART011_DR_BE (1 << 10) +#define UART011_DR_PE (1 << 9) +#define UART011_DR_FE (1 << 8) + +#define UART01x_RSR_OE 0x08 +#define UART01x_RSR_BE 0x04 +#define UART01x_RSR_PE 0x02 +#define UART01x_RSR_FE 0x01 + +#define UART011_FR_RI 0x100 +#define UART011_FR_TXFE 0x080 +#define UART011_FR_RXFF 0x040 +#define UART01x_FR_TXFF 0x020 +#define UART01x_FR_RXFE 0x010 +#define UART01x_FR_BUSY 0x008 +#define UART01x_FR_DCD 0x004 +#define UART01x_FR_DSR 0x002 +#define UART01x_FR_CTS 0x001 +#define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) + +#define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ +#define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */ +#define UART011_CR_OUT2 0x2000 /* OUT2 */ +#define UART011_CR_OUT1 0x1000 /* OUT1 */ +#define UART011_CR_RTS 0x0800 /* RTS */ +#define UART011_CR_DTR 0x0400 /* DTR */ +#define UART011_CR_RXE 0x0200 /* receive enable */ +#define UART011_CR_TXE 0x0100 /* transmit enable */ +#define UART011_CR_LBE 0x0080 /* loopback enable */ +#define UART010_CR_RTIE 0x0040 +#define UART010_CR_TIE 0x0020 +#define UART010_CR_RIE 0x0010 +#define UART010_CR_MSIE 0x0008 +#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ +#define UART01x_CR_SIREN 0x0002 /* SIR enable */ +#define UART01x_CR_UARTEN 0x0001 /* UART enable */ + +#define UART011_LCRH_SPS 0x80 +#define UART01x_LCRH_WLEN_8 0x60 +#define UART01x_LCRH_WLEN_7 0x40 +#define UART01x_LCRH_WLEN_6 0x20 +#define UART01x_LCRH_WLEN_5 0x00 +#define UART01x_LCRH_FEN 0x10 +#define UART01x_LCRH_STP2 0x08 +#define UART01x_LCRH_EPS 0x04 +#define UART01x_LCRH_PEN 0x02 +#define UART01x_LCRH_BRK 0x01 + +#define UART010_IIR_RTIS 0x08 +#define UART010_IIR_TIS 0x04 +#define UART010_IIR_RIS 0x02 +#define UART010_IIR_MIS 0x01 + +#define UART011_IFLS_RX1_8 (0 << 3) +#define UART011_IFLS_RX2_8 (1 << 3) +#define UART011_IFLS_RX4_8 (2 << 3) +#define UART011_IFLS_RX6_8 (3 << 3) +#define UART011_IFLS_RX7_8 (4 << 3) +#define UART011_IFLS_TX1_8 (0 << 0) +#define UART011_IFLS_TX2_8 (1 << 0) +#define UART011_IFLS_TX4_8 (2 << 0) +#define UART011_IFLS_TX6_8 (3 << 0) +#define UART011_IFLS_TX7_8 (4 << 0) + +/* Interrupt masks */ +#define UART011_OEIM (1 << 10) /* overrun error */ +#define UART011_BEIM (1 << 9) /* break error */ +#define UART011_PEIM (1 << 8) /* parity error */ +#define UART011_FEIM (1 << 7) /* framing error */ +#define UART011_RTIM (1 << 6) /* receive timeout */ +#define UART011_TXIM (1 << 5) /* transmit */ +#define UART011_RXIM (1 << 4) /* receive */ +#define UART011_DSRMIM (1 << 3) /* DSR interrupt mask */ +#define UART011_DCDMIM (1 << 2) /* DCD interrupt mask */ +#define UART011_CTSMIM (1 << 1) /* CTS interrupt mask */ +#define UART011_RIMIM (1 << 0) /* RI interrupt mask */ + +/* Interrupt statuses */ +#define UART011_OEIS (1 << 10) /* overrun error */ +#define UART011_BEIS (1 << 9) /* break error */ +#define UART011_PEIS (1 << 8) /* parity error */ +#define UART011_FEIS (1 << 7) /* framing error */ +#define UART011_RTIS (1 << 6) /* receive timeout */ +#define UART011_TXIS (1 << 5) /* transmit */ +#define UART011_RXIS (1 << 4) /* receive */ +#define UART011_DSRMIS (1 << 3) /* DSR */ +#define UART011_DCDMIS (1 << 2) /* DCD */ +#define UART011_CTSMIS (1 << 1) /* CTS */ +#define UART011_RIMIS (1 << 0) /* RI */ + +/* Interrupt clear masks */ +#define UART011_OEIC (1 << 10) /* overrun error */ +#define UART011_BEIC (1 << 9) /* break error */ +#define UART011_PEIC (1 << 8) /* parity error */ +#define UART011_FEIC (1 << 7) /* framing error */ +#define UART011_RTIC (1 << 6) /* receive timeout */ +#define UART011_TXIC (1 << 5) /* transmit */ +#define UART011_RXIC (1 << 4) /* receive */ +#define UART011_DSRMIC (1 << 3) /* DSR */ +#define UART011_DCDMIC (1 << 2) /* DCD */ +#define UART011_CTSMIC (1 << 1) /* CTS */ +#define UART011_RIMIC (1 << 0) /* RI */ + +#define UART011_DMAONERR (1 << 2) /* disable dma on error */ +#define UART011_TXDMAE (1 << 1) /* enable transmit dma */ +#define UART011_RXDMAE (1 << 0) /* enable receive dma */ + +#define UART01x_RSR_ANY (UART01x_RSR_OE | UART01x_RSR_BE | \ + UART01x_RSR_PE | UART01x_RSR_FE) +#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD | UART01x_FR_DSR | \ + UART01x_FR_CTS) + +/* + * Access macros for the AMBA UARTs + */ +#define UART_GET_INT_STATUS(p) readb((p)->membase + UART010_IIR) +#define UART_PUT_ICR(p, c) writel((c), (p)->membase + UART010_ICR) +#define UART_GET_FR(p) readb((p)->membase + UART01x_FR) +#define UART_GET_CHAR(p) readb((p)->membase + UART01x_DR) +#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + UART01x_DR) +#define UART_GET_RSR(p) readb((p)->membase + UART01x_RSR) +#define UART_GET_CR(p) readb((p)->membase + UART010_CR) +#define UART_PUT_CR(p, c) writel((c), (p)->membase + UART010_CR) +#define UART_GET_LCRL(p) readb((p)->membase + UART010_LCRL) +#define UART_PUT_LCRL(p, c) writel((c), (p)->membase + UART010_LCRL) +#define UART_GET_LCRM(p) readb((p)->membase + UART010_LCRM) +#define UART_PUT_LCRM(p, c) writel((c), (p)->membase + UART010_LCRM) +#define UART_GET_LCRH(p) readb((p)->membase + UART010_LCRH) +#define UART_PUT_LCRH(p, c) writel((c), (p)->membase + UART010_LCRH) +#define UART_RX_DATA(s) (((s) & UART01x_FR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & UART01x_FR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART01x_FR_TMSK) == 0) + +#define UART_DUMMY_RSR_RX /*256*/0 +#define UART_PORT_SIZE 64 + +#endif /* STMP_DBG_H */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d1dc257eb488..10c2c9c60409 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -232,6 +232,12 @@ config SPI_MXC_SELECT3 depends on SPI_MXC && (ARCH_MX3 || ARCH_MX27 || ARCH_MX25 || ARCH_MX37 || ARCH_MX51) default n +config SPI_STMP3XXX + tristate "Freescale STMP37xx/378x SPI/SSP controller" + depends on ARCH_STMP3XXX && SPI_MASTER + help + SPI driver for Freescale STMP37xx/378x SoC SSP interface + # # Add new SPI master controllers in alphabetical order above this line # diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 2c0e8e0a8d26..87d6b79b395d 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_MXC) += mxc_spi.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o +obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git a/drivers/spi/spi_stmp.c b/drivers/spi/spi_stmp.c new file mode 100644 index 000000000000..a0ae2087fdbb --- /dev/null +++ b/drivers/spi/spi_stmp.c @@ -0,0 +1,693 @@ +/* + * Freescale STMP378X SPI master driver + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <asm/dma.h> + +#include <mach/stmp3xxx.h> +#include <mach/regs-ssp.h> +#include <mach/regs-apbh.h> +#include "spi_stmp.h" + +/* 0 means DMA modei(recommended, default), !0 - PIO mode */ +static int pio /* = 0 */; +static int debug; + +/** + * stmp_spi_init_hw + * + * Initialize the SSP port + */ +static int stmp_spi_init_hw(struct stmp_spi *ss) +{ + int err; + + err = stmp37xx_spi_pins_request(ss->master_dev->bus_id, ss->id); + if (err) + goto out; + + ss->clk = clk_get(NULL, "ssp"); + if (IS_ERR(ss->clk)) { + err = PTR_ERR(ss->clk); + goto out_free_pins; + } + clk_enable(ss->clk); + + stmp3xxx_reset_block(ss->regs, 0); + stmp3xxx_dma_reset_channel(ss->dma); + + return 0; + +out_free_pins: + stmp37xx_spi_pins_release(ss->master_dev->bus_id, ss->id); +out: + return err; +} + +static void stmp_spi_release_hw(struct stmp_spi *ss) +{ + if (ss->clk && !IS_ERR(ss->clk)) { + clk_disable(ss->clk); + clk_put(ss->clk); + } + stmp37xx_spi_pins_release(ss->master_dev->bus_id, ss->id); +} + +static int stmp_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + u8 bits_per_word; + u32 hz; + struct stmp_spi *ss /* = spi_master_get_devdata(spi->master) */; + u16 rate; + + ss = spi_master_get_devdata(spi->master); + + bits_per_word = spi->bits_per_word; + if (t && t->bits_per_word) + bits_per_word = t->bits_per_word; + + /* + Calculate speed: + - by default, use maximum speed from ssp clk + - if device overrides it, use it + - if transfer specifies other speed, use transfer's one + */ + hz = 1000 * ss->speed_khz / ss->divider; + if (spi->max_speed_hz) + hz = min(hz, spi->max_speed_hz); + if (t && t->speed_hz) + hz = min(hz, t->speed_hz); + + if (hz == 0) { + dev_err(&spi->dev, "Cannot continue with zero clock\n"); + return -EINVAL; + } + + if (bits_per_word != 8) { + dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", + __func__, bits_per_word); + return -EINVAL; + } + + dev_dbg(&spi->dev, "Requested clk rate = %uHz, max = %uHz/%d = %uHz\n", + hz, ss->speed_khz, ss->divider, + ss->speed_khz * 1000 / ss->divider); + + if (ss->speed_khz * 1000 / ss->divider < hz) { + dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n", + __func__, hz); + return -EINVAL; + } + + rate = 1000 * ss->speed_khz/ss->divider/hz; + + HW_SSP_TIMING_WR_NB(ss->regs, + BF_SSP_TIMING_CLOCK_DIVIDE(ss->divider) | + BF_SSP_TIMING_CLOCK_RATE(rate - 1)); + + HW_SSP_CTRL1_WR_NB(ss->regs, + BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) | + BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | + ((spi->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | + ((spi->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0) | + (pio ? 0 : BM_SSP_CTRL1_DMA_ENABLE)); + + HW_SSP_CMD0_SET(0x00); + + return 0; +} + + +static void stmp_spi_cleanup(struct spi_device *spi) +{ + struct stmp37xx_spi_platform_data *pdata = spi->dev.platform_data; + + if (pdata && pdata->hw_release) + pdata->hw_release(spi); +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA) +static int stmp_spi_setup(struct spi_device *spi) +{ + struct stmp37xx_spi_platform_data *pdata; + struct stmp_spi *ss; + int err = 0; + + ss = spi_master_get_devdata(spi->master); + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + if (spi->mode & ~MODEBITS) { + dev_err(&spi->dev, "%s: unsupported mode bits %x\n", + __func__, spi->mode & ~MODEBITS); + err = -EINVAL; + goto out; + } + + dev_dbg(&spi->dev, "%s, mode %d, %u bits/w\n", + __func__, spi->mode & MODEBITS, spi->bits_per_word); + + pdata = spi->dev.platform_data; + + if (pdata && pdata->hw_init) { + err = pdata->hw_init(spi); + if (err) + goto out; + } + + err = stmp_spi_setup_transfer(spi, NULL); + if (err) + goto out2; + return 0; + +out2: + if (pdata) + pdata->hw_release(spi); +out: + dev_err(&spi->dev, "Failed to setup transfer, error = %d\n", err); + return err; +} + +static inline u32 stmp_spi_cs(unsigned cs) +{ + return ((cs & 1) ? BM_SSP_CTRL0_WAIT_FOR_CMD : 0) | + ((cs & 2) ? BM_SSP_CTRL0_WAIT_FOR_IRQ : 0); +} + +static int stmp_spi_txrx_dma(struct stmp_spi *ss, int cs, + unsigned char *buf, dma_addr_t dma_buf, int len, + int *first, int *last, int write) +{ + u32 c0 = 0; + dma_addr_t spi_buf_dma = dma_buf; + int count, status = 0; + enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + c0 |= (*first ? BM_SSP_CTRL0_LOCK_CS : 0); + c0 |= (*last ? BM_SSP_CTRL0_IGNORE_CRC : 0); + c0 |= (write ? 0 : BM_SSP_CTRL0_READ); + c0 |= BM_SSP_CTRL0_DATA_XFER; + + c0 |= stmp_spi_cs(cs); + + c0 |= BF_SSP_CTRL0_XFER_COUNT(len); + + if (!dma_buf) + spi_buf_dma = dma_map_single(ss->master_dev, buf, len, dir); + + ss->d.command->cmd = + BF_APBH_CHn_CMD_XFER_COUNT(len) | + BF_APBH_CHn_CMD_CMDWORDS(1) | + BM_APBH_CHn_CMD_WAIT4ENDCMD | + BM_APBH_CHn_CMD_IRQONCMPLT | + BF_APBH_CHn_CMD_COMMAND( + write ? BV_APBH_CHn_CMD_COMMAND__DMA_READ : + BV_APBH_CHn_CMD_COMMAND__DMA_WRITE); + ss->d.command->pio_words[0] = c0; + ss->d.command->buf_ptr = spi_buf_dma; + + stmp3xxx_dma_reset_channel(ss->dma); + stmp3xxx_dma_clear_interrupt(ss->dma); + stmp3xxx_dma_enable_interrupt(ss->dma); + init_completion(&ss->done); + stmp3xxx_dma_go(ss->dma, &ss->d, 1); + wait_for_completion(&ss->done); + count = 10000; + while ((HW_SSP_CTRL0_RD() & BM_SSP_CTRL0_RUN) && count--) + continue; + if (count <= 0) { + printk(KERN_ERR"%c: timeout on line %s:%d\n", + write ? 'W':'C', __func__, __LINE__); + status = -ETIMEDOUT; + } + + if (!dma_buf) + dma_unmap_single(ss->master_dev, spi_buf_dma, len, dir); + + return status; +} + +static inline void stmp_spi_enable(struct stmp_spi *ss) +{ + HW_SSP_CTRL0_SET_NB(ss->regs, BM_SSP_CTRL0_LOCK_CS); + HW_SSP_CTRL0_CLR_NB(ss->regs, BM_SSP_CTRL0_IGNORE_CRC); +} + +static inline void stmp_spi_disable(struct stmp_spi *ss) +{ + HW_SSP_CTRL0_CLR_NB(ss->regs, BM_SSP_CTRL0_LOCK_CS); + HW_SSP_CTRL0_SET_NB(ss->regs, BM_SSP_CTRL0_IGNORE_CRC); +} + +static int stmp_spi_txrx_pio(struct stmp_spi *ss, int cs, + unsigned char *buf, int len, + int *first, int *last, int write) +{ + int count; + + if (*first) { + stmp_spi_enable(ss); + *first = 0; + } + + HW_SSP_CTRL0_SET(stmp_spi_cs(cs)); + + while (len--) { + if (*last && len == 0) { + stmp_spi_disable(ss); + *last = 0; + } + HW_SSP_CTRL0_CLR_NB(ss->regs, BM_SSP_CTRL0_XFER_COUNT); + HW_SSP_CTRL0_SET_NB(ss->regs, 1); /* byte-by-byte */ + + if (write) + HW_SSP_CTRL0_CLR_NB(ss->regs, BM_SSP_CTRL0_READ); + else + HW_SSP_CTRL0_SET_NB(ss->regs, BM_SSP_CTRL0_READ); + + /* Run! */ + HW_SSP_CTRL0_SET_NB(ss->regs, BM_SSP_CTRL0_RUN); + count = 10000; + while (((HW_SSP_CTRL0_RD() & BM_SSP_CTRL0_RUN) == 0) && count--) + continue; + if (count <= 0) { + printk(KERN_ERR"%c: timeout on line %s:%d\n", + write ? 'W':'C', __func__, __LINE__); + break; + } + + if (write) + HW_SSP_DATA_WR_NB(ss->regs, *buf); + + /* Set TRANSFER */ + HW_SSP_CTRL0_SET_NB(ss->regs, BM_SSP_CTRL0_DATA_XFER); + + if (!write) { + count = 10000; + while (count-- && + (HW_SSP_STATUS_RD_NB(ss->regs) & + BM_SSP_STATUS_FIFO_EMPTY)) + continue; + if (count <= 0) { + printk(KERN_ERR"%c: timeout on line %s:%d\n", + write ? 'W':'C', __func__, __LINE__); + break; + } + *buf = (HW_SSP_DATA_RD_NB(ss->regs) & 0xFF); + } + + count = 10000; + while ((HW_SSP_CTRL0_RD() & BM_SSP_CTRL0_RUN) && count--) + continue; + if (count <= 0) { + printk(KERN_ERR"%c: timeout on line %s:%d\n", + write ? 'W':'C', __func__, __LINE__); + break; + } + + /* advance to the next byte */ + buf++; + } + return len < 0 ? 0 : -ETIMEDOUT; +} + +static int stmp_spi_handle_message(struct stmp_spi *ss, struct spi_message *m) +{ + int first, last; + struct spi_transfer *t, *tmp_t; + int status = 0; + int cs; + + first = last = 0; + + cs = m->spi->chip_select; + + list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { + + stmp_spi_setup_transfer(m->spi, t); + + if (&t->transfer_list == m->transfers.next) + first = !0; + if (&t->transfer_list == m->transfers.prev) + last = !0; + if (t->rx_buf && t->tx_buf) { + pr_debug("%s: cannot send and receive simultaneously\n", + __func__); + return -EINVAL; + } + + /* + REVISIT: + here driver completely ignores setting of t->cs_change + */ + if (t->tx_buf) { + status = pio ? + stmp_spi_txrx_pio(ss, cs, (void *)t->tx_buf, + t->len, &first, &last, 1) : + stmp_spi_txrx_dma(ss, cs, (void *)t->tx_buf, + t->tx_dma, t->len, &first, &last, 1); + if (debug) { + if (t->len < 0x10) + print_hex_dump_bytes("Tx ", + DUMP_PREFIX_OFFSET, + t->tx_buf, t->len); + else + pr_debug("Tx: %d bytes\n", t->len); + } + } + if (t->rx_buf) { + status = pio ? + stmp_spi_txrx_pio(ss, cs, t->rx_buf, + t->len, &first, &last, 0): + stmp_spi_txrx_dma(ss, cs, t->rx_buf, + t->rx_dma, t->len, &first, &last, 0); + if (debug) { + if (t->len < 0x10) + print_hex_dump_bytes("Rx ", + DUMP_PREFIX_OFFSET, + t->rx_buf, t->len); + else + pr_debug("Rx: %d bytes\n", t->len); + } + } + + if (status) + break; + + first = last = 0; + + } + return status; +} + +/** + * stmp_spi_handle + * + * The workhorse of the driver - it handles messages from the list + * + **/ +static void stmp_spi_handle(struct work_struct *w) +{ + struct stmp_spi *ss = container_of(w, struct stmp_spi, work); + unsigned long flags; + struct spi_message *m; + + BUG_ON(w == NULL); + + spin_lock_irqsave(&ss->lock, flags); + while (!list_empty(&ss->queue)) { + m = list_entry(ss->queue.next, struct spi_message, queue); + list_del_init(&m->queue); + spin_unlock_irqrestore(&ss->lock, flags); + + m->status = stmp_spi_handle_message(ss, m); + if (m->complete) + m->complete(m->context); + + spin_lock_irqsave(&ss->lock, flags); + } + spin_unlock_irqrestore(&ss->lock, flags); + + return; +} + +/** + * stmp_spi_transfer + * + * Called indirectly from spi_async, queues all the messages to + * spi_handle_message + * + * @spi: spi device + * @m: message to be queued +**/ +static int stmp_spi_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct stmp_spi *ss = spi_master_get_devdata(spi->master); + unsigned long flags; + + m->status = -EINPROGRESS; + spin_lock_irqsave(&ss->lock, flags); + list_add_tail(&m->queue, &ss->queue); + queue_work(ss->workqueue, &ss->work); + spin_unlock_irqrestore(&ss->lock, flags); + return 0; +} + +static irqreturn_t stmp_spi_irq(int irq, void *dev_id) +{ + struct stmp_spi *ss = dev_id; + + stmp3xxx_dma_clear_interrupt(ss->dma); + complete(&ss->done); + return IRQ_HANDLED; +} + +static irqreturn_t stmp_spi_irq_err(int irq, void *dev_id) +{ + struct stmp_spi *ss = dev_id; + u32 c1, st; + + c1 = HW_SSP_CTRL1_RD_NB(ss->regs); + st = HW_SSP_STATUS_RD_NB(ss->regs); + printk(KERN_ERR"IRQ - ERROR!, status = 0x%08X, c1 = 0x%08X\n", st, c1); + HW_SSP_CTRL1_CLR_NB(ss->regs, c1 & 0xCCCC0000); + + return IRQ_HANDLED; +} + +static int __init stmp_spi_probe(struct platform_device *dev) +{ + int err = 0; + struct spi_master *master; + struct stmp_spi *ss; + struct resource *r; + u32 mem; + + /* Get resources(memory, IRQ) associated with the device */ + master = spi_alloc_master(&dev->dev, sizeof(struct stmp_spi)); + + if (master == NULL) { + err = -ENOMEM; + goto out0; + } + + platform_set_drvdata(dev, master); + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (r == NULL) { + err = -ENODEV; + goto out_put_master; + } + + ss = spi_master_get_devdata(master); + ss->master_dev = &dev->dev; + ss->id = dev->id; + + INIT_WORK(&ss->work, stmp_spi_handle); + INIT_LIST_HEAD(&ss->queue); + spin_lock_init(&ss->lock); + ss->workqueue = create_singlethread_workqueue(dev->dev.bus_id); + master->transfer = stmp_spi_transfer; + master->setup = stmp_spi_setup; + master->cleanup = stmp_spi_cleanup; + + if (!request_mem_region(r->start, + r->end - r->start + 1, dev->dev.bus_id)) { + err = -ENXIO; + goto out_put_master; + } + mem = r->start; + + ss->regs = r->start; + + ss->irq = platform_get_irq(dev, 0); + if (ss->irq < 0) { + err = -ENXIO; + goto out_put_master; + } + + r = platform_get_resource(dev, IORESOURCE_DMA, 0); + if (r == NULL) { + err = -ENODEV; + goto out_put_master; + } + + ss->dma = r->start; + err = stmp3xxx_dma_request(ss->dma, &dev->dev, dev->dev.bus_id); + if (err) + goto out_put_master; + + err = stmp3xxx_dma_allocate_command(ss->dma, &ss->d); + if (err) + goto out_free_dma; + + master->bus_num = dev->id; + master->num_chipselect = 1; + + /* SPI controller initializations */ + err = stmp_spi_init_hw(ss); + if (err) { + dev_dbg(&dev->dev, "cannot initialize hardware\n"); + goto out_free_dma_desc; + } + + clk_set_rate(ss->clk, 120000); + ss->speed_khz = clk_get_rate(ss->clk); + ss->divider = 2; + dev_info(&dev->dev, "Max possible speed %d = %ld/%d kHz\n", + ss->speed_khz, clk_get_rate(ss->clk), ss->divider); + + /* Register for SPI Interrupt */ + err = request_irq(ss->irq, stmp_spi_irq, 0, + dev->dev.bus_id, ss); + if (err) { + dev_dbg(&dev->dev, "request_irq failed, %d\n", err); + goto out_release_hw; + } + err = request_irq(IRQ_SSP_ERROR, stmp_spi_irq_err, IRQF_SHARED, + dev->dev.bus_id, ss); + if (err) { + dev_dbg(&dev->dev, "request_irq(error) failed, %d\n", err); + goto out_free_irq; + } + + err = spi_register_master(master); + if (err) { + dev_dbg(&dev->dev, "cannot register spi master, %d\n", err); + goto out_free_irq_2; + } + dev_info(&dev->dev, "at 0x%08X mapped to 0x%08X, irq=%d, bus %d, %s\n", + mem, (u32)ss->regs, ss->irq, + master->bus_num, pio ? "PIO" : "DMA"); + return 0; + +out_free_irq_2: + free_irq(IRQ_SSP_ERROR, ss); +out_free_irq: + free_irq(ss->irq, ss); +out_free_dma_desc: + stmp3xxx_dma_free_command(ss->dma, &ss->d); +out_free_dma: + stmp3xxx_dma_release(ss->dma); +out_release_hw: + stmp_spi_release_hw(ss); +out_put_master: + spi_master_put(master); +out0: + return err; +} + +static int __devexit stmp_spi_remove(struct platform_device *dev) +{ + struct stmp_spi *ss; + struct spi_master *master; + + master = platform_get_drvdata(dev); + if (master == NULL) + goto out0; + ss = spi_master_get_devdata(master); + if (ss == NULL) + goto out1; + free_irq(ss->irq, ss); + if (ss->workqueue) + destroy_workqueue(ss->workqueue); + stmp3xxx_dma_free_command(ss->dma, &ss->d); + stmp3xxx_dma_release(ss->dma); + stmp_spi_release_hw(ss); + platform_set_drvdata(dev, 0); +out1: + spi_master_put(master); +out0: + return 0; +} + +#ifdef CONFIG_PM +static int stmp_spi_suspend(struct platform_device *pdev, pm_message_t pmsg) +{ + struct stmp_spi *ss; + struct spi_master *master; + + master = platform_get_drvdata(pdev); + ss = spi_master_get_devdata(master); + + ss->saved_timings = HW_SSP_TIMING_RD_NB(ss->regs); + clk_disable(ss->clk); + + return 0; +} + +static int stmp_spi_resume(struct platform_device *pdev) +{ + struct stmp_spi *ss; + struct spi_master *master; + + master = platform_get_drvdata(pdev); + ss = spi_master_get_devdata(master); + + clk_enable(ss->clk); + HW_SSP_CTRL0_CLR_NB(ss->regs, + BM_SSP_CTRL0_SFTRST | BM_SSP_CTRL0_CLKGATE); + HW_SSP_TIMING_SET_NB(ss->regs, ss->saved_timings); + + return 0; +} + +#else +#define stmp_spi_suspend NULL +#define stmp_spi_resume NULL +#endif + +static struct platform_driver stmp_spi_driver = { + .probe = stmp_spi_probe, + .remove = __devexit_p(stmp_spi_remove), + .driver = { + .name = "stmp37xx_ssp", + .owner = THIS_MODULE, + }, + .suspend = stmp_spi_suspend, + .resume = stmp_spi_resume, +}; + +static int __init stmp_spi_init(void) +{ + return platform_driver_register(&stmp_spi_driver); +} + +static void __exit stmp_spi_exit(void) +{ + platform_driver_unregister(&stmp_spi_driver); +} + +module_init(stmp_spi_init); +module_exit(stmp_spi_exit); +module_param(pio, int, S_IRUGO); +module_param(debug, int, S_IRUGO); +MODULE_AUTHOR("dmitry pervushin <dimka@embeddedalley.com>"); +MODULE_DESCRIPTION("STMP37xx SPI/SSP"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi_stmp.h b/drivers/spi/spi_stmp.h new file mode 100644 index 000000000000..aef6fac2747e --- /dev/null +++ b/drivers/spi/spi_stmp.h @@ -0,0 +1,49 @@ +/* + * Freescale STMP378X SPI master driver + * + * Author: dmitry pervushin <dimka@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __SPI_STMP_H +#define __SPI_STMP_H + +/* These two come from arch/arm/mach-xxxxx/spi.c */ +int stmp37xx_spi_pins_request(char *id, int ssp); +void stmp37xx_spi_pins_release(char *id, int ssp); + +struct stmp_spi { + int id; + + u32 regs; /* vaddr of the control registers */ + + u32 irq; + u32 dma; + struct stmp3xxx_dma_descriptor d; + + u32 speed_khz; + u32 saved_timings; + u32 divider; + + struct clk *clk; + struct device *master_dev; + + struct work_struct work; + struct workqueue_struct *workqueue; + spinlock_t lock; + struct list_head queue; + + struct completion done; +}; + +#endif /* __SPI_STMP_H */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 259de31c0dca..f8808cdd2403 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1978,6 +1978,16 @@ config FB_PNX4008_DUM_RGB ---help--- Say Y here to enable support for PNX4008 RGB Framebuffer +config FB_STMP37XX + tristate "STMP 37XX LCD Framebuffer driver" + depends on FB && (ARCH_STMP37XX || ARCH_STMP378X) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Say Y here to enable support for the framebuffer driver for the + Sigmatel STMP37XX board. + config FB_IBM_GXT4500 tristate "Framebuffer support for IBM GXT4500P adaptor" depends on FB && PPC diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 29613d5c4792..28171b7f826f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_MXC) += mxc/ +obj-$(CONFIG_FB_STMP37XX) += stmp37xxfb.o obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 82f2f07e1915..c24696c0f7a7 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -243,6 +243,14 @@ config BACKLIGHT_MXC_MC13892 depends on BACKLIGHT_MXC && MXC_MC13892_LIGHT default y +config BACKLIGHT_STMP37XX + tristate "SigmaTel STMP37xx Backlight Driver" + depends on BACKLIGHT_CLASS_DEVICE && (ARCH_STMP37XX || ARCH_STMP378X) + default y + help + If you have a STMP37xx, say y to enable the + backlight driver. + config BACKLIGHT_WM8350 tristate "WM8350 Backlight Driver" depends on BACKLIGHT_MXC && REGULATOR_WM8350 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 83c1a38d5314..4d1f076e49a6 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_BACKLIGHT_MXC_IPU) += mxc_ipu_bl.o obj-$(CONFIG_BACKLIGHT_MXC_PMIC) += mxc_pmic_bl.o obj-$(CONFIG_BACKLIGHT_WM8350) += wm8350_bl.o obj-$(CONFIG_BACKLIGHT_MXC_MC13892) += mxc_mc13892_bl.o +obj-$(CONFIG_BACKLIGHT_STMP37XX) += stmp37xx_bl.o diff --git a/drivers/video/backlight/stmp37xx_bl.c b/drivers/video/backlight/stmp37xx_bl.c new file mode 100644 index 000000000000..4a7775b41d42 --- /dev/null +++ b/drivers/video/backlight/stmp37xx_bl.c @@ -0,0 +1,378 @@ +/* + * Backlight Driver for Freescale STMP37XX/STMP378X + * + * Embedded Alley Solutions, Inc <source@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/fb.h> +#include <linux/backlight.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/regulator/consumer.h> + +#include <mach/lcdif.h> +#include <mach/regulator.h> + +struct stmp3xxx_bl_data { + struct notifier_block nb; + struct notifier_block reg_nb; + struct notifier_block reg_init_nb; + struct backlight_device *bd; + struct stmp3xxx_platform_bl_data *pdata; + int current_intensity; + int saved_intensity; + int stmp3xxxbl_suspended; + int stmp3xxxbl_constrained; +}; + +static int stmp3xxxbl_do_probe(struct stmp3xxx_bl_data *data, + struct stmp3xxx_platform_bl_data *pdata); +static int stmp3xxxbl_set_intensity(struct backlight_device *bd); +static inline void bl_register_reg(struct stmp3xxx_platform_bl_data *pdata, + struct stmp3xxx_bl_data *data); + + +/* + * If we got here init is done + */ +static int bl_init_reg_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct stmp3xxx_bl_data *bdata; + struct stmp3xxx_platform_bl_data *pdata; + struct regulator *r = regulator_get(NULL, "stmp3xxx-bl-1"); + + bdata = container_of(self, struct stmp3xxx_bl_data, reg_init_nb); + pdata = bdata->pdata; + + if (r && !IS_ERR(r)) + regulator_put(r); + else + goto out; + + bl_register_reg(pdata, bdata); + + if (pdata->regulator) { + + printk(KERN_NOTICE"%s: setting intensity\n", __func__); + + bus_unregister_notifier(&platform_bus_type, + &bdata->reg_init_nb); + mutex_lock(&bdata->bd->ops_lock); + stmp3xxxbl_set_intensity(bdata->bd); + mutex_unlock(&bdata->bd->ops_lock); + } + +out: + return 0; +} + +static int bl_reg_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct stmp3xxx_bl_data *bdata; + struct stmp3xxx_platform_bl_data *pdata; + bdata = container_of(self, struct stmp3xxx_bl_data, reg_nb); + pdata = bdata->pdata; + + mutex_lock(&bdata->bd->ops_lock); + + switch (event) { + case STMP3XXX_REG5V_IS_USB: + bdata->bd->props.max_brightness = pdata->bl_cons_intensity; + bdata->bd->props.brightness = pdata->bl_cons_intensity; + bdata->saved_intensity = bdata->current_intensity; + bdata->stmp3xxxbl_constrained = 1; + break; + case STMP3XXX_REG5V_NOT_USB: + bdata->bd->props.max_brightness = pdata->bl_max_intensity; + bdata->bd->props.brightness = bdata->saved_intensity; + bdata->stmp3xxxbl_constrained = 0; + break; + } + + stmp3xxxbl_set_intensity(bdata->bd); + mutex_unlock(&bdata->bd->ops_lock); + return 0; +} + +static inline void bl_unregister_reg(struct stmp3xxx_platform_bl_data *pdata, + struct stmp3xxx_bl_data *data) +{ + if (!pdata) + return; + if (pdata->regulator) + regulator_register_notifier(pdata->regulator, + &data->reg_nb); + if (pdata->regulator) + regulator_put(pdata->regulator); + pdata->regulator = NULL; +} + +static inline void bl_register_reg(struct stmp3xxx_platform_bl_data *pdata, + struct stmp3xxx_bl_data *data) +{ + pdata->regulator = regulator_get(NULL, "stmp3xxx-bl-1"); + if (pdata->regulator && !IS_ERR(pdata->regulator)) { + regulator_set_mode(pdata->regulator, REGULATOR_MODE_FAST); + if (pdata->regulator) { + data->reg_nb.notifier_call = bl_reg_callback; + regulator_register_notifier(pdata->regulator, + &data->reg_nb); + } + } else{ + printk(KERN_ERR "%s: failed to get regulator\n", __func__); + pdata->regulator = NULL; + } + +} + +static int bl_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct stmp3xxx_platform_fb_entry *pentry = data; + struct stmp3xxx_bl_data *bdata; + struct stmp3xxx_platform_bl_data *pdata; + + switch (event) { + case STMP3XXX_LCDIF_PANEL_INIT: + bdata = container_of(self, struct stmp3xxx_bl_data, nb); + pdata = pentry->bl_data; + bdata->pdata = pdata; + if (pdata) { + bl_register_reg(pdata, bdata); + if (!pdata->regulator) { + /* wait for regulator to appear */ + bdata->reg_init_nb.notifier_call = + bl_init_reg_callback; + bus_register_notifier(&platform_bus_type, + &bdata->reg_init_nb); + } + return stmp3xxxbl_do_probe(bdata, pdata); + } + break; + + case STMP3XXX_LCDIF_PANEL_RELEASE: + bdata = container_of(self, struct stmp3xxx_bl_data, nb); + pdata = pentry->bl_data; + if (pdata) { + bus_unregister_notifier(&platform_bus_type, + &bdata->reg_init_nb); + bl_unregister_reg(pdata, bdata); + pdata->free_bl(pdata); + } + bdata->pdata = NULL; + break; + } + return 0; +} + +#ifdef CONFIG_PM +static int stmp3xxxbl_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct stmp3xxx_bl_data *data = platform_get_drvdata(pdev); + struct stmp3xxx_platform_bl_data *pdata = data->pdata; + + data->stmp3xxxbl_suspended = 1; + if (pdata) { + dev_dbg(&pdev->dev, "real suspend\n"); + stmp3xxxbl_set_intensity(data->bd); + } + return 0; +} + +static int stmp3xxxbl_resume(struct platform_device *pdev) +{ + struct stmp3xxx_bl_data *data = platform_get_drvdata(pdev); + struct stmp3xxx_platform_bl_data *pdata = data->pdata; + int ret = 0; + + data->stmp3xxxbl_suspended = 0; + if (pdata) { + dev_dbg(&pdev->dev, "real resume\n"); + pdata->free_bl(pdata); + ret = pdata->init_bl(pdata); + if (ret) + goto out; + stmp3xxxbl_set_intensity(data->bd); + } +out: + return ret; +} +#else +#define stmp3xxxbl_suspend NULL +#define stmp3xxxbl_resume NULL +#endif +/* + * This function should be called with bd->ops_lock held + * Suspend/resume ? + */ +static int stmp3xxxbl_set_intensity(struct backlight_device *bd) +{ + struct platform_device *pdev = dev_get_drvdata(&bd->dev); + struct stmp3xxx_bl_data *data = platform_get_drvdata(pdev); + struct stmp3xxx_platform_bl_data *pdata = data->pdata; + + if (pdata) { + int ret; + + ret = pdata->set_bl_intensity(pdata, bd, + data->stmp3xxxbl_suspended); + if (ret) + bd->props.brightness = data->current_intensity; + else + data->current_intensity = bd->props.brightness; + return ret; + } else + return -ENODEV; +} + +static int stmp3xxxbl_get_intensity(struct backlight_device *bd) +{ + struct platform_device *pdev = dev_get_drvdata(&bd->dev); + struct stmp3xxx_bl_data *data = platform_get_drvdata(pdev); + + return data->current_intensity; +} + +static struct backlight_ops stmp3xxxbl_ops = { + .get_brightness = stmp3xxxbl_get_intensity, + .update_status = stmp3xxxbl_set_intensity, +}; + +static int stmp3xxxbl_do_probe(struct stmp3xxx_bl_data *data, + struct stmp3xxx_platform_bl_data *pdata) +{ + int ret = pdata->init_bl(pdata); + + if (ret) + goto out; + + data->bd->props.power = FB_BLANK_UNBLANK; + data->bd->props.fb_blank = FB_BLANK_UNBLANK; + if (data->stmp3xxxbl_constrained) { + data->bd->props.max_brightness = pdata->bl_cons_intensity; + data->bd->props.brightness = pdata->bl_cons_intensity; + } else { + data->bd->props.max_brightness = pdata->bl_max_intensity; + data->bd->props.brightness = pdata->bl_default_intensity; + } + + data->pdata = pdata; + stmp3xxxbl_set_intensity(data->bd); + +out: + return ret; +} + +static int __init stmp3xxxbl_probe(struct platform_device *pdev) +{ + struct stmp3xxx_bl_data *data; + struct stmp3xxx_platform_bl_data *pdata = pdev->dev.platform_data; + int ret = 0; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + data->bd = backlight_device_register(pdev->name, &pdev->dev, pdev, + &stmp3xxxbl_ops); + if (IS_ERR(data->bd)) { + ret = PTR_ERR(data->bd); + goto out_1; + } + + get_device(&pdev->dev); + + data->nb.notifier_call = bl_callback; + stmp3xxx_lcdif_register_client(&data->nb); + platform_set_drvdata(pdev, data); + + if (pdata) { + ret = stmp3xxxbl_do_probe(data, pdata); + if (ret) + goto out_2; + } + + goto out; + +out_2: + put_device(&pdev->dev); +out_1: + kfree(data); +out: + return ret; +} + +static int stmp3xxxbl_remove(struct platform_device *pdev) +{ + struct stmp3xxx_platform_bl_data *pdata = pdev->dev.platform_data; + struct stmp3xxx_bl_data *data = platform_get_drvdata(pdev); + struct backlight_device *bd = data->bd; + + bd->props.power = FB_BLANK_POWERDOWN; + bd->props.fb_blank = FB_BLANK_POWERDOWN; + bd->props.brightness = 0; + data->current_intensity = bd->props.brightness; + + if (pdata) { + pdata->set_bl_intensity(pdata, bd, data->stmp3xxxbl_suspended); + if (pdata->free_bl) + pdata->free_bl(pdata); + } + backlight_device_unregister(bd); + if (pdata->regulator) + regulator_put(pdata->regulator); + put_device(&pdev->dev); + platform_set_drvdata(pdev, NULL); + stmp3xxx_lcdif_unregister_client(&data->nb); + kfree(data); + + return 0; +} + +static struct platform_driver stmp3xxxbl_driver = { + .probe = stmp3xxxbl_probe, + .remove = __devexit_p(stmp3xxxbl_remove), + .suspend = stmp3xxxbl_suspend, + .resume = stmp3xxxbl_resume, + .driver = { + .name = "stmp3xxx-bl", + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxx_init(void) +{ + return platform_driver_register(&stmp3xxxbl_driver); +} + +static void __exit stmp3xxx_exit(void) +{ + platform_driver_unregister(&stmp3xxxbl_driver); +} + +module_init(stmp3xxx_init); +module_exit(stmp3xxx_exit); + +MODULE_AUTHOR("Embedded Alley Solutions, Inc <sources@embeddedalley.com>"); +MODULE_DESCRIPTION("STMP3xxx Backlight Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index d3c3af53a290..4fc9bcd1b6e1 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -220,6 +220,10 @@ static const struct fb_videomode modedb[] = { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0, FB_VMODE_DOUBLE }, { + /* 480x272 @ 60 Hz, 31.5 kHz hsync */ + NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, + 0, FB_VMODE_DOUBLE + }, { /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0, FB_VMODE_DOUBLE diff --git a/drivers/video/stmp37xxfb.c b/drivers/video/stmp37xxfb.c new file mode 100644 index 000000000000..bf058ae3e097 --- /dev/null +++ b/drivers/video/stmp37xxfb.c @@ -0,0 +1,844 @@ +/* + * Freescale STMP37XX/STMP378X framebuffer driver + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/uaccess.h> +#include <linux/cpufreq.h> + +#include <mach/hardware.h> +#include <mach/regs-pinctrl.h> +#include <mach/regs-lcdif.h> +#include <mach/regs-clkctrl.h> +#include <mach/regs-apbh.h> +#include <mach/lcdif.h> + +#include <mach/stmp3xxx.h> + +#define NUM_SCREENS 1 + +struct stmp3xxx_fb_data { + struct fb_info info; + struct stmp3xxx_platform_fb_data *pdata; + int is_blank; + ssize_t mem_size; + ssize_t map_size; + dma_addr_t phys_start; + dma_addr_t cur_phys; + int dma_irq; + int err_irq; + void *virt_start; + struct device *dev; + wait_queue_head_t vsync_wait_q; + u32 vsync_count; + void *par; +}; + +/* forward declaration */ +static int stmp3xxxfb_blank(int blank, struct fb_info *info); +static unsigned char *default_panel_name; +static struct stmp3xxx_fb_data *cdata; + +static irqreturn_t lcd_irq_handler(int irq, void *dev_id) +{ + struct stmp3xxx_fb_data *data = dev_id; + u32 status_lcd = HW_LCDIF_CTRL1_RD(); + u32 status_apbh = HW_APBH_CTRL1_RD(); + pr_debug("%s: irq %d\n", __func__, irq); + + if (status_apbh & BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ) + HW_APBH_CTRL1_CLR(BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ); + + if (status_lcd & BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ) { + pr_debug("%s: VSYNC irq\n", __func__); + data->vsync_count++; + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ); + wake_up_interruptible(&data->vsync_wait_q); + } + if (status_lcd & BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ) { + pr_debug("%s: frame done irq\n", __func__); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ); + data->vsync_count++; + } + if (status_lcd & BM_LCDIF_CTRL1_UNDERFLOW_IRQ) { + pr_debug("%s: underflow irq\n", __func__); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_UNDERFLOW_IRQ); + } + if (status_lcd & BM_LCDIF_CTRL1_OVERFLOW_IRQ) { + pr_debug("%s: overflow irq\n", __func__); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_OVERFLOW_IRQ); + } + return IRQ_HANDLED; +} + +static struct fb_var_screeninfo stmp3xxxfb_default __devinitdata = { + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo stmp3xxxfb_fix __devinitdata = { + .id = "stmp3xxxfb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +int stmp3xxxfb_get_info(struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) +{ + if (!cdata) + return -ENODEV; + + *var = cdata->info.var; + *fix = cdata->info.fix; + return 0; +} + +void stmp3xxxfb_cfg_pxp(int enable, dma_addr_t pxp_phys) +{ + if (enable) + cdata->pdata->cur->pan_display(pxp_phys); + else + cdata->pdata->cur->pan_display(cdata->cur_phys); +} + +static int stmp3xxxfb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + + if (off < info->fix.smem_len) + return dma_mmap_writecombine(data->dev, vma, + data->virt_start, + data->phys_start, + info->fix.smem_len); + else + return -EINVAL; +} + +static int stmp3xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno >= 256) /* no. of hw registers */ + return 1; + /* + * Program hardware... do anything you want with transp + */ + + /* grayscale works only partially under directcolor */ + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = + (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Directcolor: + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * {hardwarespecific} contains width of RAMDAC + * cmap[X] is programmed to + * (X << red.offset) | (X << green.offset) | (X << blue.offset) + * RAMDAC[X] is programmed to (red, green, blue) + * + * Pseudocolor: + * uses offset = 0 && length = RAMDAC register width. + * var->{color}.offset is 0 + * var->{color}.length contains widht of DAC + * cmap is not used + * RAMDAC[X] is programmed to (red, green, blue) + * Truecolor: + * does not use DAC. Usually 3 are present. + * var->{color}.offset contains start of bitfield + * var->{color}.length contains length of bitfield + * cmap is programmed to + * (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) + * RAMDAC does not exist + */ +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_PSEUDOCOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + break; + case FB_VISUAL_DIRECTCOLOR: + red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ + green = CNVT_TOHW(green, 8); + blue = CNVT_TOHW(blue, 8); + /* hey, there is bug in transp handling... */ + transp = CNVT_TOHW(transp, 8); + break; + } +#undef CNVT_TOHW + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + if (regno >= 16) + return 1; + + ((u32 *) (info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + } + return 0; +} + +static inline u_long get_line_length(int xres_virtual, int bpp) +{ + u_long length; + + length = xres_virtual * bpp; + length = (length + 31) & ~31; + length >>= 3; + return length; +} + +static int get_matching_pentry(struct stmp3xxx_platform_fb_entry *pentry, + void *data, int ret_prev) +{ + struct fb_var_screeninfo *info = data; + pr_debug("%s: %d:%d:%d vs %d:%d:%d\n", __func__, + pentry->x_res, pentry->y_res, pentry->bpp, + info->yres, info->xres, info->bits_per_pixel); + if (pentry->x_res == info->yres && pentry->y_res == info->xres && + pentry->bpp == info->bits_per_pixel) + ret_prev = (int)pentry; + return ret_prev; +} + +static int get_matching_pentry_by_name( + struct stmp3xxx_platform_fb_entry *pentry, + void *data, + int ret_prev) +{ + unsigned char *name = data; + if (!strcmp(pentry->name, name)) + ret_prev = (int)pentry; + return ret_prev; +} + +/* + * This routine actually sets the video mode. It's in here where we + * the hardware state info->par and fix which can be affected by the + * change in par. For this driver it doesn't do much. + * + * XXX: REVISIT + */ +static int stmp3xxxfb_set_par(struct fb_info *info) +{ + struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + struct stmp3xxx_platform_fb_data *pdata = data->pdata; + struct stmp3xxx_platform_fb_entry *pentry; + pentry = (void *)stmp3xxx_lcd_iterate_pdata(pdata, + get_matching_pentry, + &info->var); + + dev_dbg(data->dev, "%s: xres %d, yres %d, bpp %d\n", + __func__, + info->var.xres, + info->var.yres, + info->var.bits_per_pixel); + if (!pentry) + return -EINVAL; + + info->fix.line_length = get_line_length(info->var.xres_virtual, + info->var.bits_per_pixel); + + if (pentry == pdata->cur || !pdata->cur) + return 0; + + /* release prev panel */ + stmp3xxxfb_blank(FB_BLANK_POWERDOWN, &data->info); + if (pdata->cur->stop_panel) + pdata->cur->stop_panel(); + pdata->cur->release_panel(data->dev, pdata->cur); + + info->fix.smem_len = pentry->y_res * pentry->x_res * pentry->bpp / 8; + info->screen_size = info->fix.smem_len; + memset((void *)info->screen_base, 0, info->screen_size); + + /* init next panel */ + pdata->cur = pentry; + stmp3xxx_init_lcdif(); + pentry->init_panel(data->dev, data->phys_start, info->fix.smem_len, + pentry); + pentry->run_panel(); + stmp3xxxfb_blank(FB_BLANK_UNBLANK, &data->info); + + return 0; +} + +static int stmp3xxxfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + u32 line_length; + struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + struct stmp3xxx_platform_fb_data *pdata = data->pdata; + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = info->var.xoffset; + var->yoffset = info->var.yoffset; + } + + pr_debug("%s: xres %d, yres %d, bpp %d\n", __func__, + var->xres, var->yres, var->bits_per_pixel); + /* + * Some very basic checks + */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + + if (var->xres_virtual < var->xoffset + var->xres) + var->xres_virtual = var->xoffset + var->xres; + if (var->yres_virtual < var->yoffset + var->yres) + var->yres_virtual = var->yoffset + var->yres; + + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + dev_dbg(data->dev, + "line_length %d, var->yres_virtual %d, data->mem_size %d\n", + line_length, var->yres_virtual, data->mem_size); + if (line_length * var->yres_virtual > data->map_size) + return -ENOMEM; + + if (!stmp3xxx_lcd_iterate_pdata(pdata, get_matching_pentry, var)) + return -EINVAL; + + if (var->bits_per_pixel == 16) { + /* RGBA 5551 */ + if (var->transp.length) { + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 10; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + } else { + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + + return 0; +} + + +static int stmp3xxxfb_wait_for_vsync(u32 channel, struct fb_info *info) +{ + struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + u32 count = data->vsync_count; + int ret = 0; + + HW_LCDIF_CTRL1_SET(BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN); + ret = wait_event_interruptible_timeout(data->vsync_wait_q, + count != data->vsync_count, HZ / 10); + HW_LCDIF_CTRL1_CLR(BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN); + if (!ret) { + dev_err(data->dev, "wait for vsync timed out\n"); + ret = -ETIMEDOUT; + } + return ret; +} + +static int stmp3xxxfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + u32 channel = 0; + int ret = -EINVAL; + + switch (cmd) { + case FBIO_WAITFORVSYNC: + if (!get_user(channel, (__u32 __user *) arg)) + ret = stmp3xxxfb_wait_for_vsync(channel, info); + break; + default: + break; + } + return ret; +} + +static int stmp3xxxfb_blank(int blank, struct fb_info *info) +{ + struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + int ret = data->pdata->cur->blank_panel ? + data->pdata->cur->blank_panel(blank) : + -ENOTSUPP; + if (ret == 0) + data->is_blank = (blank != FB_BLANK_UNBLANK); + return ret; +} + +static int stmp3xxxfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + int ret = 0; + + pr_debug("%s: var->xoffset %d, info->var.xoffset %d\n", + __func__, var->xoffset, info->var.xoffset); + /* check if var is valid; also, xpan is not supported */ + if (!var || (var->xoffset != info->var.xoffset) || + (var->yoffset + var->yres > var->yres_virtual)) { + ret = -EINVAL; + goto out; + } + + if (!data->pdata->cur->pan_display) { + ret = -EINVAL; + goto out; + } + + /* update framebuffer visual */ + data->cur_phys = data->phys_start + + info->fix.line_length * var->yoffset; + data->pdata->cur->pan_display(data->cur_phys); +out: + return ret; +} + +static struct fb_ops stmp3xxxfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = stmp3xxxfb_check_var, + .fb_set_par = stmp3xxxfb_set_par, + .fb_mmap = stmp3xxxfb_mmap, + .fb_setcolreg = stmp3xxxfb_setcolreg, + .fb_ioctl = stmp3xxxfb_ioctl, + .fb_blank = stmp3xxxfb_blank, + .fb_pan_display = stmp3xxxfb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static void init_timings(struct stmp3xxx_fb_data *data) +{ + unsigned phase_time; + unsigned timings; + + /* Just use a phase_time of 1. As optimal as it gets, now. */ + phase_time = 1; + + /* Program all 4 timings the same */ + timings = phase_time; + timings |= timings << 8; + timings |= timings << 16; + HW_LCDIF_TIMING_WR(timings); +} + +#ifdef CONFIG_CPU_FREQ + +struct stmp3xxxfb_notifier_block { + struct stmp3xxx_fb_data *fb_data; + struct notifier_block nb; +}; + +static int stmp3xxxfb_notifier(struct notifier_block *self, + unsigned long phase, void *p) +{ + struct stmp3xxxfb_notifier_block *block = + container_of(self, struct stmp3xxxfb_notifier_block, nb); + struct stmp3xxx_fb_data *data = block->fb_data; + + switch (phase) { + case CPUFREQ_POSTCHANGE: + stmp3xxxfb_blank(FB_BLANK_UNBLANK, &data->info); + break; + + case CPUFREQ_PRECHANGE: + stmp3xxxfb_blank(FB_BLANK_POWERDOWN, &data->info); + break; + + default: + dev_dbg(data->dev, "didn't handle notify %ld\n", phase); + } + + return NOTIFY_DONE; +} + +static struct stmp3xxxfb_notifier_block stmp3xxxfb_nb = { + .nb = { + .notifier_call = stmp3xxxfb_notifier, + }, +}; +#endif /* CONFIG_CPU_FREQ */ + +static int get_max_memsize(struct stmp3xxx_platform_fb_entry *pentry, + void *data, int ret_prev) +{ + struct stmp3xxx_fb_data *fbdata = data; + int sz = pentry->x_res * pentry->y_res * pentry->bpp / 8; + fbdata->mem_size = sz < ret_prev ? ret_prev : sz; + pr_debug("%s: mem_size now %d\n", __func__, fbdata->mem_size); + return fbdata->mem_size; +} + +static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) +{ + int ret = 0; + struct stmp3xxx_fb_data *data; + struct resource *res; + struct fb_info *info; + struct stmp3xxx_platform_fb_data *pdata = pdev->dev.platform_data; + struct stmp3xxx_platform_fb_entry *pentry; + + if (pdata == NULL) { + ret = -ENODEV; + goto out; + } + + if (default_panel_name) { + pentry = (void *)stmp3xxx_lcd_iterate_pdata(pdata, + get_matching_pentry_by_name, + default_panel_name); + if (pentry) { + stmp3xxx_lcd_move_pentry_up(pentry, pdata); + pdata->cur = pentry; + } + } + if (!default_panel_name || !pentry) + pentry = pdata->cur; + if (!pentry || !pentry->init_panel || !pentry->run_panel || + !pentry->release_panel) { + ret = -EINVAL; + goto out; + } + + data = (struct stmp3xxx_fb_data *)framebuffer_alloc( + sizeof(struct stmp3xxx_fb_data) + + sizeof(u32) * 256 - + sizeof(struct fb_info), &pdev->dev); + if (data == NULL) { + ret = -ENOMEM; + goto out; + } + + cdata = data; + data->dev = &pdev->dev; + data->pdata = pdata; + platform_set_drvdata(pdev, data); + info = &data->info; + + dev_dbg(&pdev->dev, "resolution %dx%d, bpp %d\n", pentry->x_res, + pentry->y_res, pentry->bpp); + + stmp3xxx_lcd_iterate_pdata(pdata, get_max_memsize, data); + + data->map_size = PAGE_ALIGN(data->mem_size) * NUM_SCREENS; + dev_dbg(&pdev->dev, "memory to allocate: %d\n", data->map_size); + + data->virt_start = dma_alloc_writecombine(&pdev->dev, + data->map_size, + &data->phys_start, + GFP_KERNEL); + + if (data->virt_start == NULL) { + ret = -ENOMEM; + goto out_dma; + } + dev_dbg(&pdev->dev, "allocated at %p:0x%x\n", data->virt_start, + data->phys_start); + + stmp3xxxfb_default.bits_per_pixel = pentry->bpp; + /* NB: rotated */ + stmp3xxxfb_default.xres = pentry->y_res; + stmp3xxxfb_default.yres = pentry->x_res; + stmp3xxxfb_default.xres_virtual = pentry->y_res; + stmp3xxxfb_default.yres_virtual = data->map_size / + (pentry->y_res * pentry->bpp / 8); + if (stmp3xxxfb_default.yres_virtual >= stmp3xxxfb_default.yres * 2) + stmp3xxxfb_default.yres_virtual = stmp3xxxfb_default.yres * 2; + else + stmp3xxxfb_default.yres_virtual = stmp3xxxfb_default.yres; + + stmp3xxxfb_fix.smem_start = data->phys_start; + stmp3xxxfb_fix.smem_len = pentry->y_res * pentry->x_res * pentry->bpp / + 8; + stmp3xxxfb_fix.ypanstep = 1; + + switch (pentry->bpp) { + case 32: + case 24: + stmp3xxxfb_default.red.offset = 16; + stmp3xxxfb_default.red.length = 8; + stmp3xxxfb_default.green.offset = 8; + stmp3xxxfb_default.green.length = 8; + stmp3xxxfb_default.blue.offset = 0; + stmp3xxxfb_default.blue.length = 8; + break; + + case 16: + stmp3xxxfb_default.red.offset = 11; + stmp3xxxfb_default.red.length = 5; + stmp3xxxfb_default.green.offset = 5; + stmp3xxxfb_default.green.length = 6; + stmp3xxxfb_default.blue.offset = 0; + stmp3xxxfb_default.blue.length = 5; + break; + + default: + dev_err(&pdev->dev, "unsupported bitwidth %d\n", pentry->bpp); + ret = -EINVAL; + goto out_dma; + } + + info->screen_base = data->virt_start; + info->fbops = &stmp3xxxfb_ops; + + ret = fb_find_mode(&info->var, info, NULL, NULL, 0, NULL, 8); + + if (!ret || (ret == 4)) + info->var = stmp3xxxfb_default; + info->fix = stmp3xxxfb_fix; + info->pseudo_palette = &data->par; + data->par = NULL; + info->flags = FBINFO_FLAG_DEFAULT; + + init_waitqueue_head(&data->vsync_wait_q); + data->vsync_count = 0; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "cannot get IRQ resource\n"); + ret = -ENODEV; + goto out_dma; + } + data->dma_irq = res->start; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (res == NULL) { + dev_err(&pdev->dev, "cannot get IRQ resource\n"); + ret = -ENODEV; + goto out_dma; + } + data->err_irq = res->start; + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) + goto out_cmap; + + stmp3xxx_init_lcdif(); + ret = pentry->init_panel(data->dev, data->phys_start, + stmp3xxxfb_fix.smem_len, pentry); + if (ret) { + dev_err(&pdev->dev, "cannot initialize LCD panel\n"); + goto out_panel; + } + dev_dbg(&pdev->dev, "LCD panel initialized\n"); + init_timings(data); + + ret = request_irq(data->dma_irq, lcd_irq_handler, 0, "fb_dma", data); + if (ret) { + dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", + data->dma_irq, ret); + goto out_panel; + } + ret = request_irq(data->err_irq, lcd_irq_handler, 0, "fb_error", data); + if (ret) { + dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", + data->err_irq, ret); + goto out_irq; + } + ret = register_framebuffer(info); + if (ret) + goto out_register; + + pentry->run_panel(); + dev_dbg(&pdev->dev, "LCD DMA channel has been started\n"); + data->cur_phys = data->phys_start; + dev_dbg(&pdev->dev, "LCD running now\n"); + +#ifdef CONFIG_CPU_FREQ + stmp3xxxfb_nb.fb_data = data; + cpufreq_register_notifier(&stmp3xxxfb_nb.nb, + CPUFREQ_TRANSITION_NOTIFIER); +#endif /* CONFIG_CPU_FREQ */ + + goto out; + +out_register: + free_irq(data->err_irq, data); +out_irq: + free_irq(data->dma_irq, data); +out_panel: + fb_dealloc_cmap(&info->cmap); +out_cmap: + dma_free_writecombine(&pdev->dev, data->map_size, data->virt_start, + data->phys_start); +out_dma: + kfree(data); +out: + return ret; +} + +static int stmp3xxxfb_remove(struct platform_device *pdev) +{ + struct stmp3xxx_fb_data *data = platform_get_drvdata(pdev); + struct stmp3xxx_platform_fb_data *pdata = pdev->dev.platform_data; + struct stmp3xxx_platform_fb_entry *pentry = pdata->cur; + + stmp3xxxfb_blank(FB_BLANK_POWERDOWN, &data->info); + if (pentry->stop_panel) + pentry->stop_panel(); + pentry->release_panel(&pdev->dev, pentry); + + unregister_framebuffer(&data->info); + framebuffer_release(&data->info); + fb_dealloc_cmap(&data->info.cmap); + free_irq(data->dma_irq, data); + free_irq(data->err_irq, data); + dma_free_writecombine(&pdev->dev, data->map_size, data->virt_start, + data->phys_start); + kfree(data); + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int stmp3xxxfb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct stmp3xxx_fb_data *data = platform_get_drvdata(pdev); + struct stmp3xxx_platform_fb_data *pdata = pdev->dev.platform_data; + struct stmp3xxx_platform_fb_entry *pentry = pdata->cur; + int ret; + + ret = stmp3xxxfb_blank(FB_BLANK_POWERDOWN, &data->info); + if (ret) + goto out; + if (pentry->stop_panel) + pentry->stop_panel(); + pentry->release_panel(data->dev, pentry); + +out: + return ret; +} + +static int stmp3xxxfb_resume(struct platform_device *pdev) +{ + struct stmp3xxx_fb_data *data = platform_get_drvdata(pdev); + struct stmp3xxx_platform_fb_data *pdata = pdev->dev.platform_data; + struct stmp3xxx_platform_fb_entry *pentry = pdata->cur; + + stmp3xxx_init_lcdif(); + init_timings(data); + pentry->init_panel(data->dev, data->phys_start, data->info.fix.smem_len, + pentry); + pentry->run_panel(); + stmp3xxxfb_blank(FB_BLANK_UNBLANK, &data->info); + return 0; +} +#else +#define stmp3xxxfb_suspend NULL +#define stmp3xxxfb_resume NULL +#endif + +static struct platform_driver stmp3xxxfb_driver = { + .probe = stmp3xxxfb_probe, + .remove = stmp3xxxfb_remove, + .suspend = stmp3xxxfb_suspend, + .resume = stmp3xxxfb_resume, + .driver = { + .name = "stmp3xxx-fb", + .owner = THIS_MODULE, + }, +}; + +static int __init stmp3xxxfb_init(void) +{ + return platform_driver_register(&stmp3xxxfb_driver); +} + +static void __exit stmp3xxxfb_exit(void) +{ + platform_driver_unregister(&stmp3xxxfb_driver); +} + +module_init(stmp3xxxfb_init); +module_exit(stmp3xxxfb_exit); + +/* + * LCD panel select + */ +static int __init default_panel_select(char *str) +{ + default_panel_name = str; + return 0; +} +__setup("lcd_panel=", default_panel_select); + +MODULE_AUTHOR("Vitaly Wool <vital@embeddedalley.com>"); +MODULE_DESCRIPTION("STMP3xxx Framebuffer Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 24f707608933..f1a7dfda3aac 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -208,6 +208,15 @@ config MXC_WATCHDOG To compile this driver as a module, choose M here: the module will be called mxc_wdt. +config STMP3XXX_WATCHDOG + tristate "Sigmatel STMP3XXX watchdog" + depends on ARCH_STMP3XXX + help + Say Y here if to include support for the watchdog timer + for the Sigmatel STMP37XX/378X SoC. + To compile this driver as a module, choose M here: the + module will be called stmp3xxx_wdt. + config IOP_WATCHDOG tristate "IOP Watchdog" depends on PLAT_IOP diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 44455e1f144b..bf7832c3856c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_MXC_WATCHDOG) += mxc_wdt.o +obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c new file mode 100644 index 000000000000..72b0e0d01c00 --- /dev/null +++ b/drivers/watchdog/stmp3xxx_wdt.c @@ -0,0 +1,301 @@ +/* + * Watchdog driver for Freescale STMP37XX/STMP378X + * + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/uaccess.h> + +#include <mach/regs-rtc.h> + +#define DEFAULT_HEARTBEAT 19 +#define MAX_HEARTBEAT (0x10000000 >> 6) /* actually 0x100000000 >> 10 */ + +/* missing bitmask in headers */ +#define BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER 0x80000000 + +#define WDT_IN_USE 0 +#define WDT_OK_TO_CLOSE 1 +#define WDT_REGION_INITED 2 +#define WDT_DEVICE_INITED 3 + +#define WDOG_COUNTER_RATE 1000 /* 1 kHz clock */ + +DEFINE_SPINLOCK(io_lock); +static unsigned long wdt_status; +static const int nowayout = WATCHDOG_NOWAYOUT; +static int heartbeat = DEFAULT_HEARTBEAT; +static unsigned long boot_status; + + +static void wdt_enable(u32 value) +{ + spin_lock(&io_lock); + HW_RTC_WATCHDOG_WR(value); + HW_RTC_CTRL_SET(BM_RTC_CTRL_WATCHDOGEN); + HW_RTC_PERSISTENT1_SET(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER); + spin_unlock(&io_lock); +} + +static void wdt_disable(void) +{ + spin_lock(&io_lock); + HW_RTC_PERSISTENT1_CLR(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER); + HW_RTC_CTRL_CLR(BM_RTC_CTRL_WATCHDOGEN); + spin_unlock(&io_lock); +} + +static int stmp3xxx_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) + return -EBUSY; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + wdt_enable(heartbeat * WDOG_COUNTER_RATE); + + return nonseekable_open(inode, file); +} + +static ssize_t +stmp3xxx_wdt_write(struct file *file, const char *data, size_t len, + loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + set_bit(WDT_OK_TO_CLOSE, &wdt_status); + } + } + wdt_enable(heartbeat * WDOG_COUNTER_RATE); + } + + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_CARDRESET | + WDIOF_MAGICCLOSE | + WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING, + .identity = "STMP37XX Watchdog", +}; + +static int +stmp3xxx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_heartbeat, opts; + int ret = -ENOTTY; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info __user *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int __user *)arg); + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(boot_status, (int __user *)arg); + break; + + case WDIOC_SETOPTIONS: + get_user(opts, (int __user *)arg); + if (opts & WDIOS_DISABLECARD) + wdt_disable(); + else if (opts & WDIOS_ENABLECARD) + wdt_enable(heartbeat * WDOG_COUNTER_RATE); + else { + pr_debug("%s: unknown option 0x%x\n", __func__, opts); + ret = -EINVAL; + } + break; + + case WDIOC_SETTIMEOUT: + get_user(new_heartbeat, (int __user *)arg); + if (new_heartbeat <= 0 || new_heartbeat > MAX_HEARTBEAT) { + ret = -EINVAL; + break; + } + + heartbeat = new_heartbeat; + wdt_enable(heartbeat * WDOG_COUNTER_RATE); + /* Fall through */ + + case WDIOC_GETTIMEOUT: + ret = put_user(heartbeat, (int __user *)arg); + break; + + case WDIOC_KEEPALIVE: + wdt_enable(heartbeat * WDOG_COUNTER_RATE); + ret = 0; + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int stmp3xxx_wdt_release(struct inode *inode, struct file *file) +{ + int ret = 0; + + if (!nowayout) { + if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { + pr_debug("%s: Device closed unexpectdly\n", __func__); + ret = -EINVAL; + } else { + wdt_disable(); + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + } + } + clear_bit(WDT_IN_USE, &wdt_status); + + return ret; +} + +static const struct file_operations stmp3xxx_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = stmp3xxx_wdt_write, + .ioctl = stmp3xxx_wdt_ioctl, + .open = stmp3xxx_wdt_open, + .release = stmp3xxx_wdt_release, +}; + +static struct miscdevice stmp3xxx_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &stmp3xxx_wdt_fops, +}; + +static int stmp3xxx_wdt_probe(struct platform_device *pdev) +{ + int ret = 0; + + if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) + heartbeat = DEFAULT_HEARTBEAT; + + boot_status = HW_RTC_PERSISTENT1_RD() & + BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER; + boot_status = !!boot_status; + HW_RTC_PERSISTENT1_CLR(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER); + + dev_dbg(&pdev->dev, "STMP37XX Watchdog Timer: heartbeat %d sec\n", + heartbeat); + + ret = misc_register(&stmp3xxx_wdt_miscdev); + if (ret < 0) { + dev_err(&pdev->dev, "cannot register misc device\n"); + } else { + wdt_disable(); /* disable for now */ + set_bit(WDT_DEVICE_INITED, &wdt_status); + } + + return ret; +} + +static int stmp3xxx_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(&stmp3xxx_wdt_miscdev); + return 0; +} + +#ifdef CONFIG_PM +static int wdt_suspended; +static u32 wdt_saved_time; + +static int stmp3xxx_wdt_suspend(struct platform_device *pdev, + pm_message_t state) +{ + if (HW_RTC_CTRL_RD() & BM_RTC_CTRL_WATCHDOGEN) { + wdt_suspended = 1; + wdt_saved_time = HW_RTC_WATCHDOG_RD(); + wdt_disable(); + } + return 0; +} + +static int stmp3xxx_wdt_resume(struct platform_device *pdev) +{ + if (wdt_suspended) { + wdt_enable(wdt_saved_time); + wdt_suspended = 0; + } + return 0; +} +#else +#define stmp3xxx_wdt_suspend NULL +#define stmp3xxx_wdt_resume NULL +#endif + +static struct platform_driver platform_wdt_driver = { + .driver = { + .name = "stmp3xxx_wdt", + }, + .probe = stmp3xxx_wdt_probe, + .remove = __devexit_p(stmp3xxx_wdt_remove), + .suspend = stmp3xxx_wdt_suspend, + .resume = stmp3xxx_wdt_resume, +}; + +static int __init stmp3xxx_wdt_init(void) +{ + return platform_driver_register(&platform_wdt_driver); +} + +static void __exit stmp3xxx_wdt_exit(void) +{ + return platform_driver_unregister(&platform_wdt_driver); +} + +module_init(stmp3xxx_wdt_init); +module_exit(stmp3xxx_wdt_exit); + +MODULE_DESCRIPTION("STMP37XX Watchdog Driver"); +MODULE_LICENSE("GPL"); + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, + "Watchdog heartbeat period in seconds from 1 to " + __MODULE_STRING(MAX_HEARTBEAT) ", default " + __MODULE_STRING(DEFAULT_HEARTBEAT)); + +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/include/linux/major.h b/include/linux/major.h index 88249452b935..9c9d170d191f 100644 --- a/include/linux/major.h +++ b/include/linux/major.h @@ -170,6 +170,8 @@ #define VIOTAPE_MAJOR 230 +#define LBA_MAJOR 240 + #define BLOCK_EXT_MAJOR 259 #endif diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c4acccde9aec..453a064cefc6 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -161,6 +161,9 @@ /* Freescale Semiconductor MXC fmaily */ #define PORT_MXC 84 +/* STMP37xx ports */ +#define PORT_STMP37xx 85 + #ifdef __KERNEL__ #include <linux/compiler.h> diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 2d8f05baf721..1e48ea18e5f8 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -10,7 +10,7 @@ menuconfig SND_SOC If you want ASoC support, you should say Y here and also to the specific driver for your SoC platform below. - + ASoC provides power efficient ALSA support for embedded battery powered SoC based systems like PDA's, Phones and Personal Media Players. @@ -30,6 +30,7 @@ source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/imx/Kconfig" +source "sound/soc/stmp3xxx/Kconfig" source "sound/soc/fsl/Kconfig" source "sound/soc/davinci/Kconfig" source "sound/soc/omap/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 850776caea15..d997c29d2d8a 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ imx/ +obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ imx/ stmp3xxx/ obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cf0fcb03ef69..45a12880d3bb 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -122,3 +122,11 @@ config SND_SOC_SGTL5000 config SND_SOC_AK4647 tristate depends on I2C + +config SND_SOC_STMP378X_CODEC + tristate + depends on SND_SOC + +config SND_SOC_STMP3XXX_SPDIF + tristate + depends on SND_SOC diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e47aa87358ce..b5e5b51bc4e1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -22,6 +22,8 @@ snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-ak4647-objs := ak4647.o +snd-soc-stmp378x-codec-objs := stmp378x_codec.o +snd-soc-stmp3xxx-spdif-objs := stmp3xxx_spdif.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o @@ -47,3 +49,5 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_AK4647) += snd-soc-ak4647.o +obj-$(CONFIG_SND_SOC_STMP378X_CODEC) += snd-soc-stmp378x-codec.o +obj-$(CONFIG_SND_SOC_STMP3XXX_SPDIF) += snd-soc-stmp3xxx-spdif.o diff --git a/sound/soc/codecs/stmp378x_codec.c b/sound/soc/codecs/stmp378x_codec.c new file mode 100644 index 000000000000..0893894efef5 --- /dev/null +++ b/sound/soc/codecs/stmp378x_codec.c @@ -0,0 +1,775 @@ +/* + * ALSA codec for Freescale STMP378X ADC/DAC + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <asm/dma.h> + +#include <mach/regs-apbx.h> +#include <mach/regs-audioin.h> +#include <mach/regs-audioout.h> +#include <mach/regs-rtc.h> + +#include "stmp378x_codec.h" + +#define BV_AUDIOIN_ADCVOL_SELECT__MIC 0x00 /* missing define */ + +#define STMP378X_VERSION "0.1" +struct stmp378x_codec_priv { + struct device *dev; + struct clk *clk; +}; + +/* + * ALSA API + */ +static u32 adc_regmap[] = { + HW_AUDIOOUT_CTRL_ADDR, + HW_AUDIOOUT_STAT_ADDR, + HW_AUDIOOUT_DACSRR_ADDR, + HW_AUDIOOUT_DACVOLUME_ADDR, + HW_AUDIOOUT_DACDEBUG_ADDR, + HW_AUDIOOUT_HPVOL_ADDR, + HW_AUDIOOUT_PWRDN_ADDR, + HW_AUDIOOUT_REFCTRL_ADDR, + HW_AUDIOOUT_ANACTRL_ADDR, + HW_AUDIOOUT_TEST_ADDR, + HW_AUDIOOUT_BISTCTRL_ADDR, + HW_AUDIOOUT_BISTSTAT0_ADDR, + HW_AUDIOOUT_BISTSTAT1_ADDR, + HW_AUDIOOUT_ANACLKCTRL_ADDR, + HW_AUDIOOUT_DATA_ADDR, + HW_AUDIOOUT_SPEAKERCTRL_ADDR, + HW_AUDIOOUT_VERSION_ADDR, + HW_AUDIOIN_CTRL_ADDR, + HW_AUDIOIN_STAT_ADDR, + HW_AUDIOIN_ADCSRR_ADDR, + HW_AUDIOIN_ADCVOLUME_ADDR, + HW_AUDIOIN_ADCDEBUG_ADDR, + HW_AUDIOIN_ADCVOL_ADDR, + HW_AUDIOIN_MICLINE_ADDR, + HW_AUDIOIN_ANACLKCTRL_ADDR, + HW_AUDIOIN_DATA_ADDR, +}; + +/* + * ALSA core supports only 16 bit registers. It means we have to simulate it + * by virtually splitting a 32bit ADC/DAC registers into two halves + * high (bits 31:16) and low (bits 15:0). The routins abow detects which part + * of 32bit register is accessed. + */ +static int stmp378x_codec_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + unsigned int reg_val; + unsigned int mask = 0xffff; + + if (reg >= ADC_REGNUM) + return -EIO; + + if (reg & 0x1) { + mask <<= 16; + value <<= 16; + } + + reg_val = __raw_readl(adc_regmap[reg >> 1]); + reg_val = (reg_val & ~mask) | value; + __raw_writel(reg_val, adc_regmap[reg >> 1]); + + return 0; +} + +static unsigned int stmp378x_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + unsigned int reg_val; + + if (reg >= ADC_REGNUM) + return -1; + + reg_val = __raw_readl(adc_regmap[reg >> 1]); + if (reg & 1) + reg_val >>= 16; + + return reg_val & 0xffff; +} + +static const char *stmp378x_codec_adc_input_sel[] = + {"Mic", "Line In 1", "Head Phone", "Line In 2"}; + +static const char *stmp378x_codec_hp_output_sel[] = + {"DAC", "Line In 1"}; + +static const char *stmp378x_codec_adc_3d_sel[] = + {"Off", "Low", "Medium", "High"}; + +static const struct soc_enum stmp378x_codec_enum[] = { + SOC_ENUM_SINGLE(ADC_ADCVOL_L, 12, 4, stmp378x_codec_adc_input_sel), + SOC_ENUM_SINGLE(ADC_ADCVOL_L, 4, 4, stmp378x_codec_adc_input_sel), + SOC_ENUM_SINGLE(DAC_HPVOL_H, 0, 2, stmp378x_codec_hp_output_sel), + SOC_ENUM_SINGLE(DAC_CTRL_L, 8, 4, stmp378x_codec_adc_3d_sel), +}; + +/* Codec controls */ +static const struct snd_kcontrol_new stmp378x_snd_controls[] = { + /* Playback Volume */ + SOC_DOUBLE_R("DAC Playback Volume", + DAC_VOLUME_H, DAC_VOLUME_L, 0, 0xFF, 0), + SOC_DOUBLE_R("DAC Playback Switch", + DAC_VOLUME_H, DAC_VOLUME_L, 8, 0x01, 1), + SOC_DOUBLE("HP Playback Volume", DAC_HPVOL_L, 8, 0, 0x7F, 1), + SOC_SINGLE("HP Playback Switch", DAC_HPVOL_H, 8, 0x1, 1), + SOC_SINGLE("Speaker Playback Switch", DAC_SPEAKERCTRL_H, 8, 0x1, 1), + + /* Capture Volume */ + SOC_DOUBLE_R("ADC Capture Volume", + ADC_VOLUME_H, ADC_VOLUME_L, 0, 0xFF, 0), + SOC_DOUBLE("ADC PGA Capture Volume", ADC_ADCVOL_L, 8, 0, 0x0F, 0), + SOC_SINGLE("ADC PGA Capture Switch", ADC_ADCVOL_H, 8, 0x1, 1), + SOC_SINGLE("Mic PGA Capture Volume", ADC_MICLINE_L, 0, 0x03, 0), + + /* Virtual 3D effect */ + SOC_ENUM("3D effect", stmp378x_codec_enum[3]), +}; + +/* add non dapm controls */ +static int stmp378x_codec_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(stmp378x_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&stmp378x_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +/* Left ADC Mux */ +static const struct snd_kcontrol_new stmp378x_left_adc_controls = +SOC_DAPM_ENUM("Route", stmp378x_codec_enum[0]); + +/* Right ADC Mux */ +static const struct snd_kcontrol_new stmp378x_right_adc_controls = +SOC_DAPM_ENUM("Route", stmp378x_codec_enum[1]); + +/* Head Phone Mux */ +static const struct snd_kcontrol_new stmp378x_hp_controls = +SOC_DAPM_ENUM("Route", stmp378x_codec_enum[2]); + +static const struct snd_soc_dapm_widget stmp378x_codec_widgets[] = { + + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &stmp378x_left_adc_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &stmp378x_right_adc_controls), + SND_SOC_DAPM_MUX("HP Mux", SND_SOC_NOPM, 0, 0, + &stmp378x_hp_controls), + + SND_SOC_DAPM_INPUT("LINE1L"), + SND_SOC_DAPM_INPUT("LINE1R"), + SND_SOC_DAPM_INPUT("LINE2L"), + SND_SOC_DAPM_INPUT("LINE2R"), + SND_SOC_DAPM_INPUT("MIC"), + + SND_SOC_DAPM_OUTPUT("SPEAKER"), + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; +static const struct snd_soc_dapm_route intercon[] = { + + /* Left ADC Mux */ + {"Left ADC Mux", "Mic", "MIC"}, + {"Left ADC Mux", "Line In 1", "LINE1L"}, + {"Left ADC Mux", "Line In 2", "LINE2L"}, + {"Left ADC Mux", "Head Phone", "HPL"}, + + /* Right ADC Mux */ + {"Right ADC Mux", "Mic", "MIC"}, + {"Right ADC Mux", "Line In 1", "LINE1R"}, + {"Right ADC Mux", "Line In 2", "LINE2R"}, + {"Right ADC Mux", "Head Phone", "HPR"}, + + /* ADC */ + {"Left ADC", NULL, "Left ADC Mux"}, + {"Right ADC", NULL, "Right ADC Mux"}, + + /* HP Mux */ + {"HP Mux", "DAC", "Left DAC"}, + {"HP Mux", "DAC", "Right DAC"}, + {"HP Mux", "Line In 1", "LINE1L"}, + {"HP Mux", "Line In 1", "LINE1R"}, + + /* HP output */ + {"HPR", NULL, "HP Mux"}, + {"HPL", NULL, "HP Mux"}, + + /* Speaker amp */ + {"SPEAKER", NULL, "Right DAC"}, +}; + +static int stmp378x_codec_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, stmp378x_codec_widgets, + ARRAY_SIZE(stmp378x_codec_widgets)); + + /* set up audio path interconnects */ + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct dac_srr { + u32 rate; + u32 basemult; + u32 src_hold; + u32 src_int; + u32 src_frac; +}; + +static struct dac_srr srr_values[] = { + {192000, 0x4, 0x0, 0x0F, 0x13FF}, + {176400, 0x4, 0x0, 0x11, 0x0037}, + {128000, 0x4, 0x0, 0x17, 0x0E00}, + {96000, 0x2, 0x0, 0x0F, 0x13FF}, + {88200, 0x2, 0x0, 0x11, 0x0037}, + {64000, 0x2, 0x0, 0x17, 0x0E00}, + {48000, 0x1, 0x0, 0x0F, 0x13FF}, + {44100, 0x1, 0x0, 0x11, 0x0037}, + {32000, 0x1, 0x0, 0x17, 0x0E00}, + {24000, 0x1, 0x1, 0x0F, 0x13FF}, + {22050, 0x1, 0x1, 0x11, 0x0037}, + {16000, 0x1, 0x1, 0x17, 0x0E00}, + {12000, 0x1, 0x3, 0x0F, 0x13FF}, + {11025, 0x1, 0x3, 0x11, 0x0037}, + {8000, 0x1, 0x3, 0x17, 0x0E00} +}; + +static inline int get_srr_values(int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(srr_values); i++) + if (srr_values[i].rate == rate) + return i; + + return -1; +} + +static int stmp378x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int i; + u32 srr_value = 0; + u32 src_hold = 0; + + i = get_srr_values(params_rate(params)); + if (i < 0) + printk(KERN_WARNING "%s doesn't support rate %d\n", + codec->name, params_rate(params)); + else { + src_hold = srr_values[i].src_hold; + + srr_value = + BF_AUDIOOUT_DACSRR_BASEMULT(srr_values[i].basemult) | + BF_AUDIOOUT_DACSRR_SRC_INT(srr_values[i].src_int) | + BF_AUDIOOUT_DACSRR_SRC_FRAC(srr_values[i].src_frac) | + BF_AUDIOOUT_DACSRR_SRC_HOLD(src_hold); + + if (playback) + HW_AUDIOOUT_DACSRR_WR(srr_value); + else + HW_AUDIOIN_ADCSRR_WR(srr_value); + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + if (playback) + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_WORD_LENGTH); + else + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_WORD_LENGTH); + + break; + + case SNDRV_PCM_FORMAT_S32_LE: + if (playback) + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_WORD_LENGTH); + else + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_WORD_LENGTH); + + break; + + default: + printk(KERN_WARNING "%s doesn't support format %d\n", + codec->name, params_format(params)); + + } + + return 0; +} + +static int stmp378x_codec_dig_mute(struct snd_soc_dai *dai, int mute) +{ + u32 dac_mask = BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | + BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT; + + if (mute) + HW_AUDIOOUT_DACVOLUME_SET(dac_mask); + else + HW_AUDIOOUT_DACVOLUME_CLR(dac_mask); + + return 0; +} + +/* + * Codec initialization + */ +#define VAG_BASE_VALUE ((1400/2 - 625)/25) +static void stmp378x_codec_dac_set_vag(void) +{ + u32 refctrl_val = HW_AUDIOOUT_REFCTRL_RD(); + + refctrl_val &= ~(BM_AUDIOOUT_REFCTRL_VAG_VAL); + refctrl_val &= ~(BM_AUDIOOUT_REFCTRL_VBG_ADJ); + refctrl_val |= BF_AUDIOOUT_REFCTRL_VAG_VAL(VAG_BASE_VALUE) | + BM_AUDIOOUT_REFCTRL_ADJ_VAG | + BF_AUDIOOUT_REFCTRL_ADC_REFVAL(0xF) | + BM_AUDIOOUT_REFCTRL_ADJ_ADC | + BF_AUDIOOUT_REFCTRL_VBG_ADJ(0x3) | + BM_AUDIOOUT_REFCTRL_RAISE_REF; + + HW_AUDIOOUT_REFCTRL_WR(refctrl_val); +} + +static void +stmp378x_codec_dac_power_on(struct stmp378x_codec_priv *stmp378x_adc) +{ + /* Ungate DAC clocks */ + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_CLKGATE); + HW_AUDIOOUT_ANACLKCTRL_CLR(BM_AUDIOOUT_ANACLKCTRL_CLKGATE); + + /* Set capless mode */ + HW_AUDIOOUT_PWRDN_CLR(BM_AUDIOOUT_PWRDN_CAPLESS); + + /* 16 bit word length */ + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_WORD_LENGTH); + + /* Power up DAC */ + HW_AUDIOOUT_PWRDN_CLR(BM_AUDIOOUT_PWRDN_DAC); + /* Update DAC volume over zero crossings */ + HW_AUDIOOUT_DACVOLUME_SET(BM_AUDIOOUT_DACVOLUME_EN_ZCD); + /* Mute DAC */ + HW_AUDIOOUT_DACVOLUME_SET(BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | + BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT); + + /* Update HP volume over zero crossings */ + HW_AUDIOOUT_HPVOL_SET(BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD); + + /* Power up HP output */ + HW_AUDIOOUT_ANACTRL_SET(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND); + HW_RTC_PERSISTENT0_SET(BF_RTC_PERSISTENT0_SPARE_ANALOG(0x2)); + HW_AUDIOOUT_PWRDN_CLR(BM_AUDIOOUT_PWRDN_HEADPHONE); + HW_AUDIOOUT_ANACTRL_SET(BM_AUDIOOUT_ANACTRL_HP_CLASSAB); + HW_AUDIOOUT_ANACTRL_CLR(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND); + /* Mute HP output */ + HW_AUDIOOUT_HPVOL_SET(BM_AUDIOOUT_HPVOL_MUTE); + + /* Power up speaker amp */ + HW_AUDIOOUT_PWRDN_CLR(BM_AUDIOOUT_PWRDN_SPEAKER); + /* Mute speaker amp */ + HW_AUDIOOUT_SPEAKERCTRL_SET(BM_AUDIOOUT_SPEAKERCTRL_MUTE); +} + +static void +stmp378x_codec_dac_power_down(struct stmp378x_codec_priv *stmp378x_adc) +{ + /* Disable class AB */ + HW_AUDIOOUT_ANACTRL_CLR(BM_AUDIOOUT_ANACTRL_HP_CLASSAB); + + /* Set hold to ground */ + HW_AUDIOOUT_ANACTRL_SET(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND); + + /* Mute HP output */ + HW_AUDIOOUT_HPVOL_SET(BM_AUDIOOUT_HPVOL_MUTE); + /* Power down HP output */ + HW_AUDIOOUT_PWRDN_SET(BM_AUDIOOUT_PWRDN_HEADPHONE); + + /* Mute speaker amp */ + HW_AUDIOOUT_SPEAKERCTRL_SET(BM_AUDIOOUT_SPEAKERCTRL_MUTE); + /* Power down speaker amp */ + HW_AUDIOOUT_PWRDN_SET(BM_AUDIOOUT_PWRDN_SPEAKER); + + /* Mute DAC */ + HW_AUDIOOUT_DACVOLUME_SET(BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | + BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT); + /* Power down DAC */ + HW_AUDIOOUT_PWRDN_SET(BM_AUDIOOUT_PWRDN_DAC); + + /* Gate DAC clocks */ + HW_AUDIOOUT_ANACLKCTRL_SET(BM_AUDIOOUT_ANACLKCTRL_CLKGATE); + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_CLKGATE); +} + +static void +stmp378x_codec_adc_power_on(struct stmp378x_codec_priv *stmp378x_adc) +{ + u32 reg; + + /* Ungate ADC clocks */ + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_CLKGATE); + HW_AUDIOIN_ANACLKCTRL_CLR(BM_AUDIOIN_ANACLKCTRL_CLKGATE); + + /* Power Up ADC */ + HW_AUDIOOUT_PWRDN_CLR( + BM_AUDIOOUT_PWRDN_ADC | BM_AUDIOOUT_PWRDN_RIGHT_ADC); + + /* 16 bit word length */ + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_WORD_LENGTH); + + /* Unmute ADC channels */ + HW_AUDIOIN_ADCVOL_CLR(BM_AUDIOIN_ADCVOL_MUTE); + + /* + * The MUTE_LEFT and MUTE_RIGHT fields need to be cleared. + * They aren't presented in the datasheet, so this is hardcode. + */ + HW_AUDIOIN_ADCVOLUME_CLR(0x01000100); + + /* Set the Input channel gain 3dB */ + HW_AUDIOIN_ADCVOL_CLR(BM_AUDIOIN_ADCVOL_GAIN_LEFT); + HW_AUDIOIN_ADCVOL_CLR(BM_AUDIOIN_ADCVOL_GAIN_RIGHT); + HW_AUDIOIN_ADCVOL_SET(BF_AUDIOIN_ADCVOL_GAIN_LEFT(2)); + HW_AUDIOIN_ADCVOL_SET(BF_AUDIOIN_ADCVOL_GAIN_RIGHT(2)); + + /* Select default input - Microphone */ + HW_AUDIOIN_ADCVOL_CLR(BM_AUDIOIN_ADCVOL_SELECT_LEFT); + HW_AUDIOIN_ADCVOL_CLR(BM_AUDIOIN_ADCVOL_SELECT_RIGHT); + HW_AUDIOIN_ADCVOL_SET( + BF_AUDIOIN_ADCVOL_SELECT_LEFT(BV_AUDIOIN_ADCVOL_SELECT__MIC)); + HW_AUDIOIN_ADCVOL_SET( + BF_AUDIOIN_ADCVOL_SELECT_RIGHT(BV_AUDIOIN_ADCVOL_SELECT__MIC)); + + /* Set max ADC volume */ + reg = HW_AUDIOIN_ADCVOLUME_RD(); + reg &= ~BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT; + reg &= ~BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT; + reg |= BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ADC_VOLUME_MAX); + reg |= BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(ADC_VOLUME_MAX); + HW_AUDIOIN_ADCVOLUME_WR(reg); +} + +static void +stmp378x_codec_adc_power_down(struct stmp378x_codec_priv *stmp378x_adc) +{ + /* Mute ADC channels */ + HW_AUDIOIN_ADCVOL_SET(BM_AUDIOIN_ADCVOL_MUTE); + + /* Power Down ADC */ + HW_AUDIOOUT_PWRDN_SET( + BM_AUDIOOUT_PWRDN_ADC | BM_AUDIOOUT_PWRDN_RIGHT_ADC); + + /* Gate ADC clocks */ + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_CLKGATE); + HW_AUDIOIN_ANACLKCTRL_SET(BM_AUDIOIN_ANACLKCTRL_CLKGATE); +} + +static void +stmp378x_codec_dac_enable(struct stmp378x_codec_priv *stmp378x_adc) +{ + /* Move DAC codec out of reset */ + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_SFTRST); + + /* Reduce analog power */ + HW_AUDIOOUT_TEST_CLR(BM_AUDIOOUT_TEST_HP_I1_ADJ); + HW_AUDIOOUT_TEST_SET(BF_AUDIOOUT_TEST_HP_I1_ADJ(0x1)); + HW_AUDIOOUT_REFCTRL_SET(BM_AUDIOOUT_REFCTRL_LOW_PWR); + HW_AUDIOOUT_REFCTRL_SET(BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS); + HW_AUDIOOUT_REFCTRL_CLR(BM_AUDIOOUT_REFCTRL_BIAS_CTRL); + HW_AUDIOOUT_REFCTRL_CLR(BF_AUDIOOUT_REFCTRL_BIAS_CTRL(0x1)); + + /* Set Vag value */ + stmp378x_codec_dac_set_vag(); + + /* Power on DAC codec */ + stmp378x_codec_dac_power_on(stmp378x_adc); +} + +static void stmp378x_codec_dac_disable(struct stmp378x_codec_priv *stmp378x_adc) +{ + stmp378x_codec_dac_power_down(stmp378x_adc); +} + +static void +stmp378x_codec_adc_enable(struct stmp378x_codec_priv *stmp378x_adc) +{ + /* Move ADC codec out of reset */ + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_SFTRST); + + /* Power on ADC codec */ + stmp378x_codec_adc_power_on(stmp378x_adc); +} + +static void stmp378x_codec_adc_disable(struct stmp378x_codec_priv *stmp378x_adc) +{ + stmp378x_codec_adc_power_down(stmp378x_adc); +} + +static void +stmp378x_codec_init(struct snd_soc_codec *codec) +{ + struct stmp378x_codec_priv *stmp378x_adc = codec->private_data; + + /* Soft reset DAC block */ + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_SFTRST); + while (!(HW_AUDIOOUT_CTRL_RD() & BM_AUDIOOUT_CTRL_CLKGATE)); + + /* Soft reset ADC block */ + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_SFTRST); + while (!(HW_AUDIOIN_CTRL_RD() & BM_AUDIOIN_CTRL_CLKGATE)); + + stmp378x_codec_dac_enable(stmp378x_adc); + stmp378x_codec_adc_enable(stmp378x_adc); + + stmp378x_codec_add_controls(codec); + stmp378x_codec_add_widgets(codec); +} + +static void +stmp378x_codec_exit(struct snd_soc_codec *codec) +{ + struct stmp378x_codec_priv *stmp378x_adc = codec->private_data; + stmp378x_codec_dac_disable(stmp378x_adc); + stmp378x_codec_adc_disable(stmp378x_adc); +} + +#define STMP378X_ADC_RATES SNDRV_PCM_RATE_8000_192000 +#define STMP378X_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +struct snd_soc_dai stmp378x_codec_dai = { + .name = "stmp378x adc/dac", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = STMP378X_ADC_RATES, + .formats = STMP378X_ADC_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = STMP378X_ADC_RATES, + .formats = STMP378X_ADC_FORMATS, + }, + .ops = { + .hw_params = stmp378x_codec_hw_params, + }, + .dai_ops = { + .digital_mute = stmp378x_codec_dig_mute, + } +}; +EXPORT_SYMBOL_GPL(stmp378x_codec_dai); + +static int stmp378x_codec_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct stmp378x_codec_priv *stmp378x_adc; + int ret = 0; + + printk(KERN_INFO "STMP378X ADC/DAC Audio Codec %s\n", STMP378X_VERSION); + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + stmp378x_adc = kzalloc(sizeof(struct stmp378x_codec_priv), GFP_KERNEL); + if (stmp378x_adc == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->name = "stmp378x adc/dac"; + codec->owner = THIS_MODULE; + codec->private_data = stmp378x_adc; + codec->read = stmp378x_codec_read; + codec->write = stmp378x_codec_write; + codec->dai = &stmp378x_codec_dai; + codec->num_dai = 1; + socdev->codec = codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "%s: failed to create pcms\n", __func__); + goto pcm_err; + } + + /* Turn on audio clock */ + stmp378x_adc->dev = &pdev->dev; + stmp378x_adc->clk = clk_get(stmp378x_adc->dev, "audio"); + if (IS_ERR(stmp378x_adc->clk)) { + ret = PTR_ERR(stmp378x_adc->clk); + printk(KERN_ERR "%s: Clocks initialization failed\n", __func__); + goto clk_err; + } + clk_enable(stmp378x_adc->clk); + + stmp378x_codec_init(codec); + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "%s: failed to register card\n", __func__); + goto card_err; + } + + return ret; + +card_err: + clk_disable(stmp378x_adc->clk); + clk_put(stmp378x_adc->clk); +clk_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(socdev->codec); + return ret; +} + +static int stmp378x_codec_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct stmp378x_codec_priv *stmp378x_adc; + + if (codec == NULL) + return 0; + + stmp378x_adc = codec->private_data; + + clk_disable(stmp378x_adc->clk); + clk_put(stmp378x_adc->clk); + + stmp378x_codec_exit(codec); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + kfree(socdev->codec); + + return 0; +} + +#ifdef CONFIG_PM +static int stmp378x_codec_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct stmp378x_codec_priv *stmp378x_adc; + int ret = -EINVAL; + + if (codec == NULL) + goto out; + + stmp378x_adc = codec->private_data; + + stmp378x_codec_dac_disable(stmp378x_adc); + stmp378x_codec_adc_disable(stmp378x_adc); + clk_disable(stmp378x_adc->clk); + ret = 0; + +out: + return ret; +} + +static int stmp378x_codec_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct stmp378x_codec_priv *stmp378x_adc; + int ret = -EINVAL; + + if (codec == NULL) + goto out; + + stmp378x_adc = codec->private_data; + clk_enable(stmp378x_adc->clk); + + /* Soft reset DAC block */ + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_SFTRST); + while (!(HW_AUDIOOUT_CTRL_RD() & BM_AUDIOOUT_CTRL_CLKGATE)); + + /* Soft reset ADC block */ + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_SFTRST); + while (!(HW_AUDIOIN_CTRL_RD() & BM_AUDIOIN_CTRL_CLKGATE)); + + stmp378x_codec_dac_enable(stmp378x_adc); + stmp378x_codec_adc_enable(stmp378x_adc); + + ret = 0; + +out: + return ret; +} +#else +#define stmp378x_codec_suspend NULL +#define stmp378x_codec_resume NULL +#endif /* CONFIG_PM */ + +struct snd_soc_codec_device soc_codec_dev_stmp378x = { + .probe = stmp378x_codec_probe, + .remove = stmp378x_codec_remove, + .suspend = stmp378x_codec_suspend, + .resume = stmp378x_codec_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_stmp378x); + +MODULE_DESCRIPTION("STMP378X ADC/DAC codec"); +MODULE_AUTHOR("Vladislav Buzov"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/stmp378x_codec.h b/sound/soc/codecs/stmp378x_codec.h new file mode 100644 index 000000000000..80fce7273126 --- /dev/null +++ b/sound/soc/codecs/stmp378x_codec.h @@ -0,0 +1,87 @@ +/* + * ALSA codec for Freescale STMP378X + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __STMP378X_CODEC_H +#define __STMP378X_CODEC_H + +#define DAC_CTRL_L 0 +#define DAC_CTRL_H 1 +#define DAC_STAT_L 2 +#define DAC_STAT_H 3 +#define DAC_SRR_L 4 +#define DAC_VOLUME_L 6 +#define DAC_VOLUME_H 7 +#define DAC_DEBUG_L 8 +#define DAC_DEBUG_H 9 +#define DAC_HPVOL_L 10 +#define DAC_HPVOL_H 11 +#define DAC_PWRDN_L 12 +#define DAC_PWRDN_H 13 +#define DAC_REFCTRL_L 14 +#define DAC_REFCTRL_H 15 +#define DAC_ANACTRL_L 16 +#define DAC_ANACTRL_H 17 +#define DAC_TEST_L 18 +#define DAC_TEST_H 19 +#define DAC_BISTCTRL_L 20 +#define DAC_BISTCTRL_H 21 +#define DAC_BISTSTAT0_L 22 +#define DAC_BISTSTAT0_H 23 +#define DAC_BISTSTAT1_L 24 +#define DAC_BISTSTAT1_H 25 +#define DAC_ANACLKCTRL_L 26 +#define DAC_ANACLKCTRL_H 27 +#define DAC_DATA_L 28 +#define DAC_DATA_H 29 +#define DAC_SPEAKERCTRL_L 30 +#define DAC_SPEAKERCTRL_H 31 +#define DAC_VERSION_L 32 +#define DAC_VERSION_H 33 +#define ADC_CTRL_L 34 +#define ADC_CTRL_H 35 +#define ADC_STAT_L 36 +#define ADC_STAT_H 37 +#define ADC_SRR_L 38 +#define ADC_SRR_H 39 +#define ADC_VOLUME_L 40 +#define ADC_VOLUME_H 41 +#define ADC_DEBUG_L 42 +#define ADC_DEBUG_H 43 +#define ADC_ADCVOL_L 44 +#define ADC_ADCVOL_H 45 +#define ADC_MICLINE_L 46 +#define ADC_MICLINE_H 47 +#define ADC_ANACLKCTRL_L 48 +#define ADC_ANACLKCTRL_H 49 +#define ADC_DATA_L 50 +#define ADC_DATA_H 51 + +#define ADC_REGNUM 52 + +#define DAC_VOLUME_MIN 0x37 +#define DAC_VOLUME_MAX 0xFE +#define ADC_VOLUME_MIN 0x37 +#define ADC_VOLUME_MAX 0xFE +#define HP_VOLUME_MAX 0x0 +#define HP_VOLUME_MIN 0x7F +#define LO_VOLUME_MAX 0x0 +#define LO_VOLUME_MIN 0x1F + +extern struct snd_soc_dai stmp378x_codec_dai; +extern struct snd_soc_codec_device soc_codec_dev_stmp378x; + +#endif /* __STMP378X_CODEC_H */ diff --git a/sound/soc/codecs/stmp3xxx_spdif.c b/sound/soc/codecs/stmp3xxx_spdif.c new file mode 100644 index 000000000000..9f51ec4ffbe4 --- /dev/null +++ b/sound/soc/codecs/stmp3xxx_spdif.c @@ -0,0 +1,412 @@ +/* + * ALSA SoC STMP3xxx SPDIF transmitter driver + * + * Vladimir Barinov <vbarinov@embeddedalley.com> + * + * Copyright 2008 SigmaTel, Inc + * Copyright 2008 Embedded Alley Solutions, Inc + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <asm/dma.h> + +#include <mach/regs-spdif.h> + +#include "stmp3xxx_spdif.h" + +#define STMP3XXX_VERSION "0.1" +struct stmp3xxx_codec_priv { + struct device *dev; + struct clk *clk; +}; + +/* + * ALSA API + */ +static u32 spdif_regmap[] = { + HW_SPDIF_CTRL_ADDR, + HW_SPDIF_STAT_ADDR, + HW_SPDIF_FRAMECTRL_ADDR, + HW_SPDIF_SRR_ADDR, + HW_SPDIF_DEBUG_ADDR, + HW_SPDIF_DATA_ADDR, + HW_SPDIF_VERSION_ADDR, +}; + +/* + * ALSA core supports only 16 bit registers. It means we have to simulate it + * by virtually splitting a 32bit SPDIF registers into two halves + * high (bits 31:16) and low (bits 15:0). The routins abow detects which part + * of 32bit register is accessed. + */ +static int stmp3xxx_codec_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + unsigned int reg_val; + unsigned int mask = 0xffff; + + if (reg >= SPDIF_REGNUM) + return -EIO; + + if (reg & 0x1) { + mask <<= 16; + value <<= 16; + } + + reg_val = __raw_readl(spdif_regmap[reg >> 1]); + reg_val = (reg_val & ~mask) | value; + __raw_writel(reg_val, spdif_regmap[reg >> 1]); + + return 0; +} + +static unsigned int stmp3xxx_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + unsigned int reg_val; + + if (reg >= SPDIF_REGNUM) + return -1; + + reg_val = __raw_readl(spdif_regmap[reg >> 1]); + if (reg & 1) + reg_val >>= 16; + + return reg_val & 0xffff; +} + +/* Codec controls */ +static const struct snd_kcontrol_new stmp3xxx_snd_controls[] = { + SOC_SINGLE("PRO", SPDIF_FRAMECTRL_L, 0, 0x1, 0), + SOC_SINGLE("AUDIO", SPDIF_FRAMECTRL_L, 1, 0x1, 0), + SOC_SINGLE("COPY", SPDIF_FRAMECTRL_L, 2, 0x1, 0), + SOC_SINGLE("PRE", SPDIF_FRAMECTRL_L, 3, 0x1, 0), + SOC_SINGLE("CC", SPDIF_FRAMECTRL_L, 4, 0x7F, 0), + SOC_SINGLE("L", SPDIF_FRAMECTRL_L, 12, 0x1, 0), + SOC_SINGLE("V", SPDIF_FRAMECTRL_L, 13, 0x1, 0), + SOC_SINGLE("USER DATA", SPDIF_FRAMECTRL_L, 14, 0x1, 0), + SOC_SINGLE("AUTO MUTE", SPDIF_FRAMECTRL_H, 16, 0x1, 0), + SOC_SINGLE("V CONFIG", SPDIF_FRAMECTRL_H, 17, 0x1, 0), +}; + +/* add non dapm controls */ +static int stmp3xxx_codec_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(stmp3xxx_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&stmp3xxx_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +struct spdif_srr { + u32 rate; + u32 basemult; + u32 rate_factor; +}; + +static struct spdif_srr srr_values[] = { + {96000, 0x2, 0x0BB80}, + {88200, 0x2, 0x0AC44}, + {64000, 0x2, 0x07D00}, + {48000, 0x1, 0x0BB80}, + {44100, 0x1, 0x0AC44}, + {32000, 0x1, 0x07D00}, +}; + +static inline int get_srr_values(int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(srr_values); i++) + if (srr_values[i].rate == rate) + return i; + + return -1; +} + +static int stmp3xxx_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int i; + u32 srr_value = 0; + u32 basemult; + + i = get_srr_values(params_rate(params)); + if (i < 0) + printk(KERN_WARNING "%s doesn't support rate %d\n", + codec->name, params_rate(params)); + else { + basemult = srr_values[i].basemult; + + srr_value = BF_SPDIF_SRR_BASEMULT(basemult) | + BF_SPDIF_SRR_RATE(srr_values[i].rate_factor); + + if (playback) + HW_SPDIF_SRR_WR(srr_value); + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + if (playback) + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_WORD_LENGTH); + break; + case SNDRV_PCM_FORMAT_S32_LE: + if (playback) + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_WORD_LENGTH); + break; + default: + printk(KERN_WARNING "%s doesn't support format %d\n", + codec->name, params_format(params)); + } + + return 0; +} + +static void +stmp3xxx_codec_spdif_enable(struct stmp3xxx_codec_priv *stmp3xxx_spdif) +{ + /* Move SPDIF codec out of reset */ + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_SFTRST); + + /* Ungate SPDIF clocks */ + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_CLKGATE); + + /* 16 bit word length */ + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_WORD_LENGTH); +} + +static void +stmp3xxx_codec_spdif_disable(struct stmp3xxx_codec_priv *stmp3xxx_spdif) +{ + /* Gate SPDIF clocks */ + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_CLKGATE); +} + +static void stmp3xxx_codec_init(struct snd_soc_codec *codec) +{ + struct stmp3xxx_codec_priv *stmp3xxx_spdif = codec->private_data; + + /* Soft reset SPDIF block */ + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_SFTRST); + while (!(HW_SPDIF_CTRL_RD() & BM_SPDIF_CTRL_CLKGATE)); + + stmp3xxx_codec_spdif_enable(stmp3xxx_spdif); + + stmp3xxx_codec_add_controls(codec); +} + +static void stmp3xxx_codec_exit(struct snd_soc_codec *codec) +{ + struct stmp3xxx_codec_priv *stmp3xxx_spdif = codec->private_data; + + stmp3xxx_codec_spdif_disable(stmp3xxx_spdif); +} + +#define STMP3XXX_SPDIF_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) +#define STMP3XXX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai stmp3xxx_spdif_codec_dai = { + .name = "stmp3xxx spdif", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = STMP3XXX_SPDIF_RATES, + .formats = STMP3XXX_SPDIF_FORMATS, + }, + .ops = { + .hw_params = stmp3xxx_codec_hw_params, + }, +}; +EXPORT_SYMBOL_GPL(stmp3xxx_spdif_codec_dai); + +static int stmp3xxx_codec_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct stmp3xxx_codec_priv *stmp3xxx_spdif; + int ret = 0; + + printk(KERN_INFO + "STMP3XXX SPDIF Audio Transmitter %s\n", STMP3XXX_VERSION); + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + stmp3xxx_spdif = + kzalloc(sizeof(struct stmp3xxx_codec_priv), GFP_KERNEL); + if (stmp3xxx_spdif == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->name = "stmp3xxx spdif"; + codec->owner = THIS_MODULE; + codec->private_data = stmp3xxx_spdif; + codec->read = stmp3xxx_codec_read; + codec->write = stmp3xxx_codec_write; + codec->dai = &stmp3xxx_spdif_codec_dai; + codec->num_dai = 1; + socdev->codec = codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "%s: failed to create pcms\n", __func__); + goto pcm_err; + } + + /* Turn on audio clock */ + stmp3xxx_spdif->dev = &pdev->dev; + stmp3xxx_spdif->clk = clk_get(stmp3xxx_spdif->dev, "spdif"); + if (IS_ERR(stmp3xxx_spdif->clk)) { + ret = PTR_ERR(stmp3xxx_spdif->clk); + printk(KERN_ERR "%s: Clocks initialization failed\n", __func__); + goto clk_err; + } + clk_enable(stmp3xxx_spdif->clk); + + stmp3xxx_codec_init(codec); + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "%s: failed to register card\n", __func__); + goto card_err; + } + + return ret; + +card_err: + clk_disable(stmp3xxx_spdif->clk); + clk_put(stmp3xxx_spdif->clk); +clk_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(socdev->codec); + return ret; +} + +static int stmp3xxx_codec_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct stmp3xxx_codec_priv *stmp3xxx_spdif; + + if (codec == NULL) + return 0; + + stmp3xxx_spdif = codec->private_data; + + clk_disable(stmp3xxx_spdif->clk); + clk_put(stmp3xxx_spdif->clk); + + stmp3xxx_codec_exit(codec); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + kfree(socdev->codec); + + return 0; +} + +#ifdef CONFIG_PM +static int stmp3xxx_codec_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct stmp3xxx_codec_priv *stmp3xxx_spdif; + int ret = -EINVAL; + + if (codec == NULL) + goto out; + + stmp3xxx_spdif = codec->private_data; + + stmp3xxx_codec_spdif_disable(stmp3xxx_spdif); + clk_disable(stmp3xxx_spdif->clk); + ret = 0; + +out: + return ret; +} + +static int stmp3xxx_codec_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct stmp3xxx_codec_priv *stmp3xxx_spdif; + int ret = -EINVAL; + + if (codec == NULL) + goto out; + + stmp3xxx_spdif = codec->private_data; + clk_enable(stmp3xxx_spdif->clk); + + /* Soft reset SPDIF block */ + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_SFTRST); + while (!(HW_SPDIF_CTRL_RD() & BM_SPDIF_CTRL_CLKGATE)); + + stmp3xxx_codec_spdif_enable(stmp3xxx_spdif); + + ret = 0; + +out: + return ret; +} +#else +#define stmp3xxx_codec_suspend NULL +#define stmp3xxx_codec_resume NULL +#endif /* CONFIG_PM */ + +struct snd_soc_codec_device soc_spdif_codec_dev_stmp3xxx = { + .probe = stmp3xxx_codec_probe, + .remove = stmp3xxx_codec_remove, + .suspend = stmp3xxx_codec_suspend, + .resume = stmp3xxx_codec_resume, +}; +EXPORT_SYMBOL_GPL(soc_spdif_codec_dev_stmp3xxx); + +MODULE_DESCRIPTION("STMP3XXX SPDIF transmitter"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/stmp3xxx_spdif.h b/sound/soc/codecs/stmp3xxx_spdif.h new file mode 100644 index 000000000000..0ae20a7e8cc6 --- /dev/null +++ b/sound/soc/codecs/stmp3xxx_spdif.h @@ -0,0 +1,37 @@ +/* + * ALSA SoC STMP378x SPDIF codec driver + * + * Vladimir Barinov <vbarinov@embeddedalley.com> + * + * Copyright 2008 SigmaTel, Inc + * Copyright 2008 Embedded Alley Solutions, Inc + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#ifndef __STMP3XXX_SPDIF_CODEC_H +#define __STMP3XXX_SPDIF_CODEC_H + +#define SPDIF_CTRL_L 0 +#define SPDIF_CTRL_H 1 +#define SPDIF_STAT_L 2 +#define SPDIF_STAT_H 3 +#define SPDIF_FRAMECTRL_L 4 +#define SPDIF_FRAMECTRL_H 5 +#define SPDIF_SRR_L 6 +#define SPDIF_SRR_H 7 +#define SPDIF_DEBUG_L 8 +#define SPDIF_DEBUG_H 9 +#define SPDIF_DATA_L 10 +#define SPDIF_DATA_H 11 +#define SPDIF_VERSION_L 12 +#define SPDIF_VERSION_H 13 + +#define SPDIF_REGNUM 14 + +extern struct snd_soc_dai stmp3xxx_spdif_codec_dai; +extern struct snd_soc_codec_device soc_spdif_codec_dev_stmp3xxx; + +#endif /* __STMP3XXX_SPDIF_CODEC_H */ diff --git a/sound/soc/stmp3xxx/Kconfig b/sound/soc/stmp3xxx/Kconfig new file mode 100644 index 000000000000..5a3ee6067f90 --- /dev/null +++ b/sound/soc/stmp3xxx/Kconfig @@ -0,0 +1,31 @@ +config SND_STMP3XXX_SOC + tristate "SoC Audio for the SigmaTel STMP3XXX chips" + depends on ARCH_STMP3XXX && SND_SOC + select SND_PCM + help + Say Y or M if you want to add support for codecs embedded into + the STMP3XXX chips. + +config SND_STMP3XXX_SOC_DAI + tristate + +config SND_STMP3XXX_SOC_SPDIF_DAI + tristate + +config SND_STMP3XXX_SOC_STMP3780_DEVB + tristate "SoC Audio support for STMP3780 Development Board" + depends on SND_STMP3XXX_SOC && ARCH_STMP378X + select SND_STMP3XXX_SOC_DAI + select SND_SOC_STMP378X_CODEC + help + Say Y if you want to add support for SoC audio on stmp3780 development + board with the stmp378x codec. + +config SND_STMP3XXX_SOC_STMP3780_DEVB_SPDIF + tristate "SoC SPDIF support for STMP3780 Development Board" + depends on SND_STMP3XXX_SOC && ARCH_STMP378X + select SND_STMP3XXX_SOC_SPDIF_DAI + select SND_SOC_STMP3XXX_SPDIF + help + Say Y if you want to add support for SoC audio on stmp3780 development + board with the SPDIF transmitter. diff --git a/sound/soc/stmp3xxx/Makefile b/sound/soc/stmp3xxx/Makefile new file mode 100644 index 000000000000..082e7aaf365c --- /dev/null +++ b/sound/soc/stmp3xxx/Makefile @@ -0,0 +1,15 @@ +# STMP3XXX platfrom support +snd-soc-stmp3xxx-objs := stmp3xxx_pcm.o +snd-soc-stmp3xxx-dai-objs := stmp3xxx_dai.o +snd-soc-stmp3xxx-spdif-dai-objs := stmp3xxx_spdif_dai.o + +obj-$(CONFIG_SND_STMP3XXX_SOC) += snd-soc-stmp3xxx.o +obj-$(CONFIG_SND_STMP3XXX_SOC_DAI) += snd-soc-stmp3xxx-dai.o +obj-$(CONFIG_SND_STMP3XXX_SOC_SPDIF_DAI) += snd-soc-stmp3xxx-spdif-dai.o + +# Machine Support +snd-soc-stmp3780-devb-objs := stmp3780_devb.o +snd-soc-stmp3780-devb-spdif-objs := stmp3780_devb_spdif.o + +obj-$(CONFIG_SND_STMP3XXX_SOC_STMP3780_DEVB) += snd-soc-stmp3780-devb.o +obj-$(CONFIG_SND_STMP3XXX_SOC_STMP3780_DEVB_SPDIF) += snd-soc-stmp3780-devb-spdif.o diff --git a/sound/soc/stmp3xxx/stmp3780_devb.c b/sound/soc/stmp3xxx/stmp3780_devb.c new file mode 100644 index 000000000000..acb6414cc52f --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3780_devb.c @@ -0,0 +1,97 @@ +/* + * ASoC driver for Freescale STMP3780 development board + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <asm/mach-types.h> +#include <asm/dma.h> +#include <mach/hardware.h> +#include <mach/regs-apbx.h> + +#include "../codecs/stmp378x_codec.h" +#include "stmp3xxx_dai.h" +#include "stmp3xxx_pcm.h" + +/* stmp3780 devb digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link stmp3780_devb_dai = { + .name = "STMP378X ADC/DAC", + .stream_name = "STMP378X ADC/DAC", + .cpu_dai = &stmp3xxx_adc_dai, + .codec_dai = &stmp378x_codec_dai, +}; + +/* stmp3780 devb audio machine driver */ +static struct snd_soc_machine snd_soc_machine_stmp3780_devb = { + .name = "STMP3780 Devb", + .dai_link = &stmp3780_devb_dai, + .num_links = 1, +}; + +/* stmp3780 devb audio subsystem */ +static struct snd_soc_device stmp3780_devb_snd_devdata = { + .machine = &snd_soc_machine_stmp3780_devb, + .platform = &stmp3xxx_soc_platform, + .codec_dev = &soc_codec_dev_stmp378x, +}; + +static struct platform_device *stmp3780_devb_snd_device; + +static int __init stmp3780_devb_init(void) +{ + int ret = 0; + + stmp3780_devb_snd_device = platform_device_alloc("soc-audio", 0); + if (!stmp3780_devb_snd_device) + return -ENOMEM; + + platform_set_drvdata(stmp3780_devb_snd_device, + &stmp3780_devb_snd_devdata); + stmp3780_devb_snd_devdata.dev = &stmp3780_devb_snd_device->dev; + stmp3780_devb_snd_device->dev.platform_data = + &stmp3780_devb_snd_devdata; + + if (ret) { + platform_device_put(stmp3780_devb_snd_device); + return ret; + } + + ret = platform_device_add(stmp3780_devb_snd_device); + if (ret) + platform_device_put(stmp3780_devb_snd_device); + + return ret; +} + +static void __exit stmp3780_devb_exit(void) +{ + platform_device_unregister(stmp3780_devb_snd_device); +} + +module_init(stmp3780_devb_init); +module_exit(stmp3780_devb_exit); + +MODULE_AUTHOR("Vladislav Buzov"); +MODULE_DESCRIPTION("STMP3780 development board ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/stmp3xxx/stmp3780_devb_spdif.c b/sound/soc/stmp3xxx/stmp3780_devb_spdif.c new file mode 100644 index 000000000000..c8dbe2cf6958 --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3780_devb_spdif.c @@ -0,0 +1,95 @@ +/* + * ASoC driver for STMP3780 development board + * + * Vladimir Barinov <vbarinov@embeddedalley.com> + * + * Copyright 2008 SigmaTel, Inc + * Copyright 2008 Embedded Alley Solutions, Inc + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <asm/mach-types.h> +#include <asm/dma.h> +#include <mach/hardware.h> +#include <mach/regs-apbx.h> + +#include <mach/stmp3xxx.h> + +#include "../codecs/stmp3xxx_spdif.h" +#include "stmp3xxx_spdif_dai.h" +#include "stmp3xxx_pcm.h" + +/* stmp3780 devb digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link stmp3780_devb_dai = { + .name = "STMP3XXX SPDIF", + .stream_name = "STMP3XXX SPDIF", + .cpu_dai = &stmp3xxx_spdif_dai, + .codec_dai = &stmp3xxx_spdif_codec_dai, +}; + +/* stmp3780 devb audio machine driver */ +static struct snd_soc_machine snd_soc_machine_stmp3780_devb = { + .name = "STMP3780 Devb", + .dai_link = &stmp3780_devb_dai, + .num_links = 1, +}; + +/* stmp3780 devb audio subsystem */ +static struct snd_soc_device stmp3780_devb_snd_devdata = { + .machine = &snd_soc_machine_stmp3780_devb, + .platform = &stmp3xxx_soc_platform, + .codec_dev = &soc_spdif_codec_dev_stmp3xxx, +}; + +static struct platform_device *stmp3780_devb_snd_device; + +static int __init stmp3780_devb_init(void) +{ + int ret = 0; + + stmp3780_devb_snd_device = platform_device_alloc("soc-audio", 1); + if (!stmp3780_devb_snd_device) + return -ENOMEM; + + platform_set_drvdata(stmp3780_devb_snd_device, + &stmp3780_devb_snd_devdata); + stmp3780_devb_snd_devdata.dev = &stmp3780_devb_snd_device->dev; + stmp3780_devb_snd_device->dev.platform_data = + &stmp3780_devb_snd_devdata; + + ret = platform_device_add(stmp3780_devb_snd_device); + if (ret) + goto out; + + ret = spdif_pinmux_request(); +out: + if (ret) + platform_device_put(stmp3780_devb_snd_device); + return ret; +} + +static void __exit stmp3780_devb_exit(void) +{ + spdif_pinmux_release(); + platform_device_unregister(stmp3780_devb_snd_device); +} + +module_init(stmp3780_devb_init); +module_exit(stmp3780_devb_exit); + +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_DESCRIPTION("STMP3780 development board ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/stmp3xxx/stmp3xxx_dai.c b/sound/soc/stmp3xxx/stmp3xxx_dai.c new file mode 100644 index 000000000000..0fa7e1d89bf1 --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3xxx_dai.c @@ -0,0 +1,224 @@ +/* + * ASoC Audio Layer for Freescale STMP37XX/STMP378X ADC/DAC + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <asm/dma.h> +#include <mach/regs-audioin.h> +#include <mach/regs-audioout.h> +#include "stmp3xxx_pcm.h" + +#define STMP3XXX_ADC_RATES SNDRV_PCM_RATE_8000_192000 +#define STMP3XXX_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +struct stmp3xxx_pcm_dma_params stmp3xxx_audio_in = { + .name = "stmp3xxx adc", + .dma_bus = STMP3XXX_BUS_APBX, + .dma_ch = 0, + .irq = IRQ_ADC_DMA, +}; + +struct stmp3xxx_pcm_dma_params stmp3xxx_audio_out = { + .name = "stmp3xxx dac", + .dma_bus = STMP3XXX_BUS_APBX, + .dma_ch = 1, + .irq = IRQ_DAC_DMA, +}; + +static irqreturn_t stmp3xxx_err_irq(int irq, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + u32 ctrl_reg; + u32 overflow_mask; + u32 underflow_mask; + + if (playback) { + ctrl_reg = HW_AUDIOOUT_CTRL_RD(); + underflow_mask = BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ; + overflow_mask = BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ; + } else { + ctrl_reg = HW_AUDIOIN_CTRL_RD(); + underflow_mask = BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ; + overflow_mask = BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ; + } + + if (ctrl_reg & underflow_mask) { + printk(KERN_DEBUG "%s underflow detected\n", + playback ? "DAC" : "ADC"); + + if (playback) + HW_AUDIOOUT_CTRL_CLR( + BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ); + else + HW_AUDIOIN_CTRL_CLR( + BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ); + + } else if (ctrl_reg & overflow_mask) { + printk(KERN_DEBUG "%s overflow detected\n", + playback ? "DAC" : "ADC"); + + if (playback) + HW_AUDIOOUT_CTRL_CLR( + BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ); + else + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ); + } else + printk(KERN_WARNING "Unknown DAC error interrupt\n"); + + return IRQ_HANDLED; +} + +static int stmp3xxx_adc_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (playback) + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_RUN); + else + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_RUN); + break; + + case SNDRV_PCM_TRIGGER_STOP: + if (playback) + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_RUN); + else + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_RUN); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int stmp3xxx_adc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int irq; + int ret; + + if (playback) { + irq = IRQ_DAC_ERROR; + cpu_dai->dma_data = &stmp3xxx_audio_out; + } else { + irq = IRQ_ADC_ERROR; + cpu_dai->dma_data = &stmp3xxx_audio_in; + } + + ret = request_irq(irq, stmp3xxx_err_irq, 0, "STMP3xxx DAC/ADC Error", + substream); + if (ret) { + printk(KERN_ERR "%s: Unable to request ADC/DAC error irq %d\n", + __func__, IRQ_DAC_ERROR); + return ret; + } + + /* Enable error interrupt */ + if (playback) { + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ); + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ); + HW_AUDIOOUT_CTRL_SET(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN); + } else { + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ); + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ); + HW_AUDIOIN_CTRL_SET(BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN); + } + + return 0; +} + +static void stmp3xxx_adc_shutdown(struct snd_pcm_substream *substream) +{ + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + + /* Disable error interrupt */ + if (playback) { + HW_AUDIOOUT_CTRL_CLR(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN); + free_irq(IRQ_DAC_ERROR, substream); + } else { + HW_AUDIOIN_CTRL_CLR(BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN); + free_irq(IRQ_ADC_ERROR, substream); + } +} + +#ifdef CONFIG_PM +static int stmp3xxx_adc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + return 0; +} + +static int stmp3xxx_adc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + return 0; +} +#else +#define stmp3xxx_adc_suspend NULL +#define stmp3xxx_adc_resume NULL +#endif /* CONFIG_PM */ + +struct snd_soc_dai stmp3xxx_adc_dai = { + .name = "stmp3xxx adc/dac", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = stmp3xxx_adc_suspend, + .resume = stmp3xxx_adc_resume, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = STMP3XXX_ADC_RATES, + .formats = STMP3XXX_ADC_FORMATS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = STMP3XXX_ADC_RATES, + .formats = STMP3XXX_ADC_FORMATS, + }, + .ops = { + .startup = stmp3xxx_adc_startup, + .shutdown = stmp3xxx_adc_shutdown, + .trigger = stmp3xxx_adc_trigger, + }, +}; +EXPORT_SYMBOL_GPL(stmp3xxx_adc_dai); + +MODULE_AUTHOR("Vladislav Buzov"); +MODULE_DESCRIPTION("stmp3xxx dac/adc DAI"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/stmp3xxx/stmp3xxx_dai.h b/sound/soc/stmp3xxx/stmp3xxx_dai.h new file mode 100644 index 000000000000..409256a86d15 --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3xxx_dai.h @@ -0,0 +1,21 @@ +/* + * ASoC Audio Layer for Freescale STMP37XX/STMP378X ADC/DAC + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef _STMP3XXX_DEV_H +#define _STMP3XXX_DEV_H +extern struct snd_soc_dai stmp3xxx_adc_dai; +#endif diff --git a/sound/soc/stmp3xxx/stmp3xxx_pcm.c b/sound/soc/stmp3xxx/stmp3xxx_pcm.c new file mode 100644 index 000000000000..79fd5526fe6b --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3xxx_pcm.c @@ -0,0 +1,440 @@ +/* + * ASoC PCM interface for Freescale STMP37XX/STMP378X ADC/DAC + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <asm/dma.h> +#include <mach/hardware.h> + +#include <mach/regs-apbx.h> + +#include "stmp3xxx_pcm.h" + +static const struct snd_pcm_hardware stmp3xxx_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 255, + .buffer_bytes_max = 64 * 1024, + .fifo_size = 32, +}; + +/* + * Required to request DMA channels + */ +struct device *stmp3xxx_pcm_dev; + +struct stmp3xxx_runtime_data { + u32 dma_ch; + u32 dma_period; + u32 dma_totsize; + + struct stmp3xxx_pcm_dma_params *params; + struct stmp3xxx_dma_descriptor *dma_desc_array; +}; + +static irqreturn_t stmp3xxx_pcm_dma_irq(int irq, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + struct stmp3xxx_runtime_data *prtd = substream->runtime->private_data; + +#ifdef CONFIG_ARCH_STMP37XX + u32 err_mask = 1 << (16 + prtd->params->dma_ch); +#endif +#ifdef CONFIG_ARCH_STMP378X + u32 err_mask = 1 << prtd->params->dma_ch; +#endif + u32 irq_mask = 1 << prtd->params->dma_ch; + +#ifdef CONFIG_ARCH_STMP37XX + if (HW_APBX_CTRL1_RD() & err_mask) { +#endif +#ifdef CONFIG_ARCH_STMP378X + if (HW_APBX_CTRL2_RD() & err_mask) { +#endif + printk(KERN_WARNING "%s: DMA audio channel %d (%s) error\n", + __func__, prtd->params->dma_ch, prtd->params->name); +#ifdef CONFIG_ARCH_STMP37XX + HW_APBX_CTRL1_CLR(err_mask); +#endif +#ifdef CONFIG_ARCH_STMP378X + HW_APBX_CTRL2_CLR(err_mask); +#endif + } else if (HW_APBX_CTRL1_RD() & irq_mask) { + stmp3xxx_dma_clear_interrupt(prtd->dma_ch); + snd_pcm_period_elapsed(substream); + } else + printk(KERN_WARNING "%s: Unknown interrupt\n", __func__); + + return IRQ_HANDLED; +} + +/* + * Make a circular DMA descriptor list + */ +static int stmp3xxx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stmp3xxx_runtime_data *prtd = runtime->private_data; + dma_addr_t dma_buffer_phys; + int periods_num, playback, i; + + playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + periods_num = prtd->dma_totsize / prtd->dma_period; + dma_buffer_phys = runtime->dma_addr; + + /* Reset DMA channel, enable interrupt */ + stmp3xxx_dma_reset_channel(prtd->dma_ch); + + /* Set up a DMA chain to sent DMA buffer */ + for (i = 0; i < periods_num; i++) { + int next = (i + 1) % periods_num; + u32 cmd = 0; + + /* Link with previous command */ + prtd->dma_desc_array[i].command->next = + prtd->dma_desc_array[next].handle; + + prtd->dma_desc_array[i].next_descr = + &prtd->dma_desc_array[next]; + + cmd = BF_APBX_CHn_CMD_XFER_COUNT(prtd->dma_period) | + BM_APBX_CHn_CMD_IRQONCMPLT | + BM_APBX_CHn_CMD_CHAIN; + + /* Set DMA direction */ + if (playback) + cmd |= BF_APBX_CHn_CMD_COMMAND( + BV_APBX_CHn_CMD_COMMAND__DMA_READ); + else + cmd |= BF_APBX_CHn_CMD_COMMAND( + BV_APBX_CHn_CMD_COMMAND__DMA_WRITE); + + prtd->dma_desc_array[i].command->cmd = cmd; + prtd->dma_desc_array[i].command->buf_ptr = dma_buffer_phys; + + /* Next data chunk */ + dma_buffer_phys += prtd->dma_period; + } + + return 0; +} + +/* + * Stop circular DMA descriptor list + * We should not stop DMA in a middle of current transaction once we receive + * stop request from ALSA core. This function finds the next DMA descriptor + * and set it up to decrement DMA channel semaphore. So the current transaction + * is the last data transfer. + */ +static void stmp3xxx_pcm_stop(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stmp3xxx_runtime_data *prtd = runtime->private_data; + dma_addr_t pos; + int desc; + + /* Freez DMA channel for a moment */ + stmp3xxx_dma_freeze(prtd->dma_ch); + + /* Find current DMA descriptor */ + pos = HW_APBX_CHn_BAR_RD(prtd->params->dma_ch); + desc = (pos - runtime->dma_addr) / prtd->dma_period; + + /* Set up the next descriptor to decrement DMA channel sempahore */ + prtd->dma_desc_array[desc].next_descr->command->cmd + = BM_APBX_CHn_CMD_SEMAPHORE; + + /* Let the current DMA transaction finish */ + stmp3xxx_dma_unfreeze(prtd->dma_ch); +} + +static int stmp3xxx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct stmp3xxx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + switch (cmd) { + + case SNDRV_PCM_TRIGGER_START: + stmp3xxx_dma_go(prtd->dma_ch, prtd->dma_desc_array, 1); + break; + + case SNDRV_PCM_TRIGGER_STOP: + stmp3xxx_pcm_stop(substream); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + stmp3xxx_dma_unfreeze(prtd->dma_ch); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stmp3xxx_dma_freeze(prtd->dma_ch); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static snd_pcm_uframes_t +stmp3xxx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stmp3xxx_runtime_data *prtd = runtime->private_data; + unsigned int offset; + dma_addr_t pos; + + pos = HW_APBX_CHn_BAR_RD(prtd->params->dma_ch); + offset = bytes_to_frames(runtime, pos - runtime->dma_addr); + + if (offset >= runtime->buffer_size) + offset = 0; + + return offset; +} + +static int stmp3xxx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct stmp3xxx_runtime_data *prtd = substream->runtime->private_data; + + prtd->dma_period = params_period_bytes(hw_params); + prtd->dma_totsize = params_buffer_bytes(hw_params); + + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int stmp3xxx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int stmp3xxx_pcm_dma_request(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct stmp3xxx_runtime_data *prtd = runtime->private_data; + struct stmp3xxx_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data; + int desc_num = stmp3xxx_pcm_hardware.periods_max; + int desc; + int ret; + + if (!dma_data) + return -ENODEV; + + prtd->params = dma_data; + prtd->dma_ch = STMP3xxx_DMA(dma_data->dma_ch, dma_data->dma_bus); + + ret = stmp3xxx_dma_request(prtd->dma_ch, stmp3xxx_pcm_dev, + prtd->params->name); + if (ret) { + printk(KERN_ERR "%s: Failed to request DMA channel (%d:%d)\n", + __func__, dma_data->dma_bus, dma_data->dma_ch); + return ret; + } + + /* Allocate memory for data and pio DMA descriptors */ + prtd->dma_desc_array = + kzalloc(sizeof(struct stmp3xxx_dma_descriptor) * desc_num, + GFP_KERNEL); + if (prtd->dma_desc_array == NULL) { + printk(KERN_ERR "%s: Unable to allocate memory\n", __func__); + stmp3xxx_dma_release(prtd->dma_ch); + return -ENOMEM; + } + + for (desc = 0; desc < desc_num; desc++) { + ret = stmp3xxx_dma_allocate_command(prtd->dma_ch, + &prtd->dma_desc_array[desc]); + if (ret) { + printk(KERN_ERR"%s Unable to allocate DMA command %d\n", + __func__, desc); + goto err; + } + } + + ret = request_irq(prtd->params->irq, stmp3xxx_pcm_dma_irq, 0, + "STMP3xxx PCM DMA", substream); + if (ret) { + printk(KERN_ERR "%s: Unable to request DMA irq %d\n", __func__, + prtd->params->irq); + goto err; + } + + + /* Enable completion interrupt */ + stmp3xxx_dma_clear_interrupt(prtd->dma_ch); + stmp3xxx_dma_enable_interrupt(prtd->dma_ch); + + return 0; + +err: + while (--desc >= 0) + stmp3xxx_dma_free_command(prtd->dma_ch, + &prtd->dma_desc_array[desc]); + kfree(prtd->dma_desc_array); + stmp3xxx_dma_release(prtd->dma_ch); + + return ret; +} + +static int stmp3xxx_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stmp3xxx_runtime_data *prtd; + int ret; + + snd_soc_set_runtime_hwparams(substream, &stmp3xxx_pcm_hardware); + + prtd = kzalloc(sizeof(struct stmp3xxx_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + + runtime->private_data = prtd; + + ret = stmp3xxx_pcm_dma_request(substream); + if (ret) { + printk(KERN_ERR "stmp3xxx_pcm: Failed to request channels\n"); + kfree(prtd); + return ret; + } + + return 0; +} + +static int stmp3xxx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct stmp3xxx_runtime_data *prtd = runtime->private_data; + int desc_num = stmp3xxx_pcm_hardware.periods_max; + int desc; + + /* Free DMA irq */ + free_irq(prtd->params->irq, substream); + + /* Free DMA channel */ + for (desc = 0; desc < desc_num; desc++) + stmp3xxx_dma_free_command(prtd->dma_ch, + &prtd->dma_desc_array[desc]); + kfree(prtd->dma_desc_array); + stmp3xxx_dma_release(prtd->dma_ch); + + /* Free private runtime data */ + kfree(prtd); + + return 0; +} + +static int stmp3xxx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_coherent(NULL, vma, runtime->dma_area, + runtime->dma_addr, runtime->dma_bytes); +} + +struct snd_pcm_ops stmp3xxx_pcm_ops = { + .open = stmp3xxx_pcm_open, + .close = stmp3xxx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = stmp3xxx_pcm_hw_params, + .hw_free = stmp3xxx_pcm_hw_free, + .prepare = stmp3xxx_pcm_prepare, + .trigger = stmp3xxx_pcm_trigger, + .pointer = stmp3xxx_pcm_pointer, + .mmap = stmp3xxx_pcm_mmap, +}; + +static u64 stmp3xxx_pcm_dma_mask = DMA_32BIT_MASK; + +static int stmp3xxx_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + size_t size = stmp3xxx_pcm_hardware.buffer_bytes_max; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &stmp3xxx_pcm_dma_mask; + + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_32BIT_MASK; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, + size, size); + + return 0; +} + +static void stmp3xxx_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +/* + * We need probe/remove callbacks to setup stmp3xxx_pcm_dev + */ +static int stmp3xxx_pcm_probe(struct platform_device *pdev) +{ + stmp3xxx_pcm_dev = &pdev->dev; + return 0; +} + +static int stmp3xxx_pcm_remove(struct platform_device *pdev) +{ + stmp3xxx_pcm_dev = NULL; + return 0; +} + +struct snd_soc_platform stmp3xxx_soc_platform = { + .name = "STMP3xxx Audio", + .pcm_ops = &stmp3xxx_pcm_ops, + .probe = stmp3xxx_pcm_probe, + .remove = stmp3xxx_pcm_remove, + .pcm_new = stmp3xxx_pcm_new, + .pcm_free = stmp3xxx_pcm_free, +}; +EXPORT_SYMBOL_GPL(stmp3xxx_soc_platform); + +MODULE_AUTHOR("Vladislav Buzov"); +MODULE_DESCRIPTION("STMP3xxx DMA Module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/stmp3xxx/stmp3xxx_pcm.h b/sound/soc/stmp3xxx/stmp3xxx_pcm.h new file mode 100644 index 000000000000..78ac9487353f --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3xxx_pcm.h @@ -0,0 +1,30 @@ +/* + * ASoC PCM interface for Freescale STMP37XX/STMP378X ADC/DAC + * + * Author: Vladislav Buzov <vbuzov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef _STMP3XXX_PCM_H +#define _STMP3XXX_PCM_H + +struct stmp3xxx_pcm_dma_params { + char *name; + int dma_bus; /* DMA bus */ + int dma_ch; /* DMA channel number */ + int irq; /* DMA interrupt number */ +}; + +extern struct snd_soc_platform stmp3xxx_soc_platform; + +#endif diff --git a/sound/soc/stmp3xxx/stmp3xxx_spdif_dai.c b/sound/soc/stmp3xxx/stmp3xxx_spdif_dai.c new file mode 100644 index 000000000000..4529b3fcaf42 --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3xxx_spdif_dai.c @@ -0,0 +1,184 @@ +/* + * ALSA SoC SPDIF Audio Layer for STMP3xxx processor familiy + * + * Vladimir Barinov <vbarinov@embeddedalley.com> + * + * Copyright 2008 SigmaTel, Inc + * Copyright 2008 Embedded Alley Solutions, Inc + * Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <asm/dma.h> +#include <mach/regs-spdif.h> +#include "stmp3xxx_pcm.h" + +#define STMP3XXX_SPDIF_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) +#define STMP3XXX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +struct stmp3xxx_pcm_dma_params stmp3xxx_spdif = { + .name = "stmp3xxx spdif", + .dma_bus = STMP3XXX_BUS_APBX, + .dma_ch = 2, + .irq = IRQ_SPDIF_DMA, +}; + +static irqreturn_t stmp3xxx_err_irq(int irq, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + u32 ctrl_reg = 0; + u32 overflow_mask; + u32 underflow_mask; + + if (playback) { + ctrl_reg = HW_SPDIF_CTRL_RD(); + underflow_mask = BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ; + overflow_mask = BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ; + } + + if (ctrl_reg & underflow_mask) { + printk(KERN_DEBUG "underflow detected SPDIF\n"); + + if (playback) + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ); + } else if (ctrl_reg & overflow_mask) { + printk(KERN_DEBUG "overflow detected SPDIF\n"); + + if (playback) + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ); + } else + printk(KERN_WARNING "Unknown SPDIF error interrupt\n"); + + return IRQ_HANDLED; +} + +static int stmp3xxx_spdif_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (playback) + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_RUN); + break; + case SNDRV_PCM_TRIGGER_STOP: + if (playback) + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_RUN); + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + + default: + ret = -EINVAL; + } + + return ret; +} + +static int stmp3xxx_spdif_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int irq; + int ret; + + if (playback) { + irq = IRQ_SPDIF_ERROR; + cpu_dai->dma_data = &stmp3xxx_spdif; + } + + ret = request_irq(irq, stmp3xxx_err_irq, 0, "STMP3xxx SPDIF Error", + substream); + if (ret) { + printk(KERN_ERR "%s: Unable to request SPDIF error irq %d\n", + __func__, IRQ_SPDIF_ERROR); + return ret; + } + + /* Enable error interrupt */ + if (playback) { + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ); + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ); + HW_SPDIF_CTRL_SET(BM_SPDIF_CTRL_FIFO_ERROR_IRQ_EN); + } + + return 0; +} + +static void stmp3xxx_spdif_shutdown(struct snd_pcm_substream *substream) +{ + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + + /* Disable error interrupt */ + if (playback) { + HW_SPDIF_CTRL_CLR(BM_SPDIF_CTRL_FIFO_ERROR_IRQ_EN); + free_irq(IRQ_SPDIF_ERROR, substream); + } +} + +#ifdef CONFIG_PM +static int stmp3xxx_spdif_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + return 0; +} + +static int stmp3xxx_spdif_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + return 0; +} +#else +#define stmp3xxx_spdif_suspend NULL +#define stmp3xxx_spdif_resume NULL +#endif /* CONFIG_PM */ + +struct snd_soc_dai stmp3xxx_spdif_dai = { + .name = "stmp3xxx spdif", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = stmp3xxx_spdif_suspend, + .resume = stmp3xxx_spdif_resume, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = STMP3XXX_SPDIF_RATES, + .formats = STMP3XXX_SPDIF_FORMATS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = STMP3XXX_SPDIF_RATES, + .formats = STMP3XXX_SPDIF_FORMATS, + }, + .ops = { + .startup = stmp3xxx_spdif_startup, + .shutdown = stmp3xxx_spdif_shutdown, + .trigger = stmp3xxx_spdif_trigger, + }, +}; +EXPORT_SYMBOL_GPL(stmp3xxx_spdif_dai); + +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_DESCRIPTION("stmp3xxx SPDIF DAI"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/stmp3xxx/stmp3xxx_spdif_dai.h b/sound/soc/stmp3xxx/stmp3xxx_spdif_dai.h new file mode 100644 index 000000000000..bec3d6fad7c9 --- /dev/null +++ b/sound/soc/stmp3xxx/stmp3xxx_spdif_dai.h @@ -0,0 +1,21 @@ +/* + * ASoC Audio Layer for Freescale STMP3XXX SPDIF transmitter + * + * Author: Vladimir Barinov <vbarinov@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef _STMP3XXX_SPDIF_H +#define _STMP3XXX_SPDIF_H +extern struct snd_soc_dai stmp3xxx_spdif_dai; +#endif |