summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/configs/tegra_defconfig1548
-rw-r--r--arch/arm/configs/tegra_whistler_android_defconfig2384
-rw-r--r--arch/arm/include/asm/cacheflush.h6
-rw-r--r--arch/arm/include/asm/pgtable.h25
-rw-r--r--arch/arm/include/asm/tlbflush.h12
-rw-r--r--arch/arm/mach-tegra/Kconfig5
-rw-r--r--arch/arm/mach-tegra/Makefile30
-rw-r--r--arch/arm/mach-tegra/board-harmony-panel.c10
-rw-r--r--arch/arm/mach-tegra/board-ventana-kbc.c188
-rw-r--r--arch/arm/mach-tegra/board-ventana-panel.c84
-rw-r--r--arch/arm/mach-tegra/board-ventana-pinmux.c16
-rw-r--r--arch/arm/mach-tegra/board-ventana-power.c38
-rw-r--r--arch/arm/mach-tegra/board-ventana-sdhci.c111
-rw-r--r--arch/arm/mach-tegra/board-ventana-sensors.c292
-rw-r--r--arch/arm/mach-tegra/board-ventana.c371
-rw-r--r--arch/arm/mach-tegra/board-ventana.h17
-rw-r--r--arch/arm/mach-tegra/board-whistler-kbc.c182
-rw-r--r--arch/arm/mach-tegra/board-whistler-panel.c231
-rw-r--r--arch/arm/mach-tegra/board-whistler-pinmux.c166
-rw-r--r--arch/arm/mach-tegra/board-whistler-power.c226
-rw-r--r--arch/arm/mach-tegra/board-whistler-sdhci.c128
-rw-r--r--arch/arm/mach-tegra/board-whistler-sensors.c28
-rw-r--r--arch/arm/mach-tegra/board-whistler.c236
-rw-r--r--arch/arm/mach-tegra/board-whistler.h26
-rw-r--r--arch/arm/mach-tegra/board.h18
-rw-r--r--arch/arm/mach-tegra/common.c59
-rw-r--r--arch/arm/mach-tegra/dma.c25
-rw-r--r--arch/arm/mach-tegra/dvfs.h3
-rw-r--r--arch/arm/mach-tegra/fuse.c27
-rw-r--r--arch/arm/mach-tegra/fuse.h3
-rw-r--r--arch/arm/mach-tegra/headsmp-t2.S52
-rw-r--r--arch/arm/mach-tegra/headsmp.S83
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h20
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h3
-rw-r--r--arch/arm/mach-tegra/include/mach/kbc.h58
-rw-r--r--arch/arm/mach-tegra/include/mach/memory.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/sdhci.h11
-rw-r--r--arch/arm/mach-tegra/include/mach/spi.h42
-rw-r--r--arch/arm/mach-tegra/include/mach/system.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra2_i2s.h189
-rw-r--r--arch/arm/mach-tegra/include/mach/vmalloc.h2
-rw-r--r--arch/arm/mach-tegra/spi_tegra_slave.c860
-rw-r--r--arch/arm/mach-tegra/syncpt.c100
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c1
-rw-r--r--arch/arm/mach-tegra/tegra2_dvfs.c55
-rw-r--r--arch/arm/mach-tegra/tegra2_i2s.c392
-rw-r--r--arch/arm/mach-tegra/tegra2_speedo.c140
-rw-r--r--arch/arm/mach-tegra/usb_phy.c23
-rw-r--r--arch/arm/mm/copypage-v4mc.c2
-rw-r--r--arch/arm/mm/copypage-v6.c2
-rw-r--r--arch/arm/mm/copypage-xscale.c2
-rw-r--r--arch/arm/mm/dma-mapping.c6
-rw-r--r--arch/arm/mm/fault-armv.c6
-rw-r--r--arch/arm/mm/flush.c24
-rw-r--r--arch/arm/tools/mach-types1
-rw-r--r--drivers/hwmon/Kconfig12
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/nct1008.c271
-rw-r--r--[-rwxr-xr-x]drivers/i2c/busses/i2c-tegra.c10
-rw-r--r--drivers/i2c/i2c-core.c4
-rw-r--r--drivers/input/keyboard/Kconfig7
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/gpio_keys.c3
-rw-r--r--drivers/input/keyboard/tegra-kbc.c810
-rw-r--r--drivers/input/touchscreen/Kconfig7
-rw-r--r--drivers/input/touchscreen/Makefile1
-rwxr-xr-xdrivers/input/touchscreen/atmel_maxtouch.c2056
-rw-r--r--drivers/media/video/tegra/Kconfig7
-rw-r--r--drivers/media/video/tegra/Makefile6
-rw-r--r--drivers/media/video/tegra/avp/avp.c29
-rw-r--r--drivers/media/video/tegra/ov5650.c765
-rw-r--r--drivers/mfd/Kconfig10
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/max8907c.c251
-rw-r--r--drivers/mfd/tps6586x.c36
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile6
-rw-r--r--drivers/misc/akm8975.c12
-rw-r--r--drivers/misc/bcm4329_rfkill.c186
-rwxr-xr-xdrivers/misc/mpu3050/Kconfig54
-rwxr-xr-xdrivers/misc/mpu3050/Makefile37
-rwxr-xr-xdrivers/misc/mpu3050/README138
-rwxr-xr-xdrivers/misc/mpu3050/accel/kxtf9.c144
-rwxr-xr-xdrivers/misc/mpu3050/compass/ak8975.c146
-rwxr-xr-xdrivers/misc/mpu3050/log.h287
-rwxr-xr-xdrivers/misc/mpu3050/mldl_cfg.c872
-rwxr-xr-xdrivers/misc/mpu3050/mldl_cfg.h98
-rwxr-xr-xdrivers/misc/mpu3050/mlos-kernel.c92
-rwxr-xr-xdrivers/misc/mpu3050/mlos.h78
-rwxr-xr-xdrivers/misc/mpu3050/mlsl-kernel.c171
-rwxr-xr-xdrivers/misc/mpu3050/mlsl.h81
-rwxr-xr-xdrivers/misc/mpu3050/mltypes.h215
-rwxr-xr-xdrivers/misc/mpu3050/mpu-dev.c835
-rwxr-xr-xdrivers/misc/mpu3050/mpu-i2c.c195
-rwxr-xr-xdrivers/misc/mpu3050/mpu-i2c.h60
-rwxr-xr-xdrivers/misc/mpu3050/mpuirq.c315
-rwxr-xr-xdrivers/misc/mpu3050/mpuirq.h50
-rw-r--r--[-rwxr-xr-x]drivers/mmc/core/sdio_io.c0
-rw-r--r--drivers/mmc/host/sdhci-tegra.c124
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/net/ppp_deflate.c5
-rw-r--r--drivers/net/wireless/bcm4329/Kconfig40
-rw-r--r--drivers/net/wireless/bcm4329/Makefile23
-rw-r--r--drivers/power/Kconfig6
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/bq20z75_battery.c544
-rw-r--r--drivers/regulator/Kconfig16
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/max8907c-regulator.c416
-rw-r--r--drivers/regulator/max8952.c313
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-tegra.c471
-rw-r--r--drivers/rtc/rtc-tps6586x.c4
-rw-r--r--drivers/serial/tegra_hsuart.c45
-rw-r--r--drivers/spi/spi_tegra.c310
-rw-r--r--drivers/staging/iio/light/Kconfig13
-rw-r--r--drivers/staging/iio/light/Makefile3
-rw-r--r--drivers/staging/iio/light/isl29018.c543
-rw-r--r--drivers/usb/core/hcd.c19
-rw-r--r--drivers/usb/gadget/f_adb.c46
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c150
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h2
-rw-r--r--drivers/usb/host/ehci-tegra.c102
-rw-r--r--drivers/usb/otg/tegra-otg.c165
-rw-r--r--drivers/video/tegra/dc/dc.c74
-rw-r--r--drivers/video/tegra/dc/dc_reg.h8
-rw-r--r--drivers/video/tegra/dc/hdmi.c8
-rw-r--r--drivers/video/tegra/fb.c13
-rw-r--r--drivers/video/tegra/host/dev.c2
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c38
-rw-r--r--drivers/video/tegra/host/nvhost_acm.h2
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c4
-rw-r--r--drivers/video/tegra/host/nvhost_cpuaccess.c2
-rw-r--r--drivers/video/tegra/host/nvhost_cpuaccess.h1
-rw-r--r--drivers/video/tegra/host/nvhost_hardware.h2
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c2
-rw-r--r--[-rwxr-xr-x]include/linux/earlysuspend.h0
-rwxr-xr-xinclude/linux/i2c/atmel_maxtouch.h301
-rw-r--r--include/linux/i2c/nct1008.h46
-rw-r--r--include/linux/mfd/max8907c.h183
-rw-r--r--include/linux/mfd/tps6586x.h1
-rw-r--r--[-rwxr-xr-x]include/linux/mmc/sdio_func.h0
-rwxr-xr-xinclude/linux/mpu3050.h609
-rw-r--r--include/linux/regulator/max8907c-regulator.h46
-rw-r--r--include/linux/regulator/max8952.h40
-rw-r--r--include/linux/usb.h1
-rw-r--r--include/linux/usb/hcd.h8
-rw-r--r--[-rwxr-xr-x]include/linux/wakelock.h0
-rw-r--r--include/media/ov5650.h38
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/codecs/wm8903.c1
-rw-r--r--sound/soc/tegra/Kconfig18
-rw-r--r--sound/soc/tegra/Makefile6
-rw-r--r--sound/soc/tegra/tegra_i2s.c302
-rw-r--r--sound/soc/tegra/tegra_pcm.c499
-rw-r--r--sound/soc/tegra/tegra_soc.c384
-rw-r--r--sound/soc/tegra/tegra_soc.h100
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(&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 = &reg;
+
+ 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, &regval);
+ 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, &reg);
+ 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,
+ &reg);
+ 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, &reg);
+ 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 = &reg;
+ 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 = &reg;
+
+ 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