diff options
159 files changed, 22534 insertions, 525 deletions
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 3d730a772a2b..715cb6a3b543 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -1,14 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.35-rc2 -# Tue Jun 8 17:11:49 2010 +# Linux kernel version: 2.6.36 +# Thu Dec 23 14:43:57 2010 # CONFIG_ARM=y +CONFIG_HAVE_PWM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_GENERIC_GPIO=y -CONFIG_GENERIC_TIME=y # CONFIG_ARCH_USES_GETTIMEOFFSET is not set CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y CONFIG_HAVE_PROC_CPU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_STACKTRACE_SUPPORT=y @@ -18,10 +19,15 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_GENERIC_LOCKBREAK=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +CONFIG_ARCH_HAS_CPUFREQ=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_ARCH_PROVIDES_UDELAY=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_CONSTRUCTORS=y @@ -32,17 +38,16 @@ CONFIG_CONSTRUCTORS=y CONFIG_EXPERIMENTAL=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 -CONFIG_CROSS_COMPILE="" +CONFIG_CROSS_COMPILE="arm-eabi-" CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_LZO=y CONFIG_KERNEL_GZIP=y -# CONFIG_KERNEL_BZIP2 is not set # CONFIG_KERNEL_LZMA is not set # CONFIG_KERNEL_LZO is not set -CONFIG_SWAP=y +# CONFIG_SWAP is not set # CONFIG_SYSVIPC is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set @@ -54,11 +59,10 @@ CONFIG_SWAP=y # CONFIG_TREE_RCU=y # CONFIG_TREE_PREEMPT_RCU is not set -# CONFIG_TINY_RCU is not set # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set -# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_FAST_NO_HZ=y # CONFIG_TREE_RCU_TRACE is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -88,6 +92,7 @@ CONFIG_RD_GZIP=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=10 CONFIG_EMBEDDED=y CONFIG_UID16=y # CONFIG_SYSCTL_SYSCALL is not set @@ -105,6 +110,7 @@ CONFIG_SIGNALFD=y CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y +CONFIG_ASHMEM=y CONFIG_AIO=y CONFIG_HAVE_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y @@ -125,13 +131,13 @@ CONFIG_HAVE_OPROFILE=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y CONFIG_HAVE_CLK=y # # GCOV-based kernel profiling # # CONFIG_GCOV_KERNEL is not set -# CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y @@ -154,8 +160,6 @@ CONFIG_LBDAF=y CONFIG_IOSCHED_NOOP=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set -# CONFIG_DEFAULT_DEADLINE is not set -# CONFIG_DEFAULT_CFQ is not set CONFIG_DEFAULT_NOOP=y CONFIG_DEFAULT_IOSCHED="noop" # CONFIG_INLINE_SPIN_TRYLOCK is not set @@ -186,7 +190,7 @@ CONFIG_DEFAULT_IOSCHED="noop" # CONFIG_INLINE_WRITE_UNLOCK_BH is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y # @@ -216,10 +220,10 @@ CONFIG_MMU=y # 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_DOVE is not set # CONFIG_ARCH_KIRKWOOD is not set # CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_LPC32XX is not set # CONFIG_ARCH_MV78XX0 is not set # CONFIG_ARCH_ORION5X is not set # CONFIG_ARCH_MMP is not set @@ -240,6 +244,7 @@ CONFIG_ARCH_TEGRA=y # CONFIG_ARCH_S5P6442 is not set # CONFIG_ARCH_S5PC100 is not set # CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_S5PV310 is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_U300 is not set @@ -258,12 +263,22 @@ CONFIG_ARCH_TEGRA_2x_SOC=y # Tegra board type # CONFIG_MACH_HARMONY=y +CONFIG_MACH_VENTANA=y +# CONFIG_MACH_WHISTLER is not set # CONFIG_TEGRA_DEBUG_UART_NONE is not set # CONFIG_TEGRA_DEBUG_UARTA is not set # CONFIG_TEGRA_DEBUG_UARTB is not set # CONFIG_TEGRA_DEBUG_UARTC is not set CONFIG_TEGRA_DEBUG_UARTD=y # CONFIG_TEGRA_DEBUG_UARTE is not set +CONFIG_TEGRA_SYSTEM_DMA=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_FIQ_DEBUGGER=y +# CONFIG_TEGRA_EMC_SCALING_ENABLE is not set +CONFIG_TEGRA_CPU_DVFS=y +CONFIG_TEGRA_CORE_DVFS=y +CONFIG_TEGRA_IOVMM_GART=y +CONFIG_TEGRA_IOVMM=y # # Processor Type @@ -289,10 +304,10 @@ CONFIG_ARM_THUMB=y # CONFIG_CPU_ICACHE_DISABLE is not set # CONFIG_CPU_DCACHE_DISABLE is not set # CONFIG_CPU_BPREDICT_DISABLE is not set -CONFIG_HAS_TLS_REG=y CONFIG_OUTER_CACHE=y CONFIG_OUTER_CACHE_SYNC=y CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y CONFIG_ARM_L1_CACHE_SHIFT=5 CONFIG_ARM_DMA_MEM_BUFFERABLE=y CONFIG_ARCH_HAS_BARRIERS=y @@ -300,8 +315,17 @@ CONFIG_CPU_HAS_PMU=y # CONFIG_ARM_ERRATA_430973 is not set # CONFIG_ARM_ERRATA_458693 is not set # CONFIG_ARM_ERRATA_460075 is not set +CONFIG_ARM_ERRATA_742230=y +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set CONFIG_ARM_GIC=y CONFIG_COMMON_CLKDEV=y +CONFIG_FIQ_GLUE=y +CONFIG_FIQ_DEBUGGER=y +# CONFIG_FIQ_DEBUGGER_NO_SLEEP is not set +# CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set +# CONFIG_FIQ_DEBUGGER_CONSOLE is not set # # Bus support @@ -337,12 +361,12 @@ CONFIG_AEABI=y # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set CONFIG_HIGHMEM=y +# CONFIG_SPARSE_IRQ 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_HAVE_MEMBLOCK=y CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_PHYS_ADDR_T_64BIT is not set @@ -351,8 +375,11 @@ CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_ALIGNMENT_TRAP=y # CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set # # Boot options @@ -363,11 +390,31 @@ CONFIG_CMDLINE="mem=448M@0M console=ttyS0,115200n8 earlyprintk init=/bin/ash" # CONFIG_CMDLINE_FORCE is not set # CONFIG_XIP_KERNEL is not set # CONFIG_KEXEC is not set +# CONFIG_AUTO_ZRELADDR is not set # # CPU Power Management # -# CONFIG_CPU_IDLE is not set +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 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y # # Floating point emulation @@ -395,10 +442,19 @@ CONFIG_PM=y # CONFIG_PM_DEBUG is not set CONFIG_PM_SLEEP_SMP=y CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_NVS=y CONFIG_SUSPEND=y CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +CONFIG_FB_EARLYSUSPEND=y # CONFIG_APM_EMULATION is not set -# CONFIG_PM_RUNTIME is not set +CONFIG_PM_RUNTIME=y CONFIG_PM_OPS=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -461,8 +517,143 @@ CONFIG_IPV6_TUNNEL=y CONFIG_IPV6_MULTIPLE_TABLES=y # CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y # CONFIG_NETWORK_SECMARK is not set -# CONFIG_NETFILTER is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_ADDRTYPE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +# CONFIG_NF_NAT_SNMP_BASIC is not set +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_NF_NAT_SIP=y +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set # CONFIG_RDS is not set @@ -482,9 +673,62 @@ CONFIG_IPV6_MULTIPLE_TABLES=y # CONFIG_WAN_ROUTER is not set # CONFIG_PHONET is not set # CONFIG_IEEE802154 is not set -# CONFIG_NET_SCHED is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# 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 +# CONFIG_NET_SCH_DRR is not set +CONFIG_NET_SCH_INGRESS=y + +# +# Classification +# +CONFIG_NET_CLS=y +# 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=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK 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_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y # CONFIG_DCB is not set -CONFIG_RPS=y +# CONFIG_RPS is not set # # Network testing @@ -493,12 +737,53 @@ CONFIG_RPS=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -# CONFIG_BT is not set +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +# CONFIG_BT_BNEP_MC_FILTER is not set +# CONFIG_BT_BNEP_PROTO_FILTER is not set +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_LL=y +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set # CONFIG_AF_RXRPC is not set CONFIG_FIB_RULES=y -# CONFIG_WIRELESS is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_PRIV=y +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# + +# +# Some wireless drivers require a rate control algorithm +# # CONFIG_WIMAX is not set -# CONFIG_RFKILL is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set # CONFIG_NET_9P is not set # CONFIG_CAIF is not set @@ -520,7 +805,96 @@ CONFIG_EXTRA_FIRMWARE="" # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # CONFIG_CONNECTOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS 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_SM_FTL 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_NAND_TEGRA=y +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SST25L 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_IDS=y +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set @@ -531,19 +905,50 @@ CONFIG_BLK_DEV_LOOP=y # DRBD disabled because PROC_FS, INET or CONNECTOR not selected # # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set # CONFIG_MG_DISK is not set CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set # CONFIG_ANDROID_PMEM is not set +# CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set +CONFIG_KERNEL_DEBUGGER_CORE=y +# CONFIG_ISL29003 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_HMC6352 is not set +# CONFIG_SENSORS_AK8975 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +CONFIG_BCM4329_RFKILL=y # CONFIG_C2PORT is not set # # EEPROM support # +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set # CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Motion Sensors Support +# +CONFIG_SENSORS_MPU3050=y +# CONFIG_SENSORS_MPU3050_DEBUG is not set +# CONFIG_SENSORS_ACCELEROMETER_NONE is not set +CONFIG_SENSORS_KXTF9_MPU=y +# CONFIG_SENSORS_COMPASS_NONE is not set +CONFIG_SENSORS_AK8975_MPU=y CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -552,29 +957,152 @@ CONFIG_HAVE_IDE=y # CONFIG_SCSI_MOD=y # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set -# CONFIG_SCSI_DMA 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=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# 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=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set # CONFIG_ATA is not set -# CONFIG_MD is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y CONFIG_NETDEVICES=y +# CONFIG_IFB is not set CONFIG_DUMMY=y # 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_NET_ETHERNET is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +CONFIG_SMC91X=y +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_B44 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +CONFIG_BCM4329=m +CONFIG_BCM4329_FW_PATH="/system/vendor/firmware/fw_bcm4329.bin" +CONFIG_BCM4329_NVRAM_PATH="/system/etc/nvram.txt" +CONFIG_BCM4329_WIFI_CONTROL_FUNC=y +# CONFIG_BCM4329_DHD_USE_STATIC_BUF is not set +# CONFIG_BCM4329_HW_OOB is not set +# CONFIG_BCM4329_OOB_INTR_ONLY is not set +# CONFIG_BCM4329_GET_CUSTOM_MAC_ENABLE is not set +# CONFIG_HOSTAP is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers # + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_AX8817X is not set +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_ARMLINUX is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set # CONFIG_WAN is not set -# CONFIG_PPP is not set + +# +# CAIF transport drivers +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y # CONFIG_SLIP is not set +CONFIG_SLHC=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set @@ -584,7 +1112,85 @@ CONFIG_DUMMY=y # # Input device support # -# CONFIG_INPUT is not set +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_KEYRESET=y + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_TEGRA is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_QT602240 is not set +CONFIG_TOUCHSCREEN_PANJIT_I2C=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +CONFIG_TOUCHSCREEN_ATMEL_MT_T9=y +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set # # Hardware I/O ports @@ -596,7 +1202,8 @@ CONFIG_DUMMY=y # Character devices # # CONFIG_VT is not set -# CONFIG_DEVKMEM is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_N_GSM is not set @@ -612,6 +1219,9 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # # Non-8250 serial port support # +CONFIG_SERIAL_TEGRA=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_TIMBERDALE is not set @@ -625,9 +1235,67 @@ CONFIG_UNIX98_PTYS=y # CONFIG_R3964 is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set # CONFIG_RAMOOPS is not set -# CONFIG_I2C is not set -# CONFIG_SPI is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +CONFIG_I2C_TEGRA=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB 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_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_TEGRA=y +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set # # PPS support @@ -636,7 +1304,7 @@ CONFIG_UNIX98_PTYS=y CONFIG_ARCH_REQUIRE_GPIOLIB=y CONFIG_GPIOLIB=y # CONFIG_DEBUG_GPIO is not set -# CONFIG_GPIO_SYSFS is not set +CONFIG_GPIO_SYSFS=y # # Memory mapped GPIO expanders: @@ -646,6 +1314,13 @@ CONFIG_GPIOLIB=y # # I2C GPIO expanders: # +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +CONFIG_GPIO_PCA953X=y +# CONFIG_GPIO_PCA953X_IRQ is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set # # PCI GPIO expanders: @@ -654,6 +1329,9 @@ CONFIG_GPIOLIB=y # # SPI GPIO expanders: # +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set # # AC97 GPIO expanders: @@ -663,8 +1341,95 @@ CONFIG_GPIOLIB=y # MODULbus GPIO expanders: # # CONFIG_W1 is not set -# CONFIG_POWER_SUPPLY is not set -# CONFIG_HWMON is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_BQ20Z75 is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +CONFIG_SENSORS_NCT1008_I2C=y +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set # CONFIG_THERMAL is not set # CONFIG_WATCHDOG is not set CONFIG_SSB_POSSIBLE=y @@ -673,7 +1438,38 @@ CONFIG_SSB_POSSIBLE=y # Sonics Silicon Backplane # # CONFIG_SSB is not set -# CONFIG_MFD_SUPPORT is not set +CONFIG_MFD_SUPPORT=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC35892 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MAX8907C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_AB8500_CORE is not set +CONFIG_MFD_TPS6586X=y CONFIG_REGULATOR=y # CONFIG_REGULATOR_DEBUG is not set CONFIG_REGULATOR_DUMMY=y @@ -681,11 +1477,99 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_VIRTUAL_CONSUMER=y # CONFIG_REGULATOR_USERSPACE_CONSUMER is not set # CONFIG_REGULATOR_BQ24022 is not set -# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_TPS6586X=y +CONFIG_MEDIA_SUPPORT=y + +# +# 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_IR_CORE=y +CONFIG_VIDEO_IR=y +CONFIG_LIRC=y +# CONFIG_RC_MAP is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_SONY_DECODER is not set +CONFIG_IR_LIRC_CODEC=y +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE 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_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=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=y +CONFIG_VIDEO_IR_I2C=y +CONFIG_TEGRA_RPC=y +CONFIG_TEGRA_AVP=y +CONFIG_TEGRA_CAMERA=y +CONFIG_VIDEO_OV5650=y +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_SOC_CAMERA is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_GSPCA is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_DAB is not set # # Graphics support # +# CONFIG_DRM is not set # CONFIG_VGASTATE is not set CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y @@ -704,37 +1588,529 @@ CONFIG_FB_CFB_IMAGEBLIT=y # 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_MODE_HELPERS=y # CONFIG_FB_TILEBLITTING is not set # # Frame buffer hardware drivers # # CONFIG_FB_S1D13XXX is not set -CONFIG_FB_TEGRA=y +# CONFIG_FB_TMIO is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set # CONFIG_FB_BROADSHEET is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# NVIDIA Tegra Display Driver options +# +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_FB_TEGRA=y +CONFIG_TEGRA_NVMAP=y +CONFIG_NVMAP_RECLAIM_UNPINNED_VM=y +CONFIG_NVMAP_ALLOW_SYSMEM=y +# CONFIG_NVMAP_HIGHMEM_ONLY is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +# CONFIG_BACKLIGHT_ADP8860 is not set # # Display device support # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_LOGO is not set -# CONFIG_SOUND is not set -# CONFIG_USB_SUPPORT is not set -# CONFIG_MMC is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +CONFIG_SND_SOC=y +CONFIG_TEGRA_ALSA=y +CONFIG_TEGRA_PCM=y +CONFIG_TEGRA_I2S=y +CONFIG_TEGRA_IEC=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WM8903=y +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_3M_PCT is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CANDO is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EGALAX is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MOSART is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_STANTUM is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +CONFIG_USB_TEGRA_HCD=y +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +CONFIG_USB_WDM=y +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_FSL_USB2=y +CONFIG_USB_FSL_USB2=y +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_ANDROID=y +# CONFIG_USB_ANDROID_ACM is not set +CONFIG_USB_ANDROID_ADB=y +# CONFIG_USB_ANDROID_MASS_STORAGE is not set +CONFIG_USB_ANDROID_MTP=y +# CONFIG_USB_ANDROID_RNDIS is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_TEGRA_OTG=y +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PLTFM is not set +CONFIG_MMC_SDHCI_TEGRA=y # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set # CONFIG_ACCESSIBILITY is not set CONFIG_RTC_LIB=y -# CONFIG_RTC_CLASS is not set +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 is not set +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=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_DS3232 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_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_TEGRA 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_BQ32K is not set +CONFIG_RTC_DRV_TPS6586X=y +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 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 +# CONFIG_RTC_DRV_PCF2123 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_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# # CONFIG_DMADEVICES is not set # CONFIG_AUXDISPLAY is not set # CONFIG_UIO is not set -# CONFIG_STAGING is not set +CONFIG_STAGING=y +# CONFIG_STAGING_EXCLUDE_BUILD is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_USB_IP_COMMON is not set +# CONFIG_ECHO is not set +# CONFIG_RT2870 is not set +# CONFIG_COMEDI is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_TRANZPORT is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE=128 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE=16 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE=8 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d +# CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +# CONFIG_ANDROID_TIMED_GPIO is not set +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +# CONFIG_POHMELFS is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_FB_UDL is not set +CONFIG_IIO=y +# CONFIG_IIO_RING_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set + +# +# Accelerometers +# +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_KXSD9 is not set +# CONFIG_LIS3L02DQ is not set + +# +# Analog to digital convertors +# +# CONFIG_MAX1363 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16260 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16300 is not set +# CONFIG_ADIS16350 is not set +# CONFIG_ADIS16400 is not set + +# +# Light sensors +# +# CONFIG_SENSORS_TSL2563 is not set +CONFIG_ISL29018=y + +# +# Magnetometer sensors +# +# CONFIG_SENSORS_HMC5843 is not set + +# +# Triggers - standalone +# +# CONFIG_ZRAM is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_FB_SM7XX is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_ST_BT is not set +# CONFIG_ADIS16255 is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_EASYCAP is not set # # File systems @@ -749,9 +2125,15 @@ 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_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set @@ -764,12 +2146,12 @@ CONFIG_FS_POSIX_ACL=y CONFIG_FILE_LOCKING=y CONFIG_FSNOTIFY=y # CONFIG_DNOTIFY is not set -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 +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set # # Caches @@ -811,6 +2193,8 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_YAFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_LOGFS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set @@ -835,8 +2219,25 @@ CONFIG_NETWORK_FILESYSTEMS=y # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y @@ -893,9 +2294,8 @@ CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_SHIRQ is not set -CONFIG_DETECT_SOFTLOCKUP=y -# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set CONFIG_DETECT_HUNG_TASK=y # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 @@ -903,28 +2303,29 @@ CONFIG_SCHED_DEBUG=y CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set -CONFIG_DEBUG_SLAB=y -# CONFIG_DEBUG_SLAB_LEAK is not set +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_KMEMLEAK is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_DEBUG_RT_MUTEXES is not set # CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set -CONFIG_DEBUG_MUTEXES=y +# CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set # CONFIG_LOCK_STAT is not set -CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_HIGHMEM is not set -CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set CONFIG_DEBUG_VM=y # CONFIG_DEBUG_WRITECOUNT is not set # CONFIG_DEBUG_MEMORY_INIT is not set # CONFIG_DEBUG_LIST is not set -CONFIG_DEBUG_SG=y +# CONFIG_DEBUG_SG is not set # CONFIG_DEBUG_NOTIFIERS is not set # CONFIG_DEBUG_CREDENTIALS is not set # CONFIG_BOOT_PRINTK_DELAY is not set @@ -946,13 +2347,10 @@ CONFIG_FTRACE=y # CONFIG_PREEMPT_TRACER is not set # CONFIG_SCHED_TRACER is not set # CONFIG_ENABLE_DEFAULT_TRACERS is not set -# CONFIG_BOOT_TRACER is not set CONFIG_BRANCH_PROFILE_NONE=y # CONFIG_PROFILE_ANNOTATED_BRANCHES is not set # CONFIG_PROFILE_ALL_BRANCHES is not set # CONFIG_STACK_TRACER is not set -# CONFIG_KMEMTRACE is not set -# CONFIG_WORKQUEUE_TRACER is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_ATOMIC64_SELFTEST is not set @@ -963,9 +2361,7 @@ CONFIG_ARM_UNWIND=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_ERRORS is not set # CONFIG_DEBUG_STACK_USAGE is not set -CONFIG_DEBUG_LL=y -CONFIG_EARLY_PRINTK=y -# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_LL is not set # CONFIG_OC_ETM is not set # @@ -974,9 +2370,6 @@ CONFIG_EARLY_PRINTK=y # CONFIG_KEYS is not set # CONFIG_SECURITY is not set # CONFIG_SECURITYFS is not set -# CONFIG_DEFAULT_SECURITY_SELINUX is not set -# CONFIG_DEFAULT_SECURITY_SMACK is not set -# CONFIG_DEFAULT_SECURITY_TOMOYO is not set CONFIG_DEFAULT_SECURITY_DAC=y CONFIG_DEFAULT_SECURITY="" CONFIG_CRYPTO=y @@ -993,9 +2386,10 @@ CONFIG_CRYPTO_BLKCIPHER2=y CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_RNG2=y -CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_PCOMP2=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y # CONFIG_CRYPTO_GF128MUL is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_PCRYPT is not set @@ -1032,7 +2426,7 @@ CONFIG_CRYPTO_HMAC=y # # Digest # -# CONFIG_CRYPTO_CRC32C is not set +CONFIG_CRYPTO_CRC32C=y # CONFIG_CRYPTO_GHASH is not set # CONFIG_CRYPTO_MD4 is not set CONFIG_CRYPTO_MD5=y @@ -1079,6 +2473,7 @@ CONFIG_CRYPTO_DEFLATE=y # # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_TEGRA_AES is not set # CONFIG_BINARY_PRINTF is not set # @@ -1092,10 +2487,17 @@ CONFIG_CRC16=y # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y # CONFIG_CRC7 is not set -# CONFIG_LIBCRC32C is not set +CONFIG_LIBCRC32C=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_DECOMPRESS_GZIP=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y diff --git a/arch/arm/configs/tegra_whistler_android_defconfig b/arch/arm/configs/tegra_whistler_android_defconfig new file mode 100644 index 000000000000..e48c7ff61625 --- /dev/null +++ b/arch/arm/configs/tegra_whistler_android_defconfig @@ -0,0 +1,2384 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.36 +# Mon Dec 20 16:39:50 2010 +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_LOCKBREAK=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_ARCH_HAS_DEFAULT_IDLE=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_ARCH_PROVIDES_UDELAY=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="arm-eabi-" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_SWAP is not set +# CONFIG_SYSVIPC is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +CONFIG_RCU_FAST_NO_HZ=y +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +# CONFIG_CGROUP_NS is not set +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=10 +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_COMPAT_BRK=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +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 is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# 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_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_STMP3XXX is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X 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_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set +CONFIG_ARCH_TEGRA=y +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P6440 is not set +# CONFIG_ARCH_S5P6442 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_S5PV310 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set + +# +# NVIDIA Tegra options +# +CONFIG_ARCH_TEGRA_2x_SOC=y + +# +# Tegra board type +# +CONFIG_MACH_HARMONY=y +CONFIG_MACH_VENTANA=y +CONFIG_MACH_WHISTLER=y +# CONFIG_TEGRA_DEBUG_UART_NONE is not set +CONFIG_TEGRA_DEBUG_UARTA=y +# CONFIG_TEGRA_DEBUG_UARTB is not set +# CONFIG_TEGRA_DEBUG_UARTC is not set +# CONFIG_TEGRA_DEBUG_UARTD is not set +# CONFIG_TEGRA_DEBUG_UARTE is not set +CONFIG_TEGRA_SYSTEM_DMA=y +CONFIG_TEGRA_PWM=y +CONFIG_TEGRA_FIQ_DEBUGGER=y +# CONFIG_TEGRA_EMC_SCALING_ENABLE is not set +CONFIG_TEGRA_CPU_DVFS=y +CONFIG_TEGRA_CORE_DVFS=y +CONFIG_TEGRA_IOVMM_GART=y +CONFIG_TEGRA_IOVMM=y + +# +# Processor Type +# +CONFIG_CPU_32v6K=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARCH_HAS_BARRIERS=y +CONFIG_CPU_HAS_PMU=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +CONFIG_ARM_ERRATA_742230=y +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_743622 is not set +CONFIG_ARM_GIC=y +CONFIG_COMMON_CLKDEV=y +CONFIG_FIQ_GLUE=y +CONFIG_FIQ_DEBUGGER=y +# CONFIG_FIQ_DEBUGGER_NO_SLEEP is not set +# CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set +# CONFIG_FIQ_DEBUGGER_CONSOLE is not set + +# +# Bus support +# +# 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_SMP=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_TWD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=2 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_HZ=100 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HIGHMEM=y +# CONFIG_SPARSE_IRQ is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="mem=448M@0M console=ttyS0,115200n8 earlyprintk init=/bin/ash" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_AUTO_ZRELADDR 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 is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y +CONFIG_VFPv3=y +# CONFIG_NEON is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +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_SMP=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_NVS=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +CONFIG_FB_EARLYSUSPEND=y +# CONFIG_APM_EMULATION is not set +CONFIG_PM_RUNTIME=y +CONFIG_PM_OPS=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=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_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# 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=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_ADDRTYPE=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_LOG=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +# CONFIG_NF_NAT_SNMP_BASIC is not set +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_NF_NAT_SIP=y +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP 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_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# 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 +# CONFIG_NET_SCH_DRR is not set +CONFIG_NET_SCH_INGRESS=y + +# +# Classification +# +CONFIG_NET_CLS=y +# 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=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK 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_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_RPS is not set + +# +# 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_FIB_RULES=y +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# + +# +# Some wireless drivers require a rate control algorithm +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS 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_SM_FTL 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_NAND_TEGRA=y +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SST25L 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_IDS=y +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_ANDROID_PMEM is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +CONFIG_KERNEL_DEBUGGER_CORE=y +# CONFIG_ISL29003 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_HMC6352 is not set +CONFIG_SENSORS_AK8975=y +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085 is not set +# CONFIG_APANIC is not set +# CONFIG_BCM4329_RFKILL is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Motion Sensors Support +# +# CONFIG_SENSORS_MPU3050 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# 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=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# 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=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +CONFIG_NETDEVICES=y +# CONFIG_IFB is not set +CONFIG_DUMMY=y +# 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_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +CONFIG_SMC91X=y +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET 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_B44 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_BCM4329 is not set +# CONFIG_HOSTAP is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_KEYRESET=y + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_TEGRA=y +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_QT602240 is not set +# CONFIG_TOUCHSCREEN_PANJIT_I2C is not set +CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_ATMEL_MT_T9 is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_TEGRA=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +CONFIG_I2C_TEGRA=y +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB 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_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_TEGRA=y +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_PDA_POWER=y +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2782 is not set +CONFIG_BATTERY_BQ20Z75=y +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_NCT1008_I2C is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_MFD_SUPPORT=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC35892 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8998 is not set +CONFIG_MFD_MAX8907C=y +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13783 is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_AB8500_CORE is not set +CONFIG_MFD_TPS6586X=y +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8907C=y +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_TPS6586X=y +CONFIG_MEDIA_SUPPORT=y + +# +# 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_IR_CORE=y +CONFIG_VIDEO_IR=y +CONFIG_LIRC=y +# CONFIG_RC_MAP is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_SONY_DECODER is not set +CONFIG_IR_LIRC_CODEC=y +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE 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_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=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=y +CONFIG_VIDEO_IR_I2C=y +CONFIG_TEGRA_RPC=y +CONFIG_TEGRA_AVP=y +CONFIG_TEGRA_CAMERA=y +# CONFIG_VIDEO_OV5650 is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_SOC_CAMERA is not set +CONFIG_V4L_USB_DRIVERS=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_GSPCA is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_USB_ET61X251 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_I2C_SI4713 is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_RADIO_SI470X is not set +# CONFIG_USB_MR800 is not set +# CONFIG_RADIO_TEA5764 is not set +# CONFIG_RADIO_SAA7706H is not set +# CONFIG_RADIO_TEF6862 is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +CONFIG_VIDEO_OUTPUT_CONTROL=y +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=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set + +# +# NVIDIA Tegra Display Driver options +# +CONFIG_TEGRA_GRHOST=y +CONFIG_TEGRA_DC=y +CONFIG_FB_TEGRA=y +CONFIG_TEGRA_NVMAP=y +CONFIG_NVMAP_RECLAIM_UNPINNED_VM=y +CONFIG_NVMAP_ALLOW_SYSMEM=y +# CONFIG_NVMAP_HIGHMEM_ONLY is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +# CONFIG_BACKLIGHT_ADP8860 is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_LOGO is not set +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_3M_PCT is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CANDO is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EGALAX is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MOSART is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_STANTUM is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +CONFIG_USB_TEGRA_HCD=y +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_SELECTED=y +CONFIG_USB_GADGET_FSL_USB2=y +CONFIG_USB_FSL_USB2=y +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_ANDROID=y +# CONFIG_USB_ANDROID_ACM is not set +CONFIG_USB_ANDROID_ADB=y +# CONFIG_USB_ANDROID_MASS_STORAGE is not set +CONFIG_USB_ANDROID_MTP=y +# CONFIG_USB_ANDROID_RNDIS is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_USB_TEGRA_OTG=y +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_EMBEDDED_SDIO=y +CONFIG_MMC_PARANOID_SD_INIT=y + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PLTFM is not set +CONFIG_MMC_SDHCI_TEGRA=y +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +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 is not set +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=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_DS3232 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_ISL12022 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_BQ32K is not set +CONFIG_RTC_DRV_TPS6586X=y +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 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 +# CONFIG_RTC_DRV_PCF2123 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_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +CONFIG_STAGING=y +# CONFIG_STAGING_EXCLUDE_BUILD is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_USB_IP_COMMON is not set +# CONFIG_ECHO is not set +# CONFIG_RT2870 is not set +# CONFIG_COMEDI is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_TRANZPORT is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE=128 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE=16 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE=8 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d +# CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +# CONFIG_ANDROID_TIMED_GPIO is not set +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +# CONFIG_POHMELFS is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +# CONFIG_FB_UDL is not set +CONFIG_IIO=y +# CONFIG_IIO_RING_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set + +# +# Accelerometers +# +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_KXSD9 is not set +# CONFIG_LIS3L02DQ is not set + +# +# Analog to digital convertors +# +# CONFIG_MAX1363 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16260 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16300 is not set +# CONFIG_ADIS16350 is not set +# CONFIG_ADIS16400 is not set + +# +# Light sensors +# +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_ISL29018 is not set + +# +# Magnetometer sensors +# +# CONFIG_SENSORS_HMC5843 is not set + +# +# Triggers - standalone +# +# CONFIG_ZRAM is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_FB_SM7XX is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_ADIS16255 is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_EASYCAP 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_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_XATTR=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE 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 is not set +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 +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_YAFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS 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 is not set +# CONFIG_NFSD is not set +# CONFIG_SMB_FS is not set +# CONFIG_CEPH_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=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +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 is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +CONFIG_DEBUG_VM=y +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_OC_ETM is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=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_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# 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 +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH 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=y +# 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=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# 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=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_TEGRA_AES is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_CRC_CCITT=y +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=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 5078dc6c50d8..8c885b6f97f8 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -137,10 +137,10 @@ #endif /* - * This flag is used to indicate that the page pointed to by a pte - * is dirty and requires cleaning before returning it to the user. + * This flag is used to indicate that the page pointed to by a pte is clean + * and does not require cleaning before returning it to the user. */ -#define PG_dcache_dirty PG_arch_1 +#define PG_dcache_clean PG_arch_1 /* * MM Cache Management diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 73ee18b1a054..ab08cd74e7d3 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -279,9 +279,24 @@ extern struct page *empty_zero_page; #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) -#define set_pte_at(mm,addr,ptep,pteval) do { \ - set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \ - } while (0) +#ifndef CONFIG_SMP +static inline void __sync_icache_dcache(pte_t pteval) +{ +} +#else +extern void __sync_icache_dcache(pte_t pteval); +#endif + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + if (addr >= TASK_SIZE) + set_pte_ext(ptep, pteval, 0); + else { + __sync_icache_dcache(pteval); + set_pte_ext(ptep, pteval, PTE_EXT_NG); + } +} /* * The following only work if pte_present() is true. @@ -293,6 +308,10 @@ extern struct page *empty_zero_page; #define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG) #define pte_special(pte) (0) +#define pte_present_exec_user(pte) \ + ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_EXEC | L_PTE_USER)) == \ + (L_PTE_PRESENT | L_PTE_EXEC | L_PTE_USER)) + #define PTE_BIT_FUNC(fn,op) \ static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 33b546ae72d4..12c90ada8f6b 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -560,12 +560,20 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); #endif /* - * if PG_dcache_dirty is set for the page, we need to ensure that any + * If PG_dcache_clean is not set for the page, we need to ensure that any * cache entries for the kernels virtual memory range are written - * back to the page. + * back to the page. On SMP systems, the cache coherency is handled in the + * set_pte_at() function. */ +#ifndef CONFIG_SMP extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep); +#else +static inline void update_mmu_cache(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ +} +#endif #endif diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index e94c092b1560..f38f4ed94b5b 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -29,6 +29,11 @@ config MACH_VENTANA help Support for NVIDIA Ventana development platform +config MACH_WHISTLER + bool "Whistler board" + help + Support for NVIDIA Whistler development platform + choice prompt "Low-level debug console UART" default TEGRA_DEBUG_UART_NONE diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index b2374b94d9ea..f8ecbf3fba8e 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -1,6 +1,7 @@ obj-y += common.o obj-y += io.o obj-y += irq.o legacy_irq.o +obj-y += syncpt.o obj-y += clock.o obj-y += dvfs.o obj-y += timer.o @@ -9,11 +10,15 @@ obj-y += pinmux.o obj-y += devices.o obj-y += delay.o obj-y += powergate.o -obj-y += suspend.o -obj-y += fuse.o -obj-y += tegra_i2s_audio.o -obj-y += tegra_spdif_audio.o -obj-y += mc.o +obj-y += suspend.o +obj-y += fuse.o +ifeq ($(CONFIG_TEGRA_ALSA),y) +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_i2s.o +else +obj-y += tegra_i2s_audio.o +endif +obj-y += tegra_spdif_audio.o +obj-y += mc.o obj-$(CONFIG_USB_SUPPORT) += usb_phy.o obj-$(CONFIG_FIQ) += fiq.o obj-$(CONFIG_TEGRA_FIQ_DEBUGGER) += tegra_fiq_debugger.o @@ -24,6 +29,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_fuse.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_speedo.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += suspend-t2.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_save.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o @@ -32,10 +38,11 @@ obj-$(CONFIG_CPU_V7) += cortex-a9.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o obj-$(CONFIG_SMP) += localtimer.o obj-$(CONFIG_SMP) += platsmp.o +obj-y += headsmp.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += headsmp-t2.o -obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o +obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o -obj-$(CONFIG_CPU_IDLE) += cpuidle.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_TEGRA_IOVMM) += iovmm.o obj-$(CONFIG_TEGRA_IOVMM_GART) += iovmm-gart.o @@ -49,3 +56,12 @@ obj-${CONFIG_MACH_VENTANA} += board-ventana-pinmux.o obj-${CONFIG_MACH_VENTANA} += board-ventana-sdhci.o obj-${CONFIG_MACH_VENTANA} += board-ventana-power.o obj-${CONFIG_MACH_VENTANA} += board-ventana-panel.o +obj-${CONFIG_MACH_VENTANA} += board-ventana-sensors.o +obj-${CONFIG_MACH_VENTANA} += board-ventana-kbc.o + +obj-${CONFIG_MACH_WHISTLER} += board-whistler.o +obj-${CONFIG_MACH_WHISTLER} += board-whistler-pinmux.o +obj-${CONFIG_MACH_WHISTLER} += board-whistler-sdhci.o +obj-${CONFIG_MACH_WHISTLER} += board-whistler-power.o +obj-${CONFIG_MACH_WHISTLER} += board-whistler-panel.o +obj-${CONFIG_MACH_WHISTLER} += board-whistler-kbc.o diff --git a/arch/arm/mach-tegra/board-harmony-panel.c b/arch/arm/mach-tegra/board-harmony-panel.c index 309d72e4b490..e86b2a87489e 100644 --- a/arch/arm/mach-tegra/board-harmony-panel.c +++ b/arch/arm/mach-tegra/board-harmony-panel.c @@ -21,21 +21,27 @@ #include <mach/iomap.h> #include <mach/tegra_fb.h> +#define FBMEM_BASE 0x1c012000 +#define FBMEM_SIZE 0x500000 + /* Framebuffer */ static struct resource fb_resource[] = { [0] = { + .name = "irq", .start = INT_DISPLAY_GENERAL, .end = INT_DISPLAY_GENERAL, .flags = IORESOURCE_IRQ, }, [1] = { + .name = "regs", .start = TEGRA_DISPLAY_BASE, .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1, .flags = IORESOURCE_MEM, }, [2] = { - .start = 0x1c012000, - .end = 0x1c012000 + 0x500000 - 1, + .name = "fbmem", + .start = FBMEM_BASE, + .end = FBMEM_BASE + FBMEM_SIZE - 1, .flags = IORESOURCE_MEM, }, }; diff --git a/arch/arm/mach-tegra/board-ventana-kbc.c b/arch/arm/mach-tegra/board-ventana-kbc.c new file mode 100644 index 000000000000..869af114fa90 --- /dev/null +++ b/arch/arm/mach-tegra/board-ventana-kbc.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2010 NVIDIA, 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. + * + * 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 + */ + +/* +* Warning: Ventana might need some hardware rework to be able to work with +* kbc-driver. Default Ventana h/w configuration should use GPIO keyboard +* driver instead +*/ + + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/device.h> + +#include <mach/clk.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/pinmux.h> +#include <mach/iomap.h> +#include <mach/io.h> +#include <mach/kbc.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + + +static int plain_kbd_keycode[] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_HOME, KEY_BACK, KEY_MENU, + KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static int fn_kbd_keycode[] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_HOME, KEY_BACK, KEY_MENU, + KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + + + + +static struct tegra_kbc_wake_key ventana_wake_cfg[] = { + [0] = { + .row = 14, + .col = 1, + }, +}; + + +static struct tegra_kbc_platform_data ventana_kbc_platform_data = { + .debounce_cnt = 20, + .repeat_cnt = 50 * 32, + .wake_cnt = 1, + .wake_cfg = &ventana_wake_cfg[0], + .filter_keys = true, +}; + + +static struct resource ventana_kbc_resources[] = { + [0] = { + .start = TEGRA_KBC_BASE, + .end = TEGRA_KBC_BASE + TEGRA_KBC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_KBC, + .end = INT_KBC, + .flags = IORESOURCE_IRQ, + }, +}; + + +struct platform_device ventana_kbc_device = { + .name = "tegra-kbc", + .id = -1, + .dev = { + .platform_data = &ventana_kbc_platform_data, + }, + .resource = ventana_kbc_resources, + .num_resources = ARRAY_SIZE(ventana_kbc_resources), +}; + +int __init ventana_kbc_init(void) +{ + struct tegra_kbc_platform_data *data = &ventana_kbc_platform_data; + int i, j; + + pr_info("KBC: ventana_kbc_init\n"); + + /* + * Setup the pin configuration information. + */ + for (i = 0; i < KBC_MAX_ROW; i++) { + data->pin_cfg[i].num = i; + data->pin_cfg[i].is_row = true; + data->pin_cfg[i].is_col = false; + } + + for (j = 0; j < 7/*KBC_MAX_COL*/; j++) { + data->pin_cfg[i + j].num = j; + data->pin_cfg[i + j].is_row = false; + data->pin_cfg[i + j].is_col = true; + } + + /* tegra-kbc will use default keycodes. */ + data->plain_keycode = plain_kbd_keycode; + data->fn_keycode = fn_kbd_keycode; + data->filter_keys = true; + platform_device_register(&ventana_kbc_device); + return 0; +} + + + diff --git a/arch/arm/mach-tegra/board-ventana-panel.c b/arch/arm/mach-tegra/board-ventana-panel.c index f3e75e25bf6b..e100af193fa1 100644 --- a/arch/arm/mach-tegra/board-ventana-panel.c +++ b/arch/arm/mach-tegra/board-ventana-panel.c @@ -24,6 +24,7 @@ #include <linux/resource.h> #include <asm/mach-types.h> #include <linux/platform_device.h> +#include <linux/earlysuspend.h> #include <linux/pwm_backlight.h> #include <mach/nvhost.h> #include <mach/nvmap.h> @@ -34,12 +35,16 @@ #include "devices.h" #include "gpio-names.h" - +#define ventana_pnl_pwr_enb TEGRA_GPIO_PC6 #define ventana_bl_enb TEGRA_GPIO_PD4 #define ventana_lvds_shutdown TEGRA_GPIO_PB2 #define ventana_hdmi_hpd TEGRA_GPIO_PN7 #define ventana_hdmi_enb TEGRA_GPIO_PV5 +static struct regulator *ventana_hdmi_reg = NULL; +static struct regulator *ventana_hdmi_pll = NULL; + + static int ventana_backlight_init(struct device *dev) { int ret; @@ -88,17 +93,7 @@ static struct platform_device ventana_backlight_device = { static int ventana_panel_enable(void) { - static struct regulator *reg = NULL; - - if (reg == NULL) { - reg = regulator_get(NULL, "avdd_lvds"); - if (WARN_ON(IS_ERR(reg))) - pr_err("%s: couldn't get regulator avdd_lvds: %ld\n", - __func__, PTR_ERR(reg)); - else - regulator_enable(reg); - } - + gpio_set_value(ventana_pnl_pwr_enb, 1); gpio_set_value(ventana_lvds_shutdown, 1); return 0; } @@ -106,18 +101,42 @@ static int ventana_panel_enable(void) static int ventana_panel_disable(void) { gpio_set_value(ventana_lvds_shutdown, 0); + gpio_set_value(ventana_pnl_pwr_enb, 0); return 0; } static int ventana_hdmi_enable(void) { gpio_set_value(ventana_hdmi_enb, 1); + if (!ventana_hdmi_reg) { + ventana_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); /* LD07 */ + if (IS_ERR_OR_NULL(ventana_hdmi_reg)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi\n"); + ventana_hdmi_reg = NULL; + return PTR_ERR(ventana_hdmi_reg); + } + } + regulator_enable(ventana_hdmi_reg); + + if (!ventana_hdmi_pll) { + ventana_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); /* LD08 */ + if (IS_ERR_OR_NULL(ventana_hdmi_pll)) { + pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n"); + ventana_hdmi_pll = NULL; + regulator_disable(ventana_hdmi_reg); + ventana_hdmi_reg = NULL; + return PTR_ERR(ventana_hdmi_pll); + } + } + regulator_enable(ventana_hdmi_pll); return 0; } static int ventana_hdmi_disable(void) { gpio_set_value(ventana_hdmi_enb, 0); + regulator_disable(ventana_hdmi_reg); + regulator_disable(ventana_hdmi_pll); return 0; } @@ -194,8 +213,8 @@ static struct tegra_fb_data ventana_fb_data = { static struct tegra_fb_data ventana_hdmi_fb_data = { .win = 0, - .xres = 1280, - .yres = 720, + .xres = 1366, + .yres = 768, .bits_per_pixel = 16, }; @@ -233,7 +252,7 @@ static struct tegra_dc_platform_data ventana_disp1_pdata = { }; static struct tegra_dc_platform_data ventana_disp2_pdata = { - .flags = TEGRA_DC_FLAG_ENABLED, + .flags = 0, .default_out = &ventana_disp2_out, .fb = &ventana_hdmi_fb_data, }; @@ -295,21 +314,50 @@ static struct platform_device *ventana_gfx_devices[] __initdata = { &ventana_backlight_device, }; +#ifdef CONFIG_HAS_EARLYSUSPEND +/* put early_suspend/late_resume handlers here for the display in order + * to keep the code out of the display driver, keeping it closer to upstream + */ +struct early_suspend ventana_panel_early_suspender; + +static void ventana_panel_early_suspend(struct early_suspend *h) +{ + if (num_registered_fb > 0) + fb_blank(registered_fb[0], FB_BLANK_POWERDOWN); +} + +static void ventana_panel_late_resume(struct early_suspend *h) +{ + if (num_registered_fb > 0) + fb_blank(registered_fb[0], FB_BLANK_UNBLANK); +} +#endif + int __init ventana_panel_init(void) { int err; + gpio_request(ventana_pnl_pwr_enb, "pnl_pwr_enb"); + gpio_direction_output(ventana_pnl_pwr_enb, 1); + tegra_gpio_enable(ventana_pnl_pwr_enb); gpio_request(ventana_lvds_shutdown, "lvds_shdn"); gpio_direction_output(ventana_lvds_shutdown, 1); tegra_gpio_enable(ventana_lvds_shutdown); - gpio_request(ventana_hdmi_enb, "hdmi_5v_en"); - gpio_direction_output(ventana_hdmi_enb, 0); tegra_gpio_enable(ventana_hdmi_enb); + gpio_request(ventana_hdmi_enb, "hdmi_5v_en"); + gpio_direction_output(ventana_hdmi_enb, 1); + tegra_gpio_enable(ventana_hdmi_hpd); gpio_request(ventana_hdmi_hpd, "hdmi_hpd"); gpio_direction_input(ventana_hdmi_hpd); - tegra_gpio_enable(ventana_hdmi_hpd); + +#ifdef CONFIG_HAS_EARLYSUSPEND + ventana_panel_early_suspender.suspend = ventana_panel_early_suspend; + ventana_panel_early_suspender.resume = ventana_panel_late_resume; + ventana_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + register_early_suspend(&ventana_panel_early_suspender); +#endif err = platform_add_devices(ventana_gfx_devices, ARRAY_SIZE(ventana_gfx_devices)); diff --git a/arch/arm/mach-tegra/board-ventana-pinmux.c b/arch/arm/mach-tegra/board-ventana-pinmux.c index e85034ccda50..a0f99448ca4b 100644 --- a/arch/arm/mach-tegra/board-ventana-pinmux.c +++ b/arch/arm/mach-tegra/board-ventana-pinmux.c @@ -48,17 +48,17 @@ static __initdata struct tegra_pingroup_config ventana_pinmux[] = { {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_OSC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, - {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, {TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, - {TEGRA_PINGROUP_DDC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DDC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, - {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, @@ -67,15 +67,15 @@ static __initdata struct tegra_pingroup_config ventana_pinmux[] = { {TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_GPU, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, - {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, - {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, - {TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, - {TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_LCSN, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, @@ -110,7 +110,7 @@ static __initdata struct tegra_pingroup_config ventana_pinmux[] = { {TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, {TEGRA_PINGROUP_LPW2, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, - {TEGRA_PINGROUP_LSC1, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LSC1, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, {TEGRA_PINGROUP_LSCK, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, {TEGRA_PINGROUP_LSDA, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, {TEGRA_PINGROUP_LSDI, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, diff --git a/arch/arm/mach-tegra/board-ventana-power.c b/arch/arm/mach-tegra/board-ventana-power.c index fe1af074ab9e..d56ac998a385 100644 --- a/arch/arm/mach-tegra/board-ventana-power.c +++ b/arch/arm/mach-tegra/board-ventana-power.c @@ -29,6 +29,7 @@ #include <mach/irqs.h> #include "gpio-names.h" +#include "fuse.h" #include "power.h" #include "wakeups-t2.h" #include "board.h" @@ -36,6 +37,16 @@ #define PMC_CTRL 0x0 #define PMC_CTRL_INTR_LOW (1 << 17) +#define CHARGING_DISABLE TEGRA_GPIO_PR6 + +int __init ventana_charge_init(void) +{ + gpio_request(CHARGING_DISABLE, "chg_disable"); + gpio_direction_output(CHARGING_DISABLE, 0); + tegra_gpio_enable(CHARGING_DISABLE); + return 0; +} + static struct regulator_consumer_supply tps658621_sm0_supply[] = { REGULATOR_SUPPLY("vdd_core", NULL), }; @@ -53,11 +64,11 @@ static struct regulator_consumer_supply tps658621_ldo1_supply[] = { }; static struct regulator_consumer_supply tps658621_ldo2_supply[] = { REGULATOR_SUPPLY("vdd_rtc", NULL), + REGULATOR_SUPPLY("vdd_aon", NULL), }; static struct regulator_consumer_supply tps658621_ldo3_supply[] = { REGULATOR_SUPPLY("avdd_usb", NULL), REGULATOR_SUPPLY("avdd_usb_pll", NULL), - REGULATOR_SUPPLY("avdd_lvds", NULL), }; static struct regulator_consumer_supply tps658621_ldo4_supply[] = { REGULATOR_SUPPLY("avdd_osc", NULL), @@ -68,7 +79,7 @@ static struct regulator_consumer_supply tps658621_ldo5_supply[] = { REGULATOR_SUPPLY("vcore_mmc", "sdhci-tegra.3"), }; static struct regulator_consumer_supply tps658621_ldo6_supply[] = { - REGULATOR_SUPPLY("vddio_vi", NULL), + REGULATOR_SUPPLY("vcsi", "tegra_camera"), }; static struct regulator_consumer_supply tps658621_ldo7_supply[] = { REGULATOR_SUPPLY("avdd_hdmi", NULL), @@ -107,7 +118,7 @@ static struct regulator_init_data ldo2_data = REGULATOR_INIT(ldo2, 725, 1500); static struct regulator_init_data ldo3_data = REGULATOR_INIT(ldo3, 1250, 3300); static struct regulator_init_data ldo4_data = REGULATOR_INIT(ldo4, 1700, 2475); static struct regulator_init_data ldo5_data = REGULATOR_INIT(ldo5, 1250, 3300); -static struct regulator_init_data ldo6_data = REGULATOR_INIT(ldo6, 1250, 3300); +static struct regulator_init_data ldo6_data = REGULATOR_INIT(ldo6, 1250, 1800); static struct regulator_init_data ldo7_data = REGULATOR_INIT(ldo7, 1250, 3300); static struct regulator_init_data ldo8_data = REGULATOR_INIT(ldo8, 1250, 3300); static struct regulator_init_data ldo9_data = REGULATOR_INIT(ldo9, 1250, 3300); @@ -160,24 +171,35 @@ static struct i2c_board_info __initdata ventana_regulators[] = { }; static struct tegra_suspend_platform_data ventana_suspend_data = { + /* + * Check power on time and crystal oscillator start time + * for appropriate settings. + */ .cpu_timer = 2000, - .cpu_off_timer = 0, - .suspend_mode = TEGRA_SUSPEND_LP1, + .cpu_off_timer = 100, + .suspend_mode = TEGRA_SUSPEND_LP0, .core_timer = 0x7e7e, - .core_off_timer = 0, + .core_off_timer = 0xf, .separate_req = true, .corereq_high = false, .sysclkreq_high = true, - .wake_enb = TEGRA_WAKE_GPIO_PV2, + .wake_enb = TEGRA_WAKE_GPIO_PV2 | TEGRA_WAKE_GPIO_PC7, .wake_high = 0, .wake_low = TEGRA_WAKE_GPIO_PV2, - .wake_any = 0, + .wake_any = TEGRA_WAKE_GPIO_PC7, }; int __init ventana_regulator_init(void) { void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804; u32 pmc_ctrl; + u32 minor; + + minor = (readl(chip_id) >> 16) & 0xf; + /* A03 (but not A03p) chips do not support LP0 */ + if (minor == 3 && !(tegra_spare_fuse(18) || tegra_spare_fuse(19))) + ventana_suspend_data.suspend_mode = TEGRA_SUSPEND_LP1; /* configure the power management controller to trigger PMU * interrupts when low */ diff --git a/arch/arm/mach-tegra/board-ventana-sdhci.c b/arch/arm/mach-tegra/board-ventana-sdhci.c index 13ab48b1c7a1..7dc76f6111cc 100644 --- a/arch/arm/mach-tegra/board-ventana-sdhci.c +++ b/arch/arm/mach-tegra/board-ventana-sdhci.c @@ -16,8 +16,12 @@ #include <linux/resource.h> #include <linux/platform_device.h> +#include <linux/wlan_plat.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/mmc/host.h> #include <asm/mach-types.h> #include <mach/irqs.h> @@ -27,6 +31,32 @@ #include "gpio-names.h" #include "board.h" +#define VENTANA_WLAN_PWR TEGRA_GPIO_PK5 +#define VENTANA_WLAN_RST TEGRA_GPIO_PK6 + +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; +static int ventana_wifi_status_register(void (*callback)(int , void *), void *); +static struct clk *wifi_32k_clk; + +static int ventana_wifi_reset(int on); +static int ventana_wifi_power(int on); +static int ventana_wifi_set_carddetect(int val); + +static struct wifi_platform_data ventana_wifi_control = { + .set_power = ventana_wifi_power, + .set_reset = ventana_wifi_reset, + .set_carddetect = ventana_wifi_set_carddetect, +}; + +static struct platform_device ventana_wifi_device = { + .name = "bcm4329_wlan", + .id = 1, + .dev = { + .platform_data = &ventana_wifi_control, + }, +}; + static struct resource sdhci_resource0[] = { [0] = { .start = INT_SDMMC1, @@ -66,9 +96,23 @@ static struct resource sdhci_resource3[] = { }, }; + static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = { .clk_id = NULL, - .force_hs = 1, + .force_hs = 0, + .register_status_notify = ventana_wifi_status_register, + .cccr = { + .sdio_vsn = 2, + .multi_block = 1, + .low_speed = 0, + .wide_bus = 0, + .high_power = 1, + .high_speed = 1, + }, + .cis = { + .vendor = 0x02d0, + .device = 0x4329, + }, .cd_gpio = -1, .wp_gpio = -1, .power_gpio = -1, @@ -120,6 +164,70 @@ static struct platform_device tegra_sdhci_device3 = { }, }; +static int ventana_wifi_status_register( + void (*callback)(int card_present, void *dev_id), + void *dev_id) +{ + if (wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} + +static int ventana_wifi_set_carddetect(int val) +{ + pr_debug("%s: %d\n", __func__, val); + if (wifi_status_cb) + wifi_status_cb(val, wifi_status_cb_devid); + else + pr_warning("%s: Nobody to notify\n", __func__); + return 0; +} + +static int ventana_wifi_power(int on) +{ + pr_debug("%s: %d\n", __func__, on); + + gpio_set_value(VENTANA_WLAN_PWR, on); + mdelay(100); + gpio_set_value(VENTANA_WLAN_RST, on); + mdelay(200); + + if (on) + clk_enable(wifi_32k_clk); + else + clk_disable(wifi_32k_clk); + + return 0; +} + +static int ventana_wifi_reset(int on) +{ + pr_debug("%s: do nothing\n", __func__); + return 0; +} + +static int __init ventana_wifi_init(void) +{ + wifi_32k_clk = clk_get_sys(NULL, "blink"); + if (IS_ERR(wifi_32k_clk)) { + pr_err("%s: unable to get blink clock\n", __func__); + return PTR_ERR(wifi_32k_clk); + } + + gpio_request(VENTANA_WLAN_PWR, "wlan_power"); + gpio_request(VENTANA_WLAN_RST, "wlan_rst"); + + tegra_gpio_enable(VENTANA_WLAN_PWR); + tegra_gpio_enable(VENTANA_WLAN_RST); + + gpio_direction_output(VENTANA_WLAN_PWR, 0); + gpio_direction_output(VENTANA_WLAN_RST, 0); + + platform_device_register(&ventana_wifi_device); + return 0; +} int __init ventana_sdhci_init(void) { gpio_request(tegra_sdhci_platform_data2.power_gpio, "sdhci2_power"); @@ -140,5 +248,6 @@ int __init ventana_sdhci_init(void) platform_device_register(&tegra_sdhci_device2); platform_device_register(&tegra_sdhci_device0); + ventana_wifi_init(); return 0; } diff --git a/arch/arm/mach-tegra/board-ventana-sensors.c b/arch/arm/mach-tegra/board-ventana-sensors.c new file mode 100644 index 000000000000..c824dc66d6e1 --- /dev/null +++ b/arch/arm/mach-tegra/board-ventana-sensors.c @@ -0,0 +1,292 @@ +/* + * arch/arm/mach-tegra/board-ventana-sensors.c + * + * Copyright (c) 2010, NVIDIA, All Rights Reserved. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/i2c.h> +#include <linux/i2c/nct1008.h> +#include <linux/akm8975.h> +#include <linux/mpu3050.h> +#include <linux/i2c/pca954x.h> +#include <linux/i2c/pca953x.h> + +#include <mach/gpio.h> + +#include <media/ov5650.h> +#include <generated/mach-types.h> + +#include "gpio-names.h" +#include "board-ventana.h" + +#define ISL29018_IRQ_GPIO TEGRA_GPIO_PZ2 +#define AKM8975_IRQ_GPIO TEGRA_GPIO_PN5 +#define CAMERA_POWER_GPIO TEGRA_GPIO_PV4 +#define CAMERA_CSI_MUX_SEL_GPIO TEGRA_GPIO_PBB4 +#define AC_PRESENT_GPIO TEGRA_GPIO_PV3 + +static int ventana_camera_init(void) +{ + tegra_gpio_enable(CAMERA_POWER_GPIO); + gpio_request(CAMERA_POWER_GPIO, "camera_power_en"); + gpio_direction_output(CAMERA_POWER_GPIO, 1); + gpio_export(CAMERA_POWER_GPIO, false); + + tegra_gpio_enable(CAMERA_CSI_MUX_SEL_GPIO); + gpio_request(CAMERA_CSI_MUX_SEL_GPIO, "camera_csi_sel"); + gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 0); + gpio_export(CAMERA_CSI_MUX_SEL_GPIO, false); + + return 0; +} + +static int ventana_ov5650_power_on(void) +{ + return 0; +} + +static int ventana_ov5650_power_off(void) +{ + return 0; +} + +struct ov5650_platform_data ventana_ov5650_data = { + .power_on = ventana_ov5650_power_on, + .power_off = ventana_ov5650_power_off, +}; + +static void ventana_isl29018_init(void) +{ + tegra_gpio_enable(ISL29018_IRQ_GPIO); + gpio_request(ISL29018_IRQ_GPIO, "isl29018"); + gpio_direction_input(ISL29018_IRQ_GPIO); +} + +#ifdef CONFIG_SENSORS_AK8975 +static void ventana_akm8975_init(void) +{ + tegra_gpio_enable(AKM8975_IRQ_GPIO); + gpio_request(AKM8975_IRQ_GPIO, "akm8975"); + gpio_direction_input(AKM8975_IRQ_GPIO); +} +#endif + +static void ventana_bq20z75_init(void) +{ + tegra_gpio_enable(AC_PRESENT_GPIO); + gpio_request(AC_PRESENT_GPIO, "ac_present"); + gpio_direction_input(AC_PRESENT_GPIO); +} + +struct nct1008_platform_data ventana_nct1008_pdata = { + .conv_rate = 5, + .config = NCT1008_CONFIG_ALERT_DISABLE, + .thermal_threshold = 120, + .offset = 0, +}; + +static const struct i2c_board_info ventana_i2c0_board_info[] = { + { + I2C_BOARD_INFO("isl29018", 0x44), + .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PZ2), + }, +}; + +static const struct i2c_board_info ventana_i2c2_board_info[] = { + { + I2C_BOARD_INFO("bq20z75-battery", 0x0B), + .irq = TEGRA_GPIO_TO_IRQ(AC_PRESENT_GPIO), + }, +}; + +static struct pca953x_platform_data ventana_tca6416_data = { + .gpio_base = TEGRA_NR_GPIOS + 4, /* 4 gpios are already requested by tps6586x */ +}; + +static struct pca954x_platform_mode ventana_pca9546_modes[] = { + { .adap_id = 6, }, /* REAR CAM1 */ + { .adap_id = 7, }, /* REAR CAM2 */ + { .adap_id = 8, }, /* FRONT CAM3 */ +}; + +static struct pca954x_platform_data ventana_pca9546_data = { + .modes = ventana_pca9546_modes, + .num_modes = ARRAY_SIZE(ventana_pca9546_modes), +}; + +static const struct i2c_board_info ventana_i2c3_board_info_tca6416[] = { + { + I2C_BOARD_INFO("tca6416", 0x20), + .platform_data = &ventana_tca6416_data, + }, +}; + +static const struct i2c_board_info ventana_i2c3_board_info_pca9546[] = { + { + I2C_BOARD_INFO("pca9546", 0x70), + .platform_data = &ventana_pca9546_data, + }, +}; + +static struct i2c_board_info ventana_i2c4_board_info[] = { + { + I2C_BOARD_INFO("nct1008", 0x4C), + .platform_data = &ventana_nct1008_pdata, + }, + +#ifdef CONFIG_SENSORS_AK8975 + { + I2C_BOARD_INFO("akm8975", 0x0C), + .irq = TEGRA_GPIO_TO_IRQ(AKM8975_IRQ_GPIO), + }, +#endif +}; + +static struct i2c_board_info ventana_i2c7_board_info[] = { + { + I2C_BOARD_INFO("ov5650", 0x36), + .platform_data = &ventana_ov5650_data, + }, +}; + +#ifdef CONFIG_SENSORS_MPU3050 +static struct mpu3050_platform_data mpu3050_data = { + .int_config = 0x10, + .orientation = { 0, -1, 0, -1, 0, 0, 0, 0, -1 }, /* Orientation matrix for MPU on ventana */ + .level_shifter = 0, + .accel = { +#ifdef CONFIG_SENSORS_KXTF9_MPU + .get_slave_descr = kxtf9_get_slave_descr, +#else + .get_slave_descr = NULL, +#endif + .adapt_num = 0, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x0F, + .orientation = { 0, -1, 0, -1, 0, 0, 0, 0, -1 }, /* Orientation matrix for Kionix on ventana */ + }, + + .compass = { +#ifdef CONFIG_SENSORS_AK8975_MPU + .get_slave_descr = ak8975_get_slave_descr, +#else + .get_slave_descr = NULL, +#endif + .adapt_num = 3, /* bus number 3 on ventana */ + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = { 1, 0, 0, 0, -1, 0, 0, 0, -1 }, /* Orientation matrix for AKM on ventana */ + }, +}; + +static struct i2c_board_info __initdata mpu3050_i2c0_boardinfo[] = { + { + I2C_BOARD_INFO("mpu3050", 0x68), /*.irq = 299,*/ + .platform_data = &mpu3050_data, + }, +}; +#endif + +int __init ventana_sensors_init(void) +{ + ventana_isl29018_init(); +#ifdef CONFIG_SENSORS_AK8975 + ventana_akm8975_init(); +#endif + ventana_camera_init(); + ventana_bq20z75_init(); + + i2c_register_board_info(0, ventana_i2c0_board_info, + ARRAY_SIZE(ventana_i2c0_board_info)); + + i2c_register_board_info(2, ventana_i2c2_board_info, + ARRAY_SIZE(ventana_i2c2_board_info)); + + i2c_register_board_info(4, ventana_i2c4_board_info, + ARRAY_SIZE(ventana_i2c4_board_info)); + + i2c_register_board_info(7, ventana_i2c7_board_info, + ARRAY_SIZE(ventana_i2c7_board_info)); + +#ifdef CONFIG_SENSORS_MPU3050 + i2c_register_board_info(0, mpu3050_i2c0_boardinfo, + ARRAY_SIZE(mpu3050_i2c0_boardinfo)); +#endif + + return 0; +} + +#ifdef CONFIG_VIDEO_OV5650 + +struct ov5650_gpios { + const char *name; + int gpio; + int enabled; +}; + +#define OV5650_GPIO(_name, _gpio, _enabled) \ + { \ + .name = _name, \ + .gpio = _gpio, \ + .enabled = _enabled, \ + } + +static struct ov5650_gpios ov5650_gpio_keys[] = { + [0] = OV5650_GPIO("en_avdd_csi", AVDD_DSI_CSI_ENB_GPIO, 1), + [1] = OV5650_GPIO("cam2_pwdn", CAM2_PWR_DN_GPIO, 0), + [2] = OV5650_GPIO("cam2_rst_lo", CAM2_RST_L_GPIO, 1), + [3] = OV5650_GPIO("cam2_af_pwdn_lo", CAM2_AF_PWR_DN_L_GPIO, 0), + [4] = OV5650_GPIO("cam2_ldo_shdn_lo", CAM2_LDO_SHUTDN_L_GPIO, 1), + [5] = OV5650_GPIO("cam2_i2c_mux_rst_lo", CAM2_I2C_MUX_RST_GPIO, 1), +}; + +int __init ventana_ov5650_late_init(void) +{ + int ret; + int i; + + if (!machine_is_ventana()) + return 0; + + i2c_new_device(i2c_get_adapter(3), ventana_i2c3_board_info_tca6416); + + for (i = 0; i < ARRAY_SIZE(ov5650_gpio_keys); i++) { + ret = gpio_request(ov5650_gpio_keys[i].gpio, + ov5650_gpio_keys[i].name); + if (ret < 0) { + pr_err("%s: gpio_request failed for gpio #%d\n", + __func__, i); + goto fail; + } + gpio_direction_output(ov5650_gpio_keys[i].gpio, + ov5650_gpio_keys[i].enabled); + gpio_export(ov5650_gpio_keys[i].gpio, false); + } + + i2c_new_device(i2c_get_adapter(3), ventana_i2c3_board_info_pca9546); + + return 0; + +fail: + while (i--) + gpio_free(ov5650_gpio_keys[i].gpio); + return ret; +} + +late_initcall(ventana_ov5650_late_init); + +#endif /* CONFIG_VIDEO_OV5650 */ diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c index 6302118a335b..ec2ed8bc0e9e 100644 --- a/arch/arm/mach-tegra/board-ventana.c +++ b/arch/arm/mach-tegra/board-ventana.c @@ -26,14 +26,23 @@ #include <linux/clk.h> #include <linux/serial_8250.h> #include <linux/i2c.h> -#include <linux/i2c/panjit_ts.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/i2c-tegra.h> #include <linux/gpio.h> #include <linux/gpio_keys.h> #include <linux/input.h> +#include <linux/tegra_usb.h> #include <linux/usb/android_composite.h> +#include <linux/mfd/tps6586x.h> + +#ifdef CONFIG_TOUCHSCREEN_PANJIT_I2C +#include <linux/i2c/panjit_ts.h> +#endif + +#ifdef CONFIG_TOUCHSCREEN_ATMEL_MT_T9 +#include <linux/i2c/atmel_maxtouch.h> +#endif #include <mach/clk.h> #include <mach/iomap.h> @@ -41,9 +50,11 @@ #include <mach/pinmux.h> #include <mach/iomap.h> #include <mach/io.h> - +#include <mach/i2s.h> +#include <mach/audio.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <mach/usb_phy.h> #include "board.h" #include "clock.h" @@ -74,11 +85,84 @@ static struct platform_device debug_uart = { }, }; +static struct tegra_utmip_config utmi_phy_config[] = { + [0] = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 15, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + }, + [1] = { + .hssync_start_delay = 0, + .idle_wait_delay = 17, + .elastic_limit = 16, + .term_range_adj = 6, + .xcvr_setup = 8, + .xcvr_lsfslew = 2, + .xcvr_lsrslew = 2, + }, +}; + +static struct tegra_ulpi_config ulpi_phy_config = { + .reset_gpio = TEGRA_GPIO_PG2, + .clk = "clk_dev2", +}; + +#ifdef CONFIG_BCM4329_RFKILL + +static struct resource ventana_bcm4329_rfkill_resources[] = { + { + .name = "bcm4329_nreset_gpio", + .start = TEGRA_GPIO_PU0, + .end = TEGRA_GPIO_PU0, + .flags = IORESOURCE_IO, + }, + { + .name = "bcm4329_nshutdown_gpio", + .start = TEGRA_GPIO_PK2, + .end = TEGRA_GPIO_PK2, + .flags = IORESOURCE_IO, + }, +}; + +static struct platform_device ventana_bcm4329_rfkill_device = { + .name = "bcm4329_rfkill", + .id = -1, + .num_resources = ARRAY_SIZE(ventana_bcm4329_rfkill_resources), + .resource = ventana_bcm4329_rfkill_resources, +}; + +static noinline void __init ventana_bt_rfkill(void) +{ + /*Add Clock Resource*/ + clk_add_alias("bcm4329_32k_clk", ventana_bcm4329_rfkill_device.name, \ + "blink", NULL); + + platform_device_register(&ventana_bcm4329_rfkill_device); + + return; +} +#else +static inline void ventana_bt_rfkill(void) { } +#endif + static __initdata struct tegra_clk_init_table ventana_clk_init_table[] = { /* name parent rate enabled */ { "uartd", "pll_p", 216000000, true}, - { "pll_m", "clk_m", 600000000, true}, + { "uartc", "pll_m", 600000000, false}, + { "blink", "clk_32k", 32768, false}, + { "pll_p_out4", "pll_p", 24000000, true }, { "pwm", "clk_32k", 32768, false}, + { "pll_a", NULL, 11289600, true}, + { "pll_a_out0", NULL, 11289600, true}, + { "i2s1", "pll_a_out0", 11289600, true}, + { "i2s2", "pll_a_out0", 11289600, true}, + { "audio", "pll_a_out0", 11289600, true}, + { "audio_2x", "audio", 22579200, true}, + { "kbc", "clk_32k", 32768, true}, { NULL, NULL, 0, 0}, }; @@ -119,6 +203,23 @@ static struct platform_device androidusb_device = { }, }; +static struct i2c_board_info __initdata ventana_i2c_bus1_board_info[] = { + { + I2C_BOARD_INFO("wm8903", 0x1a), + }, +}; + +static struct tegra_ulpi_config ventana_ehci2_ulpi_phy_config = { + .reset_gpio = TEGRA_GPIO_PV1, + .clk = "clk_dev2", +}; + +static struct tegra_ehci_platform_data ventana_ehci2_ulpi_platform_data = { + .operating_mode = TEGRA_USB_HOST, + .power_down_on_bus_suspend = 0, + .phy_config = &ventana_ehci2_ulpi_phy_config, +}; + static struct tegra_i2c_platform_data ventana_i2c1_platform_data = { .adapter_nr = 0, .bus_count = 1, @@ -138,7 +239,7 @@ static const struct tegra_pingroup_config i2c2_gen2 = { static struct tegra_i2c_platform_data ventana_i2c2_platform_data = { .adapter_nr = 1, .bus_count = 2, - .bus_clk_rate = { 400000, 100000 }, + .bus_clk_rate = { 400000, 10000 }, .bus_mux = { &i2c2_ddc, &i2c2_gen2 }, .bus_mux_len = { 1, 1 }, }; @@ -156,6 +257,16 @@ static struct tegra_i2c_platform_data ventana_dvc_platform_data = { .is_dvc = true, }; +static struct tegra_audio_platform_data tegra_audio_pdata = { + .dma_on = true, /* use dma by default */ + .i2s_clk_rate = 240000000, + .dap_clk = "clk_dev1", + .audio_sync_clk = "audio_2x", + .mode = I2S_BIT_FORMAT_I2S, + .fifo_fmt = I2S_FIFO_16_LSB, + .bit_size = I2S_BIT_SIZE_16, +}; + static void ventana_i2c_init(void) { tegra_i2c_device1.dev.platform_data = &ventana_i2c1_platform_data; @@ -163,12 +274,16 @@ static void ventana_i2c_init(void) tegra_i2c_device3.dev.platform_data = &ventana_i2c3_platform_data; tegra_i2c_device4.dev.platform_data = &ventana_dvc_platform_data; - platform_device_register(&tegra_i2c_device4); - platform_device_register(&tegra_i2c_device3); - platform_device_register(&tegra_i2c_device2); + i2c_register_board_info(0, ventana_i2c_bus1_board_info, 1); + platform_device_register(&tegra_i2c_device1); + platform_device_register(&tegra_i2c_device2); + platform_device_register(&tegra_i2c_device3); + platform_device_register(&tegra_i2c_device4); } + +#ifdef CONFIG_KEYBOARD_GPIO #define GPIO_KEY(_id, _gpio, _iswake) \ { \ .code = _id, \ @@ -202,38 +317,55 @@ static struct platform_device ventana_keys_device = { }, }; +static void ventana_keys_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ventana_keys); i++) + tegra_gpio_enable(ventana_keys[i].gpio); +} +#endif + +static struct platform_device tegra_camera = { + .name = "tegra_camera", + .id = -1, +}; + static struct platform_device *ventana_devices[] __initdata = { &tegra_otg_device, &androidusb_device, &debug_uart, + &tegra_uartb_device, + &tegra_uartc_device, &pmu_device, &tegra_udc_device, + &tegra_ehci2_device, &tegra_gart_device, &tegra_aes_device, +#ifdef CONFIG_KEYBOARD_GPIO &ventana_keys_device, +#endif + &tegra_wdt_device, + &tegra_i2s_device1, + &tegra_avp_device, + &tegra_camera, }; -static void ventana_keys_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ventana_keys); i++) - tegra_gpio_enable(ventana_keys[i].gpio); -} +#ifdef CONFIG_TOUCHSCREEN_PANJIT_I2C static struct panjit_i2c_ts_platform_data panjit_data = { .gpio_reset = TEGRA_GPIO_PQ7, }; static const struct i2c_board_info ventana_i2c_bus1_touch_info[] = { { - I2C_BOARD_INFO("panjit_touch", 0x3), - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), - .platform_data = &panjit_data, - }, + I2C_BOARD_INFO("panjit_touch", 0x3), + .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), + .platform_data = &panjit_data, + }, }; -static int __init ventana_touch_init(void) +static int __init ventana_touch_init_panjit(void) { tegra_gpio_enable(TEGRA_GPIO_PV6); @@ -242,25 +374,220 @@ static int __init ventana_touch_init(void) return 0; } +#endif + +#ifdef CONFIG_TOUCHSCREEN_ATMEL_MT_T9 +/* Atmel MaxTouch touchscreen Driver data */ +/*-----------------------------------------------------*/ +/* + * Reads the CHANGELINE state; interrupt is valid if the changeline + * is low. + */ +static u8 read_chg(void) +{ + return gpio_get_value(TEGRA_GPIO_PV6); +} + +static u8 valid_interrupt(void) +{ + return !read_chg(); +} + +static struct mxt_platform_data Atmel_mxt_info = { + /* Maximum number of simultaneous touches to report. */ + .numtouch = 10, + // TODO: no need for any hw-specific things at init/exit? + .init_platform_hw = NULL, + .exit_platform_hw = NULL, + .max_x = 1366, + .max_y = 768, + .valid_interrupt = &valid_interrupt, + .read_chg = &read_chg, +}; + +static struct i2c_board_info __initdata i2c_info[] = { + { + I2C_BOARD_INFO("maXTouch", MXT_I2C_ADDRESS), + .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), + .platform_data = &Atmel_mxt_info, + }, +}; + +static int __init ventana_touch_init_atmel(void) +{ + tegra_gpio_enable(TEGRA_GPIO_PV6); /* FIXME: Ventana-specific GPIO assignment */ + tegra_gpio_enable(TEGRA_GPIO_PQ7); /* FIXME: Ventana-specific GPIO assignment */ + + gpio_set_value(TEGRA_GPIO_PQ7, 0); + msleep(1); + gpio_set_value(TEGRA_GPIO_PQ7, 1); + msleep(100); + + i2c_register_board_info(0, i2c_info, 1); + + return 0; +} +#endif + +static struct tegra_ehci_platform_data tegra_ehci_pdata[] = { + [0] = { + .phy_config = &utmi_phy_config[0], + .operating_mode = TEGRA_USB_HOST, + .power_down_on_bus_suspend = 0, + }, + [1] = { + .phy_config = &ulpi_phy_config, + .operating_mode = TEGRA_USB_HOST, + .power_down_on_bus_suspend = 1, + }, + [2] = { + .phy_config = &utmi_phy_config[1], + .operating_mode = TEGRA_USB_HOST, + .power_down_on_bus_suspend = 0, + }, +}; + +static void ventana_usb_init(void) +{ + tegra_ehci3_device.dev.platform_data=&tegra_ehci_pdata[2]; + platform_device_register(&tegra_ehci3_device); +} + +struct platform_device *tegra_usb_otg_host_register(void) +{ + struct platform_device *pdev; + void *platform_data; + int val; + + pdev = platform_device_alloc(tegra_ehci1_device.name, tegra_ehci1_device.id); + if (!pdev) + return NULL; + + val = platform_device_add_resources(pdev, tegra_ehci1_device.resource, + tegra_ehci1_device.num_resources); + if (val) + goto error; + + pdev->dev.dma_mask = tegra_ehci1_device.dev.dma_mask; + pdev->dev.coherent_dma_mask = tegra_ehci1_device.dev.coherent_dma_mask; + + platform_data = kmalloc(sizeof(struct tegra_ehci_platform_data), GFP_KERNEL); + if (!platform_data) + goto error; + + memcpy(platform_data, &tegra_ehci_pdata[0], + sizeof(struct tegra_ehci_platform_data)); + pdev->dev.platform_data = platform_data; + + val = platform_device_add(pdev); + if (val) + goto error_add; + + return pdev; + +error_add: + kfree(platform_data); +error: + pr_err("%s: failed to add the host contoller device\n", __func__); + platform_device_put(pdev); + return NULL; +} + +void tegra_usb_otg_host_unregister(struct platform_device *pdev) +{ + platform_device_unregister(pdev); +} + +static int __init ventana_gps_init(void) +{ + struct clk *clk32 = clk_get_sys(NULL, "blink"); + if (!IS_ERR(clk32)) { + clk_set_rate(clk32,clk32->parent->rate); + clk_enable(clk32); + } + + tegra_gpio_enable(TEGRA_GPIO_PZ3); + return 0; +} + +static void ventana_power_off(void) +{ + int ret; + + ret = tps6586x_power_off(); + if (ret) + pr_err("ventana: failed to power off\n"); + + while(1); +} + +static void __init ventana_power_off_init(void) +{ + pm_power_off = ventana_power_off; +} static void __init tegra_ventana_init(void) { char serial[20]; +#if defined(CONFIG_TOUCHSCREEN_PANJIT_I2C) && \ + defined(CONFIG_TOUCHSCREEN_ATMEL_MT_T9) + struct board_info BoardInfo; +#endif tegra_common_init(); tegra_clk_init_from_table(ventana_clk_init_table); ventana_pinmux_init(); - + ventana_i2c_init(); snprintf(serial, sizeof(serial), "%llx", tegra_chip_uid()); andusb_plat.serial_number = kstrdup(serial, GFP_KERNEL); + tegra_i2s_device1.dev.platform_data = &tegra_audio_pdata; + tegra_ehci2_device.dev.platform_data + = &ventana_ehci2_ulpi_platform_data; platform_add_devices(ventana_devices, ARRAY_SIZE(ventana_devices)); ventana_sdhci_init(); - ventana_i2c_init(); + ventana_charge_init(); ventana_regulator_init(); - ventana_touch_init(); + +#if defined(CONFIG_TOUCHSCREEN_PANJIT_I2C) && \ + defined(CONFIG_TOUCHSCREEN_ATMEL_MT_T9) + +#define NVODM_ATMEL_TOUCHSCREEN 0x0A00 +#define NVODM_PANJIT_TOUCHSCREEN 0x0000 + + tegra_get_board_info(&BoardInfo); + + switch (BoardInfo.sku & 0xFF00) { + case NVODM_ATMEL_TOUCHSCREEN: + pr_info("Initializing Atmel touch driver\n"); + ventana_touch_init_atmel(); + break; + default: + pr_info("Initializing Panjit touch driver\n"); + ventana_touch_init_panjit(); + break; + } +#elif defined(CONFIG_TOUCHSCREEN_ATMEL_MT_T9) + pr_info("Initializing Atmel touch driver\n"); + ventana_touch_init_atmel(); +#elif defined(CONFIG_TOUCHSCREEN_PANJIT_I2C) + pr_info("Initializing Panjit touch driver\n"); + ventana_touch_init_panjit(); +#endif + +#ifdef CONFIG_KEYBOARD_GPIO ventana_keys_init(); +#endif +#ifdef CONFIG_KEYBOARD_TEGRA + ventana_kbc_init(); +#endif + + ventana_usb_init(); + ventana_gps_init(); ventana_panel_init(); + ventana_sensors_init(); + ventana_bt_rfkill(); + ventana_power_off_init(); } MACHINE_START(VENTANA, "ventana") diff --git a/arch/arm/mach-tegra/board-ventana.h b/arch/arm/mach-tegra/board-ventana.h index 39703583249d..de26323b6cf5 100644 --- a/arch/arm/mach-tegra/board-ventana.h +++ b/arch/arm/mach-tegra/board-ventana.h @@ -17,9 +17,26 @@ #ifndef _MACH_TEGRA_BOARD_VENTANA_H #define _MACH_TEGRA_BOARD_VENTANA_H +int ventana_charge_init(void); int ventana_regulator_init(void); int ventana_sdhci_init(void); int ventana_pinmux_init(void); int ventana_panel_init(void); +int ventana_sensors_init(void); +int ventana_kbc_init(void); + +/* external gpios */ + +/* TPS6586X gpios */ +#define TPS6586X_GPIO_BASE TEGRA_NR_GPIOS +#define AVDD_DSI_CSI_ENB_GPIO TPS6586X_GPIO_BASE + 1 /* gpio2 */ + +/* TCA6416 gpios */ +#define TCA6416_GPIO_BASE TEGRA_NR_GPIOS + 4 +#define CAM2_PWR_DN_GPIO TCA6416_GPIO_BASE + 4 /* gpio4 */ +#define CAM2_RST_L_GPIO TCA6416_GPIO_BASE + 5 /* gpio5 */ +#define CAM2_AF_PWR_DN_L_GPIO TCA6416_GPIO_BASE + 6 /* gpio6 */ +#define CAM2_LDO_SHUTDN_L_GPIO TCA6416_GPIO_BASE + 7 /* gpio7 */ +#define CAM2_I2C_MUX_RST_GPIO TCA6416_GPIO_BASE + 15 /* gpio15 */ #endif diff --git a/arch/arm/mach-tegra/board-whistler-kbc.c b/arch/arm/mach-tegra/board-whistler-kbc.c new file mode 100644 index 000000000000..2d1c5474eddf --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-kbc.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2010 NVIDIA, 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/device.h> + +#include <mach/clk.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/pinmux.h> +#include <mach/iomap.h> +#include <mach/io.h> +#include <mach/kbc.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + + +static int plain_kbd_keycode[] = { + KEY_POWER, KEY_DOWN, KEY_RIGHT, KEY_SELECT, + KEY_LEFT, KEY_UP, KEY_RESERVED, KEY_RESERVED, + KEY_HOME, KEY_BACK, KEY_NUMERIC_6, KEY_NUMERIC_9, + KEY_NUMERIC_8, KEY_NUMERIC_POUND, KEY_DOT, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_NUMERIC_3, + KEY_NUMERIC_5, KEY_NUMERIC_2, KEY_NUMERIC_7, KEY_RESERVED, + KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_NUMERIC_4, KEY_RESERVED, + KEY_END, KEY_BACK, KEY_RESERVED, KEY_MENU, + KEY_RESERVED, KEY_RESERVED, KEY_NUMERIC_1, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static int fn_kbd_keycode[] = { + KEY_POWER, KEY_DOWN, KEY_RIGHT, KEY_SELECT, + KEY_LEFT, KEY_UP, KEY_RESERVED, KEY_RESERVED, + KEY_HOME, KEY_BACK, KEY_NUMERIC_6, KEY_NUMERIC_9, + KEY_NUMERIC_8, KEY_NUMERIC_POUND, KEY_DOT, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_NUMERIC_3, + KEY_NUMERIC_5, KEY_NUMERIC_2, KEY_NUMERIC_7, KEY_RESERVED, + KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_NUMERIC_4, KEY_RESERVED, + KEY_END, KEY_BACK, KEY_RESERVED, KEY_MENU, + KEY_RESERVED, KEY_RESERVED, KEY_NUMERIC_1, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + + + + +static struct tegra_kbc_wake_key whistler_wake_cfg[] = { + [0] = { + .row = 0, + .col = 0, + }, +}; + + +static struct tegra_kbc_platform_data whistler_kbc_platform_data = { + .debounce_cnt = 20, + .repeat_cnt = 50 * 32, + .wake_cnt = 1, + .wake_cfg = &whistler_wake_cfg[0], + .filter_keys = true, +}; + + +static struct resource whistler_kbc_resources[] = { + [0] = { + .start = TEGRA_KBC_BASE, + .end = TEGRA_KBC_BASE + TEGRA_KBC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_KBC, + .end = INT_KBC, + .flags = IORESOURCE_IRQ, + }, +}; + + +struct platform_device whistler_kbc_device = { + .name = "tegra-kbc", + .id = -1, + .dev = { + .platform_data = &whistler_kbc_platform_data, + }, + .resource = whistler_kbc_resources, + .num_resources = ARRAY_SIZE(whistler_kbc_resources), +}; + +int __init whistler_kbc_init(void) +{ + struct tegra_kbc_platform_data *data = &whistler_kbc_platform_data; + int i, j; + + pr_info("KBC: whistler_kbc_init\n"); + + /* + * Setup the pin configuration information. + */ + for (i = 0; i < KBC_MAX_ROW; i++) { + data->pin_cfg[i].num = i; + data->pin_cfg[i].is_row = true; + data->pin_cfg[i].is_col = false; + } + + for (j = 0; j < 7/*KBC_MAX_COL*/; j++) { + data->pin_cfg[i + j].num = j; + data->pin_cfg[i + j].is_row = false; + data->pin_cfg[i + j].is_col = true; + } + + /* tegra-kbc will use default keycodes. */ + data->plain_keycode = plain_kbd_keycode; + data->fn_keycode = fn_kbd_keycode; + data->filter_keys = true; + platform_device_register(&whistler_kbc_device); + return 0; +} + + + diff --git a/arch/arm/mach-tegra/board-whistler-panel.c b/arch/arm/mach-tegra/board-whistler-panel.c new file mode 100644 index 000000000000..86539ec94b18 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-panel.c @@ -0,0 +1,231 @@ +/* + * arch/arm/mach-tegra/board-whistler-panel.c + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/resource.h> +#include <asm/mach-types.h> +#include <linux/platform_device.h> +#include <linux/pwm_backlight.h> +#include <mach/nvhost.h> +#include <mach/nvmap.h> +#include <mach/irqs.h> +#include <mach/iomap.h> +#include <mach/dc.h> +#include <mach/fb.h> + +#include "devices.h" +#include "gpio-names.h" +#include "board.h" + +#define whistler_bl_enb TEGRA_GPIO_PW1 + +static int whistler_backlight_init(struct device *dev) { + int ret; + + ret = gpio_request(whistler_bl_enb, "backlight_enb"); + if (ret < 0) + return ret; + + ret = gpio_direction_output(whistler_bl_enb, 1); + if (ret < 0) + gpio_free(whistler_bl_enb); + else + tegra_gpio_enable(whistler_bl_enb); + + return ret; +}; + +static void whistler_backlight_exit(struct device *dev) { + gpio_set_value(whistler_bl_enb, 0); + gpio_free(whistler_bl_enb); + tegra_gpio_disable(whistler_bl_enb); +} + +static int whistler_backlight_notify(struct device *unused, int brightness) +{ + gpio_set_value(whistler_bl_enb, !!brightness); + return brightness; +} + +static struct platform_pwm_backlight_data whistler_backlight_data = { + .pwm_id = 2, + .max_brightness = 255, + .dft_brightness = 224, + .pwm_period_ns = 5000000, + .init = whistler_backlight_init, + .exit = whistler_backlight_exit, + .notify = whistler_backlight_notify, +}; + +static struct platform_device whistler_backlight_device = { + .name = "pwm-backlight", + .id = -1, + .dev = { + .platform_data = &whistler_backlight_data, + }, +}; + +static struct resource whistler_disp1_resources[] = { + { + .name = "irq", + .start = INT_DISPLAY_GENERAL, + .end = INT_DISPLAY_GENERAL, + .flags = IORESOURCE_IRQ, + }, + { + .name = "regs", + .start = TEGRA_DISPLAY_BASE, + .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1, + .flags = IORESOURCE_MEM, + }, + { + .name = "fbmem", + .flags = IORESOURCE_MEM, + }, +}; + +static struct tegra_dc_mode whistler_panel_modes[] = { + { + .pclk = 27000000, + .h_ref_to_sync = 4, + .v_ref_to_sync = 2, + .h_sync_width = 10, + .v_sync_width = 3, + .h_back_porch = 20, + .v_back_porch = 3, + .h_active = 800, + .v_active = 480, + .h_front_porch = 70, + .v_front_porch = 3, + }, +}; + +static struct tegra_dc_out_pin whistler_dc_out_pins[] = { + { + .name = TEGRA_DC_OUT_PIN_H_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_V_SYNC, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, + { + .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK, + .pol = TEGRA_DC_OUT_PIN_POL_LOW, + }, +}; + +static struct tegra_dc_out whistler_disp1_out = { + .type = TEGRA_DC_OUT_RGB, + + .align = TEGRA_DC_ALIGN_MSB, + .order = TEGRA_DC_ORDER_RED_BLUE, + + .modes = whistler_panel_modes, + .n_modes = ARRAY_SIZE(whistler_panel_modes), + + .out_pins = whistler_dc_out_pins, + .n_out_pins = ARRAY_SIZE(whistler_dc_out_pins), +}; + +static struct tegra_fb_data whistler_fb_data = { + .win = 0, + .xres = 800, + .yres = 480, + .bits_per_pixel = 32, +}; + +static struct tegra_dc_platform_data whistler_disp1_pdata = { + .flags = TEGRA_DC_FLAG_ENABLED, + .default_out = &whistler_disp1_out, + .fb = &whistler_fb_data, +}; + +static struct nvhost_device whistler_disp1_device = { + .name = "tegradc", + .id = 0, + .resource = whistler_disp1_resources, + .num_resources = ARRAY_SIZE(whistler_disp1_resources), + .dev = { + .platform_data = &whistler_disp1_pdata, + }, +}; + +static struct nvmap_platform_carveout whistler_carveouts[] = { + [0] = { + .name = "iram", + .usage_mask = NVMAP_HEAP_CARVEOUT_IRAM, + .base = TEGRA_IRAM_BASE, + .size = TEGRA_IRAM_SIZE, + .buddy_size = 0, /* no buddy allocation for IRAM */ + }, + [1] = { + .name = "generic-0", + .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC, + .base = 0x18C00000, + .size = SZ_128M - 0xC00000, + .buddy_size = SZ_32K, + }, +}; + +static struct nvmap_platform_data whistler_nvmap_data = { + .carveouts = whistler_carveouts, + .nr_carveouts = ARRAY_SIZE(whistler_carveouts), +}; + +static struct platform_device whistler_nvmap_device = { + .name = "tegra-nvmap", + .id = -1, + .dev = { + .platform_data = &whistler_nvmap_data, + }, +}; + +static struct platform_device *whistler_gfx_devices[] __initdata = { + &whistler_nvmap_device, + &tegra_grhost_device, + &tegra_pwfm2_device, + &whistler_backlight_device, +}; + +int __init whistler_panel_init(void) +{ + int err; + struct resource *res; + + whistler_carveouts[1].base = tegra_carveout_start; + whistler_carveouts[1].size = tegra_carveout_size; + + err = platform_add_devices(whistler_gfx_devices, + ARRAY_SIZE(whistler_gfx_devices)); + + res = nvhost_get_resource_byname(&whistler_disp1_device, + IORESOURCE_MEM, "fbmem"); + res->start = tegra_fb_start; + res->end = tegra_fb_start + tegra_fb_size - 1; + + if (!err) + err = nvhost_device_register(&whistler_disp1_device); + + return err; +} + diff --git a/arch/arm/mach-tegra/board-whistler-pinmux.c b/arch/arm/mach-tegra/board-whistler-pinmux.c new file mode 100644 index 000000000000..c85f72d7ce72 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-pinmux.c @@ -0,0 +1,166 @@ +/* + * arch/arm/mach-tegra/board-whistler-pinmux.c + * + * Copyright (C) 2010 NVIDIA Corporation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <mach/pinmux.h> + +#define DEFAULT_DRIVE(_name) \ + { \ + .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \ + .hsm = TEGRA_HSM_DISABLE, \ + .schmitt = TEGRA_SCHMITT_ENABLE, \ + .drive = TEGRA_DRIVE_DIV_1, \ + .pull_down = TEGRA_PULL_31, \ + .pull_up = TEGRA_PULL_31, \ + .slew_rising = TEGRA_SLEW_SLOWEST, \ + .slew_falling = TEGRA_SLEW_SLOWEST, \ + } + + +static __initdata struct tegra_drive_pingroup_config whistler_drive_pinmux[] = { + DEFAULT_DRIVE(DBG), + DEFAULT_DRIVE(DDC), + DEFAULT_DRIVE(VI1), + DEFAULT_DRIVE(VI2), + DEFAULT_DRIVE(SDIO1), +}; + +static __initdata struct tegra_pingroup_config whistler_pinmux[] = { + {TEGRA_PINGROUP_ATA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_ATB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_ATC, TEGRA_MUX_SDIO4, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_ATD, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_OSC, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_OSC, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DTE, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GMA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GMD, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GME, TEGRA_MUX_DAP5, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GPU, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCB, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCD, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LCSN, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LDC, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LM0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LM1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LPW1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LSCK, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LSDA, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LSDI, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LVP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SDB, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SDC, TEGRA_MUX_SDIO3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SDD, TEGRA_MUX_SDIO3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_SLXA, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SLXK, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_SPIA, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_SPIB, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_SPIC, TEGRA_MUX_SPI3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIF, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UAA, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UAB, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UAC, TEGRA_MUX_OWR, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE}, + {TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_UDA, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, + {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL}, +}; + +void __init whistler_pinmux_init(void) +{ + tegra_pinmux_config_table(whistler_pinmux, ARRAY_SIZE(whistler_pinmux)); + tegra_drive_pinmux_config_table(whistler_drive_pinmux, + ARRAY_SIZE(whistler_drive_pinmux)); +} diff --git a/arch/arm/mach-tegra/board-whistler-power.c b/arch/arm/mach-tegra/board-whistler-power.c new file mode 100644 index 000000000000..46aeef1001c9 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-power.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2010 NVIDIA, 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ +#include <linux/i2c.h> +#include <linux/pda_power.h> +#include <linux/platform_device.h> +#include <linux/resource.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/max8907c.h> +#include <linux/regulator/max8907c-regulator.h> +#include <linux/gpio.h> +#include <mach/suspend.h> +#include <linux/io.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> + +#include "gpio-names.h" +#include "power.h" +#include "wakeups-t2.h" +#include "board.h" + +#define PMC_CTRL 0x0 + #define PMC_CTRL_INTR_LOW (1 << 17) + +static struct regulator_consumer_supply max8907c_SD1_supply[] = { + REGULATOR_SUPPLY("vdd_cpu", NULL), +}; + +static struct regulator_consumer_supply max8907c_SD2_supply[] = { + REGULATOR_SUPPLY("vdd_core", NULL), +}; + +static struct regulator_consumer_supply max8907c_SD3_supply[] = { + REGULATOR_SUPPLY("vddio_sys", NULL), +}; + +static struct regulator_consumer_supply max8907c_LDO1_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO2_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO3_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO4_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO5_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO6_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO7_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO8_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO9_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO10_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO11_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO12_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO13_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO14_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO15_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO16_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO17_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO18_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO19_supply[] = { +}; + +static struct regulator_consumer_supply max8907c_LDO20_supply[] = { +}; + +#define MAX8907C_REGULATOR_DEVICE(_id, _minmv, _maxmv) \ +static struct regulator_init_data max8907c_##_id##_data = { \ + .constraints = { \ + .min_uV = (_minmv), \ + .max_uV = (_maxmv), \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + }, \ + .num_consumer_supplies = ARRAY_SIZE(max8907c_##_id##_supply), \ + .consumer_supplies = max8907c_##_id##_supply, \ +}; \ +static struct platform_device max8907c_##_id##_device = { \ + .name = "max8907c-regulator", \ + .id = MAX8907C_##_id, \ + .dev = { \ + .platform_data = &max8907c_##_id##_data, \ + }, \ +} + +MAX8907C_REGULATOR_DEVICE(SD1, 637500, 1425000); +MAX8907C_REGULATOR_DEVICE(SD2, 650000, 2225000); +MAX8907C_REGULATOR_DEVICE(SD3, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO1, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO2, 650000, 2225000); +MAX8907C_REGULATOR_DEVICE(LDO3, 650000, 2225000); +MAX8907C_REGULATOR_DEVICE(LDO4, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO5, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO6, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO7, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO8, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO9, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO10, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO11, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO12, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO13, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO14, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO15, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO16, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO17, 650000, 2225000); +MAX8907C_REGULATOR_DEVICE(LDO18, 650000, 2225000); +MAX8907C_REGULATOR_DEVICE(LDO19, 750000, 3900000); +MAX8907C_REGULATOR_DEVICE(LDO20, 750000, 3900000); + +static struct platform_device *whistler_max8907c_power_devices[] = { + &max8907c_SD1_device, + &max8907c_SD2_device, + &max8907c_SD3_device, + &max8907c_LDO1_device, + &max8907c_LDO2_device, + &max8907c_LDO3_device, + &max8907c_LDO4_device, + &max8907c_LDO5_device, + &max8907c_LDO6_device, + &max8907c_LDO7_device, + &max8907c_LDO8_device, + &max8907c_LDO9_device, + &max8907c_LDO10_device, + &max8907c_LDO11_device, + &max8907c_LDO12_device, + &max8907c_LDO13_device, + &max8907c_LDO14_device, + &max8907c_LDO15_device, + &max8907c_LDO16_device, + &max8907c_LDO17_device, + &max8907c_LDO18_device, + &max8907c_LDO19_device, + &max8907c_LDO20_device, +}; + +static struct max8907c_platform_data max8907c_pdata = { + .num_subdevs = ARRAY_SIZE(whistler_max8907c_power_devices), + .subdevs = whistler_max8907c_power_devices, +}; + +static struct i2c_board_info __initdata whistler_regulators[] = { + { + I2C_BOARD_INFO("max8907c", 0x3C), + .platform_data = &max8907c_pdata, + }, +}; + +static struct tegra_suspend_platform_data whistler_suspend_data = { + .cpu_timer = 2000, + .cpu_off_timer = 0, + .suspend_mode = TEGRA_SUSPEND_NONE, + .core_timer = 0x7e7e, + .core_off_timer = 0, + .separate_req = true, + .corereq_high = true, + .sysclkreq_high = true, + .wake_enb = 0, + .wake_high = 0, + .wake_low = 0, + .wake_any = 0, +}; + +int __init whistler_regulator_init(void) +{ + void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + u32 pmc_ctrl; + + /* configure the power management controller to trigger PMU + * interrupts when low */ + pmc_ctrl = readl(pmc + PMC_CTRL); + writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); + + i2c_register_board_info(4, whistler_regulators, 1); + + tegra_init_suspend(&whistler_suspend_data); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-whistler-sdhci.c b/arch/arm/mach-tegra/board-whistler-sdhci.c new file mode 100644 index 000000000000..481c19b8ea90 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-sdhci.c @@ -0,0 +1,128 @@ +/* + * arch/arm/mach-tegra/board-harmony-sdhci.c + * + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/resource.h> +#include <linux/platform_device.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> +#include <mach/irqs.h> +#include <mach/iomap.h> +#include <mach/sdhci.h> + +#include "board.h" + +static struct resource sdhci_resource0[] = { + [0] = { + .start = INT_SDMMC1, + .end = INT_SDMMC1, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = TEGRA_SDMMC1_BASE, + .end = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource sdhci_resource2[] = { + [0] = { + .start = INT_SDMMC3, + .end = INT_SDMMC3, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = TEGRA_SDMMC3_BASE, + .end = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource sdhci_resource3[] = { + [0] = { + .start = INT_SDMMC4, + .end = INT_SDMMC4, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = TEGRA_SDMMC4_BASE, + .end = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = { + .clk_id = NULL, + .force_hs = 0, + .cd_gpio = -1, + .wp_gpio = -1, + .power_gpio = -1, +}; + +static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = { + .clk_id = NULL, + .force_hs = 0, + .cd_gpio = -1, + .wp_gpio = -1, + .power_gpio = -1, +}; + +static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = { + .clk_id = NULL, + .force_hs = 0, + .cd_gpio = -1, + .wp_gpio = -1, + .power_gpio = -1, +}; + +static struct platform_device tegra_sdhci_device0 = { + .name = "sdhci-tegra", + .id = 0, + .resource = sdhci_resource0, + .num_resources = ARRAY_SIZE(sdhci_resource0), + .dev = { + .platform_data = &tegra_sdhci_platform_data0, + }, +}; + +static struct platform_device tegra_sdhci_device2 = { + .name = "sdhci-tegra", + .id = 2, + .resource = sdhci_resource2, + .num_resources = ARRAY_SIZE(sdhci_resource2), + .dev = { + .platform_data = &tegra_sdhci_platform_data2, + }, +}; + +static struct platform_device tegra_sdhci_device3 = { + .name = "sdhci-tegra", + .id = 3, + .resource = sdhci_resource3, + .num_resources = ARRAY_SIZE(sdhci_resource3), + .dev = { + .platform_data = &tegra_sdhci_platform_data3, + }, +}; + +int __init whistler_sdhci_init(void) +{ + platform_device_register(&tegra_sdhci_device3); + platform_device_register(&tegra_sdhci_device2); + platform_device_register(&tegra_sdhci_device0); + + return 0; +} diff --git a/arch/arm/mach-tegra/board-whistler-sensors.c b/arch/arm/mach-tegra/board-whistler-sensors.c new file mode 100644 index 000000000000..536a871a8303 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler-sensors.c @@ -0,0 +1,28 @@ +/* + * arch/arm/mach-tegra/board-whistler-sensors.c + * + * Copyright (c) 2010, NVIDIA, All Rights Reserved. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/i2c.h> +#include <mach/gpio.h> +#include "gpio-names.h" + +int __init whistler_sensors_init(void) +{ + return 0; +} diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c new file mode 100644 index 000000000000..6e220cad52f1 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler.c @@ -0,0 +1,236 @@ +/* + * arch/arm/mach-tegra/board-whistler.c + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/serial_8250.h> +#include <linux/i2c.h> +#include <linux/synaptics_i2c_rmi.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/i2c-tegra.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/usb/android_composite.h> +#include <linux/memblock.h> + +#include <mach/clk.h> +#include <mach/iomap.h> +#include <mach/irqs.h> +#include <mach/pinmux.h> +#include <mach/iomap.h> +#include <mach/io.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "board.h" +#include "clock.h" +#include "board-whistler.h" +#include "devices.h" +#include "gpio-names.h" +#include "fuse.h" + +static struct plat_serial8250_port debug_uart_platform_data[] = { + { + .membase = IO_ADDRESS(TEGRA_UARTA_BASE), + .mapbase = TEGRA_UARTA_BASE, + .irq = INT_UARTA, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = 216000000, + }, { + .flags = 0, + } +}; + +static struct platform_device debug_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = debug_uart_platform_data, + }, +}; + +static __initdata struct tegra_clk_init_table whistler_clk_init_table[] = { + /* name parent rate enabled */ + { "uarta", "pll_p", 216000000, true}, + { "pwm", "clk_32k", 32768, false}, + { "kbc", "clk_32k", 32768, true}, + { NULL, NULL, 0, 0}, +}; + +static char *usb_functions[] = { "mtp" }; +static char *usb_functions_adb[] = { "mtp", "adb" }; + +static struct android_usb_product usb_products[] = { + { + .product_id = 0x7102, + .num_functions = ARRAY_SIZE(usb_functions), + .functions = usb_functions, + }, + { + .product_id = 0x7100, + .num_functions = ARRAY_SIZE(usb_functions_adb), + .functions = usb_functions_adb, + }, +}; + +/* standard android USB platform data */ +static struct android_usb_platform_data andusb_plat = { + .vendor_id = 0x0955, + .product_id = 0x7100, + .manufacturer_name = "NVIDIA", + .product_name = "Whistler", + .serial_number = NULL, + .num_products = ARRAY_SIZE(usb_products), + .products = usb_products, + .num_functions = ARRAY_SIZE(usb_functions_adb), + .functions = usb_functions_adb, +}; + +static struct platform_device androidusb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &andusb_plat, + }, +}; + +static struct tegra_i2c_platform_data whistler_i2c1_platform_data = { + .adapter_nr = 0, + .bus_count = 1, + .bus_clk_rate = { 400000, 0 }, +}; + +static struct tegra_i2c_platform_data whistler_i2c2_platform_data = { + .adapter_nr = 1, + .bus_count = 1, + .bus_clk_rate = { 400000, 0 }, +}; + +static struct tegra_i2c_platform_data whistler_i2c3_platform_data = { + .adapter_nr = 3, + .bus_count = 1, + .bus_clk_rate = { 400000, 0 }, +}; + +static struct tegra_i2c_platform_data whistler_dvc_platform_data = { + .adapter_nr = 4, + .bus_count = 1, + .bus_clk_rate = { 400000, 0 }, + .is_dvc = true, +}; + +static void whistler_i2c_init(void) +{ + tegra_i2c_device1.dev.platform_data = &whistler_i2c1_platform_data; + tegra_i2c_device2.dev.platform_data = &whistler_i2c2_platform_data; + tegra_i2c_device3.dev.platform_data = &whistler_i2c3_platform_data; + tegra_i2c_device4.dev.platform_data = &whistler_dvc_platform_data; + + platform_device_register(&tegra_i2c_device4); + platform_device_register(&tegra_i2c_device3); + platform_device_register(&tegra_i2c_device2); + platform_device_register(&tegra_i2c_device1); +} + +static struct platform_device *whistler_devices[] __initdata = { + &tegra_otg_device, + &androidusb_device, + &debug_uart, + &pmu_device, + &tegra_udc_device, + &tegra_gart_device, + &tegra_wdt_device, + &tegra_avp_device, +}; + +static struct synaptics_i2c_rmi_platform_data synaptics_pdata= { + .flags = SYNAPTICS_FLIP_X | SYNAPTICS_FLIP_Y | SYNAPTICS_SWAP_XY, + .irqflags = IRQF_TRIGGER_LOW, +}; + +static const struct i2c_board_info whistler_i2c_touch_info[] = { + { + I2C_BOARD_INFO("synaptics-rmi-ts", 0x20), + .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC6), + .platform_data = &synaptics_pdata, + }, +}; + +static int __init whistler_touch_init(void) +{ + i2c_register_board_info(0, whistler_i2c_touch_info, 1); + + return 0; +} + +static void __init tegra_whistler_init(void) +{ + char serial[20]; + + tegra_common_init(); + tegra_clk_init_from_table(whistler_clk_init_table); + whistler_pinmux_init(); + + snprintf(serial, sizeof(serial), "%llx", tegra_chip_uid()); + andusb_plat.serial_number = kstrdup(serial, GFP_KERNEL); + + platform_add_devices(whistler_devices, ARRAY_SIZE(whistler_devices)); + + whistler_sdhci_init(); + whistler_i2c_init(); + whistler_regulator_init(); + whistler_panel_init(); + whistler_touch_init(); + whistler_kbc_init(); +} + +int __init tegra_whistler_protected_aperture_init(void) +{ + tegra_protected_aperture_init(tegra_grhost_aperture); + return 0; +} + +void __init tegra_whistler_reserve(void) +{ + if (memblock_reserve(0x0, 4096) < 0) + pr_warn("Cannot reserve first 4K of memory for safety\n"); + + tegra_reserve(SZ_128M, SZ_8M, SZ_16M); +} + +MACHINE_START(WHISTLER, "whistler") + .boot_params = 0x00000100, + .phys_io = IO_APB_PHYS, + .io_pg_offst = ((IO_APB_VIRT) >> 18) & 0xfffc, + .init_irq = tegra_init_irq, + .init_machine = tegra_whistler_init, + .map_io = tegra_map_common_io, + .reserve = tegra_whistler_reserve, + .timer = &tegra_timer, +MACHINE_END diff --git a/arch/arm/mach-tegra/board-whistler.h b/arch/arm/mach-tegra/board-whistler.h new file mode 100644 index 000000000000..62b682a8b2a9 --- /dev/null +++ b/arch/arm/mach-tegra/board-whistler.h @@ -0,0 +1,26 @@ +/* + * arch/arm/mach-tegra/board-whistler.h + * + * Copyright (C) 2010 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _MACH_TEGRA_BOARD_WHISTLER_H +#define _MACH_TEGRA_BOARD_WHISTLER_H + +int whistler_regulator_init(void); +int whistler_sdhci_init(void); +int whistler_pinmux_init(void); +int whistler_panel_init(void); +int whistler_kbc_init(void); + +#endif diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 04f1538b1a37..8a25cf664e8d 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -47,4 +47,22 @@ extern unsigned long tegra_lp0_vec_size; extern unsigned long tegra_grhost_aperture; extern struct sys_timer tegra_timer; + +enum board_fab { + BOARD_FAB_A = 0, + BOARD_FAB_B, + BOARD_FAB_C, + BOARD_FAB_D, +}; + +struct board_info { + u16 board_id; + u16 sku; + u8 fab; + u8 major_revision; + u8 minor_revision; +}; + +void tegra_get_board_info(struct board_info *); + #endif diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index a4b72dca2303..969544dafcaf 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -51,12 +51,21 @@ unsigned long tegra_lp0_vec_start; unsigned long tegra_lp0_vec_size; unsigned long tegra_grhost_aperture; +static struct board_info tegra_board_info = { + .board_id = -1, + .sku = -1, + .fab = -1, + .major_revision = -1, + .minor_revision = -1, +}; + void (*tegra_reset)(char mode, const char *cmd); static __initdata struct tegra_clk_init_table common_clk_init_table[] = { /* set up clocks that should always be on */ /* name parent rate enabled */ { "clk_m", NULL, 0, true }, + { "pll_m", "clk_m", 600000000, true }, { "pll_p", "clk_m", 216000000, true }, { "pll_p_out1", "pll_p", 28800000, true }, { "pll_p_out2", "pll_p", 48000000, true }, @@ -170,6 +179,56 @@ static int __init tegra_lp0_vec_arg(char *options) } early_param("lp0_vec", tegra_lp0_vec_arg); +static int __init tegra_board_info_parse(char *info) +{ + char *p; + int pos = 0; + struct board_info *bi = &tegra_board_info; + + while (info && *info) { + if ((p = strchr(info, ':'))) + *p++ = '\0'; + + if (strlen(info) > 0) { + switch(pos) { + case 0: + bi->board_id = simple_strtol(info, NULL, 16); + break; + case 1: + bi->sku = simple_strtol(info, NULL, 16); + break; + case 2: + bi->fab = simple_strtol(info, NULL, 16); + break; + case 3: + bi->major_revision = simple_strtol(info, NULL, 16); + break; + case 4: + bi->minor_revision = simple_strtol(info, NULL, 16); + break; + default: + break; + } + } + + info = p; + pos++; + } + + pr_info("board info: Id:%d%2d SKU:%d Fab:%d Rev:%c MinRev:%d\n", + bi->board_id >> 8 & 0xFF, bi->board_id & 0xFF, + bi->sku, bi->fab, bi->major_revision, bi->minor_revision); + + return 1; +} + +__setup("board_info=", tegra_board_info_parse); + +void tegra_get_board_info(struct board_info *bi) +{ + memcpy(bi, &tegra_board_info, sizeof(*bi)); +} + /* * Tegra has a protected aperture that prevents access by most non-CPU * memory masters to addresses above the aperture value. Enabling it diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index 0ac303ebf84c..484a39182d62 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -469,7 +469,30 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch, u32 csr; csr = CSR_IE_EOC | CSR_FLOW; - ahb_seq = AHB_SEQ_INTR_ENB | AHB_SEQ_BURST_1; + ahb_seq = AHB_SEQ_INTR_ENB; + + switch(req->req_sel) { + case TEGRA_DMA_REQ_SEL_SL2B1: + case TEGRA_DMA_REQ_SEL_SL2B2: + case TEGRA_DMA_REQ_SEL_SL2B3: + case TEGRA_DMA_REQ_SEL_SL2B4: + case TEGRA_DMA_REQ_SEL_SPI: + /* For spi/slink the burst size based on transfer size + * i.e. if multiple of 32 bytes then busrt is + * 8 word else if multiple of 16 bytes then burst is + * 4 word else burst size is 1 word */ + if (req->size & 0xF) + ahb_seq |= AHB_SEQ_BURST_1; + else if ((req->size >> 4) & 0x1) + ahb_seq |= AHB_SEQ_BURST_4; + else + ahb_seq |= AHB_SEQ_BURST_8; + break; + default: + ahb_seq |= AHB_SEQ_BURST_1; + break; + } + apb_seq = 0; csr |= req->req_sel << CSR_REQ_SEL_SHIFT; diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h index 68622b899c59..a785a2edc530 100644 --- a/arch/arm/mach-tegra/dvfs.h +++ b/arch/arm/mach-tegra/dvfs.h @@ -61,7 +61,8 @@ struct dvfs_rail { struct dvfs { /* Used only by tegra2_clock.c */ const char *clk_name; - int cpu_process_id; + int speedo_id; + int process_id; /* Must be initialized before tegra_dvfs_init */ int freqs_mult; diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 91919171e747..c016127cbaea 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -141,10 +141,7 @@ void tegra_init_fuse(void) u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); reg |= 1 << 28; writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); - - pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", - tegra_sku_id(), tegra_cpu_process_id(), - tegra_core_process_id()); + tegra_init_speedo_data(); } void tegra_init_fuse_dma(void) @@ -177,6 +174,12 @@ unsigned long long tegra_chip_uid(void) return (hi << 32ull) | lo; } +unsigned int tegra_spare_fuse(int bit) +{ + BUG_ON(bit < 0 || bit > 61); + return fuse_readl(FUSE_SPARE_BIT + bit * 4); +} + int tegra_sku_id(void) { int sku_id; @@ -184,19 +187,3 @@ int tegra_sku_id(void) sku_id = reg & 0xFF; return sku_id; } - -int tegra_cpu_process_id(void) -{ - int cpu_process_id; - u32 reg = fuse_readl(FUSE_SPARE_BIT); - cpu_process_id = (reg >> 6) & 3; - return cpu_process_id; -} - -int tegra_core_process_id(void) -{ - int core_process_id; - u32 reg = fuse_readl(FUSE_SPARE_BIT); - core_process_id = (reg >> 12) & 3; - return core_process_id; -} diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index 624bbfa6e5fb..1ea70b956a33 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -18,10 +18,13 @@ */ unsigned long long tegra_chip_uid(void); +unsigned int tegra_spare_fuse(int bit); int tegra_sku_id(void); int tegra_cpu_process_id(void); int tegra_core_process_id(void); +int tegra_soc_speedo_id(void); void tegra_init_fuse(void); void tegra_init_fuse_dma(void); +void tegra_init_speedo_data(void); u32 tegra_fuse_readl(unsigned long offset); void tegra_fuse_writel(u32 value, unsigned long offset); diff --git a/arch/arm/mach-tegra/headsmp-t2.S b/arch/arm/mach-tegra/headsmp-t2.S index 9da0ed68e63d..b71ff090918d 100644 --- a/arch/arm/mach-tegra/headsmp-t2.S +++ b/arch/arm/mach-tegra/headsmp-t2.S @@ -1,7 +1,7 @@ /* - * arch/arm/mach-tegra/headsmp.S + * arch/arm/mach-tegra/headsmp-t2.S * - * SMP initialization routines for Tegra SoCs + * SMP initialization routines for Tegra2 SoCs * * Copyright (c) 2009-2010, NVIDIA Corporation. * @@ -37,9 +37,7 @@ #define PMC_DPD_SAMPLE 0x20 #define PMC_DPD_ENABLE 0x24 -#define PMC_SCRATCH1 0x54 #define PMC_SCRATCH39 0x138 -#define RST_DEVICES_U 0xc #define CLK_RESET_PLLX_BASE 0xe0 #define CLK_RESET_PLLX_MISC 0xe4 @@ -50,28 +48,6 @@ /* .section ".cpuinit.text", "ax"*/ -.macro poke_ev, val, tmp - mov32 \tmp, (TEGRA_EXCEPTION_VECTORS_BASE + 0x100) - str \val, [\tmp] -.endm - -#ifdef CONFIG_SMP -/* - * tegra_secondary_startup - * - * Initial secondary processor boot vector; jumps to kernel's - * secondary_startup routine - */ -ENTRY(tegra_secondary_startup) - msr cpsr_fsxc, #0xd3 - bl __invalidate_cpu_state - cpu_id r0 - enable_coresite r1 - poke_ev r0, r1 - b secondary_startup -ENDPROC(tegra_secondary_startup) -#endif - /* * __restart_plls * @@ -108,30 +84,8 @@ __restart_plls: /* FIXME: need to record actual power transition here */ mov r0, #0 b __cortex_a9_l2x0_restart -ENDPROC(__restart_pllx) -/* - * __enable_coresite_access - * - * Takes the coresite debug interface out of reset, enables - * access to all CPUs. Called with MMU disabled. - */ - .align L1_CACHE_SHIFT -__enable_coresite_access: - mov32 r0, (TEGRA_CLK_RESET_BASE + RST_DEVICES_U) - mov32 r2, (TEGRA_TMRUS_BASE) +ENDPROC(__restart_plls) - /* assert reset for 2usec */ - ldr r1, [r0] - orr r1, #(1<<9) - str r1, [r0] - wait_for_us r3, r2, r4 - add r3, r3, #2 - bic r1, r1, #(1<<9) - wait_until r3, r2, r4 - str r1, [r0] - enable_coresite r3 - bx lr -ENDPROC(__enable_coresite_access) /* * tegra_lp2_startup * diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S new file mode 100644 index 000000000000..25f78071666e --- /dev/null +++ b/arch/arm/mach-tegra/headsmp.S @@ -0,0 +1,83 @@ +/* + * arch/arm/mach-tegra/headsmp.S + * + * SMP initialization routines for Tegra SoCs + * + * Copyright (c) 2009-2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/linkage.h> +#include <linux/init.h> + +#include <asm/assembler.h> +#include <asm/cache.h> + +#include <mach/iomap.h> +#include <mach/io.h> + +#include "power-macros.S" + +#define RST_DEVICES_U 0xc + +/* .section ".cpuinit.text", "ax"*/ + +.macro poke_ev, val, tmp + mov32 \tmp, (TEGRA_EXCEPTION_VECTORS_BASE + 0x100) + str \val, [\tmp] +.endm + +/* + * tegra_secondary_startup + * + * Initial secondary processor boot vector; jumps to kernel's + * secondary_startup routine + */ +ENTRY(tegra_secondary_startup) + msr cpsr_fsxc, #0xd3 + bl __invalidate_cpu_state + cpu_id r0 + enable_coresite r1 + poke_ev r0, r1 + b secondary_startup +ENDPROC(tegra_secondary_startup) + +/* + * __enable_coresite_access + * + * Called only on CPU0 to take the CoreSight debug interface out of + * reset. Called with MMU disabled. + */ + .align L1_CACHE_SHIFT +ENTRY(__enable_coresite_access) + mov32 r0, (TEGRA_CLK_RESET_BASE + RST_DEVICES_U) + mov32 r2, (TEGRA_TMRUS_BASE) + + /* assert reset for 2usec */ + ldr r1, [r0] +#ifndef CONFIG_TEGRA_FPGA_PLATFORM + orr r1, #(1<<9) + str r1, [r0] +#endif + wait_for_us r3, r2, r4 + add r3, r3, #2 + bic r1, r1, #(1<<9) + wait_until r3, r2, r4 + str r1, [r0] + /* Enable CoreSight */ + enable_coresite r3 + bx lr +ENDPROC(__enable_coresite_access) diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index 77a9f15bc0bf..0bc75fb4499f 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -44,6 +44,23 @@ enum { TEGRA_DC_OUT_HDMI, }; +struct tegra_dc_out_pin { + int name; + int pol; +}; + +enum { + TEGRA_DC_OUT_PIN_DATA_ENABLE, + TEGRA_DC_OUT_PIN_H_SYNC, + TEGRA_DC_OUT_PIN_V_SYNC, + TEGRA_DC_OUT_PIN_PIXEL_CLOCK, +}; + +enum { + TEGRA_DC_OUT_PIN_POL_LOW, + TEGRA_DC_OUT_PIN_POL_HIGH, +}; + struct tegra_dc_out { int type; unsigned flags; @@ -62,6 +79,9 @@ struct tegra_dc_out { struct tegra_dc_mode *modes; int n_modes; + struct tegra_dc_out_pin *out_pins; + unsigned n_out_pins; + int (*enable)(void); int (*disable)(void); }; diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h index e7fe2788e92d..e77176e7c87e 100644 --- a/arch/arm/mach-tegra/include/mach/iomap.h +++ b/arch/arm/mach-tegra/include/mach/iomap.h @@ -113,6 +113,9 @@ #define TEGRA_APB_DMA_CH0_BASE 0x6000B000 #define TEGRA_APB_DMA_CH0_SIZE 32 +#define TEGRA_AVP_CACHE_BASE 0x6000C000 +#define TEGRA_AVP_CACHE_SIZE 4 + #define TEGRA_AHB_GIZMO_BASE 0x6000C004 #define TEGRA_AHB_GIZMO_SIZE 0x10C diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h new file mode 100644 index 000000000000..641a9bbd8318 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/kbc.h @@ -0,0 +1,58 @@ +/* + * arch/arm/mach-tegra/include/mach/kbc.h + * + * Platform definitions for tegra-kbc keyboard input driver + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef ASMARM_ARCH_TEGRA_KBC_H +#define ASMARM_ARCH_TEGRA_KBC_H + +#include <linux/types.h> + +#define KBC_MAX_GPIO 24 +#define KBC_MAX_KPENT 8 + +#define KBC_MAX_ROW 16 +#define KBC_MAX_COL 8 + +#define KBC_MAX_KEY (KBC_MAX_ROW*KBC_MAX_COL) + +struct tegra_kbc_pin_cfg { + bool is_row; + bool is_col; + unsigned char num; +}; + +struct tegra_kbc_wake_key { + u8 row:4; + u8 col:4; +}; + +struct tegra_kbc_platform_data { + unsigned int debounce_cnt; + unsigned int repeat_cnt; + int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */ + int *plain_keycode; + int *fn_keycode; + int filter_keys; + struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO]; + struct tegra_kbc_wake_key *wake_cfg; +}; +#endif + diff --git a/arch/arm/mach-tegra/include/mach/memory.h b/arch/arm/mach-tegra/include/mach/memory.h index 4ebc3e055ed1..7c225b1d4d63 100644 --- a/arch/arm/mach-tegra/include/mach/memory.h +++ b/arch/arm/mach-tegra/include/mach/memory.h @@ -27,5 +27,7 @@ #define NET_IP_ALIGN 0 #define NET_SKB_PAD L1_CACHE_BYTES +#define CONSISTENT_DMA_SIZE (14 * SZ_1M) + #endif diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h index 34e2686fca45..ca4fc14038d2 100644 --- a/arch/arm/mach-tegra/include/mach/sdhci.h +++ b/arch/arm/mach-tegra/include/mach/sdhci.h @@ -18,6 +18,7 @@ #define __ASM_ARM_ARCH_TEGRA_SDHCI_H #include <linux/mmc/host.h> +#include <linux/mmc/card.h> struct tegra_sdhci_platform_data { const char *clk_id; @@ -28,6 +29,16 @@ struct tegra_sdhci_platform_data { void (*board_probe)(int id, struct mmc_host *); void (*board_remove)(int id, struct mmc_host *); + + /* embedded sdio data */ + struct sdio_cis cis; + struct sdio_cccr cccr; + struct sdio_embedded_func *funcs; + int num_funcs; + + /* card detect callback registration function */ + int (*register_status_notify)(void (*callback)(int card_present, + void *dev_id), void *dev_id); }; #endif diff --git a/arch/arm/mach-tegra/include/mach/spi.h b/arch/arm/mach-tegra/include/mach/spi.h new file mode 100644 index 000000000000..171e4007b4bc --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/spi.h @@ -0,0 +1,42 @@ +/* + * arch/arm/mach-tegra/include/mach/spi.h + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MACH_TEGRA_SPI_H +#define __MACH_TEGRA_SPI_H + +#include <linux/types.h> +#include <linux/spi/spi.h> + +typedef int (*callback)(void *client_data); + +/** + * register_spi_slave_callback - registers notification callback provided by + * the client. + * This callback indicate that the controller is all set to receive/transfer + * data. + * @spi: struct spi_device - refer to linux/spi/spi.h + * @func: Callback function + * @client_data: Data to be passed in callback + * Context: can not sleep + */ +int spi_tegra_register_callback(struct spi_device *spi, callback func, + void *client_data); + +#endif diff --git a/arch/arm/mach-tegra/include/mach/system.h b/arch/arm/mach-tegra/include/mach/system.h index 70c95ac93355..d7e807bb564f 100644 --- a/arch/arm/mach-tegra/include/mach/system.h +++ b/arch/arm/mach-tegra/include/mach/system.h @@ -32,11 +32,11 @@ static inline void arch_idle(void) static inline void tegra_assert_system_reset(void) { - void __iomem *reset = IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x04); + void __iomem *reset = IO_ADDRESS(TEGRA_PMC_BASE + 0x00); u32 reg; reg = readl(reset); - reg |= 0x04; + reg |= 0x10; writel(reg, reset); } diff --git a/arch/arm/mach-tegra/include/mach/tegra2_i2s.h b/arch/arm/mach-tegra/include/mach/tegra2_i2s.h new file mode 100644 index 000000000000..ce0702309049 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/tegra2_i2s.h @@ -0,0 +1,189 @@ +/* + * arch/arm/mach-tegra/include/mach/tegra2_i2s.h + * + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Iliyan Malchev <malchev@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_TEGRA_I2S_H +#define __ARCH_ARM_MACH_TEGRA_I2S_H + +#include <linux/kernel.h> +#include <linux/types.h> + + +/* Offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */ + +#define I2S_I2S_CTRL_0 0 +#define I2S_I2S_STATUS_0 4 +#define I2S_I2S_TIMING_0 8 +#define I2S_I2S_FIFO_SCR_0 0x0c +#define I2S_I2S_PCM_CTRL_0 0x10 +#define I2S_I2S_NW_CTRL_0 0x14 +#define I2S_I2S_TDM_CTRL_0 0x20 +#define I2S_I2S_TDM_TX_RX_CTRL_0 0x24 +#define I2S_I2S_FIFO1_0 0x40 +#define I2S_I2S_FIFO2_0 0x80 + +/* + * I2S_I2S_CTRL_0 + */ + +#define I2S_I2S_CTRL_FIFO2_TX_ENABLE (1<<30) +#define I2S_I2S_CTRL_FIFO1_ENABLE (1<<29) +#define I2S_I2S_CTRL_FIFO2_ENABLE (1<<28) +#define I2S_I2S_CTRL_FIFO1_RX_ENABLE (1<<27) +#define I2S_I2S_CTRL_FIFO_LPBK_ENABLE (1<<26) +#define I2S_I2S_CTRL_MASTER_ENABLE (1<<25) +#define I2S_I2S_CTRL_L_R_CTRL (1<<24) /* 0 = Left low/Right high */ + +#define I2S_BIT_FORMAT_I2S 0 +#define I2S_BIT_FORMAT_RJM 1 +#define I2S_BIT_FORMAT_LJM 2 +#define I2S_BIT_FORMAT_DSP 3 +#define I2S_BIT_FORMAT_SHIFT 10 + +#define I2S_I2S_CTRL_BIT_FORMAT_MASK (3<<10) +#define I2S_I2S_CTRL_BIT_FORMAT_I2S (I2S_BIT_FORMAT_I2S<<10) +#define I2S_I2S_CTRL_BIT_FORMAT_RJM (I2S_BIT_FORMAT_RJM<<10) +#define I2S_I2S_CTRL_BIT_FORMAT_LJM (I2S_BIT_FORMAT_LJM<<10) +#define I2S_I2S_CTRL_BIT_FORMAT_DSP (I2S_BIT_FORMAT_DSP<<10) + +#define I2S_BIT_SIZE_16 0 +#define I2S_BIT_SIZE_20 1 +#define I2S_BIT_SIZE_24 2 +#define I2S_BIT_SIZE_32 3 +#define I2S_BIT_SIZE_SHIFT 8 + +#define I2S_I2S_CTRL_BIT_SIZE_MASK (3 << I2S_BIT_SIZE_SHIFT) +#define I2S_I2S_CTRL_BIT_SIZE_16 (I2S_BIT_SIZE_16 << I2S_BIT_SIZE_SHIFT) +#define I2S_I2S_CTRL_BIT_SIZE_20 (I2S_BIT_SIZE_20 << I2S_BIT_SIZE_SHIFT) +#define I2S_I2S_CTRL_BIT_SIZE_24 (I2S_BIT_SIZE_24 << I2S_BIT_SIZE_SHIFT) +#define I2S_I2S_CTRL_BIT_SIZE_32 (I2S_BIT_SIZE_32 << I2S_BIT_SIZE_SHIFT) + +#define I2S_FIFO_16_LSB 0 +#define I2S_FIFO_20_LSB 1 +#define I2S_FIFO_24_LSB 2 +#define I2S_FIFO_32 3 +#define I2S_FIFO_PACKED 7 +#define I2S_FIFO_SHIFT 4 + +#define I2S_I2S_CTRL_FIFO_FORMAT_MASK (7<<4) +#define I2S_I2S_CTRL_FIFO_FORMAT_16_LSB (I2S_FIFO_16_LSB << I2S_FIFO_SHIFT) +#define I2S_I2S_CTRL_FIFO_FORMAT_20_LSB (I2S_FIFO_20_LSB << I2S_FIFO_SHIFT) +#define I2S_I2S_CTRL_FIFO_FORMAT_24_LSB (I2S_FIFO_24_LSB << I2S_FIFO_SHIFT) +#define I2S_I2S_CTRL_FIFO_FORMAT_32 (I2S_FIFO_32 << I2S_FIFO_SHIFT) +#define I2S_I2S_CTRL_FIFO_FORMAT_PACKED (I2S_FIFO_PACKED << I2S_FIFO_SHIFT) + +// Left/Right Control Polarity. 0= Left channel when LRCK is low, Right channel when LRCK is high, 1= vice versa +#define I2S_LRCK_LEFT_LOW 0 +#define I2S_LRCK_RIGHT_LOW 1 +#define I2S_LRCK_SHIFT 24 + + +#define I2S_I2S_CTRL_LRCK_MASK (1<<I2S_LRCK_SHIFT) +#define I2S_I2S_CTRL_LRCK_L_LOW (I2S_LRCK_LEFT_LOW << I2S_LRCK_SHIFT) +#define I2S_I2S_CTRL_LRCK_R_LOW (I2S_LRCK_RIGHT_LOW << I2S_LRCK_SHIFT) + + +#define I2S_I2S_IE_FIFO1_ERR (1<<3) +#define I2S_I2S_IE_FIFO2_ERR (1<<2) +#define I2S_I2S_QE_FIFO1 (1<<1) +#define I2S_I2S_QE_FIFO2 (1<<0) + +/* + * I2S_I2S_STATUS_0 + */ + +#define I2S_I2S_STATUS_FIFO1_RDY (1<<31) +#define I2S_I2S_STATUS_FIFO2_RDY (1<<30) +#define I2S_I2S_STATUS_FIFO1_BSY (1<<29) +#define I2S_I2S_STATUS_FIFO2_BSY (1<<28) +#define I2S_I2S_STATUS_FIFO1_ERR (1<<3) +#define I2S_I2S_STATUS_FIFO2_ERR (1<<2) +#define I2S_I2S_STATUS_QS_FIFO1 (1<<1) +#define I2S_I2S_STATUS_QS_FIFO2 (1<<0) + +/* + * I2S_I2S_TIMING_0 + */ + +#define I2S_I2S_TIMING_NON_SYM_ENABLE (1<<12) +#define I2S_I2S_TIMING_CHANNEL_BIT_COUNT_MASK 0x7ff +#define I2S_I2S_TIMING_CHANNEL_BIT_COUNT (1<<0) + +/* + * I2S_I2S_FIFO_SCR_0 + */ + +#define I2S_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f +#define I2S_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24 +#define I2S_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16 + +#define I2S_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_MASK (0x3f<<24) +#define I2S_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_MASK (0x3f<<16) + +#define I2S_I2S_FIFO_SCR_FIFO2_CLR (1<<12) +#define I2S_I2S_FIFO_SCR_FIFO1_CLR (1<<8) + +#define I2S_FIFO_ATN_LVL_ONE_SLOT 0 +#define I2S_FIFO_ATN_LVL_FOUR_SLOTS 1 +#define I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2 +#define I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3 +#define I2S_FIFO2_ATN_LVL_SHIFT 4 +#define I2S_FIFO1_ATN_LVL_SHIFT 0 + +#define I2S_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << I2S_FIFO2_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (I2S_FIFO_ATN_LVL_ONE_SLOT << I2S_FIFO2_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (I2S_FIFO_ATN_LVL_FOUR_SLOTS << I2S_FIFO2_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (I2S_FIFO_ATN_LVL_EIGHT_SLOTS << I2S_FIFO2_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (I2S_FIFO_ATN_LVL_TWELVE_SLOTS << I2S_FIFO2_ATN_LVL_SHIFT) + +#define I2S_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << I2S_FIFO1_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (I2S_FIFO_ATN_LVL_ONE_SLOT << I2S_FIFO1_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (I2S_FIFO_ATN_LVL_FOUR_SLOTS << I2S_FIFO1_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (I2S_FIFO_ATN_LVL_EIGHT_SLOTS << I2S_FIFO1_ATN_LVL_SHIFT) +#define I2S_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (I2S_FIFO_ATN_LVL_TWELVE_SLOTS << I2S_FIFO1_ATN_LVL_SHIFT) + +/* + * API + */ + +void i2s_dump_registers(int ifc); +int i2s_set_channel_bit_count(int ifc, int sampling, int bitclk); +void i2s_set_fifo_mode(int ifc, int fifo, int tx); +void i2s_set_loopback(int ifc, int on); +int i2s_fifo_set_attention_level(int ifc, int fifo, unsigned level); +void i2s_fifo_enable(int ifc, int fifo, int on); +void i2s_fifo_clear(int ifc, int fifo); +void i2s_set_master(int ifc, int master); +int i2s_set_bit_format(int ifc, unsigned format); +int i2s_set_bit_size(int ifc, unsigned bit_size); +int i2s_set_fifo_format(int ifc, unsigned fmt); +void i2s_set_left_right_control_polarity(int ifc, int high_low); +void i2s_set_fifo_irq_on_err(int ifc, int fifo, int on); +void i2s_set_fifo_irq_on_qe(int ifc, int fifo, int on); +void i2s_enable_fifos(int ifc, int on); +void i2s_fifo_write(int ifc, int fifo, u32 data); +u32 i2s_fifo_read(int ifc, int fifo); +u32 i2s_get_status(int ifc); +u32 i2s_get_control(int ifc); +void i2s_ack_status(int ifc); +u32 i2s_get_fifo_scr(int ifc); +u32 i2s_get_fifo_full_empty_count(int ifc, int fifo); +phys_addr_t i2s_get_fifo_phy_base(int ifc, int fifo); +struct clk *i2s_get_clock_by_name(const char *name); + +#endif /* __ARCH_ARM_MACH_TEGRA_I2S_H */ diff --git a/arch/arm/mach-tegra/include/mach/vmalloc.h b/arch/arm/mach-tegra/include/mach/vmalloc.h index fd6aa65b2dc6..db488e890b9e 100644 --- a/arch/arm/mach-tegra/include/mach/vmalloc.h +++ b/arch/arm/mach-tegra/include/mach/vmalloc.h @@ -23,6 +23,6 @@ #include <asm/sizes.h> -#define VMALLOC_END 0xFE000000UL +#define VMALLOC_END 0xF8000000UL #endif diff --git a/arch/arm/mach-tegra/spi_tegra_slave.c b/arch/arm/mach-tegra/spi_tegra_slave.c new file mode 100644 index 000000000000..48492ab9253a --- /dev/null +++ b/arch/arm/mach-tegra/spi_tegra_slave.c @@ -0,0 +1,860 @@ +/* + * arch/arm/mach-tegra/tegra_spi_slave.c + * + * Tegra slave spi driver for NVIDIA Tegra SoCs + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <linux/spi/spi.h> + +#include <mach/dma.h> +#include <mach/spi.h> + +#define SLINK_COMMAND 0x000 +#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) +#define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5) +#define SLINK_BOTH_EN (1 << 10) +#define SLINK_CS_SW (1 << 11) +#define SLINK_CS_VALUE (1 << 12) +#define SLINK_CS_POLARITY (1 << 13) +#define SLINK_IDLE_SDA_DRIVE_LOW (0 << 16) +#define SLINK_IDLE_SDA_DRIVE_HIGH (1 << 16) +#define SLINK_IDLE_SDA_PULL_LOW (2 << 16) +#define SLINK_IDLE_SDA_PULL_HIGH (3 << 16) +#define SLINK_IDLE_SDA_MASK (3 << 16) +#define SLINK_CS_POLARITY1 (1 << 20) +#define SLINK_CK_SDA (1 << 21) +#define SLINK_CS_POLARITY2 (1 << 22) +#define SLINK_CS_POLARITY3 (1 << 23) +#define SLINK_IDLE_SCLK_DRIVE_LOW (0 << 24) +#define SLINK_IDLE_SCLK_DRIVE_HIGH (1 << 24) +#define SLINK_IDLE_SCLK_PULL_LOW (2 << 24) +#define SLINK_IDLE_SCLK_PULL_HIGH (3 << 24) +#define SLINK_IDLE_SCLK_MASK (3 << 24) +#define SLINK_M_S (1 << 28) +#define SLINK_WAIT (1 << 29) +#define SLINK_GO (1 << 30) +#define SLINK_ENB (1 << 31) + +#define SLINK_COMMAND2 0x004 +#define SLINK_LSBFE (1 << 0) +#define SLINK_SSOE (1 << 1) +#define SLINK_SPIE (1 << 4) +#define SLINK_BIDIROE (1 << 6) +#define SLINK_MODFEN (1 << 7) +#define SLINK_INT_SIZE(x) (((x) & 0x1f) << 8) +#define SLINK_CS_ACTIVE_BETWEEN (1 << 17) +#define SLINK_SS_EN_CS(x) (((x) & 0x3) << 18) +#define SLINK_SS_SETUP(x) (((x) & 0x3) << 20) +#define SLINK_FIFO_REFILLS_0 (0 << 22) +#define SLINK_FIFO_REFILLS_1 (1 << 22) +#define SLINK_FIFO_REFILLS_2 (2 << 22) +#define SLINK_FIFO_REFILLS_3 (3 << 22) +#define SLINK_FIFO_REFILLS_MASK (3 << 22) +#define SLINK_WAIT_PACK_INT(x) (((x) & 0x7) << 26) +#define SLINK_SPC0 (1 << 29) +#define SLINK_TXEN (1 << 30) +#define SLINK_RXEN (1 << 31) + +#define SLINK_STATUS 0x008 +#define SLINK_COUNT(val) (((val) >> 0) & 0x1f) +#define SLINK_WORD(val) (((val) >> 5) & 0x1f) +#define SLINK_BLK_CNT(val) (((val) >> 0) & 0xffff) +#define SLINK_MODF (1 << 16) +#define SLINK_RX_UNF (1 << 18) +#define SLINK_TX_OVF (1 << 19) +#define SLINK_TX_FULL (1 << 20) +#define SLINK_TX_EMPTY (1 << 21) +#define SLINK_RX_FULL (1 << 22) +#define SLINK_RX_EMPTY (1 << 23) +#define SLINK_TX_UNF (1 << 24) +#define SLINK_RX_OVF (1 << 25) +#define SLINK_TX_FLUSH (1 << 26) +#define SLINK_RX_FLUSH (1 << 27) +#define SLINK_SCLK (1 << 28) +#define SLINK_ERR (1 << 29) +#define SLINK_RDY (1 << 30) +#define SLINK_BSY (1 << 31) + +#define SLINK_MAS_DATA 0x010 +#define SLINK_SLAVE_DATA 0x014 + +#define SLINK_DMA_CTL 0x018 +#define SLINK_DMA_BLOCK_SIZE(x) (((x) & 0xffff) << 0) +#define SLINK_TX_TRIG_1 (0 << 16) +#define SLINK_TX_TRIG_4 (1 << 16) +#define SLINK_TX_TRIG_8 (2 << 16) +#define SLINK_TX_TRIG_16 (3 << 16) +#define SLINK_TX_TRIG_MASK (3 << 16) +#define SLINK_RX_TRIG_1 (0 << 18) +#define SLINK_RX_TRIG_4 (1 << 18) +#define SLINK_RX_TRIG_8 (2 << 18) +#define SLINK_RX_TRIG_16 (3 << 18) +#define SLINK_RX_TRIG_MASK (3 << 18) +#define SLINK_PACKED (1 << 20) +#define SLINK_PACK_SIZE_4 (0 << 21) +#define SLINK_PACK_SIZE_8 (1 << 21) +#define SLINK_PACK_SIZE_16 (2 << 21) +#define SLINK_PACK_SIZE_32 (3 << 21) +#define SLINK_PACK_SIZE_MASK (3 << 21) +#define SLINK_IE_TXC (1 << 26) +#define SLINK_IE_RXC (1 << 27) +#define SLINK_DMA_EN (1 << 31) + +#define SLINK_STATUS2 0x01c +#define SLINK_TX_FIFO_EMPTY_COUNT(val) (((val) & 0x3f) >> 0) +#define SLINK_RX_FIFO_FULL_COUNT(val) (((val) & 0x3f) >> 16) + +#define SLINK_TX_FIFO 0x100 +#define SLINK_RX_FIFO 0x180 + +static const unsigned long spi_tegra_req_sels[] = { + TEGRA_DMA_REQ_SEL_SL2B1, + TEGRA_DMA_REQ_SEL_SL2B2, + TEGRA_DMA_REQ_SEL_SL2B3, + TEGRA_DMA_REQ_SEL_SL2B4, +}; + +#define BB_LEN 2048 +#define TX_FIFO_EMPTY_COUNT_MAX SLINK_TX_FIFO_EMPTY_COUNT(0x20) +#define RX_FIFO_FULL_COUNT_ZERO SLINK_RX_FIFO_FULL_COUNT(0) + +#define SLINK_STATUS2_RESET \ + (TX_FIFO_EMPTY_COUNT_MAX | \ + RX_FIFO_FULL_COUNT_ZERO << 16) + +struct spi_tegra_data { + struct spi_master *master; + struct platform_device *pdev; + spinlock_t lock; + + struct clk *clk; + void __iomem *base; + unsigned long phys; + + u32 cur_speed; + + struct list_head queue; + struct spi_transfer *cur; + unsigned cur_pos; + unsigned cur_len; + unsigned cur_bytes_per_word; + + /* The tegra spi controller has a bug which causes the first word + * in PIO transactions to be garbage. Since packed DMA transactions + * require transfers to be 4 byte aligned we need a bounce buffer + * for the generic case. + */ + struct tegra_dma_req rx_dma_req; + struct tegra_dma_channel *rx_dma; + u32 *rx_bb; + dma_addr_t rx_bb_phys; + + struct tegra_dma_req tx_dma_req; + struct tegra_dma_channel *tx_dma; + u32 *tx_bb; + dma_addr_t tx_bb_phys; + + bool is_suspended; + unsigned long save_slink_cmd; + callback client_funct; + void *client_data; + + u32 rx_complete; + u32 tx_complete; + bool abort_happen; + + u8 g_bits_per_word; +}; + +static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi, + unsigned long reg) +{ + return readl(tspi->base + reg); +} + +static inline void spi_tegra_writel(struct spi_tegra_data *tspi, + unsigned long val, + unsigned long reg) +{ + writel(val, tspi->base + reg); +} + +static void spi_tegra_clear_status(struct spi_tegra_data *tspi) +{ + unsigned long val; + unsigned long val_write = 0; + + val = spi_tegra_readl(tspi, SLINK_STATUS); + if (val & SLINK_BSY) + val_write |= SLINK_BSY; + + if (val & SLINK_ERR) { + val_write |= SLINK_ERR; + printk("%s ERROR bit set 0x%lx \n", __func__, val); + if (val & SLINK_TX_OVF) + val_write |= SLINK_TX_OVF; + if (val & SLINK_RX_OVF) + val_write |= SLINK_RX_OVF; + if (val & SLINK_RX_UNF) + val_write |= SLINK_RX_UNF; + if (val & SLINK_TX_UNF) + val_write |= SLINK_TX_UNF; + if (!(val & SLINK_TX_EMPTY)) + val_write |= SLINK_TX_FLUSH; + if (!(val & SLINK_RX_EMPTY)) + val_write |= SLINK_RX_FLUSH; + } + spi_tegra_writel(tspi, val_write, SLINK_STATUS); +} + +static void spi_tegra_go(struct spi_tegra_data *tspi) +{ + unsigned long val; + unsigned long test_val; + + wmb(); + + val = spi_tegra_readl(tspi, SLINK_DMA_CTL); + val &= ~SLINK_DMA_BLOCK_SIZE(~0) & ~SLINK_DMA_EN; + val |= SLINK_DMA_BLOCK_SIZE(tspi->rx_dma_req.size / 4 - 1); + spi_tegra_writel(tspi, val, SLINK_DMA_CTL); + tegra_dma_enqueue_req(tspi->tx_dma, &tspi->tx_dma_req); + tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req); + + val |= SLINK_DMA_EN; + val &= ~SLINK_TX_TRIG_MASK & ~SLINK_RX_TRIG_MASK; + + if (tspi->rx_dma_req.size & 0xF) + val |= SLINK_TX_TRIG_1 | SLINK_RX_TRIG_1; + else if (((tspi->rx_dma_req.size) >> 4) & 0x1) + val |= SLINK_TX_TRIG_4 | SLINK_RX_TRIG_4; + else + val |= SLINK_TX_TRIG_8 | SLINK_RX_TRIG_8; + + /* + * TRM 24.1.1.7 wait for the FIFO to be full + */ + test_val = spi_tegra_readl(tspi, SLINK_STATUS); + while (!(test_val & SLINK_TX_FULL)) + test_val = spi_tegra_readl(tspi, SLINK_STATUS); + + spi_tegra_writel(tspi, val, SLINK_DMA_CTL); +} + +static unsigned spi_tegra_fill_tx_fifo(struct spi_tegra_data *tspi, + struct spi_transfer *t) +{ + unsigned len = min(t->len - tspi->cur_pos, BB_LEN * + tspi->cur_bytes_per_word); + u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_pos; + int i, j; + unsigned long val; + + val = spi_tegra_readl(tspi, SLINK_COMMAND); + val &= ~SLINK_WORD_SIZE(~0); + val |= SLINK_WORD_SIZE(len / tspi->cur_bytes_per_word - 1); + spi_tegra_writel(tspi, val, SLINK_COMMAND); + + if (tspi->g_bits_per_word == 32) { + memcpy(tspi->tx_bb, (void *)tx_buf, len); + } else { + for (i = 0; i < len; i += tspi->cur_bytes_per_word) { + val = 0; + for (j = 0; j < tspi->cur_bytes_per_word; j++) + val |= tx_buf[i + j] << j * 8; + + tspi->tx_bb[i / tspi->cur_bytes_per_word] = val; + } + } + + tspi->tx_dma_req.size = len / tspi->cur_bytes_per_word * 4; + + return len; +} + +static unsigned spi_tegra_drain_rx_fifo(struct spi_tegra_data *tspi, + struct spi_transfer *t) +{ + unsigned len = tspi->cur_len; + int i, j; + u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_pos; + unsigned long val; + + if (tspi->g_bits_per_word == 32) { + memcpy(rx_buf, (void *)tspi->rx_bb, len); + } else { + for (i = 0; i < len; i += tspi->cur_bytes_per_word) { + val = tspi->rx_bb[i / tspi->cur_bytes_per_word]; + for (j = 0; j < tspi->cur_bytes_per_word; j++) + rx_buf[i + j] = (val >> (j * 8)) & 0xff; + } + } + + return len; +} + +int spi_tegra_register_callback(struct spi_device *spi, callback func, + void *client_data) +{ + struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master); + + if (!tspi || !func) + return -EINVAL; + tspi->client_funct = func; + tspi->client_data = client_data; + return 0; +} +EXPORT_SYMBOL(spi_tegra_register_callback); + +static void spi_tegra_start_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master); + unsigned long cs_bit; + u32 speed; + u8 bits_per_word; + unsigned long val; + + speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz; + bits_per_word = t->bits_per_word ? t->bits_per_word : + spi->bits_per_word; + tspi->g_bits_per_word = bits_per_word; + + tspi->cur_bytes_per_word = (bits_per_word - 1) / 8 + 1; + + if (speed != tspi->cur_speed) + clk_set_rate(tspi->clk, speed); + + if (tspi->cur_speed == 0) + clk_enable(tspi->clk); + + tspi->cur_speed = speed; + + spi_tegra_clear_status(tspi); + val = spi_tegra_readl(tspi, SLINK_COMMAND2); + val &= ~SLINK_SS_EN_CS(~0) | SLINK_RXEN | SLINK_TXEN; + if (t->rx_buf) + val |= SLINK_RXEN; + if (t->tx_buf) + val |= SLINK_TXEN; + val |= SLINK_SS_EN_CS(spi->chip_select); + val |= SLINK_SPIE; + spi_tegra_writel(tspi, val, SLINK_COMMAND2); + + val = spi_tegra_readl(tspi, SLINK_COMMAND); + switch (spi->chip_select) { + case 0: + cs_bit = SLINK_CS_POLARITY; + break; + + case 1: + cs_bit = SLINK_CS_POLARITY1; + break; + + case 2: + cs_bit = SLINK_CS_POLARITY2; + break; + + case 4: + cs_bit = SLINK_CS_POLARITY3; + break; + + default: + return; + } + if (spi->mode & SPI_CS_HIGH) + val |= cs_bit; + else + val &= ~cs_bit; + + val &= ~SLINK_BIT_LENGTH(~0); + val |= SLINK_BIT_LENGTH(bits_per_word - 1); + + /* FIXME: should probably control CS manually so that we can be sure + * it does not go low between transfer and to support delay_usecs + * correctly. + */ + val &= ~SLINK_IDLE_SCLK_MASK & ~SLINK_CK_SDA & ~SLINK_CS_SW; + + if (spi->mode & SPI_CPHA) + val |= SLINK_CK_SDA; + if (spi->mode & SPI_CPOL) + val |= SLINK_IDLE_SCLK_DRIVE_HIGH; + else + val |= SLINK_IDLE_SCLK_DRIVE_LOW; + + val &= ~(SLINK_M_S); /* set slave mode */ + + spi_tegra_writel(tspi, val, SLINK_COMMAND); + spi_tegra_writel(tspi, SLINK_RX_FLUSH | SLINK_TX_FLUSH, SLINK_STATUS); + tspi->cur = t; + tspi->cur_pos = 0; + tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, t); + tspi->rx_dma_req.size = tspi->tx_dma_req.size; + tspi->rx_complete = 0; + tspi->tx_complete = 0; + tspi->abort_happen = false; + + spi_tegra_go(tspi); + /* notify client that we're ready for transfer */ + if (tspi->client_funct) + tspi->client_funct(tspi->client_data); +} + +static void spi_tegra_start_message(struct spi_device *spi, + struct spi_message *m) +{ + struct spi_transfer *t; + + m->actual_length = 0; + m->status = 0; + + t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); + spi_tegra_start_transfer(spi, t); +} + +static void complete_operation(struct tegra_dma_req *req) +{ + struct spi_tegra_data *tspi = req->dev; + unsigned long val; + struct spi_message *m; + struct spi_device *spi; + u32 timeout = 0; + u32 temp = 0; + + if (tspi->abort_happen == true) { + unsigned long val_write = 0; + val_write = spi_tegra_readl(tspi, SLINK_STATUS); + val_write = val_write | SLINK_TX_FLUSH | SLINK_RX_FLUSH ; + + spi_tegra_writel(tspi, val_write, SLINK_STATUS); + + /*In order to make sure Tx fifo fluch is completed.*/ + while (spi_tegra_readl(tspi, SLINK_STATUS)&SLINK_TX_FLUSH) + ; + /*In order to make sure Rx fifo fluch is completed.*/ + while (spi_tegra_readl(tspi, SLINK_STATUS)&SLINK_RX_FLUSH) + ; + } + + /* the SPI controller may come back with both the BSY and RDY bits + * set. In this case we need to wait for the BSY bit to clear so + * that we are sure the DMA is finished. 1000 reads was empirically + * determined to be long enough. + */ + + while ((spi_tegra_readl(tspi, SLINK_STATUS) & SLINK_BSY)) { + if (timeout++ > 1000) + break; + } + + while ((spi_tegra_readl(tspi, SLINK_STATUS2)) != SLINK_STATUS2_RESET) { + if (temp++ > 50000) + break; + } + + spi_tegra_clear_status(tspi); + + val = spi_tegra_readl(tspi, SLINK_STATUS); + val |= SLINK_RDY; + spi_tegra_writel(tspi, val, SLINK_STATUS); + + m = list_first_entry(&tspi->queue, struct spi_message, queue); + + if ((timeout >= 1000) || (temp >= 50000)) + m->status = -EIO; + + spi = m->state; + + tspi->cur_pos += spi_tegra_drain_rx_fifo(tspi, tspi->cur); + m->actual_length += tspi->cur_pos; + + if (!list_is_last(&tspi->cur->transfer_list, &m->transfers)) { + tspi->cur = list_first_entry(&tspi->cur->transfer_list, + struct spi_transfer, transfer_list); + spi_tegra_start_transfer(spi, tspi->cur); + } else { + list_del(&m->queue); + + m->complete(m->context); + + if (!list_empty(&tspi->queue)) { + m = list_first_entry(&tspi->queue, struct spi_message, + queue); + spi = m->state; + spi_tegra_start_message(spi, m); + } else { + clk_disable(tspi->clk); + tspi->cur_speed = 0; + } + } +} + +static void tegra_spi_tx_dma_complete(struct tegra_dma_req *req) +{ + struct spi_tegra_data *tspi = req->dev; + unsigned long flags; + + spin_lock_irqsave(&tspi->lock, flags); + + (tspi->tx_complete)++; + + if (((tspi->rx_complete) == 1) && ((tspi->tx_complete) == 1)) + complete_operation(req); + + spin_unlock_irqrestore(&tspi->lock, flags); + +} + +static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req) +{ + struct spi_tegra_data *tspi = req->dev; + unsigned long flags; + + spin_lock_irqsave(&tspi->lock, flags); + + (tspi->rx_complete)++; + + if (((tspi->rx_complete) == 1) && ((tspi->tx_complete) == 1)) + complete_operation(req); + + spin_unlock_irqrestore(&tspi->lock, flags); +} + +static int spi_tegra_setup(struct spi_device *spi) +{ + dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n", + spi->bits_per_word, + spi->mode & SPI_CPOL ? "" : "~", + spi->mode & SPI_CPHA ? "" : "~", + spi->max_speed_hz); + + return 0; +} + +static int spi_tegra_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master); + struct spi_transfer *t; + unsigned long flags; + int was_empty; + + if (list_empty(&m->transfers) || !m->complete) + return -EINVAL; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->bits_per_word < 0 || t->bits_per_word > 32) + return -EINVAL; + + if (t->len == 0) + return -EINVAL; + + if (!t->rx_buf && !t->tx_buf) + return -EINVAL; + } + + spin_lock_irqsave(&tspi->lock, flags); + + if (WARN_ON(tspi->is_suspended)) { + spin_unlock_irqrestore(&tspi->lock, flags); + return -EBUSY; + } + + m->state = spi; + + was_empty = list_empty(&tspi->queue); + list_add_tail(&m->queue, &tspi->queue); + + if (was_empty) + spi_tegra_start_message(spi, m); + + spin_unlock_irqrestore(&tspi->lock, flags); + + return 0; +} + +static int __init spi_tegra_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct spi_tegra_data *tspi; + struct resource *r; + int ret; + + master = spi_alloc_master(&pdev->dev, sizeof *tspi); + if (master == NULL) { + dev_err(&pdev->dev, "master allocation failed\n"); + return -ENOMEM; + } + + /* the spi->mode bits understood by this driver: */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + + if (pdev->id != -1) + master->bus_num = pdev->id; + + master->setup = spi_tegra_setup; + master->transfer = spi_tegra_transfer; + master->num_chipselect = 4; + + dev_set_drvdata(&pdev->dev, master); + tspi = spi_master_get_devdata(master); + tspi->master = master; + tspi->pdev = pdev; + spin_lock_init(&tspi->lock); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + ret = -ENODEV; + goto err0; + } + + if (!request_mem_region(r->start, (r->end - r->start) + 1, + dev_name(&pdev->dev))) { + ret = -EBUSY; + goto err0; + } + + tspi->phys = r->start; + tspi->base = ioremap(r->start, r->end - r->start + 1); + if (!tspi->base) { + dev_err(&pdev->dev, "can't ioremap iomem\n"); + ret = -ENOMEM; + goto err1; + } + + tspi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR_OR_NULL(tspi->clk)) { + dev_err(&pdev->dev, "can not get clock\n"); + ret = PTR_ERR(tspi->clk); + goto err2; + } + + INIT_LIST_HEAD(&tspi->queue); + + tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); + if (!tspi->rx_dma) { + dev_err(&pdev->dev, "can not allocate rx dma channel\n"); + ret = -ENODEV; + goto err3; + } + + tspi->rx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + &tspi->rx_bb_phys, GFP_KERNEL); + if (!tspi->rx_bb) { + dev_err(&pdev->dev, "can not allocate rx bounce buffer\n"); + ret = -ENOMEM; + goto err4; + } + + memset(&tspi->rx_dma_req, 0, sizeof(struct tegra_dma_req)) ; + tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete; + tspi->rx_dma_req.to_memory = 1; + tspi->rx_dma_req.dest_addr = tspi->rx_bb_phys; + tspi->rx_dma_req.virt_addr = tspi->rx_bb ; + tspi->rx_dma_req.dest_bus_width = 32; + tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO; + tspi->rx_dma_req.source_bus_width = 32; + tspi->rx_dma_req.source_wrap = 4; + tspi->rx_dma_req.dest_wrap = 0 ; + tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id]; + tspi->rx_dma_req.dev = tspi; + + tspi->tx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); + if (IS_ERR(tspi->tx_dma)) { + dev_err(&pdev->dev, "can not allocate tx dma channel\n"); + ret = PTR_ERR(tspi->tx_dma); + goto err5; + } + + tspi->tx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + &tspi->tx_bb_phys, GFP_KERNEL); + if (!tspi->tx_bb) { + dev_err(&pdev->dev, "can not allocate tx bounce buffer\n"); + ret = -ENOMEM; + goto err6; + } + + memset(&tspi->tx_dma_req, 0, sizeof(struct tegra_dma_req)) ; + tspi->tx_dma_req.complete = tegra_spi_tx_dma_complete; + tspi->tx_dma_req.to_memory = 0; + tspi->tx_dma_req.dest_addr = tspi->phys + SLINK_TX_FIFO; + tspi->tx_dma_req.virt_addr = tspi->tx_bb ; + tspi->tx_dma_req.dest_bus_width = 32; + tspi->tx_dma_req.dest_wrap = 4; + tspi->tx_dma_req.source_wrap = 0 ; + tspi->tx_dma_req.source_addr = tspi->tx_bb_phys; + tspi->tx_dma_req.source_bus_width = 32; + tspi->tx_dma_req.req_sel = spi_tegra_req_sels[pdev->id]; + tspi->tx_dma_req.dev = tspi; + + ret = spi_register_master(master); + if (ret < 0) + goto err7; + + return ret; + +err7: + dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + tspi->tx_bb, tspi->tx_bb_phys); +err6: + tegra_dma_free_channel(tspi->tx_dma); +err5: + dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + tspi->rx_bb, tspi->rx_bb_phys); +err4: + tegra_dma_free_channel(tspi->rx_dma); +err3: + clk_put(tspi->clk); +err2: + iounmap(tspi->base); +err1: + release_mem_region(r->start, (r->end - r->start) + 1); +err0: + spi_master_put(master); + return ret; +} + +static int __devexit spi_tegra_remove(struct platform_device *pdev) +{ + struct spi_master *master; + struct spi_tegra_data *tspi; + struct resource *r; + + master = dev_get_drvdata(&pdev->dev); + tspi = spi_master_get_devdata(master); + + tegra_dma_free_channel(tspi->rx_dma); + + dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + tspi->rx_bb, tspi->rx_bb_phys); + + clk_put(tspi->clk); + iounmap(tspi->base); + + spi_master_put(master); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(r->start, (r->end - r->start) + 1); + + return 0; +} + +void spi_tegra_abort_transfer(struct spi_device *spi) +{ + struct spi_tegra_data *tspi = spi_master_get_devdata(spi->master); + struct spi_message *m; + unsigned long flags; + + spin_lock_irqsave(&tspi->lock, flags); + if (((tspi->rx_complete) != 0) || ((tspi->tx_complete) != 0)) + spin_unlock_irqrestore(&tspi->lock, flags); + + tspi->abort_happen = true; + spin_unlock_irqrestore(&tspi->lock, flags); + + m = list_first_entry(&tspi->queue, struct spi_message, queue); + m->status = -EIO; + + tegra_dma_dequeue(tspi->tx_dma); + tegra_dma_dequeue(tspi->rx_dma); +} +EXPORT_SYMBOL(spi_tegra_abort_transfer); + +#ifdef CONFIG_PM +static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct spi_master *master; + struct spi_tegra_data *tspi; + unsigned long flags; + unsigned limit = 50; + + master = dev_get_drvdata(&pdev->dev); + tspi = spi_master_get_devdata(master); + spin_lock_irqsave(&tspi->lock, flags); + tspi->is_suspended = true; + WARN_ON(!list_empty(&tspi->queue)); + + while (!list_empty(&tspi->queue) && limit--) { + spin_unlock_irqrestore(&tspi->lock, flags); + msleep(10); + spin_lock_irqsave(&tspi->lock, flags); + } + + tspi->save_slink_cmd = spi_tegra_readl(tspi, SLINK_COMMAND); + spin_unlock_irqrestore(&tspi->lock, flags); + return 0; +} + +static int spi_tegra_resume(struct platform_device *pdev) +{ + struct spi_master *master; + struct spi_tegra_data *tspi; + unsigned long flags; + + master = dev_get_drvdata(&pdev->dev); + tspi = spi_master_get_devdata(master); + spin_lock_irqsave(&tspi->lock, flags); + clk_enable(tspi->clk); + spi_tegra_writel(tspi, tspi->save_slink_cmd, SLINK_COMMAND); + clk_disable(tspi->clk); + tspi->cur_speed = 0; + tspi->is_suspended = false; + spin_unlock_irqrestore(&tspi->lock, flags); + return 0; +} +#endif + +MODULE_ALIAS("platform:tegra_spi_slave"); + +static struct platform_driver spi_tegra_driver = { + .driver = { + .name = "tegra_spi_slave", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(spi_tegra_remove), +#ifdef CONFIG_PM + .suspend = spi_tegra_suspend, + .resume = spi_tegra_resume, +#endif +}; + +static int __init spi_tegra_init(void) +{ + return platform_driver_probe(&spi_tegra_driver, spi_tegra_probe); +} +module_init(spi_tegra_init); + +static void __exit spi_tegra_exit(void) +{ + platform_driver_unregister(&spi_tegra_driver); +} +module_exit(spi_tegra_exit); + +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-tegra/syncpt.c b/arch/arm/mach-tegra/syncpt.c new file mode 100644 index 000000000000..bb649a9fe51a --- /dev/null +++ b/arch/arm/mach-tegra/syncpt.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Erik Gilling <konkers@google.com> + * + * Copyright (C) 2010, NVIDIA Corporation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <mach/iomap.h> +#include <mach/irqs.h> + +#define HOST1X_SYNC_OFFSET 0x3000 +#define HOST1X_SYNC_SIZE 0x800 +enum { + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS = 0x40, + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE = 0x60 +}; + +static void syncpt_thresh_mask(unsigned int irq) +{ + (void)irq; +} + +static void syncpt_thresh_unmask(unsigned int irq) +{ + (void)irq; +} + +static void syncpt_thresh_cascade(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *sync_regs = get_irq_desc_data(desc); + u32 reg; + int id; + + desc->chip->ack(irq); + + reg = readl(sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS); + + while ((id = __fls(reg)) >= 0) { + reg ^= BIT(id); + generic_handle_irq(id + INT_SYNCPT_THRESH_BASE); + } + + desc->chip->unmask(irq); +} + +static struct irq_chip syncpt_thresh_irq = { + .name = "syncpt", + .mask = syncpt_thresh_mask, + .unmask = syncpt_thresh_unmask +}; + +static int __init syncpt_init_irq(void) +{ + void __iomem *sync_regs; + unsigned int i; + int irq; + + sync_regs = ioremap(TEGRA_HOST1X_BASE + HOST1X_SYNC_OFFSET, + HOST1X_SYNC_SIZE); + BUG_ON(!sync_regs); + + writel(0xffffffffUL, + sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE); + writel(0xffffffffUL, + sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS); + + for (i = 0; i < INT_SYNCPT_THRESH_NR; i++) { + irq = INT_SYNCPT_THRESH_BASE + i; + set_irq_chip(irq, &syncpt_thresh_irq); + set_irq_chip_data(irq, sync_regs); + set_irq_handler(irq, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + } + if (set_irq_data(INT_HOST1X_MPCORE_SYNCPT, sync_regs)) + BUG(); + set_irq_chained_handler(INT_HOST1X_MPCORE_SYNCPT, + syncpt_thresh_cascade); + + return 0; +} + +core_initcall(syncpt_init_irq); diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 3625b8091c76..f5334151d97a 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -1930,6 +1930,7 @@ static struct clk tegra_clk_emc = { struct clk tegra_list_clks[] = { PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET), + PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET), PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0), PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c index b58a7d2ef92d..645b10bf2625 100644 --- a/arch/arm/mach-tegra/tegra2_dvfs.c +++ b/arch/arm/mach-tegra/tegra2_dvfs.c @@ -40,16 +40,20 @@ static bool tegra_dvfs_cpu_disabled = true; static const int core_millivolts[MAX_DVFS_FREQS] = {950, 1000, 1100, 1200, 1275}; static const int cpu_millivolts[MAX_DVFS_FREQS] = - {750, 775, 800, 825, 875, 900, 925, 975, 1000, 1050, 1100}; + {750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1100, 1125}; + +static const int cpu_speedo_nominal_millivolts[] = +/* spedo_id 0, 1, 2 */ + { 1100, 1025, 1125 }; #define KHZ 1000 #define MHZ 1000000 static struct dvfs_rail tegra2_dvfs_rail_vdd_cpu = { .reg_id = "vdd_cpu", - .max_millivolts = 1100, + .max_millivolts = 1125, .min_millivolts = 750, - .nominal_millivolts = 1100, + .nominal_millivolts = 1125, }; static struct dvfs_rail tegra2_dvfs_rail_vdd_core = { @@ -120,10 +124,11 @@ static struct dvfs_rail *tegra2_dvfs_rails[] = { &tegra2_dvfs_rail_vdd_aon, }; -#define CPU_DVFS(_clk_name, _process_id, _mult, _freqs...) \ +#define CPU_DVFS(_clk_name, _speedo_id, _process_id, _mult, _freqs...) \ { \ .clk_name = _clk_name, \ - .cpu_process_id = _process_id, \ + .speedo_id = _speedo_id, \ + .process_id = _process_id, \ .freqs = {_freqs}, \ .freqs_mult = _mult, \ .millivolts = cpu_millivolts, \ @@ -134,7 +139,8 @@ static struct dvfs_rail *tegra2_dvfs_rails[] = { #define CORE_DVFS(_clk_name, _auto, _mult, _freqs...) \ { \ .clk_name = _clk_name, \ - .cpu_process_id = -1, \ + .speedo_id = -1, \ + .process_id = -1, \ .freqs = {_freqs}, \ .freqs_mult = _mult, \ .millivolts = core_millivolts, \ @@ -143,11 +149,21 @@ static struct dvfs_rail *tegra2_dvfs_rails[] = { } static struct dvfs dvfs_init[] = { - /* Cpu voltages (mV): 750, 775, 800, 825, 875, 900, 925, 975, 1000, 1050, 1100 */ - CPU_DVFS("cpu", 0, MHZ, 314, 314, 314, 456, 456, 608, 608, 760, 817, 912, 1000), - CPU_DVFS("cpu", 1, MHZ, 314, 314, 314, 456, 456, 618, 618, 770, 827, 922, 1000), - CPU_DVFS("cpu", 2, MHZ, 494, 675, 675, 675, 817, 817, 922, 1000), - CPU_DVFS("cpu", 3, MHZ, 730, 760, 845, 845, 1000), + /* Cpu voltages (mV): 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1100, 1125 */ + CPU_DVFS("cpu", 0, 0, MHZ, 314, 314, 314, 456, 456, 456, 608, 608, 608, 760, 817, 817, 912, 1000), + CPU_DVFS("cpu", 0, 1, MHZ, 314, 314, 314, 456, 456, 456, 618, 618, 618, 770, 827, 827, 922, 1000), + CPU_DVFS("cpu", 0, 2, MHZ, 494, 494, 494, 675, 675, 817, 817, 922, 922, 1000), + CPU_DVFS("cpu", 0, 3, MHZ, 730, 760, 845, 845, 940, 1000), + + CPU_DVFS("cpu", 1, 0, MHZ, 380, 380, 503, 503, 655, 655, 798, 798, 902, 902, 960, 1000), + CPU_DVFS("cpu", 1, 1, MHZ, 389, 389, 503, 503, 655, 760, 798, 798, 950, 950, 1000), + CPU_DVFS("cpu", 1, 2, MHZ, 598, 598, 750, 750, 893, 893, 1000), + CPU_DVFS("cpu", 1, 3, MHZ, 730, 760, 845, 845, 940, 1000), + + CPU_DVFS("cpu", 2, 0, MHZ, 0, 0, 0, 0, 655, 655, 798, 798, 902, 902, 960, 1000, 1100, 1100, 1200), + CPU_DVFS("cpu", 2, 1, MHZ, 0, 0, 0, 0, 655, 760, 798, 798, 950, 950, 1015, 1015, 1100, 1200), + CPU_DVFS("cpu", 2, 2, MHZ, 0, 0, 0, 0, 769, 769, 902, 902, 1026, 1026, 1140, 1140, 1200), + CPU_DVFS("cpu", 2, 3, MHZ, 0, 0, 0, 0, 940, 1000, 1000, 1000, 1130, 1130, 1200), /* Core voltages (mV): 950, 1000, 1100, 1200, 1275 */ CORE_DVFS("emc", 1, KHZ, 57000, 333000, 333000, 666000, 666000), @@ -259,8 +275,15 @@ void __init tegra2_init_dvfs(void) int i; struct clk *c; struct dvfs *d; + int process_id; int ret; int cpu_process_id = tegra_cpu_process_id(); + int core_process_id = tegra_core_process_id(); + int speedo_id = tegra_soc_speedo_id(); + + BUG_ON(speedo_id >= ARRAY_SIZE(cpu_speedo_nominal_millivolts)); + tegra2_dvfs_rail_vdd_cpu.nominal_millivolts = + cpu_speedo_nominal_millivolts[speedo_id]; tegra_dvfs_init_rails(tegra2_dvfs_rails, ARRAY_SIZE(tegra2_dvfs_rails)); tegra_dvfs_add_relationships(tegra2_dvfs_relationships, @@ -272,9 +295,15 @@ void __init tegra2_init_dvfs(void) for (i = 0; i < ARRAY_SIZE(dvfs_init); i++) { d = &dvfs_init[i]; - if (d->cpu_process_id != -1 && - d->cpu_process_id != cpu_process_id) + process_id = strcmp(d->clk_name, "cpu") ? + core_process_id : cpu_process_id; + if ((d->process_id != -1 && d->process_id != process_id) || + (d->speedo_id != -1 && d->speedo_id != speedo_id)) { + pr_debug("tegra_dvfs: rejected %s speedo %d," + " process %d\n", d->clk_name, d->speedo_id, + d->process_id); continue; + } c = tegra_get_clock_by_name(d->clk_name); diff --git a/arch/arm/mach-tegra/tegra2_i2s.c b/arch/arm/mach-tegra/tegra2_i2s.c new file mode 100644 index 000000000000..74049c5d3b67 --- /dev/null +++ b/arch/arm/mach-tegra/tegra2_i2s.c @@ -0,0 +1,392 @@ +/* + * arch/arm/mach-tegra/tegra2_i2s.c + * + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Iliyan Malchev <malchev@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/err.h> + +#include "clock.h" +#include <asm/io.h> +#include <mach/iomap.h> +#include <mach/tegra2_i2s.h> + + +#define NR_I2S_IFC 2 + +#define check_ifc(n, ...) if ((n) > NR_I2S_IFC) { \ + pr_err("%s: invalid i2s interface %d\n", __func__, (n)); \ + return __VA_ARGS__; \ +} + +static phys_addr_t i2s_phy_base[NR_I2S_IFC] = { + TEGRA_I2S1_BASE, + TEGRA_I2S2_BASE, +}; + +static void *i2s_base[NR_I2S_IFC] = { + IO_ADDRESS(TEGRA_I2S1_BASE), + IO_ADDRESS(TEGRA_I2S2_BASE), +}; + +static inline void i2s_writel(int ifc, u32 val, u32 reg) +{ + __raw_writel(val, i2s_base[ifc] + reg); +} + +static inline u32 i2s_readl(int ifc, u32 reg) +{ + return __raw_readl(i2s_base[ifc] + reg); +} + +void i2s_dump_registers(int ifc) +{ + check_ifc(ifc); + + pr_info("%s: CTRL %08x\n", __func__, + i2s_readl(ifc, I2S_I2S_CTRL_0)); + pr_info("%s: STATUS %08x\n", __func__, + i2s_readl(ifc, I2S_I2S_STATUS_0)); + pr_info("%s: TIMING %08x\n", __func__, + i2s_readl(ifc, I2S_I2S_TIMING_0)); + pr_info("%s: SCR %08x\n", __func__, + i2s_readl(ifc, I2S_I2S_FIFO_SCR_0)); + pr_info("%s: FIFO1 %08x\n", __func__, + i2s_readl(ifc, I2S_I2S_FIFO1_0)); + pr_info("%s: FIFO2 %08x\n", __func__, + i2s_readl(ifc, I2S_I2S_FIFO1_0)); +} + +int i2s_set_channel_bit_count(int ifc, int sampling, int bitclk) +{ + u32 val; + int bitcnt; + + check_ifc(ifc, -EINVAL); + + bitcnt = bitclk / (2 * sampling) - 1; + + if (bitcnt < 0 || bitcnt >= 1<<11) { + pr_err("%s: bit count %d is out of bounds\n", __func__, + bitcnt); + return -EINVAL; + } + + val = bitcnt; + if (bitclk % (2 * sampling)) { + pr_info("%s: enabling non-symmetric mode\n", __func__); + val |= I2S_I2S_TIMING_NON_SYM_ENABLE; + } + + i2s_writel(ifc, val, I2S_I2S_TIMING_0); + return 0; +} + +void i2s_set_fifo_mode(int ifc, int fifo, int tx) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + if (fifo == 0) { + val &= ~I2S_I2S_CTRL_FIFO1_RX_ENABLE; + val |= (!tx) ? I2S_I2S_CTRL_FIFO1_RX_ENABLE : 0; + } + else { + val &= ~I2S_I2S_CTRL_FIFO2_TX_ENABLE; + val |= tx ? I2S_I2S_CTRL_FIFO2_TX_ENABLE : 0; + } + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +void i2s_set_loopback(int ifc, int on) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + val &= ~I2S_I2S_CTRL_FIFO_LPBK_ENABLE; + val |= on ? I2S_I2S_CTRL_FIFO_LPBK_ENABLE : 0; + + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +int i2s_fifo_set_attention_level(int ifc, int fifo, unsigned level) +{ + u32 val; + + check_ifc(ifc, -EINVAL); + + if (level > I2S_FIFO_ATN_LVL_TWELVE_SLOTS) { + pr_err("%s: invalid fifo level selector %d\n", __func__, + level); + return -EINVAL; + } + + val = i2s_readl(ifc, I2S_I2S_FIFO_SCR_0); + + if (!fifo) { + val &= ~I2S_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK; + val |= level << I2S_FIFO1_ATN_LVL_SHIFT; + } + else { + val &= ~I2S_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK; + val |= level << I2S_FIFO2_ATN_LVL_SHIFT; + } + + i2s_writel(ifc, val, I2S_I2S_FIFO_SCR_0); + return 0; +} + +void i2s_fifo_enable(int ifc, int fifo, int on) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + if (!fifo) { + val &= ~I2S_I2S_CTRL_FIFO1_ENABLE; + val |= on ? I2S_I2S_CTRL_FIFO1_ENABLE : 0; + } + else { + val &= ~I2S_I2S_CTRL_FIFO2_ENABLE; + val |= on ? I2S_I2S_CTRL_FIFO2_ENABLE : 0; + } + + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +void i2s_fifo_clear(int ifc, int fifo) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_FIFO_SCR_0); + if (!fifo) { + val &= ~I2S_I2S_FIFO_SCR_FIFO1_CLR; + val |= I2S_I2S_FIFO_SCR_FIFO1_CLR; + } + else { + val &= ~I2S_I2S_FIFO_SCR_FIFO2_CLR; + val |= I2S_I2S_FIFO_SCR_FIFO2_CLR; + } + + i2s_writel(ifc, val, I2S_I2S_FIFO_SCR_0); +} + +void i2s_set_master(int ifc, int master) +{ + u32 val; + check_ifc(ifc); + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + val &= ~I2S_I2S_CTRL_MASTER_ENABLE; + val |= master ? I2S_I2S_CTRL_MASTER_ENABLE : 0; + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +int i2s_set_bit_format(int ifc, unsigned fmt) +{ + u32 val; + + check_ifc(ifc, -EINVAL); + + if (fmt > I2S_BIT_FORMAT_DSP) { + pr_err("%s: invalid bit-format selector %d\n", __func__, fmt); + return -EINVAL; + } + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + val &= ~I2S_I2S_CTRL_BIT_FORMAT_MASK; + val |= fmt << I2S_BIT_FORMAT_SHIFT; + + i2s_writel(ifc, val, I2S_I2S_CTRL_0); + return 0; +} + +int i2s_set_bit_size(int ifc, unsigned bit_size) +{ + u32 val; + + check_ifc(ifc, -EINVAL); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + val &= ~I2S_I2S_CTRL_BIT_SIZE_MASK; + + if (bit_size > I2S_BIT_SIZE_32) { + pr_err("%s: invalid bit_size selector %d\n", __func__, + bit_size); + return -EINVAL; + } + + val |= bit_size << I2S_BIT_SIZE_SHIFT; + + i2s_writel(ifc, val, I2S_I2S_CTRL_0); + return 0; +} + +int i2s_set_fifo_format(int ifc, unsigned fmt) +{ + u32 val; + + check_ifc(ifc, -EINVAL); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + val &= ~I2S_I2S_CTRL_FIFO_FORMAT_MASK; + + if (fmt > I2S_FIFO_32 && fmt != I2S_FIFO_PACKED) { + pr_err("%s: invalid fmt selector %d\n", __func__, fmt); + return -EINVAL; + } + + val |= fmt << I2S_FIFO_SHIFT; + + i2s_writel(ifc, val, I2S_I2S_CTRL_0); + return 0; +} + +void i2s_set_left_right_control_polarity(int ifc, int high_low) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + val &= ~I2S_I2S_CTRL_L_R_CTRL; + val |= high_low ? I2S_I2S_CTRL_L_R_CTRL : 0; + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +void i2s_set_fifo_irq_on_err(int ifc, int fifo, int on) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + if (!fifo) { + val &= ~I2S_I2S_IE_FIFO1_ERR; + val |= on ? I2S_I2S_IE_FIFO1_ERR : 0; + } + else { + val &= ~I2S_I2S_IE_FIFO2_ERR; + val |= on ? I2S_I2S_IE_FIFO2_ERR : 0; + } + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +void i2s_set_fifo_irq_on_qe(int ifc, int fifo, int on) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + if (!fifo) { + val &= ~I2S_I2S_QE_FIFO1; + val |= on ? I2S_I2S_QE_FIFO1 : 0; + } + else { + val &= ~I2S_I2S_QE_FIFO2; + val |= on ? I2S_I2S_QE_FIFO2 : 0; + } + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +void i2s_enable_fifos(int ifc, int on) +{ + u32 val; + + check_ifc(ifc); + + val = i2s_readl(ifc, I2S_I2S_CTRL_0); + if (on) + val |= I2S_I2S_QE_FIFO1 | I2S_I2S_QE_FIFO2 | + I2S_I2S_IE_FIFO1_ERR | I2S_I2S_IE_FIFO2_ERR; + else + val &= ~(I2S_I2S_QE_FIFO1 | I2S_I2S_QE_FIFO2 | + I2S_I2S_IE_FIFO1_ERR | I2S_I2S_IE_FIFO2_ERR); + + i2s_writel(ifc, val, I2S_I2S_CTRL_0); +} + +void i2s_fifo_write(int ifc, int fifo, u32 data) +{ + check_ifc(ifc); + i2s_writel(ifc, data, fifo ? I2S_I2S_FIFO2_0 : I2S_I2S_FIFO1_0); +} + +u32 i2s_fifo_read(int ifc, int fifo) +{ + check_ifc(ifc, 0); + return i2s_readl(ifc, fifo ? I2S_I2S_FIFO2_0 : I2S_I2S_FIFO1_0); +} + +u32 i2s_get_status(int ifc) +{ + check_ifc(ifc, 0); + return i2s_readl(ifc, I2S_I2S_STATUS_0); +} + +u32 i2s_get_control(int ifc) +{ + check_ifc(ifc, 0); + return i2s_readl(ifc, I2S_I2S_CTRL_0); +} + +void i2s_ack_status(int ifc) +{ + check_ifc(ifc); + return i2s_writel(ifc, i2s_readl(ifc, I2S_I2S_STATUS_0), I2S_I2S_STATUS_0); +} + +u32 i2s_get_fifo_scr(int ifc) +{ + check_ifc(ifc, 0); + return i2s_readl(ifc, I2S_I2S_FIFO_SCR_0); +} + +phys_addr_t i2s_get_fifo_phy_base(int ifc, int fifo) +{ + check_ifc(ifc, 0); + return i2s_phy_base[ifc] + (fifo ? I2S_I2S_FIFO2_0 : I2S_I2S_FIFO1_0); +} + +u32 i2s_get_fifo_full_empty_count(int ifc, int fifo) +{ + u32 val; + + check_ifc(ifc, 0); + + val = i2s_readl(ifc, I2S_I2S_FIFO_SCR_0); + + if (!fifo) + val = val >> I2S_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT; + else + val = val >> I2S_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT; + + return val & I2S_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK; +} + + +struct clk *i2s_get_clock_by_name(const char *name) +{ + return tegra_get_clock_by_name(name); +} diff --git a/arch/arm/mach-tegra/tegra2_speedo.c b/arch/arm/mach-tegra/tegra2_speedo.c new file mode 100644 index 000000000000..1e5fa26a5c41 --- /dev/null +++ b/arch/arm/mach-tegra/tegra2_speedo.c @@ -0,0 +1,140 @@ +/* + * arch/arm/mach-tegra/tegra2_speedo.c + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/err.h> + +#include <mach/iomap.h> + +#include "fuse.h" + +#define CPU_SPEEDO_LSBIT 20 +#define CPU_SPEEDO_MSBIT 29 +#define CPU_SPEEDO_REDUND_LSBIT 30 +#define CPU_SPEEDO_REDUND_MSBIT 39 +#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) + +#define CORE_SPEEDO_LSBIT 40 +#define CORE_SPEEDO_MSBIT 47 +#define CORE_SPEEDO_REDUND_LSBIT 48 +#define CORE_SPEEDO_REDUND_MSBIT 55 +#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) + +#define SPEEDO_MULT 4 + +#define CHIP_ID 0x804 +#define CHIP_MINOR_SHIFT 16 +#define CHIP_MINOR_MASK (0xF << CHIP_MINOR_SHIFT) + +#define PROCESS_CORNERS_NUM 4 + +#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2) +#define SPEEDO_ID_SELECT_1(sku) \ + (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ + ((sku) != 27) && ((sku) != 28)) + +/* Maximum speedo levels for each CPU process corner */ +static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { +/* proc_id 0 1 2 3 */ + {315, 366, 420, UINT_MAX}, /* speedo_id 0 */ + {303, 368, 419, UINT_MAX}, /* speedo_id 1 */ + {316, 331, 383, UINT_MAX}, /* speedo_id 2 */ +}; + +/* Maximum speedo levels for each core process corner */ +static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { +/* proc_id 0 1 2 3 */ + {165, 195, 224, UINT_MAX}, /* speedo_id 0 */ + {165, 195, 224, UINT_MAX}, /* speedo_id 1 */ + {165, 195, 224, UINT_MAX}, /* speedo_id 2 */ +}; + +static int cpu_process_id; +static int core_process_id; +static int soc_speedo_id; + +void tegra_init_speedo_data(void) +{ + u32 reg, val; + int i, bit, rev; + int sku = tegra_sku_id(); + void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE); + + reg = readl(apb_misc + CHIP_ID); + rev = (reg & CHIP_MINOR_MASK) >> CHIP_MINOR_SHIFT; + if (SPEEDO_ID_SELECT_0(rev)) + soc_speedo_id = 0; + else if (SPEEDO_ID_SELECT_1(sku)) + soc_speedo_id = 1; + else + soc_speedo_id = 2; + BUG_ON(soc_speedo_id >= ARRAY_SIZE(cpu_process_speedos)); + BUG_ON(soc_speedo_id >= ARRAY_SIZE(core_process_speedos)); + + val = 0; + for (bit = CPU_SPEEDO_MSBIT; bit >= CPU_SPEEDO_LSBIT; bit--) { + reg = tegra_spare_fuse(bit) | + tegra_spare_fuse(bit + CPU_SPEEDO_REDUND_OFFS); + val = (val << 1) | (reg & 0x1); + } + val = val * SPEEDO_MULT; + pr_debug("%s CPU speedo level %u\n", __func__, val); + + for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { + if (val <= cpu_process_speedos[soc_speedo_id][i]) + break; + } + cpu_process_id = i; + + val = 0; + for (bit = CORE_SPEEDO_MSBIT; bit >= CORE_SPEEDO_LSBIT; bit--) { + reg = tegra_spare_fuse(bit) | + tegra_spare_fuse(bit + CORE_SPEEDO_REDUND_OFFS); + val = (val << 1) | (reg & 0x1); + } + val = val * SPEEDO_MULT; + pr_debug("%s Core speedo level %u\n", __func__, val); + + for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { + if (val <= core_process_speedos[soc_speedo_id][i]) + break; + } + core_process_id = i; + + pr_info("Tegra SKU: %d Rev: A%.2d CPU Process: %d Core Process: %d" + " Speedo ID: %d\n", sku, rev, cpu_process_id, core_process_id, + soc_speedo_id); +} + +int tegra_cpu_process_id(void) +{ + return cpu_process_id; +} + +int tegra_core_process_id(void) +{ + return core_process_id; +} + +int tegra_soc_speedo_id(void) +{ + return soc_speedo_id; +} diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 26605d9c2c0f..e7929aed1025 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -28,6 +28,8 @@ #include <asm/mach-types.h> #include <mach/usb_phy.h> #include <mach/iomap.h> +#include <mach/pinmux.h> +#include "gpio-names.h" #define USB_USBSTS 0x144 #define USB_USBSTS_PCI (1 << 2) @@ -333,6 +335,7 @@ static void utmi_phy_power_on(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; + int gpio_status; struct tegra_utmip_config *config = phy->config; val = readl(base + USB_SUSP_CTRL); @@ -433,6 +436,21 @@ static void utmi_phy_power_on(struct tegra_usb_phy *phy) val = readl(base + USB_SUSP_CTRL); val &= ~USB_SUSP_SET; writel(val, base + USB_SUSP_CTRL); + if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { + gpio_status = gpio_request(TEGRA_GPIO_PD0,"VBUS_BUS"); + if (gpio_status < 0) { + printk("VBUS_USB1 request GPIO FAILED\n"); + WARN_ON(1); + } + tegra_gpio_enable(TEGRA_GPIO_PD0); + gpio_status = gpio_direction_output(TEGRA_GPIO_PD0, 1); + if (gpio_status < 0) { + printk("VBUS_USB1 request GPIO DIRECTION FAILED \n"); + WARN_ON(1); + } + gpio_set_value(TEGRA_GPIO_PD0, 1); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL); + } } utmi_phy_clk_enable(phy); @@ -451,6 +469,11 @@ static void utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_clk_disable(phy); + if (phy->instance == 0 && phy->mode == TEGRA_USB_PHY_MODE_HOST) { + gpio_free(TEGRA_GPIO_PD0); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE); + } + if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { val = readl(base + USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 598c51ad5071..b8061519ce77 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -73,7 +73,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from, { void *kto = kmap_atomic(to, KM_USER1); - if (test_and_clear_bit(PG_dcache_dirty, &from->flags)) + if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); spin_lock(&minicache_lock); diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index f55fa1044f72..bdba6c65c901 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -79,7 +79,7 @@ static void v6_copy_user_highpage_aliasing(struct page *to, unsigned int offset = CACHE_COLOUR(vaddr); unsigned long kfrom, kto; - if (test_and_clear_bit(PG_dcache_dirty, &from->flags)) + if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); /* FIXME: not highmem safe */ diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 9920c0ae2096..649bbcd325bf 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -95,7 +95,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from, { void *kto = kmap_atomic(to, KM_USER1); - if (test_and_clear_bit(PG_dcache_dirty, &from->flags)) + if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); spin_lock(&minicache_lock); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 4bc43e535d3b..16df5767ff78 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -523,6 +523,12 @@ void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, outer_inv_range(paddr, paddr + size); dma_cache_maint_page(page, off, size, dir, dmac_unmap_area); + + /* + * Mark the D-cache clean for this page to avoid extra flushing. + */ + if (dir != DMA_TO_DEVICE) + set_bit(PG_dcache_clean, &page->flags); } EXPORT_SYMBOL(___dma_page_dev_to_cpu); diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 74e71052da12..33486f952d63 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -28,6 +28,7 @@ static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; +#ifndef CONFIG_SMP /* * We take the easy way out of this problem - we make the * PTE uncacheable. However, we leave the write buffer on. @@ -165,7 +166,7 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, * a page table, or changing an existing PTE. Basically, there are two * things that we need to take care of: * - * 1. If PG_dcache_dirty is set for the page, we need to ensure + * 1. If PG_dcache_clean is not set for the page, we need to ensure * that any cache entries for the kernels virtual memory * range are written back to the page. * 2. If we have multiple shared mappings of the same space in @@ -192,7 +193,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, return; mapping = page_mapping(page); - if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) __flush_dcache_page(mapping, page); if (mapping) { if (cache_is_vivt()) @@ -201,6 +202,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, __flush_icache_all(); } } +#endif /* !CONFIG_SMP */ /* * Check whether the write buffer has physical address aliasing diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index e0758968e9f8..7fe64b25dc5a 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -94,12 +94,10 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig #define flush_pfn_alias(pfn,vaddr) do { } while (0) #endif -#ifdef CONFIG_SMP static void flush_ptrace_access_other(void *args) { __flush_icache_all(); } -#endif static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, @@ -123,11 +121,9 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, if (vma->vm_flags & VM_EXEC) { unsigned long addr = (unsigned long)kaddr; __cpuc_coherent_kern_range(addr, addr + len); -#ifdef CONFIG_SMP if (cache_ops_need_broadcast()) smp_call_function(flush_ptrace_access_other, NULL, 1); -#endif } } @@ -216,6 +212,21 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p flush_dcache_mmap_unlock(mapping); } +#ifdef CONFIG_SMP +void __sync_icache_dcache(pte_t pteval) +{ + unsigned long pfn = pte_pfn(pteval); + + if (pfn_valid(pfn) && pte_present_exec_user(pteval)) { + struct page *page = pfn_to_page(pfn); + + if (!test_and_set_bit(PG_dcache_clean, &page->flags)) + __flush_dcache_page(NULL, page); + __flush_icache_all(); + } +} +#endif + /* * Ensure cache coherency between kernel mapping and userspace mapping * of this page. @@ -248,14 +259,15 @@ void flush_dcache_page(struct page *page) mapping = page_mapping(page); if (!cache_ops_need_broadcast() && - !PageHighMem(page) && mapping && !mapping_mapped(mapping)) - set_bit(PG_dcache_dirty, &page->flags); + mapping && !mapping_mapped(mapping)) + clear_bit(PG_dcache_clean, &page->flags); else { __flush_dcache_page(mapping, page); if (mapping && cache_is_vivt()) __flush_dcache_aliases(mapping, page); else if (mapping) __flush_icache_all(); + set_bit(PG_dcache_clean, &page->flags); } } EXPORT_SYMBOL(flush_dcache_page); diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 55590a4d87c9..e640a4478e76 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -3044,3 +3044,4 @@ harvest_desoto MACH_HARVEST_DESOTO HARVEST_DESOTO 3059 msm8x60_qrdc MACH_MSM8X60_QRDC MSM8X60_QRDC 3060 spear900 MACH_SPEAR900 SPEAR900 3061 pcontrol_g20 MACH_PCONTROL_G20 PCONTROL_G20 3062 +whistler MACH_WHISTLER WHISTLER 3241
\ No newline at end of file diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 97499d00615a..b3005f725a3a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -691,6 +691,18 @@ config SENSORS_MAX6650 This driver can also be built as a module. If so, the module will be called max6650. +config SENSORS_NCT1008_I2C + tristate "OnSemi NCT1008 Temperature Monitor chip" + depends on I2C + help + If you say yes here you get access to the temperature monitoring + functions of the OnSemi NCT1008 temperature monitor chip. + The NCT1008 can be used to measure the ambient temperature and control + the fan accordingly. + + This driver can also be built as a module. If so, the module + will be called nct1008. + config SENSORS_PC87360 tristate "National Semiconductor PC87360 family" select HWMON_VID diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index e3c2484f6c5f..7f281e112c7d 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_SENSORS_MAX1111) += max1111.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o +obj-$(CONFIG_SENSORS_NCT1008_I2C)+= nct1008.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o diff --git a/drivers/hwmon/nct1008.c b/drivers/hwmon/nct1008.c new file mode 100644 index 000000000000..bc82da400035 --- /dev/null +++ b/drivers/hwmon/nct1008.c @@ -0,0 +1,271 @@ +/* + * drivers/hwmon/nct1008.c + * + * Temperature Sensor driver for NCT1008 Temperature Monitor chip + * manufactured by ON Semiconductors (www.onsemi.com). + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/i2c/nct1008.h> +#include <linux/hwmon.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/miscdevice.h> +#include <linux/fs.h> +#include <linux/delay.h> + +#define NCT1008_LOCAL_TEMP_RD 0x00 +#define NCT1008_CONFIG_RD 0x03 +#define NCT1008_MFR_ID_RD 0xFE + +#define NCT1008_CONFIG_WR 0x09 +#define NCT1008_CONV_RATE_WR 0x0A +#define NCT1008_OFFSET_WR 0x11 +#define NCT1008_LOCAL_THERM_LIMIT_WR 0x20 + +#define DRIVER_NAME "nct1008" + +struct nct1008_data { + struct device *hwmon_dev; + struct i2c_client *client; + struct nct1008_platform_data plat_data; +}; + +static ssize_t nct1008_show_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + signed int temp_value = 0; + u8 data = 0; + + if (!dev || !buf || !attr) + return -EINVAL; + + data = i2c_smbus_read_byte_data(client, NCT1008_LOCAL_TEMP_RD); + if (data < 0) { + dev_err(&client->dev, "%s: failed to read " + "temperature\n", __func__); + return -EINVAL; + } + + temp_value = (signed int)data; + return sprintf(buf, "%d\n", temp_value); +} + +static DEVICE_ATTR(temperature, S_IRUGO, nct1008_show_temp, NULL); + +static struct attribute *nct1008_attributes[] = { + &dev_attr_temperature.attr, + NULL +}; + +static const struct attribute_group nct1008_attr_group = { + .attrs = nct1008_attributes, +}; + +static int __devinit nct1008_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct nct1008_data *pdata; + int err; + u8 data = 0; + + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL, exiting\n"); + return -ENODEV; + } + + pdata = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "%s: failed to allocate " + "device\n", __func__); + return -ENOMEM; + } + + pdata->client = client; + i2c_set_clientdata(client, pdata); + + memcpy(&pdata->plat_data, client->dev.platform_data, + sizeof(struct nct1008_platform_data)); + + data = i2c_smbus_read_byte_data(client, NCT1008_MFR_ID_RD); + if (data < 0) { + dev_err(&client->dev, "%s: failed to read manufacturer " + "id\n", __func__); + err = data; + goto fail_alloc; + } + dev_info(&client->dev, "%s:0x%x chip found\n", client->name, data); + + /* set conversion rate (conv/sec) */ + data = pdata->plat_data.conv_rate; + err = i2c_smbus_write_byte_data(client, NCT1008_CONV_RATE_WR, data); + if (err < 0) { + dev_err(&client->dev, "%s: failed to set conversion " + "rate\n", __func__); + goto fail_alloc; + } + + /* set config params */ + data = pdata->plat_data.config; + err = i2c_smbus_write_byte_data(client, NCT1008_CONFIG_WR, data); + if (err < 0) { + dev_err(&client->dev, "%s: failed to set config\n", __func__); + goto fail_alloc; + } + + /* set offset value */ + data = pdata->plat_data.offset; + err = i2c_smbus_write_byte_data(client, NCT1008_OFFSET_WR, data); + if (err < 0) { + dev_err(&client->dev, + "%s: failed to set offset\n", __func__); + goto fail_alloc; + } + + /* set cpu shutdown threshold */ + data = pdata->plat_data.thermal_threshold; + err = i2c_smbus_write_byte_data(client, NCT1008_LOCAL_THERM_LIMIT_WR, data); + if (err < 0) { + dev_err(&client->dev, + "%s: failed to set THERM# limit\n", __func__); + goto fail_alloc; + } + + pdata->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(pdata->hwmon_dev)) { + err = PTR_ERR(pdata->hwmon_dev); + dev_err(&client->dev, "%s: hwmon_device_register " + "failed\n", __func__); + goto fail_alloc; + } + + /* register sysfs hooks */ + err = sysfs_create_group(&client->dev.kobj, &nct1008_attr_group); + if (err < 0) + goto fail_sys; + + dev_info(&client->dev, "%s: initialized\n", __func__); + return 0; + +fail_sys: + hwmon_device_unregister(pdata->hwmon_dev); +fail_alloc: + kfree(pdata); + return err; +} + +static int __devexit nct1008_remove(struct i2c_client *client) +{ + struct nct1008_data *pdata = i2c_get_clientdata(client); + + if (!pdata) + return -EINVAL; + + hwmon_device_unregister(pdata->hwmon_dev); + kfree(pdata); + return 0; +} + +#ifdef CONFIG_PM +static int nct1008_suspend(struct i2c_client *client, pm_message_t state) +{ + u8 config; + int err; + + config = i2c_smbus_read_byte_data(client, NCT1008_CONFIG_RD); + if (config < 0) { + dev_err(&client->dev, "%s: failed to read config\n", __func__); + return -EIO; + } + + /* take device to standby state */ + config |= NCT1008_CONFIG_RUN_STANDBY; + + err = i2c_smbus_write_byte_data(client, NCT1008_CONFIG_WR, config); + if (err < 0) { + dev_err(&client->dev, "%s: failed to set config\n", __func__); + return -EIO; + } + + return 0; +} + +static int nct1008_resume(struct i2c_client *client) +{ + u8 config = 0; + int err; + + config = i2c_smbus_read_byte_data(client, NCT1008_CONFIG_RD); + if (config < 0) { + dev_err(&client->dev, "%s: failed to read config\n", __func__); + return -EIO; + } + + /* take device out of standby state */ + config &= ~NCT1008_CONFIG_RUN_STANDBY; + + err = i2c_smbus_write_byte_data(client, NCT1008_CONFIG_WR, config); + if (err < 0) { + dev_err(&client->dev, "%s: failed to set config\n", __func__); + return -EIO; + } + return 0; +} +#endif + +static const struct i2c_device_id nct1008_id[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nct1008_id); + +static struct i2c_driver nct1008_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRIVER_NAME, + }, + .probe = nct1008_probe, + .remove = __devexit_p(nct1008_remove), + .id_table = nct1008_id, +#ifdef CONFIG_PM + .suspend = nct1008_suspend, + .resume = nct1008_resume, +#endif +}; + +static int __init nct1008_init(void) +{ + return i2c_add_driver(&nct1008_driver); +} + +static void __exit nct1008_exit(void) +{ + i2c_del_driver(&nct1008_driver); +} + +module_init (nct1008_init); +module_exit (nct1008_exit); + +#define DRIVER_DESC "NCT1008 temperature sensor driver" +#define DRIVER_LICENSE "GPL" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b7481f496ec3..b64d66d39852 100755..100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -360,10 +360,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) } if (unlikely(status & status_err)) { - if (status & I2C_INT_NO_ACK) + if (status & I2C_INT_NO_ACK) { i2c_dev->msg_err |= I2C_ERR_NO_ACK; - if (status & I2C_INT_ARBITRATION_LOST) + dev_warn(i2c_dev->dev, " no acknowledge\n"); + } + if (status & I2C_INT_ARBITRATION_LOST) { i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST; + dev_warn(i2c_dev->dev, " arbitration lost\n"); + } complete(&i2c_dev->msg_complete); goto err; } @@ -525,7 +529,7 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap) { /* FIXME: For now keep it simple and don't support protocol mangling features */ - return I2C_FUNC_I2C; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE; } static const struct i2c_algorithm tegra_i2c_algo = { diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index bea4c5021d26..6a3333efa9c2 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2015,8 +2015,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, } status = i2c_transfer(adapter, msg, num); - if (status < 0) - return status; + if (status != num) + return -EREMOTEIO; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 9cc488d21490..149a32fa8372 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -327,6 +327,13 @@ config KEYBOARD_NEWTON To compile this driver as a module, choose M here: the module will be called newtonkbd. +config KEYBOARD_TEGRA + boolean "NVIDIA Tegra internal matrix keyboard controller support" + depends on ARCH_TEGRA + help + Say Y here if you want to use a matrix keyboard connected directly + to the internal keyboard controller on Tegra SoCs + config KEYBOARD_OPENCORES tristate "OpenCores Keyboard Controller" help diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 504b591be0cd..2c7686eb90b4 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o +obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6069abe31e42..b80b5d8ac5bd 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -601,7 +601,10 @@ static int gpio_keys_resume(struct device *dev) struct gpio_keys_button *button = &pdata->buttons[i]; if (button->wakeup && device_may_wakeup(&pdev->dev)) { int irq = gpio_to_irq(button->gpio); + unsigned int type = button->type ?: EV_KEY; disable_irq_wake(irq); + input_event(ddata->input, type, button->code, 1); + input_sync(ddata->input); } gpio_keys_report_event(&ddata->data[i]); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c new file mode 100644 index 000000000000..4dad169fd3a4 --- /dev/null +++ b/drivers/input/keyboard/tegra-kbc.c @@ -0,0 +1,810 @@ +/* + * drivers/input/keyboard/tegra-kbc.c + * + * Keyboard class input driver for the NVIDIA Tegra SoC internal matrix + * keyboard controller + * + * Copyright (c) 2009-2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/kthread.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <mach/clk.h> +#include <mach/kbc.h> + +#define KBC_CONTROL_0 0 +#define KBC_INT_0 4 +#define KBC_ROW_CFG0_0 8 +#define KBC_COL_CFG0_0 0x18 +#define KBC_RPT_DLY_0 0x2c +#define KBC_KP_ENT0_0 0x30 +#define KBC_KP_ENT1_0 0x34 +#define KBC_ROW0_MASK_0 0x38 + +#define DEBUG_MSG(m) printk(m) + +#define res_size(res) ((res)->end - (res)->start + 1) + +struct tegra_kbc { + void __iomem *mmio; + struct input_dev *idev; + int irq; + unsigned int wake_enable_rows; + unsigned int wake_enable_cols; + spinlock_t lock; + unsigned int repoll_time; + struct tegra_kbc_platform_data *pdata; + int *plain_keycode; + int *fn_keycode; + struct work_struct key_repeat; + struct workqueue_struct *kbc_work_queue; + struct clk *clk; +}; + +static int plain_kbd_keycode[] = { + /* + * Row 0 Unused, Unused, 'W', 'S', 'A', 'Z', Unused, Function, + * Row 1 Unused, Unused, Unused, Unused, Unused, Unused, Unused, Menu + * Row 2 Unused, Unused, Unused, Unused, Unused, Unused, Alt, Alt2 + * Row 3 '5', '4', 'R', 'E', 'F', 'D', 'X', Unused, + * Row 4 '7', '6', 'T', 'H', 'G', 'V', 'C', SPACEBAR, + * Row 5 '9', '8', 'U', 'Y', 'J', 'N', 'B', '|\', + * Row 6 Minus, '0', 'O', 'I', 'L', 'K', '<', M, + * Row 7 Unused, '+', '}]', '#', Unused, Unused, Unused, Menu, + * Row 8 Unused, Unused, Unused, Unused, SHIFT, SHIFT, Unused, Unused, + * Row 9 Unused, Unused, Unused, Unused, Unused, Ctrl, Unused, Ctrl, + * Row A Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, + * Row B '{[', 'P', '"', ':;', '/?, '>', Unused, Unused, + * Row C 'F10', 'F9', 'BckSpc', '3', '2', Up, Prntscr, Pause + * Row D INS, DEL, Unused, Pgup, PgDn, right, Down, Left, + * Row E F11, F12, F8, 'Q', F4, F3, '1', F7, + * Row F ESC, '~', F5, TAB, F1, F2, CAPLOCK, F6, + */ + KEY_RESERVED, KEY_RESERVED, KEY_W, KEY_S, + KEY_A, KEY_Z, KEY_RESERVED, KEY_FN, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_MENU, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_LEFTALT, KEY_RIGHTALT, + KEY_5, KEY_4, KEY_R, KEY_E, + KEY_F, KEY_D, KEY_X, KEY_RESERVED, + KEY_7, KEY_6, KEY_T, KEY_H, + KEY_G, KEY_V, KEY_C, KEY_SPACE, + KEY_9, KEY_8, KEY_U, KEY_Y, + KEY_J, KEY_N, KEY_B, KEY_BACKSLASH, + KEY_MINUS, KEY_0, KEY_O, KEY_I, + KEY_L, KEY_K, KEY_COMMA, KEY_M, + KEY_RESERVED, KEY_EQUAL, KEY_RIGHTBRACE, KEY_ENTER, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_MENU, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_LEFTSHIFT, KEY_RIGHTSHIFT, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_LEFTCTRL, KEY_RESERVED, KEY_RIGHTCTRL, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_LEFTBRACE, KEY_P, KEY_APOSTROPHE, KEY_SEMICOLON, + KEY_SLASH, KEY_DOT, KEY_RESERVED, KEY_RESERVED, + KEY_F10, KEY_F9, KEY_BACKSPACE, KEY_3, + KEY_2, KEY_UP, KEY_PRINT, KEY_PAUSE, + KEY_INSERT, KEY_DELETE, KEY_RESERVED, KEY_PAGEUP, + KEY_PAGEDOWN, KEY_RIGHT, KEY_DOWN, KEY_LEFT, + KEY_F11, KEY_F12, KEY_F8, KEY_Q, + KEY_F4, KEY_F3, KEY_1, KEY_F7, + KEY_ESC, KEY_GRAVE, KEY_F5, KEY_TAB, + KEY_F1, KEY_F2, KEY_CAPSLOCK, KEY_F6 +}; + +static int fn_kbd_keycode[] = { + /* + * Row 0 Unused, Unused, 'W', 'S', 'A', 'Z', Unused, Function, + * Row 1 Special, Unused, Unused, Unused, Unused, Unused, Unused, Menu + * Row 2 Unused, Unused, Unused, Unused, Unused, Unused, Alt, Alt2 + * Row 3 '5', '4', 'R', 'E', 'F', 'D', 'X', Unused, + * Row 4 '7', '6', 'T', 'H', 'G', 'V', 'C', SPACEBAR, + * Row 5 '9', '8', 'U', 'Y', 'J', 'N', 'B', '|\', + * Row 6 Minus, '0', 'O', 'I', 'L', 'K', '<', M, + * Row 7 Unused, '+', '}]', '#', Unused, Unused, Unused, Menu, + * Row 8 Unused, Unused, Unused, Unused, SHIFT, SHIFT, Unused, Unused, + * Row 9 Unused, Unused, Unused, Unused, Unused, Ctrl, Unused, Control, + * Row A Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, + * Row B '{[', 'P', '"', ':;', '/?, '>', Unused, Unused, + * Row C 'F10', 'F9', 'BckSpc', '3', '2', 'Up, Prntscr, Pause + * Row D INS, DEL, Unused, Pgup, PgDn, right, Down, Left, + * Row E F11, F12, F8, 'Q', F4, F3, '1', F7, + * Row F ESC, '~', F5, TAB, F1, F2, CAPLOCK, F6, + */ + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_9, KEY_8, KEY_4, KEY_RESERVED, + KEY_1, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_SLASH, KEY_6, KEY_5, + KEY_3, KEY_2, KEY_RESERVED, KEY_0, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_KPASTERISK, KEY_RESERVED, KEY_KPMINUS, + KEY_KPPLUS, KEY_DOT, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_VOLUMEUP, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_HOME, + KEY_END, KEY_BRIGHTNESSUP, KEY_VOLUMEDOWN, KEY_BRIGHTNESSDOWN, + KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_MUTE, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_QUESTION, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static int tegra_kbc_filter_keys(int *prows, int *pcols, int num_of_key_pressed) +{ + int i=0; + int j=0; + int k=0; + int filter_keys[2] = {0}; + int is_filtered = false; + int new_key_press_count = num_of_key_pressed; + + DEBUG_MSG("KBC: tegra_kbc_filter_keys\n"); + + if (num_of_key_pressed <= 3) + { + for (i=0; i<num_of_key_pressed; i++) + { + for (j=(i+1); j<num_of_key_pressed; j++) + { + if ((prows[i]+1==prows[j])||(prows[j]+1==prows[i])) + { + for (k=j; i<(num_of_key_pressed - 1); i++) + { + prows[k] = prows[k+1]; + pcols[k] = pcols[k+1]; + } + num_of_key_pressed--; + } + if ((pcols[i]+1==pcols[j])||(pcols[j]+1==pcols[i])) + { + for (k=j; i<(num_of_key_pressed - 1); i++) + { + prows[k] = prows[k+1]; + pcols[k] = pcols[k+1]; + } + num_of_key_pressed--; + } + } + } + return num_of_key_pressed; + } + + for (i=0; i<num_of_key_pressed; i++) + { + for (j=(i+1); j<num_of_key_pressed; j++) + { + if (prows[i] == prows[j]) + { + for (k=0; k<num_of_key_pressed; k++) + { + if (k == i) + continue; + + if(pcols[i] == pcols[k]) + { + filter_keys[0] = k; + is_filtered = true; + } + } + for (k=0; k<num_of_key_pressed; k++) + { + if (k == j) + continue; + if (pcols[j] == pcols[k]) + { + filter_keys[1] = k; + is_filtered = true; + } + } + goto end; + } + } + } + + end: + if (is_filtered) + { + for (i=filter_keys[0]; i<(num_of_key_pressed - 1); i++) + { + prows[i] = prows[i+1]; + pcols[i] = pcols[i+1]; + } + new_key_press_count--; + for (i=filter_keys[1]; i<(num_of_key_pressed - 1); i++) + { + prows[i] = prows[i+1]; + pcols[i] = pcols[i+1]; + } + new_key_press_count--; + } + num_of_key_pressed = new_key_press_count; + return new_key_press_count; +} + + +static int tegra_kbc_keycode(struct tegra_kbc *kbc, int r, int c, bool fn_key) +{ + if (!fn_key) + return kbc->plain_keycode[(r * KBC_MAX_COL) + c]; + else + return kbc->fn_keycode[(r * KBC_MAX_COL) + c]; +} + +#ifdef CONFIG_PM +static int tegra_kbc_open(struct input_dev *dev); +static void tegra_kbc_close(struct input_dev *dev); +static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter); + +static int tegra_kbc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + + DEBUG_MSG("KBC: tegra_kbc_suspend\n"); + + if (device_may_wakeup(&pdev->dev)) { + tegra_kbc_setup_wakekeys(kbc, true); + enable_irq_wake(kbc->irq); + /* Forcefully clear the interrupt status */ + writel(0x7, kbc->mmio + KBC_INT_0); + msleep(30); + } else { + tegra_kbc_close(kbc->idev); + } + + return 0; +} + +static int tegra_kbc_resume(struct platform_device *pdev) +{ + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + + DEBUG_MSG("KBC: tegra_kbc_resume\n"); + + if (device_may_wakeup(&pdev->dev)) { + disable_irq_wake(kbc->irq); + tegra_kbc_setup_wakekeys(kbc, false); + } else if (kbc->idev->users) + return tegra_kbc_open(kbc->idev); + + return 0; +} +#endif + +static void tegra_kbc_report_keys(struct tegra_kbc *kbc, int *fifo) +{ + int curr_fifo[KBC_MAX_KPENT]; + int rows_val[KBC_MAX_KPENT], cols_val[KBC_MAX_KPENT]; + u32 kp_ent_val[(KBC_MAX_KPENT + 3) / 4]; + u32 *kp_ents = kp_ent_val; + u32 kp_ent = 0; + unsigned long flags; + int i, j, valid = 0; + bool fn = false; + + DEBUG_MSG("KBC: tegra_kbc_report_keys\n"); + + local_irq_save(flags); + for (i = 0; i < ARRAY_SIZE(kp_ent_val); i++) + kp_ent_val[i] = readl(kbc->mmio + KBC_KP_ENT0_0 + (i*4)); + local_irq_restore(flags); + + valid = 0; + for (i = 0; i < KBC_MAX_KPENT; i++) { + if (!(i&3)) + kp_ent = *kp_ents++; + + if (kp_ent & 0x80) { + cols_val[valid] = kp_ent & 0x7; + rows_val[valid++] = (kp_ent >> 3) & 0xf; + } + kp_ent >>= 8; + } + + if (kbc->pdata->filter_keys) + valid = tegra_kbc_filter_keys(rows_val, cols_val, valid); + + for (i = 0; i < valid; i++) { + int k = tegra_kbc_keycode(kbc, rows_val[i], cols_val[i], false); + if (k == KEY_FN) { + fn = true; + break; + } + } + + j = 0; + for (i = 0; i < valid; i++) { + int k = tegra_kbc_keycode(kbc, rows_val[i], cols_val[i], fn); + if (likely(k != -1)) + curr_fifo[j++] = k; + } + valid = j; + + for (i = 0; i < KBC_MAX_KPENT; i++) { + if (fifo[i] == -1) + continue; + for (j = 0; j < valid; j++) { + if (curr_fifo[j] == fifo[i]) { + curr_fifo[j] = -1; + break; + } + } + if (j == valid) { + input_report_key(kbc->idev, fifo[i], 0); + fifo[i] = -1; + } + } + for (j = 0; j < valid; j++) { + if (curr_fifo[j] == -1) + continue; + for (i = 0; i < KBC_MAX_KPENT; i++) { + if (fifo[i] == -1) + break; + } + if (i != KBC_MAX_KPENT) { + fifo[i] = curr_fifo[j]; + input_report_key(kbc->idev, fifo[i], 1); + } else + WARN_ON(1); + } +} + +static void tegra_kbc_key_repeat(struct work_struct *work) +{ + struct tegra_kbc *kbc; + unsigned long flags; + u32 val; + int fifo[KBC_MAX_KPENT]; + int i; + + DEBUG_MSG("KBC: tegra_kbc_key_repeat\n"); + + kbc = container_of(work, struct tegra_kbc, key_repeat); + for (i = 0; i < ARRAY_SIZE(fifo); i++) + fifo[i] = -1; + + while (1) { + val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; + if (!val) { + /* release any pressed keys and exit the loop */ + for (i = 0; i < ARRAY_SIZE(fifo); i++) { + if (fifo[i] == -1) + continue; + input_report_key(kbc->idev, fifo[i], 0); + } + break; + } + tegra_kbc_report_keys(kbc, fifo); + msleep((val == 1) ? kbc->repoll_time : 1); + } + + spin_lock_irqsave(&kbc->lock, flags); + val = readl(kbc->mmio + KBC_CONTROL_0); + val |= (1<<3); + writel(val, kbc->mmio + KBC_CONTROL_0); + spin_unlock_irqrestore(&kbc->lock, flags); +} + +static void tegra_kbc_close(struct input_dev *dev) +{ + struct tegra_kbc *kbc = input_get_drvdata(dev); + unsigned long flags; + u32 val; + + DEBUG_MSG("KBC: tegra_kbc_close\n"); + + spin_lock_irqsave(&kbc->lock, flags); + val = readl(kbc->mmio + KBC_CONTROL_0); + val &= ~1; + writel(val, kbc->mmio + KBC_CONTROL_0); + spin_unlock_irqrestore(&kbc->lock, flags); + + clk_disable(kbc->clk); +} + +static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter) +{ + int i; + unsigned int rst_val; + + DEBUG_MSG("KBC: tegra_kbc_setup_wakekeys\n"); + + BUG_ON(kbc->pdata->wake_cnt > KBC_MAX_KEY); + rst_val = (filter && kbc->pdata->wake_cnt) ? ~0 : 0; + + for (i = 0; i < KBC_MAX_ROW; i++) + writel(rst_val, kbc->mmio+KBC_ROW0_MASK_0+i*4); + + if (filter) { + for (i = 0; i < kbc->pdata->wake_cnt; i++) { + u32 val, addr; + addr = kbc->pdata->wake_cfg[i].row*4 + KBC_ROW0_MASK_0; + val = readl(kbc->mmio + addr); + val &= ~(1<<kbc->pdata->wake_cfg[i].col); + writel(val, kbc->mmio + addr); + } + } +} + +static void tegra_kbc_config_pins(struct tegra_kbc *kbc) +{ + const struct tegra_kbc_platform_data *pdata = kbc->pdata; + int i; + + DEBUG_MSG("KBC: tegra_kbc_config_pins\n"); + + for (i = 0; i < KBC_MAX_GPIO; i++) { + u32 row_cfg, col_cfg; + u32 r_shift = 5 * (i%6); + u32 c_shift = 4 * (i%8); + u32 r_mask = 0x1f << r_shift; + u32 c_mask = 0xf << c_shift; + u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0; + u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0; + + row_cfg = readl(kbc->mmio + r_offs); + col_cfg = readl(kbc->mmio + c_offs); + + row_cfg &= ~r_mask; + col_cfg &= ~c_mask; + + if (pdata->pin_cfg[i].is_row) + row_cfg |= ((pdata->pin_cfg[i].num<<1) | 1) << r_shift; + else if (pdata->pin_cfg[i].is_col) + col_cfg |= ((pdata->pin_cfg[i].num<<1) | 1) << c_shift; + + writel(row_cfg, kbc->mmio + r_offs); + writel(col_cfg, kbc->mmio + c_offs); + } +} + +static int tegra_kbc_open(struct input_dev *dev) +{ + struct tegra_kbc *kbc = input_get_drvdata(dev); + unsigned long flags; + u32 val = 0; + + DEBUG_MSG("KBC: tegra_kbc_open\n"); + + clk_enable(kbc->clk); + + /* Reset the KBC controller to clear all previous status.*/ + tegra_periph_reset_assert(kbc->clk); + udelay(100); + tegra_periph_reset_deassert(kbc->clk); + udelay(100); + + tegra_kbc_config_pins(kbc); + tegra_kbc_setup_wakekeys(kbc, false); + + writel(kbc->pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0); + + val = kbc->pdata->debounce_cnt << 4; + val |= 1<<14; /* fifo interrupt threshold = 1 entry */ + val |= 1<<3; /* interrupt on FIFO threshold reached */ + val |= 1; /* enable */ + writel(val, kbc->mmio + KBC_CONTROL_0); + + /* atomically clear out any remaining entries in the key FIFO + * and enable keyboard interrupts */ + spin_lock_irqsave(&kbc->lock, flags); + + while (1) { + val = readl(kbc->mmio + KBC_INT_0); + val >>= 4; + if (val) { + val = readl(kbc->mmio + KBC_KP_ENT0_0); + val = readl(kbc->mmio + KBC_KP_ENT1_0); + } else { + break; + } + } + writel(0x7, kbc->mmio + KBC_INT_0); + spin_unlock_irqrestore(&kbc->lock, flags); + + + return 0; +} + + +static int __devexit tegra_kbc_remove(struct platform_device *pdev) +{ + struct tegra_kbc *kbc = platform_get_drvdata(pdev); + struct resource *res; + + DEBUG_MSG("KBC: tegra_kbc_remove\n"); + + free_irq(kbc->irq, pdev); + clk_disable(kbc->clk); + clk_put(kbc->clk); + + input_unregister_device(kbc->idev); + input_free_device(kbc->idev); + iounmap(kbc->mmio); + destroy_workqueue(kbc->kbc_work_queue); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res_size(res)); + + kfree(kbc); + return 0; +} + +static irqreturn_t tegra_kbc_isr(int irq, void *args) +{ + struct tegra_kbc *kbc = args; + u32 val, ctl; + + DEBUG_MSG("KBC: tegra_kbc_isr\n"); + + /* until all keys are released, defer further processing to + * the polling loop in tegra_kbc_key_repeat */ + ctl = readl(kbc->mmio + KBC_CONTROL_0); + ctl &= ~(1<<3); + writel(ctl, kbc->mmio + KBC_CONTROL_0); + + /* quickly bail out & reenable interrupts if the interrupt source + * wasn't fifo count threshold */ + val = readl(kbc->mmio + KBC_INT_0); + writel(val, kbc->mmio + KBC_INT_0); + + if (!(val & (1<<2))) { + ctl |= 1<<3; + writel(ctl, kbc->mmio + KBC_CONTROL_0); + return IRQ_HANDLED; + } + + queue_work(kbc->kbc_work_queue, &kbc->key_repeat); + return IRQ_HANDLED; +} + +static int __devinit tegra_kbc_probe(struct platform_device *pdev) +{ + struct tegra_kbc *kbc; + struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; + struct resource *res; + int irq; + int err; + int rows[KBC_MAX_ROW]; + int cols[KBC_MAX_COL]; + int i, j; + int nr = 0; + char name[64]; + + DEBUG_MSG("KBC: tegra_kbc_probe\n"); + + if (!pdata) + return -EINVAL; + + kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); + if (!kbc) + return -ENOMEM; + + kbc->pdata = pdata; + kbc->irq = -EINVAL; + + memset(rows, 0, sizeof(rows)); + memset(cols, 0, sizeof(cols)); + + kbc->idev = input_allocate_device(); + if (!kbc->idev) { + err = -ENOMEM; + goto fail; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + err = -ENXIO; + goto fail; + } + res = request_mem_region(res->start, res_size(res), pdev->name); + if (!res) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + err = -EBUSY; + goto fail; + } + kbc->mmio = ioremap(res->start, res_size(res)); + if (!kbc->mmio) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + err = -ENXIO; + goto fail; + } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keypad IRQ\n"); + err = -ENXIO; + goto fail; + } + kbc->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR_OR_NULL(kbc->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + err = (kbc->clk) ? PTR_ERR(kbc->clk) : -ENODEV; + kbc->clk = NULL; + goto fail; + } + + platform_set_drvdata(pdev, kbc); + + kbc->idev->name = pdev->name; + input_set_drvdata(kbc->idev, kbc); + kbc->idev->id.bustype = BUS_HOST; + kbc->idev->open = tegra_kbc_open; + kbc->idev->close = tegra_kbc_close; + kbc->idev->dev.parent = &pdev->dev; + spin_lock_init(&kbc->lock); + + for (i = 0; i < KBC_MAX_GPIO; i++) { + if (pdata->pin_cfg[i].is_row && pdata->pin_cfg[i].is_col) { + dev_err(&pdev->dev, "invalid pin configuration data\n"); + err = -EINVAL; + goto fail; + } + + if (pdata->pin_cfg[i].is_row) { + if (pdata->pin_cfg[i].num >= KBC_MAX_ROW) { + dev_err(&pdev->dev, "invalid row number\n"); + err = -EINVAL; + goto fail; + } + rows[pdata->pin_cfg[i].num] = 1; + nr++; + } else if (pdata->pin_cfg[i].is_col) { + if (pdata->pin_cfg[i].num >= KBC_MAX_COL) { + dev_err(&pdev->dev, "invalid column number\n"); + err = -EINVAL; + goto fail; + } + cols[pdata->pin_cfg[i].num] = 1; + } + } + kbc->wake_enable_rows = 0; + kbc->wake_enable_cols = 0; + + for (i = 0; i < pdata->wake_cnt; i++) { + kbc->wake_enable_rows |= (1 << kbc->pdata->wake_cfg[i].row); + kbc->wake_enable_cols |= (1 << kbc->pdata->wake_cfg[i].col); + } + + pdata->debounce_cnt = min_t(unsigned int, pdata->debounce_cnt, 0x3fful); + kbc->repoll_time = 5 + (16+pdata->debounce_cnt)*nr + pdata->repeat_cnt; + kbc->repoll_time = (kbc->repoll_time + 31) / 32; + + kbc->idev->evbit[0] = BIT_MASK(EV_KEY); + + /* Override the default keycodes with the board supplied ones. */ + if (pdata->plain_keycode) { + kbc->plain_keycode = pdata->plain_keycode; + kbc->fn_keycode = pdata->fn_keycode; + } else { + kbc->plain_keycode = plain_kbd_keycode; + kbc->fn_keycode = fn_kbd_keycode; + } + + for (i = 0; i < KBC_MAX_COL; i++) { + if (!cols[i]) + continue; + for (j = 0; j < KBC_MAX_ROW; j++) { + int keycode; + if (!rows[j]) + continue; + keycode = tegra_kbc_keycode(kbc, j, i, false); + if (keycode == -1) + continue; + set_bit(keycode, kbc->idev->keybit); + } + } + + + /* create the workqueue for the kbc path */ + snprintf(name, sizeof(name), "tegra-kbc"); + kbc->kbc_work_queue = create_singlethread_workqueue(name); + if (kbc->kbc_work_queue == NULL) { + dev_err(&pdev->dev, "Failed to create work queue\n"); + err = -ENODEV; + goto fail; + } + + /* keycode FIFO needs to be read atomically; leave local + * interrupts disabled when handling KBC interrupt */ + INIT_WORK(&kbc->key_repeat, tegra_kbc_key_repeat); + + err = request_irq(irq, tegra_kbc_isr, IRQF_DISABLED, pdev->name, kbc); + if (err) { + dev_err(&pdev->dev, "failed to request keypad IRQ\n"); + goto fail; + } + kbc->irq = irq; + + err = input_register_device(kbc->idev); + if (err) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto fail; + } + + device_init_wakeup(&pdev->dev, 1); + return 0; + +fail: + if (kbc->irq >= 0) + free_irq(kbc->irq, pdev); + if (kbc->idev) + input_free_device(kbc->idev); + if (kbc->clk) + clk_put(kbc->clk); + if (kbc->mmio) + iounmap(kbc->mmio); + if (kbc->kbc_work_queue) + destroy_workqueue(kbc->kbc_work_queue); + kfree(kbc); + + return err; +} + +static struct platform_driver tegra_kbc_driver = { + .probe = tegra_kbc_probe, + .remove = tegra_kbc_remove, +#ifdef CONFIG_PM + .suspend = tegra_kbc_suspend, + .resume = tegra_kbc_resume, +#endif + .driver = { + .name = "tegra-kbc" + } +}; + +static void __exit tegra_kbc_exit(void) +{ + DEBUG_MSG("KBC: tegra_kbc_exit\n"); + platform_driver_unregister(&tegra_kbc_driver); +} + +static int __devinit tegra_kbc_init(void) +{ + DEBUG_MSG("KBC: tegra_kbc_init\n"); + return platform_driver_register(&tegra_kbc_driver); +} + +module_exit(tegra_kbc_exit); +module_init(tegra_kbc_init); + +MODULE_DESCRIPTION("Tegra matrix keyboard controller driver"); + + diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d50fd5603604..f7c25b2b7ed6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -383,6 +383,13 @@ config TOUCHSCREEN_ATMEL_TSADCC To compile this driver as a module, choose M here: the module will be called atmel_tsadcc. +config TOUCHSCREEN_ATMEL_MT_T9 + tristate "Atmel Touchscreen Interface" + depends on I2C + help + To compile this driver as a module, choose M here: the + module will be called atmel_tsadcc. + config TOUCHSCREEN_UCB1400 tristate "Philips UCB1400 touchscreen" depends on AC97_BUS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 93e641bc320e..b588efc90bf8 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o +obj-$(CONFIG_TOUCHSCREEN_ATMEL_MT_T9) += atmel_maxtouch.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c new file mode 100755 index 000000000000..52a9744ec501 --- /dev/null +++ b/drivers/input/touchscreen/atmel_maxtouch.c @@ -0,0 +1,2056 @@ +/* + * Atmel maXTouch Touchscreen Controller + * + * + * Copyright (C) 2010 Atmel Corporation + * Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/debugfs.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +#include <linux/uaccess.h> + +#include <linux/i2c/atmel_maxtouch.h> + +/* + * This is a driver for the Atmel maXTouch Object Protocol + * + * When the driver is loaded, mxt_init is called. + * mxt_driver registers the "mxt_driver" structure in the i2c subsystem + * The mxt_idtable.name string allows the board support to associate + * the driver with its own data. + * + * The i2c subsystem will call the mxt_driver.probe == mxt_probe + * to detect the device. + * mxt_probe will reset the maXTouch device, and then + * determine the capabilities of the I2C peripheral in the + * host processor (needs to support BYTE transfers) + * + * If OK; mxt_probe will try to identify which maXTouch device it is + * by calling mxt_identify. + * + * If a known device is found, a linux input device is initialized + * the "mxt" device data structure is allocated, + * as well as an input device structure "mxt->input" + * "mxt->client" is provided as a parameter to mxt_probe. + * + * mxt_read_object_table is called to determine which objects + * are present in the device, and to determine their adresses. + * + * + * Addressing an object: + * + * The object is located at a 16-bit address in the object address space. + * + * The address is provided through an object descriptor table in the beginning + * of the object address space. This address can change between firmware + * revisions, so it's important that the driver will make no assumptions + * about addresses but instead reads the object table and gets the correct + * addresses there. + * + * Each object type can have several instances, and the number of + * instances is available in the object table as well. + * + * The base address of the first instance of an object is stored in + * "mxt->object_table[object_type].chip_addr", + * This is indexed by the object type and allows direct access to the + * first instance of an object. + * + * Each instance of an object is assigned a "Report Id" uniquely identifying + * this instance. Information about this instance is available in the + * "mxt->report_id" variable, which is a table indexed by the "Report Id". + * + * The maXTouch object protocol supports adding a checksum to messages. + * By setting the most significant bit of the maXTouch address, + * an 8 bit checksum is added to all writes. + * + * + * How to use driver. + * ----------------- + * Example: + * In arch/avr32/boards/atstk1000/atstk1002.c + * an "i2c_board_info" descriptor is declared. + * This contains info about which driver ("mXT224"), + * which i2c address and which pin for CHG interrupts are used. + * + * In the "atstk1002_init" routine, "i2c_register_board_info" is invoked + * with this information. Also, the I/O pins are configured, and the I2C + * controller registered is on the application processor. + * + * + */ + +static int debug = NO_DEBUG; +static int comms; +module_param(debug, int, 0644); +module_param(comms, int, 0644); + +MODULE_PARM_DESC(debug, "Activate debugging output"); +MODULE_PARM_DESC(comms, "Select communications mode"); + +/* Device Info descriptor */ +/* Parsed from maXTouch "Id information" inside device */ +struct mxt_device_info { + u8 family_id; + u8 variant_id; + u8 major; + u8 minor; + u8 build; + u8 num_objs; + u8 x_size; + u8 y_size; + char family_name[16]; /* Family name */ + char variant_name[16]; /* Variant name */ + u16 num_nodes; /* Number of sensor nodes */ +}; + +/* object descriptor table, parsed from maXTouch "object table" */ +struct mxt_object { + u16 chip_addr; + u8 type; + u8 size; + u8 instances; + u8 num_report_ids; +}; + +/* Mapping from report id to object type and instance */ +struct report_id_map { + u8 object; + u8 instance; +/* + * This is the first report ID belonging to object. It enables us to + * find out easily the touch number: each touch has different report + * ID (which are assigned to touches in increasing order). By + * subtracting the first report ID from current, we get the touch + * number. + */ + u8 first_rid; +}; + +/* Driver datastructure */ +struct mxt_data { + struct i2c_client *client; + struct input_dev *input; + char phys_name[32]; + int irq; + + u16 last_read_addr; + bool new_msgs; + u8 *last_message; + + int valid_irq_counter; + int invalid_irq_counter; + int irq_counter; + int message_counter; + int read_fail_counter; + + int bytes_to_read; + + struct delayed_work dwork; + u8 xpos_format; + u8 ypos_format; + + u8 numtouch; + + struct mxt_device_info device_info; + + u32 info_block_crc; + u32 configuration_crc; + u16 report_id_count; + struct report_id_map *rid_map; + struct mxt_object *object_table; + + u16 msg_proc_addr; + u8 message_size; + + u16 max_x_val; + u16 max_y_val; + + void (*init_hw) (void); + void (*exit_hw) (void); + u8(*valid_interrupt) (void); + u8(*read_chg) (void); + + /* debugfs variables */ + struct dentry *debug_dir; + int current_debug_datap; + + struct mutex debug_mutex; + u16 *debug_data; + + /* Character device variables */ + struct cdev cdev; + struct cdev cdev_messages; /* 2nd Char dev for messages */ + dev_t dev_num; + struct class *mxt_class; + + u16 address_pointer; + bool valid_ap; + + /* Message buffer & pointers */ + char *messages; + int msg_buffer_startp, msg_buffer_endp; + /* Put only non-touch messages to buffer if this is set */ + char nontouch_msg_only; + struct mutex msg_mutex; +}; + +#define I2C_RETRY_COUNT 5 +#define I2C_PAYLOAD_SIZE 254 + +/* Returns the start address of object in mXT memory. */ +#define MXT_BASE_ADDR(object_type, mxt) \ + get_object_address(object_type, 0, mxt->object_table, \ + mxt->device_info.num_objs) + +/* Maps a report ID to an object type (object type number). */ +#define REPORT_ID_TO_OBJECT(rid, mxt) \ + (((rid) == 0xff) ? 0 : mxt->rid_map[rid].object) + +/* Maps a report ID to an object type (string). */ +#define REPORT_ID_TO_OBJECT_NAME(rid, mxt) \ + object_type_name[REPORT_ID_TO_OBJECT(rid, mxt)] + +/* Returns non-zero if given object is a touch object */ +#define IS_TOUCH_OBJECT(object) \ + ((object == MXT_TOUCH_MULTITOUCHSCREEN_T9) || \ + (object == MXT_TOUCH_KEYARRAY_T15) || \ + (object == MXT_TOUCH_PROXIMITY_T23) || \ + (object == MXT_TOUCH_SINGLETOUCHSCREEN_T10) || \ + (object == MXT_TOUCH_XSLIDER_T11) || \ + (object == MXT_TOUCH_YSLIDER_T12) || \ + (object == MXT_TOUCH_XWHEEL_T13) || \ + (object == MXT_TOUCH_YWHEEL_T14) || \ + (object == MXT_TOUCH_KEYSET_T31) || \ + (object == MXT_TOUCH_XSLIDERSET_T32) ? 1 : 0) + +#define mxt_debug(level, ...) \ + do { \ + if (debug >= (level)) \ + pr_debug(__VA_ARGS__); \ + } while (0) + +static const u8 *object_type_name[] = { + [0] = "Reserved", + [5] = "GEN_MESSAGEPROCESSOR_T5", + [6] = "GEN_COMMANDPROCESSOR_T6", + [7] = "GEN_POWERCONFIG_T7", + [8] = "GEN_ACQUIRECONFIG_T8", + [9] = "TOUCH_MULTITOUCHSCREEN_T9", + [15] = "TOUCH_KEYARRAY_T15", + [17] = "SPT_COMMSCONFIG_T18", + [19] = "SPT_GPIOPWM_T19", + [20] = "PROCI_GRIPFACESUPPRESSION_T20", + [22] = "PROCG_NOISESUPPRESSION_T22", + [23] = "TOUCH_PROXIMITY_T23", + [24] = "PROCI_ONETOUCHGESTUREPROCESSOR_T24", + [25] = "SPT_SELFTEST_T25", + [27] = "PROCI_TWOTOUCHGESTUREPROCESSOR_T27", + [28] = "SPT_CTECONFIG_T28", + [37] = "DEBUG_DIAGNOSTICS_T37", + [38] = "SPT_USER_DATA_T38", + [40] = "PROCI_GRIPSUPPRESSION_T40", + [41] = "PROCI_PALMSUPPRESSION_T41", + [42] = "PROCI_FACESUPPRESSION_T42", + [43] = "SPT_DIGITIZER_T43", + [44] = "SPT_MESSAGECOUNT_T44", +}; + +static u16 get_object_address(uint8_t object_type, + uint8_t instance, + struct mxt_object *object_table, int max_objs); + +static int mxt_write_ap(struct mxt_data *mxt, u16 ap); + +static int mxt_read_block_wo_addr(struct i2c_client *client, + u16 length, u8 *value); + +ssize_t debug_data_read(struct mxt_data *mxt, char *buf, size_t count, + loff_t *ppos, u8 debug_command) +{ + int i; + u16 *data; + u16 diagnostics_reg; + int offset = 0; + int size; + int read_size; + int error; + char *buf_start; + u16 debug_data_addr; + u16 page_address; + u8 page; + u8 debug_command_reg; + + data = mxt->debug_data; + if (data == NULL) + return -EIO; + + /* If first read after open, read all data to buffer. */ + if (mxt->current_debug_datap == 0) { + + diagnostics_reg = MXT_BASE_ADDR(MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_DIAGNOSTIC; + if (count > (mxt->device_info.num_nodes * 2)) + count = mxt->device_info.num_nodes; + + debug_data_addr = MXT_BASE_ADDR(MXT_DEBUG_DIAGNOSTIC_T37, mxt) + + MXT_ADR_T37_DATA; + page_address = MXT_BASE_ADDR(MXT_DEBUG_DIAGNOSTIC_T37, mxt) + + MXT_ADR_T37_PAGE; + error = mxt_read_block(mxt->client, page_address, 1, &page); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, "debug data page = %d\n", page); + while (page != 0) { + error = mxt_write_byte(mxt->client, + diagnostics_reg, + MXT_CMD_T6_PAGE_DOWN); + if (error < 0) + return error; + /* Wait for command to be handled; when it has, the + register will be cleared. */ + debug_command_reg = 1; + while (debug_command_reg != 0) { + error = mxt_read_block(mxt->client, + diagnostics_reg, 1, + &debug_command_reg); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, + "Waiting for debug diag command " + "to propagate...\n"); + + } + error = mxt_read_block(mxt->client, page_address, 1, + &page); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, "debug data page = %d\n", page); + } + + /* + * Lock mutex to prevent writing some unwanted data to debug + * command register. User can still write through the char + * device interface though. TODO: fix? + */ + + mutex_lock(&mxt->debug_mutex); + /* Configure Debug Diagnostics object to show deltas/refs */ + error = mxt_write_byte(mxt->client, diagnostics_reg, + debug_command); + + /* Wait for command to be handled; when it has, the + * register will be cleared. */ + debug_command_reg = 1; + while (debug_command_reg != 0) { + error = mxt_read_block(mxt->client, + diagnostics_reg, 1, + &debug_command_reg); + if (error < 0) + return error; + mxt_debug(DEBUG_TRACE, "Waiting for debug diag command " + "to propagate...\n"); + + } + + if (error < 0) { + printk(KERN_WARNING + "Error writing to maXTouch device!\n"); + return error; + } + + size = mxt->device_info.num_nodes * sizeof(u16); + + while (size > 0) { + read_size = size > 128 ? 128 : size; + mxt_debug(DEBUG_TRACE, + "Debug data read loop, reading %d bytes...\n", + read_size); + error = mxt_read_block(mxt->client, + debug_data_addr, + read_size, + (u8 *) &data[offset]); + if (error < 0) { + printk(KERN_WARNING + "Error reading debug data\n"); + goto error; + } + offset += read_size / 2; + size -= read_size; + + /* Select next page */ + error = mxt_write_byte(mxt->client, diagnostics_reg, + MXT_CMD_T6_PAGE_UP); + if (error < 0) { + printk(KERN_WARNING + "Error writing to maXTouch device!\n"); + goto error; + } + } + mutex_unlock(&mxt->debug_mutex); + } + + buf_start = buf; + i = mxt->current_debug_datap; + + while (((buf - buf_start) < (count - 6)) && + (i < mxt->device_info.num_nodes)) { + + mxt->current_debug_datap++; + if (debug_command == MXT_CMD_T6_REFERENCES_MODE) + buf += sprintf(buf, "%d: %5d\n", i, + (u16) le16_to_cpu(data[i])); + else if (debug_command == MXT_CMD_T6_DELTAS_MODE) + buf += sprintf(buf, "%d: %5d\n", i, + (s16) le16_to_cpu(data[i])); + i++; + } + + return buf - buf_start; + error: + mutex_unlock(&mxt->debug_mutex); + return error; +} + +ssize_t deltas_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return debug_data_read(file->private_data, buf, count, ppos, + MXT_CMD_T6_DELTAS_MODE); +} + +ssize_t refs_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return debug_data_read(file->private_data, buf, count, ppos, + MXT_CMD_T6_REFERENCES_MODE); +} + +int debug_data_open(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + int i; + mxt = inode->i_private; + if (mxt == NULL) + return -EIO; + mxt->current_debug_datap = 0; + mxt->debug_data = kmalloc(mxt->device_info.num_nodes * sizeof(u16), + GFP_KERNEL); + if (mxt->debug_data == NULL) + return -ENOMEM; + + for (i = 0; i < mxt->device_info.num_nodes; i++) + mxt->debug_data[i] = 7777; + + file->private_data = mxt; + return 0; +} + +int debug_data_release(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + mxt = file->private_data; + kfree(mxt->debug_data); + return 0; +} + +const struct file_operations delta_fops = { + .owner = THIS_MODULE, + .open = debug_data_open, + .release = debug_data_release, + .read = deltas_read, +}; + +const struct file_operations refs_fops = { + .owner = THIS_MODULE, + .open = debug_data_open, + .release = debug_data_release, + .read = refs_read, +}; + +int mxt_memory_open(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + mxt = container_of(inode->i_cdev, struct mxt_data, cdev); + if (mxt == NULL) + return -EIO; + file->private_data = mxt; + return 0; +} + +int mxt_message_open(struct inode *inode, struct file *file) +{ + struct mxt_data *mxt; + mxt = container_of(inode->i_cdev, struct mxt_data, cdev_messages); + if (mxt == NULL) + return -EIO; + file->private_data = mxt; + return 0; +} + +ssize_t mxt_memory_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int i; + struct mxt_data *mxt; + + mxt = file->private_data; + if (mxt->valid_ap) { + mxt_debug(DEBUG_TRACE, "Reading %d bytes from current ap\n", + (int)count); + i = mxt_read_block_wo_addr(mxt->client, count, (u8 *) buf); + } else { + mxt_debug(DEBUG_TRACE, "Address pointer changed since set;" + "writing AP (%d) before reading %d bytes", + mxt->address_pointer, (int)count); + i = mxt_read_block(mxt->client, mxt->address_pointer, count, + buf); + } + + return i; +} + +ssize_t mxt_memory_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + int i; + int whole_blocks; + int last_block_size; + struct mxt_data *mxt; + u16 address; + + mxt = file->private_data; + address = mxt->address_pointer; + + mxt_debug(DEBUG_TRACE, "mxt_memory_write entered\n"); + whole_blocks = count / I2C_PAYLOAD_SIZE; + last_block_size = count % I2C_PAYLOAD_SIZE; + + for (i = 0; i < whole_blocks; i++) { + mxt_debug(DEBUG_TRACE, "About to write to %d...", address); + mxt_write_block(mxt->client, address, I2C_PAYLOAD_SIZE, + (u8 *) buf); + address += I2C_PAYLOAD_SIZE; + buf += I2C_PAYLOAD_SIZE; + } + + mxt_write_block(mxt->client, address, last_block_size, (u8 *) buf); + + return count; +} + +static int mxt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval; + struct mxt_data *mxt; + + retval = 0; + mxt = file->private_data; + + switch (cmd) { + case MXT_SET_ADDRESS: + retval = mxt_write_ap(mxt, (u16) arg); + if (retval >= 0) { + mxt->address_pointer = (u16) arg; + mxt->valid_ap = 1; + } + break; + case MXT_RESET: + retval = mxt_write_byte(mxt->client, + MXT_BASE_ADDR + (MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_RESET, 1); + break; + case MXT_CALIBRATE: + retval = mxt_write_byte(mxt->client, + MXT_BASE_ADDR + (MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_CALIBRATE, 1); + + break; + case MXT_BACKUP: + retval = mxt_write_byte(mxt->client, + MXT_BASE_ADDR + (MXT_GEN_COMMANDPROCESSOR_T6, + mxt) + MXT_ADR_T6_BACKUPNV, + MXT_CMD_T6_BACKUP); + break; + case MXT_NONTOUCH_MSG: + mxt->nontouch_msg_only = 1; + break; + case MXT_ALL_MSG: + mxt->nontouch_msg_only = 0; + break; + default: + return -EIO; + } + + return retval; +} + +/* + * Copies messages from buffer to user space. + * + * NOTE: if less than (mxt->message_size * 5 + 1) bytes requested, + * this will return 0! + * + */ +ssize_t mxt_message_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int i; + struct mxt_data *mxt; + char *buf_start; + + mxt = file->private_data; + if (mxt == NULL) + return -EIO; + buf_start = buf; + + mutex_lock(&mxt->msg_mutex); + /* Copy messages until buffer empty, or 'count' bytes written */ + while ((mxt->msg_buffer_startp != mxt->msg_buffer_endp) && + ((buf - buf_start) < (count - 5 * mxt->message_size - 1))) { + + for (i = 0; i < mxt->message_size; i++) { + buf += sprintf(buf, "[%2X] ", + *(mxt->messages + mxt->msg_buffer_endp * + mxt->message_size + i)); + } + buf += sprintf(buf, "\n"); + if (mxt->msg_buffer_endp < MXT_MESSAGE_BUFFER_SIZE) + mxt->msg_buffer_endp++; + else + mxt->msg_buffer_endp = 0; + } + mutex_unlock(&mxt->msg_mutex); + return buf - buf_start; +} + +const struct file_operations mxt_message_fops = { + .owner = THIS_MODULE, + .open = mxt_message_open, + .read = mxt_message_read, +}; + +const struct file_operations mxt_memory_fops = { + .owner = THIS_MODULE, + .open = mxt_memory_open, + .read = mxt_memory_read, + .write = mxt_memory_write, + .unlocked_ioctl = mxt_ioctl, +}; + +/* Writes the address pointer (to set up following reads). */ + +int mxt_write_ap(struct mxt_data *mxt, u16 ap) +{ + struct i2c_client *client; + __le16 le_ap = cpu_to_le16(ap); + client = mxt->client; + if (mxt != NULL) + mxt->last_read_addr = -1; + if (i2c_master_send(client, (u8 *) &le_ap, 2) == 2) { + mxt_debug(DEBUG_TRACE, "Address pointer set to %d\n", ap); + return 0; + } else { + mxt_debug(DEBUG_INFO, "Error writing address pointer!\n"); + return -EIO; + } +} + +/* Calculates the 24-bit CRC sum. */ +static u32 CRC_24(u32 crc, u8 byte1, u8 byte2) +{ + static const u32 crcpoly = 0x80001B; + u32 result; + u32 data_word; + + data_word = ((((u16) byte2) << 8u) | byte1); + result = ((crc << 1u) ^ data_word); + if (result & 0x1000000) + result ^= crcpoly; + return result; +} + +/* Returns object address in mXT chip, or zero if object is not found */ +static u16 get_object_address(uint8_t object_type, + uint8_t instance, + struct mxt_object *object_table, int max_objs) +{ + uint8_t object_table_index = 0; + uint8_t address_found = 0; + uint16_t address = 0; + struct mxt_object *obj; + + while ((object_table_index < max_objs) && !address_found) { + obj = &object_table[object_table_index]; + if (obj->type == object_type) { + address_found = 1; + /* Are there enough instances defined in the FW? */ + if (obj->instances >= instance) { + address = obj->chip_addr + + (obj->size + 1) * instance; + } else { + return 0; + } + } + object_table_index++; + } + return address; +} + +/* + * Reads a block of bytes from given address from mXT chip. If we are + * reading from message window, and previous read was from message window, + * there's no need to write the address pointer: the mXT chip will + * automatically set the address pointer back to message window start. + */ + +static int mxt_read_block(struct i2c_client *client, + u16 addr, u16 length, u8 *value) +{ + struct i2c_adapter *adapter = client->adapter; + struct i2c_msg msg[2]; + __le16 le_addr; + struct mxt_data *mxt; + + mxt = i2c_get_clientdata(client); + + if (mxt != NULL) { + if ((mxt->last_read_addr == addr) && + (addr == mxt->msg_proc_addr)) { + if (i2c_master_recv(client, value, length) == length) + return length; + else + return -EIO; + } else { + mxt->last_read_addr = addr; + } + } + + mxt_debug(DEBUG_TRACE, "Writing address pointer & reading %d bytes " + "in on i2c transaction...\n", length); + + le_addr = cpu_to_le16(addr); + msg[0].addr = client->addr; + msg[0].flags = 0x00; + msg[0].len = 2; + msg[0].buf = (u8 *) &le_addr; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = (u8 *) value; + if (i2c_transfer(adapter, msg, 2) == 2) + return length; + else + return -EIO; + +} + +/* Reads a block of bytes from current address from mXT chip. */ + +static int mxt_read_block_wo_addr(struct i2c_client *client, + u16 length, u8 *value) +{ + + if (i2c_master_recv(client, value, length) == length) { + mxt_debug(DEBUG_TRACE, "I2C block read ok\n"); + return length; + } else { + mxt_debug(DEBUG_INFO, "I2C block read failed\n"); + return -EIO; + } + +} + +/* Writes one byte to given address in mXT chip. */ + +static int mxt_write_byte(struct i2c_client *client, u16 addr, u8 value) +{ + struct { + __le16 le_addr; + u8 data; + + } i2c_byte_transfer; + + struct mxt_data *mxt; + + mxt = i2c_get_clientdata(client); + if (mxt != NULL) + mxt->last_read_addr = -1; + i2c_byte_transfer.le_addr = cpu_to_le16(addr); + i2c_byte_transfer.data = value; + if (i2c_master_send(client, (u8 *) &i2c_byte_transfer, 3) == 3) + return 0; + else + return -EIO; +} + +/* Writes a block of bytes (max 256) to given address in mXT chip. */ +static int mxt_write_block(struct i2c_client *client, + u16 addr, u16 length, u8 *value) +{ + int i; + struct { + __le16 le_addr; + u8 data[256]; + + } i2c_block_transfer; + + struct mxt_data *mxt; + + mxt_debug(DEBUG_TRACE, "Writing %d bytes to %d...", length, addr); + if (length > 256) + return -EINVAL; + mxt = i2c_get_clientdata(client); + if (mxt != NULL) + mxt->last_read_addr = -1; + for (i = 0; i < length; i++) + i2c_block_transfer.data[i] = *value++; + i2c_block_transfer.le_addr = cpu_to_le16(addr); + i = i2c_master_send(client, (u8 *) &i2c_block_transfer, length + 2); + if (i == (length + 2)) + return length; + else + return -EIO; +} + +/* Calculates the CRC value for mXT infoblock. */ +int calculate_infoblock_crc(u32 *crc_result, u8 *data, int crc_area_size) +{ + u32 crc = 0; + int i; + + for (i = 0; i < (crc_area_size - 1); i = i + 2) + crc = CRC_24(crc, *(data + i), *(data + i + 1)); + /* If uneven size, pad with zero */ + if (crc_area_size & 0x0001) + crc = CRC_24(crc, *(data + i), 0); + /* Return only 24 bits of CRC. */ + *crc_result = (crc & 0x00FFFFFF); + + return 0; +} + +void process_T9_message(u8 *message, struct mxt_data *mxt, int last_touch) +{ + + struct input_dev *input; + u8 status; + u16 xpos = 0xFFFF; + u16 ypos = 0xFFFF; + u8 touch_size = 255; + u8 touch_number; + u8 amplitude; + u8 report_id; + + static int stored_size[10]; + static int stored_x[10]; + static int stored_y[10]; + int i; + int active_touches = 0; + /* + * If the 'last_touch' flag is set, we have received + all the touch messages + * there are available in this cycle, so send the + events for touches that are + * active. + */ + if (last_touch) { + for (i = 0; i < 10; i++) { + if (stored_size[i]) { + active_touches++; + input_report_abs(mxt->input, ABS_MT_TRACKING_ID, + i); + input_report_abs(mxt->input, ABS_MT_TOUCH_MAJOR, + stored_size[i]); + input_report_abs(mxt->input, ABS_MT_POSITION_X, + stored_x[i]); + input_report_abs(mxt->input, ABS_MT_POSITION_Y, + stored_y[i]); + input_mt_sync(mxt->input); + } + } + if (active_touches) + input_sync(mxt->input); + else { + input_mt_sync(mxt->input); + input_sync(mxt->input); + } + + } else { + + input = mxt->input; + status = message[MXT_MSG_T9_STATUS]; + report_id = message[0]; + + if (status & MXT_MSGB_T9_SUPPRESS) { + /* Touch has been suppressed by grip/face */ + /* detection */ + mxt_debug(DEBUG_TRACE, "SUPRESS"); + } else { + xpos = message[MXT_MSG_T9_XPOSMSB] * 16 + + ((message[MXT_MSG_T9_XYPOSLSB] >> 4) & 0xF); + ypos = message[MXT_MSG_T9_YPOSMSB] * 16 + + ((message[MXT_MSG_T9_XYPOSLSB] >> 0) & 0xF); + if (mxt->max_x_val < 1024) + xpos >>= 2; + if (mxt->max_y_val < 1024) + ypos >>= 2; + + touch_number = message[MXT_MSG_REPORTID] - + mxt->rid_map[report_id].first_rid; + + stored_x[touch_number] = xpos; + stored_y[touch_number] = ypos; + + if (status & MXT_MSGB_T9_DETECT) { + /* + * TODO: more precise touch size calculation? + * mXT224 reports the number of touched nodes, + * so the exact value for touch ellipse major + * axis length would be 2*sqrt(touch_size/pi) + * (assuming round touch shape). + */ + touch_size = message[MXT_MSG_T9_TCHAREA]; + touch_size = touch_size >> 2; + if (!touch_size) + touch_size = 1; + + stored_size[touch_number] = touch_size; + + if (status & MXT_MSGB_T9_AMP) + /* Amplitude of touch has changed */ + amplitude = + message[MXT_MSG_T9_TCHAMPLITUDE]; + } + + if (status & MXT_MSGB_T9_RELEASE) { + /* The previously reported touch has + been removed. */ + stored_size[touch_number] = 0; + } + } + + if (status & MXT_MSGB_T9_SUPPRESS) { + mxt_debug(DEBUG_TRACE, "SUPRESS"); + } else { + if (status & MXT_MSGB_T9_DETECT) { + mxt_debug(DEBUG_TRACE, "DETECT:%s%s%s%s", + ((status & MXT_MSGB_T9_PRESS) ? + " PRESS" : ""), + ((status & MXT_MSGB_T9_MOVE) ? " MOVE" + : ""), + ((status & MXT_MSGB_T9_AMP) ? " AMP" : + ""), + ((status & MXT_MSGB_T9_VECTOR) ? + " VECT" : "")); + + } else if (status & MXT_MSGB_T9_RELEASE) { + mxt_debug(DEBUG_TRACE, "RELEASE"); + } + } + mxt_debug(DEBUG_TRACE, "X=%d, Y=%d, TOUCHSIZE=%d", + xpos, ypos, touch_size); + } + return; +} + +int process_message(u8 *message, u8 object, struct mxt_data *mxt) +{ + struct i2c_client *client; + u8 status; + u16 xpos = 0xFFFF; + u16 ypos = 0xFFFF; + u8 event; + u8 length; + u8 report_id; + + client = mxt->client; + length = mxt->message_size; + report_id = message[0]; + + if ((mxt->nontouch_msg_only == 0) || (!IS_TOUCH_OBJECT(object))) { + mutex_lock(&mxt->msg_mutex); + /* Copy the message to buffer */ + if (mxt->msg_buffer_startp < MXT_MESSAGE_BUFFER_SIZE) + mxt->msg_buffer_startp++; + else + mxt->msg_buffer_startp = 0; + + if (mxt->msg_buffer_startp == mxt->msg_buffer_endp) { + mxt_debug(DEBUG_TRACE, + "Message buf full, discarding last entry.\n"); + if (mxt->msg_buffer_endp < MXT_MESSAGE_BUFFER_SIZE) + mxt->msg_buffer_endp++; + else + mxt->msg_buffer_endp = 0; + } + memcpy((mxt->messages + mxt->msg_buffer_startp * length), + message, length); + mutex_unlock(&mxt->msg_mutex); + } + + switch (object) { + case MXT_GEN_COMMANDPROCESSOR_T6: + status = message[1]; + if (status & MXT_MSGB_T6_COMSERR) + dev_err(&client->dev, "maXTouch checksum error\n"); + if (status & MXT_MSGB_T6_CFGERR) { + /* + * Configuration error. A proper configuration + * needs to be written to chip and backed up. Refer + * to protocol document for further info. + */ + dev_err(&client->dev, "maXTouch configuration error\n"); + } + if (status & MXT_MSGB_T6_CAL) { + /* Calibration in action, no need to react */ + dev_info(&client->dev, + "maXTouch calibration in progress\n"); + } + if (status & MXT_MSGB_T6_SIGERR) { + /* + * Signal acquisition error, something is seriously + * wrong, not much we can in the driver to correct + * this + */ + dev_err(&client->dev, "maXTouch acquisition error\n"); + } + if (status & MXT_MSGB_T6_OFL) { + /* + * Cycle overflow, the acquisition is too short. + * Can happen temporarily when there's a complex + * touch shape on the screen requiring lots of + * processing. + */ + dev_err(&client->dev, "maXTouch cycle overflow\n"); + } + if (status & MXT_MSGB_T6_RESET) { + /* Chip has reseted, no need to react. */ + dev_info(&client->dev, "maXTouch chip reset\n"); + } + if (status == 0) { + /* Chip status back to normal. */ + dev_info(&client->dev, "maXTouch status normal\n"); + } + break; + + case MXT_TOUCH_MULTITOUCHSCREEN_T9: + process_T9_message(message, mxt, 0); + break; + + case MXT_SPT_GPIOPWM_T19: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Receiving GPIO message\n"); + break; + + case MXT_PROCI_GRIPFACESUPPRESSION_T20: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving face suppression msg\n"); + break; + + case MXT_PROCG_NOISESUPPRESSION_T22: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving noise suppression msg\n"); + status = message[MXT_MSG_T22_STATUS]; + if (status & MXT_MSGB_T22_FHCHG) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: Freq changed\n"); + } + if (status & MXT_MSGB_T22_GCAFERR) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: High noise " "level\n"); + } + if (status & MXT_MSGB_T22_FHERR) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: Freq changed - " + "Noise level too high\n"); + } + break; + + case MXT_PROCI_ONETOUCHGESTUREPROCESSOR_T24: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving one-touch gesture msg\n"); + + event = message[MXT_MSG_T24_STATUS] & 0x0F; + xpos = message[MXT_MSG_T24_XPOSMSB] * 16 + + ((message[MXT_MSG_T24_XYPOSLSB] >> 4) & 0x0F); + ypos = message[MXT_MSG_T24_YPOSMSB] * 16 + + ((message[MXT_MSG_T24_XYPOSLSB] >> 0) & 0x0F); + xpos >>= 2; + ypos >>= 2; + + switch (event) { + case MT_GESTURE_RESERVED: + break; + case MT_GESTURE_PRESS: + break; + case MT_GESTURE_RELEASE: + break; + case MT_GESTURE_TAP: + break; + case MT_GESTURE_DOUBLE_TAP: + break; + case MT_GESTURE_FLICK: + break; + case MT_GESTURE_DRAG: + break; + case MT_GESTURE_SHORT_PRESS: + break; + case MT_GESTURE_LONG_PRESS: + break; + case MT_GESTURE_REPEAT_PRESS: + break; + case MT_GESTURE_TAP_AND_PRESS: + break; + case MT_GESTURE_THROW: + break; + default: + break; + } + break; + + case MXT_SPT_SELFTEST_T25: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Receiving Self-Test msg\n"); + + if (message[MXT_MSG_T25_STATUS] == MXT_MSGR_T25_OK) { + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "maXTouch: Self-Test OK\n"); + + } else { + dev_err(&client->dev, + "maXTouch: Self-Test Failed [%02x]:" + "{%02x,%02x,%02x,%02x,%02x}\n", + message[MXT_MSG_T25_STATUS], + message[MXT_MSG_T25_STATUS + 0], + message[MXT_MSG_T25_STATUS + 1], + message[MXT_MSG_T25_STATUS + 2], + message[MXT_MSG_T25_STATUS + 3], + message[MXT_MSG_T25_STATUS + 4] + ); + } + break; + + case MXT_PROCI_TWOTOUCHGESTUREPROCESSOR_T27: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, + "Receiving 2-touch gesture message\n"); + break; + + case MXT_SPT_CTECONFIG_T28: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Receiving CTE message...\n"); + status = message[MXT_MSG_T28_STATUS]; + if (status & MXT_MSGB_T28_CHKERR) + dev_err(&client->dev, + "maXTouch: Power-Up CRC failure\n"); + + break; + default: + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "maXTouch: Unknown message!\n"); + + break; + } + + return 0; +} + +/* + * Processes messages when the interrupt line (CHG) is asserted. Keeps + * reading messages until a message with report ID 0xFF is received, + * which indicates that there is no more new messages. + * + */ + +static void mxt_worker(struct work_struct *work) +{ + struct mxt_data *mxt; + struct i2c_client *client; + + u8 *message; + u16 message_length; + u16 message_addr; + u8 report_id; + u8 object; + int error; + int i; + char *message_string; + char *message_start; + + int n = 0; + + message = NULL; + mxt = container_of(work, struct mxt_data, dwork.work); + disable_irq(mxt->irq); + client = mxt->client; + message_addr = mxt->msg_proc_addr; + message_length = mxt->message_size; + + if (message_length < 256) { + message = kmalloc(message_length, GFP_KERNEL); + if (message == NULL) { + dev_err(&client->dev, "Error allocating memory\n"); + return; + } + } else { + dev_err(&client->dev, + "Message length larger than 256 bytes not supported\n"); + return; + } + + mxt_debug("maXTouch worker active: \n"); + do { + /* Read next message, reread on failure. */ + /* -1 TO WORK AROUND A BUG ON 0.9 FW MESSAGING, needs */ + /* to be changed back if checksum is read */ + mxt->message_counter++; + for (i = 1; i < I2C_RETRY_COUNT; i++) { + error = mxt_read_block(client, + message_addr, + message_length - 1, message); + if (error >= 0) + break; + mxt->read_fail_counter++; + dev_err(&client->dev, + "Failure reading maxTouch device\n"); + } + if (error < 0) { + kfree(message); + return; + } + + if (mxt->address_pointer != message_addr) + mxt->valid_ap = 0; + report_id = message[0]; + + if (debug >= DEBUG_RAW) { + mxt_debug(DEBUG_RAW, "%s message [msg count: %08x]:", + REPORT_ID_TO_OBJECT_NAME(report_id, mxt), + mxt->message_counter); + /* 5 characters per one byte */ + message_string = kmalloc(message_length * 5, + GFP_KERNEL); + if (message_string == NULL) { + dev_err(&client->dev, + "Error allocating memory\n"); + kfree(message); + return; + } + message_start = message_string; + for (i = 0; i < message_length; i++) { + message_string += + sprintf(message_string, + "0x%02X ", message[i]); + } + mxt_debug(DEBUG_RAW, "%s", message_start); + kfree(message_start); + } + + if ((report_id != MXT_END_OF_MESSAGES) && (report_id != 0)) { + memcpy(mxt->last_message, message, message_length); + mxt->new_msgs = 1; + smp_wmb(); + /* Get type of object and process the message */ + object = mxt->rid_map[report_id].object; + process_message(message, object, mxt); + } + mxt_debug(DEBUG_TRACE, "chgline: %d\n", mxt->read_chg()); + } while (comms ? (mxt->read_chg() == 0) : + ((report_id != MXT_END_OF_MESSAGES) && (report_id != 0))); + + /* All messages processed, send the events) */ + process_T9_message(NULL, mxt, 1); + + kfree(message); + enable_irq(mxt->irq); + /* Make sure we don't miss any interrupts and read changeline. */ + if (mxt->read_chg() == 0) + schedule_delayed_work(&mxt->dwork, 0); +} + +/* + * The maXTouch device will signal the host about a new message by asserting + * the CHG line. This ISR schedules a worker routine to read the message when + * that happens. + */ + +static irqreturn_t mxt_irq_handler(int irq, void *_mxt) +{ + struct mxt_data *mxt = _mxt; + + mxt->irq_counter++; + if (mxt->valid_interrupt()) { + /* Send the signal only if falling edge generated the irq. */ + cancel_delayed_work(&mxt->dwork); + schedule_delayed_work(&mxt->dwork, 0); + mxt->valid_irq_counter++; + } else { + mxt->invalid_irq_counter++; + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +/******************************************************************************/ +/* Initialization of driver */ +/******************************************************************************/ + +static int __devinit mxt_identify(struct i2c_client *client, + struct mxt_data *mxt, u8 * id_block_data) +{ + u8 buf[7]; + int error; + int identified; + + identified = 0; + + /* Read Device info to check if chip is valid */ + error = mxt_read_block(client, MXT_ADDR_INFO_BLOCK, MXT_ID_BLOCK_SIZE, + (u8 *) buf); + + if (error < 0) { + mxt->read_fail_counter++; + dev_err(&client->dev, "Failure accessing maXTouch device\n"); + return -EIO; + } + + memcpy(id_block_data, buf, MXT_ID_BLOCK_SIZE); + + mxt->device_info.family_id = buf[0]; + mxt->device_info.variant_id = buf[1]; + mxt->device_info.major = ((buf[2] >> 4) & 0x0F); + mxt->device_info.minor = (buf[2] & 0x0F); + mxt->device_info.build = buf[3]; + mxt->device_info.x_size = buf[4]; + mxt->device_info.y_size = buf[5]; + mxt->device_info.num_objs = buf[6]; + mxt->device_info.num_nodes = mxt->device_info.x_size * + mxt->device_info.y_size; + + /* + * Check Family & Variant Info; warn if not recognized but + * still continue. + */ + + /* MXT224 */ + if (mxt->device_info.family_id == MXT224_FAMILYID) { + strcpy(mxt->device_info.family_name, "mXT224"); + + if (mxt->device_info.variant_id == MXT224_CAL_VARIANTID) { + strcpy(mxt->device_info.variant_name, "Calibrated"); + } else if (mxt->device_info.variant_id == + MXT224_UNCAL_VARIANTID) { + strcpy(mxt->device_info.variant_name, "Uncalibrated"); + } else { + dev_err(&client->dev, + "Warning: maXTouch Variant ID [%d] not " + "supported\n", mxt->device_info.variant_id); + strcpy(mxt->device_info.variant_name, "UNKNOWN"); + /* identified = -ENXIO; */ + } + + /* MXT1386 */ + } else if (mxt->device_info.family_id == MXT1386_FAMILYID) { + strcpy(mxt->device_info.family_name, "mXT1386"); + + if (mxt->device_info.variant_id == MXT1386_CAL_VARIANTID) { + strcpy(mxt->device_info.variant_name, "Calibrated"); + } else { + dev_err(&client->dev, + "Warning: maXTouch Variant ID [%d] not " + "supported\n", mxt->device_info.variant_id); + strcpy(mxt->device_info.variant_name, "UNKNOWN"); + /* identified = -ENXIO; */ + } + /* Unknown family ID! */ + } else { + dev_err(&client->dev, + "Warning: maXTouch Family ID [%d] not supported\n", + mxt->device_info.family_id); + strcpy(mxt->device_info.family_name, "UNKNOWN"); + strcpy(mxt->device_info.variant_name, "UNKNOWN"); + /* identified = -ENXIO; */ + } + + dev_info(&client->dev, + "Atmel maXTouch (Family %s (%X), Variant %s (%X)) Firmware " + "version [%d.%d] Build %d\n", + mxt->device_info.family_name, + mxt->device_info.family_id, + mxt->device_info.variant_name, + mxt->device_info.variant_id, + mxt->device_info.major, + mxt->device_info.minor, mxt->device_info.build); + dev_info(&client->dev, + "Atmel maXTouch Configuration " + "[X: %d] x [Y: %d]\n", + mxt->device_info.x_size, mxt->device_info.y_size); + return identified; +} + +/* + * Reads the object table from maXTouch chip to get object data like + * address, size, report id. For Info Block CRC calculation, already read + * id data is passed to this function too (Info Block consists of the ID + * block and object table). + * + */ +static int __devinit mxt_read_object_table(struct i2c_client *client, + struct mxt_data *mxt, + u8 *raw_id_data) +{ + u16 report_id_count; + u8 buf[MXT_OBJECT_TABLE_ELEMENT_SIZE]; + u8 *raw_ib_data; + u8 object_type; + u16 object_address; + u16 object_size; + u8 object_instances; + u8 object_report_ids; + u16 object_info_address; + u32 crc; + u32 calculated_crc; + int i; + int error; + + u8 object_instance; + u8 object_report_id; + u8 report_id; + int first_report_id; + int ib_pointer; + struct mxt_object *object_table; + + mxt_debug(DEBUG_TRACE, "maXTouch driver reading configuration\n"); + + object_table = kzalloc(sizeof(struct mxt_object) * + mxt->device_info.num_objs, GFP_KERNEL); + if (object_table == NULL) { + printk(KERN_WARNING "maXTouch: Memory allocation failed!\n"); + error = -ENOMEM; + goto err_object_table_alloc; + } + + raw_ib_data = kmalloc(MXT_OBJECT_TABLE_ELEMENT_SIZE * + mxt->device_info.num_objs + MXT_ID_BLOCK_SIZE, + GFP_KERNEL); + if (raw_ib_data == NULL) { + printk(KERN_WARNING "maXTouch: Memory allocation failed!\n"); + error = -ENOMEM; + goto err_ib_alloc; + } + + /* Copy the ID data for CRC calculation. */ + memcpy(raw_ib_data, raw_id_data, MXT_ID_BLOCK_SIZE); + ib_pointer = MXT_ID_BLOCK_SIZE; + + mxt->object_table = object_table; + + mxt_debug(DEBUG_TRACE, "maXTouch driver Memory allocated\n"); + + object_info_address = MXT_ADDR_OBJECT_TABLE; + + report_id_count = 0; + for (i = 0; i < mxt->device_info.num_objs; i++) { + mxt_debug(DEBUG_TRACE, "Reading maXTouch at [0x%04x]: ", + object_info_address); + + error = mxt_read_block(client, object_info_address, + MXT_OBJECT_TABLE_ELEMENT_SIZE, buf); + + if (error < 0) { + mxt->read_fail_counter++; + dev_err(&client->dev, + "maXTouch Object %d could not be read\n", i); + error = -EIO; + goto err_object_read; + } + + memcpy(raw_ib_data + ib_pointer, buf, + MXT_OBJECT_TABLE_ELEMENT_SIZE); + ib_pointer += MXT_OBJECT_TABLE_ELEMENT_SIZE; + + object_type = buf[0]; + object_address = (buf[2] << 8) + buf[1]; + object_size = buf[3] + 1; + object_instances = buf[4] + 1; + object_report_ids = buf[5]; + mxt_debug(DEBUG_TRACE, "Type=%03d, Address=0x%04x, " + "Size=0x%02x, %d instances, %d report id's\n", + object_type, + object_address, + object_size, object_instances, object_report_ids); + + /* TODO: check whether object is known and supported? */ + + /* Save frequently needed info. */ + if (object_type == MXT_GEN_MESSAGEPROCESSOR_T5) { + mxt->msg_proc_addr = object_address; + mxt->message_size = object_size; + printk(KERN_ALERT "message length: %d", object_size); + } + + object_table[i].type = object_type; + object_table[i].chip_addr = object_address; + object_table[i].size = object_size; + object_table[i].instances = object_instances; + object_table[i].num_report_ids = object_report_ids; + report_id_count += object_instances * object_report_ids; + + object_info_address += MXT_OBJECT_TABLE_ELEMENT_SIZE; + } + + mxt->rid_map = + kzalloc(sizeof(struct report_id_map) * (report_id_count + 1), + /* allocate for report_id 0, even if not used */ + GFP_KERNEL); + if (mxt->rid_map == NULL) { + printk(KERN_WARNING "maXTouch: Can't allocate memory!\n"); + error = -ENOMEM; + goto err_rid_map_alloc; + } + + mxt->messages = kzalloc(mxt->message_size * MXT_MESSAGE_BUFFER_SIZE, + GFP_KERNEL); + if (mxt->messages == NULL) { + printk(KERN_WARNING "maXTouch: Can't allocate memory!\n"); + error = -ENOMEM; + goto err_msg_alloc; + } + + mxt->last_message = kzalloc(mxt->message_size, GFP_KERNEL); + if (mxt->last_message == NULL) { + printk(KERN_WARNING "maXTouch: Can't allocate memory!\n"); + error = -ENOMEM; + goto err_msg_alloc; + } + + mxt->report_id_count = report_id_count; + if (report_id_count > 254) { /* 0 & 255 are reserved */ + dev_err(&client->dev, + "Too many maXTouch report id's [%d]\n", + report_id_count); + error = -ENXIO; + goto err_max_rid; + } + + /* Create a mapping from report id to object type */ + report_id = 1; /* Start from 1, 0 is reserved. */ + + /* Create table associating report id's with objects & instances */ + for (i = 0; i < mxt->device_info.num_objs; i++) { + for (object_instance = 0; + object_instance < object_table[i].instances; + object_instance++) { + first_report_id = report_id; + for (object_report_id = 0; + object_report_id < object_table[i].num_report_ids; + object_report_id++) { + mxt->rid_map[report_id].object = + object_table[i].type; + mxt->rid_map[report_id].instance = + object_instance; + mxt->rid_map[report_id].first_rid = + first_report_id; + report_id++; + } + } + } + + /* Read 3 byte CRC */ + error = mxt_read_block(client, object_info_address, 3, buf); + if (error < 0) { + mxt->read_fail_counter++; + dev_err(&client->dev, "Error reading CRC\n"); + } + + crc = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + if (calculate_infoblock_crc(&calculated_crc, raw_ib_data, ib_pointer)) { + printk(KERN_WARNING "Error while calculating CRC!\n"); + calculated_crc = 0; + } + kfree(raw_ib_data); + + mxt_debug(DEBUG_TRACE, "\nReported info block CRC = 0x%6X\n", crc); + mxt_debug(DEBUG_TRACE, "Calculated info block CRC = 0x%6X\n\n", + calculated_crc); + + if (crc == calculated_crc) { + mxt->info_block_crc = crc; + } else { + mxt->info_block_crc = 0; + printk(KERN_ALERT "maXTouch: Info block CRC invalid!\n"); + } + + if (debug >= DEBUG_VERBOSE) { + + dev_info(&client->dev, "maXTouch: %d Objects\n", + mxt->device_info.num_objs); + + for (i = 0; i < mxt->device_info.num_objs; i++) { + dev_info(&client->dev, "Type:\t\t\t[%d]: %s\n", + object_table[i].type, + object_type_name[object_table[i].type]); + dev_info(&client->dev, "\tAddress:\t0x%04X\n", + object_table[i].chip_addr); + dev_info(&client->dev, "\tSize:\t\t%d Bytes\n", + object_table[i].size); + dev_info(&client->dev, "\tInstances:\t%d\n", + object_table[i].instances); + dev_info(&client->dev, "\tReport Id's:\t%d\n", + object_table[i].num_report_ids); + } + } + + return 0; + + err_max_rid: + kfree(mxt->last_message); + err_msg_alloc: + kfree(mxt->rid_map); + err_rid_map_alloc: + err_object_read: + kfree(raw_ib_data); + err_ib_alloc: + kfree(object_table); + err_object_table_alloc: + return error; +} + +static int __devinit mxt_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mxt_data *mxt; + struct mxt_platform_data *pdata; + struct input_dev *input; + u8 *id_data; + int error; + + mxt_debug(DEBUG_INFO, "mXT224: mxt_probe\n"); + + if (client == NULL) { + pr_debug("maXTouch: client == NULL\n"); + return -EINVAL; + } else if (client->adapter == NULL) { + pr_debug("maXTouch: client->adapter == NULL\n"); + return -EINVAL; + } else if (&client->dev == NULL) { + pr_debug("maXTouch: client->dev == NULL\n"); + return -EINVAL; + } else if (&client->adapter->dev == NULL) { + pr_debug("maXTouch: client->adapter->dev == NULL\n"); + return -EINVAL; + } else if (id == NULL) { + pr_debug("maXTouch: id == NULL\n"); + return -EINVAL; + } + + mxt_debug(DEBUG_INFO, "maXTouch driver\n"); + mxt_debug(DEBUG_INFO, "\t \"%s\"\n", client->name); + mxt_debug(DEBUG_INFO, "\taddr:\t0x%04x\n", client->addr); + mxt_debug(DEBUG_INFO, "\tirq:\t%d\n", client->irq); + mxt_debug(DEBUG_INFO, "\tflags:\t0x%04x\n", client->flags); + mxt_debug(DEBUG_INFO, "\tadapter:\"%s\"\n", client->adapter->name); + mxt_debug(DEBUG_INFO, "\tdevice:\t\"%s\"\n", client->dev.init_name); + + /* Check if the I2C bus supports BYTE transfer */ + error = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); + dev_info(&client->dev, "RRC: i2c_check_functionality = %i\n", error); + error = 0xff; +/* + if (!error) { + dev_err(&client->dev, "maXTouch driver\n"); + dev_err(&client->dev, "\t \"%s\"\n", client->name); + dev_err(&client->dev, "\taddr:\t0x%04x\n", client->addr); + dev_err(&client->dev, "\tirq:\t%d\n", client->irq); + dev_err(&client->dev, "\tflags:\t0x%04x\n", client->flags); + dev_err(&client->dev, "\tadapter:\"%s\"\n", + client->adapter->name); + dev_err(&client->dev, "\tdevice:\t\"%s\"\n", + client->dev.init_name); + dev_err(&client->dev, "%s adapter not supported\n", + dev_driver_string(&client->adapter->dev)); + return -ENODEV; + } +*/ + mxt_debug(DEBUG_TRACE, "maXTouch driver functionality OK\n"); + + /* Allocate structure - we need it to identify device */ + mxt = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); + if (mxt == NULL) { + dev_err(&client->dev, "insufficient memory\n"); + error = -ENOMEM; + goto err_mxt_alloc; + } + + id_data = kmalloc(MXT_ID_BLOCK_SIZE, GFP_KERNEL); + if (id_data == NULL) { + dev_err(&client->dev, "insufficient memory\n"); + error = -ENOMEM; + goto err_id_alloc; + } + + input = input_allocate_device(); + if (!input) { + dev_err(&client->dev, "error allocating input device\n"); + error = -ENOMEM; + goto err_input_dev_alloc; + } + + /* Initialize Platform data */ + + pdata = client->dev.platform_data; + if (pdata == NULL) { + dev_err(&client->dev, "platform data is required!\n"); + error = -EINVAL; + goto err_pdata; + } + if (debug >= DEBUG_TRACE) + printk(KERN_INFO "Platform OK: pdata = 0x%08x\n", + (unsigned int)pdata); + + mxt->read_fail_counter = 0; + mxt->message_counter = 0; + mxt->max_x_val = pdata->max_x; + mxt->max_y_val = pdata->max_y; + + /* Get data that is defined in board specific code. */ + mxt->init_hw = pdata->init_platform_hw; + mxt->exit_hw = pdata->exit_platform_hw; + mxt->read_chg = pdata->read_chg; + + if (pdata->valid_interrupt != NULL) + mxt->valid_interrupt = pdata->valid_interrupt; + else + mxt->valid_interrupt = mxt_valid_interrupt_dummy; + + if (mxt->init_hw != NULL) + mxt->init_hw(); + + if (debug >= DEBUG_TRACE) + printk(KERN_INFO "maXTouch driver identifying chip\n"); + + if (mxt_identify(client, mxt, id_data) < 0) { + dev_err(&client->dev, "Chip could not be identified\n"); + error = -ENODEV; + goto err_identify; + } + /* Chip is valid and active. */ + if (debug >= DEBUG_TRACE) + printk(KERN_INFO "maXTouch driver allocating input device\n"); + + mxt->client = client; + mxt->input = input; + + INIT_DELAYED_WORK(&mxt->dwork, mxt_worker); + mutex_init(&mxt->debug_mutex); + mutex_init(&mxt->msg_mutex); + mxt_debug(DEBUG_TRACE, "maXTouch driver creating device name\n"); + + snprintf(mxt->phys_name, + sizeof(mxt->phys_name), "%s/input0", dev_name(&client->dev) + ); + input->name = "Atmel maXTouch Touchscreen controller"; + input->phys = mxt->phys_name; + input->id.bustype = BUS_I2C; + input->dev.parent = &client->dev; + + mxt_debug(DEBUG_INFO, "maXTouch name: \"%s\"\n", input->name); + mxt_debug(DEBUG_INFO, "maXTouch phys: \"%s\"\n", input->phys); + mxt_debug(DEBUG_INFO, "maXTouch driver setting abs parameters\n"); + + set_bit(BTN_TOUCH, input->keybit); + + /* Single touch */ + input_set_abs_params(input, ABS_X, 0, mxt->max_x_val, 0, 0); + input_set_abs_params(input, ABS_Y, 0, mxt->max_y_val, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, MXT_MAX_REPORTED_PRESSURE, + 0, 0); + input_set_abs_params(input, ABS_TOOL_WIDTH, 0, MXT_MAX_REPORTED_WIDTH, + 0, 0); + + /* Multitouch */ + input_set_abs_params(input, ABS_MT_POSITION_X, 0, mxt->max_x_val, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, mxt->max_y_val, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, MXT_MAX_TOUCH_SIZE, + 0, 0); + input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, MXT_MAX_NUM_TOUCHES, + 0, 0); + + __set_bit(EV_ABS, input->evbit); + __set_bit(EV_SYN, input->evbit); + __set_bit(EV_KEY, input->evbit); + + mxt_debug(DEBUG_TRACE, "maXTouch driver setting client data\n"); + i2c_set_clientdata(client, mxt); + mxt_debug(DEBUG_TRACE, "maXTouch driver setting drv data\n"); + input_set_drvdata(input, mxt); + mxt_debug(DEBUG_TRACE, "maXTouch driver input register device\n"); + error = input_register_device(mxt->input); + if (error < 0) { + dev_err(&client->dev, "Failed to register input device\n"); + goto err_register_device; + } + + error = mxt_read_object_table(client, mxt, id_data); + if (error < 0) + goto err_read_ot; + + /* Create debugfs entries. */ + mxt->debug_dir = debugfs_create_dir("maXTouch", NULL); + if (mxt->debug_dir == -ENODEV) { + /* debugfs is not enabled. */ + printk(KERN_WARNING "debugfs not enabled in kernel\n"); + } else if (mxt->debug_dir == NULL) { + printk(KERN_WARNING "error creating debugfs dir\n"); + } else { + mxt_debug(DEBUG_TRACE, "created \"maXTouch\" debugfs dir\n"); + + debugfs_create_file("deltas", S_IRUSR, mxt->debug_dir, mxt, + &delta_fops); + debugfs_create_file("refs", S_IRUSR, mxt->debug_dir, mxt, + &refs_fops); + } + + /* Create character device nodes for reading & writing registers */ + mxt->mxt_class = class_create(THIS_MODULE, "maXTouch_memory"); + /* 2 numbers; one for memory and one for messages */ + error = alloc_chrdev_region(&mxt->dev_num, 0, 2, "maXTouch_memory"); + mxt_debug(DEBUG_VERBOSE, + "device number %d allocated!\n", MAJOR(mxt->dev_num)); + if (error) + printk(KERN_WARNING "Error registering device\n"); + cdev_init(&mxt->cdev, &mxt_memory_fops); + cdev_init(&mxt->cdev_messages, &mxt_message_fops); + + mxt_debug(DEBUG_VERBOSE, "cdev initialized\n"); + mxt->cdev.owner = THIS_MODULE; + mxt->cdev_messages.owner = THIS_MODULE; + + error = cdev_add(&mxt->cdev, mxt->dev_num, 1); + if (error) + printk(KERN_WARNING "Bad cdev\n"); + + error = cdev_add(&mxt->cdev_messages, mxt->dev_num + 1, 1); + if (error) + printk(KERN_WARNING "Bad cdev\n"); + + mxt_debug(DEBUG_VERBOSE, "cdev added\n"); + + device_create(mxt->mxt_class, NULL, MKDEV(MAJOR(mxt->dev_num), 0), NULL, + "maXTouch"); + + device_create(mxt->mxt_class, NULL, MKDEV(MAJOR(mxt->dev_num), 1), NULL, + "maXTouch_messages"); + + mxt->msg_buffer_startp = 0; + mxt->msg_buffer_endp = 0; + + /* Allocate the interrupt */ + mxt_debug(DEBUG_TRACE, "maXTouch driver allocating interrupt...\n"); + mxt->irq = client->irq; + mxt->valid_irq_counter = 0; + mxt->invalid_irq_counter = 0; + mxt->irq_counter = 0; + if (mxt->irq) { + /* Try to request IRQ with falling edge first. This is + * not always supported. If it fails, try with any edge. */ + error = request_irq(mxt->irq, + mxt_irq_handler, + IRQF_TRIGGER_FALLING, + client->dev.driver->name, mxt); + if (error < 0) { + /* TODO: why only 0 works on STK1000? */ + error = request_irq(mxt->irq, + mxt_irq_handler, + 0, client->dev.driver->name, mxt); + } + + if (error < 0) { + dev_err(&client->dev, + "failed to allocate irq %d\n", mxt->irq); + goto err_irq; + } + } + + if (debug > DEBUG_INFO) + dev_info(&client->dev, "touchscreen, irq %d\n", mxt->irq); + + /* Schedule a worker routine to read any messages that might have + * been sent before interrupts were enabled. */ + cancel_delayed_work(&mxt->dwork); + schedule_delayed_work(&mxt->dwork, 0); + kfree(id_data); + + /* + TODO: REMOVE!!!!!!!!!!!!!!!!!!!!!!! + + REMOVE!!!!!!!!!!!!!!!!!!!!!!! + */ + mxt_write_byte(mxt->client, + MXT_BASE_ADDR(MXT_TOUCH_MULTITOUCHSCREEN_T9, mxt), 15); + + return 0; + + err_irq: + kfree(mxt->rid_map); + kfree(mxt->object_table); + kfree(mxt->last_message); + err_read_ot: + err_register_device: + err_identify: + err_pdata: + input_free_device(input); + err_input_dev_alloc: + kfree(id_data); + err_id_alloc: + if (mxt->exit_hw != NULL) + mxt->exit_hw(); + kfree(mxt); + err_mxt_alloc: + return error; +} + +static int __devexit mxt_remove(struct i2c_client *client) +{ + struct mxt_data *mxt; + + mxt = i2c_get_clientdata(client); + + /* Remove debug dir entries */ + debugfs_remove_recursive(mxt->debug_dir); + + if (mxt != NULL) { + + if (mxt->exit_hw != NULL) + mxt->exit_hw(); + + if (mxt->irq) + free_irq(mxt->irq, mxt); + + unregister_chrdev_region(mxt->dev_num, 2); + device_destroy(mxt->mxt_class, MKDEV(MAJOR(mxt->dev_num), 0)); + device_destroy(mxt->mxt_class, MKDEV(MAJOR(mxt->dev_num), 1)); + cdev_del(&mxt->cdev); + cdev_del(&mxt->cdev_messages); + cancel_delayed_work_sync(&mxt->dwork); + input_unregister_device(mxt->input); + class_destroy(mxt->mxt_class); + debugfs_remove(mxt->debug_dir); + + kfree(mxt->rid_map); + kfree(mxt->object_table); + kfree(mxt->last_message); + } + kfree(mxt); + + i2c_set_clientdata(client, NULL); + if (debug >= DEBUG_TRACE) + dev_info(&client->dev, "Touchscreen unregistered\n"); + + return 0; +} + +#if defined(CONFIG_PM) +static int mxt_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct mxt_data *mxt = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + enable_irq_wake(mxt->irq); + + return 0; +} + +static int mxt_resume(struct i2c_client *client) +{ + struct mxt_data *mxt = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + disable_irq_wake(mxt->irq); + + return 0; +} +#else +#define mxt_suspend NULL +#define mxt_resume NULL +#endif + +static const struct i2c_device_id mxt_idtable[] = { + {"maXTouch", 0,}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mxt_idtable); + +static struct i2c_driver mxt_driver = { + .driver = { + .name = "maXTouch", + .owner = THIS_MODULE, + }, + + .id_table = mxt_idtable, + .probe = mxt_probe, + .remove = __devexit_p(mxt_remove), + .suspend = mxt_suspend, + .resume = mxt_resume, + +}; + +static int __init mxt_init(void) +{ + int err; + err = i2c_add_driver(&mxt_driver); + if (err) { + printk(KERN_WARNING "Adding maXTouch driver failed " + "(errno = %d)\n", err); + } else { + mxt_debug(DEBUG_TRACE, "Successfully added driver %s\n", + mxt_driver.driver.name); + } + return err; +} + +static void __exit mxt_cleanup(void) +{ + i2c_del_driver(&mxt_driver); +} + +module_init(mxt_init); +module_exit(mxt_cleanup); + +MODULE_AUTHOR("Iiro Valkonen"); +MODULE_DESCRIPTION("Driver for Atmel maXTouch Touchscreen Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig index ae77e8994dc8..1a122258ad82 100644 --- a/drivers/media/video/tegra/Kconfig +++ b/drivers/media/video/tegra/Kconfig @@ -8,3 +8,10 @@ config TEGRA_CAMERA Enables support for the Tegra camera interface If unsure, say Y + +config VIDEO_OV5650 + tristate "OV5650 camera sensor support" + depends on I2C && ARCH_TEGRA + ---help--- + This is a driver for the Omnivision OV5650 5MP camera sensor + for use with the tegra isp. diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile index 68b5c42b0e7a..1ff76a82df40 100644 --- a/drivers/media/video/tegra/Makefile +++ b/drivers/media/video/tegra/Makefile @@ -1,2 +1,6 @@ +# +# Makefile for the video capture/playback device drivers. +# obj-y += avp/ -obj-$(CONFIG_TEGRA_CAMERA) += tegra_camera.o +obj-$(CONFIG_TEGRA_CAMERA) += tegra_camera.o +obj-$(CONFIG_VIDEO_OV5650) += ov5650.o diff --git a/drivers/media/video/tegra/avp/avp.c b/drivers/media/video/tegra/avp/avp.c index ced838ac6e2b..29cbfc01e44f 100644 --- a/drivers/media/video/tegra/avp/avp.c +++ b/drivers/media/video/tegra/avp/avp.c @@ -111,7 +111,7 @@ struct avp_info { struct trpc_node *rpc_node; struct miscdevice misc_dev; - bool opened; + int refcount; struct mutex open_lock; spinlock_t state_lock; @@ -1328,16 +1328,13 @@ static int tegra_avp_open(struct inode *inode, struct file *file) nonseekable_open(inode, file); mutex_lock(&avp->open_lock); - /* only one userspace client at a time */ - if (avp->opened) { - pr_err("%s: already have client, aborting\n", __func__); - ret = -EBUSY; - goto out; - } - ret = avp_init(avp, TEGRA_AVP_KERNEL_FW); - avp->opened = !ret; -out: + if (!avp->refcount) + ret = avp_init(avp, TEGRA_AVP_KERNEL_FW); + + if (!ret) + avp->refcount++; + mutex_unlock(&avp->open_lock); return ret; } @@ -1349,15 +1346,16 @@ static int tegra_avp_release(struct inode *inode, struct file *file) pr_info("%s: release\n", __func__); mutex_lock(&avp->open_lock); - if (!avp->opened) { + if (!avp->refcount) { pr_err("%s: releasing while in invalid state\n", __func__); ret = -EINVAL; goto out; } + if (avp->refcount > 0) + avp->refcount--; + if (!avp->refcount) + avp_uninit(avp); - avp_uninit(avp); - - avp->opened = false; out: mutex_unlock(&avp->open_lock); return ret; @@ -1681,12 +1679,11 @@ static int tegra_avp_remove(struct platform_device *pdev) return 0; mutex_lock(&avp->open_lock); - if (avp->opened) { + if (avp->refcount) { mutex_unlock(&avp->open_lock); return -EBUSY; } /* ensure that noone can open while we tear down */ - avp->opened = true; mutex_unlock(&avp->open_lock); misc_deregister(&avp->misc_dev); diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c new file mode 100644 index 000000000000..579249da8f43 --- /dev/null +++ b/drivers/media/video/tegra/ov5650.c @@ -0,0 +1,765 @@ +/* + * ov5650.c - ov5650 sensor driver + * + * Copyright (C) 2010 Google Inc. + * + * Contributors: + * Rebecca Schultz Zavin <rebecca@android.com> + * + * Leverage OV9640.c + * + * 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/delay.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <media/ov5650.h> + +struct ov5650_reg { + u16 addr; + u16 val; +}; + +struct ov5650_info { + int mode; + struct i2c_client *i2c_client; + struct ov5650_platform_data *pdata; +}; + +#define OV5650_TABLE_WAIT_MS 0 +#define OV5650_TABLE_END 1 +#define OV5650_MAX_RETRIES 3 + +static struct ov5650_reg mode_start[] = { + {0x3008, 0x82}, /* reset registers pg 72 */ + {OV5650_TABLE_WAIT_MS, 5}, + {0x3008, 0x42}, /* register power down pg 72 */ + {OV5650_TABLE_WAIT_MS, 5}, + {0x3103, 0x93}, /* power up system clock from PLL page 77 */ + {0x3017, 0xff}, /* PAD output enable page 100 */ + {0x3018, 0xfc}, /* PAD output enable page 100 */ + + {0x3600, 0x50}, /* analog pg 108 */ + {0x3601, 0x0d}, /* analog pg 108 */ + {0x3604, 0x50}, /* analog pg 108 */ + {0x3605, 0x04}, /* analog pg 108 */ + {0x3606, 0x3f}, /* analog pg 108 */ + {0x3612, 0x1a}, /* analog pg 108 */ + {0x3630, 0x22}, /* analog pg 108 */ + {0x3631, 0x22}, /* analog pg 108 */ + {0x3702, 0x3a}, /* analog pg 108 */ + {0x3704, 0x18}, /* analog pg 108 */ + {0x3705, 0xda}, /* analog pg 108 */ + {0x3706, 0x41}, /* analog pg 108 */ + {0x370a, 0x80}, /* analog pg 108 */ + {0x370b, 0x40}, /* analog pg 108 */ + {0x370e, 0x00}, /* analog pg 108 */ + {0x3710, 0x28}, /* analog pg 108 */ + {0x3712, 0x13}, /* analog pg 108 */ + {0x3830, 0x50}, /* manual exposure gain bit [0] */ + {0x3a18, 0x00}, /* AEC gain ceiling bit 8 pg 114 */ + {0x3a19, 0xf8}, /* AEC gain ceiling pg 114 */ + {0x3a00, 0x38}, /* AEC control 0 debug mode band low + limit mode band func pg 112 */ + + {0x3603, 0xa7}, /* analog pg 108 */ + {0x3615, 0x50}, /* analog pg 108 */ + {0x3620, 0x56}, /* analog pg 108 */ + {0x3810, 0x00}, /* TIMING HVOFFS both are zero pg 80 */ + {0x3836, 0x00}, /* TIMING HVPAD both are zero pg 82 */ + {0x3a1a, 0x06}, /* DIFF MAX an AEC register??? pg 114 */ + {0x4000, 0x01}, /* BLC enabled pg 120 */ + {0x401c, 0x48}, /* reserved pg 120 */ + {0x401d, 0x28}, /* BLC control pg 120 */ + {0x5000, 0x00}, /* ISP control00 features are disabled. pg 132 */ + {0x5001, 0x00}, /* ISP control01 awb disabled. pg 132 */ + {0x5002, 0x00}, /* ISP control02 debug mode disabled pg 132 */ + {0x503d, 0x00}, /* ISP control3D features disabled pg 133 */ + {0x5046, 0x00}, /* ISP control isp disable awbg disable pg 133 */ + + {0x300f, 0x8f}, /* PLL control00 R_SELD5 [7:6] div by 4 R_DIVL [2] + two lane div 1 SELD2P5 [1:0] div 2.5 pg 99 */ + {0x3010, 0x10}, /* PLL control01 DIVM [3:0] DIVS [7:4] div 1 pg 99 */ + {0x3011, 0x14}, /* PLL control02 R_DIVP [5:0] div 20 pg 99 */ + {0x3012, 0x02}, /* PLL CTR 03, default */ + {0x3815, 0x82}, /* PCLK to SCLK ratio bit[4:0] is set to 2 pg 81 */ + {0x3503, 0x33}, /* AEC auto AGC auto gain has no latch delay. pg 38 */ + /* {FAST_SETMODE_START, 0}, */ + {0x3613, 0x44}, /* analog pg 108 */ + {OV5650_TABLE_END, 0x0}, +}; + +static struct ov5650_reg mode_2592x1944[] = { + {0x3621, 0x2f}, /* analog horizontal binning/sampling not enabled. + pg 108 */ + {0x3632, 0x55}, /* analog pg 108 */ + {0x3703, 0xe6}, /* analog pg 108 */ + {0x370c, 0xa0}, /* analog pg 108 */ + {0x370d, 0x04}, /* analog pg 108 */ + {0x3713, 0x2f}, /* analog pg 108 */ + {0x3800, 0x02}, /* HREF start point higher 4 bits [3:0] pg 108 */ + {0x3801, 0x58}, /* HREF start point lower 8 bits [7:0] pg 108 */ + {0x3802, 0x00}, /* VREF start point higher 4 bits [3:0] pg 108 */ + {0x3803, 0x0c}, /* VREF start point [7:0] pg 108 */ + {0x3804, 0x0a}, /* HREF width higher 4 bits [3:0] pg 108 */ + {0x3805, 0x20}, /* HREF width lower 8 bits [7:0] pg 108 */ + {0x3806, 0x07}, /* VREF height higher 4 bits [3:0] pg 109 */ + {0x3807, 0xa0}, /* VREF height lower 8 bits [7:0] pg 109 */ + {0x3808, 0x0a}, /* DVP horizontal output size higher 4 bits [3:0] + pg 109 */ + {0x3809, 0x20}, /* DVP horizontal output size lower 8 bits [7:0] + pg 109 */ + {0x380a, 0x07}, /* DVP vertical output size higher 4 bits [3:0] + pg 109 */ + {0x380b, 0xa0}, /* DVP vertical output size lower 8 bits [7:0] + pg 109 */ + {0x380c, 0x0c}, /* total horizontal size higher 5 bits [4:0] pg 109, + line length */ + {0x380d, 0xb4}, /* total horizontal size lower 8 bits [7:0] pg 109, + line length */ + {0x380e, 0x07}, /* total vertical size higher 5 bits [4:0] pg 109, + frame length */ + {0x380f, 0xb0}, /* total vertical size lower 8 bits [7:0] pg 109, + frame length */ + {0x3818, 0xc0}, /* timing control reg18 mirror & dkhf pg 110 */ + {0x381a, 0x3c}, /* HS mirror adjustment pg 110 */ + {0x3a0d, 0x06}, /* b60 max pg 113 */ + {0x3c01, 0x00}, /* 5060HZ_CTRL01 pg 116 */ + {0x3007, 0x3f}, /* clock enable03 pg 98 */ + {0x5059, 0x80}, /* => NOT found */ + {0x3003, 0x03}, /* reset MIPI and DVP pg 97 */ + {0x3500, 0x00}, /* long exp 1/3 in unit of 1/16 line, pg 38 */ + {0x3501, 0x7a}, /* long exp 2/3 in unit of 1/16 line, pg 38, + note frame length start with 0x7b0, + and SENSOR_BAYER_DEFAULT_MAX_COARSE_DIFF=3 */ + {0x3502, 0xd0}, /* long exp 3/3 in unit of 1/16 line, pg 38. + Two lines of integration time. */ + {0x350a, 0x00}, /* gain output to sensor, pg 38 */ + {0x350b, 0x00}, /* gain output to sensor, pg 38 */ + {0x4801, 0x0f}, /* MIPI control01 pg 125 */ + {0x300e, 0x0c}, /* SC_MIPI_SC_CTRL0 pg 73 */ + {0x4803, 0x50}, /* MIPI CTRL3 pg 91 */ + {0x4800, 0x34}, /* MIPI CTRl0 idle and short line pg 89 */ + {OV5650_TABLE_END, 0x0000} +}; + +static struct ov5650_reg mode_1296x972[] = { + {0x3621, 0xaf}, /* analog horizontal binning/sampling not enabled. + pg 108 */ + {0x3632, 0x5a}, /* analog pg 108 */ + {0x3703, 0xb0}, /* analog pg 108 */ + {0x370c, 0xc5}, /* analog pg 108 */ + {0x370d, 0x42}, /* analog pg 108 */ + {0x3713, 0x2f}, /* analog pg 108 */ + {0x3800, 0x03}, /* HREF start point higher 4 bits [3:0] pg 108 */ + {0x3801, 0x3c}, /* HREF start point lower 8 bits [7:0] pg 108 */ + {0x3802, 0x00}, /* VREF start point higher 4 bits [3:0] pg 108 */ + {0x3803, 0x06}, /* VREF start point [7:0] pg 108 */ + {0x3804, 0x05}, /* HREF width higher 4 bits [3:0] pg 108 */ + {0x3805, 0x10}, /* HREF width lower 8 bits [7:0] pg 108 */ + {0x3806, 0x03}, /* VREF height higher 4 bits [3:0] pg 109 */ + {0x3807, 0xd0}, /* VREF height lower 8 bits [7:0] pg 109 */ + {0x3808, 0x05}, /* DVP horizontal output size higher 4 bits [3:0] + pg 109 */ + {0x3809, 0x10}, /* DVP horizontal output size lower 8 bits [7:0] + pg 109 */ + {0x380a, 0x03}, /* DVP vertical output size higher 4 bits [3:0] + pg 109 */ + {0x380b, 0xd0}, /* DVP vertical output size lower 8 bits [7:0] + pg 109 */ + {0x380c, 0x08}, /* total horizontal size higher 5 bits [4:0] + pg 109, line length */ + {0x380d, 0xa8}, /* total horizontal size lower 8 bits [7:0] pg 109, + line length */ + {0x380e, 0x05}, /* total vertical size higher 5 bits [4:0] pg 109, + frame length */ + {0x380f, 0xa4}, /* total horizontal size lower 8 bits [7:0] pg 109, + frame length */ + {0x3818, 0xc1}, /* timing control reg18 mirror & dkhf pg 110 */ + {0x381a, 0x00}, /* HS mirror adjustment pg 110 */ + {0x3a0d, 0x08}, /* b60 max pg 113 */ + {0x3c01, 0x00}, /* 5060HZ_CTRL01 pg 116 */ + {0x3007, 0x3b}, /* clock enable03 pg 98 */ + {0x5059, 0x80}, /* => NOT found. added */ + {0x3003, 0x03}, /* reset MIPI and DVP pg 97 */ + {0x3500, 0x00}, /* long exp 1/3 in unit of 1/16 line, pg 38, + note frame length is from 0x5a4, + and SENSOR_BAYER_DEFAULT_MAX_COARSE_DIFF=3 */ + {0x3501, 0x5a}, /* long exp 2/3 in unit of 1/16 line, pg 38 */ + {0x3502, 0x10}, /* long exp 3/3 in unit of 1/16 line, pg 38 */ + {0x350a, 0x00}, /* gain output to sensor, pg 38 */ + {0x350b, 0x10}, /* gain output to sensor, pg 38 */ + {0x4801, 0x0f}, /* MIPI control01 pg 125 */ + {0x300e, 0x0c}, /* SC_MIPI_SC_CTRL0 pg 73 */ + {0x4803, 0x50}, /* MIPI CTRL3 pg 91 */ + {0x4800, 0x34}, /* MIPI CTRl0 idle and short line pg 89 */ + {OV5650_TABLE_END, 0x0000} +}; + +static struct ov5650_reg mode_1920x1088[] = { + {0x3621, 0x2f}, /* analog horizontal binning/sampling not enabled. + pg 108 */ + {0x3632, 0x55}, /* analog pg 108 */ + {0x3703, 0xe6}, /* analog pg 108 */ + {0x370c, 0xa0}, /* analog pg 108 */ + {0x370d, 0x04}, /* analog pg 108 */ + {0x3713, 0x2f}, /* analog pg 108 */ + {0x3800, 0x02}, /* HREF start point higher 4 bits [3:0] pg 108 */ + {0x3801, 0x58}, /* HREF start point lower 8 bits [7:0] pg 108 */ + {0x3802, 0x00}, /* VREF start point higher 4 bits [3:0] pg 108 */ + {0x3803, 0x0c}, /* VREF start point [7:0] pg 108 */ + {0x3804, 0x0a}, /* HREF width higher 4 bits [3:0] pg 108 */ + {0x3805, 0x20}, /* HREF width lower 8 bits [7:0] pg 108 */ + {0x3806, 0x07}, /* VREF height higher 4 bits [3:0] pg 109 */ + {0x3807, 0xa0}, /* VREF height lower 8 bits [7:0] pg 109 */ + {0x3808, 0x0a}, /* DVP horizontal output size higher 4 bits [3:0] + pg 109 */ + {0x3809, 0x20}, /* DVP horizontal output size lower 8 bits [7:0] + pg 109 */ + {0x380a, 0x07}, /* DVP vertical output size higher 4 bits [3:0] + pg 109 */ + {0x380b, 0xa0}, /* DVP vertical output size lower 8 bits [7:0] + pg 109 */ + {0x380c, 0x0c}, /* total horizontal size higher 5 bits [4:0] pg 109, + line length */ + {0x380d, 0xb4}, /* total horizontal size lower 8 bits [7:0] pg 109, + line length */ + {0x380e, 0x07}, /* total vertical size higher 5 bits [4:0] pg 109, + frame length */ + {0x380f, 0xb0}, /* total vertical size lower 8 bits [7:0] pg 109, + frame length */ + {0x3818, 0xc0}, /* timing control reg18 mirror & dkhf pg 110 */ + {0x381a, 0x3c}, /* HS mirror adjustment pg 110 */ + {0x3a0d, 0x06}, /* b60 max pg 113 */ + {0x3c01, 0x00}, /* 5060HZ_CTRL01 pg 116 */ + {0x3007, 0x3f}, /* clock enable03 pg 98 */ + {0x5059, 0x80}, /* => NOT found */ + {0x3003, 0x03}, /* reset MIPI and DVP pg 97 */ + {0x3500, 0x00}, /* long exp 1/3 in unit of 1/16 line, pg 38 */ + {0x3501, 0x7a}, /* long exp 2/3 in unit of 1/16 line, pg 38, + note frame length start with 0x7b0, + and SENSOR_BAYER_DEFAULT_MAX_COARSE_DIFF=3 */ + {0x3502, 0xd0}, /* long exp 3/3 in unit of 1/16 line, pg 38. + Two lines of integration time. */ + {0x350a, 0x00}, /* gain output to sensor, pg 38 */ + {0x350b, 0x00}, /* gain output to sensor, pg 38 */ + {0x4801, 0x0f}, /* MIPI control01 pg 125 */ + {0x300e, 0x0c}, /* SC_MIPI_SC_CTRL0 pg 73 */ + {0x4803, 0x50}, /* MIPI CTRL3 pg 91 */ + {0x4800, 0x34}, /* MIPI CTRl0 idle and short line pg 89 */ + {OV5650_TABLE_END, 0x0000} +}; + +static struct ov5650_reg mode_1264x704[] = { + {0x3600, 0x54}, /* analog pg 108 */ + {0x3601, 0x05}, /* analog pg 108 */ + {0x3604, 0x40}, /* analog pg 108 */ + {0x3705, 0xdb}, /* analog pg 108 */ + {0x370a, 0x81}, /* analog pg 108 */ + {0x3615, 0x52}, /* analog pg 108 */ + {0x3810, 0x40}, /* TIMING HVOFFS both are zero pg 80 */ + {0x3836, 0x41}, /* TIMING HVPAD both are zero pg 82 */ + {0x4000, 0x05}, /* BLC enabled pg 120 */ + {0x401c, 0x42}, /* reserved pg 120 */ + {0x5046, 0x09}, /* ISP control isp disable awbg disable pg 133 */ + {0x3010, 0x00}, /* PLL control01 DIVM [3:0] DIVS [7:4] div 1 pg 99 */ + {0x3503, 0x00}, /* AEC auto AGC auto gain has no latch delay. pg 38 */ + {0x3613, 0xc4}, /* analog pg 108 */ + + {0x3621, 0xaf}, /* analog horizontal binning/sampling not enabled. + pg 108 */ + {0x3632, 0x55}, /* analog pg 108 */ + {0x3703, 0x9a}, /* analog pg 108 */ + {0x370c, 0x00}, /* analog pg 108 */ + {0x370d, 0x42}, /* analog pg 108 */ + {0x3713, 0x22}, /* analog pg 108 */ + {0x3800, 0x02}, /* HREF start point higher 4 bits [3:0] pg 108 */ + {0x3801, 0x54}, /* HREF start point lower 8 bits [7:0] pg 108 */ + {0x3802, 0x00}, /* VREF start point higher 4 bits [3:0] pg 108 */ + {0x3803, 0x0c}, /* VREF start point [7:0] pg 108 */ + {0x3804, 0x05}, /* HREF width higher 4 bits [3:0] pg 108 */ + {0x3805, 0x00}, /* HREF width lower 8 bits [7:0] pg 108 */ + {0x3806, 0x02}, /* VREF height higher 4 bits [3:0] pg 109 */ + {0x3807, 0xd0}, /* VREF height lower 8 bits [7:0] pg 109 */ + {0x3808, 0x05}, /* DVP horizontal output size higher 4 bits [3:0] + pg 109 */ + {0x3809, 0x00}, /* DVP horizontal output size lower 8 bits [7:0] + pg 109 */ + {0x380a, 0x02}, /* DVP vertical output size higher 4 bits [3:0] + pg 109 */ + {0x380b, 0xd0}, /* DVP vertical output size lower 8 bits [7:0] + pg 109 */ + {0x380c, 0x08}, /* total horizontal size higher 5 bits [4:0] pg 109, + line length */ + {0x380d, 0x72}, /* total horizontal size lower 8 bits [7:0] pg 109, + line length */ + {0x380e, 0x02}, /* total vertical size higher 5 bits [4:0] pg 109, + frame length */ + {0x380f, 0xe4}, /* total vertical size lower 8 bits [7:0] pg 109, + frame length */ + {0x3818, 0xc1}, /* timing control reg18 mirror & dkhf pg 110 */ + {0x381a, 0x3c}, /* HS mirror adjustment pg 110 */ + {0x3a0d, 0x06}, /* b60 max pg 113 */ + {0x3c01, 0x34}, /* 5060HZ_CTRL01 pg 116 */ + {0x3007, 0x3b}, /* clock enable03 pg 98 */ + {0x5059, 0x80}, /* => NOT found */ + {0x3003, 0x03}, /* reset MIPI and DVP pg 97 */ + {0x3500, 0x04}, /* long exp 1/3 in unit of 1/16 line, pg 38 */ + {0x3501, 0xa5}, /* long exp 2/3 in unit of 1/16 line, pg 38, + note frame length start with 0x7b0, + and SENSOR_BAYER_DEFAULT_MAX_COARSE_DIFF=3 */ + {0x3502, 0x10}, /* long exp 3/3 in unit of 1/16 line, pg 38. + Two lines of integration time. */ + {0x350a, 0x00}, /* gain output to sensor, pg 38 */ + {0x350b, 0x00}, /* gain output to sensor, pg 38 */ + {0x4801, 0x0f}, /* MIPI control01 pg 125 */ + {0x300e, 0x0c}, /* SC_MIPI_SC_CTRL0 pg 73 */ + {0x4803, 0x50}, /* MIPI CTRL3 pg 91 */ + {0x4800, 0x24}, /* MIPI CTRl0 idle and short line pg 89 */ + + {0x300f, 0x8b}, /* PLL control00 R_SELD5 [7:6] div by 4 R_DIVL [2] + two lane div 1 SELD2P5 [1:0] div 2.5 pg 99 */ + + {0x3711, 0x24}, + {0x3713, 0x92}, + {0x3714, 0x17}, + {0x381c, 0x10}, + {0x381d, 0x82}, + {0x381e, 0x05}, + {0x381f, 0xc0}, + {0x3821, 0x20}, + {0x3824, 0x23}, + {0x3825, 0x2c}, + {0x3826, 0x00}, + {0x3827, 0x0c}, + {0x3623, 0x01}, + {0x3633, 0x24}, + {0x3632, 0x5f}, + {0x401f, 0x03}, + + {OV5650_TABLE_END, 0x0000} +}; + +static struct ov5650_reg mode_end[] = { + {0x3212, 0x00}, /* SRM_GROUP_ACCESS (group hold begin) */ + {0x3003, 0x01}, /* reset DVP pg 97 */ + {0x3212, 0x10}, /* SRM_GROUP_ACCESS (group hold end) */ + {0x3212, 0xa0}, /* SRM_GROUP_ACCESS (group hold launch) */ + {0x3008, 0x02}, /* SYSTEM_CTRL0 mipi suspend mask pg 98 */ + + /* {FAST_SETMODE_END, 0}, */ + {OV5650_TABLE_END, 0x0000} +}; + +enum { + OV5650_MODE_2592x1944, + OV5650_MODE_1296x972, + OV5650_MODE_1920x1088, + OV5650_MODE_1264x704, +}; + +static struct ov5650_reg *mode_table[] = { + [OV5650_MODE_2592x1944] = mode_2592x1944, + [OV5650_MODE_1296x972] = mode_1296x972, + [OV5650_MODE_1920x1088] = mode_1920x1088, + [OV5650_MODE_1264x704] = mode_1264x704, +}; + +/* 2 regs to program frame length */ +static inline void ov5650_get_frame_length_regs(struct ov5650_reg *regs, + u32 frame_length) +{ + regs->addr = 0x380e; + regs->val = (frame_length >> 8) & 0xff; + (regs + 1)->addr = 0x380f; + (regs + 1)->val = (frame_length) & 0xff; +} + +/* 3 regs to program coarse time */ +static inline void ov5650_get_coarse_time_regs(struct ov5650_reg *regs, + u32 coarse_time) +{ + regs->addr = 0x3500; + regs->val = (coarse_time >> 12) & 0xff; + (regs + 1)->addr = 0x3501; + (regs + 1)->val = (coarse_time >> 4) & 0xff; + (regs + 2)->addr = 0x3502; + (regs + 2)->val = (coarse_time & 0xf) << 4; +} + +/* 1 reg to program gain */ +static inline void ov5650_get_gain_reg(struct ov5650_reg *regs, u16 gain) +{ + regs->addr = 0x350b; + regs->val = gain; +} + +static int ov5650_read_reg(struct i2c_client *client, u16 addr, u8 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[3]; + + if (!client->adapter) + return -ENODEV; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8) (addr >> 8);; + data[1] = (u8) (addr & 0xff); + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = data + 2; + + err = i2c_transfer(client->adapter, msg, 2); + + if (err != 2) + return -EINVAL; + + *val = data[2]; + + return 0; +} + +static int ov5650_write_reg(struct i2c_client *client, u16 addr, u8 val) +{ + int err; + struct i2c_msg msg; + unsigned char data[3]; + int retry = 0; + + if (!client->adapter) + return -ENODEV; + + data[0] = (u8) (addr >> 8);; + data[1] = (u8) (addr & 0xff); + data[2] = (u8) (val & 0xff); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 3; + msg.buf = data; + + do { + err = i2c_transfer(client->adapter, &msg, 1); + if (err == 1) + return 0; + retry++; + pr_err("ov5650: i2c transfer failed, retrying %x %x\n", + addr, val); + msleep(3); + } while (retry <= OV5650_MAX_RETRIES); + + return err; +} + +static int ov5650_write_table(struct i2c_client *client, + const struct ov5650_reg table[], + const struct ov5650_reg override_list[], + int num_override_regs) +{ + int err; + const struct ov5650_reg *next; + int i; + u16 val; + + for (next = table; next->addr != OV5650_TABLE_END; next++) { + if (next->addr == OV5650_TABLE_WAIT_MS) { + msleep(next->val); + continue; + } + + val = next->val; + + /* When an override list is passed in, replace the reg */ + /* value to write if the reg is in the list */ + if (override_list) { + for (i = 0; i < num_override_regs; i++) { + if (next->addr == override_list[i].addr) { + val = override_list[i].val; + break; + } + } + } + + err = ov5650_write_reg(client, next->addr, val); + if (err) + return err; + } + return 0; +} + +static int ov5650_set_mode(struct ov5650_info *info, struct ov5650_mode *mode) +{ + int sensor_mode; + int err; + struct ov5650_reg reg_list[6]; + + pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u\n", + __func__, mode->xres, mode->yres, mode->frame_length, + mode->coarse_time, mode->gain); + if (mode->xres == 2592 && mode->yres == 1944) + sensor_mode = OV5650_MODE_2592x1944; + else if (mode->xres == 1296 && mode->yres == 972) + sensor_mode = OV5650_MODE_1296x972; + else if (mode->xres == 1920 && mode->yres == 1088) + sensor_mode = OV5650_MODE_1920x1088; + else if (mode->xres == 1264 && mode->yres == 704) + sensor_mode = OV5650_MODE_1264x704; + else { + pr_err("%s: invalid resolution supplied to set mode %d %d\n", + __func__, mode->xres, mode->yres); + return -EINVAL; + } + + /* get a list of override regs for the asking frame length, */ + /* coarse integration time, and gain. */ + ov5650_get_frame_length_regs(reg_list, mode->frame_length); + ov5650_get_coarse_time_regs(reg_list + 2, mode->coarse_time); + ov5650_get_gain_reg(reg_list + 5, mode->gain); + + err = ov5650_write_table(info->i2c_client, mode_start, NULL, 0); + if (err) + return err; + + err = ov5650_write_table(info->i2c_client, mode_table[sensor_mode], + reg_list, 6); + if (err) + return err; + + err = ov5650_write_table(info->i2c_client, mode_end, NULL, 0); + if (err) + return err; + + info->mode = sensor_mode; + return 0; +} + +static int ov5650_set_frame_length(struct ov5650_info *info, u32 frame_length) +{ + struct ov5650_reg reg_list[2]; + int i = 0; + int ret; + + ov5650_get_frame_length_regs(reg_list, frame_length); + + for (i = 0; i < 2; i++) { + ret = ov5650_write_reg(info->i2c_client, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; + } + + return 0; +} + +static int ov5650_set_coarse_time(struct ov5650_info *info, u32 coarse_time) +{ + int ret; + + struct ov5650_reg reg_list[3]; + int i = 0; + + ov5650_get_coarse_time_regs(reg_list, coarse_time); + + ret = ov5650_write_reg(info->i2c_client, 0x3212, 0x01); + if (ret) + return ret; + + for (i = 0; i < 3; i++) { + ret = ov5650_write_reg(info->i2c_client, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; + } + + ret = ov5650_write_reg(info->i2c_client, 0x3212, 0x11); + if (ret) + return ret; + + ret = ov5650_write_reg(info->i2c_client, 0x3212, 0xa1); + if (ret) + return ret; + + return 0; +} + +static int ov5650_set_gain(struct ov5650_info *info, u16 gain) +{ + int ret; + struct ov5650_reg reg_list; + + ov5650_get_gain_reg(®_list, gain); + + ret = ov5650_write_reg(info->i2c_client, reg_list.addr, reg_list.val); + + return ret; +} + +static int ov5650_get_status(struct ov5650_info *info, u8 *status) +{ + int err; + + *status = 0; + err = ov5650_read_reg(info->i2c_client, 0x002, status); + return err; +} + + +static long ov5650_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int err; + struct ov5650_info *info = file->private_data; + + switch (cmd) { + case OV5650_IOCTL_SET_MODE: + { + struct ov5650_mode mode; + if (copy_from_user(&mode, + (const void __user *)arg, + sizeof(struct ov5650_mode))) { + return -EFAULT; + } + + return ov5650_set_mode(info, &mode); + } + case OV5650_IOCTL_SET_FRAME_LENGTH: + return ov5650_set_frame_length(info, (u32)arg); + case OV5650_IOCTL_SET_COARSE_TIME: + return ov5650_set_coarse_time(info, (u32)arg); + case OV5650_IOCTL_SET_GAIN: + return ov5650_set_gain(info, (u16)arg); + case OV5650_IOCTL_GET_STATUS: + { + u8 status; + + err = ov5650_get_status(info, &status); + if (err) + return err; + if (copy_to_user((void __user *)arg, &status, + 2)) { + return -EFAULT; + } + return 0; + } + default: + return -EINVAL; + } + return 0; +} + +static struct ov5650_info *info; + +static int ov5650_open(struct inode *inode, struct file *file) +{ + u8 status; + + file->private_data = info; + if (info->pdata && info->pdata->power_on) + info->pdata->power_on(); + ov5650_get_status(info, &status); + return 0; +} + +int ov5650_release(struct inode *inode, struct file *file) +{ + if (info->pdata && info->pdata->power_off) + info->pdata->power_off(); + file->private_data = NULL; + return 0; +} + + +static const struct file_operations ov5650_fileops = { + .owner = THIS_MODULE, + .open = ov5650_open, + .unlocked_ioctl = ov5650_ioctl, + .release = ov5650_release, +}; + +static struct miscdevice ov5650_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ov5650", + .fops = &ov5650_fileops, +}; + +static int ov5650_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + + pr_info("ov5650: probing sensor.\n"); + + info = kzalloc(sizeof(struct ov5650_info), GFP_KERNEL); + if (!info) { + pr_err("ov5650: Unable to allocate memory!\n"); + return -ENOMEM; + } + + err = misc_register(&ov5650_device); + if (err) { + pr_err("ov5650: Unable to register misc device!\n"); + kfree(info); + return err; + } + + info->pdata = client->dev.platform_data; + info->i2c_client = client; + + i2c_set_clientdata(client, info); + return 0; +} + +static int ov5650_remove(struct i2c_client *client) +{ + struct ov5650_info *info; + info = i2c_get_clientdata(client); + misc_deregister(&ov5650_device); + kfree(info); + return 0; +} + +static const struct i2c_device_id ov5650_id[] = { + { "ov5650", 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, ov5650_id); + +static struct i2c_driver ov5650_i2c_driver = { + .driver = { + .name = "ov5650", + .owner = THIS_MODULE, + }, + .probe = ov5650_probe, + .remove = ov5650_remove, + .id_table = ov5650_id, +}; + +static int __init ov5650_init(void) +{ + pr_info("ov5650 sensor driver loading\n"); + return i2c_add_driver(&ov5650_i2c_driver); +} + +static void __exit ov5650_exit(void) +{ + i2c_del_driver(&ov5650_i2c_driver); +} + +module_init(ov5650_init); +module_exit(ov5650_exit); + diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0d762688effe..008179158b78 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -303,6 +303,16 @@ config MFD_MAX8998 accessing the device, additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX8907C + tristate "Maxim Semiconductor MAX8907C PMIC Support" + select MFD_CORE + depends on I2C + help + Say yes here to support for Maxim Semiconductor MAX8907C. This is + a Power Management IC. This driver provies common support for + accessing the device, additional drivers must be enabled in order + to use the functionality of the device. + config MFD_WM8400 tristate "Support Wolfson Microelectronics WM8400" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index feaeeaeeddb7..84d0070a06f8 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o +obj-$(CONFIG_MFD_MAX8907C) += max8907c.o diff --git a/drivers/mfd/max8907c.c b/drivers/mfd/max8907c.c new file mode 100644 index 000000000000..0ceccbab7e37 --- /dev/null +++ b/drivers/mfd/max8907c.c @@ -0,0 +1,251 @@ +/* + * max8907c.c - mfd driver for MAX8907c + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max8907c.h> + +static struct mfd_cell cells[] = { + {.name = "max8907-regulator",}, +}; + +int max8907c_reg_read(struct device *dev, u8 reg) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct max8907c *max8907c = dev_get_drvdata(dev); + u8 val; + int ret; + + mutex_lock(&max8907c->io_lock); + + ret = max8907c->read_dev(i2c, reg, 1, &val); + + mutex_unlock(&max8907c->io_lock); + pr_debug("max8907c: reg read reg=%x, val=%x\n", + (unsigned int)reg, (unsigned int)val); + + if (ret != 0) + pr_err("Failed to read max8907c I2C driver: %d\n", ret); + return val; +} +EXPORT_SYMBOL_GPL(max8907c_reg_read); + +int max8907c_reg_write(struct device *dev, u8 reg, u8 val) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct max8907c *max8907c = dev_get_drvdata(dev); + int ret; + + pr_debug("max8907c: reg write reg=%x, val=%x\n", + (unsigned int)reg, (unsigned int)val); + mutex_lock(&max8907c->io_lock); + + ret = max8907c->write_dev(i2c, reg, 1, &val); + + mutex_unlock(&max8907c->io_lock); + + if (ret != 0) + pr_err("Failed to write max8907c I2C driver: %d\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(max8907c_reg_write); + +int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct max8907c *max8907c = dev_get_drvdata(dev); + u8 tmp; + int ret; + + pr_debug("max8907c: reg write reg=%02X, val=%02X, mask=%02X\n", + (unsigned int)reg, (unsigned int)val, (unsigned int)mask); + mutex_lock(&max8907c->io_lock); + + ret = max8907c->read_dev(i2c, reg, 1, &tmp); + if (ret == 0) { + val = (tmp & ~mask) | (val & mask); + ret = max8907c->write_dev(i2c, reg, 1, &val); + } + + mutex_unlock(&max8907c->io_lock); + + if (ret != 0) + pr_err("Failed to write max8907c I2C driver: %d\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(max8907c_set_bits); + +static int max8907c_i2c_read(void *io_data, u8 reg, u8 count, u8 * dest) +{ + struct i2c_client *i2c = (struct i2c_client *)io_data; + struct i2c_msg xfer[2]; + int ret = 0; + + xfer[0].addr = i2c->addr; + xfer[0].flags = I2C_M_NOSTART; + xfer[0].len = 1; + xfer[0].buf = ® + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = count; + xfer[1].buf = dest; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + return 0; +} + +static int max8907c_i2c_write(void *io_data, u8 reg, u8 count, const u8 * src) +{ + struct i2c_client *i2c = (struct i2c_client *)io_data; + u8 msg[0x100 + 1]; + int ret = 0; + + msg[0] = reg; + memcpy(&msg[1], src, count); + + ret = i2c_master_send(i2c, msg, count + 1); + if (ret < 0) + return ret; + if (ret != count + 1) + return -EIO; + + return 0; +} + +static int max8907c_remove_subdev(struct device *dev, void *unused) +{ + platform_device_unregister(to_platform_device(dev)); + return 0; +} + +static int max8907c_remove_subdevs(struct max8907c *max8907c) +{ + return device_for_each_child(max8907c->dev, NULL, + max8907c_remove_subdev); +} + +static int max8097c_add_subdevs(struct max8907c *max8907c, + struct max8907c_platform_data *pdata) +{ + struct platform_device *pdev; + int ret; + int i; + + for (i = 0; i < pdata->num_subdevs; i++) { + pdev = platform_device_alloc(pdata->subdevs[i]->name, + pdata->subdevs[i]->id); + + pdev->dev.parent = max8907c->dev; + pdev->dev.platform_data = pdata->subdevs[i]->dev.platform_data; + + ret = platform_device_add(pdev); + if (ret) + goto error; + } + return 0; + +error: + max8907c_remove_subdevs(max8907c); + return ret; +} + +static int max8907c_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max8907c *max8907c; + struct max8907c_platform_data *pdata = i2c->dev.platform_data; + int ret; + int i; + + max8907c = kzalloc(sizeof(struct max8907c), GFP_KERNEL); + if (max8907c == NULL) + return -ENOMEM; + + max8907c->read_dev = max8907c_i2c_read; + max8907c->write_dev = max8907c_i2c_write; + max8907c->dev = &i2c->dev; + i2c_set_clientdata(i2c, max8907c); + + mutex_init(&max8907c->io_lock); + + for (i = 0; i < ARRAY_SIZE(cells); i++) + cells[i].driver_data = max8907c; + ret = mfd_add_devices(max8907c->dev, -1, cells, ARRAY_SIZE(cells), + NULL, 0); + if (ret != 0) { + kfree(max8907c); + pr_debug("max8907c: failed to add MFD devices %X\n", ret); + return ret; + } + + ret = max8097c_add_subdevs(max8907c, pdata); + + return ret; +} + +static int max8907c_i2c_remove(struct i2c_client *i2c) +{ + struct max8907c *max8907c = i2c_get_clientdata(i2c); + + mfd_remove_devices(max8907c->dev); + kfree(max8907c); + + return 0; +} + +static const struct i2c_device_id max8907c_i2c_id[] = { + {"max8907c", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, max8907c_i2c_id); + +static struct i2c_driver max8907c_i2c_driver = { + .driver = { + .name = "max8907c", + .owner = THIS_MODULE, + }, + .probe = max8907c_i2c_probe, + .remove = max8907c_i2c_remove, + .id_table = max8907c_i2c_id, +}; + +static int __init max8907c_i2c_init(void) +{ + int ret = -ENODEV; + + ret = i2c_add_driver(&max8907c_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} + +subsys_initcall(max8907c_i2c_init); + +static void __exit max8907c_i2c_exit(void) +{ + i2c_del_driver(&max8907c_i2c_driver); +} + +module_exit(max8907c_i2c_exit); + +MODULE_DESCRIPTION("MAX8907C multi-function core driver"); +MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index ab667f296897..ad0dfe2a28fb 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -27,6 +27,10 @@ #include <linux/mfd/core.h> #include <linux/mfd/tps6586x.h> +#define TPS6586X_SUPPLYENE 0x14 +#define EXITSLREQ_BIT BIT(1) /* Exit sleep mode request */ +#define SLEEP_MODE_BIT BIT(3) /* Sleep mode */ + /* GPIO control registers */ #define TPS6586X_GPIOSET1 0x5d #define TPS6586X_GPIOSET2 0x5e @@ -251,6 +255,28 @@ out: } EXPORT_SYMBOL_GPL(tps6586x_update); +static struct i2c_client *tps6586x_i2c_client = NULL; +int tps6586x_power_off(void) +{ + struct device *dev = NULL; + int ret = -EINVAL; + + if (!tps6586x_i2c_client) + return ret; + + dev = &tps6586x_i2c_client->dev; + + ret = tps6586x_clr_bits(dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT); + if (ret) + return ret; + + ret = tps6586x_set_bits(dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); + if (ret) + return ret; + + return 0; +} + static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset) { struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio); @@ -274,6 +300,12 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset, value << offset); } +static int tps6586x_gpio_input(struct gpio_chip *gc, unsigned offset) +{ + /* FIXME: add handling of GPIOs as dedicated inputs */ + return -ENOSYS; +} + static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, int value) { @@ -302,7 +334,7 @@ static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) tps6586x->gpio.ngpio = 4; tps6586x->gpio.can_sleep = 1; - /* FIXME: add handling of GPIOs as dedicated inputs */ + tps6586x->gpio.direction_input = tps6586x_gpio_input; tps6586x->gpio.direction_output = tps6586x_gpio_output; tps6586x->gpio.set = tps6586x_gpio_set; tps6586x->gpio.get = tps6586x_gpio_get; @@ -519,6 +551,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, tps6586x_gpio_init(tps6586x, pdata->gpio_base); + tps6586x_i2c_client = client; + return 0; err_add_devs: diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0c273c04a306..8a3b4579dd2d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -436,9 +436,16 @@ config APANIC_PLABEL If your platform uses a different flash partition label for storing crashdumps, enter it here. +config BCM4329_RFKILL + bool "Enable BCM4329 RFKILL driver" + default n + ---help--- + Adds BCM4329 RFKILL driver for Broadcom BCM4329 chipset + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" source "drivers/misc/iwmc3200top/Kconfig" +source "drivers/misc/mpu3050/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 249ac2683aa5..eb16069b545e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -12,8 +12,8 @@ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o obj-$(CONFIG_BMP085) += bmp085.o obj-$(CONFIG_ICS932S401) += ics932s401.o obj-$(CONFIG_LKDTM) += lkdtm.o -obj-$(CONFIG_TIFM_CORE) += tifm_core.o -obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o +obj-$(CONFIG_TIFM_CORE) += tifm_core.o +obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o obj-$(CONFIG_ANDROID_PMEM) += pmem.o @@ -41,3 +41,5 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o obj-$(CONFIG_APANIC) += apanic.o obj-$(CONFIG_SENSORS_AK8975) += akm8975.o +obj-$(CONFIG_BCM4329_RFKILL) += bcm4329_rfkill.o +obj-$(CONFIG_SENSORS_MPU3050) += mpu3050/ diff --git a/drivers/misc/akm8975.c b/drivers/misc/akm8975.c index 830d2897afd6..0264bd6c8192 100644 --- a/drivers/misc/akm8975.c +++ b/drivers/misc/akm8975.c @@ -222,8 +222,8 @@ static int akm_aot_release(struct inode *inode, struct file *file) return 0; } -static int akm_aot_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long akm_aot_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *) arg; short flag; @@ -316,8 +316,8 @@ static int akmd_release(struct inode *inode, struct file *file) return 0; } -static int akmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long akmd_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { void __user *argp = (void __user *) arg; @@ -537,14 +537,14 @@ static const struct file_operations akmd_fops = { .owner = THIS_MODULE, .open = akmd_open, .release = akmd_release, - .ioctl = akmd_ioctl, + .unlocked_ioctl = akmd_ioctl, }; static const struct file_operations akm_aot_fops = { .owner = THIS_MODULE, .open = akm_aot_open, .release = akm_aot_release, - .ioctl = akm_aot_ioctl, + .unlocked_ioctl = akm_aot_ioctl, }; static struct miscdevice akm_aot_device = { diff --git a/drivers/misc/bcm4329_rfkill.c b/drivers/misc/bcm4329_rfkill.c new file mode 100644 index 000000000000..eeb4047631f3 --- /dev/null +++ b/drivers/misc/bcm4329_rfkill.c @@ -0,0 +1,186 @@ +/* + * drivers/misc/bcm4329_rfkill.c + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/err.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/rfkill.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/slab.h> + +struct bcm4329_rfkill_data { + int gpio_reset; + int gpio_shutdown; + int delay; + struct clk *bt_32k_clk; +}; + +static struct bcm4329_rfkill_data *bcm4329_rfkill; + +static int bcm4329_bt_rfkill_set_power(void *data, bool blocked) +{ + if (blocked) { + gpio_direction_output(bcm4329_rfkill->gpio_shutdown, 0); + gpio_direction_output(bcm4329_rfkill->gpio_reset, 0); + if (bcm4329_rfkill->bt_32k_clk) + clk_disable(bcm4329_rfkill->bt_32k_clk); + } else { + if (bcm4329_rfkill->bt_32k_clk) + clk_enable(bcm4329_rfkill->bt_32k_clk); + gpio_direction_output(bcm4329_rfkill->gpio_shutdown, 1); + gpio_direction_output(bcm4329_rfkill->gpio_reset, 1); + } + + return 0; +} + +static const struct rfkill_ops bcm4329_bt_rfkill_ops = { + .set_block = bcm4329_bt_rfkill_set_power, +}; + +static int bcm4329_rfkill_probe(struct platform_device *pdev) +{ + struct rfkill *bt_rfkill; + struct resource *res; + int ret; + bool enable = false; /* off */ + bool default_sw_block_state; + + bcm4329_rfkill = kzalloc(sizeof(*bcm4329_rfkill), GFP_KERNEL); + if (!bcm4329_rfkill) + return -ENOMEM; + + bcm4329_rfkill->bt_32k_clk = clk_get(&pdev->dev, "bcm4329_32k_clk"); + if (IS_ERR(bcm4329_rfkill->bt_32k_clk)) { + pr_warn("can't find bcm4329_32k_clk. assuming clock to chip\n"); + bcm4329_rfkill->bt_32k_clk = NULL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, + "bcm4329_nreset_gpio"); + if (!res) { + pr_err("couldn't find reset gpio\n"); + goto free_bcm_32k_clk; + } + bcm4329_rfkill->gpio_reset = res->start; + tegra_gpio_enable(bcm4329_rfkill->gpio_reset); + ret = gpio_request(bcm4329_rfkill->gpio_reset, + "bcm4329_nreset_gpio"); + if (unlikely(ret)) + goto free_bcm_32k_clk; + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, + "bcm4329_nshutdown_gpio"); + if (!res) { + pr_err("couldn't find shutdown gpio\n"); + gpio_free(bcm4329_rfkill->gpio_reset); + goto free_bcm_32k_clk; + } + tegra_gpio_enable(bcm4329_rfkill->gpio_shutdown); + ret = gpio_request(bcm4329_rfkill->gpio_shutdown, + "bcm4329_nshutdown_gpio"); + if (unlikely(ret)) { + gpio_free(bcm4329_rfkill->gpio_reset); + goto free_bcm_32k_clk; + } + + if (bcm4329_rfkill->bt_32k_clk && enable) + clk_enable(bcm4329_rfkill->bt_32k_clk); + gpio_direction_output(bcm4329_rfkill->gpio_shutdown, enable); + gpio_direction_output(bcm4329_rfkill->gpio_reset, enable); + + bt_rfkill = rfkill_alloc("bcm4329 Bluetooth", &pdev->dev, + RFKILL_TYPE_BLUETOOTH, &bcm4329_bt_rfkill_ops, + NULL); + + if (unlikely(!bt_rfkill)) + goto free_bcm_res; + + default_sw_block_state = !enable; + rfkill_set_states(bt_rfkill, default_sw_block_state, false); + + ret = rfkill_register(bt_rfkill); + + if (unlikely(ret)) { + rfkill_destroy(bt_rfkill); + goto free_bcm_res; + } + + return 0; + +free_bcm_res: + gpio_free(bcm4329_rfkill->gpio_shutdown); + gpio_free(bcm4329_rfkill->gpio_reset); +free_bcm_32k_clk: + if (bcm4329_rfkill->bt_32k_clk && enable) + clk_disable(bcm4329_rfkill->bt_32k_clk); + if (bcm4329_rfkill->bt_32k_clk) + clk_put(bcm4329_rfkill->bt_32k_clk); + kfree(bcm4329_rfkill); + return -ENODEV; +} + +static int bcm4329_rfkill_remove(struct platform_device *pdev) +{ + struct rfkill *bt_rfkill = platform_get_drvdata(pdev); + + if (bcm4329_rfkill->bt_32k_clk) + clk_put(bcm4329_rfkill->bt_32k_clk); + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + gpio_free(bcm4329_rfkill->gpio_shutdown); + gpio_free(bcm4329_rfkill->gpio_reset); + kfree(bcm4329_rfkill); + + return 0; +} + +static struct platform_driver bcm4329_rfkill_driver = { + .probe = bcm4329_rfkill_probe, + .remove = bcm4329_rfkill_remove, + .driver = { + .name = "bcm4329_rfkill", + .owner = THIS_MODULE, + }, +}; + +static int __init bcm4329_rfkill_init(void) +{ + return platform_driver_register(&bcm4329_rfkill_driver); +} + +static void __exit bcm4329_rfkill_exit(void) +{ + platform_driver_unregister(&bcm4329_rfkill_driver); +} + +module_init(bcm4329_rfkill_init); +module_exit(bcm4329_rfkill_exit); + +MODULE_DESCRIPTION("BCM4329 rfkill"); +MODULE_AUTHOR("NVIDIA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig new file mode 100755 index 000000000000..99ea1c6aa8e2 --- /dev/null +++ b/drivers/misc/mpu3050/Kconfig @@ -0,0 +1,54 @@ +
+menu "Motion Sensors Support"
+
+config SENSORS_MPU3050
+ tristate "MPU3050 Gyroscope Driver"
+ depends on I2C
+ help
+ If you say yes here you get support for the MPU3050 Gyroscope driver
+ This driver can also be built as a module. If so, the module
+ will be called mpu3050.
+
+config SENSORS_MPU3050_DEBUG
+ bool "MPU3050 debug"
+ depends on SENSORS_MPU3050
+ help
+ If you say yes here you get extra debug messages from the MPU3050
+ and other slave sensors.
+
+choice
+ prompt "Accelerometer Type"
+ depends on SENSORS_MPU3050
+ default SENSORS_KXTF9_MPU
+
+config SENSORS_ACCELEROMETER_NONE
+ bool "NONE"
+ help
+ This disables accelerometer support for the MPU3050
+
+config SENSORS_KXTF9_MPU
+ bool "Kionix KXTF9"
+ help
+ This enables support for the Kionix KXFT9 accelerometer
+
+endchoice
+
+choice
+ prompt "Compass Type"
+ depends on SENSORS_MPU3050
+ default SENSORS_AK8975_MPU
+
+config SENSORS_COMPASS_NONE
+ bool "NONE"
+ help
+ This disables compass support for the MPU3050
+
+config SENSORS_AK8975_MPU
+ bool "AKM ak8975"
+ help
+ This enables support for the AKM ak8975 compass
+
+endchoice
+
+endmenu
+
diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile new file mode 100755 index 000000000000..99955ad487fc --- /dev/null +++ b/drivers/misc/mpu3050/Makefile @@ -0,0 +1,37 @@ +
+# Kernel makefile for motions sensors
+#
+#
+
+# MPU
+obj-$(CONFIG_SENSORS_MPU3050) += mpu3050.o
+mpu3050-objs += mpuirq.o \
+ mpu-dev.o \
+ mpu-i2c.o \
+ mlsl-kernel.o \
+ mlos-kernel.o \
+ $(MLLITE_DIR)mldl_cfg.o
+
+#
+# Accel options
+#
+ifdef CONFIG_SENSORS_KXTF9_MPU
+mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o
+endif
+
+#
+# Compass options
+#
+ifdef CONFIG_SENSORS_AK8975_MPU
+mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o
+endif
+
+EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \
+ -I$(M)/../../include \
+ -Idrivers/misc/mpu3050 \
+ -Iinclude/linux
+
+ifdef CONFIG_SENSORS_MPU3050_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/misc/mpu3050/README b/drivers/misc/mpu3050/README new file mode 100755 index 000000000000..8ff0c3009eca --- /dev/null +++ b/drivers/misc/mpu3050/README @@ -0,0 +1,138 @@ +Kernel driver mpu3050 +===================== + +Supported chips: + * Invensense IMU3050 + Prefix: 'mpu3050' + Datasheet: + PS-MPU-3000A-00.2.4b.pdf + +Author: Invensense <http://invensense.com> + +Description +----------- +The mpu3050 is a motion processor that controls the mpu3050 gyroscope, a slave +accelerometer and compass. This document describes how to install the driver +into a linux kernel and a small note about how to set up the file permissions +in an android file system. + +Sysfs entries +------------- +/dev/mpu +/dev/mpuirq + +General Remarks +--------------- + +Valid addresses for the MPU3050 is 0x68. +Accelerometer must be on the secondary I2C bus. + +Programming the chip using /dev/mpu +---------------------------------- +Programming of the MPU3050 is done by first opening the /dev/mpu file and +then performing a series of IOCTLS on the handle returned. The IOCTL codes can +be found in mpu3050.h. Typically this is done by the mllite library in user +space. + +Adding to a Kernel +================== + +The mpu3050 driver is designed to be inserted in the drivers/misc part of the +kernel. Copy the mpu3050 directory and the mpu3050 include file to: + + <kernel root dir>/drivers/misc/mpu3050 + <kernel root dir>/include/linux/mpu3050.h + +respectively. + +After this is done the drivers/misc/Kconfig must be edited to add the line: + + source "drivers/misc/mpu3050/Kconfig" + +Similarly drivers/misc/Makefile must be edited to add the line: + + obj-y += mpu3050/ + +Configuration can then be done as normal. + +Board and Platform Data +----------------------- + +In order for the driver to work, board and platform data specific to the device +needs to be added to the board file. A mpu3050_platform_data structure must +be created and populatd and set in the i2c_board_info_structure. For details of +each structure member see mpu3050.h. All values below are modified for the ventana +platform. You should add these lines into the +kernel/arch/arm/mach-tegra/board-generic.c file. + +#include <linux/mpu3050.h> + +static struct mpu3050_platform_data mpu3050_data = { + .int_config = 0x10, + .orientation = { 0, -1, 0, + -1, 0, 0, + 0, 0, -1 }, //Orientation matrix for MPU on ventana + .level_shifter = 0, + .accel = { + .get_slave_descr = kxtf9_get_slave_descr, + .adapt_num = 0, + .bus = EXT_SLAVE_BUS_SECONDARY, + .address = 0x0F, + .orientation = { 0, -1, 0, + -1, 0, 0, + 0, 0, -1 }, //Orientation matrix for Kionix on ventana + }, + + + .compass = { + .get_slave_descr = ak8975_get_slave_descr, + .adapt_num = 3, //bus number 3 on ventana + .bus = EXT_SLAVE_BUS_PRIMARY, + .address = 0x0C, + .orientation = { 1, 0, 0, + 0, -1, 0, + 0, 0, -1 }, //Orientation matrix for AKM on ventana + }, + +}; + +static struct i2c_board_info __initdata mpu3050_i2c0_boardinfo[] = { + { + I2C_BOARD_INFO("mpu3050", 0x68), + /*.irq = 299,*/ + .platform_data = &mpu3050_data, + }, +}; + +Note: If you are unsure where to add this code, look for other instances of "i2c_board_info" +and copy paste this code after one of them. + +After this is done, we must register the board upon initialization. This is done in the +i2c_device_setup function in the board-generic.c file. Look for this function and add these +lines of code: + +if (ARRAY_SIZE(mpu3050_i2c0_boardinfo)) + i2c_register_board_info(0, mpu3050_i2c0_boardinfo, + ARRAY_SIZE(mpu3050_i2c0_boardinfo)); + +Before you can build the kernel, you will need to remove the existing NVidia AK8975 driver for the compass. +In the board-generic.c file, rename the instance of CONFIG_SENSORS_AK8975 to NVIDIA_CONFIG_SENSORS_AK8975. +In kernel/drivers/hwmon/Makefile, rename that instance of CONFIG_SENSORS_AK8975 to NVIDIA_CONFIG_SENSORS_AK8975 as well. +This will prevent NVidia's driver for the compass from building. + +Now you can build the new kernel. First, we must configure the kernel. Take the tegra_ventana_android_defconfig +file from this package and replace the existing one in the kernel/arch/arm/configs directory. In the root kernel +directory, you can then run: + +export CCOMPILER=/<path to android environment>/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- +make ARCH=arm CROSS_COMPILE=$CCOMPILER mrproper +make ARCH=arm CROSS_COMPILE=$CCOMPILER tegra_ventana_android_defconfig +make ARCH=arm CROSS_COMPILE=$CCOMPILER + +This should build your zImage, which you will find in kernel/arch/arm/boot/zImage. You can use the mkbootimg utility to then +make a boot.img: + + ./mkbootimg --kernel <path to android system>/kernel/arch/arm/boot/zImage --ramdisk <path to android system>/out/target/product/ventana/ramdisk.img --output boot.img + +You can then flash this boot.img using the nvflash utility. + diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c new file mode 100755 index 000000000000..ecf9e7dfd3d7 --- /dev/null +++ b/drivers/misc/mpu3050/accel/kxtf9.c @@ -0,0 +1,144 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: kxtf9.c 3867 2010-10-09 01:06:18Z prao $ + * + *******************************************************************************/ + +/** + * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file kxtf9.c + * @brief Accelerometer setup and handling methods. +**/ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include <linux/module.h> +#endif + +#include "mpu3050.h" +#include "mlsl.h" +#include "mlos.h" + +#include <log.h> +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +/***************************************** + Accelerometer Initialization Functions +*****************************************/ + +static int kxtf9_suspend(mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + /* RAM reset */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1d, 0xcd); + return result; +} + +/* full scale setting - register and mask */ +#define ACCEL_KIONIX_CTRL_REG (0x1b) +#define ACCEL_KIONIX_CTRL_MASK (0x18) + +static int kxtf9_resume(mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + unsigned char reg; + + /* RAM reset */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1d, 0xcd); + MLOSSleep(10); + /* Wake up */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0x42); + /* INT_CTRL_REG1: */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1e, 0x14); + /* WUF_THRESH: */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x5a, 0x00); + /* DATA_CTRL_REG */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x04); + /* WUF_TIMER */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x29, 0x02); + + /* Full Scale */ + reg = 0xc2; + reg &= ~ACCEL_KIONIX_CTRL_MASK; + reg |= 0x00; /* TODO FIXME michelle */ + if (slave->range.mantissa == 2) { + reg |= 0x00; + } else if (slave->range.mantissa == 4) { + reg |= 0x08; + } else if (slave->range.mantissa == 8) { + reg |= 0x10; + } + /* Normal operation */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, reg); + MLOSSleep(50); + + return ML_SUCCESS; +} + +static int kxtf9_read(mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +static struct ext_slave_descr kxtf9_descr = { + /*.suspend = */ kxtf9_suspend, + /*.resume = */ kxtf9_resume, + /*.read = */ kxtf9_read, + /*.name = */ "kxtf9", + /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, + /*.id = */ ACCEL_ID_KXTF9, + /*.reg = */ 0x06, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, + /*.range = */ {2, 0}, +}; + +struct ext_slave_descr *kxtf9_get_slave_descr(void) +{ + return &kxtf9_descr; +} + +#ifdef __KERNEL__ +EXPORT_SYMBOL(kxtf9_get_slave_descr); +#endif + +/** + * @} +**/ diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c new file mode 100755 index 000000000000..fb4c033556b3 --- /dev/null +++ b/drivers/misc/mpu3050/compass/ak8975.c @@ -0,0 +1,146 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: ak8975.c 3879 2010-10-12 03:12:37Z mcaramello $ + * + *******************************************************************************/ + +/** + * @defgroup COMPASSDL (Motion Library - Accelerometer Driver Layer) + * @brief Provides the interface to setup and handle an accelerometers + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file AK8975.c + * @brief Magnetometer setup and handling methods for AKM 8975 compass. +**/ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#ifdef __KERNEL__ +#include <linux/module.h> +#endif + +#include "mpu3050.h" +#include "mlsl.h" +#include "mlos.h" + +#include <log.h> +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +#define AK8975_REG_ST1 (0x02) +#define AK8975_REG_HXL (0x03) +#define AK8975_REG_ST2 (0x09) + +#define AK8975_REG_CNTL (0x0A) + +#define AK8975_CNTL_MODE_POWER_DOWN (0x00) +#define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x01) + +int ak8975_suspend(mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + return result; +} + +int ak8975_resume(mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = ML_SUCCESS; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_SINGLE_MEASUREMENT); + return result; +} + +int ak8975_read(mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + unsigned char stat; + unsigned char stat2; + int result = ML_SUCCESS; + + result = MLSLSerialRead(mlsl_handle, pdata->address, + AK8975_REG_ST1, 1, &stat); + ERROR_CHECK(result); + if (stat & 0x01) { + result = MLSLSerialRead(mlsl_handle, pdata->address, + AK8975_REG_HXL, 6, + (unsigned char *)data); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, pdata->address, + AK8975_REG_ST2, 1, &stat2); + ERROR_CHECK(result); + if (stat2 & 0x04) { /*data error */ + return ML_ERROR_COMPASS_DATA_NOT_READY; + } + if (stat2 & 0x08) { + return ML_ERROR_COMPASS_DATA_OVERFLOW; + } + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_SINGLE_MEASUREMENT); + return ML_SUCCESS; + } else if (stat & 0x02) { + result = MLSLSerialRead(mlsl_handle, pdata->address, + AK8975_REG_ST2, 1, &stat2); + ERROR_CHECK(result); + return ML_ERROR_COMPASS_DATA_OVERFLOW; + } else { + return ML_ERROR_COMPASS_DATA_NOT_READY; + } + +} + +struct ext_slave_descr ak8975_descr = { + /*.suspend = */ ak8975_suspend, + /*.resume = */ ak8975_resume, + /*.read = */ ak8975_read, + /*.name = */ "ak8975", + /*.type = */ EXT_SLAVE_TYPE_COMPASS, + /*.id = */ COMPASS_ID_AKM, + /*.reg = */ 0x06, + /*.len = */ 6, + /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, + /*.range = */ {9830, 4000} +}; + +struct ext_slave_descr *ak8975_get_slave_descr(void) +{ + return &ak8975_descr; +} + +#ifdef __KERNEL__ +EXPORT_SYMBOL(ak8975_get_slave_descr); +#endif + +/** + * @} +**/ diff --git a/drivers/misc/mpu3050/log.h b/drivers/misc/mpu3050/log.h new file mode 100755 index 000000000000..6cb7eae4afcf --- /dev/null +++ b/drivers/misc/mpu3050/log.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2010 InvenSense Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +// C/C++ logging functions. See the logging documentation for API details. +// +// We'd like these to be available from C code (in case we import some from +// somewhere), so this has a C interface. +// +// The output will be correct when the log file is shared between multiple +// threads and/or multiple processes so long as the operating system +// supports O_APPEND. These calls have mutex-protected data structures +// and so are NOT reentrant. Do not use MPL_LOG in a signal handler. +*/ +#ifndef _LIBS_CUTILS_MPL_LOG_H +#define _LIBS_CUTILS_MPL_LOG_H + +#include <stdarg.h> + +#ifdef ANDROID +#include <utils/Log.h> /* For the LOG macro */ +#endif + +#ifdef __KERNEL__ +#include <linux/kernel.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Normally we strip MPL_LOGV (VERBOSE messages) from release builds. + * You can modify this (for example with "#define MPL_LOG_NDEBUG 0" + * at the top of your source file) to change that behavior. + */ +#define MPL_LOGV /* comment this out to enable VERBOSE level logging */ +#ifndef MPL_LOG_NDEBUG +#ifdef NDEBUG +#define MPL_LOG_NDEBUG 1 +#else +#define MPL_LOG_NDEBUG 0 +#endif +#endif + +#ifdef __KERNEL__ +#define MPL_LOG_UNKNOWN MPL_LOG_VERBOSE +#define MPL_LOG_DEFAULT KERN_DEFAULT +#define MPL_LOG_VERBOSE KERN_CONT +#define MPL_LOG_DEBUG KERN_NOTICE +#define MPL_LOG_INFO KERN_INFO +#define MPL_LOG_WARN KERN_WARNING +#define MPL_LOG_ERROR KERN_ERR +#define MPL_LOG_SILENT MPL_LOG_VERBOSE + +#else + /* Based off the log priorities in android + /system/core/include/android/log.h */ +#define MPL_LOG_UNKNOWN (0) +#define MPL_LOG_DEFAULT (1) +#define MPL_LOG_VERBOSE (2) +#define MPL_LOG_DEBUG (3) +#define MPL_LOG_INFO (4) +#define MPL_LOG_WARN (5) +#define MPL_LOG_ERROR (6) +#define MPL_LOG_SILENT (8) +#endif + +/* + * This is the local tag used for the following simplified + * logging macros. You can change this preprocessor definition + * before using the other macros to change the tag. + */ +#ifndef MPL_LOG_TAG +#ifdef __KERNEL__ +#define MPL_LOG_TAG +#else +#define MPL_LOG_TAG NULL +#endif +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Simplified macro to send a verbose log message using the current MPL_LOG_TAG. + */ +#define MPL_LOGV +#ifndef MPL_LOGV +#if MPL_LOG_NDEBUG +#define MPL_LOGV(...) ((void)0) +#else +#define MPL_LOGV(...) ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__)) +#endif +#endif + +#ifndef CONDITION +#define CONDITION(cond) ((cond) != 0) +#endif + +#ifndef MPL_LOGV_IF +#if MPL_LOG_NDEBUG +#define MPL_LOGV_IF(cond, ...) ((void)0) +#else +#define MPL_LOGV_IF(cond, ...) \ + ((CONDITION(cond)) \ + ? ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__)) \ + : (void)0) +#endif +#endif + +/* + * Simplified macro to send a debug log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGD +#define MPL_LOGD(...) ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef MPL_LOGD_IF +#define MPL_LOGD_IF(cond, ...) \ + ((CONDITION(cond)) \ + ? ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__)) \ + : (void)0) +#endif + +/* + * Simplified macro to send an info log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGI +#define MPL_LOGI(...) ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef MPL_LOGI_IF +#define MPL_LOGI_IF(cond, ...) \ + ((CONDITION(cond)) \ + ? ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__)) \ + : (void)0) +#endif + +/* + * Simplified macro to send a warning log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGW +#define MPL_LOGW(...) ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef MPL_LOGW_IF +#define MPL_LOGW_IF(cond, ...) \ + ((CONDITION(cond)) \ + ? ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__)) \ + : (void)0) +#endif + +/* + * Simplified macro to send an error log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGE +#define MPL_LOGE(...) ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__)) +#endif + +#ifndef MPL_LOGE_IF +#define MPL_LOGE_IF(cond, ...) \ + ((CONDITION(cond)) \ + ? ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__)) \ + : (void)0) +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Log a fatal error. If the given condition fails, this stops program + * execution like a normal assertion, but also generating the given message. + * It is NOT stripped from release builds. Note that the condition test + * is -inverted- from the normal assert() semantics. + */ +#define MPL_LOG_ALWAYS_FATAL_IF(cond, ...) \ + ((CONDITION(cond)) \ + ? ((void)android_printAssert(#cond, MPL_LOG_TAG, __VA_ARGS__)) \ + : (void)0) + +#define MPL_LOG_ALWAYS_FATAL(...) \ + (((void)android_printAssert(NULL, MPL_LOG_TAG, __VA_ARGS__))) + +/* + * Versions of MPL_LOG_ALWAYS_FATAL_IF and MPL_LOG_ALWAYS_FATAL that + * are stripped out of release builds. + */ +#if MPL_LOG_NDEBUG + +#define MPL_LOG_FATAL_IF(cond, ...) ((void)0) +#define MPL_LOG_FATAL(...) ((void)0) + +#else + +#define MPL_LOG_FATAL_IF(cond, ...) MPL_LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__) +#define MPL_LOG_FATAL(...) MPL_LOG_ALWAYS_FATAL(__VA_ARGS__) + +#endif + +/* + * Assertion that generates a log message when the assertion fails. + * Stripped out of release builds. Uses the current MPL_LOG_TAG. + */ +#define MPL_LOG_ASSERT(cond, ...) MPL_LOG_FATAL_IF(!(cond), __VA_ARGS__) +/*#define MPL_LOG_ASSERT(cond) MPL_LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) */ + +/* --------------------------------------------------------------------- */ + +/* + * Basic log message macro. + * + * Example: + * MPL_LOG(MPL_LOG_WARN, NULL, "Failed with error %d", errno); + * + * The second argument may be NULL or "" to indicate the "global" tag. + */ +#ifndef MPL_LOG +#define MPL_LOG(priority, tag, ...) \ + MPL_LOG_PRI(priority, tag, __VA_ARGS__) +#endif + +/* + * Log macro that allows you to specify a number for the priority. + */ +#ifndef MPL_LOG_PRI +#ifdef ANDROID +#define MPL_LOG_PRI(priority, tag, ...) \ + LOG(priority, tag, __VA_ARGS__) +#elif defined __KERNEL__ +#define MPL_LOG_PRI(priority, tag, ...) \ + printk(MPL_##priority tag __VA_ARGS__) +#else +#define MPL_LOG_PRI(priority, tag, ...) \ + _MLPrintLog(MPL_##priority, tag, __VA_ARGS__) +#endif +#endif + +/* + * Log macro that allows you to pass in a varargs ("args" is a va_list). + */ +#ifndef MPL_LOG_PRI_VA +#ifdef ANDROID +#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \ + android_vprintLog(priority, NULL, tag, fmt, args) +#elif defined __KERNEL__ +#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \ + vprintk(MPL_##priority tag fmt, args) +#else +#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \ + _MLPrintVaLog(priority, NULL, tag, fmt, args) +#endif +#endif + +/* --------------------------------------------------------------------- */ + +/* + * =========================================================================== + * + * The stuff in the rest of this file should not be used directly. + */ + +#ifndef ANDROID + int _MLPrintLog(int priority, const char *tag, const char *fmt, ...); + int _MLPrintVaLog(int priority, const char *tag, const char *fmt, + va_list args); +/* Final implementation of actual writing to a character device */ + int _MLWriteLog(const char *buf, int buflen); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* _LIBS_CUTILS_MPL_LOG_H */ diff --git a/drivers/misc/mpu3050/mldl_cfg.c b/drivers/misc/mpu3050/mldl_cfg.c new file mode 100755 index 000000000000..d96b0a72a549 --- /dev/null +++ b/drivers/misc/mpu3050/mldl_cfg.c @@ -0,0 +1,872 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: mldl_cfg.c 3881 2010-10-12 18:58:45Z prao $ + * + ******************************************************************************/ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_cfg.c + * @brief The Motion Library Driver Layer. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#include <stddef.h> + +#include "mldl_cfg.h" +#include "mpu3050.h" + +#include "mlsl.h" +#include "mlos.h" + +#include "log.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "mldl_cfg:" + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +/* ---------------------- */ +/* - Static Functions. - */ +/* ---------------------- */ + +/** + * @internal + * @brief MLDLCfgDMP configures the Digital Motion Processor internal to + * the MPU. The DMP can be enabled or disabled and the start address + * can be set. + * + * @param enableRun Enables the DMP processing if set to TRUE. + * @param enableFIFO Enables DMP output to the FIFO if set to TRUE. + * + * @return Zero if the command is successful, an error code otherwise. + */ +static int MLDLCtrlDmp(struct mldl_cfg *pdata, mlsl_handle_t mlsl_handle, + bool enableRun, bool enableFIFO) +{ + unsigned char b; + + MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, 1, &b); + if (enableRun) { + b |= BIT_DMP_EN; + } else { + b &= ~BIT_DMP_EN; + } + + if (enableFIFO) { + b |= BIT_FIFO_EN; + } + + b |= BIT_DMP_RST; + + MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, b); + + return ML_SUCCESS; +} + +/** + * @brief Starts the DMP running + * + * @return ML_SUCCESS or non-zero error code + */ +static int MLDLDmpStart(struct mldl_cfg *pdata, mlsl_handle_t mlsl_handle) +{ + unsigned char fifoBuf[2]; + unsigned char tries = 0; + unsigned char userCtrlReg; + int result; + unsigned short len = !0; + + result = MLSLSerialRead(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, 1, &userCtrlReg); + + while (len != 0 && tries < 6) { + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, + ((userCtrlReg & (~BIT_FIFO_EN)) + | BIT_FIFO_RST)); + MLSLSerialRead(mlsl_handle, pdata->addr, + MPUREG_FIFO_COUNTH, 2, fifoBuf); + len = (((unsigned short)fifoBuf[0] << 8) + | (unsigned short)fifoBuf[1]); + tries++; + } + + MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, userCtrlReg); + + return MLDLCtrlDmp(pdata, mlsl_handle, + pdata->dmp_enable, pdata->fifo_enable); +} + +/** + * @brief enables/disables the I2C pass through to the accelerometer device. + * @param enable Non-zero to enable pass through. + * @return ML_SUCCESS if the command is successful, an error code otherwise. + */ +static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg, + mlsl_handle_t mlsl_handle, unsigned char enable) +{ + unsigned char b; + int result; + +#ifdef ML_USE_DMP_SIM + if (!MLGetGyroPresent()) /* done this way so that pc demo */ + return ML_SUCCESS; /* w/arm board works with universal api */ +#endif + + /*---- get current 'USER_CTRL' into b ----*/ + result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, 1, &b); + ERROR_CHECK(result); + + /* No change */ + if ((b & BIT_AUX_IF_EN) != (enable * BIT_AUX_IF_EN)) + return ML_SUCCESS; + + b &= ~BIT_AUX_IF_EN; + + if (!enable) { + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, + (b | BIT_AUX_IF_EN)); + ERROR_CHECK(result); + } else { + /* Coming out of I2C is tricky due to severla erratta. Do not modify + * this algorithm */ + /* + * 1) wait for the right time and send the command to change the ime + * i2c slave address to an invalid address that will get naked + * + * 0x00 is broadcast. 0x7F is ulikely to be used by any accels. + */ + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_AUX_SLV_ADDR, 0x7F); + ERROR_CHECK(result); + /* + * 2) wait enough time for a nack to occur, then go into bypass mode: + */ + MLOSSleep(2); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, (b)); + ERROR_CHECK(result); + /* + * 3) wait for up to one MPU cycle then restore the slave address + */ + MLOSSleep(5); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_AUX_SLV_ADDR, + mldl_cfg->pdata->accel.address); + ERROR_CHECK(result); + + /* + * 4) reset the ime interface + */ + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, + (b | BIT_AUX_IF_RST)); + ERROR_CHECK(result); + MLOSSleep(2); + } + + return result; +} + +struct tsProdRevMap { + /*unsigned char prodRev; */ + unsigned char siliconRev; + unsigned short sensTrim; +}; + +#define NUM_OF_PROD_REVS (DIM(prodRevsMap)) + +#define OLDEST_PROD_REV_SUPPORTED 11 +static struct tsProdRevMap prodRevsMap[] = { + {0, 0}, + {MPU_SILICON_REV_A4, 131}, /* 1 A? OBSOLETED */ + {MPU_SILICON_REV_A4, 131}, /* 2 | */ + {MPU_SILICON_REV_A4, 131}, /* 3 V */ + {MPU_SILICON_REV_A4, 131}, /* 4 */ + {MPU_SILICON_REV_A4, 131}, /* 5 */ + {MPU_SILICON_REV_A4, 131}, /* 6 */ + {MPU_SILICON_REV_A4, 131}, /* 7 */ + {MPU_SILICON_REV_A4, 131}, /* 8 */ + {MPU_SILICON_REV_A4, 131}, /* 9 */ + {MPU_SILICON_REV_A4, 131}, /* 10 */ + {MPU_SILICON_REV_B1, 131}, /* 11 B1 */ + {MPU_SILICON_REV_B1, 131}, /* 12 | */ + {MPU_SILICON_REV_B1, 131}, /* 13 V */ + {MPU_SILICON_REV_B1, 131}, /* 14 B4 */ + {MPU_SILICON_REV_B4, 131}, /* 15 | {MPU_SILICON_REV_B4, 131}, // 16 V */ + {MPU_SILICON_REV_B4, 131}, /* 17 */ + {MPU_SILICON_REV_B4, 131}, /* 18 */ + {MPU_SILICON_REV_B4, 115}, /* 19 */ + {MPU_SILICON_REV_B4, 115}, /* 20 */ + {MPU_SILICON_REV_B6, 131}, /* 21 B6 */ + {MPU_SILICON_REV_B4, 115}, /* 22 B4 */ +}; + +/** + * @internal + * @brief Get the silicon revision ID from OTP. + * The silicon revision number is in read from OTP bank 0, + * ADDR6[7:2]. The corresponding ID is retrieved by lookup + * in a map. + * @return The silicon revision ID (0 on error). + */ +static int MLDLGetSiliconRev(struct mldl_cfg *pdata, mlsl_handle_t mlsl_handle) +{ + int result; + unsigned char index = 0x00; + unsigned char bank = + (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0); + unsigned short memAddr = ((bank << 8) | 0x06); + + result = MLSLSerialReadMem(mlsl_handle, pdata->addr, + memAddr, 1, &index); + if (result) + return result; + index >>= 2; + + if (index < OLDEST_PROD_REV_SUPPORTED || NUM_OF_PROD_REVS < index) { + pdata->silicon_revision = 0; + return ML_ERROR_INVALID_MODULE; + } else { + pdata->silicon_revision = prodRevsMap[index].siliconRev; + pdata->trim = prodRevsMap[index].sensTrim; + } + return result; +} + +/** + * @brief Enable/Disable the use MPU's VDDIO level shifters. + * When enabled the voltage interface with AUX or other external + * accelerometer is using Vlogic instead of VDD (supply). + * + * @note Must be called after MLSerialOpen(). + * @note Typically be called before MLDmpOpen(). + * If called after MLDmpOpen(), must be followed by a call to + * MLDLApplyLevelShifterBit() to write the setting on the hw. + * + * @param[in] enable + * 1 to enable, 0 to disable + * + * @return ML_SUCCESS if successfull, a non-zero error code otherwise. +**/ +static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata, + mlsl_handle_t mlsl_handle, + unsigned char enable) +{ + int result; + unsigned char reg; + unsigned char mask; + unsigned char regval; + + if (0 == pdata->silicon_revision) { + return ML_ERROR_INVALID_PARAMETER; + } + + /*-- on parts before B6 the VDDIO bit is bit 7 of ACCEL_BURST_ADDR -- + NOTE: this is incompatible with ST accelerometers where the VDDIO + bit MUST be set to enable ST's internal logic to autoincrement + the register address on burst reads --*/ + if ((pdata->silicon_revision & 0xf) < MPU_SILICON_REV_B6) { + reg = MPUREG_ACCEL_BURST_ADDR; + mask = 0x80; + } else { + /*-- on B6 parts the VDDIO bit was moved to FIFO_EN2 => + the mask is always 0x04 --*/ + reg = MPUREG_FIFO_EN2; + mask = 0x04; + } + + result = MLSLSerialRead(mlsl_handle, pdata->addr, reg, 1, ®val); + if (result) + return result; + + if (enable) + regval |= mask; + else + regval &= ~mask; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, reg, regval); + + return result; +} + +/** + * @internal + * @brief This function controls the power management on the MPU device. + * The entire chip can be put to low power sleep mode, or individual + * gyros can be turned on/off. + * + * Putting the device into sleep mode depending upon the changing needs + * of the associated applications is a recommended method for reducing + * power consuption. It is a safe opearation in that sleep/wake up of + * gyros while running will not result in any interruption of data. + * + * Although it is entirely allowed to put the device into full sleep + * while running the DMP, it is not recomended because it will disrupt + * the ongoing calculations carried on inside the DMP and consequently + * the sensor fusion algorithm. Furthermore, while in sleep mode + * read & write operation from the app processor on both registers and + * memory are disabled and can only regained by restoring the MPU in + * normal power mode. + * Disabling any of the gyro axis will reduce the associated power + * consuption from the PLL but will not stop the DMP from running + * state. + * + * @param reset + * Non-zero to reset the device. Note that this setting + * is volatile and the corresponding register bit will + * clear itself right after. + * @param sleep + * Non-zero to put device into full sleep. + * @param disable_gx + * Non-zero to disable gyro X. + * @param disable_gy + * Non-zero to disable gyro Y. + * @param disable_gz + * Non-zero to disable gyro Z. + * + * @return ML_SUCCESS if successfull; a non-zero error code otherwise. + */ +static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, + mlsl_handle_t mlsl_handle, + unsigned char reset, + unsigned char sleep, + unsigned char disable_gx, + unsigned char disable_gy, unsigned char disable_gz) +{ + unsigned char b; + int result; + + result = + MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1, &b); + ERROR_CHECK(result); + + /* If we are awake, we need to put it in bypass before resetting */ + if ((!(b & BIT_SLEEP)) && reset) { + result = MLDLSetI2CBypass(pdata, mlsl_handle, 1); + } + + /* Reset if requested */ + if (reset) { + result = + MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b | BIT_H_RESET); + MLOSSleep(5); + } + + /* Some chips are awake after reset and some are asleep, check the status */ + result = + MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1, &b); + ERROR_CHECK(result); + + /* Update the suspended state just in case we return early */ + if (b & BIT_SLEEP) { + pdata->is_suspended = TRUE; + } else { + pdata->is_suspended = FALSE; + } + + if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) + == ((sleep * BIT_SLEEP) | + (disable_gz * BIT_STBY_XG) | + (disable_gy * BIT_STBY_YG) | (disable_gz * BIT_STBY_ZG))) { + return ML_SUCCESS; + } + + /* + * This specific transition between states needs to be reinterpreted: + * (1,1,1,1) -> (0,1,1,1) has to become + * (1,1,1,1) -> (1,0,0,0) -> (0,1,1,1) + * where + * (1,1,1,1) stands for (sleep=1,disable_gx=1,disable_gy=1,disable_gz=1) + */ + if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG) /* (1,1,1,1) */ + && ((!sleep) && disable_gx && disable_gy && disable_gz)) { /* (0,1,1,1) */ + + result = MLDLPowerMgmtMPU(pdata, mlsl_handle, 0, 1, 0, 0, 0); + if (result) + return result; + b |= BIT_SLEEP; + b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG); + } + + if ((b & BIT_SLEEP) != (sleep * BIT_SLEEP)) { + if (sleep) { + result = MLDLSetI2CBypass(pdata, mlsl_handle, 1); + ERROR_CHECK(result); + b |= BIT_SLEEP; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b); + ERROR_CHECK(result); + pdata->is_suspended = TRUE; + } else { + b &= ~BIT_SLEEP; + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b); + ERROR_CHECK(result); + pdata->is_suspended = FALSE; + MLOSSleep(5); + } + } + /*--- + WORKAROUND FOR PUTTING GYRO AXIS in STAND-BY MODE + 1) put one axis at a time in stand-by + ---*/ + if ((b & BIT_STBY_XG) != (disable_gx * BIT_STBY_XG)) { + b ^= BIT_STBY_XG; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b); + ERROR_CHECK(result); + } + if ((b & BIT_STBY_YG) != (disable_gy * BIT_STBY_YG)) { + b ^= BIT_STBY_YG; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b); + ERROR_CHECK(result); + } + if ((b & BIT_STBY_ZG) != (disable_gz * BIT_STBY_ZG)) { + b ^= BIT_STBY_ZG; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b); + ERROR_CHECK(result); + } + + return ML_SUCCESS; +} + +void mpu3050_print_cfg(struct mldl_cfg *mldl_cfg) +{ + struct mpu3050_platform_data *pdata = mldl_cfg->pdata; + struct ext_slave_platform_data *accel = &mldl_cfg->pdata->accel; + struct ext_slave_platform_data *compass = &mldl_cfg->pdata->compass; + + MPL_LOGD("mldl_cfg.addr = %02x\n", mldl_cfg->addr); + MPL_LOGD("mldl_cfg.int_config = %02x\n", mldl_cfg->int_config); + MPL_LOGD("mldl_cfg.ext_sync = %02x\n", mldl_cfg->ext_sync); + MPL_LOGD("mldl_cfg.full_scale = %02x\n", mldl_cfg->full_scale); + MPL_LOGD("mldl_cfg.lpf = %02x\n", mldl_cfg->lpf); + MPL_LOGD("mldl_cfg.clk_src = %02x\n", mldl_cfg->clk_src); + MPL_LOGD("mldl_cfg.divider = %02x\n", mldl_cfg->divider); + MPL_LOGD("mldl_cfg.dmp_enable = %02x\n", mldl_cfg->dmp_enable); + MPL_LOGD("mldl_cfg.fifo_enable = %02x\n", mldl_cfg->fifo_enable); + MPL_LOGD("mldl_cfg.dmp_cfg1 = %02x\n", mldl_cfg->dmp_cfg1); + MPL_LOGD("mldl_cfg.dmp_cfg2 = %02x\n", mldl_cfg->dmp_cfg2); + MPL_LOGD("mldl_cfg.offset_tc[0] = %02x\n", mldl_cfg->offset_tc[0]); + MPL_LOGD("mldl_cfg.offset_tc[1] = %02x\n", mldl_cfg->offset_tc[1]); + MPL_LOGD("mldl_cfg.offset_tc[2] = %02x\n", mldl_cfg->offset_tc[2]); + MPL_LOGD("mldl_cfg.silicon_revision = %02x\n", + mldl_cfg->silicon_revision); + MPL_LOGD("mldl_cfg.product_id = %02x\n", mldl_cfg->product_id); + MPL_LOGD("mldl_cfg.trim = %02x\n", mldl_cfg->trim); + + if (mldl_cfg->accel) { + MPL_LOGD("slave_accel->suspend = %02x\n", + (int)mldl_cfg->accel->suspend); + MPL_LOGD("slave_accel->resume = %02x\n", + (int)mldl_cfg->accel->resume); + MPL_LOGD("slave_accel->read = %02x\n", + (int)mldl_cfg->accel->read); + MPL_LOGD("slave_accel->type = %02x\n", + mldl_cfg->accel->type); + MPL_LOGD("slave_accel->reg = %02x\n", + mldl_cfg->accel->reg); + MPL_LOGD("slave_accel->len = %02x\n", + mldl_cfg->accel->len); + MPL_LOGD("slave_accel->endian = %02x\n", + mldl_cfg->accel->endian); + MPL_LOGD("slave_accel->range.mantissa= %02lx\n", + mldl_cfg->accel->range.mantissa); + MPL_LOGD("slave_accel->range.fraction= %02lx\n", + mldl_cfg->accel->range.fraction); + } else { + MPL_LOGD("slave_accel = NULL\n"); + } + + if (mldl_cfg->compass) { + MPL_LOGD("slave_compass->suspend = %02x\n", + (int)mldl_cfg->compass->suspend); + MPL_LOGD("slave_compass->resume = %02x\n", + (int)mldl_cfg->compass->resume); + MPL_LOGD("slave_compass->read = %02x\n", + (int)mldl_cfg->compass->read); + MPL_LOGD("slave_compass->type = %02x\n", + mldl_cfg->compass->type); + MPL_LOGD("slave_compass->reg = %02x\n", + mldl_cfg->compass->reg); + MPL_LOGD("slave_compass->len = %02x\n", + mldl_cfg->compass->len); + MPL_LOGD("slave_compass->endian = %02x\n", + mldl_cfg->compass->endian); + MPL_LOGD("slave_compass->range.mantissa= %02lx\n", + mldl_cfg->compass->range.mantissa); + MPL_LOGD("slave_compass->range.fraction= %02lx\n", + mldl_cfg->compass->range.fraction); + + } else { + MPL_LOGD("slave_compass = NULL\n"); + } + MPL_LOGD("accel->get_slave_descr = %x\n", + (unsigned int)accel->get_slave_descr); + MPL_LOGD("accel->adapt_num = %02x\n", accel->adapt_num); + MPL_LOGD("accel->bus = %02x\n", accel->bus); + MPL_LOGD("accel->address = %02x\n", accel->address); + MPL_LOGD("accel->orientation = \n" + " %2d %2d %2d\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n", + accel->orientation[0], accel->orientation[1], + accel->orientation[2], accel->orientation[3], + accel->orientation[4], accel->orientation[5], + accel->orientation[6], accel->orientation[7], + accel->orientation[8]); + MPL_LOGD("compass->get_slave_descr = %x\n", + (unsigned int)compass->get_slave_descr); + MPL_LOGD("compass->adapt_num = %02x\n", compass->adapt_num); + MPL_LOGD("compass->bus = %02x\n", compass->bus); + MPL_LOGD("compass->address = %02x\n", compass->address); + MPL_LOGD("compass->orientation = \n" + " %2d %2d %2d\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n", + compass->orientation[0], compass->orientation[1], + compass->orientation[2], compass->orientation[3], + compass->orientation[4], compass->orientation[5], + compass->orientation[6], compass->orientation[7], + compass->orientation[8]); + + MPL_LOGD("pdata->int_config = %02x\n", pdata->int_config); + MPL_LOGD("pdata->level_shifter = %02x\n", pdata->level_shifter); + MPL_LOGD("pdata->orientation = \n" + " %2d %2d %2d\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n", + pdata->orientation[0], pdata->orientation[1], + pdata->orientation[2], pdata->orientation[3], + pdata->orientation[4], pdata->orientation[5], + pdata->orientation[6], pdata->orientation[7], + pdata->orientation[8]); + + MPL_LOGD("Struct sizes: mldl_cfg: %d, " + "ext_slave_descr:%d, mpu3050_platform_data:%d: RamOffset: %d\n", + sizeof(struct mldl_cfg), sizeof(struct ext_slave_descr), + sizeof(struct mpu3050_platform_data), + offsetof(struct mldl_cfg, ram)); +} + +/******************************************************************************* + ******************************************************************************* + * Exported functions + ******************************************************************************* + ******************************************************************************/ + +/** + * Initializes the pdata structure to defaults. + * + * Opens the device to read silicon revision, product id and whoami. + * + * @param mldl_cfg + * The internal device configuration data structure. + * @param mlsl_handle + * The serial communication handle. + * + * @return ML_SUCCESS if silicon revision, product id and woami are supported + * by this software. + */ +int mpu3050_open(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle) +{ + int result; + /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */ + mldl_cfg->int_config = BIT_INT_ANYRD_2CLEAR | BIT_DMP_INT_EN; + mldl_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ; + mldl_cfg->lpf = MPU_FILTER_42HZ; + mldl_cfg->full_scale = MPU_FS_2000DPS; + mldl_cfg->divider = 4; + mldl_cfg->dmp_enable = 1; + mldl_cfg->fifo_enable = 1; + mldl_cfg->ext_sync = 0; + mldl_cfg->dmp_cfg1 = 0; + mldl_cfg->dmp_cfg2 = 0; + if (mldl_cfg->addr == 0) { +#ifdef __KERNEL__ + return ML_ERROR_INVALID_PARAMETER; +#else + mldl_cfg->addr = 0x68; +#endif + } + + /* + * Reset, + * Take the DMP out of sleep, and + * read the product_id, sillicon rev and whoami + */ + result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 1, 0, 0, 0, 0); + ERROR_CHECK(result); + + result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, + MPUREG_PRODUCT_ID, 1, &mldl_cfg->product_id); + ERROR_CHECK(result); + + /* Get the factory temperature compensation offsets */ + result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, + MPUREG_XG_OFFS_TC, 1, &mldl_cfg->offset_tc[0]); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, + MPUREG_YG_OFFS_TC, 1, &mldl_cfg->offset_tc[1]); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, + MPUREG_ZG_OFFS_TC, 1, &mldl_cfg->offset_tc[2]); + ERROR_CHECK(result); + + /* Configure the MPU */ + result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, 1, 0, 0, 0); + ERROR_CHECK(result); + return result; +} + +int mpu3050_resume(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + mlsl_handle_t accel_handle, + mlsl_handle_t compass_handle, + bool resume_accel, bool resume_compass) +{ + int result; + int ii; + int jj; + unsigned char reg; + + /* mpu3050_print_cfg(mldl_cfg); */ + /* Wake up the part */ + result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 1, 0, 0, 0, 0); + ERROR_CHECK(result); + + /* Configure the MPU */ + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_INT_CFG, + (mldl_cfg->int_config | mldl_cfg-> + pdata->int_config)); + ERROR_CHECK(result); + + result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, + MPUREG_PWR_MGM, 1, ®); + ERROR_CHECK(result); + reg &= ~BITS_CLKSEL; + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_PWR_MGM, mldl_cfg->clk_src | reg); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_SMPLRT_DIV, mldl_cfg->divider); + ERROR_CHECK(result); + + reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, + mldl_cfg->full_scale, mldl_cfg->lpf); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_DLPF_FS_SYNC, reg); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_DMP_CFG_1, mldl_cfg->dmp_cfg1); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_DMP_CFG_2, mldl_cfg->dmp_cfg2); + ERROR_CHECK(result); + + /* Write and verify memory */ + for (ii = 0; ii < MPU_MEM_NUM_RAM_BANKS; ii++) { + unsigned char read[128]; + result = MLSLSerialWriteMem(mlsl_handle, mldl_cfg->addr, + ((ii << 8)), + MPU_MEM_BANK_SIZE / 2, + mldl_cfg->ram[ii]); + ERROR_CHECK(result); + result = MLSLSerialReadMem(mlsl_handle, mldl_cfg->addr, + ((ii << 8) | 0), + MPU_MEM_BANK_SIZE / 2, read); + ERROR_CHECK(result); + + for (jj = 0; jj < MPU_MEM_BANK_SIZE / 2; jj++) { + /* skip the register memory locations */ + if (ii == 0 && jj < 20) + continue; + if (mldl_cfg->ram[ii][jj] != read[jj]) { + result = ML_ERROR_SERIAL_WRITE; + break; + } + } + ERROR_CHECK(result); + + result = MLSLSerialWriteMem(mlsl_handle, mldl_cfg->addr, + ((ii << 8) | MPU_MEM_BANK_SIZE / 2), + MPU_MEM_BANK_SIZE / 2, + &mldl_cfg->ram[ii][MPU_MEM_BANK_SIZE + / 2]); + ERROR_CHECK(result); + result = MLSLSerialReadMem(mlsl_handle, mldl_cfg->addr, + ((ii << 8) | MPU_MEM_BANK_SIZE / 2), + MPU_MEM_BANK_SIZE / 2, read); + ERROR_CHECK(result); + for (jj = 0; jj < MPU_MEM_BANK_SIZE / 2; jj++) { + if (mldl_cfg->ram[ii][MPU_MEM_BANK_SIZE / 2 + jj] != + read[jj]) { + result = ML_ERROR_SERIAL_WRITE; + break; + } + } + ERROR_CHECK(result); + } + + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_XG_OFFS_TC, + mldl_cfg->offset_tc[0]); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_YG_OFFS_TC, + mldl_cfg->offset_tc[1]); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, + MPUREG_ZG_OFFS_TC, + mldl_cfg->offset_tc[2]); + ERROR_CHECK(result); + + /* Configure slaves */ + result = MLDLSetLevelShifterBit(mldl_cfg, mlsl_handle, + mldl_cfg->pdata->level_shifter); + ERROR_CHECK(result); + + if (resume_accel) { + if ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume)) { + return ML_ERROR_INVALID_PARAMETER; + } + result = mldl_cfg->accel->resume(accel_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel); + ERROR_CHECK(result); + if (EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { + /* Address */ + result = + MLSLSerialWriteSingle(accel_handle, mldl_cfg->addr, + MPUREG_AUX_SLV_ADDR, + mldl_cfg->pdata-> + accel.address); + ERROR_CHECK(result); + /* Register */ + result = MLSLSerialRead(accel_handle, mldl_cfg->addr, + MPUREG_ACCEL_BURST_ADDR, 1, + ®); + ERROR_CHECK(result); + reg = ((reg & 0x80) | mldl_cfg->accel->reg); + /* Set VDDIO bit for ST accel */ + if ((ACCEL_ID_LIS331 == mldl_cfg->accel->id) + || (ACCEL_ID_LSM303 == mldl_cfg->accel->id)) { + reg |= 0x80; + } + result = + MLSLSerialWriteSingle(accel_handle, mldl_cfg->addr, + MPUREG_ACCEL_BURST_ADDR, reg); + ERROR_CHECK(result); + /* Length */ + result = MLSLSerialRead(accel_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, 1, ®); + ERROR_CHECK(result); + reg = (reg & ~BIT_AUX_RD_LENG); + result = + MLSLSerialWriteSingle(accel_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, reg); + ERROR_CHECK(result); + result = MLDLSetI2CBypass(mldl_cfg, accel_handle, 0); + ERROR_CHECK(result); + } + } + + if (resume_compass) { + if ((mldl_cfg->compass) && (mldl_cfg->compass->resume)) { + result = mldl_cfg->compass->resume(compass_handle, + mldl_cfg->compass, + &mldl_cfg-> + pdata->compass); + ERROR_CHECK(result); + } + } + + /* Now start */ + result = MLDLDmpStart(mldl_cfg, mlsl_handle); + ERROR_CHECK(result); + return result; +} + +int mpu3050_suspend(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + mlsl_handle_t accel_handle, + mlsl_handle_t compass_handle, bool accel, bool compass) +{ + int result; + /* This puts the bus into bypass mode */ + result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, 1, 0, 0, 0); + if (ML_SUCCESS == result && + accel && mldl_cfg->accel && mldl_cfg->accel->suspend) { + result = mldl_cfg->accel->suspend(accel_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel); + } + + if (ML_SUCCESS == result && compass && + mldl_cfg->compass && mldl_cfg->compass->suspend) { + result = mldl_cfg->compass->suspend(compass_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass); + } + return result; +} + +int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + unsigned char *data) +{ + if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read) + return mldl_cfg->accel->read(mlsl_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel, data); + else + return ML_ERROR_NOT_OPENED; +} + +int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + unsigned char *data) +{ + if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read) + return mldl_cfg->compass->read(mlsl_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass, data); + else + return ML_ERROR_NOT_OPENED; +} + +/***************************/ + /**@}*//* end of defgroup */ +/***************************/ diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h new file mode 100755 index 000000000000..03f752b75966 --- /dev/null +++ b/drivers/misc/mpu3050/mldl_cfg.h @@ -0,0 +1,98 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: mldl_cfg.h 3876 2010-10-12 02:42:22Z prao $ + * + *******************************************************************************/ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_cfg.h + * @brief The Motion Library Driver Layer Configuration header file. + */ + +#ifndef __MLDL_CFG_H__ +#define __MLDL_CFG_H__ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#include "mlsl.h" +#include "mpu3050.h" + +/* --------------------- */ +/* - Variables. - */ +/* --------------------- */ + +/* Platform data for the MPU */ +struct mldl_cfg { + /* MPU related configuration */ + unsigned char addr; + unsigned char int_config; + unsigned char ext_sync; + unsigned char full_scale; + unsigned char lpf; + unsigned char clk_src; + unsigned char divider; + unsigned char dmp_enable; + unsigned char fifo_enable; + unsigned char dmp_cfg1; + unsigned char dmp_cfg2; + unsigned char offset_tc[MPU_NUM_AXES]; + unsigned char __packing; + unsigned char ram[MPU_MEM_NUM_RAM_BANKS][MPU_MEM_BANK_SIZE]; + + /* MPU Related stored status and info */ + unsigned char silicon_revision; + unsigned char product_id; + unsigned short trim; + + /* Driver/Kernel related state information */ + int is_suspended; + + /* Slave related information */ + struct ext_slave_descr *accel; + struct ext_slave_descr *compass; + + struct mpu3050_platform_data *pdata; +}; + +int mpu3050_open(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle); +int mpu3050_resume(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + mlsl_handle_t accel_handle, + mlsl_handle_t compass_handle, + bool resume_accel, bool resume_compass); +int mpu3050_suspend(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + mlsl_handle_t accel_handle, + mlsl_handle_t compass_handle, + bool suspend_accel, bool suspend_compass); +int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + unsigned char *data); +int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle, + unsigned char *data); + +#endif /* __MLDL_CFG_H__ */ + +/***************************/ + /**@}*//* end of defgroup */ +/***************************/ diff --git a/drivers/misc/mpu3050/mlos-kernel.c b/drivers/misc/mpu3050/mlos-kernel.c new file mode 100755 index 000000000000..9492ec11a0bf --- /dev/null +++ b/drivers/misc/mpu3050/mlos-kernel.c @@ -0,0 +1,92 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/***************************************************************************** * + * $Id: mlos-kernel.c 3863 2010-10-08 22:05:31Z nroyer $ + ******************************************************************************/ +/** + * @defgroup + * @brief + * + * @{ + * @file mlos-kernel.c + * @brief + * + * + */ + +#include "mlos.h" +#include <linux/delay.h> +#include <linux/slab.h> + +void *MLOSMalloc(unsigned int numBytes) +{ + return kmalloc(numBytes, GFP_KERNEL); +} + +tMLError MLOSFree(void *ptr) +{ + kfree(ptr); + return ML_SUCCESS; +} + +tMLError MLOSCreateMutex(HANDLE *mutex) +{ + /* @todo implement if needed */ + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +tMLError MLOSLockMutex(HANDLE mutex) +{ + /* @todo implement if needed */ + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +tMLError MLOSUnlockMutex(HANDLE mutex) +{ + /* @todo implement if needed */ + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +tMLError MLOSDestroyMutex(HANDLE handle) +{ + /* @todo implement if needed */ + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +FILE *MLOSFOpen(char *filename) +{ + /* @todo implement if needed */ + return NULL; +} + +void MLOSFClose(FILE *fp) +{ + /* @todo implement if needed */ +} + +void MLOSSleep(int mSecs) +{ + msleep(mSecs); +} + +unsigned long MLOSGetTickCount(void) +{ + /* @todo implement if needed */ + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} diff --git a/drivers/misc/mpu3050/mlos.h b/drivers/misc/mpu3050/mlos.h new file mode 100755 index 000000000000..4a54ce236e95 --- /dev/null +++ b/drivers/misc/mpu3050/mlos.h @@ -0,0 +1,78 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: mlos.h 3863 2010-10-08 22:05:31Z nroyer $ + * + *******************************************************************************/ + +#ifndef _MLOS_H +#define _MLOS_H + +#ifndef __KERNEL__ +#include <stdio.h> +#endif + +#include "mltypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /* ------------ */ + /* - Defines. - */ + /* ------------ */ + + /* - MLOSCreateFile defines. - */ + +#define MLOS_GENERIC_READ ((unsigned int)0x80000000) +#define MLOS_GENERIC_WRITE ((unsigned int)0x40000000) +#define MLOS_FILE_SHARE_READ ((unsigned int)0x00000001) +#define MLOS_FILE_SHARE_WRITE ((unsigned int)0x00000002) +#define MLOS_OPEN_EXISTING ((unsigned int)0x00000003) + + /* ---------- */ + /* - Enums. - */ + /* ---------- */ + + /* --------------- */ + /* - Structures. - */ + /* --------------- */ + + /* --------------------- */ + /* - Function p-types. - */ + /* --------------------- */ + + void *MLOSMalloc(unsigned int numBytes); + tMLError MLOSFree(void *ptr); + tMLError MLOSCreateMutex(HANDLE *mutex); + tMLError MLOSLockMutex(HANDLE mutex); + tMLError MLOSUnlockMutex(HANDLE mutex); + FILE *MLOSFOpen(char *filename); + void MLOSFClose(FILE *fp); + + tMLError MLOSDestroyMutex(HANDLE handle); + + void MLOSSleep(int mSecs); + unsigned long MLOSGetTickCount(void); + +#ifdef __cplusplus +} +#endif +#endif /* _MLOS_H */ diff --git a/drivers/misc/mpu3050/mlsl-kernel.c b/drivers/misc/mpu3050/mlsl-kernel.c new file mode 100755 index 000000000000..4b9494f1d919 --- /dev/null +++ b/drivers/misc/mpu3050/mlsl-kernel.c @@ -0,0 +1,171 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: mlsl-kernel.c 3863 2010-10-08 22:05:31Z nroyer $ + * + ******************************************************************************/ + +#include "mlsl.h" +#include "mpu-i2c.h" + +/* ------------ */ +/* - Defines. - */ +/* ------------ */ + +/* ---------------------- */ +/* - Types definitions. - */ +/* ---------------------- */ + +/* --------------------- */ +/* - Function p-types. - */ +/* --------------------- */ + +/** + * @brief used to open the I2C or SPI serial port. + * This port is used to send and receive data to the MPU device. + * @param portNum + * The COM port number associated with the device in use. + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +tMLError MLSLSerialOpen(char const *port, mlsl_handle_t * sl_handle) +{ + return ML_SUCCESS; +} + +/** + * @brief used to reset any buffering the driver may be doing + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +tMLError MLSLSerialReset(mlsl_handle_t sl_handle) +{ + return ML_SUCCESS; +} + +/** + * @brief used to close the I2C or SPI serial port. + * This port is used to send and receive data to the MPU device. + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +tMLError MLSLSerialClose(mlsl_handle_t sl_handle) +{ + return ML_SUCCESS; +} + +/** + * @brief used to read a single byte of data. + * This should be sent by I2C or SPI. + * + * @param slaveAddr I2C slave address of device. + * @param registerAddr Register address to read. + * @param data Single byte of data to read. + * + * @return ML_SUCCESS if the command is successful, an error code otherwise. + */ +tMLError MLSLSerialWriteSingle(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned char registerAddr, unsigned char data) +{ + return sensor_i2c_write_register((struct i2c_adapter *)sl_handle, + slaveAddr, registerAddr, data); + +} + +/** + * @brief used to read multiple bytes of data. + * This should be sent by I2C or SPI. + * + * @param slaveAddr I2C slave address of device. + * @param registerAddr Register address to read. + * @param length Length of burst data. + * @param data Pointer to block of data. + * + * @return Zero if the command is successful; an error code otherwise + */ +tMLError MLSLSerialRead(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned char registerAddr, + unsigned short length, unsigned char *data) +{ + return sensor_i2c_read((struct i2c_adapter *)sl_handle, + slaveAddr, registerAddr, length, data); +} + +/** + * @brief used to write multiple bytes of data. + * This should be sent by I2C or SPI. + * + * @param slaveAddr I2C slave address of device. + * @param length Length of burst data. + * @param data Pointer to block of data. First byte is the + * register address to write. + * + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +tMLError MLSLSerialWrite(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned short length, unsigned char const *data) +{ + return sensor_i2c_write((struct i2c_adapter *)sl_handle, + slaveAddr, length, data); +} + +/** + * @brief used to read multiple bytes of data. + * This should be sent by I2C or SPI. + * + * @param slaveAddr I2C slave address of device. + * @param registerAddr Register address to read. + * @param length Length of burst data. + * @param data Pointer to block of data. + * + * @return Zero if the command is successful; an error code otherwise + */ +tMLError MLSLSerialReadMem(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned short memAddr, + unsigned short length, unsigned char *data) +{ + return mpu_memory_read((struct i2c_adapter *)sl_handle, + slaveAddr, memAddr, length, data); +} + +/** + * @brief used to write multiple bytes of data. + * This should be sent by I2C or SPI. + * + * @param slaveAddr I2C slave address of device. + * @param length Length of burst data. + * @param data Pointer to block of data. First byte is the + * register address to write. + * + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +tMLError MLSLSerialWriteMem(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned short mem_addr, + unsigned short length, unsigned char const *data) +{ + return mpu_memory_write((struct i2c_adapter *)sl_handle, + slaveAddr, mem_addr, length, data); +} + +/***********************/ + /** @} *//* defgroup */ +/*********************/ diff --git a/drivers/misc/mpu3050/mlsl.h b/drivers/misc/mpu3050/mlsl.h new file mode 100755 index 000000000000..d41683eddb77 --- /dev/null +++ b/drivers/misc/mpu3050/mlsl.h @@ -0,0 +1,81 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: mlsl.h 3863 2010-10-08 22:05:31Z nroyer $ + * + ******************************************************************************/ + +#ifndef __MSSL_H__ +#define __MSSL_H__ + +#include "mltypes.h" +#include "mpu3050.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------ */ +/* - Defines. - */ +/* ------------ */ + +/* ---------------------- */ +/* - Types definitions. - */ +/* ---------------------- */ + + typedef void *tMLSLHandle; /* For MPL coding standards */ + +/* --------------------- */ +/* - Function p-types. - */ +/* --------------------- */ + + tMLError MLSLSerialOpen(char const *port, mlsl_handle_t * sl_handle); + tMLError MLSLSerialReset(mlsl_handle_t sl_handle); + tMLError MLSLSerialClose(mlsl_handle_t sl_handle); + tMLError MLSLSerialWriteSingle(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned char registerAddr, + unsigned char data); + tMLError MLSLSerialRead(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned char registerAddr, + unsigned short length, unsigned char *data); + tMLError MLSLSerialWrite(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned short length, + unsigned char const *data); + tMLError MLSLSerialReadMem(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned short memAddr, + unsigned short length, unsigned char *data); + tMLError MLSLSerialWriteMem(mlsl_handle_t sl_handle, + unsigned char slaveAddr, + unsigned short memAddr, + unsigned short length, + unsigned char const *data); + tMLError MLSLWriteCal(unsigned char *cal, unsigned int len); + tMLError MLSLGetCalLength(unsigned int *len); + tMLError MLSLReadCal(unsigned char *cal, unsigned int len); + +#ifdef __cplusplus +} +#endif + /***********************//** @} *//* defgroup *//*********************/ +#endif // MLSL_H diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h new file mode 100755 index 000000000000..4ffc890ca7b8 --- /dev/null +++ b/drivers/misc/mpu3050/mltypes.h @@ -0,0 +1,215 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/******************************************************************************* + * + * $Id: mltypes.h 3866 2010-10-09 00:51:32Z nroyer $ + * + *******************************************************************************/ + +/** + * @defgroup MLERROR + * @brief Definition of the error codes used within the MPL and returned + * to the user. + * Every function tries to return a meaningful error code basing + * on the occuring error condition. The error code is numeric. + * + * The available error codes and their associated values are: + * - (0) ML_SUCCESS + * - (1) ML_ERROR + * - (2) ML_ERROR_INVALID_PARAMETER + * - (3) ML_ERROR_FEATURE_NOT_ENABLED + * - (4) ML_ERROR_FEATURE_NOT_IMPLEMENTED + * - (6) ML_ERROR_DMP_NOT_STARTED + * - (7) ML_ERROR_DMP_STARTED + * - (8) ML_ERROR_NOT_OPENED + * - (9) ML_ERROR_OPENED + * - (10) ML_ERROR_INVALID_MODULE + * - (11) ML_ERROR_MEMORY_EXAUSTED + * - (12) ML_ERROR_DIVIDE_BY_ZERO + * - (13) ML_ERROR_ASSERTION_FAILURE + * - (14) ML_ERROR_FILE_OPEN + * - (15) ML_ERROR_FILE_READ + * - (16) ML_ERROR_FILE_WRITE + * - (20) ML_ERROR_SERIAL_CLOSED + * - (21) ML_ERROR_SERIAL_OPEN_ERROR + * - (22) ML_ERROR_SERIAL_READ + * - (23) ML_ERROR_SERIAL_WRITE + * - (24) ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED + * - (25) ML_ERROR_SM_TRANSITION + * - (26) ML_ERROR_SM_IMPROPER_STATE + * - (30) ML_ERROR_FIFO_OVERFLOW + * - (31) ML_ERROR_FIFO_FOOTER + * - (32) ML_ERROR_FIFO_READ_COUNT + * - (33) ML_ERROR_FIFO_READ_DATA + * - (40) ML_ERROR_MEMORY_SET + * - (50) ML_ERROR_LOG_MEMORY_ERROR + * - (51) ML_ERROR_LOG_OUTPUT_ERROR + * - (60) ML_ERROR_OS_BAD_PTR + * - (61) ML_ERROR_OS_BAD_HANDLE + * - (62) ML_ERROR_OS_CREATE_FAILED + * - (63) ML_ERROR_OS_LOCK_FAILED + * - (70) ML_ERROR_COMPASS_DATA_OVERFLOW + * - (71) ML_ERROR_COMPASS_DATA_UNDERFLOW + * - (72) ML_ERROR_COMPASS_DATA_NOT_READY + * +**/ + +#ifndef MLTYPES_H +#define MLTYPES_H + +#ifdef __KERNEL__ +#include <linux/types.h> +#else +#include "stdint_invensense.h" +#endif +#include "log.h" + +/*--------------------------- + ML Types +---------------------------*/ + +typedef long long MLS64; +typedef int MLS32; +typedef unsigned int MLU32; +typedef short MLS16; +typedef unsigned short MLU16; +typedef char MLS8; +typedef unsigned char MLU8; +typedef unsigned char MLBOOL; +typedef double MLDBL; +typedef float MLFLT; + +typedef unsigned char tReg; + +/** + * @struct tMLError The MPL Error Code return type. + * + * @code + * typedef unsigned char tMLError; + * @endcode + */ +typedef unsigned char tMLError; + +#if defined(LINUX) || defined (__KERNEL__) +typedef unsigned int HANDLE; +#endif + +#ifdef __KERNEL__ +typedef HANDLE FILE; +#endif + +#ifndef __cplusplus +#ifndef __KERNEL__ +typedef int_fast8_t bool; +#endif +#endif + +/*--------------------------- + ML Defines +---------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* Dimension of an array */ +#ifndef DIM +#define DIM(array) (sizeof(array)/sizeof((array)[0])) +#endif + +/* - ML Errors. - */ +#define ERROR_NAME(x) (#x) +#define ERROR_CHECK(x) \ +{ \ + if (ML_SUCCESS != x) { \ + MPL_LOGE("%s|%s|%d returning %d\n", \ + __FILE__, __func__, __LINE__, x); \ + return x; \ + } \ +} + +#define ERROR_CHECK_FIRST(first, x) {if (ML_SUCCESS == first) first = x; } + +#define ML_SUCCESS (0) +/* Generic Error code. Propritary Error Codes only */ +#define ML_ERROR (1) + +/* Compatibility and other generic error codes */ +#define ML_ERROR_INVALID_PARAMETER (2) +#define ML_ERROR_FEATURE_NOT_ENABLED (3) +#define ML_ERROR_FEATURE_NOT_IMPLEMENTED (4) +#define ML_ERROR_DMP_NOT_STARTED (6) +#define ML_ERROR_DMP_STARTED (7) +#define ML_ERROR_NOT_OPENED (8) +#define ML_ERROR_OPENED (9) +#define ML_ERROR_INVALID_MODULE (10) +#define ML_ERROR_MEMORY_EXAUSTED (11) +#define ML_ERROR_DIVIDE_BY_ZERO (12) +#define ML_ERROR_ASSERTION_FAILURE (13) +#define ML_ERROR_FILE_OPEN (14) +#define ML_ERROR_FILE_READ (15) +#define ML_ERROR_FILE_WRITE (16) + +/* Serial Communication */ +#define ML_ERROR_SERIAL_CLOSED (20) +#define ML_ERROR_SERIAL_OPEN_ERROR (21) +#define ML_ERROR_SERIAL_READ (22) +#define ML_ERROR_SERIAL_WRITE (23) +#define ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED (24) + +/* SM = State Machine */ +#define ML_ERROR_SM_TRANSITION (25) +#define ML_ERROR_SM_IMPROPER_STATE (26) + +/* Fifo */ +#define ML_ERROR_FIFO_OVERFLOW (30) +#define ML_ERROR_FIFO_FOOTER (31) +#define ML_ERROR_FIFO_READ_COUNT (32) +#define ML_ERROR_FIFO_READ_DATA (33) + +/* Memory & Registers, Set & Get */ +#define ML_ERROR_MEMORY_SET (40) + +#define ML_ERROR_LOG_MEMORY_ERROR (50) +#define ML_ERROR_LOG_OUTPUT_ERROR (51) + +/*OS interface errors */ +#define ML_ERROR_OS_BAD_PTR (60) +#define ML_ERROR_OS_BAD_HANDLE (61) +#define ML_ERROR_OS_CREATE_FAILED (62) +#define ML_ERROR_OS_LOCK_FAILED (63) + +/* Compass errors */ +#define ML_ERROR_COMPASS_DATA_OVERFLOW (70) +#define ML_ERROR_COMPASS_DATA_UNDERFLOW (71) +#define ML_ERROR_COMPASS_DATA_NOT_READY (72) + +/*--------------------------- + p-Types +---------------------------*/ + +#endif /* MLTYPES_H */ diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c new file mode 100755 index 000000000000..dde346bc0e9b --- /dev/null +++ b/drivers/misc/mpu3050/mpu-dev.c @@ -0,0 +1,835 @@ +/* + mpu-dev.c - mpu3050 char device interface + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl> + Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. +*/ +/* Code inside mpudev_ioctl_rdrw is copied from i2c-dev.c + */ +#include <linux/i2c.h> +#include <linux/i2c-dev.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/stat.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/signal.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/pm.h> + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +#include "mpuirq.h" +#include "mlsl.h" +#include "mpu-i2c.h" +#include "mldl_cfg.h" +#include "mpu3050.h" + +#define MPU3050_EARLY_SUSPEND_IN_DRIVER 0 +#define MPU_NAME "mpu" +#define MPU_SLAVE_ADDR (0x68) + +#define MPU_GET_INTERRUPT_CNT (2) +#define MPU_GET_IRQ_TIME (3) +#define MPU_GET_LED_VALUE (4) +#define MPU_SET_TIMEOUT (5) + +/* Platform data for the MPU */ +struct mpu_private_data { + struct mldl_cfg mldl_cfg; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +static int pid; + +static struct i2c_client *this_client; + +static int mpu_open(struct inode *inode, struct file *file) +{ + printk("mpu_open\n"); + printk("current->pid %d\n", current->pid); + pid = current->pid; + file->private_data = this_client; + /* we could do some checking on the flags supplied by "open" + // i.e. O_NONBLOCK + // -> set some flag to disable interruptible_sleep_on in mpu_read */ + return 0; +} + +/* close function - called when the "file" /dev/mpu is closed in userspace */ +static int mpu_release(struct inode *inode, struct file *file) +{ + struct i2c_client *client = (struct i2c_client *)file->private_data; + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int result = 0; + + pid = 0; + + if (!mldl_cfg->is_suspended) { + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + accel_adapter = + i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = + i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + result = + mpu3050_suspend(mldl_cfg, client->adapter, accel_adapter, + compass_adapter, TRUE, TRUE); + } + + printk("mpu_release\n"); + return result; +} + +static noinline int mpudev_ioctl_rdrw(struct i2c_client *client, + unsigned long arg) +{ + struct i2c_rdwr_ioctl_data rdwr_arg; + struct i2c_msg *rdwr_pa; + u8 __user **data_ptrs; + int i, res; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) + return -EINVAL; + + rdwr_pa = (struct i2c_msg *) + kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); + if (!rdwr_pa) + return -ENOMEM; + + if (copy_from_user(rdwr_pa, rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { + kfree(rdwr_pa); + return -EFAULT; + } + + data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); + if (data_ptrs == NULL) { + kfree(rdwr_pa); + return -ENOMEM; + } + + res = 0; + for (i = 0; i < rdwr_arg.nmsgs; i++) { + /* Limit the size of the message to a sane amount; + * and don't let length change either. */ + if ((rdwr_pa[i].len > 8192) || + (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { + res = -EINVAL; + break; + } + data_ptrs[i] = (u8 __user *) rdwr_pa[i].buf; + rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); + if (rdwr_pa[i].buf == NULL) { + res = -ENOMEM; + break; + } + if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i], + rdwr_pa[i].len)) { + ++i; /* Needs to be kfreed too */ + res = -EFAULT; + break; + } + } + if (res < 0) { + int j; + for (j = 0; j < i; ++j) + kfree(rdwr_pa[j].buf); + kfree(data_ptrs); + kfree(rdwr_pa); + return res; + } + + res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); + while (i-- > 0) { + if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { + if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, + rdwr_pa[i].len)) + res = -EFAULT; + } + kfree(rdwr_pa[i].buf); + } + kfree(data_ptrs); + kfree(rdwr_pa); + return res; +} + +/* read function called when from /dev/mpu is read. Read from the FIFO */ +static ssize_t mpu_read(struct file *file, + char __user *buf, size_t count, loff_t *offset) +{ + char *tmp; + int ret; + + struct i2c_client *client = (struct i2c_client *)file->private_data; + + if (count > 8192) + count = 8192; + + tmp = kmalloc(count, GFP_KERNEL); + if (tmp == NULL) + return -ENOMEM; + + pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", + iminor(file->f_path.dentry->d_inode), count); + +/* @todo fix this to do a i2c trasnfer from the FIFO */ + ret = i2c_master_recv(client, tmp, count); + if (ret >= 0) + ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret; + kfree(tmp); + return ret; +} + +static int mpu_ioctl_get_mpu_pdata(struct i2c_client *client, unsigned long arg) +{ + int result; + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int accel_adapt_num = mldl_cfg->pdata->accel.adapt_num; + int compass_adapt_num = mldl_cfg->pdata->compass.adapt_num; + int accel_bus = mldl_cfg->pdata->accel.bus; + int compass_bus = mldl_cfg->pdata->compass.bus; + + result = copy_from_user(mldl_cfg->pdata, + (unsigned char *)arg, + sizeof(struct mpu3050_platform_data)); + /* Don't allow userspace to change the adapter number or bus */ + mldl_cfg->pdata->accel.adapt_num = accel_adapt_num; + mldl_cfg->pdata->compass.adapt_num = compass_adapt_num; + mldl_cfg->pdata->accel.bus = accel_bus; + mldl_cfg->pdata->compass.bus = compass_bus; + + return result; +} + +static int +mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + + printk("%s\n", __func__); + /* + * User space is not allowed to modify accel compass or pdata structs, + * as well as silicon_revision product_id or trim + */ + if (copy_from_user(mldl_cfg, + (struct mldl_cfg *)arg, + offsetof(struct mldl_cfg, silicon_revision))) + return -EFAULT; + + return 0; +} + +static int +mpu_ioctl_get_mpu_config(struct i2c_client *client, unsigned long arg) +{ + /* Have to be careful as there are 3 pointers in the mldl_cfg + * structure */ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct mldl_cfg *local_mldl_cfg; + int retval = 0; + + local_mldl_cfg = kmalloc(sizeof(struct mldl_cfg), GFP_KERNEL); + if (NULL == local_mldl_cfg) + return -ENOMEM; + + retval = + copy_from_user(local_mldl_cfg, (void *)arg, + sizeof(struct mldl_cfg)); + if (retval) + goto out; + + /* Fill in the accel, compass and pdata pointers */ + if (mldl_cfg->accel) { + retval = copy_to_user(local_mldl_cfg->accel, + mldl_cfg->accel, + sizeof(*mldl_cfg->accel)); + if (retval) + goto out; + } + + if (mldl_cfg->compass) { + retval = copy_to_user(local_mldl_cfg->compass, + mldl_cfg->compass, + sizeof(*mldl_cfg->compass)); + if (retval) + goto out; + } + + if (mldl_cfg->pdata) { + retval = copy_to_user(local_mldl_cfg->pdata, + mldl_cfg->pdata, + sizeof(*mldl_cfg->pdata)); + if (retval) + goto out; + } + + /* Do not modify the accel, compass and pdata pointers */ + retval = copy_to_user((struct mldl_cfg *)arg, + mldl_cfg, offsetof(struct mldl_cfg, accel)); + + out: + kfree(local_mldl_cfg); + return retval; +} + +/* ioctl - I/O control */ +static long mpu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = (struct i2c_client *)file->private_data; + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int retval = 0; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + + switch (cmd) { + case I2C_RDWR: + mpudev_ioctl_rdrw(client, arg); + break; + case I2C_SLAVE: + if ((arg & 0x7E) != (client->addr & 0x7E)) { + printk("%s: Invalid I2C_SLAVE arg %lu \n", + __func__, arg); + } + break; + case MPU_SET_MPU_CONFIG: + retval = mpu_ioctl_set_mpu_config(client, arg); + break; + case MPU_SET_INT_CONFIG: + mldl_cfg->int_config = (unsigned char)arg; + break; + case MPU_SET_EXT_SYNC: + mldl_cfg->ext_sync = (enum mpu_ext_sync)arg; + break; + case MPU_SET_FULL_SCALE: + mldl_cfg->full_scale = (enum mpu_fullscale)arg; + break; + case MPU_SET_LPF: + mldl_cfg->lpf = (enum mpu_filter)arg; + break; + case MPU_SET_CLK_SRC: + mldl_cfg->clk_src = (enum mpu_clock_sel)arg; + break; + case MPU_SET_DIVIDER: + mldl_cfg->divider = (unsigned char)arg; + break; + case MPU_SET_LEVEL_SHIFTER: + mldl_cfg->pdata->level_shifter = (unsigned char)arg; + break; + case MPU_SET_DMP_ENABLE: + mldl_cfg->dmp_enable = (unsigned char)arg; + break; + case MPU_SET_FIFO_ENABLE: + mldl_cfg->fifo_enable = (unsigned char)arg; + break; + case MPU_SET_DMP_CFG1: + mldl_cfg->dmp_cfg1 = (unsigned char)arg; + break; + case MPU_SET_DMP_CFG2: + mldl_cfg->dmp_cfg2 = (unsigned char)arg; + break; + case MPU_SET_OFFSET_TC: + retval = copy_from_user(mldl_cfg->offset_tc, + (unsigned char *)arg, + sizeof(mldl_cfg->offset_tc)); + break; + case MPU_SET_RAM: + retval = copy_from_user(mldl_cfg->ram, + (unsigned char *)arg, + sizeof(mldl_cfg->ram)); + break; + case MPU_SET_PLATFORM_DATA: + retval = mpu_ioctl_get_mpu_pdata(client, arg); + break; + case MPU_GET_MPU_CONFIG: + retval = mpu_ioctl_get_mpu_config(client, arg); + break; + case MPU_GET_INT_CONFIG: + mldl_cfg->int_config = (unsigned char)arg; + break; + case MPU_GET_EXT_SYNC: + mldl_cfg->ext_sync = (enum mpu_ext_sync)arg; + break; + case MPU_GET_FULL_SCALE: + mldl_cfg->full_scale = (enum mpu_fullscale)arg; + break; + case MPU_GET_LPF: + mldl_cfg->lpf = (enum mpu_filter)arg; + break; + case MPU_GET_CLK_SRC: + mldl_cfg->clk_src = (enum mpu_clock_sel)arg; + break; + case MPU_GET_DIVIDER: + mldl_cfg->divider = (unsigned char)arg; + break; + case MPU_GET_LEVEL_SHIFTER: + mldl_cfg->pdata->level_shifter = (unsigned char)arg; + break; + case MPU_GET_DMP_ENABLE: + mldl_cfg->dmp_enable = (unsigned char)arg; + break; + case MPU_GET_FIFO_ENABLE: + mldl_cfg->fifo_enable = (unsigned char)arg; + break; + case MPU_GET_DMP_CFG1: + mldl_cfg->dmp_cfg1 = (unsigned char)arg; + break; + case MPU_GET_DMP_CFG2: + mldl_cfg->dmp_cfg2 = (unsigned char)arg; + break; + case MPU_GET_OFFSET_TC: + retval = copy_to_user((unsigned char *)arg, + mldl_cfg->offset_tc, + sizeof(mldl_cfg->offset_tc)); + break; + case MPU_GET_RAM: + retval = copy_to_user((unsigned char *)arg, + mldl_cfg->ram, sizeof(mldl_cfg->ram)); + break; + case MPU_READ_MEMORY: + case MPU_WRITE_MEMORY: + case MPU_SUSPEND: + { + struct mpu_suspend_resume suspend; + retval = + copy_from_user(&suspend, + (struct mpu_suspend_resume *) + arg, sizeof(suspend)); + if (retval) + break; + if (suspend.gyro) { + retval = + mpu3050_suspend(mldl_cfg, + client->adapter, + accel_adapter, + compass_adapter, + suspend.accel, + suspend.compass); + } else { + /* Cannot suspend the compass or accel while + * the MPU is running */ + retval = ML_ERROR_FEATURE_NOT_IMPLEMENTED; + } + } + break; + case MPU_RESUME: + { + struct mpu_suspend_resume resume; + retval = + copy_from_user(&resume, + (struct mpu_suspend_resume *) + arg, sizeof(resume)); + if (retval) + break; + if (resume.gyro) { + retval = + mpu3050_resume(mldl_cfg, + client->adapter, + accel_adapter, + compass_adapter, + resume.accel, + resume.compass); + } else if (mldl_cfg->is_suspended) { + if (resume.accel) { + retval = + mldl_cfg->accel-> + resume(accel_adapter, + mldl_cfg->accel, + &mldl_cfg->pdata->accel); + if (retval) + break; + } + + if (resume.compass) + retval = + mldl_cfg->compass-> + resume(compass_adapter, + mldl_cfg->compass, + &mldl_cfg->pdata->compass); + } else { + /* Cannot resume the compass or accel while + * the MPU is running */ + retval = ML_ERROR_FEATURE_NOT_IMPLEMENTED; + } + } + break; + case MPU_READ_ACCEL: + { + unsigned char data[6]; + retval = + mpu3050_read_accel(mldl_cfg, client->adapter, data); + if (ML_SUCCESS == retval) + retval = + copy_to_user((unsigned char *)arg, + data, sizeof(data)); + } + break; + case MPU_READ_COMPASS: + { + unsigned char data[6]; + struct i2c_adapter *compass_adapt = + i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + retval = + mpu3050_read_compass(mldl_cfg, compass_adapt, data); + if (ML_SUCCESS == retval) + retval = + copy_to_user((unsigned char *)arg, + data, sizeof(data)); + } + break; + default: + printk("%s: Unknown cmd %d, arg %lu \n", __func__, cmd, arg); + retval = -EINVAL; + } + + return retval; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +void mpu3050_early_suspend(struct early_suspend *h) +{ + struct mpu_private_data *mpu = container_of(h, + struct + mpu_private_data, + early_suspend); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + + printk("%s: %d, %d\n", __func__, h->level, mpu->mldl_cfg.is_suspended); + if (MPU3050_EARLY_SUSPEND_IN_DRIVER) + (void)mpu3050_suspend(mldl_cfg, + accel_adapter, compass_adapter, + this_client->adapter, TRUE, TRUE); +} + +void mpu3050_early_resume(struct early_suspend *h) +{ + struct mpu_private_data *mpu = container_of(h, + struct + mpu_private_data, + early_suspend); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + + if (MPU3050_EARLY_SUSPEND_IN_DRIVER) { + if (pid) { + (void)mpu3050_resume(mldl_cfg, + accel_adapter, compass_adapter, + this_client->adapter, TRUE, TRUE); + printk("%s for pid %d\n", __func__, pid); + } + } + printk("%s: %d\n", __func__, h->level); +} +#endif + +void mpu_shutdown(struct i2c_client *client) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + + (void)mpu3050_suspend(mldl_cfg, this_client->adapter, + accel_adapter, compass_adapter, TRUE, TRUE); + printk("%s\n", __func__); +} + +int mpu_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + + if (!mpu->mldl_cfg.is_suspended) { + printk("%s: suspending on event %d\n", __func__, mesg.event); + (void)mpu3050_suspend(mldl_cfg, this_client->adapter, + accel_adapter, compass_adapter, + TRUE, TRUE); + } else { + printk("%s: Already suspended %d\n", __func__, mesg.event); + } + return 0; +} + +int mpu_resume(struct i2c_client *client) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + + if (pid) { + (void)mpu3050_resume(mldl_cfg, this_client->adapter, + accel_adapter, compass_adapter, + TRUE, TRUE); + printk("%s for pid %d\n", __func__, pid); + } + return 0; +} + +/* define which file operations are supported */ +struct file_operations mpu_fops = { + .owner = THIS_MODULE, + .read = mpu_read, +#if HAVE_COMPAT_IOCTL + .compat_ioctl = mpu_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = mpu_ioctl, +#endif + .open = mpu_open, + .release = mpu_release, +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32) +I2C_CLIENT_INSMOD; +#endif + +static struct miscdevice i2c_mpu_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = MPU_NAME, + .fops = &mpu_fops, +}; + +int mpu3050_probe(struct i2c_client *client, const struct i2c_device_id *devid) +{ + struct mpu3050_platform_data *pdata; + struct mpu_private_data *mpu; + int res = 0; + printk("%s\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + res = -ENODEV; + goto out_check_functionality_failed; + } + + mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL); + if (!mpu) { + res = -ENOMEM; + goto out_alloc_data_failed; + } + + i2c_set_clientdata(client, mpu); + this_client = client; + + pdata = (struct mpu3050_platform_data *)client->dev.platform_data; + if (!pdata) { + printk("Warning no platform data for mpu3050\n"); + } else { + mpu->mldl_cfg.pdata = pdata; + +#ifdef CONFIG_SENSORS_MPU3050_MODULE + pdata->accel.get_slave_descr = get_accel_slave_descr; + pdata->compass.get_slave_descr = get_compass_slave_descr; +#endif + + if (pdata->accel.get_slave_descr) { + mpu->mldl_cfg.accel = pdata->accel.get_slave_descr(); + printk("MPU3050: +%s\n", mpu->mldl_cfg.accel->name); + } else { + printk("MPU3050: No Accel Present\n"); + } + + if (pdata->compass.get_slave_descr) { + mpu->mldl_cfg.compass = + pdata->compass.get_slave_descr(); + printk("MPU3050: +%s\n", mpu->mldl_cfg.compass->name); + } else { + printk("MPU3050: No Compass Present\n"); + } + } + + mpu->mldl_cfg.addr = client->addr; + res = mpu3050_open(&mpu->mldl_cfg, (tMLSLHandle) client->adapter); + + if (res) { + printk("Unable to open MPU3050 %d\n", res); + res = -ENODEV; + goto out_whoami_failed; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + mpu->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + mpu->early_suspend.suspend = mpu3050_early_suspend; + mpu->early_suspend.resume = mpu3050_early_resume; + register_early_suspend(&mpu->early_suspend); +#endif + + res = misc_register(&i2c_mpu_device); + if (res < 0) { + printk("ERROR: misc_register returned %d\n", res); + goto out_misc_register_failed; + } + + if (this_client->irq > 0) { + printk("Installing irq using %d\n", this_client->irq); + res = mpuirq_init(this_client); + if (res) { + goto out_mpuirq_failed; + } + } else { + printk("WARNING: mpu3050 irq not assigned\n"); + } + + return res; + + out_mpuirq_failed: + misc_deregister(&i2c_mpu_device); + out_misc_register_failed: +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&mpu->early_suspend); +#endif + out_whoami_failed: + kfree(mpu); + out_alloc_data_failed: + out_check_functionality_failed: + printk(KERN_ERR "%s failed %d\n", __func__, res); + return res; + +} + +static int mpu3050_remove(struct i2c_client *client) +{ + struct mpu_private_data *mpu = i2c_get_clientdata(client); + printk("%s\n", __func__); + + if (client->irq) { + mpuirq_exit(); + } + + misc_deregister(&i2c_mpu_device); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&mpu->early_suspend); +#endif + kfree(mpu); + + return 0; +} + +static const struct i2c_device_id mpu3050_id[] = { + {"mpu3050", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mpu3050_id); + +static struct i2c_driver mpu3050_driver = { + .class = I2C_CLASS_HWMON, + .probe = mpu3050_probe, + .remove = mpu3050_remove, + .id_table = mpu3050_id, + .driver = { + .owner = THIS_MODULE, + .name = "mpu3050", + }, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32) + .address_data = &addr_data, +#else + .address_list = normal_i2c, +#endif + + .shutdown = mpu_shutdown, /* optional */ + .suspend = mpu_suspend, /* optional */ + .resume = mpu_resume, /* optional */ + +}; + +static int __init mpu_init(void) +{ + int res = i2c_add_driver(&mpu3050_driver); + printk("%s\n", __func__); + if (res) { + printk("%s failed\n", __func__); + } + return res; +} + +static void __exit mpu_exit(void) +{ + printk("%s\n", __func__); + i2c_del_driver(&mpu3050_driver); +} + +module_init(mpu_init); +module_exit(mpu_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("User space character device interface for MPU3050"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mpu3050"); diff --git a/drivers/misc/mpu3050/mpu-i2c.c b/drivers/misc/mpu3050/mpu-i2c.c new file mode 100755 index 000000000000..ca21b42a9e95 --- /dev/null +++ b/drivers/misc/mpu3050/mpu-i2c.c @@ -0,0 +1,195 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/***************************************************************************** * + * $Id: mpu-i2c.c 3863 2010-10-08 22:05:31Z nroyer $ + ******************************************************************************/ +/** + * @defgroup + * @brief + * + * @{ + * @file mpu-i2c.c + * @brief + * + * + */ + +#include <linux/i2c.h> + +int sensor_i2c_write(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned int len, unsigned char *data) +{ + struct i2c_msg msgs[1]; + int res; + + if (NULL == data || NULL == i2c_adap) + return -EINVAL; + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = (unsigned char *)data; + msgs[0].len = len; + + res = i2c_transfer(i2c_adap, msgs, 1); + if (res < 1) { + return res; + } else { + return 0; + } +} + +int sensor_i2c_write_register(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned char reg, unsigned char value) +{ + unsigned char data[2]; + + data[0] = reg; + data[1] = value; + return sensor_i2c_write(i2c_adap, address, 2, data); +} + +int sensor_i2c_read(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned char reg, unsigned int len, unsigned char *data) +{ + struct i2c_msg msgs[2]; + int res; + + if (NULL == data || NULL == i2c_adap) + return -EINVAL; + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = ® + msgs[0].len = 1; + + msgs[1].addr = address; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = data; + msgs[1].len = len; + + res = i2c_transfer(i2c_adap, msgs, 2); + if (res < 2) { + return res; + } else { + return 0; + } +} + +int mpu_memory_read(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char *data) +{ + unsigned char bank[2]; + unsigned char addr[2]; + unsigned char buf; + + struct i2c_msg msgs[4]; + int ret; + + if (NULL == data || NULL == i2c_adap) + return -EINVAL; + + bank[0] = 0x37; /*MPUREG_BANK_SEL; */ + bank[1] = mem_addr >> 8; + + addr[0] = 0x38; /*MPUREG_MEM_START_ADDR; */ + addr[1] = mem_addr & 0xFF; + + buf = 0x39; /* MPUREG_MEM_R_W; */ + + /* Write Message */ + msgs[0].addr = mpu_addr; + msgs[0].flags = 0; + msgs[0].buf = bank; + msgs[0].len = sizeof(bank); + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = &buf; + msgs[2].len = 1; + + msgs[3].addr = mpu_addr; + msgs[3].flags = I2C_M_RD; + msgs[3].buf = data; + msgs[3].len = len; + + ret = i2c_transfer(i2c_adap, msgs, 4); + if (ret != 4) + return ret; + else + return 0; +} + +int mpu_memory_write(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char *data) +{ + unsigned char bank[2]; + unsigned char addr[2]; + unsigned char buf[513]; + + struct i2c_msg msgs[3]; + int ret; + + if (NULL == data || NULL == i2c_adap) + return -EINVAL; + if (len >= (sizeof(buf) - 1)) + return -ENOMEM; + + bank[0] = 0x37; /*MPUREG_BANK_SEL; */ + bank[1] = mem_addr >> 8; + + addr[0] = 0x38; /*MPUREG_MEM_START_ADDR; */ + addr[1] = mem_addr & 0xFF; + + buf[0] = 0x39; /* MPUREG_MEM_R_W; */ + memcpy(buf + 1, data, len); + + /* Write Message */ + msgs[0].addr = mpu_addr; + msgs[0].flags = 0; + msgs[0].buf = bank; + msgs[0].len = sizeof(bank); + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = (unsigned char *)buf; + msgs[2].len = len + 1; + + ret = i2c_transfer(i2c_adap, msgs, 3); + if (ret != 3) + return ret; + else + return 0; +} diff --git a/drivers/misc/mpu3050/mpu-i2c.h b/drivers/misc/mpu3050/mpu-i2c.h new file mode 100755 index 000000000000..ac3f7e93b695 --- /dev/null +++ b/drivers/misc/mpu3050/mpu-i2c.h @@ -0,0 +1,60 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/***************************************************************************** * + * $Id: mpu-i2c.h 3863 2010-10-08 22:05:31Z nroyer $ + ******************************************************************************/ +/** + * @defgroup + * @brief + * + * @{ + * @file mpu-i2c.c + * @brief + * + * + */ + +#ifndef __MPU_I2C_H__ +#define __MPU_I2C_H__ + +#include <linux/i2c.h> + +int sensor_i2c_write(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned int len, unsigned char const *data); + +int sensor_i2c_write_register(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned char reg, unsigned char value); + +int sensor_i2c_read(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned char reg, unsigned int len, unsigned char *data); + +int mpu_memory_read(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char *data); + +int mpu_memory_write(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char const *data); + +#endif /* __MPU_I2C_H__ */ diff --git a/drivers/misc/mpu3050/mpuirq.c b/drivers/misc/mpu3050/mpuirq.c new file mode 100755 index 000000000000..bf3c10f176fe --- /dev/null +++ b/drivers/misc/mpu3050/mpuirq.c @@ -0,0 +1,315 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/stat.h> +#include <linux/irq.h> +#include <linux/signal.h> +#include <linux/miscdevice.h> +#include <linux/i2c.h> +#include <linux/i2c-dev.h> +#include <linux/workqueue.h> +#include <linux/poll.h> + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +#include "mpu3050.h" +#include "mpuirq.h" +#include "mldl_cfg.h" +#include "mpu-i2c.h" + +#define MPUIRQ_NAME "mpuirq" + +/* function which gets accel data and sends it to MPU */ + +DECLARE_WAIT_QUEUE_HEAD(mpuirq_wait); + +struct mpuirq_dev_data { + struct work_struct work; + struct i2c_client *mpu_client; + struct miscdevice *dev; + int irq; + int pid; + int accel_divider; + int data_ready; + int timeout; +}; + +static struct mpuirq_dev_data mpuirq_dev_data; +static struct mpuirq_data mpuirq_data; +static char *interface = MPUIRQ_NAME; + +static void mpu_accel_data_work_fcn(struct work_struct *work); + +static int mpuirq_open(struct inode *inode, struct file *file) +{ + dev_dbg(mpuirq_dev_data.dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + mpuirq_dev_data.pid = current->pid; + file->private_data = &mpuirq_dev_data; + /* we could do some checking on the flags supplied by "open" + // i.e. O_NONBLOCK + // -> set some flag to disable interruptible_sleep_on in mpuirq_read */ + return 0; +} + +/* close function - called when the "file" /dev/mpuirq is closed in userspace */ +static int mpuirq_release(struct inode *inode, struct file *file) +{ + dev_dbg(mpuirq_dev_data.dev->this_device, "mpuirq_release\n"); + return 0; +} + +/* read function called when from /dev/mpuirq is read */ +static ssize_t mpuirq_read(struct file *file, + char *buf, size_t count, loff_t * ppos) +{ + int len, err; + struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data; + + if (!mpuirq_dev_data.data_ready) { + wait_event_interruptible_timeout(mpuirq_wait, + mpuirq_dev_data.data_ready, + mpuirq_dev_data.timeout); + } + + if (mpuirq_dev_data.data_ready && NULL != buf + && count >= sizeof(mpuirq_data)) { + err = copy_to_user(buf, &mpuirq_data, sizeof(mpuirq_data)); + } else { + return 0; + } + if (err != 0) { + dev_err(p_mpuirq_dev_data->dev->this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + mpuirq_dev_data.data_ready = 0; + len = sizeof(mpuirq_data); + return len; +} + +unsigned int mpuirq_poll(struct file *file, struct poll_table_struct *poll) +{ + int mask = 0; + struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data; + + poll_wait(file, &mpuirq_wait, poll); + if (mpuirq_dev_data.data_ready) + mask |= POLLIN | POLLRDNORM; + dev_dbg(p_mpuirq_dev_data->dev->this_device, + "%s: returning %d\n", __func__, mask); + return mask; +} + +/* ioctl - I/O control */ +static long mpuirq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int data; + + switch (cmd) { + case MPUIRQ_SET_TIMEOUT: + mpuirq_dev_data.timeout = arg; + break; + + case MPUIRQ_GET_INTERRUPT_CNT: + data = mpuirq_data.interruptcount - 1; + if (mpuirq_data.interruptcount > 1) { + mpuirq_data.interruptcount = 1; + } + if (copy_to_user((int *)arg, &data, sizeof(int))) + return -EFAULT; + break; + case MPUIRQ_GET_IRQ_TIME: + if (copy_to_user((int *)arg, &mpuirq_data.irqtime, + sizeof(mpuirq_data.irqtime))) + return -EFAULT; + mpuirq_data.irqtime = 0; + break; + case MPUIRQ_SET_FREQUENCY_DIVIDER: + mpuirq_dev_data.accel_divider = arg; + break; + default: + retval = -EINVAL; + } + return retval; +} + +static void mpu_accel_data_work_fcn(struct work_struct *work) +{ + struct mpuirq_dev_data *mpuirq_dev_data = + (struct mpuirq_dev_data *)work; + struct mldl_cfg *mldl_cfg = + (struct mldl_cfg *)i2c_get_clientdata(mpuirq_dev_data->mpu_client); + struct i2c_adapter *accel_adapter; + unsigned char wbuff[16]; + unsigned char rbuff[16]; + int ii; + + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + mldl_cfg->accel->read((mlsl_handle_t) accel_adapter, + mldl_cfg->accel, &mldl_cfg->pdata->accel, rbuff); + + /* @todo add other data formats here as well */ + if (EXT_SLAVE_BIG_ENDIAN == mldl_cfg->accel->endian) { + for (ii = 0; ii < 3; ii++) { + wbuff[2 * ii + 1] = rbuff[2 * ii + 1]; + wbuff[2 * ii + 2] = rbuff[2 * ii + 0]; + } + } else { + memcpy(wbuff + 1, rbuff, mldl_cfg->accel->len); + } + + wbuff[7] = 0; + wbuff[8] = 1; /*set semaphore */ + + mpu_memory_write(mpuirq_dev_data->mpu_client->adapter, + mldl_cfg->addr, 0x0108, 8, wbuff); +} + +static irqreturn_t mpuirq_handler(int irq, void *dev_id) +{ + static int mycount; + struct timeval irqtime; + mycount++; + + mpuirq_data.interruptcount++; + + /* wake up (unblock) for reading data from userspace + // and ignore first interrupt generated in module init */ + if (mpuirq_data.interruptcount > 1) { + mpuirq_dev_data.data_ready = 1; + + do_gettimeofday(&irqtime); + mpuirq_data.irqtime = (((long long)irqtime.tv_sec) << 32); + mpuirq_data.irqtime += irqtime.tv_usec; + + if ((mpuirq_dev_data.accel_divider >= 0) && + (0 == (mycount % (mpuirq_dev_data.accel_divider + 1)))) { + schedule_work((struct work_struct *)(&mpuirq_dev_data)); + } + + wake_up_interruptible(&mpuirq_wait); + } + + return IRQ_HANDLED; + +} + +/* define which file operations are supported */ +struct file_operations mpuirq_fops = { + .owner = THIS_MODULE, + .read = mpuirq_read, + .poll = mpuirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = mpuirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = mpuirq_ioctl, +#endif + .open = mpuirq_open, + .release = mpuirq_release, +}; + +static struct miscdevice mpuirq_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = MPUIRQ_NAME, + .fops = &mpuirq_fops, +}; + +int mpuirq_init(struct i2c_client *mpu_client) +{ + + int res; + struct mldl_cfg *mldl_cfg = + (struct mldl_cfg *)i2c_get_clientdata(mpu_client); + + /* work_struct initialization */ + INIT_WORK((struct work_struct *)&mpuirq_dev_data, + mpu_accel_data_work_fcn); + mpuirq_dev_data.mpu_client = mpu_client; + + dev_info(&mpu_client->adapter->dev, + "Module Param interface = %s\n", interface); + + mpuirq_dev_data.irq = mpu_client->irq; + mpuirq_dev_data.pid = 0; + mpuirq_dev_data.accel_divider = -1; + mpuirq_dev_data.data_ready = 0; + mpuirq_dev_data.timeout = 0; + mpuirq_dev_data.dev = &mpuirq_device; + + if (mpuirq_dev_data.irq) { + unsigned long flags; + if (BIT_ACTL_LOW == ((mldl_cfg->pdata->int_config) & BIT_ACTL)) + flags = IRQF_TRIGGER_FALLING; + else + flags = IRQF_TRIGGER_RISING; + + res = + request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags, + interface, &mpuirq_dev_data.irq); + if (res) { + dev_err(&mpu_client->adapter->dev, + "myirqtest: cannot register IRQ %d\n", + mpuirq_dev_data.irq); + } else { + res = misc_register(&mpuirq_device); + if (res < 0) { + dev_err(&mpu_client->adapter->dev, + "misc_register returned %d\n", res); + free_irq(mpuirq_dev_data.irq, + &mpuirq_dev_data.irq); + } + } + + } else { + res = 0; + } + + return res; +} + +void mpuirq_exit(void) +{ + /* Free the IRQ first before flushing the work */ + if (mpuirq_dev_data.irq > 0) { + free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq); + } + flush_scheduled_work(); + + dev_info(mpuirq_device.this_device, "Unregistering %s\n", MPUIRQ_NAME); + misc_deregister(&mpuirq_device); + + return; +} + +module_param(interface, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(interface, "The Interface name"); diff --git a/drivers/misc/mpu3050/mpuirq.h b/drivers/misc/mpu3050/mpuirq.h new file mode 100755 index 000000000000..69b7eaad5717 --- /dev/null +++ b/drivers/misc/mpu3050/mpuirq.h @@ -0,0 +1,50 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ + +#ifndef __MPUIRQ__ +#define __MPUIRQ__ + +#ifdef __KERNEL__ +#include <linux/i2c-dev.h> +#endif + +#define MPUIRQ_ENABLE_DEBUG (1) +#define MPUIRQ_GET_INTERRUPT_CNT (2) +#define MPUIRQ_GET_IRQ_TIME (3) +#define MPUIRQ_GET_LED_VALUE (4) +#define MPUIRQ_SET_TIMEOUT (5) +#define MPUIRQ_SET_ACCEL_INFO (6) +#define MPUIRQ_SET_FREQUENCY_DIVIDER (7) + +struct mpuirq_data { + int interruptcount; + unsigned long long irqtime; + int data_type; + int data_size; + void *data; +}; + +#ifdef __KERNEL__ + +void mpuirq_exit(void); +int mpuirq_init(struct i2c_client *mpu_client); + +#endif + +#endif diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 549a34144646..549a34144646 100755..100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 153bd9a16dd9..b6308d5a9572 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -22,6 +22,8 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/bitops.h> #include <linux/mmc/card.h> #include <mach/sdhci.h> @@ -36,6 +38,8 @@ struct tegra_sdhci_host { struct sdhci_host *sdhci; struct clk *clk; int clk_enabled; + bool card_always_on; + u32 sdhci_ints; }; static irqreturn_t carddetect_irq(int irq, void *data) @@ -46,6 +50,14 @@ static irqreturn_t carddetect_irq(int irq, void *data) return IRQ_HANDLED; }; +static void tegra_sdhci_status_notify_cb(int card_present, void *dev_id) +{ + struct sdhci_host *sdhci = (struct sdhci_host *)dev_id; + pr_debug("%s: card_present %d\n", + mmc_hostname(sdhci->mmc), card_present); + sdhci_card_detect_callback(sdhci); +} + static int tegra_sdhci_enable_dma(struct sdhci_host *host) { return 0; @@ -112,6 +124,7 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) host = sdhci_priv(sdhci); host->sdhci = sdhci; + host->card_always_on = (plat->power_gpio == -1) ? 1 : 0; host->clk = clk_get(&pdev->dev, plat->clk_id); if (IS_ERR(host->clk)) { @@ -137,11 +150,17 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_8_BIT_DATA | SDHCI_QUIRK_NO_VERSION_REG | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | - SDHCI_QUIRK_NO_SDIO_IRQ; + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC; if (plat->force_hs != 0) sdhci->quirks |= SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + mmc_set_embedded_sdio_data(sdhci->mmc, + &plat->cis, + &plat->cccr, + plat->funcs, + plat->num_funcs); +#endif rc = sdhci_add_host(sdhci); if (rc) @@ -156,6 +175,9 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) if (rc) goto err_remove_host; + } else if (plat->register_status_notify) { + plat->register_status_notify( + tegra_sdhci_status_notify_cb, sdhci); } if (plat->board_probe) @@ -196,11 +218,91 @@ static int tegra_sdhci_remove(struct platform_device *pdev) return 0; } + +#define is_card_sdio(_card) \ +((_card) && ((_card)->type == MMC_TYPE_SDIO)) + #ifdef CONFIG_PM + + +static void tegra_sdhci_restore_interrupts(struct sdhci_host *sdhost) +{ + u32 ierr; + u32 clear = SDHCI_INT_ALL_MASK; + struct tegra_sdhci_host *host = sdhci_priv(sdhost); + + /* enable required interrupts */ + ierr = sdhci_readl(sdhost, SDHCI_INT_ENABLE); + ierr &= ~clear; + ierr |= host->sdhci_ints; + sdhci_writel(sdhost, ierr, SDHCI_INT_ENABLE); + sdhci_writel(sdhost, ierr, SDHCI_SIGNAL_ENABLE); + + if ((host->sdhci_ints & SDHCI_INT_CARD_INT) && + (sdhost->quirks & SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP)) { + u8 gap_ctrl = sdhci_readb(sdhost, SDHCI_BLOCK_GAP_CONTROL); + gap_ctrl |= 0x8; + sdhci_writeb(sdhost, gap_ctrl, SDHCI_BLOCK_GAP_CONTROL); + } +} + +static int tegra_sdhci_restore(struct sdhci_host *sdhost) +{ + unsigned long timeout; + u8 mask = SDHCI_RESET_ALL; + + sdhci_writeb(sdhost, mask, SDHCI_SOFTWARE_RESET); + + sdhost->clock = 0; + + /* Wait max 100 ms */ + timeout = 100; + + /* hw clears the bit when it's done */ + while (sdhci_readb(sdhost, SDHCI_SOFTWARE_RESET) & mask) { + if (timeout == 0) { + printk(KERN_ERR "%s: Reset 0x%x never completed.\n", + mmc_hostname(sdhost->mmc), (int)mask); + return -EIO; + } + timeout--; + mdelay(1); + } + + tegra_sdhci_restore_interrupts(sdhost); + return 0; +} + static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); - int ret; + int ret = 0; + + if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { + int div = 0; + u16 clk; + unsigned int clock = 100000; + + /* save interrupt status before suspending */ + host->sdhci_ints = sdhci_readl(host->sdhci, SDHCI_INT_ENABLE); + + /* reduce host controller clk and card clk to 100 KHz */ + tegra_sdhci_set_clock(host->sdhci, clock); + sdhci_writew(host->sdhci, 0, SDHCI_CLOCK_CONTROL); + + if (host->sdhci->max_clk > clock) { + div = 1 << (fls(host->sdhci->max_clk / clock) - 2); + if (div > 128) + div = 128; + } + + clk = div << SDHCI_DIVIDER_SHIFT; + clk |= SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN; + sdhci_writew(host->sdhci, clk, SDHCI_CLOCK_CONTROL); + + return ret; + } + ret = sdhci_suspend_host(host->sdhci, state); if (ret) @@ -215,6 +317,22 @@ static int tegra_sdhci_resume(struct platform_device *pdev) struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret; + if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { + int ret = 0; + + /* soft reset SD host controller and enable interrupts */ + ret = tegra_sdhci_restore(host->sdhci); + if (ret) { + pr_err("%s: failed, error = %d\n", __func__, ret); + return ret; + } + + mmiowb(); + host->sdhci->mmc->ops->set_ios(host->sdhci->mmc, + &host->sdhci->mmc->ios); + return 0; + } + tegra_sdhci_enable_clock(host, 1); ret = sdhci_resume_host(host->sdhci); if (ret) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 7af27866c4ed..e4d155912812 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -251,7 +251,7 @@ struct sdhci_host { /* Controller write protect bit is broken. Assume no write protection */ #define SDHCI_QUIRK_BROKEN_WRITE_PROTECT (1<<30) /* Controller needs INTERRUPT_AT_BLOCK_GAP enabled to detect card interrupts */ -#define SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP (1<<31) +#define SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP (1LL<<31) /* Controller should not program HIGH_SPEED_EN after switching to high speed */ #define SDHCI_QUIRK_BROKEN_CTRL_HISPD (1LL<<32) /* Controller supports 8-bit data width */ diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index 695bc83e0cfd..bda70852c5ef 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -306,7 +306,7 @@ static void z_decomp_free(void *arg) if (state) { zlib_inflateEnd(&state->strm); - kfree(state->strm.workspace); + vfree(state->strm.workspace); kfree(state); } } @@ -346,8 +346,7 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len) state->w_size = w_size; state->strm.next_out = NULL; - state->strm.workspace = kmalloc(zlib_inflate_workspacesize(), - GFP_KERNEL|__GFP_REPEAT); + state->strm.workspace = vmalloc(zlib_inflate_workspacesize()); if (state->strm.workspace == NULL) goto out_free; diff --git a/drivers/net/wireless/bcm4329/Kconfig b/drivers/net/wireless/bcm4329/Kconfig index ca5760d32385..0f07a7847acd 100644 --- a/drivers/net/wireless/bcm4329/Kconfig +++ b/drivers/net/wireless/bcm4329/Kconfig @@ -25,3 +25,43 @@ config BCM4329_NVRAM_PATH default "/proc/calibration" ---help--- Path to the calibration file. + +config BCM4329_WIFI_CONTROL_FUNC + bool "Use bcm4329_wlan device" + depends on BCM4329 + default n + ---help--- + Use this option to get various parameters from architecture specific + bcm4329_wlan platform device. Say n if unsure. + +if BCM4329_WIFI_CONTROL_FUNC + +config BCM4329_DHD_USE_STATIC_BUF + bool "Use static buffer" + depends on BCM4329 + default n + ---help--- + Use static buffer from kernel heap allocated during bcm4329_wlan + platform device creation. + +config BCM4329_HW_OOB + bool "Use out of band interrupt" + depends on BCM4329 + default n + ---help--- + Use out of band interrupt for wake on wireless. + +config BCM4329_OOB_INTR_ONLY + bool "Use out of band interrupt only" + depends on BCM4329 + default n + ---help--- + Use out of band interrupt for all interrupts(including SDIO interrupts). + +config BCM4329_GET_CUSTOM_MAC_ENABLE + bool "Use custom mac address" + depends on BCM4329 + default n + ---help--- + Use mac address provided by bcm4329_wlan platform device. +endif diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile index f808fb21256b..20bdab258433 100644 --- a/drivers/net/wireless/bcm4329/Makefile +++ b/drivers/net/wireless/bcm4329/Makefile @@ -3,13 +3,28 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \ -DUNRELEASEDCHIP -Dlinux -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 \ -DDHD_FIRSTREAD=64 -DDHD_GPL -DDHD_SCHED -DBDC -DTOE -DDHD_BCMEVENTS \ -DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \ - -Wall -Wstrict-prototypes -Werror -DOOB_INTR_ONLY -DCUSTOMER_HW2 \ - -DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DDHD_DEBUG_TRAP -DSOFTAP \ - -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT \ - -DGET_CUSTOM_MAC_ENABLE -DSET_RANDOM_MAC_SOFTAP -DCSCAN -DHW_OOB \ + -Wall -Wstrict-prototypes -Werror -DCUSTOMER_HW2 -DMMC_SDIO_ABORT \ + -DDHD_DEBUG_TRAP -DSOFTAP -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT \ + -DPKT_FILTER_SUPPORT -DSET_RANDOM_MAC_SOFTAP -DCSCAN \ -DKEEP_ALIVE -DCONFIG_US_NON_DFS_CHANNELS_ONLY \ -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include +ifeq ($(CONFIG_BCM4329_WIFI_CONTROL_FUNC),y) +DHDCFLAGS += -DCONFIG_WIFI_CONTROL_FUNC +endif +ifeq ($(CONFIG_BCM4329_DHD_USE_STATIC_BUF),y) +DHDCFLAGS += -DDHD_USE_STATIC_BUF +endif +ifeq ($(CONFIG_BCM4329_OOB_INTR_ONLY),y) +DHDCFLAGS += -DOOB_INTR_ONLY +endif +ifeq ($(CONFIG_BCM4329_GET_CUSTOM_MAC_ENABLE),y) +DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE +endif +ifeq ($(CONFIG_BCM4329_HW_OOB),y) +DHDCFLAGS += -DHW_OOB +endif + DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \ wl_iw.o siutils.o sbutils.o aiutils.o hndpmu.o bcmwifi.o dhd_sdio.o \ dhd_linux_sched.o dhd_cdc.o bcmsdh_sdmmc.o bcmsdh.o bcmsdh_linux.o \ diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 07343568a12e..331395108649 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -109,6 +109,12 @@ config BATTERY_WM97XX help Say Y to enable support for battery measured by WM97xx aux port. +config BATTERY_BQ20Z75 + tristate "TI BQ20Z75 Fuel gauge" + depends on I2C + help + Say Y to include support for TI BQ20Z75 (I2C) fuel gauge chips. + config BATTERY_BQ27x00 tristate "BQ27x00 battery driver" depends on I2C diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 10143aaf4ee3..69d76223ffe2 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o +obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75_battery.o obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o diff --git a/drivers/power/bq20z75_battery.c b/drivers/power/bq20z75_battery.c new file mode 100644 index 000000000000..b0d0468b4ae6 --- /dev/null +++ b/drivers/power/bq20z75_battery.c @@ -0,0 +1,544 @@ +/* + * drivers/power/bq20z75_battery.c + * + * Gas Gauge driver for TI's BQ20Z75 + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/debugfs.h> +#include <linux/power_supply.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/interrupt.h> + +#include <mach/gpio.h> + +enum { + REG_MANUFACTURER_DATA, + REG_TEMPERATURE, + REG_VOLTAGE, + REG_CURRENT, + REG_TIME_TO_EMPTY, + REG_TIME_TO_FULL, + REG_STATUS, + REG_CYCLE_COUNT, + REG_CAPACITY, + REG_SERIAL_NUMBER, + REG_MAX +}; + +#define BATTERY_MANUFACTURER_SIZE 12 +#define BATTERY_NAME_SIZE 8 + +/* manufacturer access defines */ +#define MANUFACTURER_ACCESS_STATUS 0x0006 +#define MANUFACTURER_ACCESS_SLEEP 0x0011 + +/* battery status value bits */ +#define BATTERY_INIT_DONE 0x80 +#define BATTERY_DISCHARGING 0x40 +#define BATTERY_FULL_CHARGED 0x20 +#define BATTERY_FULL_DISCHARGED 0x10 + +#define BATTERY_POLL_PERIOD 30000 + +#define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) \ + { \ + .psp = POWER_SUPPLY_PROP_##_psp, \ + .addr = _addr, \ + .min_value = _min_value, \ + .max_value = _max_value, \ + } + +static struct bq20z75_device_data { + enum power_supply_property psp; + u8 addr; + int min_value; + int max_value; +} bq20z75_data[] = { + [REG_MANUFACTURER_DATA] = BQ20Z75_DATA(PRESENT, 0x00, 0, 65535), + [REG_TEMPERATURE] = BQ20Z75_DATA(TEMP, 0x08, 0, 65535), + [REG_VOLTAGE] = BQ20Z75_DATA(VOLTAGE_NOW, 0x09, 0, 20000), + [REG_CURRENT] = BQ20Z75_DATA(CURRENT_NOW, 0x0A, -32768, 32767), + [REG_TIME_TO_EMPTY] = BQ20Z75_DATA(TIME_TO_EMPTY_AVG, 0x12, 0, 65535), + [REG_TIME_TO_FULL] = BQ20Z75_DATA(TIME_TO_FULL_AVG, 0x13, 0, 65535), + [REG_STATUS] = BQ20Z75_DATA(STATUS, 0x16, 0, 65535), + [REG_CYCLE_COUNT] = BQ20Z75_DATA(CYCLE_COUNT, 0x17, 0, 65535), + [REG_CAPACITY] = BQ20Z75_DATA(CAPACITY, 0x0e, 0, 100), + [REG_SERIAL_NUMBER] = BQ20Z75_DATA(SERIAL_NUMBER, 0x1C, 0, 65535), +}; + +static enum power_supply_property bq20z75_battery_properties[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_SERIAL_NUMBER +}; + +static enum power_supply_property bq20z75_ac_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static char *power_supplied_to[] = { + "battery", +}; + +static int bq20z75_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val); +static int bq20z75_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val); + +enum supply_type { + SUPPLY_TYPE_BATTERY = 0, + SUPPLY_TYPE_AC, +}; + +static struct power_supply bq20z75_supply[] = { + [SUPPLY_TYPE_BATTERY] = { + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = bq20z75_battery_properties, + .num_properties = ARRAY_SIZE(bq20z75_battery_properties), + .get_property = bq20z75_bat_get_property, + }, + [SUPPLY_TYPE_AC] = { + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .supplied_to = power_supplied_to, + .num_supplicants = ARRAY_SIZE(power_supplied_to), + .properties = bq20z75_ac_properties, + .num_properties = ARRAY_SIZE(bq20z75_ac_properties), + .get_property = bq20z75_ac_get_property, + }, +}; + +static struct bq20z75_device_info { + struct timer_list battery_poll_timer; + struct i2c_client *client; + int irq; +} *bq20z75_device; + +static int bq20z75_get_ac_status(void) +{ + int charger_gpio = irq_to_gpio(bq20z75_device->irq); + return !gpio_get_value(charger_gpio); +} + +static int bq20z75_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = bq20z75_get_ac_status(); + break; + default: + dev_err(&bq20z75_device->client->dev, + "%s: INVALID property\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int bq20z75_get_health(enum power_supply_property psp, + union power_supply_propval *val) +{ + s32 ret; + + /* Write to ManufacturerAccess with + * ManufacturerAccess command and then + * read the status */ + ret = i2c_smbus_write_word_data(bq20z75_device->client, + bq20z75_data[REG_MANUFACTURER_DATA].addr, + MANUFACTURER_ACCESS_STATUS); + if (ret < 0) { + dev_err(&bq20z75_device->client->dev, + "%s: i2c write for battery presence " + "failed\n", __func__); + return -EINVAL; + } + + ret = i2c_smbus_read_word_data(bq20z75_device->client, + bq20z75_data[REG_MANUFACTURER_DATA].addr); + if (ret < 0) { + dev_err(&bq20z75_device->client->dev, + "%s: i2c read for battery presence " + "failed\n", __func__); + return -EINVAL; + } + + if (ret >= bq20z75_data[REG_MANUFACTURER_DATA].min_value && + ret <= bq20z75_data[REG_MANUFACTURER_DATA].max_value) { + + /* Mask the upper nibble of 2nd byte and + * lower byte of response then + * shift the result by 8 to get status*/ + ret &= 0x0F00; + ret >>= 8; + if (psp == POWER_SUPPLY_PROP_PRESENT) { + if (ret == 0x0F) + /* battery removed */ + val->intval = 0; + else + val->intval = 1; + } else if (psp == POWER_SUPPLY_PROP_HEALTH) { + if (ret == 0x09) + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + else if (ret == 0x0B) + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (ret == 0x0C) + val->intval = POWER_SUPPLY_HEALTH_DEAD; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + } + } else { + val->intval = 0; + } + + return 0; +} + +static int bq20z75_get_psp(int reg_offset, enum power_supply_property psp, + union power_supply_propval *val) +{ + s32 ret; + int ac_status; + +recheck: + ret = i2c_smbus_read_word_data(bq20z75_device->client, + bq20z75_data[reg_offset].addr); + if (ret < 0) { + dev_err(&bq20z75_device->client->dev, + "%s: i2c read for %d failed\n", __func__, reg_offset); + return -EINVAL; + } + + if (ret >= bq20z75_data[reg_offset].min_value && + ret <= bq20z75_data[reg_offset].max_value) { + val->intval = ret; + if (psp == POWER_SUPPLY_PROP_STATUS) { + /* mask the upper byte and then find the + * actual status */ + ret &= 0x00FF; + + /* check the error conditions + * lower nibble represent error + * 0 = no error, so check the remaining bits + * != 0 means error so return */ + if ((ret & 0x000F) >= 0x01) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; + } + + while (!(ret & BATTERY_INIT_DONE)) + goto recheck; + + ac_status = bq20z75_get_ac_status(); + val->intval = ac_status ? + POWER_SUPPLY_STATUS_CHARGING : + POWER_SUPPLY_STATUS_DISCHARGING; + + if (ret & BATTERY_FULL_CHARGED) + val->intval = POWER_SUPPLY_STATUS_FULL; + } + /* bq20z75 provides battery tempreture in 0.1°K + * so convert it to °C */ + else if (psp == POWER_SUPPLY_PROP_TEMP) + val->intval = ret - 2731; + } else { + val->intval = 0; + if (psp == POWER_SUPPLY_PROP_STATUS) + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return 0; +} + +static int bq20z75_get_capacity(union power_supply_propval *val) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(bq20z75_device->client, + bq20z75_data[REG_CAPACITY].addr); + if (ret < 0) { + dev_err(&bq20z75_device->client->dev, "%s: i2c read for %d " + "failed\n", __func__, REG_CAPACITY); + return -EINVAL; + } + + /* bq20z75 spec says that this can be >100 % + * even if max value is 100 % */ + val->intval = ((ret >= 100) ? 100 : ret); + + return 0; +} + +static char bq20z75_serial[5]; +static int bq20z75_get_battery_serial_number(union power_supply_propval *val) +{ + int ret; + + ret = i2c_smbus_read_word_data(bq20z75_device->client, + bq20z75_data[REG_SERIAL_NUMBER].addr); + if (ret < 0) + return ret; + + ret = sprintf(bq20z75_serial, "%04x", ret); + val->strval = bq20z75_serial; + + return 0; +} + +static int bq20z75_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + u8 count; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + case POWER_SUPPLY_PROP_HEALTH: + if (bq20z75_get_health(psp, val)) + return -EINVAL; + break; + + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + + case POWER_SUPPLY_PROP_CAPACITY: + if (bq20z75_get_capacity(val)) + return -EINVAL; + break; + + case POWER_SUPPLY_PROP_SERIAL_NUMBER: + if (bq20z75_get_battery_serial_number(val)) + return -EINVAL; + break; + + case POWER_SUPPLY_PROP_STATUS: + case POWER_SUPPLY_PROP_CYCLE_COUNT: + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: + case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: + for (count = 0; count < REG_MAX; count++) { + if (psp == bq20z75_data[count].psp) + break; + } + + if (bq20z75_get_psp(count, psp, val)) + return -EINVAL; + break; + + default: + dev_err(&bq20z75_device->client->dev, + "%s: INVALID property\n", __func__); + return -EINVAL; + } + + return 0; +} + +static irqreturn_t ac_present_irq(int irq, void *data) +{ + power_supply_changed(&bq20z75_supply[SUPPLY_TYPE_AC]); + power_supply_changed(&bq20z75_supply[SUPPLY_TYPE_BATTERY]); + return IRQ_HANDLED; +} + +static void battery_poll_timer_func(unsigned long unused) +{ + power_supply_changed(&bq20z75_supply[SUPPLY_TYPE_BATTERY]); + power_supply_changed(&bq20z75_supply[SUPPLY_TYPE_AC]); + mod_timer(&bq20z75_device->battery_poll_timer, + jiffies + msecs_to_jiffies(BATTERY_POLL_PERIOD)); +} + +static int bq20z75_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc, i, flags; + int supply_index = SUPPLY_TYPE_BATTERY; + + bq20z75_device = kzalloc(sizeof(*bq20z75_device), GFP_KERNEL); + if (!bq20z75_device) + return -ENOMEM; + + memset(bq20z75_device, 0, sizeof(*bq20z75_device)); + + bq20z75_device->client = client; + flags = bq20z75_device->client->flags; + bq20z75_device->client->flags &= ~I2C_M_IGNORE_NAK; + + rc = i2c_smbus_read_word_data(bq20z75_device->client, + bq20z75_data[REG_SERIAL_NUMBER].addr); + if (rc < 0) { + dev_err(&bq20z75_device->client->dev, + "%s: no battery present(%d)\n", __func__, rc); + supply_index = SUPPLY_TYPE_AC; + } + + bq20z75_device->client->flags = flags; + bq20z75_device->irq = client->irq; + i2c_set_clientdata(client, bq20z75_device); + + rc = request_threaded_irq(bq20z75_device->irq, NULL, + ac_present_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "ac_present", bq20z75_device); + if (rc < 0) { + dev_err(&bq20z75_device->client->dev, + "%s: request_irq failed(%d)\n", __func__, rc); + goto fail_irq; + } + + for (i = supply_index; i < ARRAY_SIZE(bq20z75_supply); i++) { + rc = power_supply_register(&client->dev, + &bq20z75_supply[i]); + if (rc) { + dev_err(&bq20z75_device->client->dev, + "%s: Failed to register power supply\n", + __func__); + goto fail_power_register; + } + } + + setup_timer(&bq20z75_device->battery_poll_timer, + battery_poll_timer_func, 0); + mod_timer(&bq20z75_device->battery_poll_timer, + jiffies + msecs_to_jiffies(BATTERY_POLL_PERIOD)); + + dev_info(&bq20z75_device->client->dev, "driver registered\n"); + return 0; + +fail_power_register: + while (i--) + power_supply_unregister(&bq20z75_supply[i]); + free_irq(bq20z75_device->irq, bq20z75_device); +fail_irq: + kfree(bq20z75_device); + return rc; +} + +static int bq20z75_remove(struct i2c_client *client) +{ + struct bq20z75_device_info *bq20z75_device; + int i; + + bq20z75_device = i2c_get_clientdata(client); + del_timer_sync(&bq20z75_device->battery_poll_timer); + + for (i = 0; i < ARRAY_SIZE(bq20z75_supply); i++) + power_supply_unregister(&bq20z75_supply[i]); + + kfree(bq20z75_device); + + return 0; +} + +#if defined (CONFIG_PM) +static int bq20z75_suspend(struct i2c_client *client, + pm_message_t state) +{ + s32 ret; + struct bq20z75_device_info *bq20z75_device; + + bq20z75_device = i2c_get_clientdata(client); + del_timer_sync(&bq20z75_device->battery_poll_timer); + + /* write to manufacture access with sleep command */ + ret = i2c_smbus_write_word_data(bq20z75_device->client, + bq20z75_data[REG_MANUFACTURER_DATA].addr, + MANUFACTURER_ACCESS_SLEEP); + if (ret < 0) { + dev_err(&bq20z75_device->client->dev, + "%s: i2c write for %d failed\n", + __func__, MANUFACTURER_ACCESS_SLEEP); + return -EINVAL; + } + + return 0; +} + +/* any smbus transaction will wake up bq20z75 */ +static int bq20z75_resume(struct i2c_client *client) +{ + setup_timer(&bq20z75_device->battery_poll_timer, + battery_poll_timer_func, 0); + mod_timer(&bq20z75_device->battery_poll_timer, + jiffies + msecs_to_jiffies(BATTERY_POLL_PERIOD)); + return 0; +} +#endif + +static const struct i2c_device_id bq20z75_id[] = { + { "bq20z75-battery", 0 }, + {}, +}; + +static struct i2c_driver bq20z75_battery_driver = { + .probe = bq20z75_probe, + .remove = bq20z75_remove, +#if defined (CONFIG_PM) + .suspend = bq20z75_suspend, + .resume = bq20z75_resume, +#endif + .id_table = bq20z75_id, + .driver = { + .name = "bq20z75-battery", + }, +}; + +static int __init bq20z75_battery_init(void) +{ + int ret; + + ret = i2c_add_driver(&bq20z75_battery_driver); + if (ret) + dev_err(&bq20z75_device->client->dev, + "%s: i2c_add_driver failed\n", __func__); + + return ret; +} +module_init(bq20z75_battery_init); + +static void __exit bq20z75_battery_exit(void) +{ + i2c_del_driver(&bq20z75_battery_driver); +} +module_exit(bq20z75_battery_exit); + +MODULE_AUTHOR("NVIDIA Corporation"); +MODULE_DESCRIPTION("BQ20z75 battery monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 172951bf23a4..82fba419f2f5 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -108,6 +108,22 @@ config REGULATOR_MAX8998 via I2C bus. The provided regulator is suitable for S3C6410 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX8907C + tristate "Maxim 8907C voltage regulator" + depends on MFD_MAX8907C + help + This driver controls a Maxim 8907C voltage output regulator + via I2C bus. The provided regulator is suitable for Tegra + chip to control Step-Down DC-DC and LDOs. + +config REGULATOR_MAX8952 + tristate "Maxim 8952 voltage regulator" + depends on I2C + help + This driver controls a Maxim 8952 voltage output regulator + via I2C bus. The provided regulator is suitable for Tegra + chip to control Step-Down Regulator. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC" depends on TWL4030_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8285fd832e16..13ab9f9b09a0 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -18,6 +18,8 @@ obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o +obj-$(CONFIG_REGULATOR_MAX8907C) += max8907c-regulator.o +obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o diff --git a/drivers/regulator/max8907c-regulator.c b/drivers/regulator/max8907c-regulator.c new file mode 100644 index 000000000000..fc3087670164 --- /dev/null +++ b/drivers/regulator/max8907c-regulator.c @@ -0,0 +1,416 @@ +/* + * max8907c-regulator.c -- support regulators in max8907c + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/max8907c.h> +#include <linux/regulator/max8907c-regulator.h> + +#define MAX8907C_REGULATOR_CNT (ARRAY_SIZE(max8907c_regulators)) + +struct max8907c_regulator_info { + u32 min_uV; + u32 max_uV; + u32 step_uV; + u8 reg_base; + struct regulator_desc desc; +}; + +#define REG_LDO(ids, base, min, max, step) \ + { \ + .min_uV = (min), \ + .max_uV = (max), \ + .step_uV = (step), \ + .reg_base = (base), \ + .desc = { \ + .name = #ids, \ + .id = MAX8907C_##ids, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &max8907c_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define REG_FIXED(ids, voltage) \ + { \ + .min_uV = (voltage), \ + .max_uV = (voltage), \ + .desc = { \ + .name = #ids, \ + .id = MAX8907C_##ids, \ + .n_voltages = 1, \ + .ops = &max8907c_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define REG_OUT5V(ids, base, voltage) \ + { \ + .min_uV = (voltage), \ + .max_uV = (voltage), \ + .reg_base = (base), \ + .desc = { \ + .name = #ids, \ + .id = MAX8907C_##ids, \ + .n_voltages = 1, \ + .ops = &max8907c_out5v_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define REG_BBAT(ids, base, min, max, step) \ + { \ + .min_uV = (min), \ + .max_uV = (max), \ + .step_uV = (step), \ + .reg_base = (base), \ + .desc = { \ + .name = #ids, \ + .id = MAX8907C_##ids, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &max8907c_bbat_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define REG_WLED(ids, base, voltage) \ + { \ + .min_uV = (voltage), \ + .max_uV = (voltage), \ + .reg_base = (base), \ + .desc = { \ + .name = #ids, \ + .id = MAX8907C_##ids, \ + .n_voltages = 1, \ + .ops = &max8907c_wled_ops, \ + .type = REGULATOR_CURRENT, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define LDO_750_50(id, base) REG_LDO(id, (base), 750000, 3900000, 50000) +#define LDO_650_25(id, base) REG_LDO(id, (base), 650000, 2225000, 25000) + +static int max8907c_regulator_list_voltage(struct regulator_dev *dev, + unsigned index); +static int max8907c_regulator_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV); +static int max8907c_regulator_bbat_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV); +static int max8907c_regulator_ldo_get_voltage(struct regulator_dev *dev); +static int max8907c_regulator_fixed_get_voltage(struct regulator_dev *dev); +static int max8907c_regulator_bbat_get_voltage(struct regulator_dev *dev); +static int max8907c_regulator_wled_set_current_limit(struct regulator_dev *dev, + int min_uA, int max_uA); +static int max8907c_regulator_wled_get_current_limit(struct regulator_dev *dev); +static int max8907c_regulator_ldo_enable(struct regulator_dev *dev); +static int max8907c_regulator_out5v_enable(struct regulator_dev *dev); +static int max8907c_regulator_ldo_disable(struct regulator_dev *dev); +static int max8907c_regulator_out5v_disable(struct regulator_dev *dev); +static int max8907c_regulator_ldo_is_enabled(struct regulator_dev *dev); +static int max8907c_regulator_out5v_is_enabled(struct regulator_dev *dev); + +static struct regulator_ops max8907c_ldo_ops = { + .list_voltage = max8907c_regulator_list_voltage, + .set_voltage = max8907c_regulator_ldo_set_voltage, + .get_voltage = max8907c_regulator_ldo_get_voltage, + .enable = max8907c_regulator_ldo_enable, + .disable = max8907c_regulator_ldo_disable, + .is_enabled = max8907c_regulator_ldo_is_enabled, +}; + +static struct regulator_ops max8907c_fixed_ops = { + .list_voltage = max8907c_regulator_list_voltage, + .get_voltage = max8907c_regulator_fixed_get_voltage, +}; + +static struct regulator_ops max8907c_out5v_ops = { + .list_voltage = max8907c_regulator_list_voltage, + .get_voltage = max8907c_regulator_fixed_get_voltage, + .enable = max8907c_regulator_out5v_enable, + .disable = max8907c_regulator_out5v_disable, + .is_enabled = max8907c_regulator_out5v_is_enabled, +}; + +static struct regulator_ops max8907c_bbat_ops = { + .list_voltage = max8907c_regulator_list_voltage, + .set_voltage = max8907c_regulator_bbat_set_voltage, + .get_voltage = max8907c_regulator_bbat_get_voltage, +}; + +static struct regulator_ops max8907c_wled_ops = { + .list_voltage = max8907c_regulator_list_voltage, + .set_current_limit = max8907c_regulator_wled_set_current_limit, + .get_current_limit = max8907c_regulator_wled_get_current_limit, + .get_voltage = max8907c_regulator_fixed_get_voltage, +}; + +static struct max8907c_regulator_info max8907c_regulators[] = { + REG_LDO(SD1, MAX8907C_REG_SDCTL1, 650000, 2225000, 25000), + REG_LDO(SD2, MAX8907C_REG_SDCTL2, 637500, 1425000, 12500), + REG_LDO(SD3, MAX8907C_REG_SDCTL3, 750000, 3900000, 50000), + LDO_750_50(LDO1, MAX8907C_REG_LDOCTL1), + LDO_650_25(LDO2, MAX8907C_REG_LDOCTL2), + LDO_650_25(LDO3, MAX8907C_REG_LDOCTL3), + LDO_750_50(LDO4, MAX8907C_REG_LDOCTL4), + LDO_750_50(LDO5, MAX8907C_REG_LDOCTL5), + LDO_750_50(LDO6, MAX8907C_REG_LDOCTL6), + LDO_750_50(LDO7, MAX8907C_REG_LDOCTL7), + LDO_750_50(LDO8, MAX8907C_REG_LDOCTL8), + LDO_750_50(LDO9, MAX8907C_REG_LDOCTL9), + LDO_750_50(LDO10, MAX8907C_REG_LDOCTL10), + LDO_750_50(LDO11, MAX8907C_REG_LDOCTL11), + LDO_750_50(LDO12, MAX8907C_REG_LDOCTL12), + LDO_750_50(LDO13, MAX8907C_REG_LDOCTL13), + LDO_750_50(LDO14, MAX8907C_REG_LDOCTL14), + LDO_750_50(LDO15, MAX8907C_REG_LDOCTL15), + LDO_750_50(LDO16, MAX8907C_REG_LDOCTL16), + LDO_650_25(LDO17, MAX8907C_REG_LDOCTL17), + LDO_650_25(LDO18, MAX8907C_REG_LDOCTL18), + LDO_750_50(LDO19, MAX8907C_REG_LDOCTL19), + LDO_750_50(LDO20, MAX8907C_REG_LDOCTL20), + REG_OUT5V(OUT5V, MAX8907C_REG_OUT5VEN, 5000000), + REG_OUT5V(OUT33V, MAX8907C_REG_OUT33VEN, 3300000), + REG_BBAT(BBAT, MAX8907C_REG_BBAT_CNFG, 2400000, 3000000, 200000), + REG_FIXED(SDBY, 1200000), + REG_FIXED(VRTC, 3300000), + REG_WLED(WLED, MAX8907C_REG_ILED_CNTL, 0), +}; + +static int max8907c_regulator_list_voltage(struct regulator_dev *rdev, + unsigned index) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + + return info->min_uV + info->step_uV * index; +} + +static int max8907c_regulator_ldo_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + if (min_uV < info->min_uV || max_uV > info->max_uV) + return -EDOM; + + val = (min_uV - info->min_uV) / info->step_uV; + + return max8907c_reg_write(parent, info->reg_base + MAX8907C_VOUT, val); +} + +static int max8907c_regulator_bbat_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + if (min_uV < info->min_uV || max_uV > info->max_uV) + return -EDOM; + + val = (min_uV - info->min_uV) / info->step_uV; + + return max8907c_set_bits(parent, info->reg_base, MAX8907C_MASK_VBBATTCV, + val); +} + +static int max8907c_regulator_ldo_get_voltage(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + val = max8907c_reg_read(parent, info->reg_base + MAX8907C_VOUT); + return val * info->step_uV + info->min_uV; +} + +static int max8907c_regulator_fixed_get_voltage(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + + return info->min_uV; +} + +static int max8907c_regulator_bbat_get_voltage(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + val = + max8907c_reg_read(parent, info->reg_base) & MAX8907C_MASK_VBBATTCV; + return val * info->step_uV + info->min_uV; +} + +static int max8907c_regulator_wled_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + + if (min_uA > 25500) + return -EDOM; + + return max8907c_reg_write(parent, info->reg_base, min_uA / 100); +} + +static int max8907c_regulator_wled_get_current_limit(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + val = max8907c_reg_read(parent, info->reg_base); + return val * 100; +} + +static int max8907c_regulator_ldo_enable(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + + return max8907c_set_bits(parent, info->reg_base + MAX8907C_CTL, + MAX8907C_MASK_LDO_EN | MAX8907C_MASK_LDO_SEQ, + MAX8907C_MASK_LDO_EN | MAX8907C_MASK_LDO_SEQ); +} + +static int max8907c_regulator_out5v_enable(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + + return max8907c_set_bits(parent, info->reg_base, + MAX8907C_MASK_OUT5V_VINEN | + MAX8907C_MASK_OUT5V_ENSRC | + MAX8907C_MASK_OUT5V_EN, + MAX8907C_MASK_OUT5V_ENSRC | + MAX8907C_MASK_OUT5V_EN); +} + +static int max8907c_regulator_ldo_disable(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + + return max8907c_set_bits(parent, info->reg_base + MAX8907C_CTL, + MAX8907C_MASK_LDO_EN | MAX8907C_MASK_LDO_SEQ, + MAX8907C_MASK_LDO_SEQ); +} + +static int max8907c_regulator_out5v_disable(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + + return max8907c_set_bits(parent, info->reg_base, + MAX8907C_MASK_OUT5V_VINEN | + MAX8907C_MASK_OUT5V_ENSRC | + MAX8907C_MASK_OUT5V_EN, + MAX8907C_MASK_OUT5V_ENSRC); +} + +static int max8907c_regulator_ldo_is_enabled(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + val = max8907c_reg_read(parent, info->reg_base + MAX8907C_CTL); + if (val < 0) + return -EDOM; + + return (val & MAX8907C_MASK_LDO_EN) || !(val & MAX8907C_MASK_LDO_SEQ); +} + +static int max8907c_regulator_out5v_is_enabled(struct regulator_dev *rdev) +{ + const struct max8907c_regulator_info *info = rdev_get_drvdata(rdev); + struct device *parent = rdev_get_dev(rdev)->parent->parent; + int val; + + val = max8907c_reg_read(parent, info->reg_base); + if (val < 0) + return -EDOM; + + if ((val & + (MAX8907C_MASK_OUT5V_VINEN | MAX8907C_MASK_OUT5V_ENSRC | + MAX8907C_MASK_OUT5V_EN)) + == MAX8907C_MASK_OUT5V_ENSRC) + return 1; + + return 0; +} + +static int max8907c_regulator_probe(struct platform_device *pdev) +{ + struct max8907c_regulator_info *info; + struct regulator_dev *rdev; + + info = &max8907c_regulators[pdev->id]; + + rdev = regulator_register(&info->desc, + &pdev->dev, pdev->dev.platform_data, info); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Cannot register regulator \"%s\", %ld\n", + info->desc.name, PTR_ERR(rdev)); + goto error; + } + + platform_set_drvdata(pdev, rdev); + return 0; + +error: + return PTR_ERR(rdev); +} + +static int max8907c_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + return 0; +} + +static struct platform_driver max8907c_regulator_driver = { + .driver = { + .name = "max8907c-regulator", + .owner = THIS_MODULE, + }, + .probe = max8907c_regulator_probe, + .remove = __devexit_p(max8907c_regulator_remove), +}; + +static int __init max8907c_regulator_init(void) +{ + return platform_driver_register(&max8907c_regulator_driver); +} + +subsys_initcall(max8907c_regulator_init); + +static void __exit max8907c_reg_exit(void) +{ + platform_driver_unregister(&max8907c_regulator_driver); +} + +module_exit(max8907c_reg_exit); + +MODULE_DESCRIPTION("MAX8907C regulator driver"); +MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c new file mode 100644 index 000000000000..bc0c8b8835c5 --- /dev/null +++ b/drivers/regulator/max8952.c @@ -0,0 +1,313 @@ +/* + * max8952.c -- support regulators in max8952 + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/regulator/driver.h> +#include <linux/slab.h> +#include <linux/regulator/max8952.h> +#include <linux/platform_device.h> + +#define VOLTAGE_TO_VALUE(v) (((v) - 750000) / 10000) +#define VALUE_TO_VOLTAGE(val) ((val) * 10000 + 750000) + +struct max8952_info { + int voltages_count; + const int *voltages_list; + u8 reg_base; + struct regulator_desc desc; +}; + +#define REG(ids, base, list) \ + { \ + .voltages_list = (list), \ + .reg_base = (base), \ + .desc = { \ + .name = #ids, \ + .id = MAX8952_##ids, \ + .n_voltages = ARRAY_SIZE((list)), \ + .ops = &max8952_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +static const int max8952_mode0_voltages[] = { + 750000, 760000, 1260000, 1270000, 1280000, 1370000, 1380000 +}; + +static const int max8952_mode1_voltages[] = { + 750000, 760000, 1040000, 1050000, 1060000, 1370000, 1380000 +}; + +static const int max8952_mode2_voltages[] = { + 750000, 760000, 1210000, 1220000, 1230000, 1370000, 1380000 +}; + +static const int max8952_mode3_voltages[] = { + 750000, 760000, 1040000, 1050000, 1060000, 1370000, 1380000 +}; + +static int max8952_list_voltage(struct regulator_dev *dev, unsigned index); +static int max8952_set_voltage(struct regulator_dev *dev, int min_uV, + int max_uV); +static int max8952_get_voltage(struct regulator_dev *dev); + +static struct regulator_ops max8952_ops = { + .list_voltage = max8952_list_voltage, + .set_voltage = max8952_set_voltage, + .get_voltage = max8952_get_voltage, +}; + +static struct max8952_info max8952_regulators[] = { + REG(MODE0, MAX8952_REG_MODE0, max8952_mode0_voltages), + REG(MODE1, MAX8952_REG_MODE1, max8952_mode1_voltages), + REG(MODE2, MAX8952_REG_MODE2, max8952_mode2_voltages), + REG(MODE3, MAX8952_REG_MODE3, max8952_mode3_voltages), +}; + +#define MAX8952_REGULATOR_CNT (ARRAY_SIZE(max8952_regulators)) + +struct max8952 { + struct i2c_client *i2c; + struct mutex io_lock; + struct regulator_dev *rdev[MAX8952_REGULATOR_CNT]; +}; + +static int max8952_i2c_read(struct i2c_client *i2c, u8 reg, u8 count, u8 * dest) +{ + struct i2c_msg xfer[2]; + int ret; + + xfer[0].addr = i2c->addr; + xfer[0].flags = I2C_M_NOSTART; + xfer[0].len = 1; + xfer[0].buf = ® + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = count; + xfer[1].buf = dest; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret == 2) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; +} + +static int max8952_i2c_write(struct i2c_client *i2c, u8 reg, u8 count, + const u8 *src) +{ + u8 msg[0x100 + 1]; + int ret; + + msg[0] = reg; + memcpy(&msg[1], src, count); + + ret = i2c_master_send(i2c, msg, count + 1); + if (ret < 0) + return ret; + if (ret != count + 1) + return -EIO; + return 0; +} + +static u8 max8952_read(struct max8952 *max8952, u8 reg) +{ + u8 val; + int ret; + + mutex_lock(&max8952->io_lock); + + ret = max8952_i2c_read(max8952->i2c, reg, 1, &val); + + mutex_unlock(&max8952->io_lock); + pr_debug("max8952: reg read reg=%x, val=%x\n", (unsigned int)reg, + (unsigned int)val); + + if (ret < 0) + pr_err("Failed to read max8952 I2C driver: %d\n", ret); + return val; +} + +static int max8952_write(struct max8952 *max8952, u8 reg, u8 val) +{ + int ret; + + pr_debug("max8952: reg write reg=%x, val=%x\n", (unsigned int)reg, + (unsigned int)val); + mutex_lock(&max8952->io_lock); + + ret = max8952_i2c_write(max8952->i2c, reg, 1, &val); + + mutex_unlock(&max8952->io_lock); + + if (ret < 0) + pr_err("Failed to write max8952 I2C driver: %d\n", ret); + return ret; +} + +int max8952_set_bits(struct max8952 *max8952, u8 reg, u8 mask, u8 val) +{ + u8 tmp; + int ret; + + pr_debug("max8952: reg write reg=%02X, val=%02X, mask=%02X\n", + (unsigned int)reg, (unsigned int)val, (unsigned int)mask); + mutex_lock(&max8952->io_lock); + + ret = max8952_i2c_read(max8952->i2c, reg, 1, &tmp); + if (ret == 0) { + val = (tmp & ~mask) | (val & mask); + ret = max8952_i2c_write(max8952->i2c, reg, 1, &val); + } + + mutex_unlock(&max8952->io_lock); + + if (ret != 0) + pr_err("Failed to write max8952 I2C driver: %d\n", ret); + return ret; +} + +static int max8952_list_voltage(struct regulator_dev *rdev, unsigned index) +{ + const struct max8952_info *reg = &max8952_regulators[rdev_get_id(rdev)]; + + return reg->voltages_list[index]; +} + +static int max8952_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV) +{ + struct max8952 *max8952 = rdev_get_drvdata(rdev); + const struct max8952_info *reg = &max8952_regulators[rdev_get_id(rdev)]; + int val = -1; + int voltage; + int i; + + for (i = 0; i < reg->desc.n_voltages; i++) { + voltage = reg->voltages_list[i]; + if (min_uV <= voltage && voltage <= max_uV) { + val = VOLTAGE_TO_VALUE(voltage); + break; + } + } + if (val == -1) + return -EDOM; + + return max8952_set_bits(max8952, reg->reg_base, MAX8952_MASK_OUTMODE, + val); +} + +static int max8952_get_voltage(struct regulator_dev *rdev) +{ + struct max8952 *max8952 = rdev_get_drvdata(rdev); + const struct max8952_info *reg = &max8952_regulators[rdev_get_id(rdev)]; + int val; + + val = max8952_read(max8952, reg->reg_base); + val &= MAX8952_MASK_OUTMODE; + + return VALUE_TO_VOLTAGE(val); +} + +static int __devinit max8952_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) +{ + struct max8952 *max8952; + struct max8952_platform_data *pdata = i2c->dev.platform_data; + struct regulator_dev *rdev; + int id; + int i; + + max8952 = kzalloc(sizeof(struct max8952), GFP_KERNEL); + if (max8952 == NULL) + return -ENOMEM; + + max8952->i2c = i2c; + mutex_init(&max8952->io_lock); + + for (i = 0; i < pdata->num_subdevs; i++) { + id = pdata->subdevs[i]->id; + rdev = + regulator_register(&max8952_regulators[id].desc, &i2c->dev, + (struct regulator_init_data *)pdata-> + subdevs[i]->dev.platform_data, max8952); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, + "Cannot register regulator \"%s\", %ld\n", + max8952_regulators[id].desc.name, + PTR_ERR(rdev)); + goto error; + } + max8952->rdev[id] = rdev; + } + + i2c_set_clientdata(i2c, max8952); + return 0; + +error: + kfree(max8952); + return PTR_ERR(rdev); +} + +static int __devexit max8952_remove(struct i2c_client *i2c) +{ + struct max8952 *max8952 = i2c_get_clientdata(i2c); + int i; + + for (i = 0; i < MAX8952_REGULATOR_CNT; i++) { + if (max8952->rdev[i]) + regulator_unregister(max8952->rdev[i]); + } + kfree(max8952); + + return 0; +} + +static const struct i2c_device_id max8952_id[] = { + {"max8952", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, max8952_id); + +static struct i2c_driver max8952_driver = { + .probe = max8952_probe, + .remove = __devexit_p(max8952_remove), + .driver = { + .name = "max8952", + .owner = THIS_MODULE, + }, + .id_table = max8952_id, +}; + +static int __init max8952_init(void) +{ + return i2c_add_driver(&max8952_driver); +} + +subsys_initcall(max8952_init); + +static void __exit max8952_exit(void) +{ + i2c_del_driver(&max8952_driver); +} + +module_exit(max8952_exit); + +MODULE_DESCRIPTION("MAX8952 regulator driver"); +MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a86401ea8e71..350750d60fea 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -249,6 +249,16 @@ config RTC_DRV_X1205 This driver can also be built as a module. If so, the module will be called rtc-x1205. +config RTC_DRV_TEGRA + tristate "NVIDIA Tegra Internal RTC driver" + depends on ARCH_TEGRA + help + If you say yes here you get support for the + Tegra 200 series internal RTC module. + + This drive can also be built as a module. If so, the module + will be called rtc-tegra. + config RTC_DRV_PCF8563 tristate "Philips PCF8563/Epson RTC8564" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 5520733748d2..cc4a28918637 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o +obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c new file mode 100644 index 000000000000..f5cccd65a12c --- /dev/null +++ b/drivers/rtc/rtc-tegra.c @@ -0,0 +1,471 @@ +/* + * drivers/rtc/rtc-tegra.c + * + * An RTC driver for the NVIDIA Tegra 200 series internal RTC. + * + * Copyright (c) 2010, NVIDIA Corporation. + * Copyright (c) 2010 Jon Mayo <jmayo@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +/* how many attempts to wait in tegra_rtc_wait_while_busy(). */ +#define RTC_TEGRA_RETRIES 15 + +#define tegra_rtc_read(ofs) readl(rtc_base + (ofs)) +#define tegra_rtc_write(ofs, val) writel((val), rtc_base + (ofs)) + +/* STATUS: This bit is set when a write is initiated on the APB side. It is + * cleared once the write completes in RTC 32KHz clock domain which could be + * several thousands of APB clocks. This must be IDLE before a write is + * initiated. Note that this bit is only for writes. + * 0 = IDLE + * 1 = BUSY + */ +#define RTC_TEGRA_REG_BUSY 0x004 +#define RTC_TEGRA_REG_SECONDS 0x008 +#define RTC_TEGRA_REG_SHADOW_SECONDS 0x00c +#define RTC_TEGRA_REG_MILLI_SECONDS 0x010 +#define RTC_TEGRA_REG_SECONDS_ALARM0 0x014 +#define RTC_TEGRA_REG_SECONDS_ALARM1 0x018 +#define RTC_TEGRA_REG_MILLI_SECONDS_ALARM0 0x01c +#define RTC_TEGRA_REG_INTR_MASK 0x028 +/* a write to this register performs a clear. reg=reg&(~x) */ +#define RTC_TEGRA_REG_INTR_STATUS 0x02c + +/* bits in INTR_MASK */ +#define RTC_TEGRA_INTR_MASK_MSEC_CDN_ALARM (1<<4) +#define RTC_TEGRA_INTR_MASK_SEC_CDN_ALARM (1<<3) +#define RTC_TEGRA_INTR_MASK_MSEC_ALARM (1<<2) +#define RTC_TEGRA_INTR_MASK_SEC_ALARM1 (1<<1) +#define RTC_TEGRA_INTR_MASK_SEC_ALARM0 (1<<0) + +/* bits in INTR_STATUS */ +#define RTC_TEGRA_INTR_STATUS_MSEC_CDN_ALARM (1<<4) +#define RTC_TEGRA_INTR_STATUS_SEC_CDN_ALARM (1<<3) +#define RTC_TEGRA_INTR_STATUS_MSEC_ALARM (1<<2) +#define RTC_TEGRA_INTR_STATUS_SEC_ALARM1 (1<<1) +#define RTC_TEGRA_INTR_STATUS_SEC_ALARM0 (1<<0) + +static struct rtc_device *rtc_dev; +static DEFINE_SPINLOCK(tegra_rtc_lock); +static void __iomem *rtc_base; /* NULL if not initialized. */ +static int tegra_rtc_irq; /* alarm and periodic interrupt */ + +/* check is hardware is accessing APB. */ +static inline u32 tegra_rtc_check_busy(void) +{ + return tegra_rtc_read(RTC_TEGRA_REG_BUSY); +} + +/* wait for hardware to be ready for writing. + * do not call this inside the spin lock because it sleeps. + */ +static int tegra_rtc_wait_while_busy(struct device *dev) +{ + /* TODO: wait for busy then not busy to catch a leading edge. */ + int retries = RTC_TEGRA_RETRIES; + while (tegra_rtc_check_busy()) { + if (!retries--) { + dev_err(dev, "write failed:retry count exceeded.\n"); + return -ETIMEDOUT; + } + msleep(1); + } + return 0; +} + +/* waits for the RTC to not be busy accessing APB, then write a single value. */ +static int tegra_rtc_write_not_busy(struct device *dev, unsigned ofs, u32 value) +{ + unsigned long sl_irq_flags; + int ret; + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + if(tegra_rtc_check_busy()) { + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + ret = tegra_rtc_wait_while_busy(dev); + if (ret) + return ret; + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + } + tegra_rtc_write(ofs, value); + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + return 0; +} + + +static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long sec, msec; + unsigned long sl_irq_flags; + + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + + msec = tegra_rtc_read(RTC_TEGRA_REG_MILLI_SECONDS); + sec = tegra_rtc_read(RTC_TEGRA_REG_SHADOW_SECONDS); + + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + + rtc_time_to_tm(sec, tm); + + dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + tm->tm_mon+1, + tm->tm_mday, + tm->tm_year+1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + + return 0; +} + +static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long sec; + int ret; + + /* convert tm to seconds. */ + ret = rtc_valid_tm(tm); + if (ret) return ret; + rtc_tm_to_time(tm, &sec); + + dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + tm->tm_mon+1, + tm->tm_mday, + tm->tm_year+1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + + /* seconds only written if wait succeeded. */ + ret = tegra_rtc_write_not_busy(dev, RTC_TEGRA_REG_SECONDS, sec); + + dev_vdbg( + dev, "time read back as %d\n", + tegra_rtc_read(RTC_TEGRA_REG_SECONDS) + ); + return ret; +} + +static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + unsigned long sec; + unsigned long sl_irq_flags; + unsigned tmp; + + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + + sec = tegra_rtc_read(RTC_TEGRA_REG_SECONDS_ALARM0); + + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + + if (sec == 0) { + /* alarm is disabled. */ + t->enabled = 0; + t->time.tm_mon = -1; + t->time.tm_mday = -1; + t->time.tm_year = -1; + t->time.tm_hour = -1; + t->time.tm_min = -1; + t->time.tm_sec = -1; + } else { + /* alarm is enabled. */ + t->enabled = 1; + rtc_time_to_tm(sec, &t->time); + } + + tmp = tegra_rtc_read(RTC_TEGRA_REG_INTR_STATUS); + t->pending = (tmp & RTC_TEGRA_INTR_STATUS_SEC_ALARM0) != 0; + + return 0; +} + +static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + unsigned status; + unsigned long sl_irq_flags; + int ret; + + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + if(tegra_rtc_check_busy()) { /* wait for the busy bit to clear. */ + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + ret = tegra_rtc_wait_while_busy(dev); + if (ret) + return ret; + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + } + /* read the original value, and OR in the flag. */ + status = tegra_rtc_read(RTC_TEGRA_REG_INTR_MASK); + if (enabled) + status |= RTC_TEGRA_INTR_MASK_SEC_ALARM0; /* set it */ + else + status &= ~RTC_TEGRA_INTR_MASK_SEC_ALARM0; /* clear it */ + tegra_rtc_write(RTC_TEGRA_REG_INTR_MASK, status); + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + + return 0; +} + +static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + int ret; + unsigned long sec; + + if (t->enabled) + rtc_tm_to_time(&t->time, &sec); + else + sec = 0; + + ret = tegra_rtc_write_not_busy(dev, RTC_TEGRA_REG_SECONDS_ALARM0, sec); + dev_vdbg( + dev, "alarm read back as %d\n", + tegra_rtc_read(RTC_TEGRA_REG_SECONDS_ALARM0) + ); + + /* if successfully written and alarm is enabled ... */ + if (ret == 0 && sec) { + tegra_rtc_alarm_irq_enable(dev, 1); + + dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + t->time.tm_mon+1, + t->time.tm_mday, + t->time.tm_year+1900, + t->time.tm_hour, + t->time.tm_min, + t->time.tm_sec + ); + } else { + /* disable alarm if 0 or write error. */ + dev_vdbg(dev, "alarm disabled\n"); + tegra_rtc_alarm_irq_enable(dev, 0); + } + + return ret; +} + +static int tegra_rtc_ioctl( + struct device *dev, unsigned int cmd, unsigned long arg) +{ + /* use default ioctl handlers for: + * RTC_RD_TIME, RTC_SET_TIME, RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, + * RTC_WKALM_RD, RTC_IRQP_SET, RTC_IRQP_READ, RTC_PIE_ON, RTC_PIE_OFF + */ + return -ENOIOCTLCMD; +} + +/* additional proc lines. */ +static int tegra_rtc_proc(struct device *dev, struct seq_file *seq) +{ + if (!dev || !dev->driver) + return 0; + return seq_printf(seq, "name\t\t: %s\n", dev_name(dev)); +} + +static irqreturn_t tegra_rtc_irq_handler(int irq, void *dev_id) +{ + unsigned long events = 0; + unsigned status; + unsigned long sl_irq_flags; + + status = tegra_rtc_read(RTC_TEGRA_REG_INTR_STATUS); + + if (status) { + /* clear the interrupt masks and status on any irq. */ + spin_lock_irqsave(&tegra_rtc_lock, sl_irq_flags); + tegra_rtc_write(RTC_TEGRA_REG_INTR_MASK, 0); + tegra_rtc_write(RTC_TEGRA_REG_INTR_STATUS, -1); + spin_unlock_irqrestore(&tegra_rtc_lock, sl_irq_flags); + } + + /* check if Alarm */ + if ((status & RTC_TEGRA_INTR_STATUS_SEC_ALARM0)) + events |= RTC_IRQF | RTC_AF; + + /* check if Periodic */ + if ((status & RTC_TEGRA_INTR_STATUS_SEC_CDN_ALARM)) + events |= RTC_IRQF | RTC_PF; + + rtc_update_irq(rtc_dev, 1, events); + return IRQ_HANDLED; +} + +static struct rtc_class_ops tegra_rtc_ops = { + .ioctl = tegra_rtc_ioctl, + .read_time = tegra_rtc_read_time, + .set_time = tegra_rtc_set_time, + .read_alarm = tegra_rtc_read_alarm, + .set_alarm = tegra_rtc_set_alarm, + .proc = tegra_rtc_proc, + .alarm_irq_enable = tegra_rtc_alarm_irq_enable, +}; + +static int __init tegra_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err( + &pdev->dev, "Unable to allocate resources for device.\n" + ); + return -EBUSY; + } + + tegra_rtc_irq = platform_get_irq(pdev, 0); + if (tegra_rtc_irq <= 0) { + tegra_rtc_irq = 0; + return -EBUSY; + } + + rtc_base = ioremap(res->start, res->end - res->start + 1); + if (!rtc_base) { + dev_err(&pdev->dev, "Unable to grab IOs for device.\n"); + return -EBUSY; + } + + /* clear out the hardware. */ + tegra_rtc_write_not_busy(&pdev->dev, RTC_TEGRA_REG_SECONDS_ALARM0, 0); + tegra_rtc_write_not_busy(&pdev->dev, RTC_TEGRA_REG_INTR_STATUS, -1); + tegra_rtc_write_not_busy(&pdev->dev, RTC_TEGRA_REG_INTR_MASK, 0); + + device_init_wakeup(&pdev->dev, 1); + + rtc_dev = rtc_device_register( + pdev->name, &pdev->dev, &tegra_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc_dev)) { + ret = PTR_ERR(rtc_dev); + rtc_dev = NULL; + dev_err(&pdev->dev, "Unable to register device (err=%d).\n", ret); + goto err_iounmap; + } + + ret = request_irq(tegra_rtc_irq, tegra_rtc_irq_handler, + IRQF_DISABLED, "rtc alarm", &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Unable to request interrupt for device (err=%d).\n", ret); + goto err_dev_unreg; + } + + dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); + + return 0; + +err_dev_unreg: + rtc_device_unregister(rtc_dev); + rtc_dev = NULL; +err_iounmap: + iounmap(rtc_base); + rtc_base = NULL; + + return ret; +} + +static int __devexit tegra_rtc_remove(struct platform_device *pdev) +{ + if (rtc_dev) { + rtc_device_unregister(rtc_dev); + rtc_dev = NULL; + } + return 0; +} + +#ifdef CONFIG_PM +static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct device *dev=&pdev->dev; + + /* only use ALARM0 as a wake source. */ + tegra_rtc_write(RTC_TEGRA_REG_INTR_STATUS, -1); + tegra_rtc_write(RTC_TEGRA_REG_INTR_MASK, + RTC_TEGRA_INTR_STATUS_SEC_ALARM0); + dev_vdbg(dev, "alarm sec = %d\n", + tegra_rtc_read(RTC_TEGRA_REG_SECONDS_ALARM0)); + + dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n", + device_may_wakeup(dev), tegra_rtc_irq); + /* leave the alarms on as a wake source. */ + if (device_may_wakeup(dev)) + enable_irq_wake(tegra_rtc_irq); + return 0; +} + +static int tegra_rtc_resume(struct platform_device *pdev) +{ + struct device *dev=&pdev->dev; + unsigned int intr_status; + + /* clear */ + intr_status = tegra_rtc_read(RTC_TEGRA_REG_INTR_STATUS); + if (intr_status & RTC_TEGRA_INTR_STATUS_SEC_ALARM0) { + tegra_rtc_write_not_busy(dev, RTC_TEGRA_REG_INTR_MASK, 0); + tegra_rtc_write_not_busy(dev, RTC_TEGRA_REG_INTR_STATUS, -1); + } + + dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n", device_may_wakeup(dev)); + /* alarms were left on as a wake source, turn them off. */ + if (device_may_wakeup(dev)) + disable_irq_wake(tegra_rtc_irq); + return 0; +} +#endif + +static void tegra_rtc_shutdown(struct platform_device *pdev) +{ + dev_vdbg(&pdev->dev, "disabling interrupts.\n"); + tegra_rtc_alarm_irq_enable(&pdev->dev, 0); +} + +static struct platform_driver tegra_rtc_driver = { + .remove = __devexit_p(tegra_rtc_remove), + .shutdown = tegra_rtc_shutdown, + .driver = { + .name = "tegra_rtc", + .owner = THIS_MODULE, + }, +#ifdef CONFIG_PM + .suspend = tegra_rtc_suspend, + .resume = tegra_rtc_resume, +#endif +}; + +static int __init tegra_rtc_init(void) +{ + return platform_driver_probe(&tegra_rtc_driver, tegra_rtc_probe); +} +module_init(tegra_rtc_init); + +static void __exit tegra_rtc_exit(void) +{ + platform_driver_unregister(&tegra_rtc_driver); +} +module_exit(tegra_rtc_exit); + +MODULE_ALIAS("platform:tegra_rtc"); +MODULE_AUTHOR("NVIDIA Corporation"); +MODULE_DESCRIPTION("driver for Tegra internal RTC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 9ab93cb9de0e..ca6138bbda4b 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -95,7 +95,7 @@ static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm) seconds -= rtc->epoch_start; - ticks = seconds << 10; + ticks = (unsigned long long)seconds << 10; buff[0] = (ticks >> 32) & 0xff; buff[1] = (ticks >> 24) & 0xff; buff[2] = (ticks >> 16) & 0xff; @@ -148,7 +148,7 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } seconds -= rtc->epoch_start; - ticks = (seconds << 10) & 0xffffff; + ticks = (unsigned long long)seconds << 10; buff[0] = (ticks >> 16) & 0xff; buff[1] = (ticks >> 8) & 0xff; diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c index 09f5f454683c..3c8e83b807b9 100644 --- a/drivers/serial/tegra_hsuart.c +++ b/drivers/serial/tegra_hsuart.c @@ -107,7 +107,6 @@ struct tegra_uart_port { /* TX DMA */ struct tegra_dma_req tx_dma_req; struct tegra_dma_channel *tx_dma; - struct work_struct tx_work; /* RX DMA */ struct tegra_dma_req rx_dma_req; @@ -411,34 +410,6 @@ static void do_handle_tx_pio(struct tegra_uart_port *t) return; } -static void tegra_tx_dma_complete_work(struct work_struct *work) -{ - struct tegra_uart_port *t = - container_of(work, struct tegra_uart_port, tx_work); - struct tegra_dma_req *req = &t->tx_dma_req; - unsigned long flags; - int timeout = 20; - - while ((uart_readb(t, UART_LSR) & TX_EMPTY_STATUS) != TX_EMPTY_STATUS) { - timeout--; - if (timeout == 0) { - dev_err(t->uport.dev, - "timed out waiting for TX FIFO to empty\n"); - return; - } - msleep(1); - } - - spin_lock_irqsave(&t->uport.lock, flags); - - t->tx_in_progress = 0; - - if (req->status != -TEGRA_DMA_REQ_ERROR_ABORTED) - tegra_start_next_tx(t); - - spin_unlock_irqrestore(&t->uport.lock, flags); -} - static void tegra_tx_dma_complete_callback(struct tegra_dma_req *req) { struct tegra_uart_port *t = req->dev; @@ -450,11 +421,13 @@ static void tegra_tx_dma_complete_callback(struct tegra_dma_req *req) spin_lock_irqsave(&t->uport.lock, flags); xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + t->tx_in_progress = 0; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&t->uport); - schedule_work(&t->tx_work); + if (req->status != -TEGRA_DMA_REQ_ERROR_ABORTED) + tegra_start_next_tx(t); spin_unlock_irqrestore(&t->uport.lock, flags); } @@ -561,8 +534,6 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t) unsigned char fcr; unsigned long flags; - flush_work(&t->tx_work); - /* Disable interrupts */ uart_writeb(t, 0, UART_IER); @@ -939,13 +910,17 @@ static unsigned int tegra_tx_empty(struct uart_port *u) struct tegra_uart_port *t; unsigned int ret = 0; unsigned long flags; + unsigned char lsr; t = container_of(u, struct tegra_uart_port, uport); dev_vdbg(u->dev, "+tegra_tx_empty\n"); spin_lock_irqsave(&u->lock, flags); - if (!t->tx_in_progress) - ret = TIOCSER_TEMT; + if (!t->tx_in_progress) { + lsr = uart_readb(t, UART_LSR); + if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS) + ret = TIOCSER_TEMT; + } spin_unlock_irqrestore(&u->lock, flags); dev_vdbg(u->dev, "-tegra_tx_empty\n"); @@ -1180,7 +1155,6 @@ static int tegra_uart_suspend(struct platform_device *pdev, pm_message_t state) u = &t->uport; uart_suspend_port(&tegra_uart_driver, u); - flush_work(&t->tx_work); return 0; } @@ -1277,7 +1251,6 @@ static int tegra_uart_probe(struct platform_device *pdev) pr_info("Registered UART port %s%d\n", tegra_uart_driver.dev_name, u->line); - INIT_WORK(&t->tx_work, tegra_tx_dma_complete_work); return ret; fail: kfree(t); diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c index 842ac14f745d..98707dce1fdf 100644 --- a/drivers/spi/spi_tegra.c +++ b/drivers/spi/spi_tegra.c @@ -137,7 +137,14 @@ static const unsigned long spi_tegra_req_sels[] = { TEGRA_DMA_REQ_SEL_SL2B4, }; -#define BB_LEN 32 +#define BB_LEN 2048 +#define TX_FIFO_EMPTY_COUNT_MAX SLINK_TX_FIFO_EMPTY_COUNT(0x20) +#define RX_FIFO_FULL_COUNT_ZERO SLINK_RX_FIFO_FULL_COUNT(0) + +#define SLINK_STATUS2_RESET \ + (TX_FIFO_EMPTY_COUNT_MAX | \ + RX_FIFO_FULL_COUNT_ZERO << 16) + struct spi_tegra_data { struct spi_master *master; @@ -165,8 +172,23 @@ struct spi_tegra_data { struct tegra_dma_channel *rx_dma; u32 *rx_bb; dma_addr_t rx_bb_phys; + struct tegra_dma_req tx_dma_req; + struct tegra_dma_channel *tx_dma; + u32 *tx_bb; + dma_addr_t tx_bb_phys; + bool is_suspended; unsigned long save_slink_cmd; + + u32 rx_complete; + u32 tx_complete; + bool is_packed; + unsigned long packed_size; + unsigned (*spi_tegra_rx)(struct spi_tegra_data *tspi, + struct spi_transfer *t); + unsigned (*spi_tegra_tx)(struct spi_tegra_data *tspi, + struct spi_transfer *t); + u8 g_bits_per_word; }; @@ -183,22 +205,95 @@ static inline void spi_tegra_writel(struct spi_tegra_data *tspi, writel(val, tspi->base + reg); } +static void spi_tegra_clear_status(struct spi_tegra_data *tspi) +{ + unsigned long val; + unsigned long val_write = 0; + + val = spi_tegra_readl(tspi, SLINK_STATUS); + if (val & SLINK_BSY) + val_write |= SLINK_BSY; + + if (val & SLINK_ERR) { + val_write |= SLINK_ERR; + pr_err("%s ERROR bit set 0x%lx \n", __func__, val); + if (val & SLINK_TX_OVF) + val_write |= SLINK_TX_OVF; + if (val & SLINK_RX_OVF) + val_write |= SLINK_RX_OVF; + if (val & SLINK_RX_UNF) + val_write |= SLINK_RX_UNF; + if (val & SLINK_TX_UNF) + val_write |= SLINK_TX_UNF; + if (!(val & SLINK_TX_EMPTY)) + val_write |= SLINK_TX_FLUSH; + if (!(val & SLINK_RX_EMPTY)) + val_write |= SLINK_RX_FLUSH; + } + spi_tegra_writel(tspi, val_write, SLINK_STATUS); +} static void spi_tegra_go(struct spi_tegra_data *tspi) { unsigned long val; + unsigned long test_val; wmb(); val = spi_tegra_readl(tspi, SLINK_DMA_CTL); val &= ~SLINK_DMA_BLOCK_SIZE(~0) & ~SLINK_DMA_EN; - val |= SLINK_DMA_BLOCK_SIZE(tspi->rx_dma_req.size / 4 - 1); + if (tspi->is_packed) { + val |= SLINK_DMA_BLOCK_SIZE(tspi->rx_dma_req.size - 1); + val |= tspi->packed_size; + } else { + val |= SLINK_DMA_BLOCK_SIZE(tspi->rx_dma_req.size / 4 - 1); + } spi_tegra_writel(tspi, val, SLINK_DMA_CTL); - + tegra_dma_enqueue_req(tspi->tx_dma, &tspi->tx_dma_req); tegra_dma_enqueue_req(tspi->rx_dma, &tspi->rx_dma_req); + val &= ~SLINK_TX_TRIG_MASK & ~SLINK_RX_TRIG_MASK; + + if (tspi->rx_dma_req.size & 0xF) + val |= SLINK_TX_TRIG_1 | SLINK_RX_TRIG_1; + else if (((tspi->rx_dma_req.size) >> 4) & 0x1) + val |= SLINK_TX_TRIG_4 | SLINK_RX_TRIG_4; + else + val |= SLINK_TX_TRIG_8 | SLINK_RX_TRIG_8; + + spi_tegra_writel(tspi, val, SLINK_DMA_CTL); + /* + * TRM 24.1.1.7 wait for the FIFO to be full + */ + test_val = spi_tegra_readl(tspi, SLINK_STATUS); + while (!(test_val & SLINK_TX_FULL)) + test_val = spi_tegra_readl(tspi, SLINK_STATUS); + + if (tspi->is_packed) { + val = spi_tegra_readl(tspi, SLINK_DMA_CTL); + val |= SLINK_PACKED; + spi_tegra_writel(tspi, val, SLINK_DMA_CTL); + udelay(1); + } + + val = spi_tegra_readl(tspi, SLINK_DMA_CTL); val |= SLINK_DMA_EN; spi_tegra_writel(tspi, val, SLINK_DMA_CTL); } +static unsigned spi_tegra_fill_tx_fifo_packed(struct spi_tegra_data *tspi, + struct spi_transfer *t) +{ + unsigned len = min(t->len - tspi->cur_pos, BB_LEN * + tspi->cur_bytes_per_word); + unsigned long val; + + val = spi_tegra_readl(tspi, SLINK_COMMAND); + val &= ~SLINK_WORD_SIZE(~0); + val |= SLINK_WORD_SIZE(len / tspi->cur_bytes_per_word - 1); + spi_tegra_writel(tspi, val, SLINK_COMMAND); + memcpy(tspi->tx_bb, t->tx_buf, len); + tspi->tx_dma_req.size = len; + return len; +} static unsigned spi_tegra_fill_tx_fifo(struct spi_tegra_data *tspi, struct spi_transfer *t) @@ -214,16 +309,31 @@ static unsigned spi_tegra_fill_tx_fifo(struct spi_tegra_data *tspi, val |= SLINK_WORD_SIZE(len / tspi->cur_bytes_per_word - 1); spi_tegra_writel(tspi, val, SLINK_COMMAND); - for (i = 0; i < len; i += tspi->cur_bytes_per_word) { - val = 0; - for (j = 0; j < tspi->cur_bytes_per_word; j++) - val |= tx_buf[i + j] << j * 8; + if (tspi->g_bits_per_word == 32) { + memcpy(tspi->tx_bb, (void *)tx_buf, len); + } else { + for (i = 0; i < len; i += tspi->cur_bytes_per_word) { + val = 0; + for (j = 0; j < tspi->cur_bytes_per_word; j++) + val |= tx_buf[i + j] << j * 8; - spi_tegra_writel(tspi, val, SLINK_TX_FIFO); + tspi->tx_bb[i / tspi->cur_bytes_per_word] = val; + } } - tspi->rx_dma_req.size = len / tspi->cur_bytes_per_word * 4; + tspi->tx_dma_req.size = len / tspi->cur_bytes_per_word * 4; + + return len; +} + +static unsigned spi_tegra_drain_rx_fifo_packed(struct spi_tegra_data *tspi, + struct spi_transfer *t) +{ + unsigned len = min(t->len - tspi->cur_pos, BB_LEN * + tspi->cur_bytes_per_word); + memcpy(t->rx_buf, tspi->rx_bb, len); + tspi->rx_dma_req.size = len; return len; } @@ -231,19 +341,46 @@ static unsigned spi_tegra_drain_rx_fifo(struct spi_tegra_data *tspi, struct spi_transfer *t) { unsigned len = tspi->cur_len; - u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_pos; int i, j; + u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_pos; unsigned long val; - for (i = 0; i < len; i += tspi->cur_bytes_per_word) { - val = tspi->rx_bb[i / tspi->cur_bytes_per_word]; - for (j = 0; j < tspi->cur_bytes_per_word; j++) - rx_buf[i + j] = (val >> (j * 8)) & 0xff; + if (tspi->g_bits_per_word == 32) { + memcpy(rx_buf, (void *)tspi->rx_bb, len); + } else { + for (i = 0; i < len; i += tspi->cur_bytes_per_word) { + val = tspi->rx_bb[i / tspi->cur_bytes_per_word]; + for (j = 0; j < tspi->cur_bytes_per_word; j++) + rx_buf[i + j] = (val >> (j * 8)) & 0xff; + } } return len; } +static unsigned long spi_tegra_get_packed_size(struct spi_tegra_data *tspi, + struct spi_transfer *t) +{ + unsigned long val; + + switch (tspi->cur_bytes_per_word) { + case 0: + val = SLINK_PACK_SIZE_4; + break; + case 1: + val = SLINK_PACK_SIZE_8; + break; + case 2: + val = SLINK_PACK_SIZE_16; + break; + case 4: + val = SLINK_PACK_SIZE_32; + break; + default: + val = 0; + } + return val; +} static void spi_tegra_start_transfer(struct spi_device *spi, struct spi_transfer *t) { @@ -256,8 +393,24 @@ static void spi_tegra_start_transfer(struct spi_device *spi, bits_per_word = t->bits_per_word ? t->bits_per_word : spi->bits_per_word; + tspi->g_bits_per_word = bits_per_word; + tspi->cur_bytes_per_word = (bits_per_word - 1) / 8 + 1; + if (bits_per_word == 8 || bits_per_word == 16) + tspi->is_packed = 1; + else + tspi->is_packed = 0; + + tspi->packed_size = spi_tegra_get_packed_size(tspi, t); + if (tspi->is_packed) { + tspi->spi_tegra_tx = spi_tegra_fill_tx_fifo_packed; + tspi->spi_tegra_rx = spi_tegra_drain_rx_fifo_packed; + } else { + tspi->spi_tegra_tx = spi_tegra_fill_tx_fifo; + tspi->spi_tegra_rx = spi_tegra_drain_rx_fifo; + } + if (speed != tspi->cur_speed) clk_set_rate(tspi->clk, speed); @@ -266,6 +419,7 @@ static void spi_tegra_start_transfer(struct spi_device *spi, tspi->cur_speed = speed; + spi_tegra_clear_status(tspi); val = spi_tegra_readl(tspi, SLINK_COMMAND2); val &= ~SLINK_SS_EN_CS(~0) | SLINK_RXEN | SLINK_TXEN; if (t->rx_buf) @@ -274,7 +428,8 @@ static void spi_tegra_start_transfer(struct spi_device *spi, val |= SLINK_TXEN; val |= SLINK_SS_EN_CS(spi->chip_select); val |= SLINK_SPIE; - val |= SLINK_SS_SETUP(3); + if (tspi->is_packed) + val |= SLINK_CS_ACTIVE_BETWEEN; spi_tegra_writel(tspi, val, SLINK_COMMAND2); val = spi_tegra_readl(tspi, SLINK_COMMAND); @@ -303,8 +458,10 @@ static void spi_tegra_start_transfer(struct spi_device *spi, tspi->cur = t; tspi->cur_pos = 0; - tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, t); - + tspi->cur_len = tspi->spi_tegra_tx(tspi, t); + tspi->rx_dma_req.size = tspi->tx_dma_req.size; + tspi->rx_complete = 0; + tspi->tx_complete = 0; spi_tegra_go(tspi); } @@ -319,27 +476,31 @@ static void spi_tegra_start_message(struct spi_device *spi, t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); spi_tegra_start_transfer(spi, t); } - -static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req) +static void complete_operation(struct tegra_dma_req *req) { struct spi_tegra_data *tspi = req->dev; - unsigned long flags; + unsigned long val; struct spi_message *m; struct spi_device *spi; - int timeout = 0; - unsigned long val; + u32 timeout = 0; + u32 temp = 0; /* the SPI controller may come back with both the BSY and RDY bits - * set. In this case we need to wait for the BSY bit to clear so - * that we are sure the DMA is finished. 1000 reads was empirically - * determined to be long enough. - */ - while (timeout++ < 1000) { - if (!(spi_tegra_readl(tspi, SLINK_STATUS) & SLINK_BSY)) + * set. In this case we need to wait for the BSY bit to clear so + * that we are sure the DMA is finished. 1000 reads was empirically + * determined to be long enough. + */ + + while ((spi_tegra_readl(tspi, SLINK_STATUS) & SLINK_BSY)) { + if (timeout++ > 1000) + break; + } + while ((spi_tegra_readl(tspi, SLINK_STATUS2)) != SLINK_STATUS2_RESET) { + if (temp++ > 50000) break; } - spin_lock_irqsave(&tspi->lock, flags); + spi_tegra_clear_status(tspi); val = spi_tegra_readl(tspi, SLINK_STATUS); val |= SLINK_RDY; @@ -347,22 +508,17 @@ static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req) m = list_first_entry(&tspi->queue, struct spi_message, queue); - if (timeout >= 1000) + if ((timeout >= 1000) || (temp >= 50000)) m->status = -EIO; spi = m->state; - tspi->cur_pos += spi_tegra_drain_rx_fifo(tspi, tspi->cur); + tspi->cur_pos += tspi->spi_tegra_rx(tspi, tspi->cur); m->actual_length += tspi->cur_pos; - if (tspi->cur_pos < tspi->cur->len) { - tspi->cur_len = spi_tegra_fill_tx_fifo(tspi, tspi->cur); - spi_tegra_go(tspi); - } else if (!list_is_last(&tspi->cur->transfer_list, - &m->transfers)) { - tspi->cur = list_first_entry(&tspi->cur->transfer_list, - struct spi_transfer, - transfer_list); + if (!list_is_last(&tspi->cur->transfer_list, &m->transfers)) { + tspi->cur = list_first_entry(&tspi->cur->transfer_list, + struct spi_transfer, transfer_list); spi_tegra_start_transfer(spi, tspi->cur); } else { list_del(&m->queue); @@ -371,7 +527,7 @@ static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req) if (!list_empty(&tspi->queue)) { m = list_first_entry(&tspi->queue, struct spi_message, - queue); + queue); spi = m->state; spi_tegra_start_message(spi, m); } else { @@ -379,6 +535,35 @@ static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req) tspi->cur_speed = 0; } } +} +static void tegra_spi_tx_dma_complete(struct tegra_dma_req *req) +{ + struct spi_tegra_data *tspi = req->dev; + unsigned long flags; + + spin_lock_irqsave(&tspi->lock, flags); + + (tspi->tx_complete)++; + + if (((tspi->rx_complete) == 1) && ((tspi->tx_complete) == 1)) + complete_operation(req); + + spin_unlock_irqrestore(&tspi->lock, flags); + +} + +static void tegra_spi_rx_dma_complete(struct tegra_dma_req *req) +{ + struct spi_tegra_data *tspi = req->dev; + unsigned long flags; + + + spin_lock_irqsave(&tspi->lock, flags); + + (tspi->rx_complete)++; + + if (((tspi->rx_complete) == 1) && ((tspi->tx_complete) == 1)) + complete_operation(req); spin_unlock_irqrestore(&tspi->lock, flags); } @@ -489,7 +674,8 @@ static int __init spi_tegra_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - master->bus_num = pdev->id; + if (pdev->id != -1) + master->bus_num = pdev->id; master->setup = spi_tegra_setup; master->transfer = spi_tegra_transfer; @@ -530,8 +716,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev) INIT_LIST_HEAD(&tspi->queue); - tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT | - TEGRA_DMA_SHARED); + tspi->rx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); if (!tspi->rx_dma) { dev_err(&pdev->dev, "can not allocate rx dma channel\n"); ret = -ENODEV; @@ -546,23 +731,58 @@ static int __init spi_tegra_probe(struct platform_device *pdev) goto err4; } + memset(&tspi->rx_dma_req, 0, sizeof(struct tegra_dma_req)); tspi->rx_dma_req.complete = tegra_spi_rx_dma_complete; tspi->rx_dma_req.to_memory = 1; tspi->rx_dma_req.dest_addr = tspi->rx_bb_phys; + tspi->rx_dma_req.virt_addr = tspi->rx_bb; tspi->rx_dma_req.dest_bus_width = 32; tspi->rx_dma_req.source_addr = tspi->phys + SLINK_RX_FIFO; tspi->rx_dma_req.source_bus_width = 32; tspi->rx_dma_req.source_wrap = 4; + tspi->rx_dma_req.dest_wrap = 0; tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id]; tspi->rx_dma_req.dev = tspi; + tspi->tx_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); + if (IS_ERR(tspi->tx_dma)) { + dev_err(&pdev->dev, "can not allocate tx dma channel\n"); + ret = PTR_ERR(tspi->tx_dma); + goto err5; + } + + tspi->tx_bb = dma_alloc_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + &tspi->tx_bb_phys, GFP_KERNEL); + if (!tspi->tx_bb) { + dev_err(&pdev->dev, "can not allocate tx bounce buffer\n"); + ret = -ENOMEM; + goto err6; + } + + memset(&tspi->tx_dma_req, 0, sizeof(struct tegra_dma_req)); + tspi->tx_dma_req.complete = tegra_spi_tx_dma_complete; + tspi->tx_dma_req.to_memory = 0; + tspi->tx_dma_req.dest_addr = tspi->phys + SLINK_TX_FIFO; + tspi->tx_dma_req.virt_addr = tspi->tx_bb; + tspi->tx_dma_req.dest_bus_width = 32; + tspi->tx_dma_req.dest_wrap = 4; + tspi->tx_dma_req.source_wrap = 0; + tspi->tx_dma_req.source_addr = tspi->tx_bb_phys; + tspi->tx_dma_req.source_bus_width = 32; + tspi->tx_dma_req.req_sel = spi_tegra_req_sels[pdev->id]; + tspi->tx_dma_req.dev = tspi; ret = spi_register_master(master); if (ret < 0) - goto err5; + goto err7; return ret; +err7: + dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN, + tspi->tx_bb, tspi->tx_bb_phys); +err6: + tegra_dma_free_channel(tspi->tx_dma); err5: dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN, tspi->rx_bb, tspi->rx_bb_phys); @@ -609,7 +829,7 @@ static int spi_tegra_suspend(struct platform_device *pdev, pm_message_t state) struct spi_master *master; struct spi_tegra_data *tspi; unsigned long flags; - unsigned limit = 500; + unsigned limit = 50; master = dev_get_drvdata(&pdev->dev); tspi = spi_master_get_devdata(master); diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 3ddc478e6182..0d601440c6f0 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -9,6 +9,17 @@ config SENSORS_TSL2563 help If you say yes here you get support for the Taos TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors. - This driver can also be built as a module. If so, the module will be called tsl2563. + +config ISL29018 + tristate "ISL 29018 light and proximity sensor" + depends on I2C + default n + help + If you say yes here you get support for ambient light sensing and + proximity ir sensing from intersil ISL29018. + This driver will provide the measurements of ambient light intensity + in lux, proximity infrared sensing and normal infrared sensing. + Data from sensor is accessible via sysfs. + diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 30f3300e2a68..3978722c7a29 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,4 +2,5 @@ # Makefile for industrial I/O Light sensors # -obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_ISL29018) += isl29018.o diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c new file mode 100644 index 000000000000..defaf28a02d5 --- /dev/null +++ b/drivers/staging/iio/light/isl29018.c @@ -0,0 +1,543 @@ +/* + * A iio driver for the light sensor ISL 29018. + * + * Hwmon driver for monitoring ambient light intensity in luxi, proximity + * sensing and infrared sensing. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include "../iio.h" + +#define CONVERSION_TIME_MS 100 + +#define ISL29018_REG_ADD_COMMAND1 0x00 +#define COMMMAND1_OPMODE_SHIFT 5 +#define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT) +#define COMMMAND1_OPMODE_POWER_DOWN 0 +#define COMMMAND1_OPMODE_ALS_ONCE 1 +#define COMMMAND1_OPMODE_IR_ONCE 2 +#define COMMMAND1_OPMODE_PROX_ONCE 3 + +#define ISL29018_REG_ADD_COMMANDII 0x01 +#define COMMANDII_RESOLUTION_SHIFT 2 +#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT) + +#define COMMANDII_RANGE_SHIFT 0 +#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT) + +#define COMMANDII_SCHEME_SHIFT 7 +#define COMMANDII_SCHEME_MASK (0x1 << COMMANDII_SCHEME_SHIFT) + +#define ISL29018_REG_ADD_DATA_LSB 0x02 +#define ISL29018_REG_ADD_DATA_MSB 0x03 +#define ISL29018_MAX_REGS ISL29018_REG_ADD_DATA_MSB + +struct isl29018_chip { + struct iio_dev *indio_dev; + struct i2c_client *client; + struct mutex lock; + unsigned int range; + unsigned int adc_bit; + int prox_scheme; + u8 reg_cache[ISL29018_MAX_REGS]; +}; + +static bool isl29018_write_data(struct i2c_client *client, u8 reg, + u8 val, u8 mask, u8 shift) +{ + u8 regval; + int ret = 0; + struct isl29018_chip *chip = i2c_get_clientdata(client); + + regval = chip->reg_cache[reg]; + regval &= ~mask; + regval |= val << shift; + + ret = i2c_smbus_write_byte_data(client, reg, regval); + if (ret) { + dev_err(&client->dev, "Write to device fails status %x\n", ret); + return false; + } + chip->reg_cache[reg] = regval; + return true; +} + +static bool isl29018_set_range(struct i2c_client *client, unsigned long range, + unsigned int *new_range) +{ + unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; + int i; + + for (i = 0; i < (ARRAY_SIZE(supp_ranges) -1); ++i) { + if (range <= supp_ranges[i]) + break; + } + *new_range = (unsigned int)supp_ranges[i]; + + return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, + i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); +} + +static bool isl29018_set_resolution(struct i2c_client *client, + unsigned long adcbit, unsigned int *conf_adc_bit) +{ + unsigned long supp_adcbit[] = {16, 12, 8, 4}; + int i; + + for (i = 0; i < (ARRAY_SIZE(supp_adcbit)); ++i) { + if (adcbit == supp_adcbit[i]) + break; + } + *conf_adc_bit = (unsigned int)supp_adcbit[i]; + + return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, + i, COMMANDII_RESOLUTION_MASK, COMMANDII_RESOLUTION_SHIFT); +} + +static int isl29018_read_sensor_input(struct i2c_client *client, int mode) +{ + bool status; + int lsb; + int msb; + + /* Set mode */ + status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, + mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); + if (!status) { + dev_err(&client->dev, "Error in setting operating mode\n"); + return -EBUSY; + } + + msleep(CONVERSION_TIME_MS); + lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); + if (lsb < 0) { + dev_err(&client->dev, "Error in reading LSB DATA\n"); + return lsb; + } + + msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); + if (msb < 0) { + dev_err(&client->dev, "Error in reading MSB DATA\n"); + return msb; + } + + dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); + + return ((msb << 8) | lsb); +} + +static bool isl29018_read_lux(struct i2c_client *client, int *lux) +{ + int lux_data; + struct isl29018_chip *chip = i2c_get_clientdata(client); + + lux_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_ALS_ONCE); + if (lux_data > 0) { + *lux = (lux_data * chip->range) >> chip->adc_bit; + return true; + } + return false; +} + +static bool isl29018_read_ir(struct i2c_client *client, int *ir) +{ + int ir_data; + + ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE); + if (ir_data > 0) { + *ir = ir_data; + return true; + } + return false; +} + +static bool isl29018_read_proximity_ir(struct i2c_client *client, int scheme, + int *near_ir) +{ + bool status; + int prox_data = -1; + int ir_data = -1; + + /* Do proximity sensing with required scheme */ + status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, + scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT); + if (!status) { + dev_err(&client->dev, "Error in setting operating mode\n"); + return false; + } + + prox_data = isl29018_read_sensor_input(client, + COMMMAND1_OPMODE_PROX_ONCE); + if (scheme == 1) { + if (prox_data >= 0) { + *near_ir = prox_data; + return true; + } + return false; + } + + if (prox_data >= 0) + ir_data = isl29018_read_sensor_input(client, + COMMMAND1_OPMODE_IR_ONCE); + + if (prox_data >= 0 && ir_data >= 0) { + if (prox_data >= ir_data) { + *near_ir = prox_data - ir_data; + return true; + } + } + + return false; +} + +static ssize_t get_sensor_data(struct device *dev, char *buf, int mode) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + struct i2c_client *client = chip->client; + int value = 0; + bool status; + + mutex_lock(&chip->lock); + switch (mode) { + case COMMMAND1_OPMODE_PROX_ONCE: + status = isl29018_read_proximity_ir(client, + chip->prox_scheme, &value); + break; + + case COMMMAND1_OPMODE_ALS_ONCE: + status = isl29018_read_lux(client, &value); + break; + + case COMMMAND1_OPMODE_IR_ONCE: + status = isl29018_read_ir(client, &value); + break; + + default: + dev_err(&client->dev,"Mode %d is not supported\n",mode); + mutex_unlock(&chip->lock); + return -EBUSY; + } + + if (!status) { + dev_err(&client->dev, "Error in Reading data"); + mutex_unlock(&chip->lock); + return -EBUSY; + } + + mutex_unlock(&chip->lock); + return sprintf(buf, "%d\n", value); +} + +/* Sysfs interface */ +/* range */ +static ssize_t show_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + dev_vdbg(dev, "%s()\n", __func__); + return sprintf(buf, "%u\n", chip->range); +} + +static ssize_t store_range(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + struct i2c_client *client = chip->client; + bool status; + unsigned long lval; + unsigned int new_range; + + dev_vdbg(dev, "%s()\n", __func__); + + if (strict_strtoul(buf, 10, &lval)) + return -EINVAL; + + if (!(lval == 1000UL || lval == 4000UL || + lval == 16000UL || lval == 64000UL)) { + dev_err(dev, "The range is not supported\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + status = isl29018_set_range(client, lval, &new_range); + if (!status) { + mutex_unlock(&chip->lock); + dev_err(dev, "Error in setting max range\n"); + return -EINVAL; + } + chip->range = new_range; + mutex_unlock(&chip->lock); + return count; +} + +/* resolution */ +static ssize_t show_resolution(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + dev_vdbg(dev, "%s()\n", __func__); + return sprintf(buf, "%u\n", chip->adc_bit); +} + +static ssize_t store_resolution(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + struct i2c_client *client = chip->client; + bool status; + unsigned long lval; + unsigned int new_adc_bit; + + dev_vdbg(dev, "%s()\n", __func__); + + if (strict_strtoul(buf, 10, &lval)) + return -EINVAL; + if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) { + dev_err(dev, "The resolution is not supported\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + status = isl29018_set_resolution(client, lval, &new_adc_bit); + if (!status) { + mutex_unlock(&chip->lock); + dev_err(dev, "Error in setting resolution\n"); + return -EINVAL; + } + chip->adc_bit = new_adc_bit; + mutex_unlock(&chip->lock); + return count; +} + +/* proximity scheme */ +static ssize_t show_prox_scheme(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + + dev_vdbg(dev, "%s()\n", __func__); + return sprintf(buf, "%d\n", chip->prox_scheme); +} + +static ssize_t store_prox_scheme(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + unsigned long lval; + + dev_vdbg(dev, "%s()\n", __func__); + + if (strict_strtoul(buf, 10, &lval)) + return -EINVAL; + if (!(lval == 0UL || lval == 1UL)) { + dev_err(dev, "The scheme is not supported\n"); + return -EINVAL; + } + + mutex_lock(&chip->lock); + chip->prox_scheme = (int)lval; + mutex_unlock(&chip->lock); + return count; +} + +/* Read lux */ +static ssize_t show_lux(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return get_sensor_data(dev, buf, COMMMAND1_OPMODE_ALS_ONCE); +} + +/* Read ir */ +static ssize_t show_ir(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return get_sensor_data(dev, buf, COMMMAND1_OPMODE_IR_ONCE); +} + +/* Read nearest ir */ +static ssize_t show_proxim_ir(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return get_sensor_data(dev, buf, COMMMAND1_OPMODE_PROX_ONCE); +} + +/* Read name */ +static ssize_t show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct isl29018_chip *chip = indio_dev->dev_data; + return sprintf(buf, "%s\n", chip->client->name); +} + +static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0); +static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR, + show_resolution, store_resolution, 0); +static IIO_DEVICE_ATTR(proximity_scheme, S_IRUGO | S_IWUSR, + show_prox_scheme, store_prox_scheme, 0); +static IIO_DEVICE_ATTR(lux, S_IRUGO, show_lux, NULL, 0); +static IIO_DEVICE_ATTR(ir, S_IRUGO, show_ir, NULL, 0); +static IIO_DEVICE_ATTR(proxim_ir, S_IRUGO, show_proxim_ir, NULL, 0); +static IIO_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +static struct attribute *isl29018_attributes[] = { + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_range.dev_attr.attr, + &iio_dev_attr_resolution.dev_attr.attr, + &iio_dev_attr_proximity_scheme.dev_attr.attr, + &iio_dev_attr_lux.dev_attr.attr, + &iio_dev_attr_ir.dev_attr.attr, + &iio_dev_attr_proxim_ir.dev_attr.attr, + NULL +}; + +static const struct attribute_group isl29108_group = { + .attrs = isl29018_attributes, +}; + +static int isl29018_chip_init(struct i2c_client *client) +{ + struct isl29018_chip *chip = i2c_get_clientdata(client); + bool status; + int i; + int new_adc_bit; + unsigned int new_range; + + for (i = 0; i < ARRAY_SIZE(chip->reg_cache); i++) { + chip->reg_cache[i] = 0; + } + + /* set defaults */ + status = isl29018_set_range(client, chip->range, &new_range); + if (status) + status = isl29018_set_resolution(client, chip->adc_bit, + &new_adc_bit); + if (!status) { + dev_err(&client->dev, "Init of isl29018 fails\n"); + return -ENODEV; + } + return 0; +} + +static int __devinit isl29018_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct isl29018_chip *chip; + int err; + + chip = kzalloc(sizeof (struct isl29018_chip), GFP_KERNEL); + if (!chip) { + dev_err(&client->dev, "Memory allocation fails\n"); + err = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, chip); + chip->client = client; + + mutex_init(&chip->lock); + + chip->range = 1000; + chip->adc_bit = 16; + + err = isl29018_chip_init(client); + if (err) + goto exit_free; + + chip->indio_dev = iio_allocate_device(); + if (!chip->indio_dev) { + dev_err(&client->dev, "iio allocation fails\n"); + goto exit_free; + } + + chip->indio_dev->attrs = &isl29108_group; + chip->indio_dev->dev.parent = &client->dev; + chip->indio_dev->dev_data = (void *)(chip); + chip->indio_dev->driver_module = THIS_MODULE; + chip->indio_dev->modes = INDIO_DIRECT_MODE; + err = iio_device_register(chip->indio_dev); + if (err) { + dev_err(&client->dev, "iio registration fails\n"); + goto exit_iio_free; + } + + return 0; + +exit_iio_free: + iio_free_device(chip->indio_dev); +exit_free: + kfree(chip); +exit: + return err; +} + +static int __devexit isl29018_remove(struct i2c_client *client) +{ + struct isl29018_chip *chip = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s()\n", __func__); + iio_device_unregister(chip->indio_dev); + kfree(chip); + return 0; +} + +static const struct i2c_device_id isl29018_id[] = { + {"isl29018", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, isl29018_id); + +static struct i2c_driver isl29018_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "isl29018", + .owner = THIS_MODULE, + }, + .probe = isl29018_probe, + .remove = __devexit_p(isl29018_remove), + .id_table = isl29018_id, +}; + +static int __init isl29018_init(void) +{ + return i2c_add_driver(&isl29018_driver); +} + +static void __exit isl29018_exit(void) +{ + i2c_del_driver(&isl29018_driver); +} + +module_init(isl29018_init); +module_exit(isl29018_exit); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 5cca00a6d09d..84fee0f5dc34 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1265,6 +1265,14 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle, static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { + if (hcd->driver->unmap_urb_for_dma) + hcd->driver->unmap_urb_for_dma(hcd, urb); + else + usb_hcd_unmap_urb_for_dma(hcd, urb); +} + +void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ enum dma_data_direction dir; if (urb->transfer_flags & URB_SETUP_MAP_SINGLE) @@ -1311,6 +1319,15 @@ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { + if (hcd->driver->map_urb_for_dma) + return hcd->driver->map_urb_for_dma(hcd, urb, mem_flags); + else + return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); +} + +int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ enum dma_data_direction dir; int ret = 0; @@ -1400,7 +1417,7 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, } if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL))) - unmap_urb_for_dma(hcd, urb); + usb_hcd_unmap_urb_for_dma(hcd, urb); } return ret; } diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index a0b0774b9556..b9884d408a2a 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -154,12 +154,16 @@ static void adb_request_free(struct usb_request *req, struct usb_ep *ep) static inline int _lock(atomic_t *excl) { + int ret = -1; + + preempt_disable(); if (atomic_inc_return(excl) == 1) { - return 0; - } else { + ret = 0; + } else atomic_dec(excl); - return -1; - } + + preempt_enable(); + return ret; } static inline void _unlock(atomic_t *excl) @@ -409,9 +413,25 @@ static ssize_t adb_write(struct file *fp, const char __user *buf, static int adb_open(struct inode *ip, struct file *fp) { - printk(KERN_INFO "adb_open\n"); - if (_lock(&_adb_dev->open_excl)) + static unsigned long last_print; + static unsigned long count = 0; + + if (++count == 1) + last_print = jiffies; + else { + if (!time_before(jiffies, last_print + HZ/2)) + count = 0; + last_print = jiffies; + } + + if (_lock(&_adb_dev->open_excl)) { + cpu_relax(); return -EBUSY; + } + + if (count < 5) + printk(KERN_INFO "adb_open(%s)\n", current->comm); + fp->private_data = _adb_dev; @@ -423,7 +443,19 @@ static int adb_open(struct inode *ip, struct file *fp) static int adb_release(struct inode *ip, struct file *fp) { - printk(KERN_INFO "adb_release\n"); + static unsigned long last_print; + static unsigned long count = 0; + + if (++count == 1) + last_print = jiffies; + else { + if (!time_before(jiffies, last_print + HZ/2)) + count = 0; + last_print = jiffies; + } + + if (count < 5) + printk(KERN_INFO "adb_release\n"); _unlock(&_adb_dev->open_excl); return 0; } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 2fab37a2a094..6d522e0d529b 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -367,6 +367,10 @@ static void dr_controller_stop(struct fsl_udc *udc) { unsigned int tmp; + /* Clear pending interrupt status bits */ + tmp = fsl_readl(&dr_regs->usbsts); + fsl_writel(tmp, &dr_regs->usbsts); + /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); @@ -955,12 +959,18 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* Stop the ep before we deal with the queue */ ep->stopped = 1; ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + +#if defined(CONFIG_ARCH_TEGRA) + /* Touch the registers if cable is connected and phy is on */ +#endif + { + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + } /* make sure it's actually queued on this endpoint */ list_for_each_entry(req, &ep->queue, queue) { @@ -1003,12 +1013,19 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) done(ep, req, -ECONNRESET); /* Enable EP */ -out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl |= EPCTRL_TX_ENABLE; - else - epctrl |= EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); +out: +#if defined(CONFIG_ARCH_TEGRA) + /* Touch the registers if cable is connected and phy is on */ + if (fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS) +#endif + { + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl |= EPCTRL_TX_ENABLE; + else + epctrl |= EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + } ep->stopped = stopped; spin_unlock_irqrestore(&ep->udc->lock, flags); @@ -1138,6 +1155,7 @@ static int fsl_get_frame(struct usb_gadget *gadget) /*----------------------------------------------------------------------- * Tries to wake up the host connected to this gadget -----------------------------------------------------------------------*/ +#ifndef CONFIG_USB_ANDROID static int fsl_wakeup(struct usb_gadget *gadget) { struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget); @@ -1156,6 +1174,7 @@ static int fsl_wakeup(struct usb_gadget *gadget) fsl_writel(portsc, &dr_regs->portsc1); return 0; } +#endif static int can_pullup(struct fsl_udc *udc) { @@ -1253,7 +1272,9 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) /* defined in gadget.h */ static struct usb_gadget_ops fsl_gadget_ops = { .get_frame = fsl_get_frame, +#ifndef CONFIG_USB_ANDROID .wakeup = fsl_wakeup, +#endif /* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */ .vbus_session = fsl_vbus_session, .vbus_draw = fsl_vbus_draw, @@ -1581,7 +1602,7 @@ static void setup_received_irq(struct fsl_udc *udc, udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT; spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, + if (udc->driver && udc->driver->setup(&udc->gadget, &udc->local_setup_buff) < 0) ep0stall(udc); spin_lock(&udc->lock); @@ -1591,7 +1612,7 @@ static void setup_received_irq(struct fsl_udc *udc, /* No data phase, IN status from gadget */ udc->ep0_dir = USB_DIR_IN; spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, + if (udc->driver && udc->driver->setup(&udc->gadget, &udc->local_setup_buff) < 0) ep0stall(udc); spin_lock(&udc->lock); @@ -1837,7 +1858,7 @@ static void suspend_irq(struct fsl_udc *udc) udc->usb_state = USB_STATE_SUSPENDED; /* report suspend to the driver, serial.c does not support this */ - if (udc->driver->suspend) + if (udc->driver && udc->driver->suspend) udc->driver->suspend(&udc->gadget); } @@ -1847,7 +1868,7 @@ static void bus_resume(struct fsl_udc *udc) udc->resume_state = 0; /* report resume to the driver, serial.c does not support this */ - if (udc->driver->resume) + if (udc->driver && udc->driver->resume) udc->driver->resume(&udc->gadget); } @@ -1861,7 +1882,8 @@ static int reset_queues(struct fsl_udc *udc) /* report disconnect; the driver is already quiesced */ spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); + if (udc->driver && udc->driver->disconnect) + udc->driver->disconnect(&udc->gadget); spin_lock(&udc->lock); return 0; @@ -1942,6 +1964,25 @@ static void reset_irq(struct fsl_udc *udc) #endif } +#if defined(CONFIG_ARCH_TEGRA) +/* + * Restart device controller in the OTG mode on VBUS detection + */ +static void fsl_udc_restart(struct fsl_udc *udc) +{ + /* setup the controller in the device mode */ + dr_controller_setup(udc); + /* setup EP0 for setup packet */ + ep0_setup(udc); + /* start the controller */ + dr_controller_run(udc); + /* initialize the USB and EP states */ + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; +} +#endif + /* * USB device controller interrupt handler */ @@ -2756,12 +2797,27 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) -----------------------------------------------------------------*/ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) { - if (udc_controller->transceiver && - udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) - return 0; - - dr_controller_stop(udc_controller); - return 0; + if (udc_controller->transceiver) { + if (udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) { + /* we are not in device mode, return */ + return 0; + } + } + if (udc_controller->vbus_active) { + spin_lock(&udc_controller->lock); + /* Reset all internal Queues and inform client driver */ + reset_queues(udc_controller); + udc_controller->vbus_active = 0; + udc_controller->usb_state = USB_STATE_DEFAULT; + spin_unlock(&udc_controller->lock); + } + /* stop the controller and turn off the clocks */ + dr_controller_stop(udc_controller); + if (udc_controller->transceiver) { + udc_controller->transceiver->state = OTG_STATE_UNDEFINED; + } + fsl_udc_clk_suspend(); + return 0; } /*----------------------------------------------------------------- @@ -2770,19 +2826,43 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) *-----------------------------------------------------------------*/ static int fsl_udc_resume(struct platform_device *pdev) { - if (udc_controller->transceiver && - udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) - return 0; + if (udc_controller->transceiver) { + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_ID_PIN_STATUS)) { + /* If ID status is low means host is connected, return */ + return 0; + } + /* enable clock and check for VBUS */ + fsl_udc_clk_resume(); + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) { + /* if there is no VBUS then power down the clocks and return */ + fsl_udc_clk_suspend(); + return 0; + } else { + /* Detected VBUS set the transceiver state to device mode */ + udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL; + } + } else { + /* enable the clocks to the controller */ + fsl_udc_clk_resume(); + } - /* Enable DR irq reg and set controller Run */ - if (udc_controller->stopped) { - dr_controller_setup(udc_controller); - dr_controller_run(udc_controller); - } - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - return 0; +#if defined(CONFIG_ARCH_TEGRA) + fsl_udc_restart(udc_controller); +#else + /* Enable DR irq reg and set controller Run */ + if (udc_controller->stopped) { + dr_controller_setup(udc_controller); + dr_controller_run(udc_controller); + } + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; +#endif + /* Power down the phy if cable is not connected */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) + fsl_udc_clk_suspend(); + + return 0; } /*------------------------------------------------------------------------- diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 8d5bd2fe7475..99c36054e66c 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -442,7 +442,7 @@ struct ep_td_struct { #define USB_SYS_VBUS_WAKEUP_INT_ENABLE 0x100 #define USB_SYS_VBUS_WAKEUP_INT_STATUS 0x200 #define USB_SYS_VBUS_STATUS 0x400 - +#define USB_SYS_ID_PIN_STATUS (0x4) /*-------------------------------------------------------------------------*/ /* ### driver private data diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index d990c1cd9181..80dad8716575 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -32,6 +32,10 @@ #define TEGRA_USB_USBMODE_HOST (3 << 0) #define TEGRA_USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) +#define TEGRA_USB_DMA_ALIGN 32 + +#define URB_ALIGNED_TEMP_BUFFER 0x80000000 + struct tegra_ehci_context { bool valid; u32 command; @@ -383,6 +387,9 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd) /* call ehci shut down */ ehci_shutdown(hcd); + + /* we are ready to shut down, powerdown the phy */ + tegra_ehci_power_down(hcd); } static int tegra_ehci_setup(struct usb_hcd *hcd) @@ -457,6 +464,94 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd) } #endif +struct temp_buffer { + void *kmalloc_ptr; + void *old_xfer_buffer; + u8 data[0]; +}; + +static void free_temp_buffer(struct urb *urb) +{ + enum dma_data_direction dir; + struct temp_buffer *temp; + + if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) + return; + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + temp = container_of(urb->transfer_buffer, struct temp_buffer, + data); + + if (dir == DMA_FROM_DEVICE) + memcpy(temp->old_xfer_buffer, temp->data, + urb->transfer_buffer_length); + urb->transfer_buffer = temp->old_xfer_buffer; + kfree(temp->kmalloc_ptr); + + urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; +} + +static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) +{ + enum dma_data_direction dir; + struct temp_buffer *temp, *kmalloc_ptr; + size_t kmalloc_size; + void *data; + + if (urb->num_sgs || urb->sg || + urb->transfer_buffer_length == 0 || + !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) + return 0; + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + /* Allocate a buffer with enough padding for alignment */ + kmalloc_size = urb->transfer_buffer_length + + sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1; + + kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); + if (!kmalloc_ptr) + return -ENOMEM; + + /* Position our struct temp_buffer such that data is aligned */ + temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; + + temp->kmalloc_ptr = kmalloc_ptr; + temp->old_xfer_buffer = urb->transfer_buffer; + if (dir == DMA_TO_DEVICE) + memcpy(temp->data, urb->transfer_buffer, + urb->transfer_buffer_length); + urb->transfer_buffer = temp->data; + + BUILD_BUG_ON(!(URB_ALIGNED_TEMP_BUFFER & URB_DRIVER_PRIVATE)); + urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; + + return 0; +} + +static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + int ret; + + ret = alloc_temp_buffer(urb, mem_flags); + if (ret) + return ret; + + ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + if (ret) + free_temp_buffer(urb); + + return ret; +} + +static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + usb_hcd_unmap_urb_for_dma(hcd, urb); + free_temp_buffer(urb); +} + static const struct hc_driver tegra_ehci_hc_driver = { .description = hcd_name, .product_desc = "Tegra EHCI Host Controller", @@ -472,6 +567,8 @@ static const struct hc_driver tegra_ehci_hc_driver = { .shutdown = tegra_ehci_shutdown, .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, + .map_urb_for_dma = tegra_ehci_map_urb_for_dma, + .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, .endpoint_disable = ehci_endpoint_disable, .endpoint_reset = ehci_endpoint_reset, .get_frame_number = ehci_get_frame, @@ -655,9 +752,12 @@ static int tegra_ehci_remove(struct platform_device *pdev) } #endif + /* Turn Off Interrupts */ + ehci_writel(tegra->ehci, 0, &tegra->ehci->regs->intr_enable); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); usb_remove_hcd(hcd); usb_put_hcd(hcd); - + tegra_usb_phy_power_off(tegra->phy); tegra_usb_phy_close(tegra->phy); iounmap(hcd->regs); diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index 542a184824a3..652ade050d9a 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -43,6 +43,9 @@ #define USB_VBUS_STATUS (1 << 10) #define USB_INTS (USB_VBUS_INT_STATUS | USB_ID_INT_STATUS) +extern struct platform_device *tegra_usb_otg_host_register(); +extern void tegra_usb_otg_host_unregister(struct platform_device *pdev); + struct tegra_otg_data { struct otg_transceiver otg; unsigned long int_status; @@ -52,6 +55,7 @@ struct tegra_otg_data { int irq; struct platform_device *host; struct platform_device *pdev; + struct work_struct work; }; static inline unsigned long otg_readl(struct tegra_otg_data *tegra, @@ -79,58 +83,23 @@ static const char *tegra_state_name(enum usb_otg_state state) void tegra_start_host(struct tegra_otg_data *tegra) { - int retval; - struct platform_device *pdev; - struct platform_device *host = tegra->host; - void *platform_data; - - pdev = platform_device_alloc(host->name, host->id); - if (!pdev) - return; - - if (host->resource) { - retval = platform_device_add_resources(pdev, host->resource, - host->num_resources); - if (retval) - goto error; + if (!tegra->pdev) { + tegra->pdev = tegra_usb_otg_host_register(); } - - pdev->dev.dma_mask = host->dev.dma_mask; - pdev->dev.coherent_dma_mask = host->dev.coherent_dma_mask; - - platform_data = kmalloc(sizeof(struct tegra_ehci_platform_data), GFP_KERNEL); - if (!platform_data) - goto error; - - memcpy(platform_data, host->dev.platform_data, - sizeof(struct tegra_ehci_platform_data)); - pdev->dev.platform_data = platform_data; - - retval = platform_device_add(pdev); - if (retval) - goto error_add; - - tegra->pdev = pdev; - return; - -error_add: - kfree(platform_data); -error: - pr_err("%s: failed to add the host contoller device\n", __func__); - platform_device_put(pdev); } void tegra_stop_host(struct tegra_otg_data *tegra) { if (tegra->pdev) { - platform_device_unregister(tegra->pdev); + tegra_usb_otg_host_unregister(tegra->pdev); tegra->pdev = NULL; } } -static irqreturn_t tegra_otg_irq_thread(int irq, void *data) +static void irq_work(struct work_struct *work) { - struct tegra_otg_data *tegra = data; + struct tegra_otg_data *tegra = + container_of(work, struct tegra_otg_data, work); struct otg_transceiver *otg = &tegra->otg; enum usb_otg_state from = otg->state; enum usb_otg_state to = OTG_STATE_UNDEFINED; @@ -139,71 +108,72 @@ static irqreturn_t tegra_otg_irq_thread(int irq, void *data) clk_enable(tegra->clk); - status = otg_readl(tegra, USB_PHY_WAKEUP); - spin_lock_irqsave(&tegra->lock, flags); + status = tegra->int_status; + if (tegra->int_status & USB_ID_INT_STATUS) { - if (status & USB_ID_STATUS) - to = OTG_STATE_A_SUSPEND; + if (status & USB_ID_STATUS) { + if ((status & USB_VBUS_STATUS) && (from != OTG_STATE_A_HOST)) + to = OTG_STATE_B_PERIPHERAL; + else + to = OTG_STATE_A_SUSPEND; + } else to = OTG_STATE_A_HOST; - } else if (tegra->int_status & USB_VBUS_INT_STATUS) { - if (status & USB_VBUS_STATUS) - to = OTG_STATE_B_PERIPHERAL; - else - to = OTG_STATE_A_SUSPEND; } - - tegra->int_status = 0; - + if (from != OTG_STATE_A_HOST) { + if (tegra->int_status & USB_VBUS_INT_STATUS) { + if (status & USB_VBUS_STATUS) + to = OTG_STATE_B_PERIPHERAL; + else + to = OTG_STATE_A_SUSPEND; + } + } spin_unlock_irqrestore(&tegra->lock, flags); - otg->state = to; + if (to != OTG_STATE_UNDEFINED) { + otg->state = to; - dev_info(tegra->otg.dev, "%s --> %s", tegra_state_name(from), + dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from), tegra_state_name(to)); - if (to == OTG_STATE_A_SUSPEND) { - if (from == OTG_STATE_A_HOST && tegra->host) - tegra_stop_host(tegra); - else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) - usb_gadget_vbus_disconnect(otg->gadget); - } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) { - if (from == OTG_STATE_A_SUSPEND) - usb_gadget_vbus_connect(otg->gadget); - } else if (to == OTG_STATE_A_HOST && tegra->host) { - if (from == OTG_STATE_A_SUSPEND) + if (to == OTG_STATE_A_SUSPEND) { + if (from == OTG_STATE_A_HOST) + tegra_stop_host(tegra); + else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) + usb_gadget_vbus_disconnect(otg->gadget); + } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) { + if (from == OTG_STATE_A_SUSPEND) + usb_gadget_vbus_connect(otg->gadget); + } else if (to == OTG_STATE_A_HOST) { + if (from == OTG_STATE_A_SUSPEND) tegra_start_host(tegra); + } } - clk_disable(tegra->clk); - return IRQ_HANDLED; - } static irqreturn_t tegra_otg_irq(int irq, void *data) { struct tegra_otg_data *tegra = data; + unsigned long flags; unsigned long val; - clk_enable(tegra->clk); + spin_lock_irqsave(&tegra->lock, flags); - spin_lock(&tegra->lock); val = otg_readl(tegra, USB_PHY_WAKEUP); otg_writel(tegra, val, USB_PHY_WAKEUP); - /* and the interrupt enables into the interrupt status bits */ - val = (val & (val << 1)) & USB_INTS; - - tegra->int_status |= val; - - spin_unlock(&tegra->lock); + if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) { + tegra->int_status = val; + schedule_work(&tegra->work); + } - clk_disable(tegra->clk); + spin_unlock_irqrestore(&tegra->lock, flags); - return (val) ? IRQ_WAKE_THREAD : IRQ_NONE; + return IRQ_HANDLED; } static int tegra_otg_set_peripheral(struct otg_transceiver *otg, @@ -217,16 +187,24 @@ static int tegra_otg_set_peripheral(struct otg_transceiver *otg, clk_enable(tegra->clk); val = otg_readl(tegra, USB_PHY_WAKEUP); - val &= ~(USB_VBUS_INT_STATUS | USB_ID_INT_STATUS); - - if (gadget) - val |= (USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN); - else - val &= ~(USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN); - + val |= (USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN); + val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN); otg_writel(tegra, val, USB_PHY_WAKEUP); clk_disable(tegra->clk); + if ((val & USB_ID_STATUS) && (val & USB_VBUS_STATUS)) { + val |= USB_VBUS_INT_STATUS; + } else if (!(val & USB_ID_STATUS)) { + val |= USB_ID_INT_STATUS; + } else { + val &= ~(USB_ID_INT_STATUS | USB_VBUS_INT_STATUS); + } + + if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) { + tegra->int_status = val; + schedule_work (&tegra->work); + } + return 0; } @@ -243,10 +221,7 @@ static int tegra_otg_set_host(struct otg_transceiver *otg, val = otg_readl(tegra, USB_PHY_WAKEUP); val &= ~(USB_VBUS_INT_STATUS | USB_ID_INT_STATUS); - if (host) - val |= USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN; - else - val &= ~(USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN); + val |= (USB_ID_INT_EN | USB_ID_PIN_WAKEUP_EN); otg_writel(tegra, val, USB_PHY_WAKEUP); clk_disable(tegra->clk); @@ -267,7 +242,6 @@ static int tegra_otg_probe(struct platform_device *pdev) { struct tegra_otg_data *tegra; struct resource *res; - unsigned long val; int err; tegra = kzalloc(sizeof(struct tegra_otg_data), GFP_KERNEL); @@ -309,14 +283,6 @@ static int tegra_otg_probe(struct platform_device *pdev) goto err_io; } - val = otg_readl(tegra, USB_PHY_WAKEUP); - - val &= ~(USB_VBUS_INT_STATUS | USB_VBUS_INT_EN | - USB_ID_INT_STATUS | USB_ID_INT_EN | - USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN); - - otg_writel(tegra, val, USB_PHY_WAKEUP); - tegra->otg.state = OTG_STATE_A_SUSPEND; err = otg_set_transceiver(&tegra->otg); @@ -333,12 +299,13 @@ static int tegra_otg_probe(struct platform_device *pdev) } tegra->irq = res->start; err = request_threaded_irq(tegra->irq, tegra_otg_irq, - tegra_otg_irq_thread, + NULL, IRQF_SHARED, "tegra-otg", tegra); if (err) { dev_err(&pdev->dev, "Failed to register IRQ\n"); goto err_irq; } + INIT_WORK (&tegra->work, irq_work); dev_info(&pdev->dev, "otg transceiver registered\n"); return 0; diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 3c3a4754b7dc..cfe962be62f3 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -780,6 +780,76 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode) } EXPORT_SYMBOL(tegra_dc_set_mode); +static void tegra_dc_set_out_pin_polars(struct tegra_dc *dc, + const struct tegra_dc_out_pin *pins, + const unsigned int n_pins) +{ + unsigned int i; + + int name; + int pol; + + u32 pol1, pol3; + + u32 set1, unset1; + u32 set3, unset3; + + set1 = set3 = unset1 = unset3 = 0; + + for (i = 0; i < n_pins; i++) { + name = (pins + i)->name; + pol = (pins + i)->pol; + + /* set polarity by name */ + switch (name) { + case TEGRA_DC_OUT_PIN_DATA_ENABLE: + if (pol == TEGRA_DC_OUT_PIN_POL_LOW) + set3 |= LSPI_OUTPUT_POLARITY_LOW; + else + unset3 |= LSPI_OUTPUT_POLARITY_LOW; + break; + case TEGRA_DC_OUT_PIN_H_SYNC: + if (pol == TEGRA_DC_OUT_PIN_POL_LOW) + set1 |= LHS_OUTPUT_POLARITY_LOW; + else + unset1 |= LHS_OUTPUT_POLARITY_LOW; + break; + case TEGRA_DC_OUT_PIN_V_SYNC: + if (pol == TEGRA_DC_OUT_PIN_POL_LOW) + set1 |= LVS_OUTPUT_POLARITY_LOW; + else + unset1 |= LVS_OUTPUT_POLARITY_LOW; + break; + case TEGRA_DC_OUT_PIN_PIXEL_CLOCK: + if (pol == TEGRA_DC_OUT_PIN_POL_LOW) + set1 |= LSC0_OUTPUT_POLARITY_LOW; + else + unset1 |= LSC0_OUTPUT_POLARITY_LOW; + break; + default: + printk("Invalid argument in function %s\n", + __FUNCTION__); + break; + } + } + + mutex_lock(&dc->lock); + + pol1 = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY1); + pol3 = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY3); + + pol1 |= set1; + pol1 &= ~unset1; + + pol3 |= set3; + pol3 &= ~unset3; + + tegra_dc_writel(dc, pol1, DC_COM_PIN_OUTPUT_POLARITY1); + tegra_dc_writel(dc, pol3, DC_COM_PIN_OUTPUT_POLARITY3); + + mutex_unlock(&dc->lock); +} + static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out) { dc->out = out; @@ -975,6 +1045,10 @@ static bool _tegra_dc_enable(struct tegra_dc *dc) if (dc->out_ops && dc->out_ops->enable) dc->out_ops->enable(dc); + if (dc->out->out_pins) + tegra_dc_set_out_pin_polars(dc, dc->out->out_pins, + dc->out->n_out_pins); + /* force a full blending update */ dc->blend.z[0] = -1; diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h index f643ec9ec742..1911b0ed5ca6 100644 --- a/drivers/video/tegra/dc/dc_reg.h +++ b/drivers/video/tegra/dc/dc_reg.h @@ -108,9 +108,17 @@ #define DC_COM_PIN_OUTPUT_ENABLE2 0x304 #define DC_COM_PIN_OUTPUT_ENABLE3 0x305 #define DC_COM_PIN_OUTPUT_POLARITY0 0x306 + #define DC_COM_PIN_OUTPUT_POLARITY1 0x307 +#define LHS_OUTPUT_POLARITY_LOW (1 << 30) +#define LVS_OUTPUT_POLARITY_LOW (1 << 28) +#define LSC0_OUTPUT_POLARITY_LOW (1 << 24) + #define DC_COM_PIN_OUTPUT_POLARITY2 0x308 + #define DC_COM_PIN_OUTPUT_POLARITY3 0x309 +#define LSPI_OUTPUT_POLARITY_LOW (1 << 8) + #define DC_COM_PIN_OUTPUT_DATA0 0x30a #define DC_COM_PIN_OUTPUT_DATA1 0x30b #define DC_COM_PIN_OUTPUT_DATA2 0x30c diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index 006529d78101..3100bd090b78 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/wakelock.h> #include <linux/switch.h> #include <linux/workqueue.h> @@ -57,6 +58,8 @@ struct tegra_dc_hdmi_data { struct switch_dev hpd_switch; + struct wake_lock wake_lock; + spinlock_t suspend_lock; bool suspended; bool hpd_pending; @@ -619,6 +622,7 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc) tegra_dc_set_outdata(dc, hdmi); + wake_lock_init(&hdmi->wake_lock, WAKE_LOCK_SUSPEND, "HDMI"); return 0; err_free_irq: @@ -653,6 +657,7 @@ static void tegra_dc_hdmi_destroy(struct tegra_dc *dc) clk_put(hdmi->disp2_clk); tegra_edid_destroy(hdmi->edid); + wake_lock_destroy(&hdmi->wake_lock); kfree(hdmi); } @@ -1093,6 +1098,8 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc) tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + + wake_lock(&hdmi->wake_lock); } static void tegra_dc_hdmi_disable(struct tegra_dc *dc) @@ -1101,6 +1108,7 @@ static void tegra_dc_hdmi_disable(struct tegra_dc *dc) tegra_periph_reset_assert(hdmi->clk); clk_disable(hdmi->clk); + wake_unlock(&hdmi->wake_lock); } struct tegra_dc_out_ops tegra_dc_hdmi_ops = { .init = tegra_dc_hdmi_init, diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index cc26c5977a20..eae17b5dbc28 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -354,12 +354,16 @@ static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb, struct tegra_dc_win *win, const struct tegra_fb_flip_win *flip_win) { + int xres, yres; if (flip_win->handle == NULL) { win->flags = 0; win->cur_handle = NULL; return 0; } + xres = tegra_fb->info->var.xres; + yres = tegra_fb->info->var.yres; + win->flags = TEGRA_WIN_FLAG_ENABLED; if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_PREMULT) win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT; @@ -374,6 +378,15 @@ static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb, win->out_y = flip_win->attr.out_y; win->out_w = flip_win->attr.out_w; win->out_h = flip_win->attr.out_h; + + if (((win->out_x + win->out_w) > xres) && (win->out_x < xres)) { + win->out_w = xres - win->out_x; + } + + if (((win->out_y + win->out_h) > yres) && (win->out_y < yres)) { + win->out_h = yres - win->out_y; + } + win->z = flip_win->attr.z; win->cur_handle = flip_win->handle; diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c index 20a4eda0fb53..c9c88b0171a7 100644 --- a/drivers/video/tegra/host/dev.c +++ b/drivers/video/tegra/host/dev.c @@ -741,7 +741,7 @@ static int nvhost_suspend(struct platform_device *pdev, pm_message_t state) { struct nvhost_master *host = platform_get_drvdata(pdev); dev_info(&pdev->dev, "suspending\n"); - nvhost_module_suspend(&host->mod); + nvhost_module_suspend(&host->mod, true); clk_enable(host->mod.clk[0]); nvhost_syncpt_save(&host->syncpt); clk_disable(host->mod.clk[0]); diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c index c4ac035a26ec..9b56365bb44f 100644 --- a/drivers/video/tegra/host/nvhost_acm.c +++ b/drivers/video/tegra/host/nvhost_acm.c @@ -20,7 +20,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "nvhost_acm.h" +#include "dev.h" #include <linux/string.h> #include <linux/sched.h> #include <linux/err.h> @@ -155,17 +155,49 @@ static int is_module_idle(struct nvhost_module *mod) return (count == 0); } -void nvhost_module_suspend(struct nvhost_module *mod) +static void debug_not_idle(struct nvhost_module *mod) { + int i; + bool lock_released = true; + struct nvhost_master *dev = container_of(mod, struct nvhost_master, mod); + + for (i = 0; i < NVHOST_NUMCHANNELS; i++) { + struct nvhost_module *m = &dev->channels[i].mod; + if (m->name) + printk("tegra_grhost: %s: refcnt %d\n", + m->name, atomic_read(&m->refcount)); + } + + for (i = 0; i < NV_HOST1X_SYNC_MLOCK_NUM; i++) { + int c = atomic_read(&dev->cpuaccess.lock_counts[i]); + if (c) { + printk("tegra_grhost: lock id %d: refcnt %d\n", i, c); + lock_released = false; + } + } + if (lock_released) + printk("tegra_grhost: all locks released\n"); +} + +void nvhost_module_suspend(struct nvhost_module *mod, bool system_suspend) +{ + if (system_suspend && (!is_module_idle(mod))) + debug_not_idle(mod); + wait_event(mod->idle, is_module_idle(mod)); + if (system_suspend) + printk("tegra_grhost: entered idle\n"); + flush_delayed_work(&mod->powerdown); + if (system_suspend) + printk("tegra_grhost: flushed delayed work\n"); BUG_ON(mod->powered); } void nvhost_module_deinit(struct nvhost_module *mod) { int i; - nvhost_module_suspend(mod); + nvhost_module_suspend(mod, false); for (i = 0; i < mod->num_clks; i++) clk_put(mod->clk[i]); } diff --git a/drivers/video/tegra/host/nvhost_acm.h b/drivers/video/tegra/host/nvhost_acm.h index 57dcc2989113..c765d983afb4 100644 --- a/drivers/video/tegra/host/nvhost_acm.h +++ b/drivers/video/tegra/host/nvhost_acm.h @@ -57,7 +57,7 @@ int nvhost_module_init(struct nvhost_module *mod, const char *name, nvhost_modulef func, struct nvhost_module *parent, struct device *dev); void nvhost_module_deinit(struct nvhost_module *mod); -void nvhost_module_suspend(struct nvhost_module *mod); +void nvhost_module_suspend(struct nvhost_module *mod, bool system_suspend); void nvhost_module_busy(struct nvhost_module *mod); void nvhost_module_idle_mult(struct nvhost_module *mod, int refs); diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c index 40b67181c33d..949e67ffb653 100644 --- a/drivers/video/tegra/host/nvhost_channel.c +++ b/drivers/video/tegra/host/nvhost_channel.c @@ -227,8 +227,8 @@ static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action) ch->cur_ctx = NULL; nvhost_channel_submit(ch, ch->dev->nvmap, - &save, 1, &ctxsw, 1, NULL, 0, - NVSYNCPT_3D, syncval); + &save, 1, &ctxsw, 1, NULL, 0, + NVSYNCPT_3D, syncval); nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncval, diff --git a/drivers/video/tegra/host/nvhost_cpuaccess.c b/drivers/video/tegra/host/nvhost_cpuaccess.c index 9114dad97783..4a5c34d593fc 100644 --- a/drivers/video/tegra/host/nvhost_cpuaccess.c +++ b/drivers/video/tegra/host/nvhost_cpuaccess.c @@ -71,6 +71,7 @@ int nvhost_mutex_try_lock(struct nvhost_cpuaccess *ctx, unsigned int idx) nvhost_module_idle(&dev->mod); return -ERESTARTSYS; } + atomic_inc(&ctx->lock_counts[idx]); return 0; } @@ -80,6 +81,7 @@ void nvhost_mutex_unlock(struct nvhost_cpuaccess *ctx, unsigned int idx) void __iomem *sync_regs = dev->sync_aperture; writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4)); nvhost_module_idle(&dev->mod); + atomic_dec(&ctx->lock_counts[idx]); } void nvhost_read_module_regs(struct nvhost_cpuaccess *ctx, u32 module, diff --git a/drivers/video/tegra/host/nvhost_cpuaccess.h b/drivers/video/tegra/host/nvhost_cpuaccess.h index d7d6c99cd416..98ea1e1e1f8f 100644 --- a/drivers/video/tegra/host/nvhost_cpuaccess.h +++ b/drivers/video/tegra/host/nvhost_cpuaccess.h @@ -45,6 +45,7 @@ enum nvhost_module_id { struct nvhost_cpuaccess { struct resource *reg_mem[NVHOST_MODULE_NUM]; void __iomem *regs[NVHOST_MODULE_NUM]; + atomic_t lock_counts[NV_HOST1X_SYNC_MLOCK_NUM]; }; int nvhost_cpuaccess_init(struct nvhost_cpuaccess *ctx, diff --git a/drivers/video/tegra/host/nvhost_hardware.h b/drivers/video/tegra/host/nvhost_hardware.h index f69f467dd64e..a7663489727e 100644 --- a/drivers/video/tegra/host/nvhost_hardware.h +++ b/drivers/video/tegra/host/nvhost_hardware.h @@ -38,7 +38,7 @@ enum { #define NV_HOST1X_CHANNELS 8 #define NV_HOST1X_CHANNEL0_BASE 0 #define NV_HOST1X_CHANNEL_MAP_SIZE_BYTES 16384 - +#define NV_HOST1X_SYNC_MLOCK_NUM 16 #define HOST1X_CHANNEL_FIFOSTAT 0x00 #define HOST1X_CHANNEL_INDDATA 0x0c diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c index 007aaed9909f..51387ee62f8e 100644 --- a/drivers/video/tegra/host/nvhost_intr.c +++ b/drivers/video/tegra/host/nvhost_intr.c @@ -446,7 +446,7 @@ void nvhost_intr_configure (struct nvhost_intr *intr, u32 hz) { void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture; - // write microsecond clock register + /* write microsecond clock register */ writel((hz + 1000000 - 1)/1000000, sync_regs + HOST1X_SYNC_USEC_CLK); /* disable the ip_busy_timeout. this prevents write drops, etc. diff --git a/include/linux/earlysuspend.h b/include/linux/earlysuspend.h index 8343b817af31..8343b817af31 100755..100644 --- a/include/linux/earlysuspend.h +++ b/include/linux/earlysuspend.h diff --git a/include/linux/i2c/atmel_maxtouch.h b/include/linux/i2c/atmel_maxtouch.h new file mode 100755 index 000000000000..d827909ecbbd --- /dev/null +++ b/include/linux/i2c/atmel_maxtouch.h @@ -0,0 +1,301 @@ +/* + * Atmel maXTouch header file + * + * Copyright (c) 2010 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or 3 as + * published by the Free Software Foundation. + * See the file "COPYING" in the main directory of this archive + * for more details. + * + */ + +#define MXT224_I2C_ADDR1 0x4A +#define MXT224_I2C_ADDR2 0x4B +#define MXT1386_I2C_ADDR1 0x4C +#define MXT1386_I2C_ADDR2 0x4D +#define MXT1386_I2C_ADDR3 0x5A +#define MXT1386_I2C_ADDR4 0x5B + +/* + * Select this address from above depending on what maXTouch + * chip you have and how it's address pins are configured; + * see datasheet. + */ + +#define MXT_I2C_ADDRESS MXT1386_I2C_ADDR3 + +#define MXT_BL_ADDRESS 0x25 + +#define MXT224_FAMILYID 0x80 +#define MXT1386_FAMILYID 0xA0 + +#define MXT224_CAL_VARIANTID 0x01 +#define MXT224_UNCAL_VARIANTID 0x00 +#define MXT1386_CAL_VARIANTID 0x00 + +#define MXT_MAX_REPORTED_WIDTH 255 +#define MXT_MAX_REPORTED_PRESSURE 255 +#define MXT_MAX_TOUCH_SIZE 255 +#define MXT_MAX_NUM_TOUCHES 10 + +/* Fixed addresses inside maXTouch device */ +#define MXT_ADDR_INFO_BLOCK 0 +#define MXT_ADDR_OBJECT_TABLE 7 +#define MXT_ID_BLOCK_SIZE 7 +#define MXT_OBJECT_TABLE_ELEMENT_SIZE 6 + +/* Object types */ +#define MXT_DEBUG_DELTAS_T2 2 +#define MXT_DEBUG_REFERENCES_T3 3 +#define MXT_GEN_MESSAGEPROCESSOR_T5 5 +#define MXT_GEN_COMMANDPROCESSOR_T6 6 +#define MXT_GEN_POWERCONFIG_T7 7 +#define MXT_GEN_ACQUIRECONFIG_T8 8 +#define MXT_TOUCH_MULTITOUCHSCREEN_T9 9 +#define MXT_TOUCH_SINGLETOUCHSCREEN_T10 10 +#define MXT_TOUCH_XSLIDER_T11 11 +#define MXT_TOUCH_YSLIDER_T12 12 +#define MXT_TOUCH_XWHEEL_T13 13 +#define MXT_TOUCH_YWHEEL_T14 14 +#define MXT_TOUCH_KEYARRAY_T15 15 +#define MXT_SPT_GPIOPWM_T19 19 +#define MXT_PROCI_GRIPFACESUPPRESSION_T20 20 +#define MXT_PROCG_NOISESUPPRESSION_T22 22 +#define MXT_TOUCH_PROXIMITY_T23 23 +#define MXT_PROCI_ONETOUCHGESTUREPROCESSOR_T24 24 +#define MXT_SPT_SELFTEST_T25 25 +#define MXT_DEBUG_CTERANGE_T26 26 +#define MXT_PROCI_TWOTOUCHGESTUREPROCESSOR_T27 27 +#define MXT_SPT_CTECONFIG_T28 28 +#define MXT_TOUCH_KEYSET_T31 31 +#define MXT_TOUCH_XSLIDERSET_T32 32 +#define MXT_DEBUG_DIAGNOSTIC_T37 37 +#define MXT_USER_INFO_T38 38 + +/* + * If a message is read from mXT when there's no new messages available, + * the report ID of the message will be 0xFF. + */ +#define MXT_END_OF_MESSAGES 0xFF + +/* GEN_COMMANDPROCESSOR_T6 Register offsets from T6 base address */ +#define MXT_ADR_T6_RESET 0x00 +#define MXT_ADR_T6_BACKUPNV 0x01 +#define MXT_ADR_T6_CALIBRATE 0x02 +#define MXT_ADR_T6_REPORTALL 0x03 +#define MXT_ADR_T6_RESERVED 0x04 +#define MXT_ADR_T6_DIAGNOSTIC 0x05 + +/* T6 Debug Diagnostics Commands */ +#define MXT_CMD_T6_PAGE_UP 0x01 +#define MXT_CMD_T6_PAGE_DOWN 0x02 +#define MXT_CMD_T6_DELTAS_MODE 0x10 +#define MXT_CMD_T6_REFERENCES_MODE 0x11 +#define MXT_CMD_T6_CTE_MODE 0x31 + +/* T6 Backup Command */ +#define MXT_CMD_T6_BACKUP 0x55 + +/* SPT_DEBUG_DIAGNOSTIC_T37 Register offsets from T37 base address */ +#define MXT_ADR_T37_PAGE 0x01 +#define MXT_ADR_T37_DATA 0x02 + +/************************************************************************ + * MESSAGE OBJECTS ADDRESS FIELDS + * + ************************************************************************/ +#define MXT_MSG_REPORTID 0x00 + +/* MXT_GEN_MESSAGEPROCESSOR_T5 Message address definitions */ +#define MXT_MSG_T5_REPORTID 0x00 +#define MXT_MSG_T5_MESSAGE 0x01 +#define MXT_MSG_T5_CHECKSUM 0x08 + +/* MXT_GEN_COMMANDPROCESSOR_T6 Message address definitions */ +#define MXT_MSG_T6_STATUS 0x01 +#define MXT_MSGB_T6_COMSERR 0x04 +#define MXT_MSGB_T6_CFGERR 0x08 +#define MXT_MSGB_T6_CAL 0x10 +#define MXT_MSGB_T6_SIGERR 0x20 +#define MXT_MSGB_T6_OFL 0x40 +#define MXT_MSGB_T6_RESET 0x80 +/* Three bytes */ +#define MXT_MSG_T6_CHECKSUM 0x02 + +/* MXT_GEN_POWERCONFIG_T7 NO Message address definitions */ +/* MXT_GEN_ACQUIRECONFIG_T8 Message address definitions */ +/* MXT_TOUCH_MULTITOUCHSCREEN_T9 Message address definitions */ + +#define MXT_MSG_T9_STATUS 0x01 +/* Status bit field */ +#define MXT_MSGB_T9_SUPPRESS 0x02 +#define MXT_MSGB_T9_AMP 0x04 +#define MXT_MSGB_T9_VECTOR 0x08 +#define MXT_MSGB_T9_MOVE 0x10 +#define MXT_MSGB_T9_RELEASE 0x20 +#define MXT_MSGB_T9_PRESS 0x40 +#define MXT_MSGB_T9_DETECT 0x80 + +#define MXT_MSG_T9_XPOSMSB 0x02 +#define MXT_MSG_T9_YPOSMSB 0x03 +#define MXT_MSG_T9_XYPOSLSB 0x04 +#define MXT_MSG_T9_TCHAREA 0x05 +#define MXT_MSG_T9_TCHAMPLITUDE 0x06 +#define MXT_MSG_T9_TCHVECTOR 0x07 + +/* MXT_SPT_GPIOPWM_T19 Message address definitions */ +#define MXT_MSG_T19_STATUS 0x01 + +/* MXT_PROCI_GRIPFACESUPPRESSION_T20 Message address definitions */ +#define MXT_MSG_T20_STATUS 0x01 +#define MXT_MSGB_T20_FACE_SUPPRESS 0x01 +/* MXT_PROCG_NOISESUPPRESSION_T22 Message address definitions */ +#define MXT_MSG_T22_STATUS 0x01 +#define MXT_MSGB_T22_FHCHG 0x01 +#define MXT_MSGB_T22_GCAFERR 0x04 +#define MXT_MSGB_T22_FHERR 0x08 +#define MXT_MSG_T22_GCAFDEPTH 0x02 + +/* MXT_TOUCH_PROXIMITY_T23 Message address definitions */ +#define MXT_MSG_T23_STATUS 0x01 +#define MXT_MSGB_T23_FALL 0x20 +#define MXT_MSGB_T23_RISE 0x40 +#define MXT_MSGB_T23_DETECT 0x80 +/* 16 bit */ +#define MXT_MSG_T23_PROXDELTA 0x02 + +/* MXT_PROCI_ONETOUCHGESTUREPROCESSOR_T24 Message address definitions */ +#define MXT_MSG_T24_STATUS 0x01 +#define MXT_MSG_T24_XPOSMSB 0x02 +#define MXT_MSG_T24_YPOSMSB 0x03 +#define MXT_MSG_T24_XYPOSLSB 0x04 +#define MXT_MSG_T24_DIR 0x05 +/* 16 bit */ +#define MXT_MSG_T24_DIST 0x06 + +/* MXT_SPT_SELFTEST_T25 Message address definitions */ +#define MXT_MSG_T25_STATUS 0x01 +/* 5 Bytes */ +#define MXT_MSGR_T25_OK 0xFE +#define MXT_MSGR_T25_INVALID_TEST 0xFD +#define MXT_MSGR_T25_PIN_FAULT 0x11 +#define MXT_MSGR_T25_SIGNAL_LIMIT_FAULT 0x17 +#define MXT_MSGR_T25_GAIN_ERROR 0x20 +#define MXT_MSG_T25_INFO 0x02 + +/* MXT_PROCI_TWOTOUCHGESTUREPROCESSOR_T27 Message address definitions */ +#define MXT_MSG_T27_STATUS 0x01 +#define MXT_MSGB_T27_ROTATEDIR 0x10 +#define MXT_MSGB_T27_PINCH 0x20 +#define MXT_MSGB_T27_ROTATE 0x40 +#define MXT_MSGB_T27_STRETCH 0x80 +#define MXT_MSG_T27_XPOSMSB 0x02 +#define MXT_MSG_T27_YPOSMSB 0x03 +#define MXT_MSG_T27_XYPOSLSB 0x04 +#define MXT_MSG_T27_ANGLE 0x05 + +/* 16 bit */ +#define MXT_MSG_T27_SEPARATION 0x06 + +/* MXT_SPT_CTECONFIG_T28 Message address definitions */ +#define MXT_MSG_T28_STATUS 0x01 +#define MXT_MSGB_T28_CHKERR 0x01 + +/* One Touch Events */ +#define MT_GESTURE_RESERVED 0x00 +#define MT_GESTURE_PRESS 0x01 +#define MT_GESTURE_RELEASE 0x02 +#define MT_GESTURE_TAP 0x03 +#define MT_GESTURE_DOUBLE_TAP 0x04 +#define MT_GESTURE_FLICK 0x05 +#define MT_GESTURE_DRAG 0x06 +#define MT_GESTURE_SHORT_PRESS 0x07 +#define MT_GESTURE_LONG_PRESS 0x08 +#define MT_GESTURE_REPEAT_PRESS 0x09 +#define MT_GESTURE_TAP_AND_PRESS 0x0a +#define MT_GESTURE_THROW 0x0b + +/* Bootloader states */ +#define WAITING_BOOTLOAD_COMMAND 0xC0 +#define WAITING_FRAME_DATA 0x80 +#define APP_CRC_FAIL 0x40 +#define FRAME_CRC_CHECK 0x02 +#define FRAME_CRC_PASS 0x04 +#define FRAME_CRC_FAIL 0x03 + +#define MXT_MAX_FRAME_SIZE 276 + +/* Debug levels */ +#define NO_DEBUG 0 +#define DEBUG_INFO 1 +#define DEBUG_VERBOSE 2 +#define DEBUG_MESSAGES 5 +#define DEBUG_RAW 8 +#define DEBUG_TRACE 10 + +/* IOCTL commands */ +#define MXT_SET_ADDRESS 1 /* Sets the internal address pointer */ +#define MXT_RESET 2 /* Resets the device */ +#define MXT_CALIBRATE 3 /* Calibrates the device */ +#define MXT_BACKUP 4 /* Backups the current state of registers to + NVM */ +#define MXT_NONTOUCH_MSG 5 /* Only non-touch messages can be read from + the message buffer + (/dev/maXTouch_messages) */ +#define MXT_ALL_MSG 6 /* All messages can be read from the message + buffer */ + +/* Message buffer size. This is a ring buffer, and when full, the oldest entry + will be overwritten. */ +#define MXT_MESSAGE_BUFFER_SIZE 128 + +/* Routines for memory access within a 16 bit address space */ + +static int mxt_read_block(struct i2c_client *client, u16 addr, u16 length, + u8 *value); +static int mxt_write_byte(struct i2c_client *client, u16 addr, u8 value); +static int mxt_write_block(struct i2c_client *client, u16 addr, u16 length, + u8 *value); + +/* TODO: */ +/* Bootloader specific function prototypes. */ +static int mxt_read_byte_bl(struct i2c_client *client, u8 * value); +static int mxt_read_block_bl(struct i2c_client *client, u16 length, u8 * value); +static int mxt_write_byte_bl(struct i2c_client *client, u8 value); +static int mxt_write_block_bl(struct i2c_client *client, u16 length, + u8 *value); + +/** + * struct mxt_platform_data - includes platform specific informatio + * related to Atmel maXTouch touchscreen controller. + * + * @numtouch: Number of simultaneous touches supported + * @init_platform_hw(): Initialization function, which can for example + * trigger a hardware reset by toggling a GPIO pin + * @exit_platform_hw(): Function to run when the driver is unloaded. + * @valid_interrupt(): Function that checks the validity of the interrupt - + * function that check the validity of a interrupt (by + * reading the changeline interrupt pin and checking that + * it really is low for example). + * @max_x: Reported X range + * @max_y: Reported Y range + */ + +struct mxt_platform_data { + u8 numtouch; /* Number of touches to report */ + void (*init_platform_hw) (void); + void (*exit_platform_hw) (void); + int max_x; /* The default reported X range */ + int max_y; /* The default reported Y range */ + u8(*valid_interrupt) (void); + u8(*read_chg) (void); +}; + +static u8 mxt_valid_interrupt_dummy(void) +{ + return 1; +} + +void mxt_hw_reset(void); diff --git a/include/linux/i2c/nct1008.h b/include/linux/i2c/nct1008.h new file mode 100644 index 000000000000..a037f8a9b2ed --- /dev/null +++ b/include/linux/i2c/nct1008.h @@ -0,0 +1,46 @@ +/* + * linux/include/i2c/nct1008.h + * + * Temperature monitoring device from On Semiconductors + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _LINUX_NCT1008_H +#define _LINUX_NCT1008_H + +/* config params */ +#define NCT1008_CONFIG_ALERT_DISABLE 0x80 +#define NCT1008_CONFIG_RUN_STANDBY 0x40 +#define NCT1008_CONFIG_ALERT_THERM2 0x20 +#define NCT1008_CONFIG_ENABLE_EXTENDED 0x04 + +struct nct1008_platform_data { + /* temperature conversion rate */ + int conv_rate; + + /* configuration parameters */ + int config; + + /* cpu shut down threshold */ + int thermal_threshold; + + /* temperature offset */ + int offset; +}; + +#endif /* _LINUX_NCT1008_H */ diff --git a/include/linux/mfd/max8907c.h b/include/linux/mfd/max8907c.h new file mode 100644 index 000000000000..c78849a32860 --- /dev/null +++ b/include/linux/mfd/max8907c.h @@ -0,0 +1,183 @@ +/* linux/mfd/max8907c.h + * + * Functions to access MAX8907C power management chip. + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MFD_MAX8907C_H +#define __LINUX_MFD_MAX8907C_H + +/* MAX8907C register map */ +#define MAX8907C_REG_SYSENSEL 0x00 +#define MAX8907C_REG_ON_OFF_IRQ1 0x01 +#define MAX8907C_REG_ON_OFF_IRQ1_MASK 0x02 +#define MAX8907C_REG_ON_OFF_STAT 0x03 +#define MAX8907C_REG_SDCTL1 0x04 +#define MAX8907C_REG_SDSEQCNT1 0x05 +#define MAX8907C_REG_SDV1 0x06 +#define MAX8907C_REG_SDCTL2 0x07 +#define MAX8907C_REG_SDSEQCNT2 0x08 +#define MAX8907C_REG_SDV2 0x09 +#define MAX8907C_REG_SDCTL3 0x0A +#define MAX8907C_REG_SDSEQCNT3 0x0B +#define MAX8907C_REG_SDV3 0x0C +#define MAX8907C_REG_ON_OFF_IRQ2 0x0D +#define MAX8907C_REG_ON_OFF_IRQ2_MASK 0x0E +#define MAX8907C_REG_RESET_CNFG 0x0F +#define MAX8907C_REG_LDOCTL16 0x10 +#define MAX8907C_REG_LDOSEQCNT16 0x11 +#define MAX8907C_REG_LDO16VOUT 0x12 +#define MAX8907C_REG_SDBYSEQCNT 0x13 +#define MAX8907C_REG_LDOCTL17 0x14 +#define MAX8907C_REG_LDOSEQCNT17 0x15 +#define MAX8907C_REG_LDO17VOUT 0x16 +#define MAX8907C_REG_LDOCTL1 0x18 +#define MAX8907C_REG_LDOSEQCNT1 0x19 +#define MAX8907C_REG_LDO1VOUT 0x1A +#define MAX8907C_REG_LDOCTL2 0x1C +#define MAX8907C_REG_LDOSEQCNT2 0x1D +#define MAX8907C_REG_LDO2VOUT 0x1E +#define MAX8907C_REG_LDOCTL3 0x20 +#define MAX8907C_REG_LDOSEQCNT3 0x21 +#define MAX8907C_REG_LDO3VOUT 0x22 +#define MAX8907C_REG_LDOCTL4 0x24 +#define MAX8907C_REG_LDOSEQCNT4 0x25 +#define MAX8907C_REG_LDO4VOUT 0x26 +#define MAX8907C_REG_LDOCTL5 0x28 +#define MAX8907C_REG_LDOSEQCNT5 0x29 +#define MAX8907C_REG_LDO5VOUT 0x2A +#define MAX8907C_REG_LDOCTL6 0x2C +#define MAX8907C_REG_LDOSEQCNT6 0x2D +#define MAX8907C_REG_LDO6VOUT 0x2E +#define MAX8907C_REG_LDOCTL7 0x30 +#define MAX8907C_REG_LDOSEQCNT7 0x31 +#define MAX8907C_REG_LDO7VOUT 0x32 +#define MAX8907C_REG_LDOCTL8 0x34 +#define MAX8907C_REG_LDOSEQCNT8 0x35 +#define MAX8907C_REG_LDO8VOUT 0x36 +#define MAX8907C_REG_LDOCTL9 0x38 +#define MAX8907C_REG_LDOSEQCNT9 0x39 +#define MAX8907C_REG_LDO9VOUT 0x3A +#define MAX8907C_REG_LDOCTL10 0x3C +#define MAX8907C_REG_LDOSEQCNT10 0x3D +#define MAX8907C_REG_LDO10VOUT 0x3E +#define MAX8907C_REG_LDOCTL11 0x40 +#define MAX8907C_REG_LDOSEQCNT11 0x41 +#define MAX8907C_REG_LDO11VOUT 0x42 +#define MAX8907C_REG_LDOCTL12 0x44 +#define MAX8907C_REG_LDOSEQCNT12 0x45 +#define MAX8907C_REG_LDO12VOUT 0x46 +#define MAX8907C_REG_LDOCTL13 0x48 +#define MAX8907C_REG_LDOSEQCNT13 0x49 +#define MAX8907C_REG_LDO13VOUT 0x4A +#define MAX8907C_REG_LDOCTL14 0x4C +#define MAX8907C_REG_LDOSEQCNT14 0x4D +#define MAX8907C_REG_LDO14VOUT 0x4E +#define MAX8907C_REG_LDOCTL15 0x50 +#define MAX8907C_REG_LDOSEQCNT15 0x51 +#define MAX8907C_REG_LDO15VOUT 0x52 +#define MAX8907C_REG_OUT5VEN 0x54 +#define MAX8907C_REG_OUT5VSEQ 0x55 +#define MAX8907C_REG_OUT33VEN 0x58 +#define MAX8907C_REG_OUT33VSEQ 0x59 +#define MAX8907C_REG_LDOCTL19 0x5C +#define MAX8907C_REG_LDOSEQCNT19 0x5D +#define MAX8907C_REG_LDO19VOUT 0x5E +#define MAX8907C_REG_LBCNFG 0x60 +#define MAX8907C_REG_SEQ1CNFG 0x64 +#define MAX8907C_REG_SEQ2CNFG 0x65 +#define MAX8907C_REG_SEQ3CNFG 0x66 +#define MAX8907C_REG_SEQ4CNFG 0x67 +#define MAX8907C_REG_SEQ5CNFG 0x68 +#define MAX8907C_REG_SEQ6CNFG 0x69 +#define MAX8907C_REG_SEQ7CNFG 0x6A +#define MAX8907C_REG_LDOCTL18 0x72 +#define MAX8907C_REG_LDOSEQCNT18 0x73 +#define MAX8907C_REG_LDO18VOUT 0x74 +#define MAX8907C_REG_BBAT_CNFG 0x78 +#define MAX8907C_REG_CHG_CNTL1 0x7C +#define MAX8907C_REG_CHG_CNTL2 0x7D +#define MAX8907C_REG_CHG_IRQ1 0x7E +#define MAX8907C_REG_CHG_IRQ2 0x7F +#define MAX8907C_REG_CHG_IRQ1_MASK 0x80 +#define MAX8907C_REG_CHG_IRQ2_MASK 0x81 +#define MAX8907C_REG_CHG_STAT 0x82 +#define MAX8907C_REG_WLED_MODE_CNTL 0x84 +#define MAX8907C_REG_ILED_CNTL 0x84 +#define MAX8907C_REG_II1RR 0x8E +#define MAX8907C_REG_II2RR 0x8F +#define MAX8907C_REG_LDOCTL20 0x9C +#define MAX8907C_REG_LDOSEQCNT20 0x9D +#define MAX8907C_REG_LDO20VOUT 0x9E + +/* RTC register */ +#define MAX8907C_REG_RTC_SEC 0x00 +#define MAX8907C_REG_RTC_MIN 0x01 +#define MAX8907C_REG_RTC_HOURS 0x02 +#define MAX8907C_REG_RTC_WEEKDAY 0x03 +#define MAX8907C_REG_RTC_DATE 0x04 +#define MAX8907C_REG_RTC_MONTH 0x05 +#define MAX8907C_REG_RTC_YEAR1 0x06 +#define MAX8907C_REG_RTC_YEAR2 0x07 +#define MAX8907C_REG_ALARM0_SEC 0x08 +#define MAX8907C_REG_ALARM0_MIN 0x09 +#define MAX8907C_REG_ALARM0_HOURS 0x0A +#define MAX8907C_REG_ALARM0_WEEKDAY 0x0B +#define MAX8907C_REG_ALARM0_DATE 0x0C +#define MAX8907C_REG_ALARM0_MONTH 0x0D +#define MAX8907C_REG_ALARM0_YEAR1 0x0E +#define MAX8907C_REG_ALARM0_YEAR2 0x0F +#define MAX8907C_REG_ALARM1_SEC 0x10 +#define MAX8907C_REG_ALARM1_MIN 0x11 +#define MAX8907C_REG_ALARM1_HOURS 0x12 +#define MAX8907C_REG_ALARM1_WEEKDAY 0x13 +#define MAX8907C_REG_ALARM1_DATE 0x14 +#define MAX8907C_REG_ALARM1_MONTH 0x15 +#define MAX8907C_REG_ALARM1_YEAR1 0x16 +#define MAX8907C_REG_ALARM1_YEAR2 0x17 +#define MAX8907C_REG_ALARM0_CNTL 0x18 +#define MAX8907C_REG_ALARM1_CNTL 0x19 +#define MAX8907C_REG_RTC_STATUS 0x1A +#define MAX8907C_REG_RTC_CNTL 0x1B +#define MAX8907C_REG_RTC_IRQ 0x1C +#define MAX8907C_REG_IRQ_IRQ_MASK 0x1D +#define MAX8907C_REG_MPL_CNTL 0x1E + +/* ADC and Touch Screen Controller register map */ + +#define MAX8907C_CTL 0 +#define MAX8907C_SEQCNT 1 +#define MAX8907C_VOUT 2 + +/* mask bit fields */ +#define MAX8907C_MASK_LDO_SEQ 0x1C +#define MAX8907C_MASK_LDO_EN 0x01 +#define MAX8907C_MASK_VBBATTCV 0x03 +#define MAX8907C_MASK_OUT5V_VINEN 0x10 +#define MAX8907C_MASK_OUT5V_ENSRC 0x0E +#define MAX8907C_MASK_OUT5V_EN 0x01 + +struct max8907c { + struct device *dev; + + int (*read_dev) (void *io_data, u8 reg, u8 count, u8 * dst); + int (*write_dev) (void *io_data, u8 reg, u8 count, const u8 * src); + + struct mutex io_lock; +}; + +struct max8907c_platform_data { + int num_subdevs; + struct platform_device **subdevs; +}; + +int max8907c_reg_read(struct device *dev, u8 reg); +int max8907c_reg_write(struct device *dev, u8 reg, u8 val); +int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val); + +#endif diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index d96fb3d3e624..bd20aa696485 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -78,5 +78,6 @@ extern int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask); extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask); extern int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask); +extern int tps6586x_power_off(void); #endif /*__LINUX_MFD_TPS6586X_H */ diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 557acae8cf95..557acae8cf95 100755..100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h diff --git a/include/linux/mpu3050.h b/include/linux/mpu3050.h new file mode 100755 index 000000000000..9c8ddc2ad0af --- /dev/null +++ b/include/linux/mpu3050.h @@ -0,0 +1,609 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +/****************************************************************************** + * + * $Id: mpu3050.h 3868 2010-10-09 01:22:37Z dsrivastava $ + * + ******************************************************************************/ + +/** + * @defgroup + * @brief + * + * @{ + * @file mpu3050.h + * @brief +**/ + +#ifndef __MPU3050_H_ +#define __MPU3050_H_ + +#ifdef __KERNEL__ +#include <linux/types.h> +#endif + +typedef void *mlsl_handle_t; + +#define DEFAULT_MPU_SLAVEADDR 0x68 + +/*==== MPU REGISTER SET ====*/ +enum mpu_register { + MPUREG_WHO_AM_I = 0, /* 00 0x00 */ + MPUREG_PRODUCT_ID, /* 01 0x01 */ + MPUREG_02_RSVD, /* 02 0x02 */ + MPUREG_03_RSVD, /* 03 0x03 */ + MPUREG_04_RSVD, /* 04 0x04 */ + MPUREG_XG_OFFS_TC, /* 05 0x05 */ + MPUREG_06_RSVD, /* 06 0x06 */ + MPUREG_07_RSVD, /* 07 0x07 */ + MPUREG_YG_OFFS_TC, /* 08 0x08 */ + MPUREG_09_RSVD, /* 09 0x09 */ + MPUREG_0A_RSVD, /* 10 0x0a */ + MPUREG_ZG_OFFS_TC, /* 11 0x0b */ + MPUREG_X_OFFS_USRH, /* 12 0x0c */ + MPUREG_X_OFFS_USRL, /* 13 0x0d */ + MPUREG_Y_OFFS_USRH, /* 14 0x0e */ + MPUREG_Y_OFFS_USRL, /* 15 0x0f */ + MPUREG_Z_OFFS_USRH, /* 16 0x10 */ + MPUREG_Z_OFFS_USRL, /* 17 0x11 */ + MPUREG_FIFO_EN1, /* 18 0x12 */ + MPUREG_FIFO_EN2, /* 19 0x13 */ + MPUREG_AUX_SLV_ADDR, /* 20 0x14 */ + MPUREG_SMPLRT_DIV, /* 21 0x15 */ + MPUREG_DLPF_FS_SYNC, /* 22 0x16 */ + MPUREG_INT_CFG, /* 23 0x17 */ + MPUREG_ACCEL_BURST_ADDR, /* 24 0x18 */ + MPUREG_19_RSVD, /* 25 0x19 */ + MPUREG_INT_STATUS, /* 26 0x1a */ + MPUREG_TEMP_OUT_H, /* 27 0x1b */ + MPUREG_TEMP_OUT_L, /* 28 0x1c */ + MPUREG_GYRO_XOUT_H, /* 29 0x1d */ + MPUREG_GYRO_XOUT_L, /* 30 0x1e */ + MPUREG_GYRO_YOUT_H, /* 31 0x1f */ + MPUREG_GYRO_YOUT_L, /* 32 0x20 */ + MPUREG_GYRO_ZOUT_H, /* 33 0x21 */ + MPUREG_GYRO_ZOUT_L, /* 34 0x22 */ + MPUREG_23_RSVD, /* 35 0x23 */ + MPUREG_24_RSVD, /* 36 0x24 */ + MPUREG_25_RSVD, /* 37 0x25 */ + MPUREG_26_RSVD, /* 38 0x26 */ + MPUREG_27_RSVD, /* 39 0x27 */ + MPUREG_28_RSVD, /* 40 0x28 */ + MPUREG_29_RSVD, /* 41 0x29 */ + MPUREG_2A_RSVD, /* 42 0x2a */ + MPUREG_2B_RSVD, /* 43 0x2b */ + MPUREG_2C_RSVD, /* 44 0x2c */ + MPUREG_2D_RSVD, /* 45 0x2d */ + MPUREG_2E_RSVD, /* 46 0x2e */ + MPUREG_2F_RSVD, /* 47 0x2f */ + MPUREG_30_RSVD, /* 48 0x30 */ + MPUREG_31_RSVD, /* 49 0x31 */ + MPUREG_32_RSVD, /* 50 0x32 */ + MPUREG_33_RSVD, /* 51 0x33 */ + MPUREG_34_RSVD, /* 52 0x34 */ + MPUREG_DMP_CFG_1, /* 53 0x35 */ + MPUREG_DMP_CFG_2, /* 54 0x36 */ + MPUREG_BANK_SEL, /* 55 0x37 */ + MPUREG_MEM_START_ADDR, /* 56 0x38 */ + MPUREG_MEM_R_W, /* 57 0x39 */ + MPUREG_FIFO_COUNTH, /* 58 0x3a */ + MPUREG_FIFO_COUNTL, /* 59 0x3b */ + MPUREG_FIFO_R_W, /* 60 0x3c */ + MPUREG_USER_CTRL, /* 61 0x3d */ + MPUREG_PWR_MGM, /* 62 0x3e */ + MPUREG_3F_RSVD, /* 63 0x3f */ + NUM_OF_MPU_REGISTERS /* 64 0x40 */ +}; + +/*==== BITS FOR MPU ====*/ + +/*---- MPU 'FIFO_EN1' register (12) ----*/ +#define BIT_TEMP_OUT 0x80 +#define BIT_GYRO_XOUT 0x40 +#define BIT_GYRO_YOUT 0x20 +#define BIT_GYRO_ZOUT 0x10 +#define BIT_ACCEL_XOUT 0x08 +#define BIT_ACCEL_YOUT 0x04 +#define BIT_ACCEL_ZOUT 0x02 +#define BIT_AUX_1OUT 0x01 +/*---- MPU 'FIFO_EN2' register (13) ----*/ +#define BIT_AUX_2OUT 0x02 +#define BIT_AUX_3OUT 0x01 +/*---- MPU 'DLPF_FS_SYNC' register (16) ----*/ +#define BITS_EXT_SYNC_NONE 0x00 +#define BITS_EXT_SYNC_TEMP 0x20 +#define BITS_EXT_SYNC_GYROX 0x40 +#define BITS_EXT_SYNC_GYROY 0x60 +#define BITS_EXT_SYNC_GYROZ 0x80 +#define BITS_EXT_SYNC_ACCELX 0xA0 +#define BITS_EXT_SYNC_ACCELY 0xC0 +#define BITS_EXT_SYNC_ACCELZ 0xE0 +#define BITS_EXT_SYNC_MASK 0xE0 +#define BITS_FS_250DPS 0x00 +#define BITS_FS_500DPS 0x08 +#define BITS_FS_1000DPS 0x10 +#define BITS_FS_2000DPS 0x18 +#define BITS_FS_MASK 0x18 +#define BITS_DLPF_CFG_256HZ_NOLPF2 0x00 +#define BITS_DLPF_CFG_188HZ 0x01 +#define BITS_DLPF_CFG_98HZ 0x02 +#define BITS_DLPF_CFG_42HZ 0x03 +#define BITS_DLPF_CFG_20HZ 0x04 +#define BITS_DLPF_CFG_10HZ 0x05 +#define BITS_DLPF_CFG_5HZ 0x06 +#define BITS_DLPF_CFG_2100HZ_NOLPF 0x07 +#define BITS_DLPF_CFG_MASK 0x07 +/*---- MPU 'INT_CFG' register (17) ----*/ +#define BIT_ACTL 0x80 +#define BIT_ACTL_LOW 0x80 +#define BIT_ACTL_HIGH 0x00 +#define BIT_OPEN 0x40 +#define BIT_OPEN_DRAIN 0x40 +#define BIT_PUSH_PULL 0x00 +#define BIT_LATCH_INT_EN 0x20 +#define BIT_LATCH_INT_EN 0x20 +#define BIT_INT_PULSE_WIDTH_50US 0x00 +#define BIT_INT_ANYRD_2CLEAR 0x10 +#define BIT_INT_STAT_READ_2CLEAR 0x00 +#define BIT_MPU_RDY_EN 0x04 +#define BIT_DMP_INT_EN 0x02 +#define BIT_RAW_RDY_EN 0x01 +/*---- MPU 'INT_STATUS' register (1A) ----*/ +#define BIT_INT_STATUS_FIFO_OVERLOW (0x80) +#define BIT_MPU_RDY 0x04 +#define BIT_DMP_INT 0x02 +#define BIT_RAW_RDY 0x01 +/*---- MPU 'BANK_SEL' register (37) ----*/ +#define BIT_PRFTCH_EN 0x20 +#define BIT_CFG_USER_BANK 0x10 +#define BITS_MEM_SEL 0x0f +/*---- MPU 'USER_CTRL' register (3D) ----*/ +#define BIT_DMP_EN 0x80 +#define BIT_FIFO_EN 0x40 +#define BIT_AUX_IF_EN 0x20 +#define BIT_AUX_RD_LENG 0x10 +#define BIT_AUX_IF_RST 0x08 +#define BIT_DMP_RST 0x04 +#define BIT_FIFO_RST 0x02 +#define BIT_GYRO_RST 0x01 +/*---- MPU 'PWR_MGM' register (3E) ----*/ +#define BIT_H_RESET 0x80 +#define BIT_SLEEP 0x40 +#define BIT_STBY_XG 0x20 +#define BIT_STBY_YG 0x10 +#define BIT_STBY_ZG 0x08 +#define BITS_CLKSEL 0x07 + +/*---- MPU Silicon Revision ----*/ +#define MPU_SILICON_REV_A4 1 /* MPU A4 Device */ +#define MPU_SILICON_REV_B1 2 /* MPU B1 Device */ +#define MPU_SILICON_REV_B4 3 /* MPU B4 Device */ +#define MPU_SILICON_REV_B6 4 /* MPU B6 Device */ + +/*---- MPU Memory ----*/ +#define MPU_MEM_BANK_SIZE 256 +#define FIFO_HW_SIZE (512) /* FIFO hw is 512 bytes */ + +typedef enum { + MPU_MEM_RAM_BANK_0 = 0, + MPU_MEM_RAM_BANK_1, + MPU_MEM_RAM_BANK_2, + MPU_MEM_RAM_BANK_3, + MPU_MEM_NUM_RAM_BANKS, + MPU_MEM_OTP_BANK_0 = MPU_MEM_NUM_RAM_BANKS, + /* This one is always last */ + MPU_MEM_NUM_BANKS +} tMPUMemoryBanks, MPU_MEMORY_BANKS; + +#define MPU_NUM_AXES (3) + +/*---- structure containing control variables used by MLDL ----*/ +/*---- MPU clock source settings ----*/ +/*---- MPU filter selections ----*/ +enum mpu_filter { + MPU_FILTER_256HZ_NOLPF2 = 0, + MPU_FILTER_188HZ, + MPU_FILTER_98HZ, + MPU_FILTER_42HZ, + MPU_FILTER_20HZ, + MPU_FILTER_10HZ, + MPU_FILTER_5HZ, + MPU_FILTER_2100HZ_NOLPF, + NUM_MPU_FILTER +}; + +enum mpu_fullscale { + MPU_FS_250DPS = 0, + MPU_FS_500DPS, + MPU_FS_1000DPS, + MPU_FS_2000DPS, + NUM_MPU_FS +}; + +enum mpu_clock_sel { + MPU_CLK_SEL_INTERNAL = 0, + MPU_CLK_SEL_PLLGYROX, + MPU_CLK_SEL_PLLGYROY, + MPU_CLK_SEL_PLLGYROZ, + MPU_CLK_SEL_PLLEXT32K, + MPU_CLK_SEL_PLLEXT19M, + MPU_CLK_SEL_RESERVED, + MPU_CLK_SEL_STOP, + NUM_CLK_SEL +}; + +enum mpu_ext_sync { + MPU_EXT_SYNC_NONE = 0, + MPU_EXT_SYNC_TEMP, + MPU_EXT_SYNC_GYROX, + MPU_EXT_SYNC_GYROY, + MPU_EXT_SYNC_GYROZ, + MPU_EXT_SYNC_ACCELX, + MPU_EXT_SYNC_ACCELY, + MPU_EXT_SYNC_ACCELZ, + NUM_MPU_EXT_SYNC +}; + +#define DLPF_FS_SYNC_VALUE(ext_sync, full_scale, lpf) \ + ((ext_sync << 5) | (full_scale << 3) | lpf) + +/* IOCTL commands for /dev/mpu */ +#define MPU_SET_MPU_CONFIG (0x00) +#define MPU_SET_INT_CONFIG (0x01) +#define MPU_SET_EXT_SYNC (0x02) +#define MPU_SET_FULL_SCALE (0x03) +#define MPU_SET_LPF (0x04) +#define MPU_SET_CLK_SRC (0x05) +#define MPU_SET_DIVIDER (0x06) +#define MPU_SET_LEVEL_SHIFTER (0x07) +#define MPU_SET_DMP_ENABLE (0x08) +#define MPU_SET_FIFO_ENABLE (0x09) +#define MPU_SET_DMP_CFG1 (0x0a) +#define MPU_SET_DMP_CFG2 (0x0b) +#define MPU_SET_OFFSET_TC (0x0c) +#define MPU_SET_RAM (0x0d) + +#define MPU_SET_PLATFORM_DATA (0x0e) + +#define MPU_GET_MPU_CONFIG (0x80) +#define MPU_GET_INT_CONFIG (0x81) +#define MPU_GET_EXT_SYNC (0x82) +#define MPU_GET_FULL_SCALE (0x83) +#define MPU_GET_LPF (0x84) +#define MPU_GET_CLK_SRC (0x85) +#define MPU_GET_DIVIDER (0x86) +#define MPU_GET_LEVEL_SHIFTER (0x87) +#define MPU_GET_DMP_ENABLE (0x88) +#define MPU_GET_FIFO_ENABLE (0x89) +#define MPU_GET_DMP_CFG1 (0x8a) +#define MPU_GET_DMP_CFG2 (0x8b) +#define MPU_GET_OFFSET_TC (0x8c) +#define MPU_GET_RAM (0x8d) + +#define MPU_READ_REGISTER (0x40) +#define MPU_WRITE_REGISTER (0x41) +#define MPU_READ_MEMORY (0x42) +#define MPU_WRITE_MEMORY (0x43) + +#define MPU_SUSPEND (0x44) +#define MPU_RESUME (0x45) +#define MPU_READ_COMPASS (0x46) +#define MPU_READ_ACCEL (0x47) + +/* Structure for the following IOCTL's: + MPU_SET_RAM + MPU_GET_RAM + MPU_READ_REGISTER + MPU_WRITE_REGISTER + MPU_READ_MEMORY + MPU_WRITE_MEMORY +*/ +struct mpu_read_write { + unsigned short address; + unsigned short length; + unsigned char *data; +}; + +/* Structure for the following IOCTL's + MPU_SUSPEND + MPU_RESUME +*/ +struct mpu_suspend_resume { + int gyro; + int accel; + int compass; +}; + +enum ext_slave_type { + EXT_SLAVE_TYPE_GYROSCOPE, + EXT_SLAVE_TYPE_ACCELEROMETER, + EXT_SLAVE_TYPE_COMPASS, + /* EXT_SLAVE_TYPE_PRESSURE, */ + /* EXT_SLAVE_TYPE_TEMPERATURE */ +}; + +enum ext_slave_id { + ID_INVALID = 0, + + ACCEL_ID_LIS331, + ACCEL_ID_LSM303, + ACCEL_ID_KXSD9, + ACCEL_ID_KXTF9, + ACCEL_ID_BMA150, + ACCEL_ID_BMA222, + ACCEL_ID_ADI346, + ACCEL_ID_MMA8450, + ACCEL_ID_MMA8451, + + COMPASS_ID_AKM, + COMPASS_ID_AICHI, + COMPASS_ID_YAS529, + COMPASS_ID_HMC5883, + COMPASS_ID_LSM303, + COMPASS_ID_MMC314X, +}; + +enum ext_slave_endian { + EXT_SLAVE_BIG_ENDIAN, + EXT_SLAVE_LITTLE_ENDIAN, + EXT_SLAVE_FS8_BIG_ENDIAN, + EXT_SLAVE_FS16_BIG_ENDIAN, +}; + +enum ext_slave_bus { + EXT_SLAVE_BUS_PRIMARY, + EXT_SLAVE_BUS_SECONDARY, +}; + +/** + * struct ext_slave_platform_data - Platform data for mpu3050 slave devices + * + * @get_slave_descr: Function pointer to retrieve the struct ext_slave_descr + * for this slave + * @adapt_num: the I2C adapter number. + * @bus: the bus the slave is attached to: enum ext_slave_bus + * @address: the I2C slave address of the slave device. + * @orientation: the mounting matrix of the device relative to MPU. + * @private_data: additional data, user customizable. Not touched by the MPU + * driver. + * + * The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + * + * @code + * struct ext_slave_platform_data { + * struct ext_slave_descr* (*get_slave_descr) (void); + * int adapt_num; + * int bus; + * unsigned char address; + * signed char orientation[9]; + * void *private_data; + * }; + * @endcode + */ +struct ext_slave_platform_data { + struct ext_slave_descr *(*get_slave_descr) (void); + int adapt_num; + int bus; + unsigned char address; + signed char orientation[9]; + void *private_data; +}; + +struct tFixPntRange { + long mantissa; + long fraction; +}; + +/** + * struct ext_slave_descr - Description of the slave device for programming + * + * @suspend: function pointer to put the device in suspended state + * @resume: function pointer to put the device in running state + * @read: function that reads the device data + * + * @name: text name of the device + * @type: device type. enum ext_slave_type + * @id: enum ext_slave_id + * @reg: starting register address to retrieve data. + * @len: length in bytes of the sensor data. Should be 6. + * @endian: byte order of the data. enum ext_slave_endian + * @range: full scale range of the slave ouput: struct tFixPntRange + * + * Defines the functions and information about the slave the mpu3050 needs to + * use the slave device. + * + * @code + * struct ext_slave_descr { + * int (*suspend) (mlsl_handle_t mlsl_handle, + * struct ext_slave_descr *slave, + * struct ext_slave_platform_data *pdata); + * int (*resume) (mlsl_handle_t mlsl_handle, + * struct ext_slave_descr *slave, + * struct ext_slave_platform_data *pdata); + * int (*read) (mlsl_handle_t mlsl_handle, + * struct ext_slave_descr *slave, + * struct ext_slave_platform_data *pdata, + * unsigned char * data); + * + * unsigned char type; + * unsigned char id; + * unsigned char reg; + * unsigned int len; + * unsigned char endian; + * struct tFixPntRange range; + * }; + * @endcode + */ +struct ext_slave_descr { + int (*suspend) (mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*resume) (mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + int (*read) (mlsl_handle_t mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data); + + char *name; + unsigned char type; + unsigned char id; + unsigned char reg; + unsigned int len; + unsigned char endian; + struct tFixPntRange range; +}; + +/** + * struct mpu3050_platform_data - Platform data for the mpu3050 driver + * @int_config: Bits [7:3] of the int config register. + * @orientation: Orientation matrix of the gyroscope + * @level_shifter: 0: VLogic 1: VDD + * @accel: Accel platform data + * @compass: Compass platform data + * + * Contains platform specific information on how to configure the MPU3050 to + * work on this platform. The orientation matricies are 3x3 rotation matricies + * that are applied to the data to rotate from the mounting orientation to the + * platform orientation. The values must be one of 0, 1, or -1 and each row and + * column should have exactly 1 non-zero value. + * + * @code + * struct mpu3050_platform_data { + * unsigned char int_config; + * signed char orientation[MPU_NUM_AXES*MPU_NUM_AXES]; + * unsigned char level_shifter; + * struct ext_slave_platform_data accel; + * struct ext_slave_platform_data compass; + * }; + * @endcode + */ +struct mpu3050_platform_data { + unsigned char int_config; + signed char orientation[MPU_NUM_AXES * MPU_NUM_AXES]; + unsigned char level_shifter; + struct ext_slave_platform_data accel; + struct ext_slave_platform_data compass; +}; + +/* + Accelerometer +*/ +#define get_accel_slave_descr NULL + +#ifdef CONFIG_SENSORS_ADXL346 /* ADI accelerometer */ +struct ext_slave_descr *adxl346_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr adxl346_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_BMA150 /* Bosch accelerometer */ +struct ext_slave_descr *bma150_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr bma150_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_BMA222 /* Bosch 222 accelerometer */ +struct ext_slave_descr *bma222_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr bma222_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_KXSD9 /* Kionix accelerometer */ +struct ext_slave_descr *kxsd9_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr kxsd9_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_KXTF9_MPU /* Kionix accelerometer */ +struct ext_slave_descr *kxtf9_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr kxtf9_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_LIS331DLH /* ST accelerometer */ +struct ext_slave_descr *lis331dlh_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lis331dlh_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_LSM303DLHA /* ST accelerometer */ +struct ext_slave_descr *lsm303dlha_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lsm303dlha_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_MMA8450 /* Freescale accelerometer */ +struct ext_slave_descr *mma8450_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr mma8450_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_MMA8451 /* Freescale accelerometer */ +struct ext_slave_descr *mma8451_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr mma8451_get_slave_descr +#endif + +/* + Compass +*/ +#define get_compass_slave_descr NULL + +#ifdef CONFIG_SENSORS_AK8975_MPU /* AKM compass */ +struct ext_slave_descr *ak8975_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr ak8975_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_AMI304 /* AICHI Steel compass */ +struct ext_slave_descr *ami304_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr ami304_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_HMC5883 /* Honeywell compass */ +struct ext_slave_descr *hmc5883_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hmc5883_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_MMC314X /* MEMSIC compass */ +struct ext_slave_descr *mmc314x_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr mmc314x_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_LSM303DLHM /* ST compass */ +struct ext_slave_descr *lsm303dlhm_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr lsm303dlhm_get_slave_descr +#endif + +#ifdef CONFIG_SENSORS_YAS529 /* Yamaha compass */ +struct ext_slave_descr *yas529_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr yas529_get_slave_descr +#endif + +#endif /* __MPU3050_H_ */ diff --git a/include/linux/regulator/max8907c-regulator.h b/include/linux/regulator/max8907c-regulator.h new file mode 100644 index 000000000000..ddc5f0a60339 --- /dev/null +++ b/include/linux/regulator/max8907c-regulator.h @@ -0,0 +1,46 @@ +/* linux/regulator/max8907c-regulator.h + * + * Functions to access MAX8907C power management chip. + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_REGULATOR_MAX8907C_H +#define __LINUX_REGULATOR_MAX8907C_H + +/* IDs */ +#define MAX8907C_SD1 0 +#define MAX8907C_SD2 1 +#define MAX8907C_SD3 2 +#define MAX8907C_LDO1 3 +#define MAX8907C_LDO2 4 +#define MAX8907C_LDO3 5 +#define MAX8907C_LDO4 6 +#define MAX8907C_LDO5 7 +#define MAX8907C_LDO6 8 +#define MAX8907C_LDO7 9 +#define MAX8907C_LDO8 10 +#define MAX8907C_LDO9 11 +#define MAX8907C_LDO10 12 +#define MAX8907C_LDO11 13 +#define MAX8907C_LDO12 14 +#define MAX8907C_LDO13 15 +#define MAX8907C_LDO14 16 +#define MAX8907C_LDO15 17 +#define MAX8907C_LDO16 18 +#define MAX8907C_LDO17 19 +#define MAX8907C_LDO18 20 +#define MAX8907C_LDO19 21 +#define MAX8907C_LDO20 22 +#define MAX8907C_OUT5V 23 +#define MAX8907C_OUT33V 24 +#define MAX8907C_BBAT 25 +#define MAX8907C_SDBY 26 +#define MAX8907C_VRTC 27 +#define MAX8907C_WLED 27 + +#endif diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h new file mode 100644 index 000000000000..abe50beb1b55 --- /dev/null +++ b/include/linux/regulator/max8952.h @@ -0,0 +1,40 @@ +/* linux/regulator/max8952.h + * + * Functions to access MAX8952 power management chip. + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_REGULATOR_MAX8952_H +#define __LINUX_REGULATOR_MAX8952_H + +/* Regiater map */ +#define MAX8952_REG_MODE0 0x00 +#define MAX8952_REG_MODE1 0x01 +#define MAX8952_REG_MODE2 0x02 +#define MAX8952_REG_MODE3 0x03 +#define MAX8952_REG_CONTROL 0x04 +#define MAX8952_REG_SYNC 0x05 +#define MAX8952_REG_RAMP 0x06 +#define MAX8952_REG_CHIP_ID1 0x08 +#define MAX8952_REG_CHIP_ID2 0x09 + +/* Register bit-mask */ +#define MAX8952_MASK_OUTMODE 0x3F + +/* IDs */ +#define MAX8952_MODE0 0 +#define MAX8952_MODE1 1 +#define MAX8952_MODE2 2 +#define MAX8952_MODE3 3 + +struct max8952_platform_data { + int num_subdevs; + struct platform_device **subdevs; +}; + +#endif diff --git a/include/linux/usb.h b/include/linux/usb.h index 35fe6ab222bb..cd07173c1bc0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -975,6 +975,7 @@ extern int usb_disabled(void); #define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */ #define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */ #define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */ +#define URB_DRIVER_PRIVATE 0x80000000 /* For driver-private use */ struct usb_iso_packet_descriptor { unsigned int offset; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 3b571f1ffbb3..8aaf6872949f 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -233,6 +233,11 @@ struct hc_driver { int (*urb_dequeue)(struct usb_hcd *hcd, struct urb *urb, int status); + /* dma support */ + int (*map_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags); + void (*unmap_urb_for_dma)(struct usb_hcd *hcd, struct urb *urb); + /* hw synch, freeing endpoint resources that urb_dequeue can't */ void (*endpoint_disable)(struct usb_hcd *hcd, struct usb_host_endpoint *ep); @@ -327,6 +332,9 @@ extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb); extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags); extern int usb_hcd_unlink_urb(struct urb *urb, int status); +extern int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags); +extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb); extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status); extern void usb_hcd_flush_endpoint(struct usb_device *udev, diff --git a/include/linux/wakelock.h b/include/linux/wakelock.h index a096d24ada1d..a096d24ada1d 100755..100644 --- a/include/linux/wakelock.h +++ b/include/linux/wakelock.h diff --git a/include/media/ov5650.h b/include/media/ov5650.h new file mode 100644 index 000000000000..cc3ec7194526 --- /dev/null +++ b/include/media/ov5650.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2008 NVIDIA Corporation. All rights reserved. + * + * NVIDIA Corporation and its licensors retain all intellectual property + * and proprietary rights in and to this software and related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA Corporation is strictly prohibited. + */ + +#ifndef __OV5650_H__ +#define __OV5650_H__ + +#include <linux/ioctl.h> /* For IOCTL macros */ + +#define OV5650_IOCTL_SET_MODE _IOW('o', 1, struct ov5650_mode) +#define OV5650_IOCTL_SET_FRAME_LENGTH _IOW('o', 2, __u32) +#define OV5650_IOCTL_SET_COARSE_TIME _IOW('o', 3, __u32) +#define OV5650_IOCTL_SET_GAIN _IOW('o', 4, __u16) +#define OV5650_IOCTL_GET_STATUS _IOR('o', 5, __u8) + +struct ov5650_mode { + int xres; + int yres; + __u32 frame_length; + __u32 coarse_time; + __u16 gain; +}; +#ifdef __KERNEL__ +struct ov5650_platform_data { + int (*power_on)(void); + int (*power_off)(void); + +}; +#endif /* __KERNEL__ */ + +#endif /* __OV5650_H__ */ + diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 3e598e756e54..ba426cd21390 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -40,6 +40,7 @@ source "sound/soc/s3c24xx/Kconfig" source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/txx9/Kconfig" +source "sound/soc/tegra/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index eb183443eee4..d4d25076ea14 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/ obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += txx9/ +obj-$(CONFIG_SND_SOC) += tegra/ diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index bf08282d5ee5..dbe9b52456ef 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -945,6 +945,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, reg &= ~(WM8903_VMID_RES_MASK); reg |= WM8903_VMID_RES_50K; snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); + snd_soc_write(codec, WM8903_BIAS_CONTROL_0, 0xB); break; case SND_SOC_BIAS_STANDBY: diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig new file mode 100644 index 000000000000..3fd917d0297e --- /dev/null +++ b/sound/soc/tegra/Kconfig @@ -0,0 +1,18 @@ +config TEGRA_ALSA + tristate "Tegra ALSA SoC support" + select TEGRA_PCM + select TEGRA_I2S + select TEGRA_IEC + select SND_SOC_WM8903 + help + Say Y if you for ALSA SoC support + +config TEGRA_PCM + tristate "Tegra ALSA pcm callbacks" + +config TEGRA_I2S + tristate "Tegra I2S" + +config TEGRA_IEC + tristate "Tegra IEC" + diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile new file mode 100644 index 000000000000..b1bc3d02109c --- /dev/null +++ b/sound/soc/tegra/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -DNV_DEBUG=0 +obj-$(CONFIG_TEGRA_PCM) += tegra_pcm.o +obj-$(CONFIG_TEGRA_I2S) += tegra_i2s.o +obj-$(CONFIG_TEGRA_ALSA) += tegra_soc.o + + diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c new file mode 100644 index 000000000000..69e07b0c5181 --- /dev/null +++ b/sound/soc/tegra/tegra_i2s.c @@ -0,0 +1,302 @@ +/* + * tegra_i2s.c -- ALSA Soc Audio Layer + * + * (c) 2010 Nvidia Graphics Pvt. Ltd. + * http://www.nvidia.com + * + * (c) 2006 Wolfson Microelectronics PLC. + * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * (c) 2004-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "tegra_soc.h" + +static void *das_base = IO_ADDRESS(TEGRA_APB_MISC_BASE); + +static inline unsigned long das_readl(unsigned long offset) +{ + return readl(das_base + offset); +} + +static inline void das_writel(unsigned long value, unsigned long offset) +{ + writel(value, das_base + offset); +} + +static int tegra_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct tegra_runtime_data *prtd = runtime->private_data; + int ret=0; + int val; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val = I2S_BIT_SIZE_16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val = I2S_BIT_SIZE_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val = I2S_BIT_SIZE_32; + break; + default: + ret =-EINVAL; + goto err; + } + + i2s_set_bit_size(I2S_IFC, val); + + switch (params_rate(params)) { + case 8000: + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + val = params_rate(params); + break; + default: + ret = -EINVAL; + goto err; + } + + i2s_set_channel_bit_count(I2S_IFC, val, clk_get_rate(prtd->i2s_clk)); + + return 0; + +err: + return ret; +} + + +static int tegra_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + int val1; + int val2; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + val1 = 1; + break; + case SND_SOC_DAIFMT_CBM_CFM: + val1= 0; + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + /* Tegra does not support different combinations of + * master and slave for FSYNC and BCLK */ + default: + return -EINVAL; + } + + i2s_set_master(I2S_IFC, val1); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + val1 = I2S_BIT_FORMAT_DSP; + val2 = 0; + break; + case SND_SOC_DAIFMT_DSP_B: + val1 = I2S_BIT_FORMAT_DSP; + val2 = 1; + break; + case SND_SOC_DAIFMT_I2S: + val1 = I2S_BIT_FORMAT_I2S; + val2 = 0; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val1 = I2S_BIT_FORMAT_RJM; + val2 = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + val1 = I2S_BIT_FORMAT_LJM; + val2 = 0; + break; + default: + return -EINVAL; + } + + i2s_set_bit_format(I2S_IFC,val1); + i2s_set_left_right_control_polarity(I2S_IFC,val2); + + /* Clock inversion */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* frame inversion not valid for DSP modes */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + /* aif1 |= WM8903_AIF_BCLK_INV; */ + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + /* aif1 |= WM8903_AIF_BCLK_INV | + * WM8903_AIF_LRCLK_INV; */ + break; + case SND_SOC_DAIFMT_IB_NF: + /* aif1 |= WM8903_AIF_BCLK_INV; */ + break; + case SND_SOC_DAIFMT_NB_IF: + /* aif1 |= WM8903_AIF_LRCLK_INV; */ + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tegra_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + return 0; +} + +static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_STOP: + 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 tegra_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void tegra_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ +} + +static int tegra_i2s_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + /* DAC1 -> DAP1, DAC1 master, DAP2 bypass */ + das_writel(0, APB_MISC_DAS_DAP_CTRL_SEL_0); + das_writel(0, APB_MISC_DAS_DAC_INPUT_DATA_CLK_SEL_0); + i2s_enable_fifos(I2S_IFC, 0); + i2s_set_left_right_control_polarity(I2S_IFC, 0); /* default */ + i2s_set_master(I2S_IFC, 1); /* set as master */ + i2s_set_fifo_mode(I2S_IFC, FIFO1, 1); /* FIFO1 is TX */ + i2s_set_fifo_mode(I2S_IFC, FIFO2, 0); /* FIFO2 is RX */ + i2s_set_bit_format(I2S_IFC, I2S_BIT_FORMAT_I2S); + i2s_set_bit_size(I2S_IFC, I2S_BIT_SIZE_16); + i2s_set_fifo_format(I2S_IFC, I2S_FIFO_PACKED); + return 0; +} + +static struct snd_soc_dai_ops tegra_i2s_dai_ops = { + .startup = tegra_i2s_startup, + .shutdown = tegra_i2s_shutdown, + .trigger = tegra_i2s_trigger, + .hw_params = tegra_i2s_hw_params, + .set_fmt = tegra_i2s_set_dai_fmt, + .set_sysclk = tegra_i2s_set_dai_sysclk, +}; + +struct snd_soc_dai tegra_i2s_dai = { + .name = "tegra-i2s", + .id = 0, + .probe = tegra_i2s_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = TEGRA_SAMPLE_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = TEGRA_SAMPLE_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &tegra_i2s_dai_ops, +}; +EXPORT_SYMBOL_GPL(tegra_i2s_dai); + +static int tegra_i2s_driver_probe(struct platform_device *dev) +{ + int ret; + + tegra_i2s_dai.dev = &dev->dev; + tegra_i2s_dai.private_data = NULL; + ret = snd_soc_register_dai(&tegra_i2s_dai); + return ret; +} + + +static int __devexit tegra_i2s_driver_remove(struct platform_device *dev) +{ + snd_soc_unregister_dai(&tegra_i2s_dai); + return 0; +} + +static struct platform_driver tegra_i2s_driver = { + .probe = tegra_i2s_driver_probe, + .remove = __devexit_p(tegra_i2s_driver_remove), + .driver = { + .name = "i2s", + .owner = THIS_MODULE, + }, +}; + +static int __init tegra_i2s_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&tegra_i2s_driver); + return ret; +} +module_init(tegra_i2s_init); + +static void __exit tegra_i2s_exit(void) +{ + platform_driver_unregister(&tegra_i2s_driver); +} +module_exit(tegra_i2s_exit); + +/* Module information */ +MODULE_DESCRIPTION("Tegra I2S SoC interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c new file mode 100644 index 000000000000..6ec095d6a3a8 --- /dev/null +++ b/sound/soc/tegra/tegra_pcm.c @@ -0,0 +1,499 @@ +/* + * tegra_pcm.c -- ALSA Soc Audio Layer + * + * (c) 2010 Nvidia Graphics Pvt. Ltd. + * http://www.nvidia.com + * + * (c) 2006 Wolfson Microelectronics PLC. + * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * (c) 2004-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "tegra_soc.h" + +#define PLAYBACK_STARTED true +#define PLAYBACK_STOPPED false + +static void start_i2s_playback(void) +{ + i2s_fifo_set_attention_level(I2S_IFC, I2S_FIFO_TX, + I2S_FIFO_ATN_LVL_FOUR_SLOTS); + i2s_fifo_enable(I2S_IFC, I2S_FIFO_TX, 1); +} + +static void stop_i2s_playback(void) +{ + i2s_set_fifo_irq_on_err(I2S_IFC, I2S_FIFO_TX, 0); + i2s_set_fifo_irq_on_qe(I2S_IFC, I2S_FIFO_TX, 0); + i2s_fifo_enable(I2S_IFC, I2S_FIFO_TX, 0); + while (i2s_get_status(I2S_IFC) & I2S_I2S_FIFO_TX_BUSY); +} + +static void tegra_pcm_play(struct tegra_runtime_data *prtd) +{ + static int reqid = 0; + struct snd_pcm_substream *substream = prtd->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dma_buffer *buf = &substream->dma_buffer; + + if (runtime->dma_addr) { + prtd->size = frames_to_bytes(runtime, runtime->period_size); + if (reqid == 0) { + prtd->dma_req1.source_addr = buf->addr + + + frames_to_bytes(runtime,prtd->dma_pos); + prtd->dma_req1.size = prtd->size; + tegra_dma_enqueue_req(prtd->dma_chan, &prtd->dma_req1); + reqid = 1; + } else { + prtd->dma_req2.source_addr = buf->addr + + + frames_to_bytes(runtime,prtd->dma_pos); + prtd->dma_req2.size = prtd->size; + tegra_dma_enqueue_req(prtd->dma_chan, &prtd->dma_req2); + reqid = 0; + } + } + + prtd->dma_pos += runtime->period_size; + if (prtd->dma_pos >= runtime->buffer_size) { + prtd->dma_pos = 0; + } + +} + +static void dma_tx_complete_callback (struct tegra_dma_req *req) +{ + struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev; + struct snd_pcm_substream *substream = prtd->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (++prtd->period_index >= runtime->periods) { + prtd->period_index = 0; + } + + snd_pcm_period_elapsed(substream); + tegra_pcm_play(prtd); +} + +static void setup_dma_tx_request(struct tegra_dma_req *req) +{ + memset(req, 0, sizeof(*req)); + req->complete = dma_tx_complete_callback; + req->to_memory = false; + req->dest_addr = i2s_get_fifo_phy_base(I2S_IFC, I2S_FIFO_TX); + req->dest_wrap = 4; + req->source_bus_width = 32; + req->source_wrap = 0; + req->dest_bus_width = 32; + req->req_sel = I2S_IFC ? 1 : 2; /* 1 = I2S2, 2 = I2S1 */ +} + +/* recording */ +static void start_i2s_capture(void) +{ + i2s_fifo_set_attention_level(I2S_IFC, I2S_FIFO_RX, + I2S_FIFO_ATN_LVL_FOUR_SLOTS); + i2s_fifo_enable(I2S_IFC, I2S_FIFO_RX, 1); +} + +static void stop_i2s_capture(void) +{ + i2s_set_fifo_irq_on_err(I2S_IFC, I2S_FIFO_RX, 0); + i2s_set_fifo_irq_on_qe(I2S_IFC, I2S_FIFO_RX, 0); + i2s_fifo_enable(I2S_IFC, I2S_FIFO_RX, 0); + while (i2s_get_status(I2S_IFC) & I2S_I2S_FIFO_RX_BUSY); +} + +static void tegra_pcm_capture(struct tegra_runtime_data *prtd) +{ + static int reqid = 0; + struct snd_pcm_substream *substream = prtd->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dma_buffer *buf = &substream->dma_buffer; + + if (runtime->dma_addr) { + prtd->size = frames_to_bytes(runtime, runtime->period_size); + if (reqid == 0) { + prtd->dma_req1.dest_addr = buf->addr + + + frames_to_bytes(runtime,prtd->dma_pos); + prtd->dma_req1.size = prtd->size; + tegra_dma_enqueue_req(prtd->dma_chan, &prtd->dma_req1); + reqid = 1; + } else { + prtd->dma_req2.dest_addr = buf->addr + + + frames_to_bytes(runtime,prtd->dma_pos); + prtd->dma_req2.size = prtd->size; + tegra_dma_enqueue_req(prtd->dma_chan, &prtd->dma_req2); + reqid = 0; + } + } + + prtd->dma_pos += runtime->period_size; + if (prtd->dma_pos >= runtime->buffer_size) { + prtd->dma_pos = 0; + } + +} + +static void dma_rx_complete_callback(struct tegra_dma_req *req) +{ + struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev; + struct snd_pcm_substream *substream = prtd->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (++prtd->period_index >= runtime->periods) { + prtd->period_index = 0; + } + + snd_pcm_period_elapsed(substream); + tegra_pcm_capture(prtd); +} + +static void setup_dma_rx_request(struct tegra_dma_req *req) +{ + memset(req, 0, sizeof(*req)); + req->complete = dma_rx_complete_callback; + req->to_memory = true; + req->source_addr = i2s_get_fifo_phy_base(I2S_IFC, I2S_FIFO_RX); + req->dest_wrap = 0; + req->source_bus_width = 32; + req->source_wrap = 4; + req->dest_bus_width = 32; + req->req_sel = I2S_IFC ? 1 : 2; /* 1 = I2S2, 2 = I2S1 */ +} + +static const struct snd_pcm_hardware tegra_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | \ + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | \ + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID , + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (PAGE_SIZE * 8), + .period_bytes_min = 1024, + .period_bytes_max = (PAGE_SIZE), + .periods_min = 2, + .periods_max = 8, + .fifo_size = 4, +}; + +static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + return 0; +} + +static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} + +static int tegra_pcm_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct tegra_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + prtd->state = STATE_INIT; + tegra_pcm_play(prtd); /* dma enqueue req1 */ + tegra_pcm_play(prtd); /* dma enqueue req2 */ + start_i2s_playback(); + } else if (prtd->state != STATE_INIT) { + /* start recording */ + prtd->state = STATE_INIT; + tegra_pcm_capture(prtd); /* dma enqueue req1 */ + tegra_pcm_capture(prtd); /* dma enqueue req2 */ + start_i2s_capture(); + } + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + case SNDRV_PCM_TRIGGER_STOP: + prtd->state = STATE_ABORT; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct tegra_runtime_data *prtd = runtime->private_data; + int size; + size = prtd->period_index * runtime->period_size; + return (size); +} + +static int tegra_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct tegra_runtime_data *prtd; + int ret=0; + + prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + + memset(prtd, 0, sizeof(*prtd)); + runtime->private_data = prtd; + prtd->substream = substream; + + /* Enable the DAP outputs */ + tegra_pinmux_set_tristate(TEGRA_PINGROUP_DAP1,TEGRA_TRI_NORMAL); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV1,TEGRA_TRI_NORMAL); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV2,TEGRA_TRI_NORMAL); + + /* Setup I2S clocks */ + prtd->i2s_clk = i2s_get_clock_by_name(I2S_NAME); + if (!prtd->i2s_clk) { + pr_err("%s: could not get i2s1 clock\n", __func__); + return -EIO; + } + + clk_set_rate(prtd->i2s_clk, I2S_CLK); + if (clk_enable(prtd->i2s_clk)) { + pr_err("%s: failed to enable i2s1 clock\n", __func__); + return -EIO; + } + + i2s_set_channel_bit_count(I2S_IFC, TEGRA_DEFAULT_SR, + clk_get_rate(prtd->i2s_clk)); + + prtd->dap_mclk = i2s_get_clock_by_name("clk_dev1"); + if (!prtd->dap_mclk) { + pr_err("%s: could not get DAP clock\n", __func__); + return -EIO; + } + clk_enable(prtd->dap_mclk); + + prtd->audio_sync_clk = i2s_get_clock_by_name("audio_2x"); + if (!prtd->audio_sync_clk) { + pr_err("%s: could not get audio_2x clock\n", __func__); + return -EIO; + } + clk_enable(prtd->audio_sync_clk); + + prtd->state = STATE_INVALID; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + setup_dma_tx_request(&prtd->dma_req1); + setup_dma_tx_request(&prtd->dma_req2); + } else { + setup_dma_rx_request(&prtd->dma_req1); + setup_dma_rx_request(&prtd->dma_req2); + } + + prtd->dma_req1.dev = prtd; + prtd->dma_req2.dev = prtd; + + prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); + if (IS_ERR(prtd->dma_chan)) { + pr_err("%s: could not allocate DMA channel for I2S: %ld\n", + __func__, PTR_ERR(prtd->dma_chan)); + ret = PTR_ERR(prtd->dma_chan); + goto fail; + } + + /* Set HW params now that initialization is complete */ + snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); + + goto end; + +fail: + prtd->state = STATE_EXIT; + + if (prtd->dma_chan) { + tegra_dma_flush(prtd->dma_chan); + tegra_dma_free_channel(prtd->dma_chan); + } + /* Tristate the DAP pinmux */ + tegra_pinmux_set_tristate(TEGRA_PINGROUP_DAP1,TEGRA_TRI_TRISTATE); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV1,TEGRA_TRI_TRISTATE); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV2,TEGRA_TRI_TRISTATE); + + kfree(prtd); + +end: + return ret; +} + +static int tegra_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct tegra_runtime_data *prtd = runtime->private_data; + + if (!prtd) { + printk(KERN_ERR "tegra_pcm_close called with prtd == NULL\n"); + return 0; + } + + prtd->state = STATE_EXIT; + + if (prtd->dma_chan) { + tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req1); + tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req2); + stop_i2s_playback(); + tegra_dma_flush(prtd->dma_chan); + tegra_dma_free_channel(prtd->dma_chan); + prtd->dma_chan = NULL; + } + + kfree(prtd); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_DAP1,TEGRA_TRI_TRISTATE); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV1,TEGRA_TRI_TRISTATE); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV2,TEGRA_TRI_TRISTATE); + + return 0; +} + +static int tegra_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops tegra_pcm_ops = { + .open = tegra_pcm_open, + .close = tegra_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = tegra_pcm_hw_params, + .hw_free = tegra_pcm_hw_free, + .prepare = tegra_pcm_prepare, + .trigger = tegra_pcm_trigger, + .pointer = tegra_pcm_pointer, + .mmap = tegra_pcm_mmap, +}; + +static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = tegra_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + buf->bytes = size; + return 0; +} + +static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static void tegra_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + buf = &substream->dma_buffer; + if (!buf) { + printk(KERN_ERR "no buffer %d \n",stream); + continue; + } + tegra_pcm_deallocate_dma_buffer(pcm ,stream); + } + +} + +static u64 tegra_dma_mask = DMA_BIT_MASK(32); + +static int tegra_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &tegra_dma_mask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = tegra_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = tegra_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } +out: + return ret; +} + +struct snd_soc_platform tegra_soc_platform = { + .name = "tegra-audio", + .pcm_ops = &tegra_pcm_ops, + .pcm_new = tegra_pcm_new, + .pcm_free = tegra_pcm_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(tegra_soc_platform); + +static int __init tegra_soc_platform_init(void) +{ + return snd_soc_register_platform(&tegra_soc_platform); +} +module_init(tegra_soc_platform_init); + +static void __exit tegra_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&tegra_soc_platform); +} +module_exit(tegra_soc_platform_exit); + +MODULE_DESCRIPTION("Tegra PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_soc.c b/sound/soc/tegra/tegra_soc.c new file mode 100644 index 000000000000..5dbf3c8eb478 --- /dev/null +++ b/sound/soc/tegra/tegra_soc.c @@ -0,0 +1,384 @@ +/* + * tegra_soc.c -- SoC audio for tegra + * + * (c) 2010 Nvidia Graphics Pvt. Ltd. + * http://www.nvidia.com + * + * Copyright 2007 Wolfson Microelectronics PLC. + * Author: Graeme Gregory + * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include "../codecs/wm8903.h" +#include "tegra_soc.h" +#include <mach/audio.h> + +static struct platform_device *tegra_snd_device; +static int tegra_jack_func; +static int tegra_spk_func; + +#define TEGRA_HP 0 +#define TEGRA_MIC 1 +#define TEGRA_LINE 2 +#define TEGRA_HEADSET 3 +#define TEGRA_HP_OFF 4 +#define TEGRA_SPK_ON 0 +#define TEGRA_SPK_OFF 1 + +/* codec register values */ +#define B07_INEMUTE 7 +#define B06_VOL_M3DB 6 +#define B00_IN_VOL 0 +#define B00_INR_ENA 0 +#define B01_INL_ENA 1 +#define R06_MICBIAS_CTRL_0 6 +#define B07_MICDET_HYST_ENA 7 +#define B04_MICDET_THR 4 +#define B02_MICSHORT_THR 2 +#define B01_MICDET_ENA 1 +#define B00_MICBIAS_ENA 0 +#define B15_DRC_ENA 15 +#define B03_DACL_ENA 3 +#define B02_DACR_ENA 2 +#define B01_ADCL_ENA 1 +#define B00_ADCR_ENA 0 +#define B06_IN_CM_ENA 6 +#define B04_IP_SEL_N 4 +#define B02_IP_SEL_P 2 +#define B00_MODE 0 +#define B06_AIF_ADCL 7 +#define B06_AIF_ADCR 6 +#define B05_ADC_HPF_CUT 5 +#define B04_ADC_HPF_ENA 4 +#define B01_ADCL_DATINV 1 +#define B00_ADCR_DATINV 0 +#define R20_SIDETONE_CTRL 32 +#define R29_DRC_1 41 +#define SET_REG_VAL(r,m,l,v) (((r)&(~((m)<<(l))))|(((v)&(m))<<(l))) + + +static void tegra_ext_control(struct snd_soc_codec *codec) +{ + /* set up jack connection */ + switch (tegra_jack_func) { + case TEGRA_HP: + /* set = unmute headphone */ + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_disable_pin(codec, "Headset Jack"); + break; + case TEGRA_MIC: + /* reset = mute headphone */ + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_disable_pin(codec, "Headset Jack"); + break; + case TEGRA_LINE: + snd_soc_dapm_disable_pin(codec, "Mic Jack"); + snd_soc_dapm_enable_pin(codec, "Line Jack"); + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_disable_pin(codec, "Headset Jack"); + break; + case TEGRA_HEADSET: + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Headset Jack"); + break; + } + + if (tegra_spk_func == TEGRA_SPK_ON) { + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + } else { + snd_soc_dapm_disable_pin(codec, "Ext Spk"); + } + /* signal a DAPM event */ + snd_soc_dapm_sync(codec); +} + +static int tegra_hifi_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_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int err; + struct snd_soc_codec *codec = codec_dai->codec; + int CtrlReg = 0; + int VolumeCtrlReg = 0; + int SidetoneCtrlReg = 0; + int SideToneAtenuation = 0; + + err = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + printk(KERN_ERR "codec_dai fmt not set \n"); + return err; + } + + err = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS); + if (err < 0) { + printk(KERN_ERR "cpu_dai fmt not set \n"); + return err; + } + err = snd_soc_dai_set_sysclk(codec_dai, 0, I2S_CLK, SND_SOC_CLOCK_IN); + + if (err<0) { + printk(KERN_ERR "codec_dai clock not set\n"); + return err; + } + err = snd_soc_dai_set_sysclk(cpu_dai, 0, I2S_CLK, SND_SOC_CLOCK_IN); + + if (err<0) { + printk(KERN_ERR "cpu_dai clock not set\n"); + return err; + } + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) { + snd_soc_write(codec, WM8903_ANALOGUE_LEFT_INPUT_0, 0X7); + snd_soc_write(codec, WM8903_ANALOGUE_RIGHT_INPUT_0, 0X7); + // Mic Bias enable + CtrlReg = (0x1<<B00_MICBIAS_ENA) | (0x1<<B01_MICDET_ENA); + snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, CtrlReg); + // Enable DRC + CtrlReg = snd_soc_read(codec, WM8903_DRC_0); + CtrlReg |= (1<<B15_DRC_ENA); + snd_soc_write(codec, WM8903_DRC_0, CtrlReg); + // Single Ended Mic + CtrlReg = (0x0<<B06_IN_CM_ENA) | + (0x0<<B00_MODE) | (0x0<<B04_IP_SEL_N) + | (0x1<<B02_IP_SEL_P); + VolumeCtrlReg = (0x5 << B00_IN_VOL); + // Mic Setting + snd_soc_write(codec, WM8903_ANALOGUE_LEFT_INPUT_1, CtrlReg); + snd_soc_write(codec, WM8903_ANALOGUE_RIGHT_INPUT_1, CtrlReg); + // voulme for single ended mic + snd_soc_write(codec, WM8903_ANALOGUE_LEFT_INPUT_0, + VolumeCtrlReg); + snd_soc_write(codec, WM8903_ANALOGUE_RIGHT_INPUT_0, + VolumeCtrlReg); + // replicate mic setting on both channels + CtrlReg = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_0); + CtrlReg = SET_REG_VAL(CtrlReg, 0x1, B06_AIF_ADCR, 0x0); + CtrlReg = SET_REG_VAL(CtrlReg, 0x1, B06_AIF_ADCL, 0x0); + snd_soc_write(codec, WM8903_AUDIO_INTERFACE_0, CtrlReg); + // Enable analog inputs + CtrlReg = (0x1<<B01_INL_ENA) | (0x1<<B00_INR_ENA); + snd_soc_write(codec, WM8903_POWER_MANAGEMENT_0, CtrlReg); + // ADC Settings + CtrlReg = snd_soc_read(codec, WM8903_ADC_DIGITAL_0); + CtrlReg |= (0x1<<B04_ADC_HPF_ENA); + snd_soc_write(codec, WM8903_ADC_DIGITAL_0, CtrlReg); + SidetoneCtrlReg = 0; + snd_soc_write(codec, R20_SIDETONE_CTRL, SidetoneCtrlReg); + // Enable ADC + CtrlReg = snd_soc_read(codec, WM8903_POWER_MANAGEMENT_6); + CtrlReg |= (0x1<<B00_ADCR_ENA)|(0x1<<B01_ADCL_ENA); + snd_soc_write(codec, WM8903_POWER_MANAGEMENT_6, CtrlReg); + // Enable Sidetone + SidetoneCtrlReg = (0x1<<2) | (0x2<<0); + SideToneAtenuation = 12 ; // sidetone 0 db + SidetoneCtrlReg |= (SideToneAtenuation<<8) + | (SideToneAtenuation<<4); + snd_soc_write(codec, R20_SIDETONE_CTRL, SidetoneCtrlReg); + CtrlReg = snd_soc_read(codec, R29_DRC_1); + CtrlReg |= 0x3; //mic volume 18 db + snd_soc_write(codec, R29_DRC_1, CtrlReg); + } + + return 0; +} + +static struct snd_soc_ops tegra_hifi_ops = { + .hw_params = tegra_hifi_hw_params, +}; + + +static int tegra_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = tegra_jack_func; + return 0; +} + +static int tegra_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (tegra_jack_func == ucontrol->value.integer.value[0]) + return 0; + + tegra_jack_func = ucontrol->value.integer.value[0]; + tegra_ext_control(codec); + return 1; +} + +static int tegra_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = tegra_spk_func; + return 0; +} + +static int tegra_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + + if (tegra_spk_func == ucontrol->value.integer.value[0]) + return 0; + + tegra_spk_func = ucontrol->value.integer.value[0]; + tegra_ext_control(codec); + return 1; +} + +/*tegra machine dapm widgets */ +static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_LINE("Line Jack", NULL), + SND_SOC_DAPM_HP("Headset Jack", NULL), +}; + +/* Tegra machine audio map (connections to the codec pins) */ +static const struct snd_soc_dapm_route audio_map[] = { + + /* headset Jack - in = micin, out = LHPOUT*/ + {"Headset Jack", NULL, "HPOUTL"}, + + /* headphone connected to LHPOUT1, RHPOUT1 */ + {"Headphone Jack", NULL, "HPOUTR"}, {"Headphone Jack", NULL, "HPOUTL"}, + + /* speaker connected to LOUT, ROUT */ + {"Ext Spk", NULL, "LINEOUTR"}, {"Ext Spk", NULL, "LINEOUTL"}, + + /* mic is connected to MICIN (via right channel of headphone jack) */ + {"IN1L", NULL, "Mic Jack"}, + + /* Same as the above but no mic bias for line signals */ + {"IN2L", NULL, "Line Jack"}, +}; + +static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", + "Off" + }; +static const char *spk_function[] = {"On", "Off"}; +static const struct soc_enum tegra_enum[] = { + SOC_ENUM_SINGLE_EXT(5, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const struct snd_kcontrol_new wm8903_tegra_controls[] = { + SOC_ENUM_EXT("Jack Function", tegra_enum[0], tegra_get_jack, + tegra_set_jack), + SOC_ENUM_EXT("Speaker Function", tegra_enum[1], tegra_get_spk, + tegra_set_spk), +}; + + +static int tegra_codec_init(struct snd_soc_codec *codec) +{ + int err; + + /* Add tegra specific controls */ + err = snd_soc_add_controls(codec, wm8903_tegra_controls, + ARRAY_SIZE(wm8903_tegra_controls)); + if (err < 0) + return err; + + /* Add tegra specific widgets */ + snd_soc_dapm_new_controls(codec, wm8903_dapm_widgets, + ARRAY_SIZE(wm8903_dapm_widgets)); + + /* Set up tegra specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* Default to HP output */ + tegra_jack_func = TEGRA_HP; + tegra_spk_func = TEGRA_SPK_ON; + tegra_ext_control(codec); + + snd_soc_dapm_sync(codec); + + return 0; +} + +extern struct snd_soc_dai tegra_i2s_dai; +extern struct snd_soc_platform tegra_soc_platform; + +static struct snd_soc_dai_link tegra_soc_dai = { + .name = "WM8903", + .stream_name = "WM8903 HiFi", + .cpu_dai = &tegra_i2s_dai, + .codec_dai = &wm8903_dai, + .init = tegra_codec_init, + .ops = &tegra_hifi_ops, +}; + +static struct snd_soc_card tegra_snd_soc = { + .name = "tegra", + .platform = &tegra_soc_platform, + .dai_link = &tegra_soc_dai, + .num_links = 1, +}; + +struct tegra_setup_data { + int i2c_bus; + unsigned short i2c_address; +}; + +static struct snd_soc_device tegra_snd_devdata = { + .card = &tegra_snd_soc, + .codec_dev = &soc_codec_dev_wm8903, +}; + +static int __init tegra_init(void) +{ + int ret; + struct tegra_setup_data tegra_setup; + + tegra_snd_device = platform_device_alloc("soc-audio", -1); + if (!tegra_snd_device) + return -ENOMEM; + + memset(&tegra_setup,0,sizeof(struct tegra_setup_data)); + platform_set_drvdata(tegra_snd_device, &tegra_snd_devdata); + tegra_snd_devdata.dev = &tegra_snd_device->dev; + ret = platform_device_add(tegra_snd_device); + if (ret) { + printk(KERN_ERR "audio device could not be added \n"); + platform_device_put(tegra_snd_device); + return ret; + } + + return ret; +} + +static void __exit tegra_exit(void) +{ + platform_device_unregister(tegra_snd_device); +} + +module_init(tegra_init); +module_exit(tegra_exit); + +/* Module information */ +MODULE_DESCRIPTION("Tegra ALSA SoC"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h new file mode 100644 index 000000000000..5cb2a2ccf851 --- /dev/null +++ b/sound/soc/tegra/tegra_soc.h @@ -0,0 +1,100 @@ +/* + * tegra_soc.h -- SoC audio for tegra + * + * (c) 2010 Nvidia Graphics Pvt. Ltd. + * http://www.nvidia.com + * + * Copyright 2007 Wolfson Microelectronics PLC. + * Author: Graeme Gregory + * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __TEGRA_AUDIO__ +#define __TEGRA_AUDIO__ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/jiffies.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/kthread.h> +#include <linux/moduleparam.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <mach/iomap.h> +#include <mach/tegra2_i2s.h> +#include <mach/irqs.h> +#include <mach/pinmux.h> +#include <mach/audio.h> +#include <mach/dma.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc-dapm.h> +#include <sound/soc-dai.h> +#include <sound/tlv.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/hardware/scoop.h> + +#define STATE_INIT 0 +#define STATE_ABORT 1 +#define STATE_EXIT 2 +#define STATE_EXITED 3 +#define STATE_INVALID 4 + +#define APB_MISC_DAS_DAP_CTRL_SEL_0 0xc00 +#define APB_MISC_DAS_DAC_INPUT_DATA_CLK_SEL_0 0xc40 + +#define FIFO1 0 +#define FIFO2 1 + +#define I2S_IFC 0 +#define I2S_INT INT_I2S1 +#define I2S_NAME "i2s1" +#define I2S_FIFO_TX FIFO1 +#define I2S_I2S_FIFO_TX_BUSY I2S_I2S_STATUS_FIFO1_BSY +#define I2S_I2S_FIFO_TX_QS I2S_I2S_STATUS_QS_FIFO1 +#define I2S_FIFO_RX FIFO2 +#define I2S_I2S_FIFO_RX_BUSY I2S_I2S_STATUS_FIFO2_BSY +#define I2S_I2S_FIFO_RX_QS I2S_I2S_STATUS_QS_FIFO2 + +#define I2S_CLK 11289600 +#define TEGRA_DEFAULT_SR 44100 + +#define TEGRA_SAMPLE_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +struct tegra_dma_channel; + +struct tegra_runtime_data { + struct snd_pcm_substream *substream; + int size; + int dma_pos; + struct tegra_dma_req dma_req1, dma_req2; + volatile int state; + int period_index; + struct tegra_dma_channel *dma_chan; + struct clk *i2s_clk; + struct clk *dap_mclk; + struct clk *audio_sync_clk; +}; + +#endif |