From: lw Date: Mon, 12 Dec 2011 11:15:50 +0000 (+0800) Subject: add new mpu3050 driver support from manufacturing company X-Git-Tag: firefly_0821_release~9712^2~13 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=9d713b4a25d289395d2860c385f2a1a195d8d449;p=firefly-linux-kernel-4.4.55.git add new mpu3050 driver support from manufacturing company --- diff --git a/arch/arm/configs/rk29_phonesdk_defconfig b/arch/arm/configs/rk29_phonesdk_defconfig index 093edf254d38..61d129b9a4c6 100755 --- a/arch/arm/configs/rk29_phonesdk_defconfig +++ b/arch/arm/configs/rk29_phonesdk_defconfig @@ -1,15 +1,15 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.32.27 -# Mon Jun 27 20:36:24 2011 +# Linux/arm 3.0.8 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y CONFIG_HAVE_SCHED_CLOCK=y CONFIG_GENERIC_GPIO=y -CONFIG_GENERIC_TIME=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_HARDIRQS=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_HAVE_LATENCYTOP_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y @@ -18,43 +18,65 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_ZONE_DMA=y +CONFIG_NEED_DMA_MAP_STATE=y CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -CONFIG_CONSTRUCTORS=y +CONFIG_HAVE_IRQ_WORK=y # # General setup # CONFIG_EXPERIMENTAL=y CONFIG_BROKEN_ON_SMP=y -CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_LZO=y +CONFIG_DEFAULT_HOSTNAME="(none)" # CONFIG_SWAP is not set # CONFIG_SYSVIPC is not set # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set # CONFIG_TASKSTATS is not set # CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_SHOW=y +# CONFIG_SPARSE_IRQ is not set # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_TREE_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set +# CONFIG_TINY_PREEMPT_RCU is not set +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=19 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 @@ -64,24 +86,27 @@ CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y -# CONFIG_SYSFS_DEPRECATED_V2 is not set -# CONFIG_RELAY is not set +# CONFIG_BLK_CGROUP is not set # CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY 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_XZ 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=5 -CONFIG_EMBEDDED=y +CONFIG_EXPERT=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 @@ -95,10 +120,15 @@ CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_ASHMEM=y CONFIG_AIO=y +CONFIG_EMBEDDED=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 @@ -109,12 +139,13 @@ CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y # # GCOV-based kernel profiling # -# CONFIG_SLOW_WORK is not set CONFIG_HAVE_GENERIC_DMA_COHERENT=y CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y @@ -134,76 +165,116 @@ CONFIG_BLOCK=y # IO Schedulers # CONFIG_IOSCHED_NOOP=y -# CONFIG_IOSCHED_AS is not set # CONFIG_IOSCHED_DEADLINE is not set CONFIG_IOSCHED_CFQ=y -# CONFIG_DEFAULT_AS is not set -# CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_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 is not set 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_MXS is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set # CONFIG_ARCH_IOP33X is not set # CONFIG_ARCH_IXP23XX is not set # CONFIG_ARCH_IXP2000 is not set # CONFIG_ARCH_IXP4XX is not set -# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_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 is not set # 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_S5PC1XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS4 is not set # CONFIG_ARCH_SHARK is not set -# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_TCC_926 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_ARCH_BCMRING is not set -# CONFIG_ARCH_RK2818 is not set CONFIG_ARCH_RK29=y -CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set # CONFIG_MACH_RK29SDK is not set # CONFIG_MACH_RK29SDK_DDR3 is not set # CONFIG_MACH_RK29WINACCORD is not set +# CONFIG_MACH_RK29_K97 is not set # CONFIG_MACH_RK29FIH is not set # CONFIG_MACH_RK29_MALATA is not set CONFIG_MACH_RK29_PHONESDK=y # CONFIG_MACH_RK29_A22 is not set +# CONFIG_MACH_RK29_TD8801_V2 is not set # CONFIG_MACH_RK29_PHONEPADSDK is not set # CONFIG_MACH_RK29_newton is not set +# CONFIG_MACH_RK29_PHONE_Z5 is not set +# CONFIG_MACH_RK29_P91 is not set # CONFIG_DDR_TYPE_DDRII is not set CONFIG_DDR_TYPE_LPDDR=y # CONFIG_DDR_TYPE_DDR3_800D is not set @@ -228,11 +299,11 @@ CONFIG_DDR_TYPE_LPDDR=y # CONFIG_DDR_TYPE_DDR3_2133M is not set # CONFIG_DDR_TYPE_DDR3_2133N is not set # CONFIG_DDR_TYPE_DDR3_DEFAULT is not set -CONFIG_RK29_MEM_SIZE_512M=y -# CONFIG_RK29_MEM_SIZE_1G is not set CONFIG_RK29_MEM_SIZE_M=512 CONFIG_DDR_SDRAM_FREQ=192 CONFIG_DDR_FREQ=y +# CONFIG_DDR_RECONFIG is not set +CONFIG_WIFI_CONTROL_FUNC=y # # RK29 VPU (Video Processing Unit) support @@ -245,16 +316,21 @@ CONFIG_RK29_LAST_LOG=y # # support for RK29 power manage # +# CONFIG_RK29_WORKING_POWER_MANAGEMENT is not set CONFIG_RK29_CLK_SWITCH_TO_32K=y CONFIG_RK29_GPIO_SUSPEND=y +# CONFIG_RK29_NEON_POWERDOMAIN_SET is not set CONFIG_RK29_SPI_INSRAM=y +# +# System MMU +# + # # Processor Type # -CONFIG_CPU_32=y -CONFIG_CPU_32v6K=y CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y CONFIG_CPU_32v7=y CONFIG_CPU_ABRT_EV7=y CONFIG_CPU_PABRT_V7=y @@ -271,17 +347,22 @@ CONFIG_CPU_CP15_MMU=y # CONFIG_ARM_THUMB=y CONFIG_ARM_THUMBEE=y +# CONFIG_SWP_EMULATE 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_HAS_TLS_REG=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=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_743622 is not set +# CONFIG_ARM_ERRATA_754322 is not set CONFIG_ARM_GIC=y CONFIG_PL330=y -CONFIG_COMMON_CLKDEV=y +# CONFIG_FIQ_DEBUGGER is not set # # Bus support @@ -310,41 +391,55 @@ 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 is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE 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_COMPACTION is not set # CONFIG_PHYS_ADDR_T_64BIT is not set -CONFIG_ZONE_DMA_FLAG=0 +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y -CONFIG_HAVE_MLOCK=y -CONFIG_HAVE_MLOCKED_PAGE_BIT=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_NEED_PER_CPU_KM=y +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_ALIGNMENT_TRAP=y # CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set # # Boot options # +# CONFIG_USE_OF is not set CONFIG_ZBOOT_ROM_TEXT=0 CONFIG_ZBOOT_ROM_BSS=0 CONFIG_CMDLINE="" # CONFIG_XIP_KERNEL is not set CONFIG_KEXEC=y CONFIG_ATAGS_PROC=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set # # CPU Power Management # + +# +# CPU Frequency scaling +# CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TABLE=y -# CONFIG_CPU_FREQ_DEBUG is not set CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_STAT_DETAILS=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set @@ -352,10 +447,12 @@ CONFIG_CPU_FREQ_STAT_DETAILS=y # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_CPU_IDLE is not set @@ -381,9 +478,6 @@ CONFIG_HAVE_AOUT=y # # Power management options # -CONFIG_PM=y -# CONFIG_PM_DEBUG is not set -CONFIG_PM_SLEEP=y CONFIG_SUSPEND=y CONFIG_SUSPEND_FREEZER=y CONFIG_HAS_WAKELOCK=y @@ -395,8 +489,12 @@ CONFIG_EARLYSUSPEND=y # CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set # CONFIG_CONSOLE_EARLYSUSPEND is not set CONFIG_FB_EARLYSUSPEND=y -# CONFIG_APM_EMULATION is not set +CONFIG_PM_SLEEP=y # CONFIG_PM_RUNTIME is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_SUSPEND_TIME is not set CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -404,7 +502,6 @@ CONFIG_NET=y # Networking options # CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set @@ -415,13 +512,12 @@ CONFIG_XFRM=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y # CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set +# CONFIG_NET_IPGRE_DEMUX is not set # CONFIG_ARPD is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set @@ -441,13 +537,16 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set # CONFIG_IPV6 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 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 @@ -463,6 +562,7 @@ CONFIG_ANDROID_PARANOID_NETWORK=y # CONFIG_IEEE802154 is not set # CONFIG_NET_SCHED is not set # CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set # # Network testing @@ -477,33 +577,50 @@ 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 is not set +# 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_BT_HCIBCM4325=y CONFIG_IDBLOCK=y # CONFIG_WIFI_MAC is not set # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y -# CONFIG_CFG80211 is not set -CONFIG_CFG80211_DEFAULT_PS_VALUE=0 -# CONFIG_WIRELESS_OLD_REGULATORY is not set 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=y # CONFIG_RFKILL_PM is not set # CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set # CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set # # Device Drivers @@ -527,8 +644,6 @@ CONFIG_EXTRA_FIRMWARE="" 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 @@ -545,6 +660,7 @@ CONFIG_MTD_BLOCK=y # 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 # @@ -594,6 +710,7 @@ CONFIG_MTD_NAND_IDS=y CONFIG_MTD_RKNAND=y CONFIG_MTD_NAND_RK29XX=y CONFIG_MTD_RKNAND_BUFFER=y +# CONFIG_MTD_EMMC_CLK_POWER_SAVE is not set # CONFIG_MTD_NAND_RK29XX_DEBUG is not set # CONFIG_MTD_ONENAND is not set @@ -601,29 +718,43 @@ CONFIG_MTD_RKNAND_BUFFER=y # 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_BLK_DEV_RBD is not set +# CONFIG_SENSORS_LIS3LV02D is not set CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set CONFIG_ANDROID_PMEM=y +# CONFIG_INTEL_MID_PTI is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set -# CONFIG_KERNEL_DEBUGGER_CORE is not set +# CONFIG_APDS9802ALS is not set # CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X 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=y CONFIG_APANIC_PLABEL="kpanic" @@ -631,6 +762,10 @@ CONFIG_APANIC_PLABEL="kpanic" CONFIG_MTK23D=y # CONFIG_FM580X is not set # CONFIG_MU509 is not set +# CONFIG_MW100 is not set +# CONFIG_RK29_NEWTON is not set +# CONFIG_RK29_SC8800 is not set +# CONFIG_TDSC8800 is not set # CONFIG_C2PORT is not set # @@ -644,44 +779,53 @@ CONFIG_MTK23D=y # CONFIG_RK29_SUPPORT_MODEM is not set CONFIG_RK29_GPS=y CONFIG_GPS_GNS7560=y - -# -# Motion Sensors Support -# -# CONFIG_MPU_NONE is not set +CONFIG_MPU_SENSORS_TIMERIRQ=y +CONFIG_INV_SENSORS=y CONFIG_MPU_SENSORS_MPU3050=y -# CONFIG_MPU_SENSORS_MPU6000 is not set -# CONFIG_MPU_SENSORS_ACCELEROMETER_NONE is not set -# CONFIG_MPU_SENSORS_ADXL346 is not set -# CONFIG_MPU_SENSORS_BMA150 is not set +# CONFIG_MPU_SENSORS_MPU6050A2 is not set +# CONFIG_MPU_SENSORS_MPU6050B1 is not set +CONFIG_MPU_SENSORS_MPU3050_GYRO=y +CONFIG_INV_SENSORS_ACCELEROMETERS=y +# CONFIG_MPU_SENSORS_ADXL34X is not set # CONFIG_MPU_SENSORS_BMA222 is not set +# CONFIG_MPU_SENSORS_BMA150 is not set +# CONFIG_MPU_SENSORS_BMA250 is not set # CONFIG_MPU_SENSORS_KXSD9 is not set CONFIG_MPU_SENSORS_KXTF9=y # CONFIG_MPU_SENSORS_LIS331DLH is not set # CONFIG_MPU_SENSORS_LIS3DH is not set -# CONFIG_MPU_SENSORS_LSM303DLHA is not set +# CONFIG_MPU_SENSORS_LSM303DLX_A is not set # CONFIG_MPU_SENSORS_MMA8450 is not set # CONFIG_MPU_SENSORS_MMA845X is not set -# CONFIG_MPU_SENSORS_COMPASS_NONE is not set +CONFIG_INV_SENSORS_COMPASS=y CONFIG_MPU_SENSORS_AK8975=y +# CONFIG_MPU_SENSORS_AK8972 is not set # CONFIG_MPU_SENSORS_MMC314X is not set # CONFIG_MPU_SENSORS_AMI30X is not set # CONFIG_MPU_SENSORS_AMI306 is not set # CONFIG_MPU_SENSORS_HMC5883 is not set -# CONFIG_MPU_SENSORS_LSM303DLHM is not set -# CONFIG_MPU_SENSORS_YAS529 is not set +# CONFIG_MPU_SENSORS_LSM303DLX_M is not set +# CONFIG_MPU_SENSORS_MMC314XMS is not set # CONFIG_MPU_SENSORS_YAS530 is not set # CONFIG_MPU_SENSORS_HSCDTD002B is not set # CONFIG_MPU_SENSORS_HSCDTD004A is not set -CONFIG_MPU_SENSORS_PRESSURE_NONE=y -# CONFIG_MPU_SENSORS_BMA085 is not set -CONFIG_MPU_SENSORS_TIMERIRQ=y +# CONFIG_INV_SENSORS_PRESSURE is not set +# CONFIG_MPU_USERSPACE_DEBUG is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C 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 @@ -710,10 +854,12 @@ CONFIG_SCSI_WAIT_SCAN=m # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set # 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 @@ -727,10 +873,13 @@ CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y # CONFIG_DM_SNAPSHOT is not set # CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID 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_DM_FLAKEY is not set +# CONFIG_TARGET_CORE is not set CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set @@ -738,6 +887,7 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_VETH is not set +CONFIG_MII=y CONFIG_PHYLIB=y # @@ -756,10 +906,10 @@ CONFIG_PHYLIB=y # CONFIG_NATIONAL_PHY is not set # CONFIG_STE10XP is not set # CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set # CONFIG_FIXED_PHY is not set # CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y -CONFIG_MII=y # CONFIG_AX88796 is not set # CONFIG_RK29_VMAC is not set # CONFIG_SMC91X is not set @@ -777,17 +927,19 @@ CONFIG_MII=y # 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_KS8842 is not set # CONFIG_KS8851 is not set # CONFIG_KS8851_MLL is not set +# CONFIG_FTMAC100 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set CONFIG_WLAN=y CONFIG_WLAN_80211=y # CONFIG_WIFI_NONE is not set CONFIG_BCM4329=y -# CONFIG_MV8686 is not set # CONFIG_BCM4319 is not set +# CONFIG_MV8686 is not set +# CONFIG_RTL8192CU is not set +# CONFIG_AR6003 is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -802,7 +954,12 @@ CONFIG_BCM4329=y # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set # CONFIG_USB_HSO is not set +# CONFIG_USB_IPHETH is not set # CONFIG_WAN is not set + +# +# CAIF transport drivers +# CONFIG_PPP=y CONFIG_PPP_MULTILINK=y CONFIG_PPP_FILTER=y @@ -812,7 +969,6 @@ CONFIG_PPP_DEFLATE=y CONFIG_PPP_BSDCOMP=y # CONFIG_PPP_MPPE is not set # CONFIG_PPPOE is not set -# CONFIG_PPPOL2TP is not set # CONFIG_PPPOLAC is not set # CONFIG_PPPOPNS is not set # CONFIG_SLIP is not set @@ -829,6 +985,7 @@ CONFIG_SLHC=y CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set # # Userland interfaces @@ -844,15 +1001,21 @@ CONFIG_INPUT_KEYRESET=y # CONFIG_INPUT_KEYBOARD=y CONFIG_KEYS_RK29=y +# CONFIG_KEYS_RK29_NEWTON is not set # CONFIG_SYNAPTICS_SO340010 is not set # CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set # CONFIG_KEYBOARD_ATKBD is not set -# CONFIG_QT2160 is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_GPIO is not set # CONFIG_KEYBOARD_WM831X_GPIO is not set +# 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_MPR121 is not set # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_OPENCORES is not set # CONFIG_KEYBOARD_STOWAWAY is not set @@ -866,15 +1029,20 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_ADS7846 is not set # CONFIG_TOUCHSCREEN_AD7877 is not set # CONFIG_TOUCHSCREEN_ILI2102_IIC is not set +# CONFIG_TOUCHSCREEN_GT8XX is not set # CONFIG_TOUCHSCREEN_IT7250 is not set -# CONFIG_TOUCHSCREEN_AD7879_I2C is not set -# CONFIG_TOUCHSCREEN_AD7879_SPI is not set # CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_BU21013 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_MAX11801 is not set # CONFIG_TOUCHSCREEN_MCS5000 is not set # CONFIG_TOUCHSCREEN_MTOUCH is not set # CONFIG_TOUCHSCREEN_INEXIO is not set @@ -883,22 +1051,35 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set # CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_WM831X is not set # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set # CONFIG_HANNSTAR_P1003 is not set # CONFIG_ATMEL_MXT224 is not set # CONFIG_SINTEK_3FA16 is not set # CONFIG_EETI_EGALAX is not set # CONFIG_TOUCHSCREEN_IT7260 is not set +# CONFIG_TOUCHSCREEN_IT7260_I2C is not set +# CONFIG_TOUCHSCREEN_NAS is not set +# CONFIG_LAIBAO_TS is not set # CONFIG_TOUCHSCREEN_GT801_IIC is not set CONFIG_TOUCHSCREEN_GT818_IIC=y +# CONFIG_TOUCHSCREEN_PIXCIR is not set # CONFIG_D70_L3188A is not set +# CONFIG_TOUCHSCREEN_GT819 is not set +# CONFIG_TOUCHSCREEN_FT5306 is not set # CONFIG_TOUCHSCREEN_FT5406 is not set +# CONFIG_ATMEL_MXT1386 is not set CONFIG_INPUT_MISC=y CONFIG_INPUT_LPSENSOR_ISL29028=y # CONFIG_INPUT_LPSENSOR_CM3602 is not set +# CONFIG_INPUT_LPSENSOR_AL3006 is not set +# 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 @@ -908,13 +1089,20 @@ CONFIG_INPUT_LPSENSOR_ISL29028=y # CONFIG_INPUT_CM109 is not set CONFIG_INPUT_UINPUT=y # CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_PCF8574 is not set # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set CONFIG_INPUT_WM831X_ON=y +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set # CONFIG_MAG_SENSORS is not set CONFIG_G_SENSOR_DEVICE=y # CONFIG_GS_MMA7660 is not set # CONFIG_GS_MMA8452 is not set +# CONFIG_GS_KXTF9 is not set +# CONFIG_GS_LIS3DH is not set # CONFIG_GS_L3G4200D is not set +# CONFIG_GS_BMA023 is not set +# CONFIG_GYRO_SENSOR_DEVICE is not set # CONFIG_INPUT_JOGBALL is not set # CONFIG_LIGHT_SENSOR_DEVICE is not set @@ -932,9 +1120,14 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y # CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set CONFIG_DEVMEM=y CONFIG_DEVKMEM=y -# CONFIG_SERIAL_NONSTANDARD is not set # # Serial drivers @@ -945,36 +1138,70 @@ CONFIG_DEVKMEM=y # Non-8250 serial port support # # 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_RK29=y CONFIG_UART0_RK29=y CONFIG_UART0_CTS_RTS_RK29=y +# CONFIG_UART0_DMA_RK29 is not set CONFIG_UART1_RK29=y CONFIG_UART2_RK29=y CONFIG_UART2_CTS_RTS_RK29=y +# CONFIG_UART2_DMA_RK29 is not set CONFIG_UART3_RK29=y # CONFIG_UART3_CTS_RTS_RK29 is not set +# CONFIG_UART3_DMA_RK29 is not set CONFIG_SERIAL_RK29_CONSOLE=y # CONFIG_SERIAL_SC8800 is not set -CONFIG_UNIX98_PTYS=y -# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set -# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC 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 is not set +# 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_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# 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_RK29=y # @@ -993,17 +1220,9 @@ CONFIG_I2C3_RK29=y CONFIG_RK29_I2C3_CONTROLLER=y # CONFIG_RK29_I2C3_GPIO is not set # CONFIG_I2C_DEV_RK29 is not set - -# -# Miscellaneous I2C Chip support -# -# CONFIG_DS1682 is not set -# CONFIG_SENSORS_TSL2550 is not set -# CONFIG_SENSORS_PCA963X is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set CONFIG_SPI=y # CONFIG_SPI_DEBUG is not set CONFIG_SPI_MASTER=y @@ -1011,12 +1230,19 @@ CONFIG_SPI_MASTER=y # # SPI Master Controller Drivers # +# CONFIG_SPI_ALTERA is not set # CONFIG_SPI_BITBANG is not set # CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set CONFIG_SPIM_RK29=y CONFIG_SPIM0_RK29=y CONFIG_SPIM1_RK29=y CONFIG_LCD_USE_SPIM_CONTROL=y +# CONFIG_LCD_USE_SPI0 is not set +CONFIG_LCD_USE_SPI1=y +# CONFIG_SPI_DESIGNWARE is not set # # SPI Protocol Masters @@ -1026,7 +1252,6 @@ CONFIG_LCD_USE_SPIM_CONTROL=y CONFIG_ADC=y # CONFIG_ADC_RK28 is not set CONFIG_ADC_RK29=y -# CONFIG_SPI_FPGA is not set # # Headset device support @@ -1037,23 +1262,39 @@ CONFIG_RK_HEADSET_DET=y # PPS support # # CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# CONFIG_ARCH_REQUIRE_GPIOLIB=y CONFIG_GPIOLIB=y # CONFIG_DEBUG_GPIO is not set # CONFIG_GPIO_SYSFS is not set # -# Memory mapped GPIO expanders: +# Memory mapped GPIO drivers: # +# CONFIG_GPIO_BASIC_MMIO is not set +# 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_WM831X=y CONFIG_GPIO_WM8994=y +# CONFIG_GPIO_ADP5588 is not set # # PCI GPIO expanders: @@ -1065,6 +1306,7 @@ CONFIG_GPIO_WM8994=y # CONFIG_GPIO_MAX7301 is not set # CONFIG_GPIO_MCP23S08 is not set # CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set # # AC97 GPIO expanders: @@ -1076,6 +1318,10 @@ CONFIG_EXPANDED_GPIO_IRQ_NUM=0 # CONFIG_EXPAND_GPIO_SOFT_INTERRUPT is not set CONFIG_SPI_FPGA_GPIO_NUM=96 CONFIG_SPI_FPGA_GPIO_IRQ_NUM=16 + +# +# MODULbus GPIO expanders: +# # CONFIG_W1 is not set CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set @@ -1083,13 +1329,20 @@ CONFIG_POWER_SUPPLY=y CONFIG_WM831X_BACKUP=y CONFIG_WM831X_POWER=y CONFIG_WM831X_CHARGER_DISPLAY=y -# CONFIG_BATTERY_DS2760 is not set +# CONFIG_WM831X_WITH_BATTERY is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 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_BATTERY_MAX17042 is not set # CONFIG_BATTERY_STC3100 is not set # CONFIG_BATTERY_BQ27510 is not set +# CONFIG_BATTERY_BQ27541 is not set # CONFIG_BATTERY_BQ3060 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_GPIO is not set # CONFIG_HWMON is not set # CONFIG_THERMAL is not set # CONFIG_WATCHDOG is not set @@ -1099,23 +1352,36 @@ CONFIG_SSB_POSSIBLE=y # Sonics Silicon Backplane # # CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y # -# Multifunction device drivers +# Broadcom specific AMBA # +# CONFIG_BCMA 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_TPS6105X is not set # CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS6586X is not set # CONFIG_TWL4030_CORE is not set -# CONFIG_TPS65910_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X 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_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set # CONFIG_MFD_WM8400 is not set CONFIG_MFD_WM831X=y # CONFIG_MFD_WM831X_I2C is not set @@ -1124,44 +1390,71 @@ CONFIG_MFD_WM831X_SPI=y # CONFIG_MFD_WM8350_I2C is not set CONFIG_MFD_WM8994=y # CONFIG_MFD_PCF50633 is not set -# CONFIG_MFD_MC13783 is not set -# CONFIG_AB3100_CORE is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set # CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65910 is not set 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_MAX8952 is not set CONFIG_REGULATOR_WM831X=y CONFIG_REGULATOR_WM8994=y # CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set # CONFIG_REGULATOR_TPS65023 is not set # CONFIG_REGULATOR_TPS6507X is not set # CONFIG_RK2818_REGULATOR_CHARGE is not set # CONFIG_RK2818_REGULATOR_LP8725 is not set +# CONFIG_REGULATOR_ACT8891 is not set # CONFIG_RK29_PWM_REGULATOR is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_TPS6524X is not set CONFIG_MEDIA_SUPPORT=y # # Multimedia core support # +# CONFIG_MEDIA_CONTROLLER is not set CONFIG_VIDEO_DEV=y CONFIG_VIDEO_V4L2_COMMON=y -CONFIG_VIDEO_ALLOW_V4L1=y -CONFIG_VIDEO_V4L1_COMPAT=y # CONFIG_DVB_CORE is not set CONFIG_VIDEO_MEDIA=y # # Multimedia drivers # +CONFIG_RC_CORE=y +CONFIG_LIRC=y +CONFIG_RC_MAP=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_RC5_SZ_DECODER=y +CONFIG_IR_LIRC_CODEC=y +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_RC_LOOPBACK 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_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y CONFIG_MEDIA_TUNER_TDA9887=y CONFIG_MEDIA_TUNER_TEA5761=y CONFIG_MEDIA_TUNER_TEA5767=y @@ -1170,20 +1463,56 @@ CONFIG_MEDIA_TUNER_XC2028=y CONFIG_MEDIA_TUNER_XC5000=y CONFIG_MEDIA_TUNER_MC44S803=y CONFIG_VIDEO_V4L2=y -CONFIG_VIDEO_V4L1=y CONFIG_VIDEOBUF_GEN=y CONFIG_VIDEOBUF_DMA_CONTIG=y +CONFIG_VIDEOBUF2_CORE=y # CONFIG_VIDEO_RK29XX_VOUT is not set 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_VIVI is not set -# CONFIG_VIDEO_CPIA is not set +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# MPEG video encoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# # CONFIG_VIDEO_CPIA2 is not set -# CONFIG_VIDEO_SAA5246A is not set -# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set CONFIG_SOC_CAMERA=y +# CONFIG_SOC_CAMERA_IMX074 is not set # CONFIG_SOC_CAMERA_MT9M001 is not set # CONFIG_SOC_CAMERA_MT9M111 is not set # CONFIG_SOC_CAMERA_MT9M112 is not set @@ -1192,15 +1521,19 @@ CONFIG_SOC_CAMERA=y # CONFIG_SOC_CAMERA_MT9P111 is not set # CONFIG_SOC_CAMERA_MT9D112 is not set # CONFIG_SOC_CAMERA_MT9D113 is not set +# CONFIG_SOC_CAMERA_MT9T112 is not set # CONFIG_SOC_CAMERA_MT9V022 is not set +# CONFIG_SOC_CAMERA_RJ54N1 is not set # CONFIG_SOC_CAMERA_TW9910 is not set # CONFIG_SOC_CAMERA_PLATFORM is not set +# CONFIG_SOC_CAMERA_OV2640 is not set +# CONFIG_SOC_CAMERA_OV6650 is not set # CONFIG_SOC_CAMERA_OV772X is not set # CONFIG_SOC_CAMERA_OV7675 is not set # CONFIG_SOC_CAMERA_OV2655 is not set CONFIG_SOC_CAMERA_OV2659=y +# CONFIG_SOC_CAMERA_OV7690 is not set # CONFIG_SOC_CAMERA_OV9650 is not set -# CONFIG_SOC_CAMERA_OV2640 is not set # CONFIG_SOC_CAMERA_OV3640 is not set CONFIG_SOC_CAMERA_OV5642=y CONFIG_OV5642_AUTOFOCUS=y @@ -1208,6 +1541,7 @@ CONFIG_OV5642_AUTOFOCUS=y # CONFIG_SOC_CAMERA_OV5640 is not set # CONFIG_SOC_CAMERA_S5K6AA is not set # CONFIG_SOC_CAMERA_GT2005 is not set +# CONFIG_SOC_CAMERA_GC0307 is not set # CONFIG_SOC_CAMERA_GC0308 is not set # CONFIG_SOC_CAMERA_GC0309 is not set # CONFIG_SOC_CAMERA_GC2015 is not set @@ -1216,12 +1550,17 @@ CONFIG_OV5642_AUTOFOCUS=y # CONFIG_SOC_CAMERA_SIV120B is not set # CONFIG_SOC_CAMERA_SID130B is not set # CONFIG_SOC_CAMERA_NT99250 is not set +# CONFIG_SOC_CAMERA_OV9640 is not set +# CONFIG_SOC_CAMERA_OV9740 is not set +# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set # CONFIG_VIDEO_SH_MOBILE_CEU is not set CONFIG_VIDEO_RK29=y CONFIG_VIDEO_RK29_WORK_ONEFRAME=y # CONFIG_VIDEO_RK29_WORK_PINGPONG is not set CONFIG_VIDEO_RK29_WORK_IPP=y # CONFIG_VIDEO_RK29_WORK_NOT_IPP is not set +CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON=y +# CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF is not set CONFIG_V4L_USB_DRIVERS=y # CONFIG_USB_VIDEO_CLASS is not set CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y @@ -1229,16 +1568,24 @@ CONFIG_USB_GSPCA=m # CONFIG_USB_M5602 is not set # CONFIG_USB_STV06XX is not set # CONFIG_USB_GL860 is not set +# CONFIG_USB_GSPCA_BENQ is not set # CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set # CONFIG_USB_GSPCA_ETOMS is not set # CONFIG_USB_GSPCA_FINEPIX is not set # CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set # CONFIG_USB_GSPCA_MARS is not set # CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set # CONFIG_USB_GSPCA_OV519 is not set # CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set # CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set # CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set # CONFIG_USB_GSPCA_SN9C20X is not set # CONFIG_USB_GSPCA_SONIXB is not set # CONFIG_USB_GSPCA_SONIXJ is not set @@ -1248,35 +1595,31 @@ CONFIG_USB_GSPCA=m # CONFIG_USB_GSPCA_SPCA506 is not set # CONFIG_USB_GSPCA_SPCA508 is not set # CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set # CONFIG_USB_GSPCA_SQ905 is not set # CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set # CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STV0680 is not set # CONFIG_USB_GSPCA_SUNPLUS is not set # CONFIG_USB_GSPCA_T613 is not set # CONFIG_USB_GSPCA_TV8532 is not set # CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set # CONFIG_USB_GSPCA_ZC3XX 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_VICAM is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_KONICAWC is not set -# CONFIG_USB_QUICKCAM_MESSENGER is not set # CONFIG_USB_ET61X251 is not set -# CONFIG_VIDEO_OVCAMCHIP is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_SE401 is not set # CONFIG_USB_SN9C102 is not set -# CONFIG_USB_STV680 is not set -# CONFIG_USB_ZC0301 is not set # CONFIG_USB_PWC is not set -CONFIG_USB_PWC_INPUT_EVDEV=y # 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 @@ -1284,12 +1627,21 @@ CONFIG_RADIO_ADAPTERS=y # 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_RADIO_WL1273 is not set + +# +# Texas Instruments WL128x FM driver (ST based) +# +# CONFIG_RADIO_WL128X is not set # CONFIG_SMS_SIANO_MDTV is not set -# CONFIG_DAB is not set # # Graphics support # +# CONFIG_DRM is not set +# CONFIG_ION is not set # CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y @@ -1305,6 +1657,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_SYS_IMAGEBLIT is not set # CONFIG_FB_FOREIGN_ENDIAN is not set # CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set @@ -1316,15 +1669,16 @@ CONFIG_FB_CFB_IMAGEBLIT=y # # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_TMIO is not set -# CONFIG_FB_RK2818 is not set CONFIG_FB_RK29=y CONFIG_FB_WORK_IPP=y # CONFIG_FB_SCALING_OSD is not set CONFIG_FB_ROTATE_VIDEO=y +# CONFIG_FB_MIRROR_X_Y is not set CONFIG_CLOSE_WIN1_DYNAMIC=y +# CONFIG_FB_WIMO is not set +# CONFIG_FB_UDL 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=y # CONFIG_LCD_CLASS_DEVICE is not set @@ -1332,9 +1686,12 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_BACKLIGHT_WM831X=y # CONFIG_BACKLIGHT_RK29_BL is not set +# CONFIG_BACKLIGHT_RK29_NEWTON_BL is not set # CONFIG_FIH_TOUCHKEY_LED is not set # CONFIG_BACKLIGHT_AW9364 is not set # CONFIG_BUTTON_LIGHT is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set # # Display device support @@ -1345,6 +1702,7 @@ CONFIG_DISPLAY_SUPPORT=y # Display hardware drivers # # CONFIG_LCD_NULL is not set +# CONFIG_LCD_LG_LP097X02 is not set # CONFIG_LCD_TD043MGEA1 is not set # CONFIG_LCD_HX8357 is not set # CONFIG_LCD_TJ048NC01CA is not set @@ -1353,8 +1711,10 @@ CONFIG_DISPLAY_SUPPORT=y # CONFIG_LCD_RGB_TFT480800_25_E is not set # CONFIG_LCD_HSD100PXN is not set # CONFIG_LCD_HSD07PFW1 is not set +# CONFIG_LCD_BYD8688FTGF is not set # CONFIG_LCD_B101AW06 is not set CONFIG_LCD_LS035Y8DX02A=y +# CONFIG_LCD_LS035Y8DX04A is not set # CONFIG_LCD_CPTCLAA038LA31XE is not set # CONFIG_LCD_A060SE02 is not set # CONFIG_LCD_S1D13521 is not set @@ -1364,9 +1724,10 @@ CONFIG_LCD_LS035Y8DX02A=y # CONFIG_LCD_MCU_TFT480800_25_E is not set # CONFIG_LCD_NT35510 is not set # CONFIG_LCD_ILI9803_CPT4_3 is not set -# CONFIG_DEFAULT_OUT_HDMI is not set # CONFIG_LCD_AT070TNA2 is not set # CONFIG_LCD_AT070TN93 is not set +# CONFIG_LCD_TX23D88VM is not set +# CONFIG_LCD_A050VL01 is not set # # HDMI @@ -1376,7 +1737,6 @@ CONFIG_LCD_LS035Y8DX02A=y # # Console display driver support # -# CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y # CONFIG_FRAMEBUFFER_CONSOLE is not set CONFIG_LOGO=y @@ -1409,24 +1769,90 @@ CONFIG_SND_JACK=y # CONFIG_SND_SPI is not set # CONFIG_SND_USB is not set CONFIG_SND_SOC=y +# CONFIG_SND_SOC_CACHE_LZO is not set CONFIG_SND_RK29_SOC=y CONFIG_SND_RK29_SOC_I2S=y # CONFIG_SND_RK29_SOC_I2S_2CH is not set CONFIG_SND_RK29_SOC_I2S_8CH=y +# CONFIG_SND_I2S_DMA_EVENT_DYNAMIC is not set +CONFIG_SND_I2S_DMA_EVENT_STATIC=y # CONFIG_SND_RK29_SOC_WM8988 is not set # CONFIG_SND_RK29_SOC_WM8900 is not set -# CONFIG_SND_RK29_SOC_alc5621 is not set -# CONFIG_SND_RK29_SOC_alc5631 is not set +# CONFIG_SND_RK29_SOC_RT5621 is not set +# CONFIG_SND_RK29_SOC_RT5631 is not set # CONFIG_SND_RK29_SOC_RT5625 is not set CONFIG_SND_RK29_SOC_WM8994=y # CONFIG_SND_RK29_SOC_CS42L52 is not set +# CONFIG_SND_RK29_SOC_AIC3111 is not set # CONFIG_SND_RK29_CODEC_SOC_MASTER is not set CONFIG_SND_RK29_CODEC_SOC_SLAVE=y +# CONFIG_ADJUST_VOL_BY_CODEC is not set CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WM_HUBS=y CONFIG_SND_SOC_WM8994=y # CONFIG_SOUND_PRIME is not set -CONFIG_HID_SUPPORT = y +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_A4TECH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN 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_EMS_FF is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH 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_ARVO is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_ROCCAT_KONEPLUS is not set +# CONFIG_HID_ROCCAT_KOVAPLUS is not set +# CONFIG_HID_ROCCAT_PYRA is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY 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 @@ -1441,8 +1867,6 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set -# CONFIG_USB_SUSPEND is not set -# CONFIG_USB_OTG is not set # CONFIG_USB_OTG_WHITELIST is not set CONFIG_USB_OTG_BLACKLIST_HUB=y # CONFIG_USB_MON is not set @@ -1461,7 +1885,6 @@ CONFIG_USB_OTG_BLACKLIST_HUB=y # CONFIG_USB_R8A66597_HCD is not set # CONFIG_USB_HWA_HCD is not set # CONFIG_USB_MUSB_HDRC is not set -# CONFIG_USB_GADGET_MUSB_HDRC is not set # # USB Device Class drivers @@ -1480,6 +1903,7 @@ CONFIG_USB_OTG_BLACKLIST_HUB=y # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set @@ -1491,6 +1915,8 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_ONETOUCH is not set # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set # CONFIG_USB_LIBUSUAL is not set # @@ -1536,6 +1962,7 @@ CONFIG_USB_SERIAL_GENERIC=y # 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 @@ -1546,9 +1973,13 @@ CONFIG_USB_SERIAL_GENERIC=y # CONFIG_USB_SERIAL_TI is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y CONFIG_USB_SERIAL_OPTION=y # 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 # @@ -1561,7 +1992,6 @@ CONFIG_USB_SERIAL_OPTION=y # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set -# CONFIG_USB_BERRY_CHARGE is not set # CONFIG_USB_LED is not set # CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set @@ -1573,30 +2003,16 @@ CONFIG_USB_SERIAL_OPTION=y # CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_TEST is not set # CONFIG_USB_ISIGHTFW is not set -# CONFIG_USB_VST is not set +# CONFIG_USB_YUREX 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_VBUS_DRAW=2 CONFIG_USB_GADGET_SELECTED=y -# CONFIG_USB_GADGET_AT91 is not set -# CONFIG_USB_GADGET_ATMEL_USBA is not set -# CONFIG_USB_GADGET_FSL_USB2 is not set -# CONFIG_USB_GADGET_LH7A40X is not set -# CONFIG_USB_GADGET_OMAP is not set -# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_FUSB300 is not set # CONFIG_USB_GADGET_R8A66597 is not set -# CONFIG_USB_GADGET_PXA27X is not set -# CONFIG_USB_GADGET_S3C_HSOTG is not set -# CONFIG_USB_GADGET_IMX is not set -# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_PXA_U2O is not set # CONFIG_USB_GADGET_M66592 is not set -# CONFIG_USB_GADGET_AMD5536UDC is not set -# CONFIG_USB_GADGET_FSL_QE is not set -# CONFIG_USB_GADGET_CI13XXX is not set -# CONFIG_USB_GADGET_NET2280 is not set -# CONFIG_USB_GADGET_GOKU is not set -# CONFIG_USB_GADGET_LANGWELL is not set CONFIG_USB_GADGET_DWC_OTG=y CONFIG_USB_DWC_OTG=y # CONFIG_USB_GADGET_DUMMY_HCD is not set @@ -1604,22 +2020,27 @@ 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_G_NCM 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=y -# CONFIG_USB_ANDROID_RNDIS is not set +CONFIG_USB_G_ANDROID=y # 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_WAKELOCK is not set # CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set # CONFIG_NOP_USB_XCEIV is not set CONFIG_USB11_HOST=y CONFIG_USB11_HOST_EN=y @@ -1630,10 +2051,12 @@ CONFIG_DWC_OTG_DEVICE_ONLY=y # CONFIG_DWC_OTG_BOTH_HOST_SLAVE is not set CONFIG_DWC_CONN_EN=y # CONFIG_DWC_OTG_DEBUG is not set +# CONFIG_DWC_REMOTE_WAKEUP is not set CONFIG_DWC_OTG=y CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_CLKGATE is not set CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y @@ -1641,6 +2064,7 @@ CONFIG_MMC_PARANOID_SD_INIT=y # MMC/SD/SDIO Card Drivers # CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set # CONFIG_SDIO_UART is not set @@ -1649,21 +2073,23 @@ CONFIG_MMC_BLOCK_BOUNCE=y # # MMC/SD/SDIO Host Controller Drivers # -# CONFIG_SDMMC_RK29_OLD=y CONFIG_SDMMC_RK29=y # # Now, there are two SDMMC controllers selected, SDMMC0 and SDMMC1. # +# CONFIG_SDMMC_RK29_OLD is not set CONFIG_SDMMC0_RK29=y -# CONFIG_EMMC_RK29 is not set +# CONFIG_SDMMC0_RK29_WRITE_PROTECT is not set CONFIG_SDMMC1_RK29=y +# CONFIG_SDMMC1_RK29_WRITE_PROTECT is not set # CONFIG_MMC_SDHCI is not set -# CONFIG_MMC_AT91 is not set -# CONFIG_MMC_ATMELMCI is not set -# CONFIG_MMC_SPI is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set # CONFIG_MEMSTICK is not set # CONFIG_NEW_LEDS is not set +# CONFIG_NFC_DEVICES is not set CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y # CONFIG_ACCESSIBILITY is not set @@ -1692,22 +2118,28 @@ CONFIG_RTC_INTF_ALARM_DEV=y # 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_S35390A is not set # CONFIG_RTC_DRV_S35392A is not set # CONFIG_RTC_DRV_FM3130 is not set # CONFIG_RTC_DRV_RX8581 is not set # CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set # # SPI RTC drivers # +# CONFIG_RTC_DRV_M41T93 is not set # CONFIG_RTC_DRV_M41T94 is not set # CONFIG_RTC_DRV_DS1305 is not set # CONFIG_RTC_DRV_DS1390 is not set @@ -1729,7 +2161,9 @@ CONFIG_RTC_INTF_ALARM_DEV=y # 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 CONFIG_RTC_DRV_WM831X=y @@ -1739,17 +2173,13 @@ CONFIG_RTC_DRV_WM831X=y # CONFIG_DMADEVICES is not set # CONFIG_AUXDISPLAY is not set # CONFIG_UIO is not set - -# -# TI VLYNQ -# CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set -# CONFIG_USB_IP_COMMON is not set -# CONFIG_PRISM2_USB is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_USBIP_CORE is not set # CONFIG_ECHO is not set -# CONFIG_COMEDI is not set +# CONFIG_BRCMUTIL is not set # CONFIG_ASUS_OLED is not set +# CONFIG_R8712U is not set # CONFIG_TRANZPORT is not set # @@ -1769,60 +2199,57 @@ CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d CONFIG_ANDROID_TIMED_OUTPUT=y CONFIG_ANDROID_TIMED_GPIO=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y - -# -# Qualcomm MSM Camera And Video -# - -# -# Camera Sensor Selection -# -# CONFIG_DST is not set # CONFIG_POHMELFS is not set -# CONFIG_PLAN9AUTH 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 - -# -# RAR Register Driver -# -# CONFIG_RAR_REGISTER is not set # CONFIG_IIO is not set # -# DSP -# -# CONFIG_RK2818_DSP is not set - -# -# RK1000 control +# GPU Vivante # -# CONFIG_RK1000_CONTROL is not set +CONFIG_VIVANTE=y # -# rk2818 POWER CONTROL +# IPP # -# CONFIG_RK2818_POWER is not set +CONFIG_RK29_IPP=y +# CONFIG_DEINTERLACE is not set +# CONFIG_XVMALLOC is not set +# CONFIG_ZRAM is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_LIRC_STAGING is not set +# CONFIG_EASYCAP is not set +CONFIG_MACH_NO_WESTBRIDGE=y +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set # -# GPU Vivante +# Speakup console speech # -CONFIG_VIVANTE=y +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set # -# IPP +# Altera FPGA firmware download module # -CONFIG_RK29_IPP=y -CONFIG_DEINTERLACE=n +# CONFIG_ALTERA_STAPL is not set +CONFIG_CLKDEV_LOOKUP=y # # CMMB # # CONFIG_CMMB is not set # CONFIG_TEST_CODE is not set +# CONFIG_RK29_SMC is not set + +# +# CIR support +# +# CONFIG_RK_CIR is not set # # File systems @@ -1832,24 +2259,24 @@ CONFIG_EXT3_FS=y CONFIG_EXT3_DEFAULTS_TO_ORDERED=y # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y # CONFIG_EXT4_FS_XATTR is not set # CONFIG_EXT4_DEBUG is not set CONFIG_JBD=y CONFIG_JBD2=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set -# CONFIG_OCFS2_FS is not set # CONFIG_BTRFS_FS is not set # CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set CONFIG_FILE_LOCKING=y CONFIG_FSNOTIFY=y # CONFIG_DNOTIFY is not set -CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set +# CONFIG_QUOTACTL is not set # CONFIG_AUTOFS4_FS is not set CONFIG_FUSE_FS=y # CONFIG_CUSE is not set @@ -1884,6 +2311,7 @@ CONFIG_PROC_PAGE_MONITOR=y CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLB_PAGE is not set # CONFIG_CONFIGFS_FS is not set CONFIG_MISC_FILESYSTEMS=y @@ -1896,6 +2324,7 @@ CONFIG_MISC_FILESYSTEMS=y # 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=y # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -1904,6 +2333,7 @@ CONFIG_CRAMFS=y # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set # CONFIG_NETWORK_FILESYSTEMS is not set @@ -1953,12 +2383,12 @@ CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=y -# CONFIG_DLM is not set # # Kernel hacking # CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_FRAME_WARN=1024 @@ -1967,12 +2397,13 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_UNUSED_SYMBOLS is not set # CONFIG_DEBUG_FS is not set # CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH 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_DEFAULT_HUNG_TASK_TIMEOUT=120 # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 # CONFIG_SCHED_DEBUG is not set @@ -1988,47 +2419,63 @@ CONFIG_TIMER_STATS=y # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set +# CONFIG_SPARSE_RCU_POINTER 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_STACK_USAGE is not set # CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_WRITECOUNT is not set # CONFIG_DEBUG_MEMORY_INIT is not set # CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT 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_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y # 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_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set -# CONFIG_PAGE_POISONING is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_DEBUG_PAGEALLOC is not set CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_TRACING_SUPPORT=y # CONFIG_FTRACE is not set +# CONFIG_DMA_API_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_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set CONFIG_ARM_UNWIND=y # CONFIG_DEBUG_USER is not set -CONFIG_DEBUG_ERRORS=y -# 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_DMESG_RESTRICT is not set # CONFIG_SECURITY is not set # CONFIG_SECURITYFS is not set -# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" CONFIG_CRYPTO=y # @@ -2042,9 +2489,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_WORKQUEUE=y @@ -2098,7 +2546,7 @@ CONFIG_CRYPTO_SHA1=y # # Ciphers # -# CONFIG_CRYPTO_AES is not set +CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANUBIS is not set CONFIG_CRYPTO_ARC4=y # CONFIG_CRYPTO_BLOWFISH is not set @@ -2126,6 +2574,8 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y # Random Number Generation # # CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set CONFIG_CRYPTO_HW=y # CONFIG_BINARY_PRINTF is not set @@ -2133,7 +2583,6 @@ CONFIG_CRYPTO_HW=y # Library routines # CONFIG_BITREVERSE=y -CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_CRC_CCITT=y CONFIG_CRC16=y # CONFIG_CRC_T10DIF is not set @@ -2143,6 +2592,8 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y CONFIG_REED_SOLOMON=y CONFIG_REED_SOLOMON_ENC8=y @@ -2151,3 +2602,4 @@ CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set diff --git a/arch/arm/mach-rk29/board-rk29-phonesdk.c b/arch/arm/mach-rk29/board-rk29-phonesdk.c index 247b2985610d..b72efe8bb629 100755 --- a/arch/arm/mach-rk29/board-rk29-phonesdk.c +++ b/arch/arm/mach-rk29/board-rk29-phonesdk.c @@ -599,57 +599,31 @@ static struct mma8452_platform_data mma8452_info = { }; #endif -#if defined (CONFIG_MPU_SENSORS_MPU3050) /*mpu3050*/ -static struct mpu3050_platform_data mpu3050_data = { - .int_config = 0x10, - //.orientation = { 1, 0, 0,0, -1, 0,0, 0, 1 }, - //.orientation = { 0, 1, 0,-1, 0, 0,0, 0, -1 }, - //.orientation = { -1, 0, 0,0, -1, 0,0, 0, -1 }, - //.orientation = { 0, 1, 0, -1, 0, 0, 0, 0, 1 }, - .orientation = { 1, 0, 0,0, 1, 0, 0, 0, 1 }, - .level_shifter = 0, +#if defined (CONFIG_MPU_SENSORS_MPU3050) +static struct mpu_platform_data mpu3050_data = { + .int_config = 0x10, + .orientation = { 1, 0, 0,0, 1, 0, 0, 0, 1 }, +}; +#endif + +/* accel */ #if defined (CONFIG_MPU_SENSORS_KXTF9) - .accel = { -#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE - .get_slave_descr = NULL , -#else - .get_slave_descr = get_accel_slave_descr , -#endif - .adapt_num = 0, // The i2c bus to which the mpu device is - // connected - //.irq = RK29_PIN6_PC4, - .bus = EXT_SLAVE_BUS_SECONDARY, //The secondary I2C of MPU - .address = 0x0f, - //.orientation = { 1, 0, 0,0, 1, 0,0, 0, 1 }, - //.orientation = { 0, -1, 0,-1, 0, 0,0, 0, -1 }, - //.orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 }, - //.orientation = { 0, 1 ,0, -1 ,0, 0, 0, 0, 1 }, - .orientation = {1, 0, 0, 0, 1, 0, 0, 0, 1}, - }, +static struct ext_slave_platform_data inv_mpu_kxtf9_data = { + .bus = EXT_SLAVE_BUS_SECONDARY, + .adapt_num = 0, + .orientation = {1, 0, 0, 0, 1, 0, 0, 0, 1}, +}; #endif + +/* compass */ #if defined (CONFIG_MPU_SENSORS_AK8975) - .compass = { -#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE - .get_slave_descr = NULL,/*ak5883_get_slave_descr,*/ -#else - .get_slave_descr = get_compass_slave_descr, -#endif - .adapt_num = 0, // The i2c bus to which the compass device is. - // It can be difference with mpu - // connected - //.irq = RK29_PIN6_PC5, - .bus = EXT_SLAVE_BUS_PRIMARY, - .address = 0x0d, - //.orientation = { -1, 0, 0,0, -1, 0,0, 0, 1 }, - //.orientation = { 0, -1, 0,-1, 0, 0,0, 0, -1 }, - //.orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 }, - //.orientation = { 0, -1, 0, 1, 0, 0, 0, 0, 1 }, - .orientation = {0, 1, 0, -1, 0, 0, 0, 0, 1}, - }, +static struct ext_slave_platform_data inv_mpu_ak8975_data = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .adapt_num = 0, + .orientation = {0, 1, 0, -1, 0, 0, 0, 0, 1}, }; #endif -#endif #if defined(CONFIG_GPIO_WM831X) struct rk29_gpio_expander_info wm831x_gpio_settinginfo[] = { @@ -2125,6 +2099,25 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = { .platform_data = &mpu3050_data, }, #endif +#if defined (CONFIG_MPU_SENSORS_KXTF9) + { + .type = "kxtf9", + .addr = 0x0f, + .flags = 0, + //.irq = RK29_PIN6_PC4, + .platform_data = &inv_mpu_kxtf9_data, + }, +#endif +#if defined (CONFIG_MPU_SENSORS_AK8975) + { + .type = "ak8975", + .addr = 0x0d, + .flags = 0, + //.irq = RK29_PIN6_PC5, + .platform_data = &inv_mpu_ak8975_data, + }, +#endif + }; #endif diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7b48ab90e592..04505e619825 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -561,7 +561,7 @@ source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" source "drivers/misc/rk29_modem/Kconfig" source "drivers/misc/gps/Kconfig" -source "drivers/misc/mpu3050/Kconfig" +source "drivers/misc/inv_mpu/Kconfig" source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 410e64d7103d..dd3ff0b6fefa 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_MW100) += MW100.o obj-$(CONFIG_STE) += ste.o obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem/ obj-$(CONFIG_GPS_GNS7560) += gps/ -obj-y += mpu3050/ +obj-y += inv_mpu/ obj-$(CONFIG_RK29_NEWTON) += newton.o obj-$(CONFIG_TDSC8800) += tdsc8800.o obj-$(CONFIG_RK29_SC8800) += sc8800.o diff --git a/drivers/misc/inv_mpu/Kconfig b/drivers/misc/inv_mpu/Kconfig new file mode 100644 index 000000000000..53c7c200d453 --- /dev/null +++ b/drivers/misc/inv_mpu/Kconfig @@ -0,0 +1,77 @@ +config MPU_SENSORS_TIMERIRQ + tristate "MPU Timer IRQ" + help + If you say yes here you get access to the timerirq device handle which + can be used to select on. This can be used instead of IRQ's, sleeping, + or timer threads. Reading from this device returns the same type of + information as reading from the MPU and slave IRQ's. + +menuconfig: INV_SENSORS + tristate "Motion Processing Unit" + depends on I2C + default y + +if INV_SENSORS + +choice + prompt "MPU Master" + depends on I2C && INV_SENSORS + default MPU_SENSORS_MPU3050 + +config MPU_SENSORS_MPU3050 + bool "MPU3050" + depends on I2C + select MPU_SENSORS_MPU3050_GYRO + 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 MPU_SENSORS_MPU6050A2 + bool "MPU6050A2" + depends on I2C + select MPU_SENSORS_MPU6050_GYRO + help + If you say yes here you get support for the MPU6050A2 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu6050a2. + +config MPU_SENSORS_MPU6050B1 + bool "MPU6050B1" + select MPU_SENSORS_MPU6050_GYRO + depends on I2C + help + If you say yes here you get support for the MPU6050 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu6050b1. + +endchoice + +choice + prompt "Gyroscope Type" + depends on I2C && INV_SENSORS + default MPU_SENSORS_MPU3050_GYRO + +config MPU_SENSORS_MPU3050_GYRO + bool "MPU3050 built in gyroscope" + depends on MPU_SENSORS_MPU3050 + +config MPU_SENSORS_MPU6050_GYRO + bool "MPU6050 built in gyroscope" + depends on MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + +endchoice + +source "drivers/misc/inv_mpu/accel/Kconfig" +source "drivers/misc/inv_mpu/compass/Kconfig" +source "drivers/misc/inv_mpu/pressure/Kconfig" + +config MPU_USERSPACE_DEBUG + bool "MPU Userspace debugging ioctls" + help + Allows the ioctls MPU_SET_MPU_PLATFORM_DATA and + MPU_SET_EXT_SLAVE_PLATFORM_DATA, which allows userspace applications + to override the slave address and orientation. This is dangerous + and could cause the devices not to work. + +endif #INV_SENSORS diff --git a/drivers/misc/inv_mpu/Makefile b/drivers/misc/inv_mpu/Makefile new file mode 100644 index 000000000000..248648f6567c --- /dev/null +++ b/drivers/misc/inv_mpu/Makefile @@ -0,0 +1,45 @@ + +# Kernel makefile for motions sensors +# +# + +# MPU +ifdef CONFIG_MPU_SENSORS_MPU3050 +INV_MODULE_NAME := mpu3050 +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050A2 +INV_MODULE_NAME := mpu6050 +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050B1 +INV_MODULE_NAME := mpu6050 +endif + +obj-$(CONFIG_INV_SENSORS) += $(INV_MODULE_NAME).o + +$(INV_MODULE_NAME)-objs += mpuirq.o +$(INV_MODULE_NAME)-objs += slaveirq.o +$(INV_MODULE_NAME)-objs += mpu-dev.o +$(INV_MODULE_NAME)-objs += mlsl-kernel.o +$(INV_MODULE_NAME)-objs += mldl_cfg.o +$(INV_MODULE_NAME)-objs += mldl_print_cfg.o + +ifdef CONFIG_MPU_SENSORS_MPU6050A2 +$(INV_MODULE_NAME)-objs += accel/mpu6050.o +endif + +ifdef CONFIG_MPU_SENSORS_MPU6050B1 +$(INV_MODULE_NAME)-objs += accel/mpu6050.o +endif + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER +EXTRA_CFLAGS += -DINV_CACHE_DMP=1 + +obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o + +obj-y += accel/ +obj-y += compass/ +obj-y += pressure/ + diff --git a/drivers/misc/inv_mpu/README b/drivers/misc/inv_mpu/README new file mode 100644 index 000000000000..ce592c81ba5f --- /dev/null +++ b/drivers/misc/inv_mpu/README @@ -0,0 +1,104 @@ +Kernel driver mpu +===================== + +Supported chips: + * InvenSense IMU3050 + Prefix: 'mpu3050' + Datasheet: + PS-MPU-3000A-00.2.4b.pdf + +Author: InvenSense + +Description +----------- +The mpu is a motion processor unit that controls the mpu3050 gyroscope, a slave +accelerometer, a compass and a pressure sensor. This document describes how to +install the driver into a Linux kernel. + +Sysfs entries +------------- +/dev/mpu +/dev/mpuirq +/dev/accelirq +/dev/compassirq +/dev/pressureirq + +General Remarks MPU3050 +----------------------- +* Valid addresses for the MPU3050 is 0x68. +* Accelerometer must be on the secondary I2C bus for MPU3050, the + magnetometer must be on the primary bus and pressure sensor must + be on the primary bus. + +Programming the chip using /dev/mpu +---------------------------------- +Programming of 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 mpu.h. Typically this is done by the mllite library in user +space. + +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 mpu_platform_data structure must +be created and populated and set in the i2c_board_info_structure. For details +of each structure member see mpu.h. All values below are simply an example and +should be modified for your platform. + +#include + +static struct mpu_platform_data mpu3050_data = { + .int_config = 0x10, + .orientation = { -1, 0, 0, + 0, 1, 0, + 0, 0, -1 }, +}; + +/* accel */ +static struct ext_slave_platform_data inv_mpu_kxtf9_data = { + .bus = EXT_SLAVE_BUS_SECONDARY, + .orientation = { -1, 0, 0, + 0, 1, 0, + 0, 0, -1 }, +}; +/* compass */ +static struct ext_slave_platform_data inv_mpu_ak8975_data = { + .bus = EXT_SLAVE_BUS_PRIMARY, + .orientation = { 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }, +}; + +static struct i2c_board_info __initdata panda_inv_mpu_i2c4_boardinfo[] = { + { + I2C_BOARD_INFO("mpu3050", 0x68), + .irq = (IH_GPIO_BASE + MPUIRQ_GPIO), + .platform_data = &mpu3050_data, + }, + { + I2C_BOARD_INFO("kxtf9", 0x0F), + .irq = (IH_GPIO_BASE + ACCEL_IRQ_GPIO), + .platform_data = &inv_mpu_kxtf9_data + }, + { + I2C_BOARD_INFO("ak8975", 0x0E), + .irq = (IH_GPIO_BASE + COMPASS_IRQ_GPIO), + .platform_data = &inv_mpu_ak8975_data, + }, +}; + +Typically the IRQ is a GPIO input pin and needs to be configured properly. If +in the above example GPIO 168 corresponds to IRQ 299, the following should be +done as well: + +#define MPU_GPIO_IRQ 168 + + gpio_request(MPU_GPIO_IRQ,"MPUIRQ"); + gpio_direction_input(MPU_GPIO_IRQ) + +Dynamic Debug +============= + +The mpu3050 makes use of dynamic debug. For details on how to use this +refer to Documentation/dynamic-debug-howto.txt diff --git a/drivers/misc/inv_mpu/accel/Kconfig b/drivers/misc/inv_mpu/accel/Kconfig new file mode 100644 index 000000000000..4e280bd876bc --- /dev/null +++ b/drivers/misc/inv_mpu/accel/Kconfig @@ -0,0 +1,133 @@ +menuconfig INV_SENSORS_ACCELEROMETERS + bool "Accelerometer Slave Sensors" + default y + ---help--- + Say Y here to get to see options for device drivers for various + accelerometrs for integration with the MPU3050 or MPU6050 driver. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if INV_SENSORS_ACCELEROMETERS + +config MPU_SENSORS_ADXL34X + tristate "ADI adxl34x" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ADI adxl345 or adxl346 accelerometers. + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_BMA222 + tristate "Bosch BMA222" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Bosch BMA222 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_BMA150 + tristate "Bosch BMA150" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Bosch BMA150 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_BMA250 + tristate "Bosch BMA250" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Bosch BMA250 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_KXSD9 + tristate "Kionix KXSD9" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Kionix KXSD9 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_KXTF9 + tristate "Kionix KXTF9" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Kionix KXFT9 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_LIS331DLH + tristate "ST lis331dlh" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ST lis331dlh accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_LIS3DH + tristate "ST lis3dh" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ST lis3dh accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_LSM303DLX_A + tristate "ST lsm303dlx" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the ST lsm303dlh and lsm303dlm accelerometers + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_MMA8450 + tristate "Freescale mma8450" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Freescale mma8450 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_MMA845X + tristate "Freescale mma8451/8452/8453" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the Freescale mma8451/8452/8453 accelerometer + This support is for integration with the MPU3050 gyroscope device + driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +config MPU_SENSORS_MPU6050_ACCEL + tristate "MPU6050 built in accelerometer" + depends on MPU_SENSORS_MPU6050B1 || MPU_SENSORS_MPU6050A2 + help + This enables support for the MPU6050 built in accelerometer. + This the built in support for integration with the MPU6050 gyroscope + device driver. This is the only accelerometer supported with the + MPU6050. Specifying another accelerometer in the board file will + result in runtime errors. + +endif diff --git a/drivers/misc/inv_mpu/accel/Makefile b/drivers/misc/inv_mpu/accel/Makefile new file mode 100644 index 000000000000..1f0f5bec6774 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/Makefile @@ -0,0 +1,38 @@ +# +# Accel Slaves to MPUxxxx +# +obj-$(CONFIG_MPU_SENSORS_ADXL34X) += inv_mpu_adxl34x.o +inv_mpu_adxl34x-objs += adxl34x.o + +obj-$(CONFIG_MPU_SENSORS_BMA150) += inv_mpu_bma150.o +inv_mpu_bma150-objs += bma150.o + +obj-$(CONFIG_MPU_SENSORS_KXTF9) += inv_mpu_kxtf9.o +inv_mpu_kxtf9-objs += kxtf9.o + +obj-$(CONFIG_MPU_SENSORS_BMA222) += inv_mpu_bma222.o +inv_mpu_bma222-objs += bma222.o + +obj-$(CONFIG_MPU_SENSORS_BMA250) += inv_mpu_bma250.o +inv_mpu_bma250-objs += bma250.o + +obj-$(CONFIG_MPU_SENSORS_KXSD9) += inv_mpu_kxsd9.o +inv_mpu_kxsd9-objs += kxsd9.o + +obj-$(CONFIG_MPU_SENSORS_LIS331DLH) += inv_mpu_lis331.o +inv_mpu_lis331-objs += lis331.o + +obj-$(CONFIG_MPU_SENSORS_LIS3DH) += inv_mpu_lis3dh.o +inv_mpu_lis3dh-objs += lis3dh.o + +obj-$(CONFIG_MPU_SENSORS_LSM303DLX_A) += inv_mpu_lsm303dlx_a.o +inv_mpu_lsm303dlx_a-objs += lsm303dlx_a.o + +obj-$(CONFIG_MPU_SENSORS_MMA8450) += inv_mpu_mma8450.o +inv_mpu_mma8450-objs += mma8450.o + +obj-$(CONFIG_MPU_SENSORS_MMA845X) += inv_mpu_mma845x.o +inv_mpu_mma845x-objs += mma845x.o + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER diff --git a/drivers/misc/inv_mpu/accel/adxl34x.c b/drivers/misc/inv_mpu/accel/adxl34x.c new file mode 100644 index 000000000000..f2bff8a75925 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/adxl34x.c @@ -0,0 +1,728 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file adxl34x.c + * @brief Accelerometer setup and handling methods for AD adxl345 and + * adxl346. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include + +#include +#include "mlsl.h" +#include "mldl_cfg.h" + +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* -------------------------------------------------------------------------- */ + +/* registers */ +#define ADXL34X_ODR_REG (0x2C) +#define ADXL34X_PWR_REG (0x2D) +#define ADXL34X_DATAFORMAT_REG (0x31) + +/* masks */ +#define ADXL34X_ODR_MASK (0x0F) +#define ADXL34X_PWR_SLEEP_MASK (0x04) +#define ADXL34X_PWR_MEAS_MASK (0x08) +#define ADXL34X_DATAFORMAT_JUSTIFY_MASK (0x04) +#define ADXL34X_DATAFORMAT_FSR_MASK (0x03) + +/* -------------------------------------------------------------------------- */ + +struct adxl34x_config { + unsigned int odr; /** < output data rate in mHz */ + unsigned int fsr; /** < full scale range mg */ + unsigned int fsr_reg_mask; /** < register setting for fsr */ +}; + +struct adxl34x_private_data { + struct adxl34x_config suspend; /** < suspend configuration */ + struct adxl34x_config resume; /** < resume configuration */ +}; + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct adxl34x_config *config, + int apply, + long odr) +{ + int result = INV_SUCCESS; + unsigned char new_odr_mask; + + /* ADXL346 (Rev. A) pages 13, 24 */ + if (odr >= 3200000) { + new_odr_mask = 0x0F; + config->odr = 3200000; + } else if (odr >= 1600000) { + new_odr_mask = 0x0E; + config->odr = 1600000; + } else if (odr >= 800000) { + new_odr_mask = 0x0D; + config->odr = 800000; + } else if (odr >= 400000) { + new_odr_mask = 0x0C; + config->odr = 400000; + } else if (odr >= 200000) { + new_odr_mask = 0x0B; + config->odr = 200000; + } else if (odr >= 100000) { + new_odr_mask = 0x0A; + config->odr = 100000; + } else if (odr >= 50000) { + new_odr_mask = 0x09; + config->odr = 50000; + } else if (odr >= 25000) { + new_odr_mask = 0x08; + config->odr = 25000; + } else if (odr >= 12500) { + new_odr_mask = 0x07; + config->odr = 12500; + } else if (odr >= 6250) { + new_odr_mask = 0x06; + config->odr = 6250; + } else if (odr >= 3130) { + new_odr_mask = 0x05; + config->odr = 3130; + } else if (odr >= 1560) { + new_odr_mask = 0x04; + config->odr = 1560; + } else if (odr >= 780) { + new_odr_mask = 0x03; + config->odr = 780; + } else if (odr >= 390) { + new_odr_mask = 0x02; + config->odr = 390; + } else if (odr >= 200) { + new_odr_mask = 0x01; + config->odr = 200; + } else { + new_odr_mask = 0x00; + config->odr = 100; + } + + if (apply) { + unsigned char reg_odr; + result = inv_serial_read(mlsl_handle, pdata->address, + ADXL34X_ODR_REG, 1, ®_odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg_odr &= ~ADXL34X_ODR_MASK; + reg_odr |= new_odr_mask; + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_ODR_REG, reg_odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("ODR: %d mHz\n", config->odr); + } + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range in milli gees (mg). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct adxl34x_config *config, + int apply, + long fsr) +{ + int result = INV_SUCCESS; + + if (fsr <= 2000) { + config->fsr_reg_mask = 0x00; + config->fsr = 2000; + } else if (fsr <= 4000) { + config->fsr_reg_mask = 0x01; + config->fsr = 4000; + } else if (fsr <= 8000) { + config->fsr_reg_mask = 0x02; + config->fsr = 8000; + } else { /* 8001 -> oo */ + config->fsr_reg_mask = 0x03; + config->fsr = 16000; + } + + if (apply) { + unsigned char reg_df; + result = inv_serial_read(mlsl_handle, pdata->address, + ADXL34X_DATAFORMAT_REG, 1, ®_df); + reg_df &= ~ADXL34X_DATAFORMAT_FSR_MASK; + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_DATAFORMAT_REG, + reg_df | config->fsr_reg_mask); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("FSR: %d mg\n", config->fsr); + } + return result; +} + +/** + * @brief facility to retrieve the device configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to store the returned configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct adxl34x_private_data *private_data = + (struct adxl34x_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +/** + * @brief device configuration facility. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to the configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct adxl34x_private_data *private_data = + (struct adxl34x_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return adxl34x_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return adxl34x_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return adxl34x_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return adxl34x_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + return INV_SUCCESS; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + + /* + struct adxl34x_config *suspend_config = + &((struct adxl34x_private_data *)pdata->private_data)->suspend; + + result = adxl34x_set_odr(mlsl_handle, pdata, suspend_config, + true, suspend_config->odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; +} + result = adxl34x_set_fsr(mlsl_handle, pdata, suspend_config, + true, suspend_config->fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; +} + */ + + /* + Page 25 + When clearing the sleep bit, it is recommended that the part + be placed into standby mode and then set back to measurement mode + with a subsequent write. + This is done to ensure that the device is properly biased if sleep + mode is manually disabled; otherwise, the first few samples of data + after the sleep bit is cleared may have additional noise, + especially if the device was asleep when the bit was cleared. */ + + /* go in standy-by mode (suspends measurements) */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_PWR_REG, ADXL34X_PWR_MEAS_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* and then in sleep */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_PWR_REG, + ADXL34X_PWR_MEAS_MASK | ADXL34X_PWR_SLEEP_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + struct adxl34x_config *resume_config = + &((struct adxl34x_private_data *)pdata->private_data)->resume; + unsigned char reg; + + /* + Page 25 + When clearing the sleep bit, it is recommended that the part + be placed into standby mode and then set back to measurement mode + with a subsequent write. + This is done to ensure that the device is properly biased if sleep + mode is manually disabled; otherwise, the first few samples of data + after the sleep bit is cleared may have additional noise, + especially if the device was asleep when the bit was cleared. */ + + /* remove sleep, but leave in stand-by */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_PWR_REG, ADXL34X_PWR_MEAS_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = adxl34x_set_odr(mlsl_handle, pdata, resume_config, + true, resume_config->odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* + -> FSR + -> Justiy bit for Big endianess + -> resulution to 10 bits + */ + reg = ADXL34X_DATAFORMAT_JUSTIFY_MASK; + reg |= resume_config->fsr_reg_mask; + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_DATAFORMAT_REG, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* go in measurement mode */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_PWR_REG, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* DATA_FORMAT: full resolution of +/-2g; data is left justified */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + 0x31, reg); + + return result; +} + +/** + * @brief one-time device driver initialization function. + * If the driver is built as a kernel module, this function will be + * called when the module is loaded in the kernel. + * If the driver is built-in in the kernel, this function will be + * called at boot time. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + long range; + + struct adxl34x_private_data *private_data; + private_data = (struct adxl34x_private_data *) + kzalloc(sizeof(struct adxl34x_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + result = adxl34x_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = adxl34x_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + range = range_fixedpoint_to_long_mg(slave->range); + result = adxl34x_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + result = adxl34x_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = adxl34x_suspend(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief one-time device driver exit function. + * If the driver is built as a kernel module, this function will be + * called when the module is removed from the kernel. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int adxl34x_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + return result; +} + +static struct ext_slave_descr adxl34x_descr = { + .init = adxl34x_init, + .exit = adxl34x_exit, + .suspend = adxl34x_suspend, + .resume = adxl34x_resume, + .read = adxl34x_read, + .config = adxl34x_config, + .get_config = adxl34x_get_config, + .name = "adxl34x", /* 5 or 6 */ + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_ADXL34X, + .read_reg = 0x32, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *adxl34x_get_slave_descr(void) +{ + return &adxl34x_descr; +} + +/* -------------------------------------------------------------------------- */ +struct adxl34x_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int adxl34x_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct adxl34x_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + adxl34x_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int adxl34x_mod_remove(struct i2c_client *client) +{ + struct adxl34x_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + adxl34x_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id adxl34x_mod_id[] = { + { "adxl34x", ACCEL_ID_ADXL34X }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, adxl34x_mod_id); + +static struct i2c_driver adxl34x_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = adxl34x_mod_probe, + .remove = adxl34x_mod_remove, + .id_table = adxl34x_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "adxl34x_mod", + }, + .address_list = normal_i2c, +}; + +static int __init adxl34x_mod_init(void) +{ + int res = i2c_add_driver(&adxl34x_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "adxl34x_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit adxl34x_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&adxl34x_mod_driver); +} + +module_init(adxl34x_mod_init); +module_exit(adxl34x_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate ADXL34X sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("adxl34x_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/bma150.c b/drivers/misc/inv_mpu/accel/bma150.c new file mode 100644 index 000000000000..fd2d7b5dd1c3 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/bma150.c @@ -0,0 +1,777 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file bma150.c + * @brief Accelerometer setup and handling methods for Bosch BMA150. + */ +#define DEBUG +/* -------------------------------------------------------------------------- */ +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include "mlsl.h" +#include "mldl_cfg.h" + +/* -------------------------------------------------------------------------- */ +/* registers */ +#define BMA150_CTRL_REG (0x14) +#define BMA150_INT_REG (0x15) +#define BMA150_PWR_REG (0x0A) + +/* masks */ +#define BMA150_CTRL_MASK (0x18) +#define BMA150_CTRL_MASK_ODR (0xF8) +#define BMA150_CTRL_MASK_FSR (0xE7) +#define BMA150_INT_MASK_WUP (0xF8) +#define BMA150_INT_MASK_IRQ (0xDF) +#define BMA150_PWR_MASK_SLEEP (0x01) +#define BMA150_PWR_MASK_SOFT_RESET (0x02) + +/* -------------------------------------------------------------------------- */ +struct bma150_config { + unsigned int odr; /** < output data rate mHz */ + unsigned int fsr; /** < full scale range mgees */ + unsigned int irq_type; /** < type of IRQ, see bma150_set_irq */ + unsigned char ctrl_reg; /** < control register value */ + unsigned char int_reg; /** < interrupt control register value */ +}; + +struct bma150_private_data { + struct bma150_config suspend; /** < suspend configuration */ + struct bma150_config resume; /** < resume configuration */ +}; + +/** + * @brief Simply disables the IRQ since it is not usable on BMA150 devices. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * configuration to apply to, suspend or resume + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param irq_type + * the type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + * The only supported IRQ type is MPU_SLAVE_IRQ_TYPE_NONE which + * corresponds to disabling the IRQ completely. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma150_config *config, + int apply, + long irq_type) +{ + int result = INV_SUCCESS; + + if (irq_type != MPU_SLAVE_IRQ_TYPE_NONE) + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + + config->irq_type = MPU_SLAVE_IRQ_TYPE_NONE; + config->int_reg = 0x00; + + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_CTRL_REG, config->ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_INT_REG, config->int_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma150_config *config, + int apply, + long odr) +{ + unsigned char odr_bits = 0; + unsigned char wup_bits = 0; + int result = INV_SUCCESS; + + if (odr > 100000) { + config->odr = 190000; + odr_bits = 0x03; + } else if (odr > 50000) { + config->odr = 100000; + odr_bits = 0x02; + } else if (odr > 25000) { + config->odr = 50000; + odr_bits = 0x01; + } else if (odr > 0) { + config->odr = 25000; + odr_bits = 0x00; + } else { + config->odr = 0; + wup_bits = 0x00; + } + + config->int_reg &= BMA150_INT_MASK_WUP; + config->ctrl_reg &= BMA150_CTRL_MASK_ODR; + config->ctrl_reg |= odr_bits; + + MPL_LOGV("ODR: %d\n", config->odr); + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_CTRL_REG, config->ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_INT_REG, config->int_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma150_config *config, + int apply, + long fsr) +{ + unsigned char fsr_bits; + int result = INV_SUCCESS; + + if (fsr <= 2048) { + fsr_bits = 0x00; + config->fsr = 2048; + } else if (fsr <= 4096) { + fsr_bits = 0x08; + config->fsr = 4096; + } else { + fsr_bits = 0x10; + config->fsr = 8192; + } + + config->ctrl_reg &= BMA150_CTRL_MASK_FSR; + config->ctrl_reg |= fsr_bits; + + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_CTRL_REG, config->ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_CTRL_REG, config->ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @brief one-time device driver initialization function. + * If the driver is built as a kernel module, this function will be + * called when the module is loaded in the kernel. + * If the driver is built-in in the kernel, this function will be + * called at boot time. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg; + long range; + + struct bma150_private_data *private_data; + private_data = (struct bma150_private_data *) + kzalloc(sizeof(struct bma150_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_PWR_REG, BMA150_PWR_MASK_SOFT_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); + + result = inv_serial_read(mlsl_handle, pdata->address, + BMA150_CTRL_REG, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + private_data->resume.ctrl_reg = reg; + private_data->suspend.ctrl_reg = reg; + + result = inv_serial_read(mlsl_handle, pdata->address, + BMA150_INT_REG, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + private_data->resume.int_reg = reg; + private_data->suspend.int_reg = reg; + + result = bma150_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma150_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + range = range_fixedpoint_to_long_mg(slave->range); + result = bma150_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + result = bma150_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = bma150_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma150_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_PWR_REG, BMA150_PWR_MASK_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief one-time device driver exit function. + * If the driver is built as a kernel module, this function will be + * called when the module is removed from the kernel. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +/** + * @brief device configuration facility. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to the configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct bma150_private_data *private_data = + (struct bma150_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return bma150_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return bma150_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return bma150_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return bma150_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return bma150_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return bma150_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + return INV_SUCCESS; +} + +/** + * @brief facility to retrieve the device configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to store the returned configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct bma150_private_data *private_data = + (struct bma150_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.irq_type; + break; + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char ctrl_reg; + unsigned char int_reg; + + struct bma150_private_data *private_data = + (struct bma150_private_data *)(pdata->private_data); + + ctrl_reg = private_data->suspend.ctrl_reg; + int_reg = private_data->suspend.int_reg; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_PWR_REG, BMA150_PWR_MASK_SOFT_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_CTRL_REG, ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_INT_REG, int_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_PWR_REG, BMA150_PWR_MASK_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char ctrl_reg; + unsigned char int_reg; + + struct bma150_private_data *private_data = + (struct bma150_private_data *)(pdata->private_data); + + ctrl_reg = private_data->resume.ctrl_reg; + int_reg = private_data->resume.int_reg; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_PWR_REG, BMA150_PWR_MASK_SOFT_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_CTRL_REG, ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_INT_REG, int_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA150_PWR_REG, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma150_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + return inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); +} + +static struct ext_slave_descr bma150_descr = { + .init = bma150_init, + .exit = bma150_exit, + .suspend = bma150_suspend, + .resume = bma150_resume, + .read = bma150_read, + .config = bma150_config, + .get_config = bma150_get_config, + .name = "bma150", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_BMA150, + .read_reg = 0x02, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *bma150_get_slave_descr(void) +{ + return &bma150_descr; +} + +/* -------------------------------------------------------------------------- */ + +/* Platform data for the MPU */ +struct bma150_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int bma150_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct bma150_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + bma150_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int bma150_mod_remove(struct i2c_client *client) +{ + struct bma150_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + bma150_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id bma150_mod_id[] = { + { "bma150", ACCEL_ID_BMA150 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bma150_mod_id); + +static struct i2c_driver bma150_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = bma150_mod_probe, + .remove = bma150_mod_remove, + .id_table = bma150_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "bma150_mod", + }, + .address_list = normal_i2c, +}; + +static int __init bma150_mod_init(void) +{ + int res = i2c_add_driver(&bma150_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "bma150_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit bma150_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&bma150_mod_driver); +} + +module_init(bma150_mod_init); +module_exit(bma150_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate BMA150 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("bma150_mod"); + +/** + * @} + */ + diff --git a/drivers/misc/inv_mpu/accel/bma222.c b/drivers/misc/inv_mpu/accel/bma222.c new file mode 100644 index 000000000000..e9fc99b1a62d --- /dev/null +++ b/drivers/misc/inv_mpu/accel/bma222.c @@ -0,0 +1,654 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/* + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file bma222.c + * @brief Accelerometer setup and handling methods for Bosch BMA222. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include "mlsl.h" +#include "mldl_cfg.h" + +/* -------------------------------------------------------------------------- */ + +#define BMA222_STATUS_REG (0x0A) +#define BMA222_FSR_REG (0x0F) +#define ADXL34X_ODR_REG (0x10) +#define BMA222_PWR_REG (0x11) +#define BMA222_SOFTRESET_REG (0x14) + +#define BMA222_STATUS_RDY_MASK (0x80) +#define BMA222_FSR_MASK (0x0F) +#define BMA222_ODR_MASK (0x1F) +#define BMA222_PWR_SLEEP_MASK (0x80) +#define BMA222_PWR_AWAKE_MASK (0x00) +#define BMA222_SOFTRESET_MASK (0xB6) +#define BMA222_SOFTRESET_MASK (0xB6) + +/* -------------------------------------------------------------------------- */ + +struct bma222_config { + unsigned int odr; /** < output data rate in mHz */ + unsigned int fsr; /** < full scale range mg */ +}; + +struct bma222_private_data { + struct bma222_config suspend; /** < suspend configuration */ + struct bma222_config resume; /** < resume configuration */ +}; + + +/* -------------------------------------------------------------------------- */ + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma222_config *config, + int apply, + long odr) +{ + int result = INV_SUCCESS; + unsigned char reg_odr; + + if (odr >= 1000000) { + reg_odr = 0x0F; + config->odr = 1000000; + } else if (odr >= 500000) { + reg_odr = 0x0E; + config->odr = 500000; + } else if (odr >= 250000) { + reg_odr = 0x0D; + config->odr = 250000; + } else if (odr >= 125000) { + reg_odr = 0x0C; + config->odr = 125000; + } else if (odr >= 62500) { + reg_odr = 0x0B; + config->odr = 62500; + } else if (odr >= 32000) { + reg_odr = 0x0A; + config->odr = 32000; + } else if (odr >= 16000) { + reg_odr = 0x09; + config->odr = 16000; + } else { + reg_odr = 0x08; + config->odr = 8000; + } + + if (apply) { + MPL_LOGV("ODR: %d\n", config->odr); + result = inv_serial_single_write(mlsl_handle, pdata->address, + ADXL34X_ODR_REG, reg_odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma222_config *config, + int apply, + long fsr) +{ + int result = INV_SUCCESS; + unsigned char reg_fsr_mask; + + if (fsr <= 2000) { + reg_fsr_mask = 0x03; + config->fsr = 2000; + } else if (fsr <= 4000) { + reg_fsr_mask = 0x05; + config->fsr = 4000; + } else if (fsr <= 8000) { + reg_fsr_mask = 0x08; + config->fsr = 8000; + } else { /* 8001 -> oo */ + reg_fsr_mask = 0x0C; + config->fsr = 16000; + } + + if (apply) { + MPL_LOGV("FSR: %d\n", config->fsr); + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA222_FSR_REG, reg_fsr_mask); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @brief one-time device driver initialization function. + * If the driver is built as a kernel module, this function will be + * called when the module is loaded in the kernel. + * If the driver is built-in in the kernel, this function will be + * called at boot time. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + + struct bma222_private_data *private_data; + private_data = (struct bma222_private_data *) + kzalloc(sizeof(struct bma222_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA222_SOFTRESET_REG, BMA222_SOFTRESET_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); + + result = bma222_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma222_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = bma222_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, 2000); + result = bma222_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, 2000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA222_PWR_REG, BMA222_PWR_SLEEP_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief one-time device driver exit function. + * If the driver is built as a kernel module, this function will be + * called when the module is removed from the kernel. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + + +/** + * @brief facility to retrieve the device configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to store the returned configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct bma222_private_data *private_data = + (struct bma222_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +/** + * @brief device configuration facility. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to the configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct bma222_private_data *private_data = + (struct bma222_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return bma222_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return bma222_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return bma222_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return bma222_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + return INV_SUCCESS; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct bma222_config *suspend_config = + &((struct bma222_private_data *)pdata->private_data)->suspend; + + result = bma222_set_odr(mlsl_handle, pdata, suspend_config, + true, suspend_config->odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma222_set_fsr(mlsl_handle, pdata, suspend_config, + true, suspend_config->fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA222_PWR_REG, BMA222_PWR_SLEEP_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + msleep(3); /* 3 ms powerup time maximum */ + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct bma222_config *resume_config = + &((struct bma222_private_data *)pdata->private_data)->resume; + + /* Soft reset */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA222_SOFTRESET_REG, BMA222_SOFTRESET_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(10); + + result = bma222_set_odr(mlsl_handle, pdata, resume_config, + true, resume_config->odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma222_set_fsr(mlsl_handle, pdata, resume_config, + true, resume_config->fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma222_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + result = inv_serial_read(mlsl_handle, pdata->address, + BMA222_STATUS_REG, 1, data); + if (data[0] & BMA222_STATUS_RDY_MASK) { + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + return result; + } else + return INV_ERROR_ACCEL_DATA_NOT_READY; +} + +static struct ext_slave_descr bma222_descr = { + .init = bma222_init, + .exit = bma222_exit, + .suspend = bma222_suspend, + .resume = bma222_resume, + .read = bma222_read, + .config = bma222_config, + .get_config = bma222_get_config, + .name = "bma222", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_BMA222, + .read_reg = 0x02, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *bma222_get_slave_descr(void) +{ + return &bma222_descr; +} + +/* -------------------------------------------------------------------------- */ + +struct bma222_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int bma222_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct bma222_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + bma222_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int bma222_mod_remove(struct i2c_client *client) +{ + struct bma222_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + bma222_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id bma222_mod_id[] = { + { "bma222", ACCEL_ID_BMA222 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bma222_mod_id); + +static struct i2c_driver bma222_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = bma222_mod_probe, + .remove = bma222_mod_remove, + .id_table = bma222_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "bma222_mod", + }, + .address_list = normal_i2c, +}; + +static int __init bma222_mod_init(void) +{ + int res = i2c_add_driver(&bma222_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "bma222_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit bma222_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&bma222_mod_driver); +} + +module_init(bma222_mod_init); +module_exit(bma222_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate BMA222 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("bma222_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/bma250.c b/drivers/misc/inv_mpu/accel/bma250.c new file mode 100644 index 000000000000..6a245f4566aa --- /dev/null +++ b/drivers/misc/inv_mpu/accel/bma250.c @@ -0,0 +1,787 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file bma250.c + * @brief Accelerometer setup and handling methods for Bosch BMA250. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include "mlsl.h" +#include "mldl_cfg.h" + +/* -------------------------------------------------------------------------- */ + +/* registers */ +#define BMA250_STATUS_REG (0x0A) +#define BMA250_FSR_REG (0x0F) +#define BMA250_ODR_REG (0x10) +#define BMA250_PWR_REG (0x11) +#define BMA250_SOFTRESET_REG (0x14) +#define BMA250_INT_TYPE_REG (0x17) +#define BMA250_INT_DST_REG (0x1A) +#define BMA250_INT_SRC_REG (0x1E) + +/* masks */ +#define BMA250_STATUS_RDY_MASK (0x80) +#define BMA250_FSR_MASK (0x0F) +#define BMA250_ODR_MASK (0x1F) +#define BMA250_PWR_SLEEP_MASK (0x80) +#define BMA250_PWR_AWAKE_MASK (0x00) +#define BMA250_SOFTRESET_MASK (0xB6) +#define BMA250_INT_TYPE_MASK (0x10) +#define BMA250_INT_DST_1_MASK (0x01) +#define BMA250_INT_DST_2_MASK (0x80) +#define BMA250_INT_SRC_MASK (0x00) + +/* -------------------------------------------------------------------------- */ + +struct bma250_config { + unsigned int odr; /** < output data rate in mHz */ + unsigned int fsr; /** < full scale range mg */ + unsigned char irq_type; +}; + +struct bma250_private_data { + struct bma250_config suspend; /** < suspend configuration */ + struct bma250_config resume; /** < resume configuration */ +}; + +/* -------------------------------------------------------------------------- */ +/** + * @brief Sets the IRQ to fire when one of the IRQ events occur. + * Threshold and duration will not be used unless the type is MOT or + * NMOT. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * configuration to apply to, suspend or resume + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param irq_type + * the type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma250_config *config, + int apply, long irq_type) +{ + int result = INV_SUCCESS; + unsigned char irqtype_reg; + unsigned char irqdst_reg; + unsigned char irqsrc_reg; + + switch (irq_type) { + case MPU_SLAVE_IRQ_TYPE_DATA_READY: + /* data ready int. */ + irqtype_reg = BMA250_INT_TYPE_MASK; + /* routed to interrupt pin 1 */ + irqdst_reg = BMA250_INT_DST_1_MASK; + /* from filtered data */ + irqsrc_reg = BMA250_INT_SRC_MASK; + break; + /* unfinished + case MPU_SLAVE_IRQ_TYPE_MOTION: + reg1 = 0x00; + reg2 = config->mot_int1_cfg; + reg3 = ; + break; + */ + case MPU_SLAVE_IRQ_TYPE_NONE: + irqtype_reg = 0x00; + irqdst_reg = 0x00; + irqsrc_reg = 0x00; + break; + default: + return INV_ERROR_INVALID_PARAMETER; + break; + } + + config->irq_type = (unsigned char)irq_type; + + if (apply) { + /* select the type of interrupt to use */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_INT_TYPE_REG, irqtype_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* select to which interrupt pin to route it to */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_INT_DST_REG, irqdst_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* select whether the interrupt works off filtered or + unfiltered data */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_INT_SRC_REG, irqsrc_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma250_config *config, + int apply, + long odr) +{ + int result = INV_SUCCESS; + unsigned char reg_odr; + + /* Table uses bandwidth which is half the sample rate */ + odr = odr >> 1; + if (odr >= 1000000) { + reg_odr = 0x0F; + config->odr = 2000000; + } else if (odr >= 500000) { + reg_odr = 0x0E; + config->odr = 1000000; + } else if (odr >= 250000) { + reg_odr = 0x0D; + config->odr = 500000; + } else if (odr >= 125000) { + reg_odr = 0x0C; + config->odr = 250000; + } else if (odr >= 62500) { + reg_odr = 0x0B; + config->odr = 125000; + } else if (odr >= 31250) { + reg_odr = 0x0A; + config->odr = 62500; + } else if (odr >= 15630) { + reg_odr = 0x09; + config->odr = 31250; + } else { + reg_odr = 0x08; + config->odr = 15630; + } + + if (apply) { + MPL_LOGV("ODR: %d\n", config->odr); + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_ODR_REG, reg_odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct bma250_config *config, + int apply, + long fsr) +{ + int result = INV_SUCCESS; + unsigned char reg_fsr_mask; + + if (fsr <= 2000) { + reg_fsr_mask = 0x03; + config->fsr = 2000; + } else if (fsr <= 4000) { + reg_fsr_mask = 0x05; + config->fsr = 4000; + } else if (fsr <= 8000) { + reg_fsr_mask = 0x08; + config->fsr = 8000; + } else { /* 8001 -> oo */ + reg_fsr_mask = 0x0C; + config->fsr = 16000; + } + + if (apply) { + MPL_LOGV("FSR: %d\n", config->fsr); + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_FSR_REG, reg_fsr_mask); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @brief one-time device driver initialization function. + * If the driver is built as a kernel module, this function will be + * called when the module is loaded in the kernel. + * If the driver is built-in in the kernel, this function will be + * called at boot time. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + long range; + + struct bma250_private_data *private_data; + private_data = kzalloc(sizeof(struct bma250_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_SOFTRESET_REG, BMA250_SOFTRESET_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); + + result = bma250_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma250_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + range = range_fixedpoint_to_long_mg(slave->range); + result = bma250_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + result = bma250_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = bma250_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma250_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_PWR_REG, BMA250_PWR_SLEEP_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief one-time device driver exit function. + * If the driver is built as a kernel module, this function will be + * called when the module is removed from the kernel. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +/** + * @brief device configuration facility. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to the configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct bma250_private_data *private_data = + (struct bma250_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return bma250_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return bma250_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return bma250_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return bma250_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return bma250_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return bma250_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + return INV_SUCCESS; +} + +/** + * @brief facility to retrieve the device configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to store the returned configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct bma250_private_data *private_data = + (struct bma250_private_data *)(pdata->private_data); + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.irq_type; + break; + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct bma250_config *suspend_config = + &((struct bma250_private_data *)pdata->private_data)->suspend; + + result = bma250_set_odr(mlsl_handle, pdata, suspend_config, + true, suspend_config->odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma250_set_fsr(mlsl_handle, pdata, suspend_config, + true, suspend_config->fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma250_set_irq(mlsl_handle, pdata, suspend_config, + true, suspend_config->irq_type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_PWR_REG, BMA250_PWR_SLEEP_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + msleep(3); /* 3 ms powerup time maximum */ + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct bma250_config *resume_config = + &((struct bma250_private_data *)pdata->private_data)->resume; + + result = bma250_set_odr(mlsl_handle, pdata, resume_config, + true, resume_config->odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma250_set_fsr(mlsl_handle, pdata, resume_config, + true, resume_config->fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = bma250_set_irq(mlsl_handle, pdata, resume_config, + true, resume_config->irq_type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + BMA250_PWR_REG, BMA250_PWR_AWAKE_MASK); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int bma250_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + result = inv_serial_read(mlsl_handle, pdata->address, + BMA250_STATUS_REG, 1, data); + if (1) { /* KLP - workaroud for small data ready window */ + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + return result; + } else + return INV_ERROR_ACCEL_DATA_NOT_READY; +} + +static struct ext_slave_descr bma250_descr = { + .init = bma250_init, + .exit = bma250_exit, + .suspend = bma250_suspend, + .resume = bma250_resume, + .read = bma250_read, + .config = bma250_config, + .get_config = bma250_get_config, + .name = "bma250", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_BMA250, + .read_reg = 0x02, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *bma250_get_slave_descr(void) +{ + return &bma250_descr; +} + +/* -------------------------------------------------------------------------- */ + +/* Platform data for the MPU */ +struct bma250_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int bma250_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct bma250_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + bma250_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int bma250_mod_remove(struct i2c_client *client) +{ + struct bma250_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + bma250_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id bma250_mod_id[] = { + { "bma250", ACCEL_ID_BMA250 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bma250_mod_id); + +static struct i2c_driver bma250_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = bma250_mod_probe, + .remove = bma250_mod_remove, + .id_table = bma250_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "bma250_mod", + }, + .address_list = normal_i2c, +}; + +static int __init bma250_mod_init(void) +{ + int res = i2c_add_driver(&bma250_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "bma250_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit bma250_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&bma250_mod_driver); +} + +module_init(bma250_mod_init); +module_exit(bma250_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate BMA250 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("bma250_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/cma3000.c b/drivers/misc/inv_mpu/accel/cma3000.c new file mode 100644 index 000000000000..496d1f29bdc0 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/cma3000.c @@ -0,0 +1,222 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/* + * @addtogroup ACCELDL + * @brief Accelerometer setup and handling methods for VTI CMA3000. + * + * @{ + * @file cma3000.c + * @brief Accelerometer setup and handling methods for VTI CMA3000 + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* -------------------------------------------------------------------------- */ + +static int cma3000_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + /* RAM reset */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, 0x1d, 0xcd); + return result; +} + +static int cma3000_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + + return INV_SUCCESS; +} + +static int cma3000_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + result = inv_serial_read(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + return result; +} + +static struct ext_slave_descr cma3000_descr = { + .init = NULL, + .exit = NULL, + .suspend = cma3000_suspend, + .resume = cma3000_resume, + .read = cma3000_read, + .config = NULL, + .get_config = NULL, + .name = "cma3000", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ID_INVALID, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {2, 0}, + .trigger = NULL, + +}; + +static +struct ext_slave_descr *cma3000_get_slave_descr(void) +{ + return &cma3000_descr; +} + +/* -------------------------------------------------------------------------- */ + +struct cma3000_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int cma3000_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct cma3000_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + cma3000_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int cma3000_mod_remove(struct i2c_client *client) +{ + struct cma3000_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + cma3000_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id cma3000_mod_id[] = { + { "cma3000", ACCEL_ID_CMA3000 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cma3000_mod_id); + +static struct i2c_driver cma3000_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = cma3000_mod_probe, + .remove = cma3000_mod_remove, + .id_table = cma3000_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "cma3000_mod", + }, + .address_list = normal_i2c, +}; + +static int __init cma3000_mod_init(void) +{ + int res = i2c_add_driver(&cma3000_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "cma3000_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit cma3000_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&cma3000_mod_driver); +} + +module_init(cma3000_mod_init); +module_exit(cma3000_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate CMA3000 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("cma3000_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/kxsd9.c b/drivers/misc/inv_mpu/accel/kxsd9.c new file mode 100644 index 000000000000..5cb4eaf6b4ab --- /dev/null +++ b/drivers/misc/inv_mpu/accel/kxsd9.c @@ -0,0 +1,264 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Accelerometer setup and handling methods for Kionix KXSD9. + * + * @{ + * @file kxsd9.c + * @brief Accelerometer setup and handling methods for Kionix KXSD9. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* -------------------------------------------------------------------------- */ + +static int kxsd9_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + /* CTRL_REGB: low-power standby mode */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, 0x0d, 0x0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +/* full scale setting - register and mask */ +#define ACCEL_KIONIX_CTRL_REG (0x0C) +#define ACCEL_KIONIX_CTRL_MASK (0x3) + +static int kxsd9_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char reg; + + /* Full Scale */ + reg = 0x0; + reg &= ~ACCEL_KIONIX_CTRL_MASK; + reg |= 0x00; + if (slave->range.mantissa == 4) { /* 4g scale = 4.9951 */ + reg |= 0x2; + slave->range.fraction = 9951; + } else if (slave->range.mantissa == 7) { /* 6g scale = 7.5018 */ + reg |= 0x1; + slave->range.fraction = 5018; + } else if (slave->range.mantissa == 9) { /* 8g scale = 9.9902 */ + reg |= 0x0; + slave->range.fraction = 9902; + } else { + slave->range.mantissa = 2; /* 2g scale = 2.5006 */ + slave->range.fraction = 5006; + reg |= 0x3; + } + reg |= 0xC0; /* 100Hz LPF */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_KIONIX_CTRL_REG, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* normal operation */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, 0x0d, 0x40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_SUCCESS; +} + +static int kxsd9_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + return result; +} + +static struct ext_slave_descr kxsd9_descr = { + .init = NULL, + .exit = NULL, + .suspend = kxsd9_suspend, + .resume = kxsd9_resume, + .read = kxsd9_read, + .config = NULL, + .get_config = NULL, + .name = "kxsd9", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_KXSD9, + .read_reg = 0x00, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {2, 5006}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *kxsd9_get_slave_descr(void) +{ + return &kxsd9_descr; +} + +/* -------------------------------------------------------------------------- */ +struct kxsd9_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int kxsd9_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct kxsd9_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + kxsd9_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int kxsd9_mod_remove(struct i2c_client *client) +{ + struct kxsd9_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + kxsd9_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id kxsd9_mod_id[] = { + { "kxsd9", ACCEL_ID_KXSD9 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, kxsd9_mod_id); + +static struct i2c_driver kxsd9_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = kxsd9_mod_probe, + .remove = kxsd9_mod_remove, + .id_table = kxsd9_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "kxsd9_mod", + }, + .address_list = normal_i2c, +}; + +static int __init kxsd9_mod_init(void) +{ + int res = i2c_add_driver(&kxsd9_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "kxsd9_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit kxsd9_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&kxsd9_mod_driver); +} + +module_init(kxsd9_mod_init); +module_exit(kxsd9_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate KXSD9 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("kxsd9_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/kxtf9.c b/drivers/misc/inv_mpu/accel/kxtf9.c new file mode 100755 index 000000000000..80776f249c63 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/kxtf9.c @@ -0,0 +1,841 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Accelerometer setup and handling methods for Kionix KXTF9. + * + * @{ + * @file kxtf9.c + * @brief Accelerometer setup and handling methods for Kionix KXTF9. +*/ + +/* -------------------------------------------------------------------------- */ + +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 1 + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +#define KXTF9_XOUT_HPF_L (0x00) /* 0000 0000 */ +#define KXTF9_XOUT_HPF_H (0x01) /* 0000 0001 */ +#define KXTF9_YOUT_HPF_L (0x02) /* 0000 0010 */ +#define KXTF9_YOUT_HPF_H (0x03) /* 0000 0011 */ +#define KXTF9_ZOUT_HPF_L (0x04) /* 0001 0100 */ +#define KXTF9_ZOUT_HPF_H (0x05) /* 0001 0101 */ +#define KXTF9_XOUT_L (0x06) /* 0000 0110 */ +#define KXTF9_XOUT_H (0x07) /* 0000 0111 */ +#define KXTF9_YOUT_L (0x08) /* 0000 1000 */ +#define KXTF9_YOUT_H (0x09) /* 0000 1001 */ +#define KXTF9_ZOUT_L (0x0A) /* 0001 1010 */ +#define KXTF9_ZOUT_H (0x0B) /* 0001 1011 */ +#define KXTF9_ST_RESP (0x0C) /* 0000 1100 */ +#define KXTF9_WHO_AM_I (0x0F) /* 0000 1111 */ +#define KXTF9_TILT_POS_CUR (0x10) /* 0001 0000 */ +#define KXTF9_TILT_POS_PRE (0x11) /* 0001 0001 */ +#define KXTF9_INT_SRC_REG1 (0x15) /* 0001 0101 */ +#define KXTF9_INT_SRC_REG2 (0x16) /* 0001 0110 */ +#define KXTF9_STATUS_REG (0x18) /* 0001 1000 */ +#define KXTF9_INT_REL (0x1A) /* 0001 1010 */ +#define KXTF9_CTRL_REG1 (0x1B) /* 0001 1011 */ +#define KXTF9_CTRL_REG2 (0x1C) /* 0001 1100 */ +#define KXTF9_CTRL_REG3 (0x1D) /* 0001 1101 */ +#define KXTF9_INT_CTRL_REG1 (0x1E) /* 0001 1110 */ +#define KXTF9_INT_CTRL_REG2 (0x1F) /* 0001 1111 */ +#define KXTF9_INT_CTRL_REG3 (0x20) /* 0010 0000 */ +#define KXTF9_DATA_CTRL_REG (0x21) /* 0010 0001 */ +#define KXTF9_TILT_TIMER (0x28) /* 0010 1000 */ +#define KXTF9_WUF_TIMER (0x29) /* 0010 1001 */ +#define KXTF9_TDT_TIMER (0x2B) /* 0010 1011 */ +#define KXTF9_TDT_H_THRESH (0x2C) /* 0010 1100 */ +#define KXTF9_TDT_L_THRESH (0x2D) /* 0010 1101 */ +#define KXTF9_TDT_TAP_TIMER (0x2E) /* 0010 1110 */ +#define KXTF9_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */ +#define KXTF9_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */ +#define KXTF9_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */ +#define KXTF9_WUF_THRESH (0x5A) /* 0101 1010 */ +#define KXTF9_TILT_ANGLE (0x5C) /* 0101 1100 */ +#define KXTF9_HYST_SET (0x5F) /* 0101 1111 */ + +#define KXTF9_MAX_DUR (0xFF) +#define KXTF9_MAX_THS (0xFF) +#define KXTF9_THS_COUNTS_P_G (32) + +/* -------------------------------------------------------------------------- */ + +struct kxtf9_config { + unsigned long odr; /* Output data rate mHz */ + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ + unsigned int irq_type; + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char reg_odr; + unsigned char reg_int_cfg1; + unsigned char reg_int_cfg2; + unsigned char ctrl_reg1; +}; + +struct kxtf9_private_data { + struct kxtf9_config suspend; + struct kxtf9_config resume; +}; + +static int kxtf9_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, int apply, long ths) +{ + int result = INV_SUCCESS; + if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS) + ths = (long)(KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char) + ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + config->reg_ths); + return result; +} + +static int kxtf9_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, int apply, long dur) +{ + int result = INV_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000L; + config->dur = dur; + + if (reg_dur > KXTF9_MAX_DUR) + reg_dur = KXTF9_MAX_DUR; + + config->reg_dur = (unsigned char)reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int kxtf9_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, int apply, long irq_type) +{ + int result = INV_SUCCESS; + struct kxtf9_private_data *private_data = pdata->private_data; + + config->irq_type = (unsigned char)irq_type; + config->ctrl_reg1 &= ~0x22; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + config->ctrl_reg1 |= 0x20; + config->reg_int_cfg1 = 0x38; + config->reg_int_cfg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + config->ctrl_reg1 |= 0x02; + if ((unsigned long)config == + (unsigned long)&private_data->suspend) + config->reg_int_cfg1 = 0x34; + else + config->reg_int_cfg1 = 0x24; + config->reg_int_cfg2 = 0xE0; + } else { + config->reg_int_cfg1 = 0x00; + config->reg_int_cfg2 = 0x00; + } + + if (apply) { + /* Must clear bit 7 before writing new configuration */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + config->reg_int_cfg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG2, + config->reg_int_cfg2); + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n", + (unsigned long)config->ctrl_reg1, + (unsigned long)config->reg_int_cfg1, + (unsigned long)config->reg_int_cfg2); + + return result; +} + +/** + * Set the Output data rate for the particular configuration + * + * @param config Config to modify with new ODR + * @param odr Output data rate in units of 1/1000Hz + */ +static int kxtf9_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, int apply, long odr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + /* Data sheet says there is 12.5 hz, but that seems to produce a single + * correct data value, thus we remove it from the table */ + if (odr > 400000L) { + config->odr = 800000L; + bits = 0x06; + } else if (odr > 200000L) { + config->odr = 400000L; + bits = 0x05; + } else if (odr > 100000L) { + config->odr = 200000L; + bits = 0x04; + } else if (odr > 50000) { + config->odr = 100000L; + bits = 0x03; + } else if (odr > 25000) { + config->odr = 50000; + bits = 0x02; + } else if (odr != 0) { + config->odr = 25000; + bits = 0x01; + } else { + config->odr = 0; + bits = 0; + } + + if (odr != 0) + config->ctrl_reg1 |= 0x80; + else + config->ctrl_reg1 &= ~0x80; + + config->reg_odr = bits; + kxtf9_set_dur(mlsl_handle, pdata, config, apply, config->dur); + MPL_LOGV("ODR: %ld, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + config->reg_odr); + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + return result; +} + +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int kxtf9_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, int apply, long fsr) +{ + int result = INV_SUCCESS; + + config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7); + if (fsr <= 2000) { + config->fsr = 2000; + config->ctrl_reg1 |= 0x00; + } else if (fsr <= 4000) { + config->fsr = 4000; + config->ctrl_reg1 |= 0x08; + } else { + config->fsr = 8000; + config->ctrl_reg1 |= 0x10; + } + + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) { + /* Must clear bit 7 before writing new configuration */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + return result; +} + +static int kxtf9_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char data; + struct kxtf9_private_data *private_data = pdata->private_data; + + /* Wake up */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* INT_CTRL_REG1: */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + private_data->suspend.reg_int_cfg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* WUF_THRESH: */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + private_data->suspend.reg_ths); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* DATA_CTRL_REG */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + private_data->suspend.reg_odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* WUF_TIMER */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, + private_data->suspend.reg_dur); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Normal operation */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + private_data->suspend.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + KXTF9_INT_REL, 1, &data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/* full scale setting - register and mask */ +#define ACCEL_KIONIX_CTRL_REG (0x1b) +#define ACCEL_KIONIX_CTRL_MASK (0x18) + +static int kxtf9_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char data; + struct kxtf9_private_data *private_data = pdata->private_data; + + /* Wake up */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* INT_CTRL_REG1: */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + private_data->resume.reg_int_cfg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* WUF_THRESH: */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + private_data->resume.reg_ths); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* DATA_CTRL_REG */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + private_data->resume.reg_odr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* WUF_TIMER */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, + private_data->resume.reg_dur); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Normal operation */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + private_data->resume.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + KXTF9_INT_REL, 1, &data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_SUCCESS; +} + +static int kxtf9_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + + struct kxtf9_private_data *private_data; + int result = INV_SUCCESS; + + private_data = (struct kxtf9_private_data *) + kzalloc(sizeof(struct kxtf9_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + /* RAM reset */ + /* Fastest Reset */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Fastest Reset */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, 0x36); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Reset */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + KXTF9_CTRL_REG3, 0xcd); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(2); + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0xC0; + private_data->suspend.ctrl_reg1 = 0x40; + + result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend, + false, 1000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume, + false, 2540); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 50000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000L); + + result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, 2000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, 2000); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend, + false, 80); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume, + false, 40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int kxtf9_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int kxtf9_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct kxtf9_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return kxtf9_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return kxtf9_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return kxtf9_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return kxtf9_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return kxtf9_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return kxtf9_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return kxtf9_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return kxtf9_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return kxtf9_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return kxtf9_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int kxtf9_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct kxtf9_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.irq_type; + break; + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int kxtf9_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + unsigned char reg; + result = inv_serial_read(mlsl_handle, pdata->address, + KXTF9_INT_SRC_REG2, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!(reg & 0x10)) + return INV_ERROR_ACCEL_DATA_NOT_READY; + + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static struct ext_slave_descr kxtf9_descr = { + .init = kxtf9_init, + .exit = kxtf9_exit, + .suspend = kxtf9_suspend, + .resume = kxtf9_resume, + .read = kxtf9_read, + .config = kxtf9_config, + .get_config = kxtf9_get_config, + .name = "kxtf9", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_KXTF9, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *kxtf9_get_slave_descr(void) +{ + return &kxtf9_descr; +} + +/* -------------------------------------------------------------------------- */ +struct kxtf9_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int kxtf9_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct kxtf9_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + kxtf9_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int kxtf9_mod_remove(struct i2c_client *client) +{ + struct kxtf9_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + kxtf9_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id kxtf9_mod_id[] = { + { "kxtf9", ACCEL_ID_KXTF9 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, kxtf9_mod_id); + +static struct i2c_driver kxtf9_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = kxtf9_mod_probe, + .remove = kxtf9_mod_remove, + .id_table = kxtf9_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "kxtf9_mod", + }, + .address_list = normal_i2c, +}; + +static int __init kxtf9_mod_init(void) +{ + int res = i2c_add_driver(&kxtf9_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "kxtf9_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit kxtf9_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&kxtf9_mod_driver); +} + +module_init(kxtf9_mod_init); +module_exit(kxtf9_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate KXTF9 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("kxtf9_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/lis331.c b/drivers/misc/inv_mpu/accel/lis331.c new file mode 100644 index 000000000000..bcbec252af97 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/lis331.c @@ -0,0 +1,745 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file lis331.c + * @brief Accelerometer setup and handling methods for ST LIS331DLH. + */ + +/* -------------------------------------------------------------------------- */ + +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 1 + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* full scale setting - register & mask */ +#define LIS331DLH_CTRL_REG1 (0x20) +#define LIS331DLH_CTRL_REG2 (0x21) +#define LIS331DLH_CTRL_REG3 (0x22) +#define LIS331DLH_CTRL_REG4 (0x23) +#define LIS331DLH_CTRL_REG5 (0x24) +#define LIS331DLH_HP_FILTER_RESET (0x25) +#define LIS331DLH_REFERENCE (0x26) +#define LIS331DLH_STATUS_REG (0x27) +#define LIS331DLH_OUT_X_L (0x28) +#define LIS331DLH_OUT_X_H (0x29) +#define LIS331DLH_OUT_Y_L (0x2a) +#define LIS331DLH_OUT_Y_H (0x2b) +#define LIS331DLH_OUT_Z_L (0x2b) +#define LIS331DLH_OUT_Z_H (0x2d) + +#define LIS331DLH_INT1_CFG (0x30) +#define LIS331DLH_INT1_SRC (0x31) +#define LIS331DLH_INT1_THS (0x32) +#define LIS331DLH_INT1_DURATION (0x33) + +#define LIS331DLH_INT2_CFG (0x34) +#define LIS331DLH_INT2_SRC (0x35) +#define LIS331DLH_INT2_THS (0x36) +#define LIS331DLH_INT2_DURATION (0x37) + +/* CTRL_REG1 */ +#define LIS331DLH_CTRL_MASK (0x30) +#define LIS331DLH_SLEEP_MASK (0x20) +#define LIS331DLH_PWR_MODE_NORMAL (0x20) + +#define LIS331DLH_MAX_DUR (0x7F) + + +/* -------------------------------------------------------------------------- */ + +struct lis331dlh_config { + unsigned int odr; + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; +}; + +struct lis331dlh_private_data { + struct lis331dlh_config suspend; + struct lis331dlh_config resume; +}; + +/* -------------------------------------------------------------------------- */ +static int lis331dlh_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, long ths) +{ + int result = INV_SUCCESS; + if ((unsigned int)ths >= config->fsr) + ths = (long)config->fsr - 1; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_THS, + config->reg_ths); + return result; +} + +static int lis331dlh_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, long dur) +{ + int result = INV_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000L; + config->dur = dur; + + if (reg_dur > LIS331DLH_MAX_DUR) + reg_dur = LIS331DLH_MAX_DUR; + + config->reg_dur = (unsigned char)reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_DURATION, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int lis331dlh_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, long irq_type) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = config->mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG3, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_CFG, reg2); + } + + return result; +} + +/** + * Set the Output data rate for the particular configuration + * + * @param config Config to modify with new ODR + * @param odr Output data rate in units of 1/1000Hz + */ +static int lis331dlh_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, long odr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + /* normal power modes */ + if (odr > 400000) { + config->odr = 1000000; + bits = LIS331DLH_PWR_MODE_NORMAL | 0x18; + } else if (odr > 100000) { + config->odr = 400000; + bits = LIS331DLH_PWR_MODE_NORMAL | 0x10; + } else if (odr > 50000) { + config->odr = 100000; + bits = LIS331DLH_PWR_MODE_NORMAL | 0x08; + } else if (odr > 10000) { + config->odr = 50000; + bits = LIS331DLH_PWR_MODE_NORMAL | 0x00; + /* low power modes */ + } else if (odr > 5000) { + config->odr = 10000; + bits = 0xC0; + } else if (odr > 2000) { + config->odr = 5000; + bits = 0xA0; + } else if (odr > 1000) { + config->odr = 2000; + bits = 0x80; + } else if (odr > 500) { + config->odr = 1000; + bits = 0x60; + } else if (odr > 0) { + config->odr = 500; + bits = 0x40; + } else { + config->odr = 0; + bits = 0; + } + + config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7); + lis331dlh_set_dur(mlsl_handle, pdata, config, apply, config->dur); + MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG1, + config->ctrl_reg1); + return result; +} + +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int lis331dlh_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis331dlh_config *config, + int apply, long fsr) +{ + unsigned char reg1 = 0x40; + int result = INV_SUCCESS; + + if (fsr <= 2048) { + config->fsr = 2048; + } else if (fsr <= 4096) { + reg1 |= 0x30; + config->fsr = 4096; + } else { + reg1 |= 0x10; + config->fsr = 8192; + } + + lis331dlh_set_ths(mlsl_handle, pdata, config, apply, config->ths); + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG4, reg1); + + return result; +} + +static int lis331dlh_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + struct lis331dlh_private_data *private_data = + (struct lis331dlh_private_data *)(pdata->private_data); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG1, + private_data->suspend.ctrl_reg1); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG2, 0x0f); + reg1 = 0x40; + if (private_data->suspend.fsr == 8192) + reg1 |= 0x30; + else if (private_data->suspend.fsr == 4096) + reg1 |= 0x10; + /* else bits [4..5] are already zero */ + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG4, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_THS, + private_data->suspend.reg_ths); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_DURATION, + private_data->suspend.reg_dur); + + if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (private_data->suspend.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = private_data->suspend.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG3, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_CFG, reg2); + result = inv_serial_read(mlsl_handle, pdata->address, + LIS331DLH_HP_FILTER_RESET, 1, ®1); + return result; +} + +static int lis331dlh_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + struct lis331dlh_private_data *private_data = + (struct lis331dlh_private_data *)(pdata->private_data); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG1, + private_data->resume.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(6); + + /* Full Scale */ + reg1 = 0x40; + if (private_data->resume.fsr == 8192) + reg1 |= 0x30; + else if (private_data->resume.fsr == 4096) + reg1 |= 0x10; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG4, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Configure high pass filter */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG2, 0x0F); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = private_data->resume.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_CTRL_REG3, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_THS, + private_data->resume.reg_ths); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_DURATION, + private_data->resume.reg_dur); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS331DLH_INT1_CFG, reg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + LIS331DLH_HP_FILTER_RESET, 1, ®1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int lis331dlh_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + result = inv_serial_read(mlsl_handle, pdata->address, + LIS331DLH_STATUS_REG, 1, data); + if (data[0] & 0x0F) { + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, + data); + return result; + } else + return INV_ERROR_ACCEL_DATA_NOT_READY; +} + +static int lis331dlh_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + struct lis331dlh_private_data *private_data; + long range; + private_data = (struct lis331dlh_private_data *) + kzalloc(sizeof(struct lis331dlh_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0x37; + private_data->suspend.ctrl_reg1 = 0x47; + private_data->resume.mot_int1_cfg = 0x95; + private_data->suspend.mot_int1_cfg = 0x2a; + + lis331dlh_set_odr(mlsl_handle, pdata, &private_data->suspend, false, 0); + lis331dlh_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + + range = range_fixedpoint_to_long_mg(slave->range); + lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + + lis331dlh_set_ths(mlsl_handle, pdata, &private_data->suspend, + false, 80); + lis331dlh_set_ths(mlsl_handle, pdata, &private_data->resume, false, 40); + + + lis331dlh_set_dur(mlsl_handle, pdata, &private_data->suspend, + false, 1000); + lis331dlh_set_dur(mlsl_handle, pdata, &private_data->resume, + false, 2540); + + lis331dlh_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + lis331dlh_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + return INV_SUCCESS; +} + +static int lis331dlh_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int lis331dlh_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis331dlh_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return lis331dlh_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return lis331dlh_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return lis331dlh_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return lis331dlh_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return lis331dlh_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return lis331dlh_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return lis331dlh_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return lis331dlh_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return lis331dlh_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return lis331dlh_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int lis331dlh_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis331dlh_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.irq_type; + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_descr lis331dlh_descr = { + .init = lis331dlh_init, + .exit = lis331dlh_exit, + .suspend = lis331dlh_suspend, + .resume = lis331dlh_resume, + .read = lis331dlh_read, + .config = lis331dlh_config, + .get_config = lis331dlh_get_config, + .name = "lis331dlh", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_LIS331, + .read_reg = (0x28 | 0x80), /* 0x80 for burst reads */ + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {2, 480}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *lis331_get_slave_descr(void) +{ + return &lis331dlh_descr; +} + +/* -------------------------------------------------------------------------- */ +struct lis331_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int lis331_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct lis331_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + lis331_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int lis331_mod_remove(struct i2c_client *client) +{ + struct lis331_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + lis331_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id lis331_mod_id[] = { + { "lis331", ACCEL_ID_LIS331 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lis331_mod_id); + +static struct i2c_driver lis331_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = lis331_mod_probe, + .remove = lis331_mod_remove, + .id_table = lis331_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "lis331_mod", + }, + .address_list = normal_i2c, +}; + +static int __init lis331_mod_init(void) +{ + int res = i2c_add_driver(&lis331_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "lis331_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit lis331_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&lis331_mod_driver); +} + +module_init(lis331_mod_init); +module_exit(lis331_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate LIS331 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("lis331_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/lis3dh.c b/drivers/misc/inv_mpu/accel/lis3dh.c new file mode 100644 index 000000000000..27206e4b847c --- /dev/null +++ b/drivers/misc/inv_mpu/accel/lis3dh.c @@ -0,0 +1,728 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file lis3dh.c + * @brief Accelerometer setup and handling methods for ST LIS3DH. + */ + +/* -------------------------------------------------------------------------- */ + +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* full scale setting - register & mask */ +#define LIS3DH_CTRL_REG1 (0x20) +#define LIS3DH_CTRL_REG2 (0x21) +#define LIS3DH_CTRL_REG3 (0x22) +#define LIS3DH_CTRL_REG4 (0x23) +#define LIS3DH_CTRL_REG5 (0x24) +#define LIS3DH_CTRL_REG6 (0x25) +#define LIS3DH_REFERENCE (0x26) +#define LIS3DH_STATUS_REG (0x27) +#define LIS3DH_OUT_X_L (0x28) +#define LIS3DH_OUT_X_H (0x29) +#define LIS3DH_OUT_Y_L (0x2a) +#define LIS3DH_OUT_Y_H (0x2b) +#define LIS3DH_OUT_Z_L (0x2c) +#define LIS3DH_OUT_Z_H (0x2d) + +#define LIS3DH_INT1_CFG (0x30) +#define LIS3DH_INT1_SRC (0x31) +#define LIS3DH_INT1_THS (0x32) +#define LIS3DH_INT1_DURATION (0x33) + +#define LIS3DH_MAX_DUR (0x7F) + +/* -------------------------------------------------------------------------- */ + +struct lis3dh_config { + unsigned long odr; + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; +}; + +struct lis3dh_private_data { + struct lis3dh_config suspend; + struct lis3dh_config resume; +}; + +/* -------------------------------------------------------------------------- */ + +static int lis3dh_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, int apply, long ths) +{ + int result = INV_SUCCESS; + if ((unsigned int)ths > 1000 * config->fsr) + ths = (long)1000 * config->fsr; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_THS, + config->reg_ths); + return result; +} + +static int lis3dh_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, int apply, long dur) +{ + int result = INV_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000L; + config->dur = dur; + + if (reg_dur > LIS3DH_MAX_DUR) + reg_dur = LIS3DH_MAX_DUR; + + config->reg_dur = (unsigned char)reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_DURATION, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int lis3dh_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, + int apply, long irq_type) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x10; + reg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x40; + reg2 = config->mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG3, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_CFG, reg2); + } + + return result; +} + +/** + * Set the Output data rate for the particular configuration + * + * @param config Config to modify with new ODR + * @param odr Output data rate in units of 1/1000Hz + */ +static int lis3dh_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, int apply, long odr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + if (odr > 400000L) { + config->odr = 1250000L; + bits = 0x90; + } else if (odr > 200000L) { + config->odr = 400000L; + bits = 0x70; + } else if (odr > 100000L) { + config->odr = 200000L; + bits = 0x60; + } else if (odr > 50000) { + config->odr = 100000L; + bits = 0x50; + } else if (odr > 25000) { + config->odr = 50000; + bits = 0x40; + } else if (odr > 10000) { + config->odr = 25000; + bits = 0x30; + } else if (odr > 1000) { + config->odr = 10000; + bits = 0x20; + } else if (odr > 500) { + config->odr = 1000; + bits = 0x10; + } else { + config->odr = 0; + bits = 0; + } + + config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0xf); + lis3dh_set_dur(mlsl_handle, pdata, config, apply, config->dur); + MPL_LOGV("ODR: %ld, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, + config->ctrl_reg1); + return result; +} + +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int lis3dh_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lis3dh_config *config, int apply, long fsr) +{ + int result = INV_SUCCESS; + unsigned char reg1 = 0x48; + + if (fsr <= 2048) { + config->fsr = 2048; + } else if (fsr <= 4096) { + reg1 |= 0x10; + config->fsr = 4096; + } else if (fsr <= 8192) { + reg1 |= 0x20; + config->fsr = 8192; + } else { + reg1 |= 0x30; + config->fsr = 16348; + } + + lis3dh_set_ths(mlsl_handle, pdata, config, apply, config->ths); + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG4, reg1); + + return result; +} + +static int lis3dh_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + struct lis3dh_private_data *private_data = pdata->private_data; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, + private_data->suspend.ctrl_reg1); + + reg1 = 0x48; + if (private_data->suspend.fsr == 16384) + reg1 |= 0x30; + else if (private_data->suspend.fsr == 8192) + reg1 |= 0x20; + else if (private_data->suspend.fsr == 4096) + reg1 |= 0x10; + else if (private_data->suspend.fsr == 2048) + reg1 |= 0x00; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG4, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_THS, + private_data->suspend.reg_ths); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_DURATION, + private_data->suspend.reg_dur); + + if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x10; + reg2 = 0x00; + } else if (private_data->suspend.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x40; + reg2 = private_data->suspend.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG3, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_CFG, reg2); + result = inv_serial_read(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG6, 1, ®1); + + return result; +} + +static int lis3dh_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg1; + unsigned char reg2; + struct lis3dh_private_data *private_data = pdata->private_data; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, + private_data->resume.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(6); + + /* Full Scale */ + reg1 = 0x48; + if (private_data->suspend.fsr == 16384) + reg1 |= 0x30; + else if (private_data->suspend.fsr == 8192) + reg1 |= 0x20; + else if (private_data->suspend.fsr == 4096) + reg1 |= 0x10; + else if (private_data->suspend.fsr == 2048) + reg1 |= 0x00; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG4, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x10; + reg2 = 0x00; + } else if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x40; + reg2 = private_data->resume.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG3, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_THS, + private_data->resume.reg_ths); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_DURATION, + private_data->resume.reg_dur); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_INT1_CFG, reg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG6, 1, ®1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int lis3dh_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + result = inv_serial_read(mlsl_handle, pdata->address, + LIS3DH_STATUS_REG, 1, data); + if (data[0] & 0x0F) { + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, + data); + return result; + } else + return INV_ERROR_ACCEL_DATA_NOT_READY; +} + +static int lis3dh_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + long range; + struct lis3dh_private_data *private_data; + private_data = (struct lis3dh_private_data *) + kzalloc(sizeof(struct lis3dh_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0x67; + private_data->suspend.ctrl_reg1 = 0x18; + private_data->resume.mot_int1_cfg = 0x95; + private_data->suspend.mot_int1_cfg = 0x2a; + + lis3dh_set_odr(mlsl_handle, pdata, &private_data->suspend, false, 0); + lis3dh_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000L); + + range = range_fixedpoint_to_long_mg(slave->range); + lis3dh_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + lis3dh_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + + lis3dh_set_ths(mlsl_handle, pdata, &private_data->suspend, + false, 80); + lis3dh_set_ths(mlsl_handle, pdata, &private_data->resume, + false, 40); + + lis3dh_set_dur(mlsl_handle, pdata, &private_data->suspend, + false, 1000); + lis3dh_set_dur(mlsl_handle, pdata, &private_data->resume, + false, 2540); + + lis3dh_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + lis3dh_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LIS3DH_CTRL_REG1, 0x07); + msleep(6); + + return INV_SUCCESS; +} + +static int lis3dh_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int lis3dh_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis3dh_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return lis3dh_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return lis3dh_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return lis3dh_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return lis3dh_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return lis3dh_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return lis3dh_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return lis3dh_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return lis3dh_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return lis3dh_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return lis3dh_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, *((long *)data->data)); + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + return INV_SUCCESS; +} + +static int lis3dh_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lis3dh_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long)private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long)private_data->resume.irq_type; + break; + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_descr lis3dh_descr = { + .init = lis3dh_init, + .exit = lis3dh_exit, + .suspend = lis3dh_suspend, + .resume = lis3dh_resume, + .read = lis3dh_read, + .config = lis3dh_config, + .get_config = lis3dh_get_config, + .name = "lis3dh", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_LIS3DH, + .read_reg = 0x28 | 0x80, /* 0x80 for burst reads */ + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {2, 480}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *lis3dh_get_slave_descr(void) +{ + return &lis3dh_descr; +} + +/* -------------------------------------------------------------------------- */ +struct lis3dh_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int lis3dh_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct lis3dh_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + lis3dh_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int lis3dh_mod_remove(struct i2c_client *client) +{ + struct lis3dh_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + lis3dh_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id lis3dh_mod_id[] = { + { "lis3dh", ACCEL_ID_LIS3DH }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lis3dh_mod_id); + +static struct i2c_driver lis3dh_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = lis3dh_mod_probe, + .remove = lis3dh_mod_remove, + .id_table = lis3dh_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "lis3dh_mod", + }, + .address_list = normal_i2c, +}; + +static int __init lis3dh_mod_init(void) +{ + int res = i2c_add_driver(&lis3dh_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "lis3dh_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit lis3dh_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&lis3dh_mod_driver); +} + +module_init(lis3dh_mod_init); +module_exit(lis3dh_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate LIS3DH sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("lis3dh_mod"); + +/* + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/lsm303dlx_a.c b/drivers/misc/inv_mpu/accel/lsm303dlx_a.c new file mode 100644 index 000000000000..576282a0fb16 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/lsm303dlx_a.c @@ -0,0 +1,881 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file lsm303dlx_a.c + * @brief Accelerometer setup and handling methods for ST LSM303DLH + * or LSM303DLM accel. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* -------------------------------------------------------------------------- */ + +/* full scale setting - register & mask */ +#define LSM303DLx_CTRL_REG1 (0x20) +#define LSM303DLx_CTRL_REG2 (0x21) +#define LSM303DLx_CTRL_REG3 (0x22) +#define LSM303DLx_CTRL_REG4 (0x23) +#define LSM303DLx_CTRL_REG5 (0x24) +#define LSM303DLx_HP_FILTER_RESET (0x25) +#define LSM303DLx_REFERENCE (0x26) +#define LSM303DLx_STATUS_REG (0x27) +#define LSM303DLx_OUT_X_L (0x28) +#define LSM303DLx_OUT_X_H (0x29) +#define LSM303DLx_OUT_Y_L (0x2a) +#define LSM303DLx_OUT_Y_H (0x2b) +#define LSM303DLx_OUT_Z_L (0x2b) +#define LSM303DLx_OUT_Z_H (0x2d) + +#define LSM303DLx_INT1_CFG (0x30) +#define LSM303DLx_INT1_SRC (0x31) +#define LSM303DLx_INT1_THS (0x32) +#define LSM303DLx_INT1_DURATION (0x33) + +#define LSM303DLx_INT2_CFG (0x34) +#define LSM303DLx_INT2_SRC (0x35) +#define LSM303DLx_INT2_THS (0x36) +#define LSM303DLx_INT2_DURATION (0x37) + +#define LSM303DLx_CTRL_MASK (0x30) +#define LSM303DLx_SLEEP_MASK (0x20) +#define LSM303DLx_PWR_MODE_NORMAL (0x20) + +#define LSM303DLx_MAX_DUR (0x7F) + +/* -------------------------------------------------------------------------- */ + +struct lsm303dlx_a_config { + unsigned int odr; + unsigned int fsr; /** < full scale range mg */ + unsigned int ths; /** < Motion no-motion thseshold mg */ + unsigned int dur; /** < Motion no-motion duration ms */ + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; +}; + +struct lsm303dlx_a_private_data { + struct lsm303dlx_a_config suspend; + struct lsm303dlx_a_config resume; +}; + +/* -------------------------------------------------------------------------- */ + +static int lsm303dlx_a_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lsm303dlx_a_config *config, + int apply, + long ths) +{ + int result = INV_SUCCESS; + if ((unsigned int) ths >= config->fsr) + ths = (long) config->fsr - 1; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_THS, + config->reg_ths); + return result; +} + +static int lsm303dlx_a_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lsm303dlx_a_config *config, + int apply, + long dur) +{ + int result = INV_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000L; + config->dur = dur; + + if (reg_dur > LSM303DLx_MAX_DUR) + reg_dur = LSM303DLx_MAX_DUR; + + config->reg_dur = (unsigned char) reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_DURATION, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int lsm303dlx_a_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lsm303dlx_a_config *config, + int apply, + long irq_type) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = config->mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG3, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_CFG, reg2); + } + + return result; +} + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lsm303dlx_a_config *config, + int apply, + long odr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + /* normal power modes */ + if (odr > 400000) { + config->odr = 1000000; + bits = LSM303DLx_PWR_MODE_NORMAL | 0x18; + } else if (odr > 100000) { + config->odr = 400000; + bits = LSM303DLx_PWR_MODE_NORMAL | 0x10; + } else if (odr > 50000) { + config->odr = 100000; + bits = LSM303DLx_PWR_MODE_NORMAL | 0x08; + } else if (odr > 10000) { + config->odr = 50000; + bits = LSM303DLx_PWR_MODE_NORMAL | 0x00; + /* low power modes */ + } else if (odr > 5000) { + config->odr = 10000; + bits = 0xC0; + } else if (odr > 2000) { + config->odr = 5000; + bits = 0xA0; + } else if (odr > 1000) { + config->odr = 2000; + bits = 0x80; + } else if (odr > 500) { + config->odr = 1000; + bits = 0x60; + } else if (odr > 0) { + config->odr = 500; + bits = 0x40; + } else { + config->odr = 0; + bits = 0; + } + + config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7); + lsm303dlx_a_set_dur(mlsl_handle, pdata, config, apply, config->dur); + MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG1, + config->ctrl_reg1); + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct lsm303dlx_a_config *config, + int apply, + long fsr) +{ + unsigned char reg1 = 0x40; + int result = INV_SUCCESS; + + if (fsr <= 2048) { + config->fsr = 2048; + } else if (fsr <= 4096) { + reg1 |= 0x30; + config->fsr = 4096; + } else { + reg1 |= 0x10; + config->fsr = 8192; + } + + lsm303dlx_a_set_ths(mlsl_handle, pdata, + config, apply, config->ths); + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG4, reg1); + + return result; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + struct lsm303dlx_a_private_data *private_data = + (struct lsm303dlx_a_private_data *)(pdata->private_data); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG1, + private_data->suspend.ctrl_reg1); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG2, 0x0f); + reg1 = 0x40; + if (private_data->suspend.fsr == 8192) + reg1 |= 0x30; + else if (private_data->suspend.fsr == 4096) + reg1 |= 0x10; + /* else bits [4..5] are already zero */ + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG4, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_THS, + private_data->suspend.reg_ths); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_DURATION, + private_data->suspend.reg_dur); + + if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (private_data->suspend.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = private_data->suspend.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG3, reg1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_CFG, reg2); + result = inv_serial_read(mlsl_handle, pdata->address, + LSM303DLx_HP_FILTER_RESET, 1, ®1); + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + struct lsm303dlx_a_private_data *private_data = + (struct lsm303dlx_a_private_data *)(pdata->private_data); + + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG1, + private_data->resume.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(6); + + /* Full Scale */ + reg1 = 0x40; + if (private_data->resume.fsr == 8192) + reg1 |= 0x30; + else if (private_data->resume.fsr == 4096) + reg1 |= 0x10; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG4, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Configure high pass filter */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG2, 0x0F); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x02; + reg2 = 0x00; + } else if (private_data->resume.irq_type == + MPU_SLAVE_IRQ_TYPE_MOTION) { + reg1 = 0x00; + reg2 = private_data->resume.mot_int1_cfg; + } else { + reg1 = 0x00; + reg2 = 0x00; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_CTRL_REG3, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_THS, + private_data->resume.reg_ths); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_DURATION, + private_data->resume.reg_dur); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + LSM303DLx_INT1_CFG, reg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + LSM303DLx_HP_FILTER_RESET, 1, ®1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + result = inv_serial_read(mlsl_handle, pdata->address, + LSM303DLx_STATUS_REG, 1, data); + if (data[0] & 0x0F) { + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, slave->read_len, data); + return result; + } else + return INV_ERROR_ACCEL_DATA_NOT_READY; +} + +/** + * @brief one-time device driver initialization function. + * If the driver is built as a kernel module, this function will be + * called when the module is loaded in the kernel. + * If the driver is built-in in the kernel, this function will be + * called at boot time. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + long range; + struct lsm303dlx_a_private_data *private_data; + private_data = (struct lsm303dlx_a_private_data *) + kzalloc(sizeof(struct lsm303dlx_a_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0x37; + private_data->suspend.ctrl_reg1 = 0x47; + private_data->resume.mot_int1_cfg = 0x95; + private_data->suspend.mot_int1_cfg = 0x2a; + + lsm303dlx_a_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + lsm303dlx_a_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + + range = range_fixedpoint_to_long_mg(slave->range); + lsm303dlx_a_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + lsm303dlx_a_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + + lsm303dlx_a_set_ths(mlsl_handle, pdata, &private_data->suspend, + false, 80); + lsm303dlx_a_set_ths(mlsl_handle, pdata, &private_data->resume, + false, 40); + + lsm303dlx_a_set_dur(mlsl_handle, pdata, &private_data->suspend, + false, 1000); + lsm303dlx_a_set_dur(mlsl_handle, pdata, &private_data->resume, + false, 2540); + + lsm303dlx_a_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + lsm303dlx_a_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + return INV_SUCCESS; +} + +/** + * @brief one-time device driver exit function. + * If the driver is built as a kernel module, this function will be + * called when the module is removed from the kernel. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +/** + * @brief device configuration facility. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to the configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lsm303dlx_a_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return lsm303dlx_a_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return lsm303dlx_a_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return lsm303dlx_a_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return lsm303dlx_a_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return lsm303dlx_a_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return lsm303dlx_a_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return lsm303dlx_a_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return lsm303dlx_a_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return lsm303dlx_a_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return lsm303dlx_a_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +/** + * @brief facility to retrieve the device configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to store the returned configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int lsm303dlx_a_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct lsm303dlx_a_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.irq_type; + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_descr lsm303dlx_a_descr = { + .init = lsm303dlx_a_init, + .exit = lsm303dlx_a_exit, + .suspend = lsm303dlx_a_suspend, + .resume = lsm303dlx_a_resume, + .read = lsm303dlx_a_read, + .config = lsm303dlx_a_config, + .get_config = lsm303dlx_a_get_config, + .name = "lsm303dlx_a", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_LSM303DLX, + .read_reg = (0x28 | 0x80), /* 0x80 for burst reads */ + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {2, 480}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *lsm303dlx_a_get_slave_descr(void) +{ + return &lsm303dlx_a_descr; +} + +/* -------------------------------------------------------------------------- */ +struct lsm303dlx_a_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int lsm303dlx_a_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct lsm303dlx_a_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + lsm303dlx_a_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int lsm303dlx_a_mod_remove(struct i2c_client *client) +{ + struct lsm303dlx_a_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + lsm303dlx_a_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id lsm303dlx_a_mod_id[] = { + { "lsm303dlx", ACCEL_ID_LSM303DLX }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lsm303dlx_a_mod_id); + +static struct i2c_driver lsm303dlx_a_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = lsm303dlx_a_mod_probe, + .remove = lsm303dlx_a_mod_remove, + .id_table = lsm303dlx_a_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "lsm303dlx_a_mod", + }, + .address_list = normal_i2c, +}; + +static int __init lsm303dlx_a_mod_init(void) +{ + int res = i2c_add_driver(&lsm303dlx_a_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "lsm303dlx_a_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit lsm303dlx_a_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&lsm303dlx_a_mod_driver); +} + +module_init(lsm303dlx_a_mod_init); +module_exit(lsm303dlx_a_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate LSM303DLX_A sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("lsm303dlx_a_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/mma8450.c b/drivers/misc/inv_mpu/accel/mma8450.c new file mode 100644 index 000000000000..f698ee98bf50 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/mma8450.c @@ -0,0 +1,804 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file mma8450.c + * @brief Accelerometer setup and handling methods for Freescale MMA8450. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/* full scale setting - register & mask */ +#define ACCEL_MMA8450_XYZ_DATA_CFG (0x16) + +#define ACCEL_MMA8450_CTRL_REG1 (0x38) +#define ACCEL_MMA8450_CTRL_REG2 (0x39) +#define ACCEL_MMA8450_CTRL_REG4 (0x3B) +#define ACCEL_MMA8450_CTRL_REG5 (0x3C) + +#define ACCEL_MMA8450_CTRL_REG (0x38) +#define ACCEL_MMA8450_CTRL_MASK (0x03) + +#define ACCEL_MMA8450_SLEEP_MASK (0x03) + +/* -------------------------------------------------------------------------- */ + +struct mma8450_config { + unsigned int odr; + unsigned int fsr; /** < full scale range mg */ + unsigned int ths; /** < Motion no-motion thseshold mg */ + unsigned int dur; /** < Motion no-motion duration ms */ + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; +}; + +struct mma8450_private_data { + struct mma8450_config suspend; + struct mma8450_config resume; +}; + + +/* -------------------------------------------------------------------------- */ + +static int mma8450_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma8450_config *config, + int apply, + long ths) +{ + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +static int mma8450_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma8450_config *config, + int apply, + long dur) +{ + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +/** + * @brief Sets the IRQ to fire when one of the IRQ events occur. + * Threshold and duration will not be used unless the type is MOT or + * NMOT. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * configuration to apply to, suspend or resume + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param irq_type + * the type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma8450_config *config, + int apply, + long irq_type) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + unsigned char reg3; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x01; + reg2 = 0x01; + reg3 = 0x07; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_NONE) { + reg1 = 0x00; + reg2 = 0x00; + reg3 = 0x00; + } else { + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + } + + if (apply) { + /* XYZ_DATA_CFG: event flag enabled on Z axis */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_XYZ_DATA_CFG, reg3); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG4, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG5, reg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return result; +} + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma8450_config *config, + int apply, + long odr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + if (odr > 200000) { + config->odr = 400000; + bits = 0x00; + } else if (odr > 100000) { + config->odr = 200000; + bits = 0x04; + } else if (odr > 50000) { + config->odr = 100000; + bits = 0x08; + } else if (odr > 25000) { + config->odr = 50000; + bits = 0x0C; + } else if (odr > 12500) { + config->odr = 25000; + bits = 0x40; /* Sleep -> Auto wake mode */ + } else if (odr > 1563) { + config->odr = 12500; + bits = 0x10; + } else if (odr > 0) { + config->odr = 1563; + bits = 0x14; + } else { + config->ctrl_reg1 = 0; /* Set FS1.FS2 to Standby */ + config->odr = 0; + bits = 0; + } + + config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x3); + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, config->ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("ODR: %d mHz, 0x%02x\n", + config->odr, (int)config->ctrl_reg1); + } + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma8450_config *config, + int apply, + long fsr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + if (fsr <= 2000) { + bits = 0x01; + config->fsr = 2000; + } else if (fsr <= 4000) { + bits = 0x02; + config->fsr = 4000; + } else { + bits = 0x03; + config->fsr = 8000; + } + + config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0xFC); + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, config->ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("FSR: %d mg\n", config->fsr); + } + return result; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct mma8450_private_data *private_data = pdata->private_data; + + if (private_data->suspend.fsr == 4000) + slave->range.mantissa = 4; + else if (private_data->suspend.fsr == 8000) + slave->range.mantissa = 8; + else + slave->range.mantissa = 2; + slave->range.fraction = 0; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (private_data->suspend.ctrl_reg1) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, + private_data->suspend.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = mma8450_set_irq(mlsl_handle, pdata, + &private_data->suspend, + true, private_data->suspend.irq_type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + struct mma8450_private_data *private_data = pdata->private_data; + + /* Full Scale */ + if (private_data->resume.fsr == 4000) + slave->range.mantissa = 4; + else if (private_data->resume.fsr == 8000) + slave->range.mantissa = 8; + else + slave->range.mantissa = 2; + slave->range.fraction = 0; + + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (private_data->resume.ctrl_reg1) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA8450_CTRL_REG1, + private_data->resume.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + result = mma8450_set_irq(mlsl_handle, pdata, + &private_data->resume, + true, private_data->resume.irq_type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + int result; + unsigned char local_data[4]; /* Status register + 3 bytes data */ + result = inv_serial_read(mlsl_handle, pdata->address, + 0x00, sizeof(local_data), local_data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + memcpy(data, &local_data[1], (slave->read_len) - 1); + + MPL_LOGV("Data Not Ready: %02x %02x %02x %02x\n", + local_data[0], local_data[1], + local_data[2], local_data[3]); + + return result; +} + +/** + * @brief one-time device driver initialization function. + * If the driver is built as a kernel module, this function will be + * called when the module is loaded in the kernel. + * If the driver is built-in in the kernel, this function will be + * called at boot time. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + struct mma8450_private_data *private_data; + private_data = (struct mma8450_private_data *) + kzalloc(sizeof(struct mma8450_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + mma8450_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + mma8450_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + mma8450_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, 2000); + mma8450_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, 2000); + mma8450_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, + MPU_SLAVE_IRQ_TYPE_NONE); + mma8450_set_irq(mlsl_handle, pdata, &private_data->resume, + false, + MPU_SLAVE_IRQ_TYPE_NONE); + return INV_SUCCESS; +} + +/** + * @brief one-time device driver exit function. + * If the driver is built as a kernel module, this function will be + * called when the module is removed from the kernel. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +/** + * @brief device configuration facility. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to the configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mma8450_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return mma8450_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return mma8450_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return mma8450_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return mma8450_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return mma8450_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return mma8450_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return mma8450_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return mma8450_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return mma8450_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return mma8450_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +/** + * @brief facility to retrieve the device configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a pointer to store the returned configuration data structure. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma8450_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mma8450_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.irq_type; + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_descr mma8450_descr = { + .init = mma8450_init, + .exit = mma8450_exit, + .suspend = mma8450_suspend, + .resume = mma8450_resume, + .read = mma8450_read, + .config = mma8450_config, + .get_config = mma8450_get_config, + .name = "mma8450", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_MMA8450, + .read_reg = 0x00, + .read_len = 4, + .endian = EXT_SLAVE_FS8_BIG_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *mma8450_get_slave_descr(void) +{ + return &mma8450_descr; +} + +/* -------------------------------------------------------------------------- */ +struct mma8450_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int mma8450_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct mma8450_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + mma8450_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int mma8450_mod_remove(struct i2c_client *client) +{ + struct mma8450_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + mma8450_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id mma8450_mod_id[] = { + { "mma8450", ACCEL_ID_MMA8450 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mma8450_mod_id); + +static struct i2c_driver mma8450_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = mma8450_mod_probe, + .remove = mma8450_mod_remove, + .id_table = mma8450_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "mma8450_mod", + }, + .address_list = normal_i2c, +}; + +static int __init mma8450_mod_init(void) +{ + int res = i2c_add_driver(&mma8450_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "mma8450_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit mma8450_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&mma8450_mod_driver); +} + +module_init(mma8450_mod_init); +module_exit(mma8450_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate MMA8450 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mma8450_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/mma845x.c b/drivers/misc/inv_mpu/accel/mma845x.c new file mode 100644 index 000000000000..5f62b22388b1 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/mma845x.c @@ -0,0 +1,713 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup ACCELDL + * @brief Provides the interface to setup and handle an accelerometer. + * + * @{ + * @file mma845x.c + * @brief Accelerometer setup and handling methods for Freescale MMA845X + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +#define ACCEL_MMA845X_XYZ_DATA_CFG (0x0E) +#define ACCEL_MMA845X_CTRL_REG1 (0x2A) +#define ACCEL_MMA845X_CTRL_REG4 (0x2D) +#define ACCEL_MMA845X_CTRL_REG5 (0x2E) + +#define ACCEL_MMA845X_SLEEP_MASK (0x01) + +/* full scale setting - register & mask */ +#define ACCEL_MMA845X_CFG_REG (0x0E) +#define ACCEL_MMA845X_CTRL_MASK (0x03) + +/* -------------------------------------------------------------------------- */ + +struct mma845x_config { + unsigned int odr; + unsigned int fsr; /** < full scale range mg */ + unsigned int ths; /** < Motion no-motion thseshold mg */ + unsigned int dur; /** < Motion no-motion duration ms */ + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char ctrl_reg1; + unsigned char irq_type; + unsigned char mot_int1_cfg; +}; + +struct mma845x_private_data { + struct mma845x_config suspend; + struct mma845x_config resume; +}; + +/* -------------------------------------------------------------------------- */ + +static int mma845x_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma845x_config *config, + int apply, + long ths) +{ + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +static int mma845x_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma845x_config *config, + int apply, + long dur) +{ + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +/** + * @brief Sets the IRQ to fire when one of the IRQ events occur. + * Threshold and duration will not be used unless the type is MOT or + * NMOT. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * configuration to apply to, suspend or resume + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param irq_type + * the type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma845x_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma845x_config *config, + int apply, + long irq_type) +{ + int result = INV_SUCCESS; + unsigned char reg1; + unsigned char reg2; + + config->irq_type = (unsigned char)irq_type; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + reg1 = 0x01; + reg2 = 0x01; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_NONE) { + reg1 = 0x00; + reg2 = 0x00; + } else { + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + } + + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG4, reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG5, reg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return result; +} + +/** + * @brief Set the output data rate for the particular configuration. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * Config to modify with new ODR. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param odr + * Output data rate in units of 1/1000Hz (mHz). + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma845x_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma845x_config *config, + int apply, + long odr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + if (odr > 400000) { + config->odr = 800000; + bits = 0x01; + } else if (odr > 200000) { + config->odr = 400000; + bits = 0x09; + } else if (odr > 100000) { + config->odr = 200000; + bits = 0x11; + } else if (odr > 50000) { + config->odr = 100000; + bits = 0x19; + } else if (odr > 12500) { + config->odr = 50000; + bits = 0x21; + } else if (odr > 6250) { + config->odr = 12500; + bits = 0x29; + } else if (odr > 1560) { + config->odr = 6250; + bits = 0x31; + } else if (odr > 0) { + config->odr = 1560; + bits = 0x39; + } else { + config->ctrl_reg1 = 0; /* Set FS1.FS2 to Standby */ + config->odr = 0; + bits = 0; + } + + config->ctrl_reg1 = bits; + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG1, + config->ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("ODR: %d mHz, 0x%02x\n", config->odr, + (int)config->ctrl_reg1); + } + return result; +} + +/** + * @brief Set the full scale range of the accels + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param pdata + * a pointer to the slave platform data. + * @param config + * pointer to configuration. + * @param apply + * whether to apply immediately or save the settings to be applied + * at the next resume. + * @param fsr + * requested full scale range. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma845x_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct mma845x_config *config, + int apply, + long fsr) +{ + unsigned char bits; + int result = INV_SUCCESS; + + if (fsr <= 2000) { + bits = 0x00; + config->fsr = 2000; + } else if (fsr <= 4000) { + bits = 0x01; + config->fsr = 4000; + } else { + bits = 0x02; + config->fsr = 8000; + } + + if (apply) { + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA845X_XYZ_DATA_CFG, + bits); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("FSR: %d mg\n", config->fsr); + } + return result; +} + +/** + * @brief suspends the device to put it in its lowest power mode. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma845x_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct mma845x_private_data *private_data = pdata->private_data; + + /* Full Scale */ + if (private_data->suspend.fsr == 4000) + slave->range.mantissa = 4; + else if (private_data->suspend.fsr == 8000) + slave->range.mantissa = 8; + else + slave->range.mantissa = 2; + + slave->range.fraction = 0; + + result = mma845x_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + true, private_data->suspend.fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG1, + private_data->suspend.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief resume the device in the proper power state given the configuration + * chosen. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma845x_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + struct mma845x_private_data *private_data = pdata->private_data; + + /* Full Scale */ + if (private_data->resume.fsr == 4000) + slave->range.mantissa = 4; + else if (private_data->resume.fsr == 8000) + slave->range.mantissa = 8; + else + slave->range.mantissa = 2; + + slave->range.fraction = 0; + + result = mma845x_set_fsr(mlsl_handle, pdata, + &private_data->resume, + true, private_data->resume.fsr); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write(mlsl_handle, pdata->address, + ACCEL_MMA845X_CTRL_REG1, + private_data->resume.ctrl_reg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +/** + * @brief read the sensor data from the device. + * + * @param mlsl_handle + * the handle to the serial channel the device is connected to. + * @param slave + * a pointer to the slave descriptor data structure. + * @param pdata + * a pointer to the slave platform data. + * @param data + * a buffer to store the data read. + * + * @return INV_SUCCESS if successful or a non-zero error code. + */ +static int mma845x_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + int result; + unsigned char local_data[7]; /* Status register + 6 bytes data */ + result = inv_serial_read(mlsl_handle, pdata->address, + slave->read_reg, sizeof(local_data), + local_data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + memcpy(data, &local_data[1], slave->read_len); + return result; +} + +static int mma845x_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + long range; + struct mma845x_private_data *private_data; + private_data = (struct mma845x_private_data *) + kzalloc(sizeof(struct mma845x_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + + mma845x_set_odr(mlsl_handle, pdata, &private_data->suspend, + false, 0); + mma845x_set_odr(mlsl_handle, pdata, &private_data->resume, + false, 200000); + + range = range_fixedpoint_to_long_mg(slave->range); + mma845x_set_fsr(mlsl_handle, pdata, &private_data->suspend, + false, range); + mma845x_set_fsr(mlsl_handle, pdata, &private_data->resume, + false, range); + + mma845x_set_irq(mlsl_handle, pdata, &private_data->suspend, + false, MPU_SLAVE_IRQ_TYPE_NONE); + mma845x_set_irq(mlsl_handle, pdata, &private_data->resume, + false, MPU_SLAVE_IRQ_TYPE_NONE); + return INV_SUCCESS; +} + +static int mma845x_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int mma845x_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mma845x_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return mma845x_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return mma845x_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return mma845x_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return mma845x_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return mma845x_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return mma845x_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return mma845x_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return mma845x_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return mma845x_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return mma845x_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int mma845x_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct mma845x_private_data *private_data = pdata->private_data; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.irq_type; + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_descr mma845x_descr = { + .init = mma845x_init, + .exit = mma845x_exit, + .suspend = mma845x_suspend, + .resume = mma845x_resume, + .read = mma845x_read, + .config = mma845x_config, + .get_config = mma845x_get_config, + .name = "mma845x", + .type = EXT_SLAVE_TYPE_ACCEL, + .id = ACCEL_ID_MMA845X, + .read_reg = 0x00, + .read_len = 6, + .endian = EXT_SLAVE_FS16_BIG_ENDIAN, + .range = {2, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *mma845x_get_slave_descr(void) +{ + return &mma845x_descr; +} + +/* -------------------------------------------------------------------------- */ +struct mma845x_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int mma845x_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct mma845x_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + mma845x_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int mma845x_mod_remove(struct i2c_client *client) +{ + struct mma845x_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + mma845x_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id mma845x_mod_id[] = { + { "mma845x", ACCEL_ID_MMA845X }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mma845x_mod_id); + +static struct i2c_driver mma845x_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = mma845x_mod_probe, + .remove = mma845x_mod_remove, + .id_table = mma845x_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "mma845x_mod", + }, + .address_list = normal_i2c, +}; + +static int __init mma845x_mod_init(void) +{ + int res = i2c_add_driver(&mma845x_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "mma845x_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit mma845x_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&mma845x_mod_driver); +} + +module_init(mma845x_mod_init); +module_exit(mma845x_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate MMA845X sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mma845x_mod"); + + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/mpu6050.h b/drivers/misc/inv_mpu/accel/mpu6050.h new file mode 100644 index 000000000000..c347bcb4d773 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/mpu6050.h @@ -0,0 +1,28 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + + +#ifndef __MPU6050_H__ +#define __MPU6050_H__ + +#include + +struct ext_slave_descr *mpu6050_get_slave_descr(void); + +#endif diff --git a/drivers/misc/inv_mpu/compass/Kconfig b/drivers/misc/inv_mpu/compass/Kconfig new file mode 100644 index 000000000000..6c4c13a6e19a --- /dev/null +++ b/drivers/misc/inv_mpu/compass/Kconfig @@ -0,0 +1,121 @@ +menuconfig INV_SENSORS_COMPASS + bool "Compass Slave Sensors" + default y + ---help--- + Say Y here to get to see options for device drivers for various + compasses. This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if INV_SENSORS_COMPASS + +config MPU_SENSORS_AK8975 + tristate "AKM ak8975" + help + This enables support for the AKM ak8975 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_AK8972 + tristate "AKM ak8972" + help + This enables support for the AKM ak8972 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_MMC314X + tristate "MEMSIC mmc314x" + help + This enables support for the MEMSIC mmc314x compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_AMI30X + tristate "Aichi Steel ami30X" + help + This enables support for the Aichi Steel ami304/ami305 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_AMI306 + tristate "Aichi Steel ami306" + help + This enables support for the Aichi Steel ami306 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_HMC5883 + tristate "Honeywell hmc5883" + help + This enables support for the Honeywell hmc5883 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_LSM303DLX_M + tristate "ST lsm303dlx" + help + This enables support for the ST lsm303dlh and lsm303dlm compasses + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_MMC314XMS + tristate "MEMSIC mmc314xMS" + help + This enables support for the MEMSIC mmc314xMS compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_YAS529 + tristate "Yamaha yas529" + depends on INPUT_YAS_MAGNETOMETER + help + This enables support for the Yamaha yas529 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_YAS530 + tristate "Yamaha yas530" + help + This enables support for the Yamaha yas530 compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_HSCDTD002B + tristate "Alps hscdtd002b" + help + This enables support for the Alps hscdtd002b compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +config MPU_SENSORS_HSCDTD004A + tristate "Alps hscdtd004a" + help + This enables support for the Alps hscdtd004a compass + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one compass can be registered at a time. + Specifying more that one compass in the board file will result + in runtime errors. + +endif diff --git a/drivers/misc/inv_mpu/compass/Makefile b/drivers/misc/inv_mpu/compass/Makefile new file mode 100644 index 000000000000..aa8aa6a2657b --- /dev/null +++ b/drivers/misc/inv_mpu/compass/Makefile @@ -0,0 +1,38 @@ +# +# Compass Slaves MPUxxxx +# +obj-$(CONFIG_MPU_SENSORS_AMI30X) += inv_mpu_ami30x.o +inv_mpu_ami30x-objs += ami30x.o + +obj-$(CONFIG_MPU_SENSORS_AMI306) += inv_mpu_ami306.o +inv_mpu_ami306-objs += ami306.o + +obj-$(CONFIG_MPU_SENSORS_HMC5883) += inv_mpu_hmc5883.o +inv_mpu_hmc5883-objs += hmc5883.o + +obj-$(CONFIG_MPU_SENSORS_LSM303DLX_M) += inv_mpu_lsm303dlx_m.o +inv_mpu_lsm303dlx_m-objs += lsm303dlx_m.o + +obj-$(CONFIG_MPU_SENSORS_MMC314X) += inv_mpu_mmc314x.o +inv_mpu_mmc314x-objs += mmc314x.o + +obj-$(CONFIG_MPU_SENSORS_YAS529) += inv_mpu_yas529.o +inv_mpu_yas529-objs += yas529-kernel.o + +obj-$(CONFIG_MPU_SENSORS_YAS530) += inv_mpu_yas530.o +inv_mpu_yas530-objs += yas530.o + +obj-$(CONFIG_MPU_SENSORS_HSCDTD002B) += inv_mpu_hscdtd002b.o +inv_mpu_hscdtd002b-objs += hscdtd002b.o + +obj-$(CONFIG_MPU_SENSORS_HSCDTD004A) += inv_mpu_hscdtd004a.o +inv_mpu_hscdtd004a-objs += hscdtd004a.o + +obj-$(CONFIG_MPU_SENSORS_AK8975) += inv_mpu_ak8975.o +inv_mpu_ak8975-objs += ak8975.o + +obj-$(CONFIG_MPU_SENSORS_AK8972) += inv_mpu_ak8972.o +inv_mpu_ak8972-objs += ak8972.o + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER diff --git a/drivers/misc/inv_mpu/compass/ak8972.c b/drivers/misc/inv_mpu/compass/ak8972.c new file mode 100644 index 000000000000..7eb15b44039d --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ak8972.c @@ -0,0 +1,499 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file ak8972.c + * @brief Magnetometer setup and handling methods for the AKM AK8972 compass device. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define AK8972_REG_ST1 (0x02) +#define AK8972_REG_HXL (0x03) +#define AK8972_REG_ST2 (0x09) + +#define AK8972_REG_CNTL (0x0A) +#define AK8972_REG_ASAX (0x10) +#define AK8972_REG_ASAY (0x11) +#define AK8972_REG_ASAZ (0x12) + +#define AK8972_CNTL_MODE_POWER_DOWN (0x00) +#define AK8972_CNTL_MODE_SINGLE_MEASUREMENT (0x01) +#define AK8972_CNTL_MODE_FUSE_ROM_ACCESS (0x0f) + +/* -------------------------------------------------------------------------- */ +struct ak8972_config { + char asa[COMPASS_NUM_AXES]; /* axis sensitivity adjustment */ +}; + +struct ak8972_private_data { + struct ak8972_config init; +}; + +/* -------------------------------------------------------------------------- */ +static int ak8972_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char serial_data[COMPASS_NUM_AXES]; + + struct ak8972_private_data *private_data; + private_data = (struct ak8972_private_data *) + kzalloc(sizeof(struct ak8972_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8972_REG_CNTL, + AK8972_CNTL_MODE_POWER_DOWN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Wait at least 100us */ + udelay(100); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8972_REG_CNTL, + AK8972_CNTL_MODE_FUSE_ROM_ACCESS); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Wait at least 200us */ + udelay(200); + + result = inv_serial_read(mlsl_handle, pdata->address, + AK8972_REG_ASAX, + COMPASS_NUM_AXES, serial_data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + pdata->private_data = private_data; + + private_data->init.asa[0] = serial_data[0]; + private_data->init.asa[1] = serial_data[1]; + private_data->init.asa[2] = serial_data[2]; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8972_REG_CNTL, + AK8972_CNTL_MODE_POWER_DOWN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + udelay(100); + return INV_SUCCESS; +} + +static int ak8972_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int ak8972_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AK8972_REG_CNTL, + AK8972_CNTL_MODE_POWER_DOWN); + msleep(1); /* wait at least 100us */ + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int ak8972_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AK8972_REG_CNTL, + AK8972_CNTL_MODE_SINGLE_MEASUREMENT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int ak8972_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + unsigned char regs[8]; + unsigned char *stat = ®s[0]; + unsigned char *stat2 = ®s[7]; + int result = INV_SUCCESS; + int status = INV_SUCCESS; + + result = + inv_serial_read(mlsl_handle, pdata->address, AK8972_REG_ST1, + 8, regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Always return the data and the status registers */ + memcpy(data, ®s[1], 6); + data[6] = regs[0]; + data[7] = regs[7]; + + /* + * ST : data ready - + * Measurement has been completed and data is ready to be read. + */ + if (*stat & 0x01) + status = INV_SUCCESS; + + /* + * ST2 : data error - + * occurs when data read is started outside of a readable period; + * data read would not be correct. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour but we + * stil account for it and return an error, since the data would be + * corrupted. + * DERR bit is self-clearing when ST2 register is read. + */ + if (*stat2 & 0x04) + status = INV_ERROR_COMPASS_DATA_ERROR; + /* + * ST2 : overflow - + * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT. + * This is likely to happen in presence of an external magnetic + * disturbance; it indicates, the sensor data is incorrect and should + * be ignored. + * An error is returned. + * HOFL bit clears when a new measurement starts. + */ + if (*stat2 & 0x08) + status = INV_ERROR_COMPASS_DATA_OVERFLOW; + /* + * ST : overrun - + * the previous sample was not fetched and lost. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour and we + * don't consider this condition an error. + * DOR bit is self-clearing when ST2 or any meas. data register is + * read. + */ + if (*stat & 0x02) { + /* status = INV_ERROR_COMPASS_DATA_UNDERFLOW; */ + status = INV_SUCCESS; + } + + /* + * trigger next measurement if: + * - stat is non zero; + * - if stat is zero and stat2 is non zero. + * Won't trigger if data is not ready and there was no error. + */ + if (*stat != 0x00 || *stat2 != 0x00) { + result = inv_serial_single_write( + mlsl_handle, pdata->address, + AK8972_REG_CNTL, AK8972_CNTL_MODE_SINGLE_MEASUREMENT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return status; +} + +static int ak8972_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + int result; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_WRITE_REGISTERS: + result = inv_serial_write(mlsl_handle, pdata->address, + data->len, + (unsigned char *)data->data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + case MPU_SLAVE_CONFIG_ODR_RESUME: + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int ak8972_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct ak8972_private_data *private_data = pdata->private_data; + int result; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_READ_REGISTERS: + { + unsigned char *serial_data = + (unsigned char *)data->data; + result = + inv_serial_read(mlsl_handle, pdata->address, + serial_data[0], data->len - 1, + &serial_data[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + } + case MPU_SLAVE_READ_SCALE: + { + unsigned char *serial_data = + (unsigned char *)data->data; + serial_data[0] = private_data->init.asa[0]; + serial_data[1] = private_data->init.asa[1]; + serial_data[2] = private_data->init.asa[2]; + result = INV_SUCCESS; + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + } + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = 0; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = 8000; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_read_trigger ak8972_read_trigger = { + /*.reg = */ 0x0A, + /*.value = */ 0x01 +}; + +static struct ext_slave_descr ak8972_descr = { + .init = ak8972_init, + .exit = ak8972_exit, + .suspend = ak8972_suspend, + .resume = ak8972_resume, + .read = ak8972_read, + .config = ak8972_config, + .get_config = ak8972_get_config, + .name = "ak8972", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_AK8972, + .read_reg = 0x01, + .read_len = 9, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {39321, 6000}, + .trigger = &ak8972_read_trigger, +}; + +static +struct ext_slave_descr *ak8972_get_slave_descr(void) +{ + return &ak8972_descr; +} + +/* -------------------------------------------------------------------------- */ +struct ak8972_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int ak8972_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct ak8972_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + ak8972_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int ak8972_mod_remove(struct i2c_client *client) +{ + struct ak8972_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + inv_mpu_unregister_slave(client, private_data->pdata, + ak8972_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id ak8972_mod_id[] = { + { "ak8972", COMPASS_ID_AK8972 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ak8972_mod_id); + +static struct i2c_driver ak8972_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = ak8972_mod_probe, + .remove = ak8972_mod_remove, + .id_table = ak8972_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "ak8972_mod", + }, + .address_list = normal_i2c, +}; + +static int __init ak8972_mod_init(void) +{ + int res = i2c_add_driver(&ak8972_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "ak8972_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit ak8972_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&ak8972_mod_driver); +} + +module_init(ak8972_mod_init); +module_exit(ak8972_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate AK8972 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ak8972_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/ak8975.c b/drivers/misc/inv_mpu/compass/ak8975.c new file mode 100755 index 000000000000..9a67d7c1e397 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ak8975.c @@ -0,0 +1,501 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file ak8975.c + * @brief Magnetometer setup and handling methods for the AKM AK8975, + * AKM AK8975B, and AKM AK8975C compass devices. + */ + +/* -------------------------------------------------------------------------- */ +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.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_REG_ASAX (0x10) +#define AK8975_REG_ASAY (0x11) +#define AK8975_REG_ASAZ (0x12) + +#define AK8975_CNTL_MODE_POWER_DOWN (0x00) +#define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x01) +#define AK8975_CNTL_MODE_FUSE_ROM_ACCESS (0x0f) + +/* -------------------------------------------------------------------------- */ +struct ak8975_config { + char asa[COMPASS_NUM_AXES]; /* axis sensitivity adjustment */ +}; + +struct ak8975_private_data { + struct ak8975_config init; +}; + +/* -------------------------------------------------------------------------- */ +static int ak8975_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char serial_data[COMPASS_NUM_AXES]; + + struct ak8975_private_data *private_data; + private_data = (struct ak8975_private_data *) + kzalloc(sizeof(struct ak8975_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; +#if 0 + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Wait at least 100us */ + udelay(100); + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_FUSE_ROM_ACCESS); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } +#endif + /* Wait at least 200us */ + udelay(200); + + result = inv_serial_read(mlsl_handle, pdata->address, + AK8975_REG_ASAX, + COMPASS_NUM_AXES, serial_data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + pdata->private_data = private_data; + + private_data->init.asa[0] = serial_data[0]; + private_data->init.asa[1] = serial_data[1]; + private_data->init.asa[2] = serial_data[2]; +#if 0 + result = inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } +#endif + udelay(100); + return INV_SUCCESS; +} + +static int ak8975_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int ak8975_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_POWER_DOWN); + msleep(1); /* wait at least 100us */ + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int ak8975_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AK8975_REG_CNTL, + AK8975_CNTL_MODE_SINGLE_MEASUREMENT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int ak8975_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, unsigned char *data) +{ + unsigned char regs[8]; + unsigned char *stat = ®s[0]; + unsigned char *stat2 = ®s[7]; + int result = INV_SUCCESS; + int status = INV_SUCCESS; + + result = + inv_serial_read(mlsl_handle, pdata->address, AK8975_REG_ST1, + 8, regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Always return the data and the status registers */ + memcpy(data, ®s[1], 6); + data[6] = regs[0]; + data[7] = regs[7]; + + /* + * ST : data ready - + * Measurement has been completed and data is ready to be read. + */ + if (*stat & 0x01) + status = INV_SUCCESS; + + /* + * ST2 : data error - + * occurs when data read is started outside of a readable period; + * data read would not be correct. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour but we + * stil account for it and return an error, since the data would be + * corrupted. + * DERR bit is self-clearing when ST2 register is read. + */ + if (*stat2 & 0x04) + status = INV_ERROR_COMPASS_DATA_ERROR; + /* + * ST2 : overflow - + * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT. + * This is likely to happen in presence of an external magnetic + * disturbance; it indicates, the sensor data is incorrect and should + * be ignored. + * An error is returned. + * HOFL bit clears when a new measurement starts. + */ + if (*stat2 & 0x08) + status = INV_ERROR_COMPASS_DATA_OVERFLOW; + /* + * ST : overrun - + * the previous sample was not fetched and lost. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour and we + * don't consider this condition an error. + * DOR bit is self-clearing when ST2 or any meas. data register is + * read. + */ + if (*stat & 0x02) { + /* status = INV_ERROR_COMPASS_DATA_UNDERFLOW; */ + status = INV_SUCCESS; + } + + /* + * trigger next measurement if: + * - stat is non zero; + * - if stat is zero and stat2 is non zero. + * Won't trigger if data is not ready and there was no error. + */ + if (*stat != 0x00 || *stat2 != 0x00) { + result = inv_serial_single_write( + mlsl_handle, pdata->address, + AK8975_REG_CNTL, AK8975_CNTL_MODE_SINGLE_MEASUREMENT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return status; +} + +static int ak8975_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + int result; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_WRITE_REGISTERS: + result = inv_serial_write(mlsl_handle, pdata->address, + data->len, + (unsigned char *)data->data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + case MPU_SLAVE_CONFIG_ODR_RESUME: + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int ak8975_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct ak8975_private_data *private_data = pdata->private_data; + int result; + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_READ_REGISTERS: + { + unsigned char *serial_data = + (unsigned char *)data->data; + result = + inv_serial_read(mlsl_handle, pdata->address, + serial_data[0], data->len - 1, + &serial_data[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + } + case MPU_SLAVE_READ_SCALE: + { + unsigned char *serial_data = + (unsigned char *)data->data; + serial_data[0] = private_data->init.asa[0]; + serial_data[1] = private_data->init.asa[1]; + serial_data[2] = private_data->init.asa[2]; + result = INV_SUCCESS; + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + break; + } + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = 0; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = 8000; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_read_trigger ak8975_read_trigger = { + /*.reg = */ 0x0A, + /*.value = */ 0x01 +}; + +static struct ext_slave_descr ak8975_descr = { + .init = ak8975_init, + .exit = ak8975_exit, + .suspend = ak8975_suspend, + .resume = ak8975_resume, + .read = ak8975_read, + .config = ak8975_config, + .get_config = ak8975_get_config, + .name = "ak8975", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_AK8975, + .read_reg = 0x01, + .read_len = 10, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {9830, 4000}, + .trigger = &ak8975_read_trigger, +}; + +static +struct ext_slave_descr *ak8975_get_slave_descr(void) +{ + return &ak8975_descr; +} + +/* -------------------------------------------------------------------------- */ +struct ak8975_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int ak8975_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct ak8975_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + ak8975_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int ak8975_mod_remove(struct i2c_client *client) +{ + struct ak8975_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + inv_mpu_unregister_slave(client, private_data->pdata, + ak8975_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id ak8975_mod_id[] = { + { "ak8975", COMPASS_ID_AK8975 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ak8975_mod_id); + +static struct i2c_driver ak8975_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = ak8975_mod_probe, + .remove = ak8975_mod_remove, + .id_table = ak8975_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "ak8975_mod", + }, + .address_list = normal_i2c, +}; + +static int __init ak8975_mod_init(void) +{ + int res = i2c_add_driver(&ak8975_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "ak8975_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit ak8975_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&ak8975_mod_driver); +} + +module_init(ak8975_mod_init); +module_exit(ak8975_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate AK8975 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ak8975_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/ami306.c b/drivers/misc/inv_mpu/compass/ami306.c new file mode 100644 index 000000000000..f645457d1612 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ami306.c @@ -0,0 +1,1020 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file ami306.c + * @brief Magnetometer setup and handling methods for Aichi AMI306 + * compass. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include "ami_hw.h" +#include "ami_sensor_def.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define AMI306_REG_DATAX (0x10) +#define AMI306_REG_STAT1 (0x18) +#define AMI306_REG_CNTL1 (0x1B) +#define AMI306_REG_CNTL2 (0x1C) +#define AMI306_REG_CNTL3 (0x1D) +#define AMI306_REG_CNTL4_1 (0x5C) +#define AMI306_REG_CNTL4_2 (0x5D) + +#define AMI306_BIT_CNTL1_PC1 (0x80) +#define AMI306_BIT_CNTL1_ODR1 (0x10) +#define AMI306_BIT_CNTL1_FS1 (0x02) + +#define AMI306_BIT_CNTL2_IEN (0x10) +#define AMI306_BIT_CNTL2_DREN (0x08) +#define AMI306_BIT_CNTL2_DRP (0x04) +#define AMI306_BIT_CNTL3_F0RCE (0x40) + +#define AMI_FINE_MAX (96) +#define AMI_STANDARD_OFFSET (0x800) +#define AMI_GAIN_COR_DEFAULT (1000) + +/* -------------------------------------------------------------------------- */ +struct ami306_private_data { + int isstandby; + unsigned char fine[3]; + struct ami_sensor_parametor param; + struct ami_win_parameter win; +}; + +/* -------------------------------------------------------------------------- */ +static inline unsigned short little_u8_to_u16(unsigned char *p_u8) +{ + return p_u8[0] | (p_u8[1] << 8); +} + +static int ami306_set_bits8(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + unsigned char reg, unsigned char bits) +{ + int result; + unsigned char buf; + + result = inv_serial_read(mlsl_handle, pdata->address, reg, 1, &buf); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + buf |= bits; + result = inv_serial_single_write(mlsl_handle, pdata->address, reg, buf); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +static int ami306_wait_data_ready(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + unsigned long usecs, unsigned long times) +{ + int result = 0; + unsigned char buf; + + for (; 0 < times; --times) { + udelay(usecs); + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_STA1, 1, &buf); + if (buf & AMI_STA1_DRDY_BIT) + return 0; + else if (buf & AMI_STA1_DOR_BIT) + return INV_ERROR_COMPASS_DATA_OVERFLOW; + } + return INV_ERROR_COMPASS_DATA_NOT_READY; +} + +static int ami306_read_raw_data(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + short dat[3]) +{ + int result; + unsigned char buf[6]; + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_DATAX, sizeof(buf), buf); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dat[0] = little_u8_to_u16(&buf[0]); + dat[1] = little_u8_to_u16(&buf[2]); + dat[2] = little_u8_to_u16(&buf[4]); + return result; +} + +#define AMI_WAIT_DATAREADY_RETRY 3 /* retry times */ +#define AMI_DRDYWAIT 800 /* u(micro) sec */ +static int ami306_force_mesurement(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + short ver[3]) +{ + int result; + int status; + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL3, AMI_CTRL3_FORCE_BIT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = ami306_wait_data_ready(mlsl_handle, pdata, + AMI_DRDYWAIT, AMI_WAIT_DATAREADY_RETRY); + if (result && result != INV_ERROR_COMPASS_DATA_OVERFLOW) { + LOG_RESULT_LOCATION(result); + return result; + } + /* READ DATA X,Y,Z */ + status = ami306_read_raw_data(mlsl_handle, pdata, ver); + if (status) { + LOG_RESULT_LOCATION(status); + return status; + } + + return result; +} + +static int ami306_mea(void *mlsl_handle, + struct ext_slave_platform_data *pdata, short val[3]) +{ + int result = ami306_force_mesurement(mlsl_handle, pdata, val); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + val[0] += AMI_STANDARD_OFFSET; + val[1] += AMI_STANDARD_OFFSET; + val[2] += AMI_STANDARD_OFFSET; + return result; +} + +static int ami306_write_offset(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + unsigned char *fine) +{ + int result = 0; + unsigned char dat[3]; + dat[0] = AMI_REG_OFFX; + dat[1] = 0x7f & fine[0]; + dat[2] = 0; + result = inv_serial_write(mlsl_handle, pdata->address, + sizeof(dat), dat); + dat[0] = AMI_REG_OFFY; + dat[1] = 0x7f & fine[1]; + dat[2] = 0; + result = inv_serial_write(mlsl_handle, pdata->address, + sizeof(dat), dat); + dat[0] = AMI_REG_OFFZ; + dat[1] = 0x7f & fine[2]; + dat[2] = 0; + result = inv_serial_write(mlsl_handle, pdata->address, + sizeof(dat), dat); + return result; +} + +static int ami306_start_sensor(void *mlsl_handle, + struct ext_slave_platform_data *pdata) +{ + int result = 0; + unsigned char buf[3]; + struct ami306_private_data *private_data = pdata->private_data; + + /* Step 1 */ + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL1, + AMI_CTRL1_PC1 | AMI_CTRL1_FS1_FORCE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Step 2 */ + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL2, AMI_CTRL2_DREN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Step 3 */ + buf[0] = AMI_REG_CTRL4; + buf[1] = AMI_CTRL4_HS & 0xFF; + buf[2] = (AMI_CTRL4_HS >> 8) & 0xFF; + result = inv_serial_write(mlsl_handle, pdata->address, + sizeof(buf), buf); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Step 4 */ + result = ami306_write_offset(mlsl_handle, pdata, private_data->fine); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +/** + * This function does this. + * + * @param mlsl_handle this param is this. + * @param slave + * @param pdata + * + * @return INV_SUCCESS or non-zero error code. + */ +static int ami306_read_param(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = 0; + unsigned char regs[12]; + struct ami306_private_data *private_data = pdata->private_data; + struct ami_sensor_parametor *param = &private_data->param; + + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_SENX, sizeof(regs), regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Little endian 16 bit registers */ + param->m_gain.x = little_u8_to_u16(®s[0]); + param->m_gain.y = little_u8_to_u16(®s[2]); + param->m_gain.z = little_u8_to_u16(®s[4]); + + param->m_interference.xy = regs[7]; + param->m_interference.xz = regs[6]; + param->m_interference.yx = regs[9]; + param->m_interference.yz = regs[8]; + param->m_interference.zx = regs[11]; + param->m_interference.zy = regs[10]; + + param->m_offset.x = AMI_STANDARD_OFFSET; + param->m_offset.y = AMI_STANDARD_OFFSET; + param->m_offset.z = AMI_STANDARD_OFFSET; + + param->m_gain_cor.x = AMI_GAIN_COR_DEFAULT; + param->m_gain_cor.y = AMI_GAIN_COR_DEFAULT; + param->m_gain_cor.z = AMI_GAIN_COR_DEFAULT; + + return result; +} + +static int ami306_initial_b0_adjust(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char fine[3] = { 0 }; + short data[3]; + int diff[3] = { 0x7fff, 0x7fff, 0x7fff }; + int fn = 0; + int ax = 0; + unsigned char buf[3]; + struct ami306_private_data *private_data = pdata->private_data; + + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL2, AMI_CTRL2_DREN); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + buf[0] = AMI_REG_CTRL4; + buf[1] = AMI_CTRL4_HS & 0xFF; + buf[2] = (AMI_CTRL4_HS >> 8) & 0xFF; + result = inv_serial_write(mlsl_handle, pdata->address, + sizeof(buf), buf); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + for (fn = 0; fn < AMI_FINE_MAX; ++fn) { /* fine 0 -> 95 */ + fine[0] = fine[1] = fine[2] = fn; + result = ami306_write_offset(mlsl_handle, pdata, fine); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = ami306_force_mesurement(mlsl_handle, pdata, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("[%d] x:%-5d y:%-5d z:%-5d\n", + fn, data[0], data[1], data[2]); + + for (ax = 0; ax < 3; ax++) { + /* search point most close to zero. */ + if (diff[ax] > abs(data[ax])) { + private_data->fine[ax] = fn; + diff[ax] = abs(data[ax]); + } + } + } + MPL_LOGV("fine x:%-5d y:%-5d z:%-5d\n", + private_data->fine[0], private_data->fine[1], + private_data->fine[2]); + + result = ami306_write_offset(mlsl_handle, pdata, private_data->fine); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Software Reset */ + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL3, AMI_CTRL3_SRST_BIT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; +} + +#define SEH_RANGE_MIN 100 +#define SEH_RANGE_MAX 3950 +static int ami306_search_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + int axis; + unsigned char regs[6]; + unsigned char run_flg[3] = { 1, 1, 1 }; + unsigned char fine[3]; + unsigned char win_range_fine[3]; + unsigned short fine_output[3]; + short val[3]; + unsigned short cnt[3] = { 0 }; + struct ami306_private_data *private_data = pdata->private_data; + + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_FINEOUTPUT_X, sizeof(regs), regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + fine_output[0] = little_u8_to_u16(®s[0]); + fine_output[1] = little_u8_to_u16(®s[2]); + fine_output[2] = little_u8_to_u16(®s[4]); + + for (axis = 0; axis < 3; ++axis) { + if (fine_output[axis] == 0) { + MPL_LOGV("error fine_output %d axis:%d\n", + __LINE__, axis); + return -1; + } + /* fines per a window */ + win_range_fine[axis] = (SEH_RANGE_MAX - SEH_RANGE_MIN) + / fine_output[axis]; + } + + /* get current fine */ + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFX, 2, ®s[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFY, 2, ®s[2]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFZ, 2, ®s[4]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + fine[0] = (unsigned char)(regs[0] & 0x7f); + fine[1] = (unsigned char)(regs[2] & 0x7f); + fine[2] = (unsigned char)(regs[4] & 0x7f); + + while (run_flg[0] == 1 || run_flg[1] == 1 || run_flg[2] == 1) { + + result = ami306_mea(mlsl_handle, pdata, val); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + MPL_LOGV("val x:%-5d y:%-5d z:%-5d\n", val[0], val[1], val[2]); + MPL_LOGV("now fine x:%-5d y:%-5d z:%-5d\n", + fine[0], fine[1], fine[2]); + + for (axis = 0; axis < 3; ++axis) { + if (axis == 0) { /* X-axis is reversed */ + val[axis] = 0x0FFF & ~val[axis]; + } + if (val[axis] < SEH_RANGE_MIN) { + /* At the case of less low limmit. */ + fine[axis] -= win_range_fine[axis]; + MPL_LOGV("min : fine=%d diff=%d\n", + fine[axis], win_range_fine[axis]); + } + if (val[axis] > SEH_RANGE_MAX) { + /* At the case of over high limmit. */ + fine[axis] += win_range_fine[axis]; + MPL_LOGV("max : fine=%d diff=%d\n", + fine[axis], win_range_fine[axis]); + } + if (SEH_RANGE_MIN <= val[axis] && + val[axis] <= SEH_RANGE_MAX) { + /* In the current window. */ + int diff_fine = + (val[axis] - AMI_STANDARD_OFFSET) / + fine_output[axis]; + fine[axis] += diff_fine; + run_flg[axis] = 0; + MPL_LOGV("mid : fine=%d diff=%d\n", + fine[axis], diff_fine); + } + + if (!(0 <= fine[axis] && fine[axis] < AMI_FINE_MAX)) { + MPL_LOGE("fine err :%d\n", cnt[axis]); + goto out; + } + if (cnt[axis] > 3) { + MPL_LOGE("cnt err :%d\n", cnt[axis]); + goto out; + } + cnt[axis]++; + } + MPL_LOGV("new fine x:%-5d y:%-5d z:%-5d\n", + fine[0], fine[1], fine[2]); + + /* set current fine */ + result = ami306_write_offset(mlsl_handle, pdata, fine); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + memcpy(private_data->fine, fine, sizeof(fine)); +out: + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL3, AMI_CTRL3_SRST_BIT); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + udelay(250 + 50); + return 0; +} + +static int ami306_read_win(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = 0; + unsigned char regs[6]; + struct ami306_private_data *private_data = pdata->private_data; + struct ami_win_parameter *win = &private_data->win; + + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFOTPX, sizeof(regs), regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + win->m_0Gauss_fine.x = (unsigned char)(regs[0] & 0x7f); + win->m_0Gauss_fine.y = (unsigned char)(regs[2] & 0x7f); + win->m_0Gauss_fine.z = (unsigned char)(regs[4] & 0x7f); + + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFX, 2, ®s[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFY, 2, ®s[2]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_REG_OFFZ, 2, ®s[4]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + win->m_fine.x = (unsigned char)(regs[0] & 0x7f); + win->m_fine.y = (unsigned char)(regs[2] & 0x7f); + win->m_fine.z = (unsigned char)(regs[4] & 0x7f); + + result = inv_serial_read(mlsl_handle, pdata->address, + AMI_FINEOUTPUT_X, sizeof(regs), regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + win->m_fine_output.x = little_u8_to_u16(®s[0]); + win->m_fine_output.y = little_u8_to_u16(®s[2]); + win->m_fine_output.z = little_u8_to_u16(®s[4]); + + return result; +} + +static int ami306_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg; + result = inv_serial_read(mlsl_handle, pdata->address, + AMI306_REG_CNTL1, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + reg &= ~(AMI306_BIT_CNTL1_PC1 | AMI306_BIT_CNTL1_FS1); + result = inv_serial_single_write(mlsl_handle, pdata->address, + AMI306_REG_CNTL1, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int ami306_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + unsigned char regs[] = { + AMI306_REG_CNTL4_1, + 0x7E, + 0xA0 + }; + /* Step1. Set CNTL1 reg to power model active (Write CNTL1:PC1=1) */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + AMI306_REG_CNTL1, + AMI306_BIT_CNTL1_PC1 | + AMI306_BIT_CNTL1_FS1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Step2. Set CNTL2 reg to DRDY active high and enabled + (Write CNTL2:DREN=1) */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + AMI306_REG_CNTL2, + AMI306_BIT_CNTL2_DREN | + AMI306_BIT_CNTL2_DRP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Step3. Set CNTL4 reg to for measurement speed: Write CNTL4, 0xA07E */ + result = inv_serial_write(mlsl_handle, pdata->address, + ARRAY_SIZE(regs), regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Step4. skipped */ + + /* Step5. Set CNTL3 reg to forced measurement period + (Write CNTL3:FORCE=1) */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + AMI306_REG_CNTL3, + AMI306_BIT_CNTL3_F0RCE); + + return result; +} + +static int ami306_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + int ii; + short val[COMPASS_NUM_AXES]; + + result = ami306_mea(mlsl_handle, pdata, val); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + for (ii = 0; ii < COMPASS_NUM_AXES; ii++) { + val[ii] -= AMI_STANDARD_OFFSET; + data[2 * ii] = val[ii] & 0xFF; + data[(2 * ii) + 1] = (val[ii] >> 8) & 0xFF; + } + return result; +} + +static int ami306_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + struct ami306_private_data *private_data; + private_data = (struct ami306_private_data *) + kzalloc(sizeof(struct ami306_private_data), GFP_KERNEL); + + if (!private_data) + return INV_ERROR_MEMORY_EXAUSTED; + + pdata->private_data = private_data; + result = ami306_set_bits8(mlsl_handle, pdata, + AMI_REG_CTRL1, + AMI_CTRL1_PC1 | AMI_CTRL1_FS1_FORCE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Read Parameters */ + result = ami306_read_param(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Read Window */ + result = ami306_initial_b0_adjust(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = ami306_start_sensor(mlsl_handle, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = ami306_read_win(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write(mlsl_handle, pdata->address, + AMI306_REG_CNTL1, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_SUCCESS; +} + +static int ami306_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + kfree(pdata->private_data); + return INV_SUCCESS; +} + +static int ami306_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + if (!data->data) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + switch (data->key) { + case MPU_SLAVE_PARAM: + case MPU_SLAVE_WINDOW: + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + case MPU_SLAVE_CONFIG_ODR_RESUME: + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static int ami306_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + int result; + struct ami306_private_data *private_data = pdata->private_data; + if (!data->data) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + switch (data->key) { + case MPU_SLAVE_PARAM: + if (sizeof(struct ami_sensor_parametor) > data->len) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + if (data->apply) { + result = ami306_read_param(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + memcpy(data->data, &private_data->param, + sizeof(struct ami_sensor_parametor)); + break; + case MPU_SLAVE_WINDOW: + if (sizeof(struct ami_win_parameter) > data->len) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + if (data->apply) { + result = ami306_read_win(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + memcpy(data->data, &private_data->win, + sizeof(struct ami_win_parameter)); + break; + case MPU_SLAVE_SEARCHOFFSET: + if (sizeof(struct ami_win_parameter) > data->len) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + if (data->apply) { + result = ami306_search_offset(mlsl_handle, + slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Start sensor */ + result = ami306_start_sensor(mlsl_handle, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = ami306_read_win(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + memcpy(data->data, &private_data->win, + sizeof(struct ami_win_parameter)); + break; + case MPU_SLAVE_READWINPARAMS: + if (sizeof(struct ami_win_parameter) > data->len) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + if (data->apply) { + result = ami306_initial_b0_adjust(mlsl_handle, + slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Start sensor */ + result = ami306_start_sensor(mlsl_handle, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = ami306_read_win(mlsl_handle, slave, pdata); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + memcpy(data->data, &private_data->win, + sizeof(struct ami_win_parameter)); + break; + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = 0; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = 50000; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + case MPU_SLAVE_CONFIG_FSR_RESUME: + case MPU_SLAVE_CONFIG_MOT_THS: + case MPU_SLAVE_CONFIG_NMOT_THS: + case MPU_SLAVE_CONFIG_MOT_DUR: + case MPU_SLAVE_CONFIG_NMOT_DUR: + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + case MPU_SLAVE_CONFIG_IRQ_RESUME: + case MPU_SLAVE_READ_SCALE: + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + +static struct ext_slave_read_trigger ami306_read_trigger = { + /*.reg = */ AMI_REG_CTRL3, + /*.value = */ AMI_CTRL3_FORCE_BIT +}; + +static struct ext_slave_descr ami306_descr = { + .init = ami306_init, + .exit = ami306_exit, + .suspend = ami306_suspend, + .resume = ami306_resume, + .read = ami306_read, + .config = ami306_config, + .get_config = ami306_get_config, + .name = "ami306", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_AMI306, + .read_reg = 0x0E, + .read_len = 13, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {5461, 3333}, + .trigger = &ami306_read_trigger, +}; + +static +struct ext_slave_descr *ami306_get_slave_descr(void) +{ + return &ami306_descr; +} + +/* -------------------------------------------------------------------------- */ +struct ami306_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int ami306_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct ami306_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + ami306_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int ami306_mod_remove(struct i2c_client *client) +{ + struct ami306_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + ami306_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id ami306_mod_id[] = { + { "ami306", COMPASS_ID_AMI306 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ami306_mod_id); + +static struct i2c_driver ami306_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = ami306_mod_probe, + .remove = ami306_mod_remove, + .id_table = ami306_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "ami306_mod", + }, + .address_list = normal_i2c, +}; + +static int __init ami306_mod_init(void) +{ + int res = i2c_add_driver(&ami306_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "ami306_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit ami306_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&ami306_mod_driver); +} + +module_init(ami306_mod_init); +module_exit(ami306_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate AMI306 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ami306_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/ami30x.c b/drivers/misc/inv_mpu/compass/ami30x.c new file mode 100644 index 000000000000..0c4937c44263 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ami30x.c @@ -0,0 +1,308 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file ami30x.c + * @brief Magnetometer setup and handling methods for Aichi AMI304 + * and AMI305 compass devices. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define AMI30X_REG_DATAX (0x10) +#define AMI30X_REG_STAT1 (0x18) +#define AMI30X_REG_CNTL1 (0x1B) +#define AMI30X_REG_CNTL2 (0x1C) +#define AMI30X_REG_CNTL3 (0x1D) + +#define AMI30X_BIT_CNTL1_PC1 (0x80) +#define AMI30X_BIT_CNTL1_ODR1 (0x10) +#define AMI30X_BIT_CNTL1_FS1 (0x02) + +#define AMI30X_BIT_CNTL2_IEN (0x10) +#define AMI30X_BIT_CNTL2_DREN (0x08) +#define AMI30X_BIT_CNTL2_DRP (0x04) +#define AMI30X_BIT_CNTL3_F0RCE (0x40) + +/* -------------------------------------------------------------------------- */ +static int ami30x_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char reg; + result = + inv_serial_read(mlsl_handle, pdata->address, AMI30X_REG_CNTL1, + 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + reg &= ~(AMI30X_BIT_CNTL1_PC1 | AMI30X_BIT_CNTL1_FS1); + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AMI30X_REG_CNTL1, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int ami30x_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Set CNTL1 reg to power model active */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AMI30X_REG_CNTL1, + AMI30X_BIT_CNTL1_PC1 | + AMI30X_BIT_CNTL1_FS1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Set CNTL2 reg to DRDY active high and enabled */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AMI30X_REG_CNTL2, + AMI30X_BIT_CNTL2_DREN | + AMI30X_BIT_CNTL2_DRP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Set CNTL3 reg to forced measurement period */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AMI30X_REG_CNTL3, AMI30X_BIT_CNTL3_F0RCE); + + return result; +} + +static int ami30x_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + int result = INV_SUCCESS; + + /* Read status reg and check if data ready (DRDY) */ + result = + inv_serial_read(mlsl_handle, pdata->address, AMI30X_REG_STAT1, + 1, &stat); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (stat & 0x40) { + result = + inv_serial_read(mlsl_handle, pdata->address, + AMI30X_REG_DATAX, 6, (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* start another measurement */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + AMI30X_REG_CNTL3, + AMI30X_BIT_CNTL3_F0RCE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_SUCCESS; + } + + return INV_ERROR_COMPASS_DATA_NOT_READY; +} + + +/* For AMI305,the range field needs to be modified to {9830.4f} */ +static struct ext_slave_descr ami30x_descr = { + .init = NULL, + .exit = NULL, + .suspend = ami30x_suspend, + .resume = ami30x_resume, + .read = ami30x_read, + .config = NULL, + .get_config = NULL, + .name = "ami30x", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_AMI30X, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {5461, 3333}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *ami30x_get_slave_descr(void) +{ + return &ami30x_descr; +} + +/* -------------------------------------------------------------------------- */ +struct ami30x_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int ami30x_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct ami30x_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + ami30x_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int ami30x_mod_remove(struct i2c_client *client) +{ + struct ami30x_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + ami30x_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id ami30x_mod_id[] = { + { "ami30x", COMPASS_ID_AMI30X }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ami30x_mod_id); + +static struct i2c_driver ami30x_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = ami30x_mod_probe, + .remove = ami30x_mod_remove, + .id_table = ami30x_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "ami30x_mod", + }, + .address_list = normal_i2c, +}; + +static int __init ami30x_mod_init(void) +{ + int res = i2c_add_driver(&ami30x_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "ami30x_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit ami30x_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&ami30x_mod_driver); +} + +module_init(ami30x_mod_init); +module_exit(ami30x_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate AMI30X sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ami30x_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/ami_hw.h b/drivers/misc/inv_mpu/compass/ami_hw.h new file mode 100644 index 000000000000..32a04e91cdc1 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ami_hw.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 Information System Products Co.,Ltd. + * + * 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. + */ + +#ifndef AMI_HW_H +#define AMI_HW_H + +#define AMI_I2C_BUS_NUM 2 + +#ifdef AMI304_MODEL +#define AMI_I2C_ADDRESS 0x0F +#else +#define AMI_I2C_ADDRESS 0x0E +#endif + +#define AMI_GPIO_INT 152 +#define AMI_GPIO_DRDY 153 + +/* AMI-Sensor Internal Register Address + *(Please refer to AMI-Sensor Specifications) + */ +#define AMI_MOREINFO_CMDCODE 0x0d +#define AMI_WHOIAM_CMDCODE 0x0f +#define AMI_REG_DATAX 0x10 +#define AMI_REG_DATAY 0x12 +#define AMI_REG_DATAZ 0x14 +#define AMI_REG_STA1 0x18 +#define AMI_REG_CTRL1 0x1b +#define AMI_REG_CTRL2 0x1c +#define AMI_REG_CTRL3 0x1d +#define AMI_REG_B0X 0x20 +#define AMI_REG_B0Y 0x22 +#define AMI_REG_B0Z 0x24 +#define AMI_REG_CTRL5 0x40 +#define AMI_REG_CTRL4 0x5c +#define AMI_REG_TEMP 0x60 +#define AMI_REG_DELAYX 0x68 +#define AMI_REG_DELAYY 0x6e +#define AMI_REG_DELAYZ 0x74 +#define AMI_REG_OFFX 0x6c +#define AMI_REG_OFFY 0x72 +#define AMI_REG_OFFZ 0x78 +#define AMI_FINEOUTPUT_X 0x90 +#define AMI_FINEOUTPUT_Y 0x92 +#define AMI_FINEOUTPUT_Z 0x94 +#define AMI_REG_SENX 0x96 +#define AMI_REG_SENY 0x98 +#define AMI_REG_SENZ 0x9a +#define AMI_REG_GAINX 0x9c +#define AMI_REG_GAINY 0x9e +#define AMI_REG_GAINZ 0xa0 +#define AMI_GETVERSION_CMDCODE 0xe8 +#define AMI_SERIALNUMBER_CMDCODE 0xea +#define AMI_REG_B0OTPX 0xa2 +#define AMI_REG_B0OTPY 0xb8 +#define AMI_REG_B0OTPZ 0xce +#define AMI_REG_OFFOTPX 0xf8 +#define AMI_REG_OFFOTPY 0xfa +#define AMI_REG_OFFOTPZ 0xfc + +/* AMI-Sensor Control Bit (Please refer to AMI-Sensor Specifications) */ +#define AMI_CTRL1_PC1 0x80 +#define AMI_CTRL1_FS1_FORCE 0x02 +#define AMI_CTRL1_ODR1 0x10 +#define AMI_CTRL2_DREN 0x08 +#define AMI_CTRL2_DRP 0x04 +#define AMI_CTRL3_FORCE_BIT 0x40 +#define AMI_CTRL3_B0_LO_BIT 0x10 +#define AMI_CTRL3_SRST_BIT 0x80 +#define AMI_CTRL4_HS 0xa07e +#define AMI_CTRL4_AB 0x0001 +#define AMI_STA1_DRDY_BIT 0x40 +#define AMI_STA1_DOR_BIT 0x20 + +#endif diff --git a/drivers/misc/inv_mpu/compass/ami_sensor_def.h b/drivers/misc/inv_mpu/compass/ami_sensor_def.h new file mode 100644 index 000000000000..64032e2bf1fb --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ami_sensor_def.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2010 Information System Products Co.,Ltd. + * + * 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. + */ + +/* + * Definitions for ami306 compass chip. + */ +#ifndef AMI_SENSOR_DEF_H +#define AMI_SENSOR_DEF_H + +/********************************************************************* + Constant + *********************************************************************/ +#define AMI_OK 0x00 /**< Normal */ +#define AMI_PARAM_ERR 0x01 /**< Parameter Error */ +#define AMI_SEQ_ERR 0x02 /**< Squence Error */ +#define AMI_SYSTEM_ERR 0x10 /**< System Error */ +#define AMI_BLOCK_ERR 0x20 /**< Block Error */ +#define AMI_ERROR 0x99 /**< other Error */ + +/********************************************************************* + Struct definition + *********************************************************************/ +/** axis sensitivity(gain) calibration parameter information */ +struct ami_vector3d { + signed short x; /**< X-axis */ + signed short y; /**< Y-axis */ + signed short z; /**< Z-axis */ +}; + +/** axis interference information */ +struct ami_interference { + /**< Y-axis magnetic field for X-axis correction value */ + signed short xy; + /**< Z-axis magnetic field for X-axis correction value */ + signed short xz; + /**< X-axis magnetic field for Y-axis correction value */ + signed short yx; + /**< Z-axis magnetic field for Y-axis correction value */ + signed short yz; + /**< X-axis magnetic field for Z-axis correction value */ + signed short zx; + /**< Y-axis magnetic field for Z-axis correction value */ + signed short zy; +}; + +/** sensor calibration Parameter information */ +struct ami_sensor_parametor { + /**< geomagnetic field sensor gain */ + struct ami_vector3d m_gain; + /**< geomagnetic field sensor gain correction parameter */ + struct ami_vector3d m_gain_cor; + /**< geomagnetic field sensor offset */ + struct ami_vector3d m_offset; + /**< geomagnetic field sensor axis interference parameter */ + struct ami_interference m_interference; +#ifdef AMI_6AXIS + /**< acceleration sensor gain */ + struct ami_vector3d a_gain; + /**< acceleration sensor offset */ + struct ami_vector3d a_offset; + /**< acceleration sensor deviation */ + signed short a_deviation; +#endif +}; + +/** G2-Sensor measurement value (voltage ADC value ) */ +struct ami_sensor_rawvalue { + /**< geomagnetic field sensor measurement X-axis value + (mounted position/direction reference) */ + unsigned short mx; + /**< geomagnetic field sensor measurement Y-axis value + (mounted position/direction reference) */ + unsigned short my; + /**< geomagnetic field sensor measurement Z-axis value + (mounted position/direction reference) */ + unsigned short mz; +#ifdef AMI_6AXIS + /**< acceleration sensor measurement X-axis value + (mounted position/direction reference) */ + unsigned short ax; + /**< acceleration sensor measurement Y-axis value + (mounted position/direction reference) */ + unsigned short ay; + /**< acceleration sensor measurement Z-axis value + (mounted position/direction reference) */ + unsigned short az; +#endif + /**< temperature sensor measurement value */ + unsigned short temperature; +}; + +/** Window function Parameter information */ +struct ami_win_parameter { + /**< current fine value */ + struct ami_vector3d m_fine; + /**< change per 1coarse */ + struct ami_vector3d m_fine_output; + /**< fine value at zero gauss */ + struct ami_vector3d m_0Gauss_fine; +#ifdef AMI304 + /**< current b0 value */ + struct ami_vector3d m_b0; + /**< current coarse value */ + struct ami_vector3d m_coar; + /**< change per 1fine */ + struct ami_vector3d m_coar_output; + /**< coarse value at zero gauss */ + struct ami_vector3d m_0Gauss_coar; + /**< delay value */ + struct ami_vector3d m_delay; +#endif +}; + +/** AMI chip information ex) 1)model 2)s/n 3)ver 4)more info in the chip */ +struct ami_chipinfo { + unsigned short info; /* INFO 0x0d/0x0e reg. */ + unsigned short ver; /* VER 0xe8/0xe9 reg. */ + unsigned short sn; /* SN 0xea/0xeb reg. */ + unsigned char wia; /* WIA 0x0f reg. */ +}; + +/** AMI Driver Information */ +struct ami_driverinfo { + unsigned char remarks[40]; /* Some Information */ + unsigned char datetime[30]; /* compiled date&time */ + unsigned char ver_major; /* major version */ + unsigned char ver_middle; /* middle.. */ + unsigned char ver_minor; /* minor .. */ +}; + +#endif diff --git a/drivers/misc/inv_mpu/compass/hmc5883.c b/drivers/misc/inv_mpu/compass/hmc5883.c new file mode 100644 index 000000000000..fdf2ac00565a --- /dev/null +++ b/drivers/misc/inv_mpu/compass/hmc5883.c @@ -0,0 +1,391 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file hmc5883.c + * @brief Magnetometer setup and handling methods for Honeywell + * HMC5883 compass. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +enum HMC_REG { + HMC_REG_CONF_A = 0x0, + HMC_REG_CONF_B = 0x1, + HMC_REG_MODE = 0x2, + HMC_REG_X_M = 0x3, + HMC_REG_X_L = 0x4, + HMC_REG_Z_M = 0x5, + HMC_REG_Z_L = 0x6, + HMC_REG_Y_M = 0x7, + HMC_REG_Y_L = 0x8, + HMC_REG_STATUS = 0x9, + HMC_REG_ID_A = 0xA, + HMC_REG_ID_B = 0xB, + HMC_REG_ID_C = 0xC +}; + +enum HMC_CONF_A { + HMC_CONF_A_DRATE_MASK = 0x1C, + HMC_CONF_A_DRATE_0_75 = 0x00, + HMC_CONF_A_DRATE_1_5 = 0x04, + HMC_CONF_A_DRATE_3 = 0x08, + HMC_CONF_A_DRATE_7_5 = 0x0C, + HMC_CONF_A_DRATE_15 = 0x10, + HMC_CONF_A_DRATE_30 = 0x14, + HMC_CONF_A_DRATE_75 = 0x18, + HMC_CONF_A_MEAS_MASK = 0x3, + HMC_CONF_A_MEAS_NORM = 0x0, + HMC_CONF_A_MEAS_POS = 0x1, + HMC_CONF_A_MEAS_NEG = 0x2 +}; + +enum HMC_CONF_B { + HMC_CONF_B_GAIN_MASK = 0xE0, + HMC_CONF_B_GAIN_0_9 = 0x00, + HMC_CONF_B_GAIN_1_2 = 0x20, + HMC_CONF_B_GAIN_1_9 = 0x40, + HMC_CONF_B_GAIN_2_5 = 0x60, + HMC_CONF_B_GAIN_4_0 = 0x80, + HMC_CONF_B_GAIN_4_6 = 0xA0, + HMC_CONF_B_GAIN_5_5 = 0xC0, + HMC_CONF_B_GAIN_7_9 = 0xE0 +}; + +enum HMC_MODE { + HMC_MODE_MASK = 0x3, + HMC_MODE_CONT = 0x0, + HMC_MODE_SINGLE = 0x1, + HMC_MODE_IDLE = 0x2, + HMC_MODE_SLEEP = 0x3 +}; + +/* -------------------------------------------------------------------------- */ +static int hmc5883_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + result = + inv_serial_single_write(mlsl_handle, pdata->address, + HMC_REG_MODE, HMC_MODE_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(3); + + return result; +} + +static int hmc5883_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Use single measurement mode. Start at sleep state. */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + HMC_REG_MODE, HMC_MODE_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Config normal measurement */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + HMC_REG_CONF_A, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Adjust gain to 307 LSB/Gauss */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + HMC_REG_CONF_B, HMC_CONF_B_GAIN_5_5); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int hmc5883_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + int result = INV_SUCCESS; + unsigned char tmp; + short axisFixed; + + /* Read status reg. to check if data is ready */ + result = + inv_serial_read(mlsl_handle, pdata->address, HMC_REG_STATUS, 1, + &stat); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (stat & 0x01) { + result = + inv_serial_read(mlsl_handle, pdata->address, + HMC_REG_X_M, 6, (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* switch YZ axis to proper position */ + tmp = data[2]; + data[2] = data[4]; + data[4] = tmp; + tmp = data[3]; + data[3] = data[5]; + data[5] = tmp; + + /*drop data if overflows */ + if ((data[0] == 0xf0) || (data[2] == 0xf0) + || (data[4] == 0xf0)) { + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, + pdata->address, + HMC_REG_MODE, + HMC_MODE_SINGLE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return INV_ERROR_COMPASS_DATA_OVERFLOW; + } + /* convert to fixed point and apply sensitivity correction for + Z-axis */ + axisFixed = + (short)((unsigned short)data[5] + + (unsigned short)data[4] * 256); + /* scale up by 1.125 (36/32) */ + axisFixed = (short)(axisFixed * 36); + data[4] = axisFixed >> 8; + data[5] = axisFixed & 0xFF; + + axisFixed = + (short)((unsigned short)data[3] + + (unsigned short)data[2] * 256); + axisFixed = (short)(axisFixed * 32); + data[2] = axisFixed >> 8; + data[3] = axisFixed & 0xFF; + + axisFixed = + (short)((unsigned short)data[1] + + (unsigned short)data[0] * 256); + axisFixed = (short)(axisFixed * 32); + data[0] = axisFixed >> 8; + data[1] = axisFixed & 0xFF; + + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + HMC_REG_MODE, HMC_MODE_SINGLE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_SUCCESS; + } else { + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + HMC_REG_MODE, HMC_MODE_SINGLE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_ERROR_COMPASS_DATA_NOT_READY; + } +} + +static struct ext_slave_descr hmc5883_descr = { + .init = NULL, + .exit = NULL, + .suspend = hmc5883_suspend, + .resume = hmc5883_resume, + .read = hmc5883_read, + .config = NULL, + .get_config = NULL, + .name = "hmc5883", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_HMC5883, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {10673, 6156}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *hmc5883_get_slave_descr(void) +{ + return &hmc5883_descr; +} + +/* -------------------------------------------------------------------------- */ +struct hmc5883_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int hmc5883_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct hmc5883_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + hmc5883_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int hmc5883_mod_remove(struct i2c_client *client) +{ + struct hmc5883_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + hmc5883_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id hmc5883_mod_id[] = { + { "hmc5883", COMPASS_ID_HMC5883 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, hmc5883_mod_id); + +static struct i2c_driver hmc5883_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = hmc5883_mod_probe, + .remove = hmc5883_mod_remove, + .id_table = hmc5883_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "hmc5883_mod", + }, + .address_list = normal_i2c, +}; + +static int __init hmc5883_mod_init(void) +{ + int res = i2c_add_driver(&hmc5883_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "hmc5883_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit hmc5883_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&hmc5883_mod_driver); +} + +module_init(hmc5883_mod_init); +module_exit(hmc5883_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate HMC5883 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("hmc5883_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/hscdtd002b.c b/drivers/misc/inv_mpu/compass/hscdtd002b.c new file mode 100644 index 000000000000..4f6013cbe3dc --- /dev/null +++ b/drivers/misc/inv_mpu/compass/hscdtd002b.c @@ -0,0 +1,294 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file hscdtd002b.c + * @brief Magnetometer setup and handling methods for Alps HSCDTD002B + * compass. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define COMPASS_HSCDTD002B_STAT (0x18) +#define COMPASS_HSCDTD002B_CTRL1 (0x1B) +#define COMPASS_HSCDTD002B_CTRL2 (0x1C) +#define COMPASS_HSCDTD002B_CTRL3 (0x1D) +#define COMPASS_HSCDTD002B_DATAX (0x10) + +/* -------------------------------------------------------------------------- */ +static int hscdtd002b_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Power mode: stand-by */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL1, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); /* turn-off time */ + + return result; +} + +static int hscdtd002b_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Soft reset */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL3, 0x80); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Force state; Power mode: active */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL1, 0x82); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Data ready enable */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL2, 0x08); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); /* turn-on time */ + + return result; +} + +static int hscdtd002b_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + int result = INV_SUCCESS; + int status = INV_SUCCESS; + + /* Read status reg. to check if data is ready */ + result = + inv_serial_read(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_STAT, 1, &stat); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (stat & 0x40) { + result = + inv_serial_read(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_DATAX, 6, + (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + status = INV_SUCCESS; + } else if (stat & 0x20) { + status = INV_ERROR_COMPASS_DATA_OVERFLOW; + } else { + status = INV_ERROR_COMPASS_DATA_NOT_READY; + } + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD002B_CTRL3, 0x40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return status; +} + +static struct ext_slave_descr hscdtd002b_descr = { + .init = NULL, + .exit = NULL, + .suspend = hscdtd002b_suspend, + .resume = hscdtd002b_resume, + .read = hscdtd002b_read, + .config = NULL, + .get_config = NULL, + .name = "hscdtd002b", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_HSCDTD002B, + .read_reg = 0x10, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {9830, 4000}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *hscdtd002b_get_slave_descr(void) +{ + return &hscdtd002b_descr; +} + +/* -------------------------------------------------------------------------- */ +struct hscdtd002b_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int hscdtd002b_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct hscdtd002b_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + hscdtd002b_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int hscdtd002b_mod_remove(struct i2c_client *client) +{ + struct hscdtd002b_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + hscdtd002b_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id hscdtd002b_mod_id[] = { + { "hscdtd002b", COMPASS_ID_HSCDTD002B }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, hscdtd002b_mod_id); + +static struct i2c_driver hscdtd002b_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = hscdtd002b_mod_probe, + .remove = hscdtd002b_mod_remove, + .id_table = hscdtd002b_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "hscdtd002b_mod", + }, + .address_list = normal_i2c, +}; + +static int __init hscdtd002b_mod_init(void) +{ + int res = i2c_add_driver(&hscdtd002b_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "hscdtd002b_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit hscdtd002b_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&hscdtd002b_mod_driver); +} + +module_init(hscdtd002b_mod_init); +module_exit(hscdtd002b_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate HSCDTD002B sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("hscdtd002b_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/hscdtd004a.c b/drivers/misc/inv_mpu/compass/hscdtd004a.c new file mode 100644 index 000000000000..f0915599bd2f --- /dev/null +++ b/drivers/misc/inv_mpu/compass/hscdtd004a.c @@ -0,0 +1,318 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file hscdtd004a.c + * @brief Magnetometer setup and handling methods for Alps HSCDTD004A + * compass. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define COMPASS_HSCDTD004A_STAT (0x18) +#define COMPASS_HSCDTD004A_CTRL1 (0x1B) +#define COMPASS_HSCDTD004A_CTRL2 (0x1C) +#define COMPASS_HSCDTD004A_CTRL3 (0x1D) +#define COMPASS_HSCDTD004A_DATAX (0x10) + +/* -------------------------------------------------------------------------- */ + +static int hscdtd004a_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Power mode: stand-by */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL1, 0x00); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); /* turn-off time */ + + return result; +} + +static int hscdtd004a_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char data1, data2[2]; + + result = inv_serial_read(mlsl_handle, pdata->address, 0xf, 1, &data1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(mlsl_handle, pdata->address, 0xd, 2, data2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (data1 != 0x49 || data2[0] != 0x45 || data2[1] != 0x54) { + LOG_RESULT_LOCATION(INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED); + return INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED; + } + return result; +} + +static int hscdtd004a_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Soft reset */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL3, 0x80); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Normal state; Power mode: active */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL1, 0x82); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Data ready enable */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL2, 0x7C); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(1); /* turn-on time */ + return result; +} + +static int hscdtd004a_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + int result = INV_SUCCESS; + int status = INV_SUCCESS; + + /* Read status reg. to check if data is ready */ + result = + inv_serial_read(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_STAT, 1, &stat); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (stat & 0x48) { + result = + inv_serial_read(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_DATAX, 6, + (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + status = INV_SUCCESS; + } else if (stat & 0x68) { + status = INV_ERROR_COMPASS_DATA_OVERFLOW; + } else { + status = INV_ERROR_COMPASS_DATA_NOT_READY; + } + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + COMPASS_HSCDTD004A_CTRL3, 0x40); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return status; + +} + +static struct ext_slave_descr hscdtd004a_descr = { + .init = hscdtd004a_init, + .exit = NULL, + .suspend = hscdtd004a_suspend, + .resume = hscdtd004a_resume, + .read = hscdtd004a_read, + .config = NULL, + .get_config = NULL, + .name = "hscdtd004a", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_HSCDTD004A, + .read_reg = 0x10, + .read_len = 6, + .endian = EXT_SLAVE_LITTLE_ENDIAN, + .range = {9830, 4000}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *hscdtd004a_get_slave_descr(void) +{ + return &hscdtd004a_descr; +} + +/* -------------------------------------------------------------------------- */ +struct hscdtd004a_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int hscdtd004a_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct hscdtd004a_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + hscdtd004a_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int hscdtd004a_mod_remove(struct i2c_client *client) +{ + struct hscdtd004a_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + hscdtd004a_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id hscdtd004a_mod_id[] = { + { "hscdtd004a", COMPASS_ID_HSCDTD004A }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, hscdtd004a_mod_id); + +static struct i2c_driver hscdtd004a_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = hscdtd004a_mod_probe, + .remove = hscdtd004a_mod_remove, + .id_table = hscdtd004a_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "hscdtd004a_mod", + }, + .address_list = normal_i2c, +}; + +static int __init hscdtd004a_mod_init(void) +{ + int res = i2c_add_driver(&hscdtd004a_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "hscdtd004a_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit hscdtd004a_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&hscdtd004a_mod_driver); +} + +module_init(hscdtd004a_mod_init); +module_exit(hscdtd004a_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate HSCDTD004A sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("hscdtd004a_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/lsm303dlx_m.c b/drivers/misc/inv_mpu/compass/lsm303dlx_m.c new file mode 100644 index 000000000000..32f8cdddb00b --- /dev/null +++ b/drivers/misc/inv_mpu/compass/lsm303dlx_m.c @@ -0,0 +1,395 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file lsm303dlx_m.c + * @brief Magnetometer setup and handling methods for ST LSM303 + * compass. + * This magnetometer device is part of a combo chip with the + * ST LIS331DLH accelerometer and the logic in entirely based + * on the Honeywell HMC5883 magnetometer. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +enum LSM_REG { + LSM_REG_CONF_A = 0x0, + LSM_REG_CONF_B = 0x1, + LSM_REG_MODE = 0x2, + LSM_REG_X_M = 0x3, + LSM_REG_X_L = 0x4, + LSM_REG_Z_M = 0x5, + LSM_REG_Z_L = 0x6, + LSM_REG_Y_M = 0x7, + LSM_REG_Y_L = 0x8, + LSM_REG_STATUS = 0x9, + LSM_REG_ID_A = 0xA, + LSM_REG_ID_B = 0xB, + LSM_REG_ID_C = 0xC +}; + +enum LSM_CONF_A { + LSM_CONF_A_DRATE_MASK = 0x1C, + LSM_CONF_A_DRATE_0_75 = 0x00, + LSM_CONF_A_DRATE_1_5 = 0x04, + LSM_CONF_A_DRATE_3 = 0x08, + LSM_CONF_A_DRATE_7_5 = 0x0C, + LSM_CONF_A_DRATE_15 = 0x10, + LSM_CONF_A_DRATE_30 = 0x14, + LSM_CONF_A_DRATE_75 = 0x18, + LSM_CONF_A_MEAS_MASK = 0x3, + LSM_CONF_A_MEAS_NORM = 0x0, + LSM_CONF_A_MEAS_POS = 0x1, + LSM_CONF_A_MEAS_NEG = 0x2 +}; + +enum LSM_CONF_B { + LSM_CONF_B_GAIN_MASK = 0xE0, + LSM_CONF_B_GAIN_0_9 = 0x00, + LSM_CONF_B_GAIN_1_2 = 0x20, + LSM_CONF_B_GAIN_1_9 = 0x40, + LSM_CONF_B_GAIN_2_5 = 0x60, + LSM_CONF_B_GAIN_4_0 = 0x80, + LSM_CONF_B_GAIN_4_6 = 0xA0, + LSM_CONF_B_GAIN_5_5 = 0xC0, + LSM_CONF_B_GAIN_7_9 = 0xE0 +}; + +enum LSM_MODE { + LSM_MODE_MASK = 0x3, + LSM_MODE_CONT = 0x0, + LSM_MODE_SINGLE = 0x1, + LSM_MODE_IDLE = 0x2, + LSM_MODE_SLEEP = 0x3 +}; + +/* -------------------------------------------------------------------------- */ + +static int lsm303dlx_m_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + result = + inv_serial_single_write(mlsl_handle, pdata->address, + LSM_REG_MODE, LSM_MODE_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(3); + + return result; +} + +static int lsm303dlx_m_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + /* Use single measurement mode. Start at sleep state. */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + LSM_REG_MODE, LSM_MODE_SLEEP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Config normal measurement */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + LSM_REG_CONF_A, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Adjust gain to 320 LSB/Gauss */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + LSM_REG_CONF_B, LSM_CONF_B_GAIN_5_5); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int lsm303dlx_m_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + int result = INV_SUCCESS; + short axis_fixed; + + /* Read status reg. to check if data is ready */ + result = + inv_serial_read(mlsl_handle, pdata->address, LSM_REG_STATUS, 1, + &stat); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (stat & 0x01) { + result = + inv_serial_read(mlsl_handle, pdata->address, + LSM_REG_X_M, 6, (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /*drop data if overflows */ + if ((data[0] == 0xf0) || (data[2] == 0xf0) + || (data[4] == 0xf0)) { + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, + pdata->address, + LSM_REG_MODE, + LSM_MODE_SINGLE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return INV_ERROR_COMPASS_DATA_OVERFLOW; + } + /* convert to fixed point and apply sensitivity correction for + Z-axis */ + axis_fixed = + (short)((unsigned short)data[5] + + (unsigned short)data[4] * 256); + /* scale up by 1.125 (36/32) approximate of 1.122 (320/285) */ + if (slave->id == COMPASS_ID_LSM303DLM) { + /* NOTE/IMPORTANT: + lsm303dlm compass axis definition doesn't + respect the right hand rule. We invert + the sign of the Z axis to fix that. */ + axis_fixed = (short)(-1 * axis_fixed * 36); + } else { + axis_fixed = (short)(axis_fixed * 36); + } + data[4] = axis_fixed >> 8; + data[5] = axis_fixed & 0xFF; + + axis_fixed = + (short)((unsigned short)data[3] + + (unsigned short)data[2] * 256); + axis_fixed = (short)(axis_fixed * 32); + data[2] = axis_fixed >> 8; + data[3] = axis_fixed & 0xFF; + + axis_fixed = + (short)((unsigned short)data[1] + + (unsigned short)data[0] * 256); + axis_fixed = (short)(axis_fixed * 32); + data[0] = axis_fixed >> 8; + data[1] = axis_fixed & 0xFF; + + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + LSM_REG_MODE, LSM_MODE_SINGLE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_SUCCESS; + } else { + /* trigger next measurement read */ + result = + inv_serial_single_write(mlsl_handle, pdata->address, + LSM_REG_MODE, LSM_MODE_SINGLE); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return INV_ERROR_COMPASS_DATA_NOT_READY; + } +} + +static struct ext_slave_descr lsm303dlx_m_descr = { + .init = NULL, + .exit = NULL, + .suspend = lsm303dlx_m_suspend, + .resume = lsm303dlx_m_resume, + .read = lsm303dlx_m_read, + .config = NULL, + .get_config = NULL, + .name = "lsm303dlx_m", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = ID_INVALID, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {10240, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *lsm303dlx_m_get_slave_descr(void) +{ + return &lsm303dlx_m_descr; +} + +/* -------------------------------------------------------------------------- */ +struct lsm303dlx_m_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static const struct i2c_device_id lsm303dlx_m_mod_id[] = { + { "lsm303dlh", COMPASS_ID_LSM303DLH }, + { "lsm303dlm", COMPASS_ID_LSM303DLM }, + {} +}; +MODULE_DEVICE_TABLE(i2c, lsm303dlx_m_mod_id); + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int lsm303dlx_m_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct lsm303dlx_m_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + lsm303dlx_m_descr.id = devid->driver_data; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + lsm303dlx_m_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int lsm303dlx_m_mod_remove(struct i2c_client *client) +{ + struct lsm303dlx_m_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + lsm303dlx_m_get_slave_descr); + + kfree(private_data); + return 0; +} + +static struct i2c_driver lsm303dlx_m_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = lsm303dlx_m_mod_probe, + .remove = lsm303dlx_m_mod_remove, + .id_table = lsm303dlx_m_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "lsm303dlx_m_mod", + }, + .address_list = normal_i2c, +}; + +static int __init lsm303dlx_m_mod_init(void) +{ + int res = i2c_add_driver(&lsm303dlx_m_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "lsm303dlx_m_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit lsm303dlx_m_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&lsm303dlx_m_mod_driver); +} + +module_init(lsm303dlx_m_mod_init); +module_exit(lsm303dlx_m_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate lsm303dlx_m sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("lsm303dlx_m_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/mmc314x.c b/drivers/misc/inv_mpu/compass/mmc314x.c new file mode 100644 index 000000000000..786fadcc3e48 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/mmc314x.c @@ -0,0 +1,313 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file mmc314x.c + * @brief Magnetometer setup and handling methods for the + * MEMSIC MMC314x compass. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ + +static int reset_int = 1000; +static int read_count = 1; +static char reset_mode; /* in Z-init section */ + +/* -------------------------------------------------------------------------- */ +#define MMC314X_REG_ST (0x00) +#define MMC314X_REG_X_MSB (0x01) + +#define MMC314X_CNTL_MODE_WAKE_UP (0x01) +#define MMC314X_CNTL_MODE_SET (0x02) +#define MMC314X_CNTL_MODE_RESET (0x04) + +/* -------------------------------------------------------------------------- */ + +static int mmc314x_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + return result; +} + +static int mmc314x_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + + int result; + result = + inv_serial_single_write(mlsl_handle, pdata->address, + MMC314X_REG_ST, MMC314X_CNTL_MODE_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(10); + result = + inv_serial_single_write(mlsl_handle, pdata->address, + MMC314X_REG_ST, MMC314X_CNTL_MODE_SET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(10); + read_count = 1; + return INV_SUCCESS; +} + +static int mmc314x_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result, ii; + short tmp[3]; + unsigned char tmpdata[6]; + + if (read_count > 1000) + read_count = 1; + + result = + inv_serial_read(mlsl_handle, pdata->address, MMC314X_REG_X_MSB, + 6, (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + for (ii = 0; ii < 6; ii++) + tmpdata[ii] = data[ii]; + + for (ii = 0; ii < 3; ii++) { + tmp[ii] = (short)((tmpdata[2 * ii] << 8) + tmpdata[2 * ii + 1]); + tmp[ii] = tmp[ii] - 4096; + tmp[ii] = tmp[ii] * 16; + } + + for (ii = 0; ii < 3; ii++) { + data[2 * ii] = (unsigned char)(tmp[ii] >> 8); + data[2 * ii + 1] = (unsigned char)(tmp[ii]); + } + + if (read_count % reset_int == 0) { + if (reset_mode) { + result = + inv_serial_single_write(mlsl_handle, + pdata->address, + MMC314X_REG_ST, + MMC314X_CNTL_MODE_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reset_mode = 0; + return INV_ERROR_COMPASS_DATA_NOT_READY; + } else { + result = + inv_serial_single_write(mlsl_handle, + pdata->address, + MMC314X_REG_ST, + MMC314X_CNTL_MODE_SET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reset_mode = 1; + read_count++; + return INV_ERROR_COMPASS_DATA_NOT_READY; + } + } + result = + inv_serial_single_write(mlsl_handle, pdata->address, + MMC314X_REG_ST, MMC314X_CNTL_MODE_WAKE_UP); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + read_count++; + + return INV_SUCCESS; +} + +static struct ext_slave_descr mmc314x_descr = { + .init = NULL, + .exit = NULL, + .suspend = mmc314x_suspend, + .resume = mmc314x_resume, + .read = mmc314x_read, + .config = NULL, + .get_config = NULL, + .name = "mmc314x", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_MMC314X, + .read_reg = 0x01, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {400, 0}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *mmc314x_get_slave_descr(void) +{ + return &mmc314x_descr; +} + +/* -------------------------------------------------------------------------- */ +struct mmc314x_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int mmc314x_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct mmc314x_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + mmc314x_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int mmc314x_mod_remove(struct i2c_client *client) +{ + struct mmc314x_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + mmc314x_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id mmc314x_mod_id[] = { + { "mmc314x", COMPASS_ID_MMC314X }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mmc314x_mod_id); + +static struct i2c_driver mmc314x_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = mmc314x_mod_probe, + .remove = mmc314x_mod_remove, + .id_table = mmc314x_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "mmc314x_mod", + }, + .address_list = normal_i2c, +}; + +static int __init mmc314x_mod_init(void) +{ + int res = i2c_add_driver(&mmc314x_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "mmc314x_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit mmc314x_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&mmc314x_mod_driver); +} + +module_init(mmc314x_mod_init); +module_exit(mmc314x_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate MMC314X sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("mmc314x_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/yas529-kernel.c b/drivers/misc/inv_mpu/compass/yas529-kernel.c new file mode 100644 index 000000000000..f53223fba641 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/yas529-kernel.c @@ -0,0 +1,611 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-acc" + +/*----- YAMAHA YAS529 Registers ------*/ +enum YAS_REG { + YAS_REG_CMDR = 0x00, /* 000 < 5 */ + YAS_REG_XOFFSETR = 0x20, /* 001 < 5 */ + YAS_REG_Y1OFFSETR = 0x40, /* 010 < 5 */ + YAS_REG_Y2OFFSETR = 0x60, /* 011 < 5 */ + YAS_REG_ICOILR = 0x80, /* 100 < 5 */ + YAS_REG_CAL = 0xA0, /* 101 < 5 */ + YAS_REG_CONFR = 0xC0, /* 110 < 5 */ + YAS_REG_DOUTR = 0xE0 /* 111 < 5 */ +}; + +/* -------------------------------------------------------------------------- */ + +static long a1; +static long a2; +static long a3; +static long a4; +static long a5; +static long a6; +static long a7; +static long a8; +static long a9; + +/* -------------------------------------------------------------------------- */ +static int yas529_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; +} + +static int yas529_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 = I2C_M_RD; + msgs[0].buf = data; + msgs[0].len = len; + + res = i2c_transfer(i2c_adap, msgs, 1); + if (res < 1) + return res; + else + return 0; +} + +static int yas529_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + return result; +} + +static int yas529_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + unsigned char dummyData[1] = { 0 }; + unsigned char dummyRegister = 0; + unsigned char rawData[6]; + unsigned char calData[9]; + + short xoffset, y1offset, y2offset; + short d2, d3, d4, d5, d6, d7, d8, d9; + + /* YAS529 Application Manual MS-3C - Section 4.4.5 */ + /* =============================================== */ + /* Step 1 - register initialization */ + /* zero initialization coil register - "100 00 000" */ + dummyData[0] = YAS_REG_ICOILR | 0x00; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* zero config register - "110 00 000" */ + dummyData[0] = YAS_REG_CONFR | 0x00; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Step 2 - initialization coil operation */ + dummyData[0] = YAS_REG_ICOILR | 0x11; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x01; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x12; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x02; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x13; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x03; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x14; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x04; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x15; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x05; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x16; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x06; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x17; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x07; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x10; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_ICOILR | 0x00; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Step 3 - rough offset measurement */ + /* Config register - Measurements results - "110 00 000" */ + dummyData[0] = YAS_REG_CONFR | 0x00; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Measurements command register - Rough offset measurement - + "000 00001" */ + dummyData[0] = YAS_REG_CMDR | 0x01; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(2); /* wait at least 1.5ms */ + + /* Measurement data read */ + result = + yas529_sensor_i2c_read(mlsl_handle, pdata->address, + dummyRegister, 6, rawData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + xoffset = + (short)((unsigned short)rawData[5] + + ((unsigned short)rawData[4] & 0x7) * 256) - 5; + if (xoffset < 0) + xoffset = 0; + y1offset = + (short)((unsigned short)rawData[3] + + ((unsigned short)rawData[2] & 0x7) * 256) - 5; + if (y1offset < 0) + y1offset = 0; + y2offset = + (short)((unsigned short)rawData[1] + + ((unsigned short)rawData[0] & 0x7) * 256) - 5; + if (y2offset < 0) + y2offset = 0; + + /* Step 4 - rough offset setting */ + /* Set rough offset register values */ + dummyData[0] = YAS_REG_XOFFSETR | xoffset; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_Y1OFFSETR | y1offset; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + dummyData[0] = YAS_REG_Y2OFFSETR | y2offset; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* CAL matrix read (first read is invalid) */ + /* Config register - CAL register read - "110 01 000" */ + dummyData[0] = YAS_REG_CONFR | 0x08; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* CAL data read */ + result = + yas529_sensor_i2c_read(mlsl_handle, pdata->address, + dummyRegister, 9, calData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Config register - CAL register read - "110 01 000" */ + dummyData[0] = YAS_REG_CONFR | 0x08; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* CAL data read */ + result = + yas529_sensor_i2c_read(mlsl_handle, pdata->address, + dummyRegister, 9, calData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Calculate coefficients of the sensitivity correction matrix */ + a1 = 100; + d2 = (calData[0] & 0xFC) >> 2; /* [71..66] 6bit */ + a2 = (short)(d2 - 32); + /* [65..62] 4bit */ + d3 = ((calData[0] & 0x03) << 2) | ((calData[1] & 0xC0) >> 6); + a3 = (short)(d3 - 8); + d4 = (calData[1] & 0x3F); /* [61..56] 6bit */ + a4 = (short)(d4 - 32); + d5 = (calData[2] & 0xFC) >> 2; /* [55..50] 6bit */ + a5 = (short)(d5 - 32) + 70; + /* [49..44] 6bit */ + d6 = ((calData[2] & 0x03) << 4) | ((calData[3] & 0xF0) >> 4); + a6 = (short)(d6 - 32); + /* [43..38] 6bit */ + d7 = ((calData[3] & 0x0F) << 2) | ((calData[4] & 0xC0) >> 6); + a7 = (short)(d7 - 32); + d8 = (calData[4] & 0x3F); /* [37..32] 6bit */ + a8 = (short)(d8 - 32); + d9 = (calData[5] & 0xFE) >> 1; /* [31..25] 7bit */ + a9 = (short)(d9 - 64) + 130; + + return result; +} + +static int yas529_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + unsigned char stat; + unsigned char rawData[6]; + unsigned char dummyData[1] = { 0 }; + unsigned char dummyRegister = 0; + int result = INV_SUCCESS; + short SX, SY1, SY2, SY, SZ; + short row1fixed, row2fixed, row3fixed; + + /* Config register - Measurements results - "110 00 000" */ + dummyData[0] = YAS_REG_CONFR | 0x00; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Measurements command register - Normal magnetic field measurement - + "000 00000" */ + dummyData[0] = YAS_REG_CMDR | 0x00; + result = + yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(10); + /* Measurement data read */ + result = + yas529_sensor_i2c_read(mlsl_handle, pdata->address, + dummyRegister, 6, (unsigned char *)&rawData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + stat = rawData[0] & 0x80; + if (stat == 0x00) { + /* Extract raw data */ + SX = (short)((unsigned short)rawData[5] + + ((unsigned short)rawData[4] & 0x7) * 256); + SY1 = + (short)((unsigned short)rawData[3] + + ((unsigned short)rawData[2] & 0x7) * 256); + SY2 = + (short)((unsigned short)rawData[1] + + ((unsigned short)rawData[0] & 0x7) * 256); + if ((SX <= 1) || (SY1 <= 1) || (SY2 <= 1)) + return INV_ERROR_COMPASS_DATA_UNDERFLOW; + if ((SX >= 1024) || (SY1 >= 1024) || (SY2 >= 1024)) + return INV_ERROR_COMPASS_DATA_OVERFLOW; + /* Convert to XYZ axis */ + SX = -1 * SX; + SY = SY2 - SY1; + SZ = SY1 + SY2; + + /* Apply sensitivity correction matrix */ + row1fixed = (short)((a1 * SX + a2 * SY + a3 * SZ) >> 7) * 41; + row2fixed = (short)((a4 * SX + a5 * SY + a6 * SZ) >> 7) * 41; + row3fixed = (short)((a7 * SX + a8 * SY + a9 * SZ) >> 7) * 41; + + data[0] = row1fixed >> 8; + data[1] = row1fixed & 0xFF; + data[2] = row2fixed >> 8; + data[3] = row2fixed & 0xFF; + data[4] = row3fixed >> 8; + data[5] = row3fixed & 0xFF; + + return INV_SUCCESS; + } else { + return INV_ERROR_COMPASS_DATA_NOT_READY; + } +} + +static struct ext_slave_descr yas529_descr = { + .init = NULL, + .exit = NULL, + .suspend = yas529_suspend, + .resume = yas529_resume, + .read = yas529_read, + .config = NULL, + .get_config = NULL, + .name = "yas529", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_YAS529, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {19660, 8000}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *yas529_get_slave_descr(void) +{ + return &yas529_descr; +} + +/* -------------------------------------------------------------------------- */ +struct yas529_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int yas529_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct yas529_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + yas529_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int yas529_mod_remove(struct i2c_client *client) +{ + struct yas529_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + yas529_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id yas529_mod_id[] = { + { "yas529", COMPASS_ID_YAS529 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, yas529_mod_id); + +static struct i2c_driver yas529_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = yas529_mod_probe, + .remove = yas529_mod_remove, + .id_table = yas529_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "yas529_mod", + }, + .address_list = normal_i2c, +}; + +static int __init yas529_mod_init(void) +{ + int res = i2c_add_driver(&yas529_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "yas529_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit yas529_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&yas529_mod_driver); +} + +module_init(yas529_mod_init); +module_exit(yas529_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate YAS529 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("yas529_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/yas530.c b/drivers/misc/inv_mpu/compass/yas530.c new file mode 100644 index 000000000000..fdca05ba8e5c --- /dev/null +++ b/drivers/misc/inv_mpu/compass/yas530.c @@ -0,0 +1,580 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file yas530.c + * @brief Magnetometer setup and handling methods for Yamaha YAS530 + * compass when used in a user-space solution (no kernel driver). + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mpu-dev.h" + +#include "log.h" +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" + +/* -------------------------------------------------------------------------- */ +#define YAS530_REGADDR_DEVICE_ID (0x80) +#define YAS530_REGADDR_ACTUATE_INIT_COIL (0x81) +#define YAS530_REGADDR_MEASURE_COMMAND (0x82) +#define YAS530_REGADDR_CONFIG (0x83) +#define YAS530_REGADDR_MEASURE_INTERVAL (0x84) +#define YAS530_REGADDR_OFFSET_X (0x85) +#define YAS530_REGADDR_OFFSET_Y1 (0x86) +#define YAS530_REGADDR_OFFSET_Y2 (0x87) +#define YAS530_REGADDR_TEST1 (0x88) +#define YAS530_REGADDR_TEST2 (0x89) +#define YAS530_REGADDR_CAL (0x90) +#define YAS530_REGADDR_MEASURE_DATA (0xb0) + +/* -------------------------------------------------------------------------- */ +static int Cx, Cy1, Cy2; +static int /*a1, */ a2, a3, a4, a5, a6, a7, a8, a9; +static int k; + +static unsigned char dx, dy1, dy2; +static unsigned char d2, d3, d4, d5, d6, d7, d8, d9, d0; +static unsigned char dck; + +/* -------------------------------------------------------------------------- */ + +static int set_hardware_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + char offset_x, char offset_y1, char offset_y2) +{ + char data; + int result = INV_SUCCESS; + + data = offset_x & 0x3f; + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_OFFSET_X, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + data = offset_y1 & 0x3f; + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_OFFSET_Y1, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + data = offset_y2 & 0x3f; + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_OFFSET_Y2, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int set_measure_command(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + int ldtc, int fors, int dlymes) +{ + int result = INV_SUCCESS; + + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_MEASURE_COMMAND, 0x01); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int measure_normal(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + int *busy, unsigned short *t, + unsigned short *x, unsigned short *y1, + unsigned short *y2) +{ + unsigned char data[8]; + unsigned short b, to, xo, y1o, y2o; + int result; + ktime_t sleeptime; + result = set_measure_command(mlsl_handle, slave, pdata, 0, 0, 0); + sleeptime = ktime_set(0, 2 * NSEC_PER_MSEC); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_hrtimeout(&sleeptime, HRTIMER_MODE_REL); + + result = inv_serial_read(mlsl_handle, pdata->address, + YAS530_REGADDR_MEASURE_DATA, 8, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + b = (data[0] >> 7) & 0x01; + to = ((data[0] << 2) & 0x1fc) | ((data[1] >> 6) & 0x03); + xo = ((data[2] << 5) & 0xfe0) | ((data[3] >> 3) & 0x1f); + y1o = ((data[4] << 5) & 0xfe0) | ((data[5] >> 3) & 0x1f); + y2o = ((data[6] << 5) & 0xfe0) | ((data[7] >> 3) & 0x1f); + + *busy = b; + *t = to; + *x = xo; + *y1 = y1o; + *y2 = y2o; + + return result; +} + +static int check_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + char offset_x, char offset_y1, char offset_y2, + int *flag_x, int *flag_y1, int *flag_y2) +{ + int result; + int busy; + short t, x, y1, y2; + + result = set_hardware_offset(mlsl_handle, slave, pdata, + offset_x, offset_y1, offset_y2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = measure_normal(mlsl_handle, slave, pdata, + &busy, &t, &x, &y1, &y2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + *flag_x = 0; + *flag_y1 = 0; + *flag_y2 = 0; + + if (x > 2048) + *flag_x = 1; + if (y1 > 2048) + *flag_y1 = 1; + if (y2 > 2048) + *flag_y2 = 1; + if (x < 2048) + *flag_x = -1; + if (y1 < 2048) + *flag_y1 = -1; + if (y2 < 2048) + *flag_y2 = -1; + + return result; +} + +static int measure_and_set_offset(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + char *offset) +{ + int i; + int result = INV_SUCCESS; + char offset_x = 0, offset_y1 = 0, offset_y2 = 0; + int flag_x = 0, flag_y1 = 0, flag_y2 = 0; + static const int correct[5] = { 16, 8, 4, 2, 1 }; + + for (i = 0; i < 5; i++) { + result = check_offset(mlsl_handle, slave, pdata, + offset_x, offset_y1, offset_y2, + &flag_x, &flag_y1, &flag_y2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (flag_x) + offset_x += flag_x * correct[i]; + if (flag_y1) + offset_y1 += flag_y1 * correct[i]; + if (flag_y2) + offset_y2 += flag_y2 * correct[i]; + } + + result = set_hardware_offset(mlsl_handle, slave, pdata, + offset_x, offset_y1, offset_y2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + offset[0] = offset_x; + offset[1] = offset_y1; + offset[2] = offset_y2; + + return result; +} + +static void coordinate_conversion(short x, short y1, short y2, short t, + int32_t *xo, int32_t *yo, int32_t *zo) +{ + int32_t sx, sy1, sy2, sy, sz; + int32_t hx, hy, hz; + + sx = x - (Cx * t) / 100; + sy1 = y1 - (Cy1 * t) / 100; + sy2 = y2 - (Cy2 * t) / 100; + + sy = sy1 - sy2; + sz = -sy1 - sy2; + + hx = k * ((100 * sx + a2 * sy + a3 * sz) / 10); + hy = k * ((a4 * sx + a5 * sy + a6 * sz) / 10); + hz = k * ((a7 * sx + a8 * sy + a9 * sz) / 10); + + *xo = hx; + *yo = hy; + *zo = hz; +} + +static int yas530_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + return result; +} + +static int yas530_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + + unsigned char dummyData = 0x00; + char offset[3] = { 0, 0, 0 }; + unsigned char data[16]; + unsigned char read_reg[1]; + + /* =============================================== */ + + /* Step 1 - Test register initialization */ + dummyData = 0x00; + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_TEST1, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = + inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_TEST2, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Device ID read */ + result = inv_serial_read(mlsl_handle, pdata->address, + YAS530_REGADDR_DEVICE_ID, 1, read_reg); + + /*Step 2 Read the CAL register */ + /* CAL data read */ + result = inv_serial_read(mlsl_handle, pdata->address, + YAS530_REGADDR_CAL, 16, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* CAL data Second Read */ + result = inv_serial_read(mlsl_handle, pdata->address, + YAS530_REGADDR_CAL, 16, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /*Cal data */ + dx = data[0]; + dy1 = data[1]; + dy2 = data[2]; + d2 = (data[3] >> 2) & 0x03f; + d3 = ((data[3] << 2) & 0x0c) | ((data[4] >> 6) & 0x03); + d4 = data[4] & 0x3f; + d5 = (data[5] >> 2) & 0x3f; + d6 = ((data[5] << 4) & 0x30) | ((data[6] >> 4) & 0x0f); + d7 = ((data[6] << 3) & 0x78) | ((data[7] >> 5) & 0x07); + d8 = ((data[7] << 1) & 0x3e) | ((data[8] >> 7) & 0x01); + d9 = ((data[8] << 1) & 0xfe) | ((data[9] >> 7) & 0x01); + d0 = (data[9] >> 2) & 0x1f; + dck = ((data[9] << 1) & 0x06) | ((data[10] >> 7) & 0x01); + + /*Correction Data */ + Cx = (int)dx * 6 - 768; + Cy1 = (int)dy1 * 6 - 768; + Cy2 = (int)dy2 * 6 - 768; + a2 = (int)d2 - 32; + a3 = (int)d3 - 8; + a4 = (int)d4 - 32; + a5 = (int)d5 + 38; + a6 = (int)d6 - 32; + a7 = (int)d7 - 64; + a8 = (int)d8 - 32; + a9 = (int)d9; + k = (int)d0 + 10; + + /*Obtain the [49:47] bits */ + dck &= 0x07; + + /*Step 3 : Storing the CONFIG with the CLK value */ + dummyData = 0x00 | (dck << 2); + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_CONFIG, dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /*Step 4 : Set Acquisition Interval Register */ + dummyData = 0x00; + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_MEASURE_INTERVAL, + dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /*Step 5 : Reset Coil */ + dummyData = 0x00; + result = inv_serial_single_write(mlsl_handle, pdata->address, + YAS530_REGADDR_ACTUATE_INIT_COIL, + dummyData); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Offset Measurement and Set */ + result = measure_and_set_offset(mlsl_handle, slave, pdata, offset); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + +static int yas530_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result = INV_SUCCESS; + + int busy; + short t, x, y1, y2; + int32_t xyz[3]; + short rawfixed[3]; + + result = measure_normal(mlsl_handle, slave, pdata, + &busy, &t, &x, &y1, &y2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + coordinate_conversion(x, y1, y2, t, &xyz[0], &xyz[1], &xyz[2]); + + rawfixed[0] = (short)(xyz[0] / 100); + rawfixed[1] = (short)(xyz[1] / 100); + rawfixed[2] = (short)(xyz[2] / 100); + + data[0] = rawfixed[0] >> 8; + data[1] = rawfixed[0] & 0xFF; + data[2] = rawfixed[1] >> 8; + data[3] = rawfixed[1] & 0xFF; + data[4] = rawfixed[2] >> 8; + data[5] = rawfixed[2] & 0xFF; + + if (busy) + return INV_ERROR_COMPASS_DATA_NOT_READY; + return result; +} + +static struct ext_slave_descr yas530_descr = { + .init = NULL, + .exit = NULL, + .suspend = yas530_suspend, + .resume = yas530_resume, + .read = yas530_read, + .config = NULL, + .get_config = NULL, + .name = "yas530", + .type = EXT_SLAVE_TYPE_COMPASS, + .id = COMPASS_ID_YAS530, + .read_reg = 0x06, + .read_len = 6, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {3276, 8001}, + .trigger = NULL, +}; + +static +struct ext_slave_descr *yas530_get_slave_descr(void) +{ + return &yas530_descr; +} + +/* -------------------------------------------------------------------------- */ +struct yas530_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int yas530_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct yas530_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + yas530_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int yas530_mod_remove(struct i2c_client *client) +{ + struct yas530_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + yas530_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id yas530_mod_id[] = { + { "yas530", COMPASS_ID_YAS530 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, yas530_mod_id); + +static struct i2c_driver yas530_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = yas530_mod_probe, + .remove = yas530_mod_remove, + .id_table = yas530_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "yas530_mod", + }, + .address_list = normal_i2c, +}; + +static int __init yas530_mod_init(void) +{ + int res = i2c_add_driver(&yas530_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "yas530_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit yas530_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&yas530_mod_driver); +} + +module_init(yas530_mod_init); +module_exit(yas530_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate YAS530 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("yas530_mod"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/log.h b/drivers/misc/inv_mpu/log.h new file mode 100644 index 000000000000..5630602e3efa --- /dev/null +++ b/drivers/misc/inv_mpu/log.h @@ -0,0 +1,287 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/* + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (C) 2005 The Android Open Source Project + * + * 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 "mltypes.h" +#include + + +#include + + +/* --------------------------------------------------------------------- */ + +/* + * 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. + */ +#ifndef MPL_LOG_NDEBUG +#ifdef NDEBUG +#define MPL_LOG_NDEBUG 1 +#else +#define MPL_LOG_NDEBUG 0 +#endif +#endif + +#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 + + + +/* + * 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 +#define MPL_LOG_TAG +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Simplified macro to send a verbose log message using the current MPL_LOG_TAG. + */ +#ifndef MPL_LOGV +#if MPL_LOG_NDEBUG +#define MPL_LOGV(fmt, ...) \ + do { \ + if (0) \ + MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__);\ + } while (0) +#else +#define MPL_LOGV(fmt, ...) MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__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, fmt, ...) \ + do { if (0) MPL_LOG(fmt, ##__VA_ARGS__); } while (0) +#else +#define MPL_LOGV_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__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(fmt, ...) MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGD_IF +#define MPL_LOGD_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__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(fmt, ...) pr_info(KERN_INFO MPL_LOG_TAG fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGI_IF +#define MPL_LOGI_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__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(fmt, ...) printk(KERN_WARNING MPL_LOG_TAG fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGW_IF +#define MPL_LOGW_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__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(fmt, ...) printk(KERN_ERR MPL_LOG_TAG fmt, ##__VA_ARGS__) +#endif + +#ifndef MPL_LOGE_IF +#define MPL_LOGE_IF(cond, fmt, ...) \ + ((CONDITION(cond)) \ + ? MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__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, fmt, ...) \ + ((CONDITION(cond)) \ + ? ((void)android_printAssert(#cond, MPL_LOG_TAG, \ + fmt, ##__VA_ARGS__)) \ + : (void)0) + +#define MPL_LOG_ALWAYS_FATAL(fmt, ...) \ + (((void)android_printAssert(NULL, MPL_LOG_TAG, fmt, ##__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, fmt, ...) \ + do { \ + if (0) \ + MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__); \ + } while (0) +#define MPL_LOG_FATAL(fmt, ...) \ + do { \ + if (0) \ + MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) \ + } while (0) +#else +#define MPL_LOG_FATAL_IF(cond, fmt, ...) \ + MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__) +#define MPL_LOG_FATAL(fmt, ...) \ + MPL_LOG_ALWAYS_FATAL(fmt, ##__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, fmt, ...) \ + MPL_LOG_FATAL_IF(!(cond), fmt, ##__VA_ARGS__) + +/* --------------------------------------------------------------------- */ + +/* + * 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, fmt, ...) \ + MPL_LOG_PRI(priority, tag, fmt, ##__VA_ARGS__) +#endif + +/* + * Log macro that allows you to specify a number for the priority. + */ +#ifndef MPL_LOG_PRI +#define MPL_LOG_PRI(priority, tag, fmt, ...) \ + pr_debug(MPL_##priority tag fmt, ##__VA_ARGS__) +#endif + +/* + * Log macro that allows you to pass in a varargs ("args" is a va_list). + */ +#ifndef MPL_LOG_PRI_VA +/* not allowed in the Kernel because there is no dev_dbg that takes a va_list */ +#endif + +/* --------------------------------------------------------------------- */ + +/* + * =========================================================================== + * + * The stuff in the rest of this file should not be used directly. + */ + +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); + +static inline void __print_result_location(int result, + const char *file, + const char *func, int line) +{ + MPL_LOGE("%s|%s|%d returning %d\n", file, func, line, result); +} + +#define LOG_RESULT_LOCATION(condition) \ + do { \ + __print_result_location((int)(condition), __FILE__, \ + __func__, __LINE__); \ + } while (0) + + +#endif /* _LIBS_CUTILS_MPL_LOG_H */ diff --git a/drivers/misc/inv_mpu/mldl_cfg.c b/drivers/misc/inv_mpu/mldl_cfg.c new file mode 100755 index 000000000000..ccacc8ec0b56 --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_cfg.c @@ -0,0 +1,1765 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_cfg.c + * @brief The Motion Library Driver Layer. + */ + +/* -------------------------------------------------------------------------- */ +#include +#include + +#include + +#include "mldl_cfg.h" +#include +#include "mpu3050.h" + +#include "mlsl.h" +#include "mldl_print_cfg.h" +#include "log.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "mldl_cfg:" + +/* -------------------------------------------------------------------------- */ + +#define SLEEP 1 +#define WAKE_UP 0 +#define RESET 1 +#define STANDBY 1 + +/* -------------------------------------------------------------------------- */ + +/** + * @brief Stop the DMP running + * + * @return INV_SUCCESS or non-zero error code + */ +static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + unsigned char user_ctrl_reg; + int result; + + if (mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED) + return INV_SUCCESS; + + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + user_ctrl_reg = (user_ctrl_reg & (~BIT_FIFO_EN)) | BIT_FIFO_RST; + user_ctrl_reg = (user_ctrl_reg & (~BIT_DMP_EN)) | BIT_DMP_RST; + + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status |= MPU_DMP_IS_SUSPENDED; + + return result; +} + +/** + * @brief Starts the DMP running + * + * @return INV_SUCCESS or non-zero error code + */ +static int dmp_start(struct mldl_cfg *mldl_cfg, void *mlsl_handle) +{ + unsigned char user_ctrl_reg; + int result; + + if ((!(mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED) && + mldl_cfg->mpu_gyro_cfg->dmp_enable) + || + ((mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED) && + !mldl_cfg->mpu_gyro_cfg->dmp_enable)) + return INV_SUCCESS; + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, + ((user_ctrl_reg & (~BIT_FIFO_EN)) + | BIT_FIFO_RST)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + user_ctrl_reg |= BIT_DMP_EN; + + if (mldl_cfg->mpu_gyro_cfg->fifo_enable) + user_ctrl_reg |= BIT_FIFO_EN; + else + user_ctrl_reg &= ~BIT_FIFO_EN; + + user_ctrl_reg |= BIT_DMP_RST; + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, user_ctrl_reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~MPU_DMP_IS_SUSPENDED; + + return result; +} + + + +static int mpu3050_set_i2c_bypass(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, unsigned char enable) +{ + unsigned char b; + int result; + unsigned char status = mldl_cfg->inv_mpu_state->status; + + if ((status & MPU_GYRO_IS_BYPASSED && enable) || + (!(status & MPU_GYRO_IS_BYPASSED) && !enable)) + return INV_SUCCESS; + + /*---- get current 'USER_CTRL' into b ----*/ + result = inv_serial_read( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, &b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + b &= ~BIT_AUX_IF_EN; + + if (!enable) { + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, + (b | BIT_AUX_IF_EN)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } else { + /* Coming out of I2C is tricky due to several erratta. Do not + * modify this algorithm + */ + /* + * 1) wait for the right time and send the command to change + * the aux i2c slave address to an invalid address that will + * get nack'ed + * + * 0x00 is broadcast. 0x7F is unlikely to be used by any aux. + */ + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_AUX_SLV_ADDR, 0x7F); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* + * 2) wait enough time for a nack to occur, then go into + * bypass mode: + */ + msleep(2); + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, (b)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* + * 3) wait for up to one MPU cycle then restore the slave + * address + */ + msleep(inv_mpu_get_sampling_period_us(mldl_cfg->mpu_gyro_cfg) + / 1000); + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_AUX_SLV_ADDR, + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL] + ->address); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* + * 4) reset the ime interface + */ + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, + (b | BIT_AUX_IF_RST)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(2); + } + if (enable) + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED; + else + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED; + + return result; +} + + +/** + * @brief enables/disables the I2C bypass to an external device + * connected to MPU's secondary I2C bus. + * @param enable + * Non-zero to enable pass through. + * @return INV_SUCCESS if successful, a non-zero error code otherwise. + */ +static int mpu_set_i2c_bypass(struct mldl_cfg *mldl_cfg, void *mlsl_handle, + unsigned char enable) +{ + return mpu3050_set_i2c_bypass(mldl_cfg, mlsl_handle, enable); +} + + +#define NUM_OF_PROD_REVS (ARRAY_SIZE(prod_rev_map)) + +/* NOTE : when not indicated, product revision + is considered an 'npp'; non production part */ + +struct prod_rev_map_t { + unsigned char silicon_rev; + unsigned short gyro_trim; +}; + +#define OLDEST_PROD_REV_SUPPORTED 11 +static struct prod_rev_map_t prod_rev_map[] = { + {0, 0}, + {MPU_SILICON_REV_A4, 131}, /* 1 A? OBSOLETED */ + {MPU_SILICON_REV_A4, 131}, /* 2 | */ + {MPU_SILICON_REV_A4, 131}, /* 3 | */ + {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 V */ + {MPU_SILICON_REV_B1, 131}, /* 11 B1 */ + {MPU_SILICON_REV_B1, 131}, /* 12 | */ + {MPU_SILICON_REV_B1, 131}, /* 13 | */ + {MPU_SILICON_REV_B1, 131}, /* 14 V */ + {MPU_SILICON_REV_B4, 131}, /* 15 B4 */ + {MPU_SILICON_REV_B4, 131}, /* 16 | */ + {MPU_SILICON_REV_B4, 131}, /* 17 | */ + {MPU_SILICON_REV_B4, 131}, /* 18 | */ + {MPU_SILICON_REV_B4, 115}, /* 19 | */ + {MPU_SILICON_REV_B4, 115}, /* 20 V */ + {MPU_SILICON_REV_B6, 131}, /* 21 B6 (B6/A9) */ + {MPU_SILICON_REV_B4, 115}, /* 22 B4 (B7/A10) */ + {MPU_SILICON_REV_B6, 0}, /* 23 B6 */ + {MPU_SILICON_REV_B6, 0}, /* 24 | */ + {MPU_SILICON_REV_B6, 0}, /* 25 | */ + {MPU_SILICON_REV_B6, 131}, /* 26 V (B6/A11) */ +}; + +/** + * @internal + * @brief Get the silicon revision ID from OTP for MPU3050. + * The silicon revision number is in read from OTP bank 0, + * ADDR6[7:2]. The corresponding ID is retrieved by lookup + * in a map. + * + * @param mldl_cfg + * a pointer to the mldl config data structure. + * @param mlsl_handle + * an file handle to the serial communication device the + * device is connected to. + * + * @return 0 on success, a non-zero error code otherwise. + */ +static int inv_get_silicon_rev_mpu3050( + struct mldl_cfg *mldl_cfg, void *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 mem_addr = ((bank << 8) | 0x06); + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + + result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PRODUCT_ID, 1, + &mpu_chip_info->product_id); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_serial_read_mem( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + mem_addr, 1, &index); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + index >>= 2; + + /* clean the prefetch and cfg user bank bits */ + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_BANK_SEL, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (index < OLDEST_PROD_REV_SUPPORTED || index >= NUM_OF_PROD_REVS) { + mpu_chip_info->silicon_revision = 0; + mpu_chip_info->gyro_sens_trim = 0; + MPL_LOGE("Unsupported Product Revision Detected : %d\n", index); + return INV_ERROR_INVALID_MODULE; + } + + mpu_chip_info->product_revision = index; + mpu_chip_info->silicon_revision = prod_rev_map[index].silicon_rev; + mpu_chip_info->gyro_sens_trim = prod_rev_map[index].gyro_trim; + if (mpu_chip_info->gyro_sens_trim == 0) { + MPL_LOGE("gyro sensitivity trim is 0" + " - unsupported non production part.\n"); + return INV_ERROR_INVALID_MODULE; + } + + return result; +} +#define inv_get_silicon_rev inv_get_silicon_rev_mpu3050 + + +/** + * @brief Enable / Disable the use MPU's secondary I2C interface level + * shifters. + * When enabled the secondary I2C interface to which the external + * device is connected runs at VDD voltage (main supply). + * When disabled the 2nd interface runs at VDDIO voltage. + * See the device specification for more details. + * + * @note using this API may produce unpredictable results, depending on how + * the MPU and slave device are setup on the target platform. + * Use of this API should entirely be restricted to system + * integrators. Once the correct value is found, there should be no + * need to change the level shifter at runtime. + * + * @pre Must be called after inv_serial_start(). + * @note Typically called before inv_dmp_open(). + * + * @param[in] enable: + * 0 to run at VDDIO (default), + * 1 to run at VDD. + * + * @return INV_SUCCESS if successfull, a non-zero error code otherwise. + */ +static int inv_mpu_set_level_shifter_bit(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, unsigned char enable) +{ + int result; + unsigned char regval; + + unsigned char reg; + unsigned char mask; + + if (0 == mldl_cfg->mpu_chip_info->silicon_revision) + return INV_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 ((mldl_cfg->mpu_chip_info->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 = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + reg, 1, ®val); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (enable) + regval |= mask; + else + regval &= ~mask; + + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, reg, regval); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + return result; + return INV_SUCCESS; +} + + +/** + * @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 being applied. + * @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 INV_SUCCESS if successfull; a non-zero error code otherwise. + */ +static int mpu3050_pwr_mgmt(struct mldl_cfg *mldl_cfg, + void *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 = + inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, 1, &b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* If we are awake, we need to put it in bypass before resetting */ + if ((!(b & BIT_SLEEP)) && reset) + result = mpu_set_i2c_bypass(mldl_cfg, mlsl_handle, 1); + + /* Reset if requested */ + if (reset) { + MPL_LOGV("Reset MPU3050\n"); + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, b | BIT_H_RESET); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + msleep(5); + /* Some chips are awake after reset and some are asleep, + * check the status */ + result = inv_serial_read( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, 1, &b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + /* Update the suspended state just in case we return early */ + if (b & BIT_SLEEP) { + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_SUSPENDED; + mldl_cfg->inv_mpu_state->status |= MPU_DEVICE_IS_SUSPENDED; + } else { + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_SUSPENDED; + mldl_cfg->inv_mpu_state->status &= ~MPU_DEVICE_IS_SUSPENDED; + } + + /* if power status match requested, nothing else's left to do */ + if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == + (((sleep != 0) * BIT_SLEEP) | + ((disable_gx != 0) * BIT_STBY_XG) | + ((disable_gy != 0) * BIT_STBY_YG) | + ((disable_gz != 0) * BIT_STBY_ZG))) { + return INV_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) is (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) + && ((!sleep) && disable_gx && disable_gy && disable_gz)) { + result = mpu3050_pwr_mgmt(mldl_cfg, 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 != 0) * BIT_SLEEP)) { + if (sleep) { + result = mpu_set_i2c_bypass(mldl_cfg, mlsl_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + b |= BIT_SLEEP; + result = + inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status |= + MPU_GYRO_IS_SUSPENDED; + mldl_cfg->inv_mpu_state->status |= + MPU_DEVICE_IS_SUSPENDED; + } else { + b &= ~BIT_SLEEP; + result = + inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= + ~MPU_GYRO_IS_SUSPENDED; + mldl_cfg->inv_mpu_state->status &= + ~MPU_DEVICE_IS_SUSPENDED; + msleep(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 != 0) * BIT_STBY_XG)) { + b ^= BIT_STBY_XG; + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + if ((b & BIT_STBY_YG) != ((disable_gy != 0) * BIT_STBY_YG)) { + b ^= BIT_STBY_YG; + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + if ((b & BIT_STBY_ZG) != ((disable_gz != 0) * BIT_STBY_ZG)) { + b ^= BIT_STBY_ZG; + result = inv_serial_single_write( + mlsl_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, b); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + return INV_SUCCESS; +} + + +/** + * @brief sets the clock source for the gyros. + * @param mldl_cfg + * a pointer to the struct mldl_cfg data structure. + * @param gyro_handle + * an handle to the serial device the gyro is assigned to. + * @return ML_SUCCESS if successful, a non-zero error code otherwise. + */ +static int mpu_set_clock_source(void *gyro_handle, struct mldl_cfg *mldl_cfg) +{ + int result; + unsigned char cur_clk_src; + unsigned char reg; + + /* clock source selection */ + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + cur_clk_src = reg & BITS_CLKSEL; + reg &= ~BITS_CLKSEL; + + + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_PWR_MGM, mldl_cfg->mpu_gyro_cfg->clk_src | reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* TODO : workarounds to be determined and implemented */ + + return result; +} + +/** + * Configures the MPU I2C Master + * + * @mldl_cfg Handle to the configuration data + * @gyro_handle handle to the gyro communictation interface + * @slave Can be Null if turning off the slave + * @slave_pdata Can be null if turning off the slave + * @slave_id enum ext_slave_type to determine which index to use + * + * + * This fucntion configures the slaves by: + * 1) Setting up the read + * a) Read Register + * b) Read Length + * 2) Set up the data trigger (MPU6050 only) + * a) Set trigger write register + * b) Set Trigger write value + * 3) Set up the divider (MPU6050 only) + * 4) Set the slave bypass mode depending on slave + * + * returns INV_SUCCESS or non-zero error code + */ +static int mpu_set_slave_mpu3050(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *slave_pdata, + int slave_id) +{ + int result; + unsigned char reg; + unsigned char slave_reg; + unsigned char slave_len; + unsigned char slave_endian; + unsigned char slave_address; + + if (slave_id != EXT_SLAVE_TYPE_ACCEL) + return 0; + + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true); + + if (NULL == slave || NULL == slave_pdata) { + slave_reg = 0; + slave_len = 0; + slave_endian = 0; + slave_address = 0; + mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 0; + } else { + slave_reg = slave->read_reg; + slave_len = slave->read_len; + slave_endian = slave->endian; + slave_address = slave_pdata->address; + mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 1; + } + + /* Address */ + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_AUX_SLV_ADDR, slave_address); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + /* Register */ + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_ACCEL_BURST_ADDR, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg = ((reg & 0x80) | slave_reg); + result = inv_serial_single_write(gyro_handle, + mldl_cfg->mpu_chip_info->addr, + MPUREG_ACCEL_BURST_ADDR, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Length */ + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + reg = (reg & ~BIT_AUX_RD_LENG); + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_USER_CTRL, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + return result; +} + + +static int mpu_set_slave(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *slave_pdata, + int slave_id) +{ + return mpu_set_slave_mpu3050(mldl_cfg, gyro_handle, slave, + slave_pdata, slave_id); +} +/** + * Check to see if the gyro was reset by testing a couple of registers known + * to change on reset. + * + * @mldl_cfg mldl configuration structure + * @gyro_handle handle used to communicate with the gyro + * + * @return INV_SUCCESS or non-zero error code + */ +static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + int result = INV_SUCCESS; + unsigned char reg; + + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DMP_CFG_2, 1, ®); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (mldl_cfg->mpu_gyro_cfg->dmp_cfg2 != reg) + return true; + + if (0 != mldl_cfg->mpu_gyro_cfg->dmp_cfg1) + return false; + + /* Inconclusive assume it was reset */ + return true; +} + + +int inv_mpu_set_firmware(struct mldl_cfg *mldl_cfg, void *mlsl_handle, + const unsigned char *data, int size) +{ + int bank, offset, write_size; + int result; + unsigned char read[MPU_MEM_BANK_SIZE]; + + if (mldl_cfg->inv_mpu_state->status & MPU_DEVICE_IS_SUSPENDED) { +#if INV_CACHE_DMP == 1 + memcpy(mldl_cfg->mpu_ram->ram, data, size); + return INV_SUCCESS; +#else + LOG_RESULT_LOCATION(INV_ERROR_MEMORY_SET); + return INV_ERROR_MEMORY_SET; +#endif + } + + if (!(mldl_cfg->inv_mpu_state->status & MPU_DMP_IS_SUSPENDED)) { + LOG_RESULT_LOCATION(INV_ERROR_MEMORY_SET); + return INV_ERROR_MEMORY_SET; + } + /* Write and verify memory */ + for (bank = 0; size > 0; bank++, + size -= write_size, + data += write_size) { + if (size > MPU_MEM_BANK_SIZE) + write_size = MPU_MEM_BANK_SIZE; + else + write_size = size; + + result = inv_serial_write_mem(mlsl_handle, + mldl_cfg->mpu_chip_info->addr, + ((bank << 8) | 0x00), + write_size, + data); + if (result) { + LOG_RESULT_LOCATION(result); + MPL_LOGE("Write mem error in bank %d\n", bank); + return result; + } + result = inv_serial_read_mem(mlsl_handle, + mldl_cfg->mpu_chip_info->addr, + ((bank << 8) | 0x00), + write_size, + read); + if (result) { + LOG_RESULT_LOCATION(result); + MPL_LOGE("Read mem error in bank %d\n", bank); + return result; + } + +#define ML_SKIP_CHECK 20 + for (offset = 0; offset < write_size; offset++) { + /* skip the register memory locations */ + if (bank == 0 && offset < ML_SKIP_CHECK) + continue; + if (data[offset] != read[offset]) { + result = INV_ERROR_SERIAL_WRITE; + break; + } + } + if (result != INV_SUCCESS) { + LOG_RESULT_LOCATION(result); + MPL_LOGE("Read data mismatch at bank %d, offset %d\n", + bank, offset); + return result; + } + } + return INV_SUCCESS; +} + +static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle, + unsigned long sensors) +{ + int result; + int ii; + unsigned char reg; + unsigned char regs[7]; + + /* Wake up the part */ + result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, false, false, + !(sensors & INV_X_GYRO), + !(sensors & INV_Y_GYRO), + !(sensors & INV_Z_GYRO)); + + if (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG) && + !mpu_was_reset(mldl_cfg, gyro_handle)) { + return INV_SUCCESS; + } + + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_INT_CFG, + (mldl_cfg->mpu_gyro_cfg->int_config | + mldl_cfg->pdata->int_config)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_SMPLRT_DIV, mldl_cfg->mpu_gyro_cfg->divider); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = mpu_set_clock_source(gyro_handle, mldl_cfg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + reg = DLPF_FS_SYNC_VALUE(mldl_cfg->mpu_gyro_cfg->ext_sync, + mldl_cfg->mpu_gyro_cfg->full_scale, + mldl_cfg->mpu_gyro_cfg->lpf); + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DLPF_FS_SYNC, reg); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DMP_CFG_1, mldl_cfg->mpu_gyro_cfg->dmp_cfg1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_DMP_CFG_2, mldl_cfg->mpu_gyro_cfg->dmp_cfg2); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Write and verify memory */ +#if INV_CACHE_DMP != 0 + inv_mpu_set_firmware(mldl_cfg, gyro_handle, + mldl_cfg->mpu_ram->ram, mldl_cfg->mpu_ram->length); +#endif + + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_XG_OFFS_TC, mldl_cfg->mpu_offsets->tc[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_YG_OFFS_TC, mldl_cfg->mpu_offsets->tc[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_single_write( + gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_ZG_OFFS_TC, mldl_cfg->mpu_offsets->tc[2]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + regs[0] = MPUREG_X_OFFS_USRH; + for (ii = 0; ii < ARRAY_SIZE(mldl_cfg->mpu_offsets->gyro); ii++) { + regs[1 + ii * 2] = + (unsigned char)(mldl_cfg->mpu_offsets->gyro[ii] >> 8) + & 0xff; + regs[1 + ii * 2 + 1] = + (unsigned char)(mldl_cfg->mpu_offsets->gyro[ii] & 0xff); + } + result = inv_serial_write(gyro_handle, mldl_cfg->mpu_chip_info->addr, + 7, regs); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Configure slaves */ + result = inv_mpu_set_level_shifter_bit(mldl_cfg, gyro_handle, + mldl_cfg->pdata->level_shifter); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_NEEDS_CONFIG; + + return result; +} + +int gyro_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data) +{ + struct mpu_gyro_cfg *mpu_gyro_cfg = mldl_cfg->mpu_gyro_cfg; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets; + int ii; + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_INT_CONFIG: + mpu_gyro_cfg->int_config = *((__u8 *)data->data); + break; + case MPU_SLAVE_EXT_SYNC: + mpu_gyro_cfg->ext_sync = *((__u8 *)data->data); + break; + case MPU_SLAVE_FULL_SCALE: + mpu_gyro_cfg->full_scale = *((__u8 *)data->data); + break; + case MPU_SLAVE_LPF: + mpu_gyro_cfg->lpf = *((__u8 *)data->data); + break; + case MPU_SLAVE_CLK_SRC: + mpu_gyro_cfg->clk_src = *((__u8 *)data->data); + break; + case MPU_SLAVE_DIVIDER: + mpu_gyro_cfg->divider = *((__u8 *)data->data); + break; + case MPU_SLAVE_DMP_ENABLE: + mpu_gyro_cfg->dmp_enable = *((__u8 *)data->data); + break; + case MPU_SLAVE_FIFO_ENABLE: + mpu_gyro_cfg->fifo_enable = *((__u8 *)data->data); + break; + case MPU_SLAVE_DMP_CFG1: + mpu_gyro_cfg->dmp_cfg1 = *((__u8 *)data->data); + break; + case MPU_SLAVE_DMP_CFG2: + mpu_gyro_cfg->dmp_cfg2 = *((__u8 *)data->data); + break; + case MPU_SLAVE_TC: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + mpu_offsets->tc[ii] = ((__u8 *)data->data)[ii]; + break; + case MPU_SLAVE_GYRO: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + mpu_offsets->gyro[ii] = ((__u16 *)data->data)[ii]; + break; + case MPU_SLAVE_ADDR: + mpu_chip_info->addr = *((__u8 *)data->data); + break; + case MPU_SLAVE_PRODUCT_REVISION: + mpu_chip_info->product_revision = *((__u8 *)data->data); + break; + case MPU_SLAVE_SILICON_REVISION: + mpu_chip_info->silicon_revision = *((__u8 *)data->data); + break; + case MPU_SLAVE_PRODUCT_ID: + mpu_chip_info->product_id = *((__u8 *)data->data); + break; + case MPU_SLAVE_GYRO_SENS_TRIM: + mpu_chip_info->gyro_sens_trim = *((__u16 *)data->data); + break; + case MPU_SLAVE_ACCEL_SENS_TRIM: + mpu_chip_info->accel_sens_trim = *((__u16 *)data->data); + break; + case MPU_SLAVE_RAM: + if (data->len != mldl_cfg->mpu_ram->length) + return INV_ERROR_INVALID_PARAMETER; + + memcpy(mldl_cfg->mpu_ram->ram, data->data, data->len); + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_NEEDS_CONFIG; + return INV_SUCCESS; +} + +int gyro_get_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data) +{ + struct mpu_gyro_cfg *mpu_gyro_cfg = mldl_cfg->mpu_gyro_cfg; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets; + int ii; + + if (!data->data) + return INV_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_INT_CONFIG: + *((__u8 *)data->data) = mpu_gyro_cfg->int_config; + break; + case MPU_SLAVE_EXT_SYNC: + *((__u8 *)data->data) = mpu_gyro_cfg->ext_sync; + break; + case MPU_SLAVE_FULL_SCALE: + *((__u8 *)data->data) = mpu_gyro_cfg->full_scale; + break; + case MPU_SLAVE_LPF: + *((__u8 *)data->data) = mpu_gyro_cfg->lpf; + break; + case MPU_SLAVE_CLK_SRC: + *((__u8 *)data->data) = mpu_gyro_cfg->clk_src; + break; + case MPU_SLAVE_DIVIDER: + *((__u8 *)data->data) = mpu_gyro_cfg->divider; + break; + case MPU_SLAVE_DMP_ENABLE: + *((__u8 *)data->data) = mpu_gyro_cfg->dmp_enable; + break; + case MPU_SLAVE_FIFO_ENABLE: + *((__u8 *)data->data) = mpu_gyro_cfg->fifo_enable; + break; + case MPU_SLAVE_DMP_CFG1: + *((__u8 *)data->data) = mpu_gyro_cfg->dmp_cfg1; + break; + case MPU_SLAVE_DMP_CFG2: + *((__u8 *)data->data) = mpu_gyro_cfg->dmp_cfg2; + break; + case MPU_SLAVE_TC: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + ((__u8 *)data->data)[ii] = mpu_offsets->tc[ii]; + break; + case MPU_SLAVE_GYRO: + for (ii = 0; ii < GYRO_NUM_AXES; ii++) + ((__u16 *)data->data)[ii] = mpu_offsets->gyro[ii]; + break; + case MPU_SLAVE_ADDR: + *((__u8 *)data->data) = mpu_chip_info->addr; + break; + case MPU_SLAVE_PRODUCT_REVISION: + *((__u8 *)data->data) = mpu_chip_info->product_revision; + break; + case MPU_SLAVE_SILICON_REVISION: + *((__u8 *)data->data) = mpu_chip_info->silicon_revision; + break; + case MPU_SLAVE_PRODUCT_ID: + *((__u8 *)data->data) = mpu_chip_info->product_id; + break; + case MPU_SLAVE_GYRO_SENS_TRIM: + *((__u16 *)data->data) = mpu_chip_info->gyro_sens_trim; + break; + case MPU_SLAVE_ACCEL_SENS_TRIM: + *((__u16 *)data->data) = mpu_chip_info->accel_sens_trim; + break; + case MPU_SLAVE_RAM: + if (data->len != mldl_cfg->mpu_ram->length) + return INV_ERROR_INVALID_PARAMETER; + + memcpy(data->data, mldl_cfg->mpu_ram->ram, data->len); + break; + default: + LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED); + return INV_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return INV_SUCCESS; +} + + +/******************************************************************************* + ******************************************************************************* + * Exported functions + ******************************************************************************* + ******************************************************************************/ + +/** + * Initializes the pdata structure to defaults. + * + * Opens the device to read silicon revision, product id and whoami. + * + * @mldl_cfg + * The internal device configuration data structure. + * @mlsl_handle + * The serial communication handle. + * + * @return INV_SUCCESS if silicon revision, product id and woami are supported + * by this software. + */ +int inv_mpu_open(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, void *pressure_handle) +{ + int result; + void *slave_handle[EXT_SLAVE_NUM_TYPES]; + int ii; + + /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */ + ii = 0; + mldl_cfg->inv_mpu_cfg->ignore_system_suspend = false; + mldl_cfg->mpu_gyro_cfg->int_config = BIT_DMP_INT_EN; + mldl_cfg->mpu_gyro_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ; + mldl_cfg->mpu_gyro_cfg->lpf = MPU_FILTER_42HZ; + mldl_cfg->mpu_gyro_cfg->full_scale = MPU_FS_2000DPS; + mldl_cfg->mpu_gyro_cfg->divider = 4; + mldl_cfg->mpu_gyro_cfg->dmp_enable = 1; + mldl_cfg->mpu_gyro_cfg->fifo_enable = 1; + mldl_cfg->mpu_gyro_cfg->ext_sync = 0; + mldl_cfg->mpu_gyro_cfg->dmp_cfg1 = 0; + mldl_cfg->mpu_gyro_cfg->dmp_cfg2 = 0; + mldl_cfg->inv_mpu_state->status = + MPU_DMP_IS_SUSPENDED | + MPU_GYRO_IS_SUSPENDED | + MPU_ACCEL_IS_SUSPENDED | + MPU_COMPASS_IS_SUSPENDED | + MPU_PRESSURE_IS_SUSPENDED | + MPU_DEVICE_IS_SUSPENDED; + mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 0; + + slave_handle[EXT_SLAVE_TYPE_GYROSCOPE] = gyro_handle; + slave_handle[EXT_SLAVE_TYPE_ACCEL] = accel_handle; + slave_handle[EXT_SLAVE_TYPE_COMPASS] = compass_handle; + slave_handle[EXT_SLAVE_TYPE_PRESSURE] = pressure_handle; + + if (mldl_cfg->mpu_chip_info->addr == 0) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + /* + * Reset, + * Take the DMP out of sleep, and + * read the product_id, sillicon rev and whoami + */ + mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED; + result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, RESET, 0, 0, 0, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + result = inv_get_silicon_rev(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Get the factory temperature compensation offsets */ + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_XG_OFFS_TC, 1, + &mldl_cfg->mpu_offsets->tc[0]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_YG_OFFS_TC, 1, + &mldl_cfg->mpu_offsets->tc[1]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr, + MPUREG_ZG_OFFS_TC, 1, + &mldl_cfg->mpu_offsets->tc[2]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Into bypass mode before sleeping and calling the slaves init */ + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = inv_mpu_set_level_shifter_bit(mldl_cfg, gyro_handle, + mldl_cfg->pdata->level_shifter); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + +#if INV_CACHE_DMP != 0 + result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP, 0, 0, 0); +#endif + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + + return result; + +} + +/** + * Close the mpu interface + * + * @mldl_cfg pointer to the configuration structure + * @mlsl_handle pointer to the serial layer handle + * + * @return INV_SUCCESS or non-zero error code + */ +int inv_mpu_close(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle) +{ + return 0; +} + +/** + * @brief resume the MPU device and all the other sensor + * devices from their low power state. + * + * @mldl_cfg + * pointer to the configuration structure + * @gyro_handle + * the main file handle to the MPU device. + * @accel_handle + * an handle to the accelerometer device, if sitting + * onto a separate bus. Can match mlsl_handle if + * the accelerometer device operates on the same + * primary bus of MPU. + * @compass_handle + * an handle to the compass device, if sitting + * onto a separate bus. Can match mlsl_handle if + * the compass device operates on the same + * primary bus of MPU. + * @pressure_handle + * an handle to the pressure sensor device, if sitting + * onto a separate bus. Can match mlsl_handle if + * the pressure sensor device operates on the same + * primary bus of MPU. + * @resume_gyro + * whether resuming the gyroscope device is + * actually needed (if the device supports low power + * mode of some sort). + * @resume_accel + * whether resuming the accelerometer device is + * actually needed (if the device supports low power + * mode of some sort). + * @resume_compass + * whether resuming the compass device is + * actually needed (if the device supports low power + * mode of some sort). + * @resume_pressure + * whether resuming the pressure sensor device is + * actually needed (if the device supports low power + * mode of some sort). + * @return INV_SUCCESS or a non-zero error code. + */ +int inv_mpu_resume(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors) +{ + int result = INV_SUCCESS; + int ii; + bool resume_slave[EXT_SLAVE_NUM_TYPES]; + bool resume_dmp = sensors & INV_DMP_PROCESSOR; + void *slave_handle[EXT_SLAVE_NUM_TYPES]; + resume_slave[EXT_SLAVE_TYPE_GYROSCOPE] = + (sensors & (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)); + resume_slave[EXT_SLAVE_TYPE_ACCEL] = + sensors & INV_THREE_AXIS_ACCEL; + resume_slave[EXT_SLAVE_TYPE_COMPASS] = + sensors & INV_THREE_AXIS_COMPASS; + resume_slave[EXT_SLAVE_TYPE_PRESSURE] = + sensors & INV_THREE_AXIS_PRESSURE; + + slave_handle[EXT_SLAVE_TYPE_GYROSCOPE] = gyro_handle; + slave_handle[EXT_SLAVE_TYPE_ACCEL] = accel_handle; + slave_handle[EXT_SLAVE_TYPE_COMPASS] = compass_handle; + slave_handle[EXT_SLAVE_TYPE_PRESSURE] = pressure_handle; + + + mldl_print_cfg(mldl_cfg); + + /* Skip the Gyro since slave[EXT_SLAVE_TYPE_GYROSCOPE] is NULL */ + for (ii = EXT_SLAVE_TYPE_ACCEL; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (resume_slave[ii] && + ((!mldl_cfg->slave[ii]) || + (!mldl_cfg->slave[ii]->resume))) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + } + + if ((resume_slave[EXT_SLAVE_TYPE_GYROSCOPE] || resume_dmp) + && ((mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_SUSPENDED) || + (mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG))) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = dmp_stop(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = gyro_resume(mldl_cfg, gyro_handle, sensors); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!mldl_cfg->slave[ii] || + !mldl_cfg->pdata_slave[ii] || + !resume_slave[ii] || + !(mldl_cfg->inv_mpu_state->status & (1 << ii))) + continue; + + if (EXT_SLAVE_BUS_SECONDARY == + mldl_cfg->pdata_slave[ii]->bus) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, + true); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + result = mldl_cfg->slave[ii]->resume(slave_handle[ii], + mldl_cfg->slave[ii], + mldl_cfg->pdata_slave[ii]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + mldl_cfg->inv_mpu_state->status &= ~(1 << ii); + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (resume_dmp && + !(mldl_cfg->inv_mpu_state->status & (1 << ii)) && + mldl_cfg->pdata_slave[ii] && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata_slave[ii]->bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->slave[ii], + mldl_cfg->pdata_slave[ii], + mldl_cfg->slave[ii]->type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + } + + /* Turn on the master i2c iterface if necessary */ + if (resume_dmp) { + result = mpu_set_i2c_bypass( + mldl_cfg, gyro_handle, + !(mldl_cfg->inv_mpu_state->i2c_slaves_enabled)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* Now start */ + result = dmp_start(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mldl_cfg->inv_mpu_cfg->requested_sensors = sensors; + + return result; +} + +/** + * @brief suspend the MPU device and all the other sensor + * devices into their low power state. + * @mldl_cfg + * a pointer to the struct mldl_cfg internal data + * structure. + * @gyro_handle + * the main file handle to the MPU device. + * @accel_handle + * an handle to the accelerometer device, if sitting + * onto a separate bus. Can match gyro_handle if + * the accelerometer device operates on the same + * primary bus of MPU. + * @compass_handle + * an handle to the compass device, if sitting + * onto a separate bus. Can match gyro_handle if + * the compass device operates on the same + * primary bus of MPU. + * @pressure_handle + * an handle to the pressure sensor device, if sitting + * onto a separate bus. Can match gyro_handle if + * the pressure sensor device operates on the same + * primary bus of MPU. + * @accel + * whether suspending the accelerometer device is + * actually needed (if the device supports low power + * mode of some sort). + * @compass + * whether suspending the compass device is + * actually needed (if the device supports low power + * mode of some sort). + * @pressure + * whether suspending the pressure sensor device is + * actually needed (if the device supports low power + * mode of some sort). + * @return INV_SUCCESS or a non-zero error code. + */ +int inv_mpu_suspend(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors) +{ + int result = INV_SUCCESS; + int ii; + struct ext_slave_descr **slave = mldl_cfg->slave; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + bool suspend_dmp = ((sensors & INV_DMP_PROCESSOR) == INV_DMP_PROCESSOR); + bool suspend_slave[EXT_SLAVE_NUM_TYPES]; + void *slave_handle[EXT_SLAVE_NUM_TYPES]; + + suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE] = + ((sensors & (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)) + == (INV_X_GYRO | INV_Y_GYRO | INV_Z_GYRO)); + suspend_slave[EXT_SLAVE_TYPE_ACCEL] = + ((sensors & INV_THREE_AXIS_ACCEL) == INV_THREE_AXIS_ACCEL); + suspend_slave[EXT_SLAVE_TYPE_COMPASS] = + ((sensors & INV_THREE_AXIS_COMPASS) == INV_THREE_AXIS_COMPASS); + suspend_slave[EXT_SLAVE_TYPE_PRESSURE] = + ((sensors & INV_THREE_AXIS_PRESSURE) == + INV_THREE_AXIS_PRESSURE); + + slave_handle[EXT_SLAVE_TYPE_GYROSCOPE] = gyro_handle; + slave_handle[EXT_SLAVE_TYPE_ACCEL] = accel_handle; + slave_handle[EXT_SLAVE_TYPE_COMPASS] = compass_handle; + slave_handle[EXT_SLAVE_TYPE_PRESSURE] = pressure_handle; + + if (suspend_dmp) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + result = dmp_stop(mldl_cfg, gyro_handle); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + /* Gyro */ + if (suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE] && + !(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_SUSPENDED)) { + result = mpu3050_pwr_mgmt( + mldl_cfg, gyro_handle, 0, + suspend_dmp && suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE], + (unsigned char)(sensors & INV_X_GYRO), + (unsigned char)(sensors & INV_Y_GYRO), + (unsigned char)(sensors & INV_Z_GYRO)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + bool is_suspended = mldl_cfg->inv_mpu_state->status & (1 << ii); + if (!slave[ii] || !pdata_slave[ii] || + is_suspended || !suspend_slave[ii]) + continue; + + if (EXT_SLAVE_BUS_SECONDARY == pdata_slave[ii]->bus) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + result = slave[ii]->suspend(slave_handle[ii], + slave[ii], + pdata_slave[ii]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + if (EXT_SLAVE_BUS_SECONDARY == pdata_slave[ii]->bus) { + result = mpu_set_slave(mldl_cfg, gyro_handle, + NULL, NULL, + slave[ii]->type); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mldl_cfg->inv_mpu_state->status |= (1 << ii); + } + + /* Re-enable the i2c master if there are configured slaves and DMP */ + if (!suspend_dmp) { + result = mpu_set_i2c_bypass( + mldl_cfg, gyro_handle, + !(mldl_cfg->inv_mpu_state->i2c_slaves_enabled)); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + mldl_cfg->inv_mpu_cfg->requested_sensors = (~sensors) & INV_ALL_SENSORS; + + return result; +} + +int inv_mpu_slave_read(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + int bypass_result; + int remain_bypassed = true; + + if (NULL == slave || NULL == slave->read) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_CONFIGURATION); + return INV_ERROR_INVALID_CONFIGURATION; + } + + if ((EXT_SLAVE_BUS_SECONDARY == pdata->bus) + && (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_BYPASSED))) { + remain_bypassed = false; + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = slave->read(slave_handle, slave, pdata, data); + + if (!remain_bypassed) { + bypass_result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 0); + if (bypass_result) { + LOG_RESULT_LOCATION(bypass_result); + return bypass_result; + } + } + return result; +} + +int inv_mpu_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + int remain_bypassed = true; + + if (NULL == slave || NULL == slave->config) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_CONFIGURATION); + return INV_ERROR_INVALID_CONFIGURATION; + } + + if (data->apply && (EXT_SLAVE_BUS_SECONDARY == pdata->bus) + && (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_BYPASSED))) { + remain_bypassed = false; + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = slave->config(slave_handle, slave, pdata, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!remain_bypassed) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +int inv_mpu_get_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + int remain_bypassed = true; + + if (NULL == slave || NULL == slave->get_config) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_CONFIGURATION); + return INV_ERROR_INVALID_CONFIGURATION; + } + + if (data->apply && (EXT_SLAVE_BUS_SECONDARY == pdata->bus) + && (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_BYPASSED))) { + remain_bypassed = false; + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + + result = slave->get_config(slave_handle, slave, pdata, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + if (!remain_bypassed) { + result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 0); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + } + return result; +} + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/mldl_cfg.h b/drivers/misc/inv_mpu/mldl_cfg.h new file mode 100644 index 000000000000..1c23878940b7 --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_cfg.h @@ -0,0 +1,380 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_cfg.h + * @brief The Motion Library Driver Layer Configuration header file. + */ + +#ifndef __MLDL_CFG_H__ +#define __MLDL_CFG_H__ + +#include "mltypes.h" +#include "mlsl.h" +#include +#include "mpu3050.h" + +#include "log.h" + +/************************************************************************* + * Sensors Bit definitions + *************************************************************************/ + +#define INV_X_GYRO (0x0001) +#define INV_Y_GYRO (0x0002) +#define INV_Z_GYRO (0x0004) +#define INV_DMP_PROCESSOR (0x0008) + +#define INV_X_ACCEL (0x0010) +#define INV_Y_ACCEL (0x0020) +#define INV_Z_ACCEL (0x0040) + +#define INV_X_COMPASS (0x0080) +#define INV_Y_COMPASS (0x0100) +#define INV_Z_COMPASS (0x0200) + +#define INV_X_PRESSURE (0x0300) +#define INV_Y_PRESSURE (0x0800) +#define INV_Z_PRESSURE (0x1000) + +#define INV_TEMPERATURE (0x2000) +#define INV_TIME (0x4000) + +#define INV_THREE_AXIS_GYRO (0x000F) +#define INV_THREE_AXIS_ACCEL (0x0070) +#define INV_THREE_AXIS_COMPASS (0x0380) +#define INV_THREE_AXIS_PRESSURE (0x1C00) + +#define INV_FIVE_AXIS (0x007B) +#define INV_SIX_AXIS_GYRO_ACCEL (0x007F) +#define INV_SIX_AXIS_ACCEL_COMPASS (0x03F0) +#define INV_NINE_AXIS (0x03FF) +#define INV_ALL_SENSORS (0x7FFF) + +#define MPL_PROD_KEY(ver, rev) (ver * 100 + rev) + +/* -------------------------------------------------------------------------- */ +struct mpu_ram { + __u16 length; + __u8 *ram; +}; + +struct mpu_gyro_cfg { + __u8 int_config; + __u8 ext_sync; + __u8 full_scale; + __u8 lpf; + __u8 clk_src; + __u8 divider; + __u8 dmp_enable; + __u8 fifo_enable; + __u8 dmp_cfg1; + __u8 dmp_cfg2; +}; + +/* Offset registers that can be calibrated */ +struct mpu_offsets { + __u8 tc[GYRO_NUM_AXES]; + __u16 gyro[GYRO_NUM_AXES]; +}; + +/* Chip related information that can be read and verified */ +struct mpu_chip_info { + __u8 addr; + __u8 product_revision; + __u8 silicon_revision; + __u8 product_id; + __u16 gyro_sens_trim; + /* Only used for MPU6050 */ + __u16 accel_sens_trim; +}; + + +struct inv_mpu_cfg { + __u32 requested_sensors; + __u8 ignore_system_suspend; +}; + +/* Driver related state information */ +struct inv_mpu_state { +#define MPU_GYRO_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_GYROSCOPE) +#define MPU_ACCEL_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_ACCEL) +#define MPU_COMPASS_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_COMPASS) +#define MPU_PRESSURE_IS_SUSPENDED (0x01 << EXT_SLAVE_TYPE_PRESSURE) +#define MPU_GYRO_IS_BYPASSED (0x10) +#define MPU_DMP_IS_SUSPENDED (0x20) +#define MPU_GYRO_NEEDS_CONFIG (0x40) +#define MPU_DEVICE_IS_SUSPENDED (0x80) + __u8 status; + /* 0-1 for 3050, bitfield of BIT_SLVx_DLY_EN, x = [0..4] */ + __u8 i2c_slaves_enabled; +}; + +/* Platform data for the MPU */ +struct mldl_cfg { + struct mpu_ram *mpu_ram; + struct mpu_gyro_cfg *mpu_gyro_cfg; + struct mpu_offsets *mpu_offsets; + struct mpu_chip_info *mpu_chip_info; + + /* MPU Related stored status and info */ + struct inv_mpu_cfg *inv_mpu_cfg; + struct inv_mpu_state *inv_mpu_state; + + /* Slave related information */ + struct ext_slave_descr *slave[EXT_SLAVE_NUM_TYPES]; + /* Platform Data */ + struct mpu_platform_data *pdata; + struct ext_slave_platform_data *pdata_slave[EXT_SLAVE_NUM_TYPES]; +}; + +/* -------------------------------------------------------------------------- */ + +int inv_mpu_open(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle); +int inv_mpu_close(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle); +int inv_mpu_resume(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors); +int inv_mpu_suspend(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + void *compass_handle, + void *pressure_handle, + unsigned long sensors); +int inv_mpu_set_firmware(struct mldl_cfg *mldl_cfg, + void *mlsl_handle, + const unsigned char *data, + int size); + +/* -------------------------------------------------------------------------- */ +/* Slave Read functions */ +int inv_mpu_slave_read(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data); +static inline int inv_mpu_read_accel(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, unsigned char *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_read( + mldl_cfg, gyro_handle, accel_handle, + mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL], + data); +} + +static inline int inv_mpu_read_compass(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *compass_handle, + unsigned char *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_read( + mldl_cfg, gyro_handle, compass_handle, + mldl_cfg->slave[EXT_SLAVE_TYPE_COMPASS], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_COMPASS], + data); +} + +static inline int inv_mpu_read_pressure(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *pressure_handle, + unsigned char *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_read( + mldl_cfg, gyro_handle, pressure_handle, + mldl_cfg->slave[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + data); +} + +int gyro_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data); + +/* Slave Config functions */ +int inv_mpu_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); +static inline int inv_mpu_config_accel(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_config( + mldl_cfg, gyro_handle, accel_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]); +} + +static inline int inv_mpu_config_compass(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *compass_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_config( + mldl_cfg, gyro_handle, compass_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_COMPASS], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_COMPASS]); +} + +static inline int inv_mpu_config_pressure(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *pressure_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_slave_config( + mldl_cfg, gyro_handle, pressure_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_PRESSURE]); +} + +int gyro_get_config(void *mlsl_handle, + struct mldl_cfg *mldl_cfg, + struct ext_slave_config *data); + +/* Slave get config functions */ +int inv_mpu_get_slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *slave_handle, + struct ext_slave_config *data, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata); + +static inline int inv_mpu_get_accel_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *accel_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_get_slave_config( + mldl_cfg, gyro_handle, accel_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]); +} + +static inline int inv_mpu_get_compass_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *compass_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg || !(mldl_cfg->pdata)) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_get_slave_config( + mldl_cfg, gyro_handle, compass_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_COMPASS], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_COMPASS]); +} + +static inline int inv_mpu_get_pressure_config(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + void *pressure_handle, + struct ext_slave_config *data) +{ + if (!mldl_cfg || !(mldl_cfg->pdata)) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + return inv_mpu_get_slave_config( + mldl_cfg, gyro_handle, pressure_handle, data, + mldl_cfg->slave[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_PRESSURE]); +} + +/* -------------------------------------------------------------------------- */ + +static inline +long inv_mpu_get_sampling_rate_hz(struct mpu_gyro_cfg *gyro_cfg) +{ + if (((gyro_cfg->lpf) == 0) || ((gyro_cfg->lpf) == 7)) + return 8000L / (gyro_cfg->divider + 1); + else + return 1000L / (gyro_cfg->divider + 1); +} + +static inline +long inv_mpu_get_sampling_period_us(struct mpu_gyro_cfg *gyro_cfg) +{ + if (((gyro_cfg->lpf) == 0) || ((gyro_cfg->lpf) == 7)) + return (long) (1000000L * (gyro_cfg->divider + 1)) / 8000L; + else + return (long) (1000000L * (gyro_cfg->divider + 1)) / 1000L; +} + +#endif /* __MLDL_CFG_H__ */ + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/mldl_print_cfg.c b/drivers/misc/inv_mpu/mldl_print_cfg.c new file mode 100644 index 000000000000..5c6951b69823 --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_print_cfg.c @@ -0,0 +1,137 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @addtogroup MLDL + * + * @{ + * @file mldl_print_cfg.c + * @brief The Motion Library Driver Layer. + */ + +#include +#include "mldl_cfg.h" +#include "mlsl.h" +#include "linux/mpu.h" + +#include "log.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "mldl_print_cfg:" + +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 0 + +void mldl_print_cfg(struct mldl_cfg *mldl_cfg) +{ + struct mpu_gyro_cfg *mpu_gyro_cfg = mldl_cfg->mpu_gyro_cfg; + struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets; + struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info; + struct inv_mpu_cfg *inv_mpu_cfg = mldl_cfg->inv_mpu_cfg; + struct inv_mpu_state *inv_mpu_state = mldl_cfg->inv_mpu_state; + struct ext_slave_descr **slave = mldl_cfg->slave; + struct mpu_platform_data *pdata = mldl_cfg->pdata; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + /* mpu_gyro_cfg */ + MPL_LOGI("int_config = %02x\n", mpu_gyro_cfg->int_config); + MPL_LOGI("ext_sync = %02x\n", mpu_gyro_cfg->ext_sync); + MPL_LOGI("full_scale = %02x\n", mpu_gyro_cfg->full_scale); + MPL_LOGI("lpf = %02x\n", mpu_gyro_cfg->lpf); + MPL_LOGI("clk_src = %02x\n", mpu_gyro_cfg->clk_src); + MPL_LOGI("divider = %02x\n", mpu_gyro_cfg->divider); + MPL_LOGI("dmp_enable = %02x\n", mpu_gyro_cfg->dmp_enable); + MPL_LOGI("fifo_enable = %02x\n", mpu_gyro_cfg->fifo_enable); + MPL_LOGI("dmp_cfg1 = %02x\n", mpu_gyro_cfg->dmp_cfg1); + MPL_LOGI("dmp_cfg2 = %02x\n", mpu_gyro_cfg->dmp_cfg2); + /* mpu_offsets */ + MPL_LOGV("tc[0] = %02x\n", mpu_offsets->tc[0]); + MPL_LOGV("tc[1] = %02x\n", mpu_offsets->tc[1]); + MPL_LOGV("tc[2] = %02x\n", mpu_offsets->tc[2]); + MPL_LOGV("gyro[0] = %04x\n", mpu_offsets->gyro[0]); + MPL_LOGV("gyro[1] = %04x\n", mpu_offsets->gyro[1]); + MPL_LOGV("gyro[2] = %04x\n", mpu_offsets->gyro[2]); + + /* mpu_chip_info */ + MPL_LOGV("addr = %02x\n", mldl_cfg->mpu_chip_info->addr); + + MPL_LOGV("silicon_revision = %02x\n", mpu_chip_info->silicon_revision); + MPL_LOGV("product_revision = %02x\n", mpu_chip_info->product_revision); + MPL_LOGV("product_id = %02x\n", mpu_chip_info->product_id); + MPL_LOGV("gyro_sens_trim = %02x\n", mpu_chip_info->gyro_sens_trim); + + MPL_LOGV("requested_sensors = %04x\n", inv_mpu_cfg->requested_sensors); + MPL_LOGV("ignore_system_suspend= %04x\n", + inv_mpu_cfg->ignore_system_suspend); + MPL_LOGV("status = %04x\n", inv_mpu_state->status); + MPL_LOGV("i2c_slaves_enabled= %04x\n", + inv_mpu_state->i2c_slaves_enabled); + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!slave[ii]) + continue; + MPL_LOGV("SLAVE %d:\n", ii); + MPL_LOGV(" suspend = %02x\n", (int)slave[ii]->suspend); + MPL_LOGV(" resume = %02x\n", (int)slave[ii]->resume); + MPL_LOGV(" read = %02x\n", (int)slave[ii]->read); + MPL_LOGV(" type = %02x\n", slave[ii]->type); + MPL_LOGV(" reg = %02x\n", slave[ii]->read_reg); + MPL_LOGV(" len = %02x\n", slave[ii]->read_len); + MPL_LOGV(" endian = %02x\n", slave[ii]->endian); + MPL_LOGV(" range.mantissa= %02x\n", + slave[ii]->range.mantissa); + MPL_LOGV(" range.fraction= %02x\n", + slave[ii]->range.fraction); + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + continue; + MPL_LOGV("PDATA_SLAVE[%d]\n", ii); + MPL_LOGV(" irq = %02x\n", pdata_slave[ii]->irq); + MPL_LOGV(" adapt_num = %02x\n", pdata_slave[ii]->adapt_num); + MPL_LOGV(" bus = %02x\n", pdata_slave[ii]->bus); + MPL_LOGV(" address = %02x\n", pdata_slave[ii]->address); + MPL_LOGV(" orientation=\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n" + " %2d %2d %2d\n", + pdata_slave[ii]->orientation[0], + pdata_slave[ii]->orientation[1], + pdata_slave[ii]->orientation[2], + pdata_slave[ii]->orientation[3], + pdata_slave[ii]->orientation[4], + pdata_slave[ii]->orientation[5], + pdata_slave[ii]->orientation[6], + pdata_slave[ii]->orientation[7], + pdata_slave[ii]->orientation[8]); + } + + MPL_LOGV("pdata->int_config = %02x\n", pdata->int_config); + MPL_LOGV("pdata->level_shifter = %02x\n", pdata->level_shifter); + MPL_LOGV("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]); +} diff --git a/drivers/misc/inv_mpu/mldl_print_cfg.h b/drivers/misc/inv_mpu/mldl_print_cfg.h new file mode 100644 index 000000000000..2e1911440cca --- /dev/null +++ b/drivers/misc/inv_mpu/mldl_print_cfg.h @@ -0,0 +1,38 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @defgroup + * @brief + * + * @{ + * @file mldl_print_cfg.h + * @brief + * + * + */ +#ifndef __MLDL_PRINT_CFG__ +#define __MLDL_PRINT_CFG__ + +#include "mldl_cfg.h" + + +void mldl_print_cfg(struct mldl_cfg *mldl_cfg); + +#endif /* __MLDL_PRINT_CFG__ */ diff --git a/drivers/misc/inv_mpu/mlsl-kernel.c b/drivers/misc/inv_mpu/mlsl-kernel.c new file mode 100755 index 000000000000..25b5fb098d19 --- /dev/null +++ b/drivers/misc/inv_mpu/mlsl-kernel.c @@ -0,0 +1,440 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +#include "mlsl.h" +#include +#include "log.h" +#include "mpu3050.h" + +#define MPU_I2C_RATE 200*1000 +static int inv_i2c_write(struct i2c_adapter *i2c_adap, + unsigned char address, + unsigned int len, unsigned char const *data) +{ + struct i2c_msg msgs[1]; + int res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = (unsigned char *)data; + msgs[0].len = len; + msgs[0].scl_rate = MPU_I2C_RATE; + //msgs[0].udelay = 200; + + res = i2c_transfer(i2c_adap, msgs, 1); + if (res == 1) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + +static int inv_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 inv_i2c_write(i2c_adap, address, 2, data); +} + +static int inv_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 (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + + msgs[0].addr = address; + msgs[0].flags = 0; /* write */ + msgs[0].buf = ® + msgs[0].len = 1; + msgs[0].scl_rate = MPU_I2C_RATE; + //msgs[0].udelay = 200; + + msgs[1].addr = address; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = data; + msgs[1].len = len; + msgs[1].scl_rate = MPU_I2C_RATE; + //msgs[1].udelay = 200; + + res = i2c_transfer(i2c_adap, msgs, 2); + if (res == 2) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + +static 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 res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + + bank[0] = MPUREG_BANK_SEL; + bank[1] = mem_addr >> 8; + + addr[0] = MPUREG_MEM_START_ADDR; + addr[1] = mem_addr & 0xFF; + + buf = 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[0].scl_rate = MPU_I2C_RATE; + //msgs[0].udelay = 200; + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + msgs[1].scl_rate = MPU_I2C_RATE; + //msgs[1].udelay = 200; + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = &buf; + msgs[2].len = 1; + msgs[2].scl_rate = MPU_I2C_RATE; + //msgs[2].udelay = 200; + + msgs[3].addr = mpu_addr; + msgs[3].flags = I2C_M_RD; + msgs[3].buf = data; + msgs[3].len = len; + msgs[3].scl_rate = MPU_I2C_RATE; + //msgs[3].udelay = 200; + + res = i2c_transfer(i2c_adap, msgs, 4); + if (res == 4) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; +} + +static int mpu_memory_write(struct i2c_adapter *i2c_adap, + unsigned char mpu_addr, + unsigned short mem_addr, + unsigned int len, unsigned char const *data) +{ + unsigned char bank[2]; + unsigned char addr[2]; + unsigned char buf[513]; + + struct i2c_msg msgs[3]; + int res; + + if (!data || !i2c_adap) { + LOG_RESULT_LOCATION(-EINVAL); + return -EINVAL; + } + if (len >= (sizeof(buf) - 1)) { + LOG_RESULT_LOCATION(-ENOMEM); + return -ENOMEM; + } + + bank[0] = MPUREG_BANK_SEL; + bank[1] = mem_addr >> 8; + + addr[0] = MPUREG_MEM_START_ADDR; + addr[1] = mem_addr & 0xFF; + + buf[0] = 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[0].scl_rate = MPU_I2C_RATE; + //msgs[0].udelay = 200; + + msgs[1].addr = mpu_addr; + msgs[1].flags = 0; + msgs[1].buf = addr; + msgs[1].len = sizeof(addr); + msgs[1].scl_rate = MPU_I2C_RATE; + //msgs[1].udelay = 200; + + msgs[2].addr = mpu_addr; + msgs[2].flags = 0; + msgs[2].buf = (unsigned char *)buf; + msgs[2].len = len + 1; + msgs[2].scl_rate = MPU_I2C_RATE; + //msgs[2].udelay = 200; + + res = i2c_transfer(i2c_adap, msgs, 3); + if (res == 3) + return 0; + else if(res == 0) + return -EBUSY; + else + return res; + +} + +int inv_serial_single_write( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned char data) +{ + return inv_i2c_write_register((struct i2c_adapter *)sl_handle, + slave_addr, register_addr, data); +} +EXPORT_SYMBOL(inv_serial_single_write); + +int inv_serial_write( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data) +{ + int result; + const unsigned short data_length = length - 1; + const unsigned char start_reg_addr = data[0]; + unsigned char i2c_write[SERIAL_MAX_TRANSFER_SIZE + 1]; + unsigned short bytes_written = 0; + + while (bytes_written < data_length) { + unsigned short this_len = min(SERIAL_MAX_TRANSFER_SIZE, + data_length - bytes_written); + if (bytes_written == 0) { + result = inv_i2c_write((struct i2c_adapter *) + sl_handle, slave_addr, + 1 + this_len, data); + } else { + /* manually increment register addr between chunks */ + i2c_write[0] = start_reg_addr + bytes_written; + memcpy(&i2c_write[1], &data[1 + bytes_written], + this_len); + result = inv_i2c_write((struct i2c_adapter *) + sl_handle, slave_addr, + 1 + this_len, i2c_write); + } + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_written += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_write); + +int inv_serial_read( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned short length, + unsigned char *data) +{ + int result; + unsigned short bytes_read = 0; + + if ((slave_addr & 0x7E) == DEFAULT_MPU_SLAVEADDR + && (register_addr == MPUREG_FIFO_R_W || + register_addr == MPUREG_MEM_R_W)) { + LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); + return INV_ERROR_INVALID_PARAMETER; + } + + while (bytes_read < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); + result = inv_i2c_read((struct i2c_adapter *)sl_handle, + slave_addr, register_addr + bytes_read, + this_len, &data[bytes_read]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_read += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_read); + +int inv_serial_write_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char const *data) +{ + int result; + unsigned short bytes_written = 0; + + if ((mem_addr & 0xFF) + length > MPU_MEM_BANK_SIZE) { + pr_err("memory read length (%d B) extends beyond its" + " limits (%d) if started at location %d\n", length, + MPU_MEM_BANK_SIZE, mem_addr & 0xFF); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_written < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_written); + result = mpu_memory_write((struct i2c_adapter *)sl_handle, + slave_addr, mem_addr + bytes_written, + this_len, &data[bytes_written]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_written += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_write_mem); + +int inv_serial_read_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char *data) +{ + int result; + unsigned short bytes_read = 0; + + if ((mem_addr & 0xFF) + length > MPU_MEM_BANK_SIZE) { + printk + ("memory read length (%d B) extends beyond its limits (%d) " + "if started at location %d\n", length, + MPU_MEM_BANK_SIZE, mem_addr & 0xFF); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_read < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); + result = + mpu_memory_read((struct i2c_adapter *)sl_handle, + slave_addr, mem_addr + bytes_read, + this_len, &data[bytes_read]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_read += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_read_mem); + +int inv_serial_write_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data) +{ + int result; + unsigned char i2c_write[SERIAL_MAX_TRANSFER_SIZE + 1]; + unsigned short bytes_written = 0; + + if (length > FIFO_HW_SIZE) { + printk(KERN_ERR + "maximum fifo write length is %d\n", FIFO_HW_SIZE); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_written < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_written); + i2c_write[0] = MPUREG_FIFO_R_W; + memcpy(&i2c_write[1], &data[bytes_written], this_len); + result = inv_i2c_write((struct i2c_adapter *)sl_handle, + slave_addr, this_len + 1, i2c_write); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_written += this_len; + } + return 0; +} +EXPORT_SYMBOL(inv_serial_write_fifo); + +int inv_serial_read_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char *data) +{ + int result; + unsigned short bytes_read = 0; + + if (length > FIFO_HW_SIZE) { + printk(KERN_ERR + "maximum fifo read length is %d\n", FIFO_HW_SIZE); + return INV_ERROR_INVALID_PARAMETER; + } + while (bytes_read < length) { + unsigned short this_len = + min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); + result = inv_i2c_read((struct i2c_adapter *)sl_handle, + slave_addr, MPUREG_FIFO_R_W, this_len, + &data[bytes_read]); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + bytes_read += this_len; + } + + return 0; +} +EXPORT_SYMBOL(inv_serial_read_fifo); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/mlsl.h b/drivers/misc/inv_mpu/mlsl.h new file mode 100644 index 000000000000..204baedc1e20 --- /dev/null +++ b/drivers/misc/inv_mpu/mlsl.h @@ -0,0 +1,186 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +#ifndef __MLSL_H__ +#define __MLSL_H__ + +/** + * @defgroup MLSL + * @brief Motion Library - Serial Layer. + * The Motion Library System Layer provides the Motion Library + * with the communication interface to the hardware. + * + * The communication interface is assumed to support serial + * transfers in burst of variable length up to + * SERIAL_MAX_TRANSFER_SIZE. + * The default value for SERIAL_MAX_TRANSFER_SIZE is 128 bytes. + * Transfers of length greater than SERIAL_MAX_TRANSFER_SIZE, will + * be subdivided in smaller transfers of length <= + * SERIAL_MAX_TRANSFER_SIZE. + * The SERIAL_MAX_TRANSFER_SIZE definition can be modified to + * overcome any host processor transfer size limitation down to + * 1 B, the minimum. + * An higher value for SERIAL_MAX_TRANSFER_SIZE will favor + * performance and efficiency while requiring higher resource usage + * (mostly buffering). A smaller value will increase overhead and + * decrease efficiency but allows to operate with more resource + * constrained processor and master serial controllers. + * The SERIAL_MAX_TRANSFER_SIZE definition can be found in the + * mlsl.h header file and master serial controllers. + * The SERIAL_MAX_TRANSFER_SIZE definition can be found in the + * mlsl.h header file. + * + * @{ + * @file mlsl.h + * @brief The Motion Library System Layer. + * + */ + +#include "mltypes.h" +#include + + +/* + * NOTE : to properly support Yamaha compass reads, + * the max transfer size should be at least 9 B. + * Length in bytes, typically a power of 2 >= 2 + */ +#define SERIAL_MAX_TRANSFER_SIZE 128 + + +/** + * inv_serial_single_write() - used to write a single byte of data. + * @sl_handle pointer to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @register_addr Register address to write. + * @data Single byte of data to write. + * + * It is called by the MPL to write a single byte of data to the MPU. + * + * returns INV_SUCCESS if successful, a non-zero error code otherwise. + */ +int inv_serial_single_write( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned char data); + +/** + * inv_serial_write() - used to write multiple bytes of data to registers. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @register_addr Register address to write. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS if successful, a non-zero error code otherwise. + */ +int inv_serial_write( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data); + +/** + * inv_serial_read() - used to read multiple bytes of data from registers. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @register_addr Register address to read. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_read( + void *sl_handle, + unsigned char slave_addr, + unsigned char register_addr, + unsigned short length, + unsigned char *data); + +/** + * inv_serial_read_mem() - used to read multiple bytes of data from the memory. + * This should be sent by I2C or SPI. + * + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @mem_addr The location in the memory to read from. + * @length Length of burst data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_read_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char *data); + +/** + * inv_serial_write_mem() - used to write multiple bytes of data to the memory. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @mem_addr The location in the memory to write to. + * @length Length of burst data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_write_mem( + void *sl_handle, + unsigned char slave_addr, + unsigned short mem_addr, + unsigned short length, + unsigned char const *data); + +/** + * inv_serial_read_fifo() - used to read multiple bytes of data from the fifo. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_read_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char *data); + +/** + * inv_serial_write_fifo() - used to write multiple bytes of data to the fifo. + * @sl_handle a file handle to the serial device used for the communication. + * @slave_addr I2C slave address of device. + * @length Length of burst of data. + * @data Pointer to block of data. + * + * returns INV_SUCCESS == 0 if successful; a non-zero error code otherwise. + */ +int inv_serial_write_fifo( + void *sl_handle, + unsigned char slave_addr, + unsigned short length, + unsigned char const *data); + +/** + * @} + */ +#endif /* __MLSL_H__ */ diff --git a/drivers/misc/inv_mpu/mltypes.h b/drivers/misc/inv_mpu/mltypes.h new file mode 100644 index 000000000000..a249f93be3ee --- /dev/null +++ b/drivers/misc/inv_mpu/mltypes.h @@ -0,0 +1,234 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @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) INV_SUCCESS + * - (32) INV_ERROR + * - (22 / EINVAL) INV_ERROR_INVALID_PARAMETER + * - (1 / EPERM) INV_ERROR_FEATURE_NOT_ENABLED + * - (36) INV_ERROR_FEATURE_NOT_IMPLEMENTED + * - (38) INV_ERROR_DMP_NOT_STARTED + * - (39) INV_ERROR_DMP_STARTED + * - (40) INV_ERROR_NOT_OPENED + * - (41) INV_ERROR_OPENED + * - (19 / ENODEV) INV_ERROR_INVALID_MODULE + * - (12 / ENOMEM) INV_ERROR_MEMORY_EXAUSTED + * - (44) INV_ERROR_DIVIDE_BY_ZERO + * - (45) INV_ERROR_ASSERTION_FAILURE + * - (46) INV_ERROR_FILE_OPEN + * - (47) INV_ERROR_FILE_READ + * - (48) INV_ERROR_FILE_WRITE + * - (49) INV_ERROR_INVALID_CONFIGURATION + * - (52) INV_ERROR_SERIAL_CLOSED + * - (53) INV_ERROR_SERIAL_OPEN_ERROR + * - (54) INV_ERROR_SERIAL_READ + * - (55) INV_ERROR_SERIAL_WRITE + * - (56) INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED + * - (57) INV_ERROR_SM_TRANSITION + * - (58) INV_ERROR_SM_IMPROPER_STATE + * - (62) INV_ERROR_FIFO_OVERFLOW + * - (63) INV_ERROR_FIFO_FOOTER + * - (64) INV_ERROR_FIFO_READ_COUNT + * - (65) INV_ERROR_FIFO_READ_DATA + * - (72) INV_ERROR_MEMORY_SET + * - (82) INV_ERROR_LOG_MEMORY_ERROR + * - (83) INV_ERROR_LOG_OUTPUT_ERROR + * - (92) INV_ERROR_OS_BAD_PTR + * - (93) INV_ERROR_OS_BAD_HANDLE + * - (94) INV_ERROR_OS_CREATE_FAILED + * - (95) INV_ERROR_OS_LOCK_FAILED + * - (102) INV_ERROR_COMPASS_DATA_OVERFLOW + * - (103) INV_ERROR_COMPASS_DATA_UNDERFLOW + * - (104) INV_ERROR_COMPASS_DATA_NOT_READY + * - (105) INV_ERROR_COMPASS_DATA_ERROR + * - (107) INV_ERROR_CALIBRATION_LOAD + * - (108) INV_ERROR_CALIBRATION_STORE + * - (109) INV_ERROR_CALIBRATION_LEN + * - (110) INV_ERROR_CALIBRATION_CHECKSUM + * - (111) INV_ERROR_ACCEL_DATA_OVERFLOW + * - (112) INV_ERROR_ACCEL_DATA_UNDERFLOW + * - (113) INV_ERROR_ACCEL_DATA_NOT_READY + * - (114) INV_ERROR_ACCEL_DATA_ERROR + * + * The available warning codes and their associated values are: + * - (115) INV_WARNING_MOTION_RACE + * - (116) INV_WARNING_QUAT_TRASHED + * + * @{ + * @file mltypes.h + * @} + */ + +#ifndef MLTYPES_H +#define MLTYPES_H + +#include +#include + + + + +/*--------------------------- + * ML Defines + *--------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif + +/* - ML Errors. - */ +#define ERROR_NAME(x) (#x) +#define ERROR_CHECK_FIRST(first, x) \ + { if (INV_SUCCESS == first) first = x; } + +#define INV_SUCCESS (0) +/* Generic Error code. Proprietary Error Codes only */ +#define INV_ERROR_BASE (0x20) +#define INV_ERROR (INV_ERROR_BASE) + +/* Compatibility and other generic error codes */ +#define INV_ERROR_INVALID_PARAMETER (EINVAL) +#define INV_ERROR_FEATURE_NOT_ENABLED (EPERM) +#define INV_ERROR_FEATURE_NOT_IMPLEMENTED (INV_ERROR_BASE + 4) +#define INV_ERROR_DMP_NOT_STARTED (INV_ERROR_BASE + 6) +#define INV_ERROR_DMP_STARTED (INV_ERROR_BASE + 7) +#define INV_ERROR_NOT_OPENED (INV_ERROR_BASE + 8) +#define INV_ERROR_OPENED (INV_ERROR_BASE + 9) +#define INV_ERROR_INVALID_MODULE (ENODEV) +#define INV_ERROR_MEMORY_EXAUSTED (ENOMEM) +#define INV_ERROR_DIVIDE_BY_ZERO (INV_ERROR_BASE + 12) +#define INV_ERROR_ASSERTION_FAILURE (INV_ERROR_BASE + 13) +#define INV_ERROR_FILE_OPEN (INV_ERROR_BASE + 14) +#define INV_ERROR_FILE_READ (INV_ERROR_BASE + 15) +#define INV_ERROR_FILE_WRITE (INV_ERROR_BASE + 16) +#define INV_ERROR_INVALID_CONFIGURATION (INV_ERROR_BASE + 17) + +/* Serial Communication */ +#define INV_ERROR_SERIAL_CLOSED (INV_ERROR_BASE + 20) +#define INV_ERROR_SERIAL_OPEN_ERROR (INV_ERROR_BASE + 21) +#define INV_ERROR_SERIAL_READ (INV_ERROR_BASE + 22) +#define INV_ERROR_SERIAL_WRITE (INV_ERROR_BASE + 23) +#define INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED (INV_ERROR_BASE + 24) + +/* SM = State Machine */ +#define INV_ERROR_SM_TRANSITION (INV_ERROR_BASE + 25) +#define INV_ERROR_SM_IMPROPER_STATE (INV_ERROR_BASE + 26) + +/* Fifo */ +#define INV_ERROR_FIFO_OVERFLOW (INV_ERROR_BASE + 30) +#define INV_ERROR_FIFO_FOOTER (INV_ERROR_BASE + 31) +#define INV_ERROR_FIFO_READ_COUNT (INV_ERROR_BASE + 32) +#define INV_ERROR_FIFO_READ_DATA (INV_ERROR_BASE + 33) + +/* Memory & Registers, Set & Get */ +#define INV_ERROR_MEMORY_SET (INV_ERROR_BASE + 40) + +#define INV_ERROR_LOG_MEMORY_ERROR (INV_ERROR_BASE + 50) +#define INV_ERROR_LOG_OUTPUT_ERROR (INV_ERROR_BASE + 51) + +/* OS interface errors */ +#define INV_ERROR_OS_BAD_PTR (INV_ERROR_BASE + 60) +#define INV_ERROR_OS_BAD_HANDLE (INV_ERROR_BASE + 61) +#define INV_ERROR_OS_CREATE_FAILED (INV_ERROR_BASE + 62) +#define INV_ERROR_OS_LOCK_FAILED (INV_ERROR_BASE + 63) + +/* Compass errors */ +#define INV_ERROR_COMPASS_DATA_OVERFLOW (INV_ERROR_BASE + 70) +#define INV_ERROR_COMPASS_DATA_UNDERFLOW (INV_ERROR_BASE + 71) +#define INV_ERROR_COMPASS_DATA_NOT_READY (INV_ERROR_BASE + 72) +#define INV_ERROR_COMPASS_DATA_ERROR (INV_ERROR_BASE + 73) + +/* Load/Store calibration */ +#define INV_ERROR_CALIBRATION_LOAD (INV_ERROR_BASE + 75) +#define INV_ERROR_CALIBRATION_STORE (INV_ERROR_BASE + 76) +#define INV_ERROR_CALIBRATION_LEN (INV_ERROR_BASE + 77) +#define INV_ERROR_CALIBRATION_CHECKSUM (INV_ERROR_BASE + 78) + +/* Accel errors */ +#define INV_ERROR_ACCEL_DATA_OVERFLOW (INV_ERROR_BASE + 79) +#define INV_ERROR_ACCEL_DATA_UNDERFLOW (INV_ERROR_BASE + 80) +#define INV_ERROR_ACCEL_DATA_NOT_READY (INV_ERROR_BASE + 81) +#define INV_ERROR_ACCEL_DATA_ERROR (INV_ERROR_BASE + 82) + +/* No Motion Warning States */ +#define INV_WARNING_MOTION_RACE (INV_ERROR_BASE + 83) +#define INV_WARNING_QUAT_TRASHED (INV_ERROR_BASE + 84) +#define INV_WARNING_GYRO_MAG (INV_ERROR_BASE + 85) + +#ifdef INV_USE_LEGACY_NAMES +#define ML_SUCCESS INV_SUCCESS +#define ML_ERROR INV_ERROR +#define ML_ERROR_INVALID_PARAMETER INV_ERROR_INVALID_PARAMETER +#define ML_ERROR_FEATURE_NOT_ENABLED INV_ERROR_FEATURE_NOT_ENABLED +#define ML_ERROR_FEATURE_NOT_IMPLEMENTED INV_ERROR_FEATURE_NOT_IMPLEMENTED +#define ML_ERROR_DMP_NOT_STARTED INV_ERROR_DMP_NOT_STARTED +#define ML_ERROR_DMP_STARTED INV_ERROR_DMP_STARTED +#define ML_ERROR_NOT_OPENED INV_ERROR_NOT_OPENED +#define ML_ERROR_OPENED INV_ERROR_OPENED +#define ML_ERROR_INVALID_MODULE INV_ERROR_INVALID_MODULE +#define ML_ERROR_MEMORY_EXAUSTED INV_ERROR_MEMORY_EXAUSTED +#define ML_ERROR_DIVIDE_BY_ZERO INV_ERROR_DIVIDE_BY_ZERO +#define ML_ERROR_ASSERTION_FAILURE INV_ERROR_ASSERTION_FAILURE +#define ML_ERROR_FILE_OPEN INV_ERROR_FILE_OPEN +#define ML_ERROR_FILE_READ INV_ERROR_FILE_READ +#define ML_ERROR_FILE_WRITE INV_ERROR_FILE_WRITE +#define ML_ERROR_INVALID_CONFIGURATION INV_ERROR_INVALID_CONFIGURATION +#define ML_ERROR_SERIAL_CLOSED INV_ERROR_SERIAL_CLOSED +#define ML_ERROR_SERIAL_OPEN_ERROR INV_ERROR_SERIAL_OPEN_ERROR +#define ML_ERROR_SERIAL_READ INV_ERROR_SERIAL_READ +#define ML_ERROR_SERIAL_WRITE INV_ERROR_SERIAL_WRITE +#define ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED \ + INV_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED +#define ML_ERROR_SM_TRANSITION INV_ERROR_SM_TRANSITION +#define ML_ERROR_SM_IMPROPER_STATE INV_ERROR_SM_IMPROPER_STATE +#define ML_ERROR_FIFO_OVERFLOW INV_ERROR_FIFO_OVERFLOW +#define ML_ERROR_FIFO_FOOTER INV_ERROR_FIFO_FOOTER +#define ML_ERROR_FIFO_READ_COUNT INV_ERROR_FIFO_READ_COUNT +#define ML_ERROR_FIFO_READ_DATA INV_ERROR_FIFO_READ_DATA +#define ML_ERROR_MEMORY_SET INV_ERROR_MEMORY_SET +#define ML_ERROR_LOG_MEMORY_ERROR INV_ERROR_LOG_MEMORY_ERROR +#define ML_ERROR_LOG_OUTPUT_ERROR INV_ERROR_LOG_OUTPUT_ERROR +#define ML_ERROR_OS_BAD_PTR INV_ERROR_OS_BAD_PTR +#define ML_ERROR_OS_BAD_HANDLE INV_ERROR_OS_BAD_HANDLE +#define ML_ERROR_OS_CREATE_FAILED INV_ERROR_OS_CREATE_FAILED +#define ML_ERROR_OS_LOCK_FAILED INV_ERROR_OS_LOCK_FAILED +#define ML_ERROR_COMPASS_DATA_OVERFLOW INV_ERROR_COMPASS_DATA_OVERFLOW +#define ML_ERROR_COMPASS_DATA_UNDERFLOW INV_ERROR_COMPASS_DATA_UNDERFLOW +#define ML_ERROR_COMPASS_DATA_NOT_READY INV_ERROR_COMPASS_DATA_NOT_READY +#define ML_ERROR_COMPASS_DATA_ERROR INV_ERROR_COMPASS_DATA_ERROR +#define ML_ERROR_CALIBRATION_LOAD INV_ERROR_CALIBRATION_LOAD +#define ML_ERROR_CALIBRATION_STORE INV_ERROR_CALIBRATION_STORE +#define ML_ERROR_CALIBRATION_LEN INV_ERROR_CALIBRATION_LEN +#define ML_ERROR_CALIBRATION_CHECKSUM INV_ERROR_CALIBRATION_CHECKSUM +#define ML_ERROR_ACCEL_DATA_OVERFLOW INV_ERROR_ACCEL_DATA_OVERFLOW +#define ML_ERROR_ACCEL_DATA_UNDERFLOW INV_ERROR_ACCEL_DATA_UNDERFLOW +#define ML_ERROR_ACCEL_DATA_NOT_READY INV_ERROR_ACCEL_DATA_NOT_READY +#define ML_ERROR_ACCEL_DATA_ERROR INV_ERROR_ACCEL_DATA_ERROR +#endif + +/* For Linux coding compliance */ + +#endif /* MLTYPES_H */ diff --git a/drivers/misc/inv_mpu/mpu-dev.c b/drivers/misc/inv_mpu/mpu-dev.c new file mode 100755 index 000000000000..1ccbaa7fa449 --- /dev/null +++ b/drivers/misc/inv_mpu/mpu-dev.c @@ -0,0 +1,1255 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mpuirq.h" +#include "slaveirq.h" +#include "mlsl.h" +#include "mldl_cfg.h" +#include + + +/* Platform data for the MPU */ +struct mpu_private_data { + struct miscdevice dev; + struct i2c_client *client; + + /* mldl_cfg data */ + struct mldl_cfg mldl_cfg; + struct mpu_ram mpu_ram; + struct mpu_gyro_cfg mpu_gyro_cfg; + struct mpu_offsets mpu_offsets; + struct mpu_chip_info mpu_chip_info; + struct inv_mpu_cfg inv_mpu_cfg; + struct inv_mpu_state inv_mpu_state; + + struct mutex mutex; + wait_queue_head_t mpu_event_wait; + struct completion completion; + struct timer_list timeout; + struct notifier_block nb; + struct mpuirq_data mpu_pm_event; + int response_timeout; /* In seconds */ + unsigned long event; + int pid; + struct module *slave_modules[EXT_SLAVE_NUM_TYPES]; +}; + +struct mpu_private_data *mpu_private_data; +static struct i2c_client *this_client; + +static void mpu_pm_timeout(u_long data) +{ + struct mpu_private_data *mpu = (struct mpu_private_data *)data; + struct i2c_client *client = mpu->client; + dev_dbg(&client->adapter->dev, "%s\n", __func__); + complete(&mpu->completion); +} + +static int mpu_pm_notifier_callback(struct notifier_block *nb, + unsigned long event, void *unused) +{ + struct mpu_private_data *mpu = + container_of(nb, struct mpu_private_data, nb); + struct i2c_client *client = mpu->client; + struct timeval event_time; + dev_dbg(&client->adapter->dev, "%s: %ld\n", __func__, event); + + /* Prevent the file handle from being closed before we initialize + the completion event */ + mutex_lock(&mpu->mutex); + if (!(mpu->pid) || + (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) { + mutex_unlock(&mpu->mutex); + return NOTIFY_OK; + } + + if (event == PM_SUSPEND_PREPARE) + mpu->event = MPU_PM_EVENT_SUSPEND_PREPARE; + if (event == PM_POST_SUSPEND) + mpu->event = MPU_PM_EVENT_POST_SUSPEND; + + do_gettimeofday(&event_time); + mpu->mpu_pm_event.interruptcount++; + mpu->mpu_pm_event.irqtime = + (((long long)event_time.tv_sec) << 32) + event_time.tv_usec; + mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT; + mpu->mpu_pm_event.data = mpu->event; + + if (mpu->response_timeout > 0) { + mpu->timeout.expires = jiffies + mpu->response_timeout * HZ; + add_timer(&mpu->timeout); + } + INIT_COMPLETION(mpu->completion); + mutex_unlock(&mpu->mutex); + + wake_up_interruptible(&mpu->mpu_event_wait); + wait_for_completion(&mpu->completion); + del_timer_sync(&mpu->timeout); + dev_dbg(&client->adapter->dev, "%s: %ld DONE\n", __func__, event); + return NOTIFY_OK; +} + +static int mpu_dev_open(struct inode *inode, struct file *file) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct i2c_client *client = mpu->client; + int result; + int ii; + dev_dbg(&client->adapter->dev, "%s\n", __func__); + dev_dbg(&client->adapter->dev, "current->pid %d\n", current->pid); + + result = mutex_lock_interruptible(&mpu->mutex); + if (mpu->pid) { + mutex_unlock(&mpu->mutex); + return -EBUSY; + } + mpu->pid = current->pid; + file->private_data = &mpu->dev; + + /* Reset the sensors to the default */ + if (result) { + dev_err(&client->adapter->dev, + "%s: mutex_lock_interruptible returned %d\n", + __func__, result); + return result; + } + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) + __module_get(mpu->slave_modules[ii]); + + mutex_unlock(&mpu->mutex); + 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 mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int result = 0; + int ii; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + mldl_cfg->inv_mpu_cfg->requested_sensors = 0; + result = inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + mpu->pid = 0; + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) + module_put(mpu->slave_modules[ii]); + + mutex_unlock(&mpu->mutex); + complete(&mpu->completion); + dev_dbg(&client->adapter->dev, "mpu_release\n"); + + return result; +} + +/* 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) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long); + int err; + + if (!mpu->event && (!(file->f_flags & O_NONBLOCK))) + wait_event_interruptible(mpu->mpu_event_wait, mpu->event); + + if (!mpu->event || !buf + || count < sizeof(mpu->mpu_pm_event)) + return 0; + + err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event)); + if (err) { + dev_err(&client->adapter->dev, + "Copy to user returned %d\n", err); + return -EFAULT; + } + mpu->event = 0; + return len; +} + +static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + int mask = 0; + + poll_wait(file, &mpu->mpu_event_wait, poll); + if (mpu->event) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +static int mpu_dev_ioctl_get_ext_slave_platform_data( + struct i2c_client *client, + struct ext_slave_platform_data __user *arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct ext_slave_platform_data *pdata_slave; + struct ext_slave_platform_data local_pdata_slave; + + if (copy_from_user(&local_pdata_slave, arg, sizeof(local_pdata_slave))) + return -EFAULT; + + if (local_pdata_slave.type >= EXT_SLAVE_NUM_TYPES) + return -EINVAL; + + pdata_slave = mpu->mldl_cfg.pdata_slave[local_pdata_slave.type]; + /* All but private data and irq_data */ + if (!pdata_slave) + return -ENODEV; + if (copy_to_user(arg, pdata_slave, sizeof(*pdata_slave))) + return -EFAULT; + return 0; +} + +static int mpu_dev_ioctl_get_mpu_platform_data( + struct i2c_client *client, + struct mpu_platform_data __user *arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct mpu_platform_data *pdata = mpu->mldl_cfg.pdata; + + if (copy_to_user(arg, pdata, sizeof(*pdata))) + return -EFAULT; + return 0; +} + +static int mpu_dev_ioctl_get_ext_slave_descr( + struct i2c_client *client, + struct ext_slave_descr __user *arg) +{ + struct mpu_private_data *mpu = + (struct mpu_private_data *)i2c_get_clientdata(client); + struct ext_slave_descr *slave; + struct ext_slave_descr local_slave; + + if (copy_from_user(&local_slave, arg, sizeof(local_slave))) + return -EFAULT; + + if (local_slave.type >= EXT_SLAVE_NUM_TYPES) + return -EINVAL; + + slave = mpu->mldl_cfg.slave[local_slave.type]; + /* All but private data and irq_data */ + if (!slave) + return -ENODEV; + if (copy_to_user(arg, slave, sizeof(*slave))) + return -EFAULT; + return 0; +} + + +/** + * slave_config() - Pass a requested slave configuration to the slave sensor + * + * @adapter the adaptor to use to communicate with the slave + * @mldl_cfg the mldl configuration structuer + * @slave pointer to the slave descriptor + * @usr_config The configuration to pass to the slave sensor + * + * returns 0 or non-zero error code + */ +static int inv_mpu_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = gyro_config(gyro_adapter, mldl_cfg, &config); + kfree(config.data); + return retval; +} + +static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + void *user_data; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + user_data = config.data; + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = gyro_get_config(gyro_adapter, mldl_cfg, &config); + if (!retval) + retval = copy_to_user((unsigned char __user *)user_data, + config.data, config.len); + kfree(config.data); + return retval; +} + +static int slave_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + void *slave_adapter, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + if ((!slave) || (!slave->config)) + return -ENODEV; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = inv_mpu_slave_config(mldl_cfg, gyro_adapter, slave_adapter, + &config, slave, pdata); + kfree(config.data); + return retval; +} + +static int slave_get_config(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + void *slave_adapter, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config __user *usr_config) +{ + int retval = 0; + struct ext_slave_config config; + void *user_data; + if (!(slave) || !(slave->get_config)) + return -ENODEV; + + retval = copy_from_user(&config, usr_config, sizeof(config)); + if (retval) + return -EFAULT; + + user_data = config.data; + if (config.len && config.data) { + void *data; + data = kmalloc(config.len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)config.data, config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = inv_mpu_get_slave_config(mldl_cfg, gyro_adapter, + slave_adapter, &config, slave, pdata); + if (retval) { + kfree(config.data); + return retval; + } + retval = copy_to_user((unsigned char __user *)user_data, + config.data, config.len); + kfree(config.data); + return retval; +} + +static int inv_slave_read(struct mldl_cfg *mldl_cfg, + void *gyro_adapter, + void *slave_adapter, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + void __user *usr_data) +{ + int retval; + unsigned char *data; + data = kzalloc(slave->read_len, GFP_KERNEL); + if (!data) + return -EFAULT; + + retval = inv_mpu_slave_read(mldl_cfg, gyro_adapter, slave_adapter, + slave, pdata, data); + + if ((!retval) && + (copy_to_user((unsigned char __user *)usr_data, + data, slave->read_len))) + retval = -EFAULT; + + kfree(data); + return retval; +} + +static int mpu_handle_mlsl(void *sl_handle, + unsigned char addr, + unsigned int cmd, + struct mpu_read_write __user *usr_msg) +{ + int retval = 0; + struct mpu_read_write msg; + unsigned char *user_data; + retval = copy_from_user(&msg, usr_msg, sizeof(msg)); + if (retval) + return -EFAULT; + + user_data = msg.data; + if (msg.length && msg.data) { + unsigned char *data; + data = kmalloc(msg.length, GFP_KERNEL); + if (!data) + return -ENOMEM; + + retval = copy_from_user(data, + (void __user *)msg.data, msg.length); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + msg.data = data; + } else { + return -EPERM; + } + + switch (cmd) { + case MPU_READ: + retval = inv_serial_read(sl_handle, addr, + msg.address, msg.length, msg.data); + break; + case MPU_WRITE: + retval = inv_serial_write(sl_handle, addr, + msg.length, msg.data); + break; + case MPU_READ_MEM: + retval = inv_serial_read_mem(sl_handle, addr, + msg.address, msg.length, msg.data); + break; + case MPU_WRITE_MEM: + retval = inv_serial_write_mem(sl_handle, addr, + msg.address, msg.length, + msg.data); + break; + case MPU_READ_FIFO: + retval = inv_serial_read_fifo(sl_handle, addr, + msg.length, msg.data); + break; + case MPU_WRITE_FIFO: + retval = inv_serial_write_fifo(sl_handle, addr, + msg.length, msg.data); + break; + + }; + if (retval) { + dev_err(&((struct i2c_adapter *)sl_handle)->dev, + "%s: i2c %d error %d\n", + __func__, cmd, retval); + kfree(msg.data); + return retval; + } + retval = copy_to_user((unsigned char __user *)user_data, + msg.data, msg.length); + kfree(msg.data); + return retval; +} + +/* ioctl - I/O control */ +static long mpu_dev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mpu_private_data *mpu = + container_of(file->private_data, struct mpu_private_data, dev); + struct i2c_client *client = mpu->client; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + int retval = 0; + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_descr **slave = mldl_cfg->slave; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + retval = mutex_lock_interruptible(&mpu->mutex); + if (retval) { + dev_err(&this_client->adapter->dev, + "%s: mutex_lock_interruptible returned %d\n", + __func__, retval); + return retval; + } + + switch (cmd) { + case MPU_GET_EXT_SLAVE_PLATFORM_DATA: + retval = mpu_dev_ioctl_get_ext_slave_platform_data( + client, + (struct ext_slave_platform_data __user *)arg); + break; + case MPU_GET_MPU_PLATFORM_DATA: + retval = mpu_dev_ioctl_get_mpu_platform_data( + client, + (struct mpu_platform_data __user *)arg); + break; + case MPU_GET_EXT_SLAVE_DESCR: + retval = mpu_dev_ioctl_get_ext_slave_descr( + client, + (struct ext_slave_descr __user *)arg); + break; + case MPU_READ: + case MPU_WRITE: + case MPU_READ_MEM: + case MPU_WRITE_MEM: + case MPU_READ_FIFO: + case MPU_WRITE_FIFO: + retval = mpu_handle_mlsl( + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + mldl_cfg->mpu_chip_info->addr, cmd, + (struct mpu_read_write __user *)arg); + break; + case MPU_CONFIG_GYRO: + retval = inv_mpu_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + (struct ext_slave_config __user *)arg); + break; + case MPU_CONFIG_ACCEL: + retval = slave_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave[EXT_SLAVE_TYPE_ACCEL], + pdata_slave[EXT_SLAVE_TYPE_ACCEL], + (struct ext_slave_config __user *)arg); + break; + case MPU_CONFIG_COMPASS: + retval = slave_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave[EXT_SLAVE_TYPE_COMPASS], + pdata_slave[EXT_SLAVE_TYPE_COMPASS], + (struct ext_slave_config __user *)arg); + break; + case MPU_CONFIG_PRESSURE: + retval = slave_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + slave[EXT_SLAVE_TYPE_PRESSURE], + pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_GYRO: + retval = inv_mpu_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_ACCEL: + retval = slave_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave[EXT_SLAVE_TYPE_ACCEL], + pdata_slave[EXT_SLAVE_TYPE_ACCEL], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_COMPASS: + retval = slave_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave[EXT_SLAVE_TYPE_COMPASS], + pdata_slave[EXT_SLAVE_TYPE_COMPASS], + (struct ext_slave_config __user *)arg); + break; + case MPU_GET_CONFIG_PRESSURE: + retval = slave_get_config( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + slave[EXT_SLAVE_TYPE_PRESSURE], + pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + (struct ext_slave_config __user *)arg); + break; + case MPU_SUSPEND: + retval = inv_mpu_suspend( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + arg); + break; + case MPU_RESUME: + retval = inv_mpu_resume( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + arg); + break; + case MPU_PM_EVENT_HANDLED: + dev_dbg(&client->adapter->dev, "%s: %d\n", __func__, cmd); + complete(&mpu->completion); + break; + case MPU_READ_ACCEL: + retval = inv_slave_read( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave[EXT_SLAVE_TYPE_ACCEL], + pdata_slave[EXT_SLAVE_TYPE_ACCEL], + (unsigned char __user *)arg); + break; + case MPU_READ_COMPASS: + retval = inv_slave_read( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave[EXT_SLAVE_TYPE_COMPASS], + pdata_slave[EXT_SLAVE_TYPE_COMPASS], + (unsigned char __user *)arg); + break; + case MPU_READ_PRESSURE: + retval = inv_slave_read( + mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + slave[EXT_SLAVE_TYPE_PRESSURE], + pdata_slave[EXT_SLAVE_TYPE_PRESSURE], + (unsigned char __user *)arg); + break; + case MPU_GET_REQUESTED_SENSORS: + if (copy_to_user( + (__u32 __user *)arg, + &mldl_cfg->inv_mpu_cfg->requested_sensors, + sizeof(mldl_cfg->inv_mpu_cfg->requested_sensors))) + retval = -EFAULT; + break; + case MPU_SET_REQUESTED_SENSORS: + mldl_cfg->inv_mpu_cfg->requested_sensors = arg; + break; + case MPU_GET_IGNORE_SYSTEM_SUSPEND: + if (copy_to_user( + (unsigned char __user *)arg, + &mldl_cfg->inv_mpu_cfg->ignore_system_suspend, + sizeof(mldl_cfg->inv_mpu_cfg->ignore_system_suspend))) + retval = -EFAULT; + break; + case MPU_SET_IGNORE_SYSTEM_SUSPEND: + mldl_cfg->inv_mpu_cfg->ignore_system_suspend = arg; + break; + case MPU_GET_MLDL_STATUS: + if (copy_to_user( + (unsigned char __user *)arg, + &mldl_cfg->inv_mpu_state->status, + sizeof(mldl_cfg->inv_mpu_state->status))) + retval = -EFAULT; + break; + case MPU_GET_I2C_SLAVES_ENABLED: + if (copy_to_user( + (unsigned char __user *)arg, + &mldl_cfg->inv_mpu_state->i2c_slaves_enabled, + sizeof(mldl_cfg->inv_mpu_state->i2c_slaves_enabled))) + retval = -EFAULT; + break; + default: + dev_err(&client->adapter->dev, + "%s: Unknown cmd %x, arg %lu\n", + __func__, cmd, arg); + retval = -EINVAL; + }; + + mutex_unlock(&mpu->mutex); + + + //dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",__func__, cmd, arg, retval); + + if (retval > 0) + retval = -retval; + + return retval; +} + +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 *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + (void)inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + mutex_unlock(&mpu->mutex); + dev_dbg(&client->adapter->dev, "%s\n", __func__); +} + +int mpu_dev_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 *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + if (!mldl_cfg->inv_mpu_cfg->ignore_system_suspend) { + dev_dbg(&client->adapter->dev, + "%s: suspending on event %d\n", __func__, mesg.event); + (void)inv_mpu_suspend(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + INV_ALL_SENSORS); + } else { + dev_dbg(&client->adapter->dev, + "%s: Already suspended %d\n", __func__, mesg.event); + } + mutex_unlock(&mpu->mutex); + return 0; +} + +int mpu_dev_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 *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + + mutex_lock(&mpu->mutex); + if (mpu->pid && !mldl_cfg->inv_mpu_cfg->ignore_system_suspend) { + (void)inv_mpu_resume(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE], + mldl_cfg->inv_mpu_cfg->requested_sensors); + dev_dbg(&client->adapter->dev, + "%s for pid %d\n", __func__, mpu->pid); + } + mutex_unlock(&mpu->mutex); + return 0; +} + +/* define which file operations are supported */ +static const struct file_operations mpu_fops = { + .owner = THIS_MODULE, + .read = mpu_read, + .poll = mpu_poll, +#if HAVE_COMPAT_IOCTL + .compat_ioctl = mpu_dev_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = mpu_dev_ioctl, +#endif + //.unlocked_ioctl = mpu_dev_ioctl, + .open = mpu_dev_open, + .release = mpu_release, +}; + +int inv_mpu_register_slave(struct module *slave_module, + struct i2c_client *slave_client, + struct ext_slave_platform_data *slave_pdata, + struct ext_slave_descr *(*get_slave_descr)(void)) +{ + struct mpu_private_data *mpu = mpu_private_data; + struct mldl_cfg *mldl_cfg; + struct ext_slave_descr *slave_descr; + struct ext_slave_platform_data **pdata_slave; + char *irq_name = NULL; + int result = 0; + + if (!slave_client || !slave_pdata || !get_slave_descr) + return -EINVAL; + + if (!mpu) { + dev_err(&slave_client->adapter->dev, + "%s: Null mpu_private_data\n", __func__); + return -EINVAL; + } + mldl_cfg = &mpu->mldl_cfg; + pdata_slave = mldl_cfg->pdata_slave; + slave_descr = get_slave_descr(); + + if (!slave_descr) { + dev_err(&slave_client->adapter->dev, + "%s: Null ext_slave_descr\n", __func__); + return -EINVAL; + } + + mutex_lock(&mpu->mutex); + if (mpu->pid) { + mutex_unlock(&mpu->mutex); + return -EBUSY; + } + + if (pdata_slave[slave_descr->type]) { + result = -EBUSY; + goto out_unlock_mutex; + } + + slave_pdata->address = slave_client->addr; + slave_pdata->irq = slave_client->irq; + slave_pdata->adapt_num = i2c_adapter_id(slave_client->adapter); + + dev_info(&slave_client->adapter->dev, + "%s: +%s Type %d: Addr: %2x IRQ: %2d, Adapt: %2d\n", + __func__, + slave_descr->name, + slave_descr->type, + slave_pdata->address, + slave_pdata->irq, + slave_pdata->adapt_num); + + switch (slave_descr->type) { + case EXT_SLAVE_TYPE_ACCEL: + irq_name = "accelirq"; + break; + case EXT_SLAVE_TYPE_COMPASS: + irq_name = "compassirq"; + break; + case EXT_SLAVE_TYPE_PRESSURE: + irq_name = "pressureirq"; + break; + default: + irq_name = "none"; + }; + if (slave_descr->init) { + result = slave_descr->init(slave_client->adapter, + slave_descr, + slave_pdata); + if (result) { + dev_err(&slave_client->adapter->dev, + "%s init failed %d\n", + slave_descr->name, result); + goto out_unlock_mutex; + } + } + + pdata_slave[slave_descr->type] = slave_pdata; + mpu->slave_modules[slave_descr->type] = slave_module; + mldl_cfg->slave[slave_descr->type] = slave_descr; + + goto out_unlock_mutex; + +out_unlock_mutex: + mutex_unlock(&mpu->mutex); + + if (!result && irq_name && (slave_pdata->irq > 0)) { + int warn_result; + dev_info(&slave_client->adapter->dev, + "Installing %s irq using %d\n", + irq_name, + slave_pdata->irq); + warn_result = slaveirq_init(slave_client->adapter, + slave_pdata, irq_name); + if (result) + dev_err(&slave_client->adapter->dev, + "%s irq assigned error: %d\n", + slave_descr->name, warn_result); + } else { + dev_warn(&slave_client->adapter->dev, + "%s irq not assigned: %d %d %d\n", + slave_descr->name, + result, (int)irq_name, slave_pdata->irq); + } + + return result; +} +EXPORT_SYMBOL(inv_mpu_register_slave); + +void inv_mpu_unregister_slave(struct i2c_client *slave_client, + struct ext_slave_platform_data *slave_pdata, + struct ext_slave_descr *(*get_slave_descr)(void)) +{ + struct mpu_private_data *mpu = mpu_private_data; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct ext_slave_descr *slave_descr; + int result; + + dev_info(&slave_client->adapter->dev, "%s\n", __func__); + + if (!slave_client || !slave_pdata || !get_slave_descr) + return; + + if (slave_pdata->irq) + slaveirq_exit(slave_pdata); + + slave_descr = get_slave_descr(); + if (!slave_descr) + return; + + mutex_lock(&mpu->mutex); + + if (slave_descr->exit) { + result = slave_descr->exit(slave_client->adapter, + slave_descr, + slave_pdata); + if (result) + dev_err(&slave_client->adapter->dev, + "Accel exit failed %d\n", result); + } + mldl_cfg->slave[slave_descr->type] = NULL; + mldl_cfg->pdata_slave[slave_descr->type] = NULL; + mpu->slave_modules[slave_descr->type] = NULL; + + mutex_unlock(&mpu->mutex); + +} +EXPORT_SYMBOL(inv_mpu_unregister_slave); + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static const struct i2c_device_id mpu_id[] = { + {"mpu3050", 0}, + {"mpu6050", 0}, + {"mpu6050_no_accel", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mpu_id); + +int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid) +{ + struct mpu_platform_data *pdata; + struct mpu_private_data *mpu; + struct mldl_cfg *mldl_cfg; + int res = 0; + int ii = 0; + + dev_info(&client->adapter->dev, "%s: %d\n", __func__, ii++); + + 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; + } + mldl_cfg = &mpu->mldl_cfg; + mldl_cfg->mpu_ram = &mpu->mpu_ram; + mldl_cfg->mpu_gyro_cfg = &mpu->mpu_gyro_cfg; + mldl_cfg->mpu_offsets = &mpu->mpu_offsets; + mldl_cfg->mpu_chip_info = &mpu->mpu_chip_info; + mldl_cfg->inv_mpu_cfg = &mpu->inv_mpu_cfg; + mldl_cfg->inv_mpu_state = &mpu->inv_mpu_state; + + mldl_cfg->mpu_ram->length = MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE; + mldl_cfg->mpu_ram->ram = kzalloc(mldl_cfg->mpu_ram->length, GFP_KERNEL); + if (!mldl_cfg->mpu_ram->ram) { + res = -ENOMEM; + goto out_alloc_ram_failed; + } + mpu_private_data = mpu; + i2c_set_clientdata(client, mpu); + this_client = client; + mpu->client = client; + + init_waitqueue_head(&mpu->mpu_event_wait); + mutex_init(&mpu->mutex); + init_completion(&mpu->completion); + + mpu->response_timeout = 60; /* Seconds */ + mpu->timeout.function = mpu_pm_timeout; + mpu->timeout.data = (u_long) mpu; + init_timer(&mpu->timeout); + + mpu->nb.notifier_call = mpu_pm_notifier_callback; + mpu->nb.priority = 0; + res = register_pm_notifier(&mpu->nb); + if (res) { + dev_err(&client->adapter->dev, + "Unable to register pm_notifier %d\n", res); + goto out_register_pm_notifier_failed; + } + + pdata = (struct mpu_platform_data *)client->dev.platform_data; + if (!pdata) { + dev_WARN(&client->adapter->dev, + "Missing platform data for mpu\n"); + } + mldl_cfg->pdata = pdata; + + mldl_cfg->mpu_chip_info->addr = client->addr; + res = inv_mpu_open(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL); + + if (res) { + dev_err(&client->adapter->dev, + "Unable to open %s %d\n", MPU_NAME, res); + res = -ENODEV; + goto out_whoami_failed; + } + + mpu->dev.minor = MISC_DYNAMIC_MINOR; + mpu->dev.name = "mpu"; + mpu->dev.fops = &mpu_fops; + res = misc_register(&mpu->dev); + if (res < 0) { + dev_err(&client->adapter->dev, + "ERROR: misc_register returned %d\n", res); + goto out_misc_register_failed; + } + + if (client->irq) { + dev_info(&client->adapter->dev, + "Installing irq using %d\n", client->irq); + res = mpuirq_init(client, mldl_cfg); + if (res) + goto out_mpuirq_failed; + } else { + dev_WARN(&client->adapter->dev, + "Missing %s IRQ\n", MPU_NAME); + } + return res; + +out_mpuirq_failed: + misc_deregister(&mpu->dev); +out_misc_register_failed: + inv_mpu_close(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL); +out_whoami_failed: + unregister_pm_notifier(&mpu->nb); +out_register_pm_notifier_failed: + kfree(mldl_cfg->mpu_ram->ram); + mpu_private_data = NULL; +out_alloc_ram_failed: + kfree(mpu); +out_alloc_data_failed: +out_check_functionality_failed: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, res); + return res; + +} + +static int mpu_remove(struct i2c_client *client) +{ + struct mpu_private_data *mpu = i2c_get_clientdata(client); + struct i2c_adapter *slave_adapter[EXT_SLAVE_NUM_TYPES]; + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct ext_slave_platform_data **pdata_slave = mldl_cfg->pdata_slave; + int ii; + + for (ii = 0; ii < EXT_SLAVE_NUM_TYPES; ii++) { + if (!pdata_slave[ii]) + slave_adapter[ii] = NULL; + else + slave_adapter[ii] = + i2c_get_adapter(pdata_slave[ii]->adapt_num); + } + + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter; + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_close(mldl_cfg, + slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE], + slave_adapter[EXT_SLAVE_TYPE_ACCEL], + slave_adapter[EXT_SLAVE_TYPE_COMPASS], + slave_adapter[EXT_SLAVE_TYPE_PRESSURE]); + + + if (client->irq) + mpuirq_exit(); + + misc_deregister(&mpu->dev); + + unregister_pm_notifier(&mpu->nb); + + kfree(mpu->mldl_cfg.mpu_ram->ram); + kfree(mpu); + + return 0; +} + +static struct i2c_driver mpu_driver = { + .class = I2C_CLASS_HWMON, + .probe = mpu_probe, + .remove = mpu_remove, + .id_table = mpu_id, + .driver = { + .owner = THIS_MODULE, + .name = MPU_NAME, + }, + .address_list = normal_i2c, + .shutdown = mpu_shutdown, /* optional */ + .suspend = mpu_dev_suspend, /* optional */ + .resume = mpu_dev_resume, /* optional */ + +}; + +static int __init mpu_init(void) +{ + int res = i2c_add_driver(&mpu_driver); + pr_info("%s: Probe name %s\n", __func__, MPU_NAME); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit mpu_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&mpu_driver); +} + +module_init(mpu_init); +module_exit(mpu_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("User space character device interface for MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS(MPU_NAME); diff --git a/drivers/misc/inv_mpu/mpu-dev.h b/drivers/misc/inv_mpu/mpu-dev.h new file mode 100644 index 000000000000..b6a4fcfac586 --- /dev/null +++ b/drivers/misc/inv_mpu/mpu-dev.h @@ -0,0 +1,36 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + + +#ifndef __MPU_DEV_H__ +#define __MPU_DEV_H__ + +#include +#include +#include + +int inv_mpu_register_slave(struct module *slave_module, + struct i2c_client *client, + struct ext_slave_platform_data *pdata, + struct ext_slave_descr *(*slave_descr)(void)); + +void inv_mpu_unregister_slave(struct i2c_client *client, + struct ext_slave_platform_data *pdata, + struct ext_slave_descr *(*slave_descr)(void)); +#endif diff --git a/drivers/misc/inv_mpu/mpu3050.h b/drivers/misc/inv_mpu/mpu3050.h new file mode 100644 index 000000000000..02af16ed1216 --- /dev/null +++ b/drivers/misc/inv_mpu/mpu3050.h @@ -0,0 +1,251 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +#ifndef __MPU_H_ +#error Do not include this file directly. Include mpu.h instead. +#endif + +#ifndef __MPU3050_H_ +#define __MPU3050_H_ + +#include + + +#define MPU_NAME "mpu3050" +#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_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) + +enum MPU_MEMORY_BANKS { + 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 +}; + +/*---- 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) + +#endif /* __MPU3050_H_ */ diff --git a/drivers/misc/inv_mpu/mpuirq.c b/drivers/misc/inv_mpu/mpuirq.c new file mode 100755 index 000000000000..8bfddc87a04e --- /dev/null +++ b/drivers/misc/inv_mpu/mpuirq.c @@ -0,0 +1,257 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpuirq.h" +#include "mldl_cfg.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 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 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; + 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 && + mpuirq_dev_data.timeout && (!(file->f_flags & O_NONBLOCK))) { + 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)); + mpuirq_data.data_type = 0; + } 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; + + poll_wait(file, &mpuirq_wait, poll); + if (mpuirq_dev_data.data_ready) + mask |= POLLIN | POLLRDNORM; + 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 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 */ + mpuirq_dev_data.data_ready = 1; + + do_gettimeofday(&irqtime); + mpuirq_data.irqtime = (((long long)irqtime.tv_sec) << 32); + mpuirq_data.irqtime += irqtime.tv_usec; + mpuirq_data.data_type = MPUIRQ_DATA_TYPE_MPU_IRQ; + mpuirq_data.data = 0; + + wake_up_interruptible(&mpuirq_wait); + + return IRQ_HANDLED; + +} + +/* define which file operations are supported */ +const struct file_operations mpuirq_fops = { + .owner = THIS_MODULE, + .read = mpuirq_read, + .poll = mpuirq_poll, + + .unlocked_ioctl = mpuirq_ioctl, + .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, struct mldl_cfg *mldl_cfg) +{ + + int res; + + mpuirq_dev_data.mpu_client = mpu_client; + + dev_info(&mpu_client->adapter->dev, + "Module Param interface = %s\n", interface); + + mpuirq_dev_data.irq = gpio_to_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; + + flags |= IRQF_SHARED; + 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) +{ + if (mpuirq_dev_data.irq > 0) + free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq); + + 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/inv_mpu/mpuirq.h b/drivers/misc/inv_mpu/mpuirq.h new file mode 100644 index 000000000000..33480711f79d --- /dev/null +++ b/drivers/misc/inv_mpu/mpuirq.h @@ -0,0 +1,36 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +#ifndef __MPUIRQ__ +#define __MPUIRQ__ + +#include +#include +#include +#include "mldl_cfg.h" + +#define MPUIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x40, unsigned long) +#define MPUIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x41, unsigned long) +#define MPUIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x42, struct timeval) +#define MPUIRQ_SET_FREQUENCY_DIVIDER _IOW(MPU_IOCTL, 0x43, unsigned long) + +void mpuirq_exit(void); +int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg); + +#endif diff --git a/drivers/misc/inv_mpu/pressure/Kconfig b/drivers/misc/inv_mpu/pressure/Kconfig new file mode 100644 index 000000000000..f1c021e8f126 --- /dev/null +++ b/drivers/misc/inv_mpu/pressure/Kconfig @@ -0,0 +1,20 @@ +menuconfig: INV_SENSORS_PRESSURE + bool "Pressure Sensor Slaves" + depends on INV_SENSORS + default y + help + Select y to see a list of supported pressure sensors that can be + integrated with the MPUxxxx set of motion processors. + +if INV_SENSORS_PRESSURE + +config MPU_SENSORS_BMA085 + tristate "Bosch BMA085" + help + This enables support for the Bosch bma085 pressure sensor + This support is for integration with the MPU3050 or MPU6050 gyroscope + device driver. Only one accelerometer can be registered at a time. + Specifying more that one accelerometer in the board file will result + in runtime errors. + +endif diff --git a/drivers/misc/inv_mpu/pressure/Makefile b/drivers/misc/inv_mpu/pressure/Makefile new file mode 100644 index 000000000000..595923d809dc --- /dev/null +++ b/drivers/misc/inv_mpu/pressure/Makefile @@ -0,0 +1,8 @@ +# +# Pressure Slaves to MPUxxxx +# +obj-$(CONFIG_MPU_SENSORS_BMA085) += inv_mpu_bma085.o +inv_mpu_bma085-objs += bma085.o + +EXTRA_CFLAGS += -Idrivers/misc/inv_mpu +EXTRA_CFLAGS += -D__C99_DESIGNATED_INITIALIZER diff --git a/drivers/misc/inv_mpu/pressure/bma085.c b/drivers/misc/inv_mpu/pressure/bma085.c new file mode 100644 index 000000000000..696d2b6e183c --- /dev/null +++ b/drivers/misc/inv_mpu/pressure/bma085.c @@ -0,0 +1,367 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +/** + * @defgroup ACCELDL (Motion Library - Pressure Driver Layer) + * @brief Provides the interface to setup and handle a pressure + * connected to the secondary I2C interface of the gyroscope. + * + * @{ + * @file bma085.c + * @brief Pressure setup and handling methods. + */ + +/* ------------------ */ +/* - Include Files. - */ +/* ------------------ */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include "mlsl.h" +#include "log.h" + +/* + * this structure holds all device specific calibration parameters + */ +struct bmp085_calibration_param_t { + short ac1; + short ac2; + short ac3; + unsigned short ac4; + unsigned short ac5; + unsigned short ac6; + short b1; + short b2; + short mb; + short mc; + short md; + long param_b5; +}; + +struct bmp085_calibration_param_t cal_param; + +#define PRESSURE_BMA085_PARAM_MG 3038 /* calibration parameter */ +#define PRESSURE_BMA085_PARAM_MH -7357 /* calibration parameter */ +#define PRESSURE_BMA085_PARAM_MI 3791 /* calibration parameter */ + +/********************************************* + * Pressure Initialization Functions + *********************************************/ + +static int bma085_suspend(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result = INV_SUCCESS; + return result; +} + +#define PRESSURE_BMA085_PROM_START_ADDR (0xAA) +#define PRESSURE_BMA085_PROM_DATA_LEN (22) +#define PRESSURE_BMP085_CTRL_MEAS_REG (0xF4) +/* temperature measurent */ +#define PRESSURE_BMP085_T_MEAS (0x2E) +/* pressure measurement; oversampling_setting */ +#define PRESSURE_BMP085_P_MEAS_OSS_0 (0x34) +#define PRESSURE_BMP085_P_MEAS_OSS_1 (0x74) +#define PRESSURE_BMP085_P_MEAS_OSS_2 (0xB4) +#define PRESSURE_BMP085_P_MEAS_OSS_3 (0xF4) +#define PRESSURE_BMP085_ADC_OUT_MSB_REG (0xF6) +#define PRESSURE_BMP085_ADC_OUT_LSB_REG (0xF7) + +static int bma085_resume(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + int result; + unsigned char data[PRESSURE_BMA085_PROM_DATA_LEN]; + + result = + inv_serial_read(mlsl_handle, pdata->address, + PRESSURE_BMA085_PROM_START_ADDR, + PRESSURE_BMA085_PROM_DATA_LEN, data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + + /* parameters AC1-AC6 */ + cal_param.ac1 = (data[0] << 8) | data[1]; + cal_param.ac2 = (data[2] << 8) | data[3]; + cal_param.ac3 = (data[4] << 8) | data[5]; + cal_param.ac4 = (data[6] << 8) | data[7]; + cal_param.ac5 = (data[8] << 8) | data[9]; + cal_param.ac6 = (data[10] << 8) | data[11]; + + /* parameters B1,B2 */ + cal_param.b1 = (data[12] << 8) | data[13]; + cal_param.b2 = (data[14] << 8) | data[15]; + + /* parameters MB,MC,MD */ + cal_param.mb = (data[16] << 8) | data[17]; + cal_param.mc = (data[18] << 8) | data[19]; + cal_param.md = (data[20] << 8) | data[21]; + + return result; +} + +static int bma085_read(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + unsigned char *data) +{ + int result; + long pressure, x1, x2, x3, b3, b6; + unsigned long b4, b7; + unsigned long up; + unsigned short ut; + short oversampling_setting = 0; + short temperature; + long divisor; + + /* get temprature */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + PRESSURE_BMP085_CTRL_MEAS_REG, + PRESSURE_BMP085_T_MEAS); + msleep(5); + result = + inv_serial_read(mlsl_handle, pdata->address, + PRESSURE_BMP085_ADC_OUT_MSB_REG, 2, + (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + ut = (data[0] << 8) | data[1]; + + x1 = (((long) ut - (long)cal_param.ac6) * (long)cal_param.ac5) >> 15; + divisor = x1 + cal_param.md; + if (!divisor) + return INV_ERROR_DIVIDE_BY_ZERO; + + x2 = ((long)cal_param.mc << 11) / (x1 + cal_param.md); + cal_param.param_b5 = x1 + x2; + /* temperature in 0.1 degree C */ + temperature = (short)((cal_param.param_b5 + 8) >> 4); + + /* get pressure */ + result = inv_serial_single_write(mlsl_handle, pdata->address, + PRESSURE_BMP085_CTRL_MEAS_REG, + PRESSURE_BMP085_P_MEAS_OSS_0); + msleep(5); + result = + inv_serial_read(mlsl_handle, pdata->address, + PRESSURE_BMP085_ADC_OUT_MSB_REG, 2, + (unsigned char *)data); + if (result) { + LOG_RESULT_LOCATION(result); + return result; + } + up = (((unsigned long) data[0] << 8) | ((unsigned long) data[1])); + + b6 = cal_param.param_b5 - 4000; + /* calculate B3 */ + x1 = (b6*b6) >> 12; + x1 *= cal_param.b2; + x1 >>= 11; + + x2 = (cal_param.ac2*b6); + x2 >>= 11; + + x3 = x1 + x2; + + b3 = (((((long)cal_param.ac1) * 4 + x3) + << oversampling_setting) + 2) >> 2; + + /* calculate B4 */ + x1 = (cal_param.ac3 * b6) >> 13; + x2 = (cal_param.b1 * ((b6*b6) >> 12)) >> 16; + x3 = ((x1 + x2) + 2) >> 2; + b4 = (cal_param.ac4 * (unsigned long) (x3 + 32768)) >> 15; + if (!b4) + return INV_ERROR; + + b7 = ((unsigned long)(up - b3) * (50000>>oversampling_setting)); + if (b7 < 0x80000000) + pressure = (b7 << 1) / b4; + else + pressure = (b7 / b4) << 1; + + x1 = pressure >> 8; + x1 *= x1; + x1 = (x1 * PRESSURE_BMA085_PARAM_MG) >> 16; + x2 = (pressure * PRESSURE_BMA085_PARAM_MH) >> 16; + /* pressure in Pa */ + pressure += (x1 + x2 + PRESSURE_BMA085_PARAM_MI) >> 4; + + data[0] = (unsigned char)(pressure >> 16); + data[1] = (unsigned char)(pressure >> 8); + data[2] = (unsigned char)(pressure & 0xFF); + + return result; +} + +static struct ext_slave_descr bma085_descr = { + .init = NULL, + .exit = NULL, + .suspend = bma085_suspend, + .resume = bma085_resume, + .read = bma085_read, + .config = NULL, + .get_config = NULL, + .name = "bma085", + .type = EXT_SLAVE_TYPE_PRESSURE, + .id = PRESSURE_ID_BMA085, + .read_reg = 0xF6, + .read_len = 3, + .endian = EXT_SLAVE_BIG_ENDIAN, + .range = {0, 0}, +}; + +static +struct ext_slave_descr *bma085_get_slave_descr(void) +{ + return &bma085_descr; +} + +/* Platform data for the MPU */ +struct bma085_mod_private_data { + struct i2c_client *client; + struct ext_slave_platform_data *pdata; +}; + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int bma085_mod_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct ext_slave_platform_data *pdata; + struct bma085_mod_private_data *private_data; + int result = 0; + + dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + result = -ENODEV; + goto out_no_free; + } + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->adapter->dev, + "Missing platform data for slave %s\n", devid->name); + result = -EFAULT; + goto out_no_free; + } + + private_data = kzalloc(sizeof(*private_data), GFP_KERNEL); + if (!private_data) { + result = -ENOMEM; + goto out_no_free; + } + + i2c_set_clientdata(client, private_data); + private_data->client = client; + private_data->pdata = pdata; + + result = inv_mpu_register_slave(THIS_MODULE, client, pdata, + bma085_get_slave_descr); + if (result) { + dev_err(&client->adapter->dev, + "Slave registration failed: %s, %d\n", + devid->name, result); + goto out_free_memory; + } + + return result; + +out_free_memory: + kfree(private_data); +out_no_free: + dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result); + return result; + +} + +static int bma085_mod_remove(struct i2c_client *client) +{ + struct bma085_mod_private_data *private_data = + i2c_get_clientdata(client); + + dev_dbg(&client->adapter->dev, "%s\n", __func__); + + inv_mpu_unregister_slave(client, private_data->pdata, + bma085_get_slave_descr); + + kfree(private_data); + return 0; +} + +static const struct i2c_device_id bma085_mod_id[] = { + { "bma085", PRESSURE_ID_BMA085 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bma085_mod_id); + +static struct i2c_driver bma085_mod_driver = { + .class = I2C_CLASS_HWMON, + .probe = bma085_mod_probe, + .remove = bma085_mod_remove, + .id_table = bma085_mod_id, + .driver = { + .owner = THIS_MODULE, + .name = "bma085_mod", + }, + .address_list = normal_i2c, +}; + +static int __init bma085_mod_init(void) +{ + int res = i2c_add_driver(&bma085_mod_driver); + pr_info("%s: Probe name %s\n", __func__, "bma085_mod"); + if (res) + pr_err("%s failed\n", __func__); + return res; +} + +static void __exit bma085_mod_exit(void) +{ + pr_info("%s\n", __func__); + i2c_del_driver(&bma085_mod_driver); +} + +module_init(bma085_mod_init); +module_exit(bma085_mod_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Driver to integrate BMA085 sensor with the MPU"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("bma085_mod"); +/** + * @} +**/ diff --git a/drivers/misc/inv_mpu/slaveirq.c b/drivers/misc/inv_mpu/slaveirq.c new file mode 100755 index 000000000000..95e690ee60cb --- /dev/null +++ b/drivers/misc/inv_mpu/slaveirq.c @@ -0,0 +1,266 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "slaveirq.h" +#include "mldl_cfg.h" + +/* function which gets slave data and sends it to SLAVE */ + +struct slaveirq_dev_data { + struct miscdevice dev; + struct i2c_client *slave_client; + struct mpuirq_data data; + wait_queue_head_t slaveirq_wait; + int irq; + int pid; + int data_ready; + int timeout; +}; + +/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 + * drivers: misc: pass miscdevice pointer via file private data + */ +static int slaveirq_open(struct inode *inode, struct file *file) +{ + /* Device node is availabe in the file->private_data, this is + * exactly what we want so we leave it there */ + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + dev_dbg(data->dev.this_device, + "%s current->pid %d\n", __func__, current->pid); + data->pid = current->pid; + return 0; +} + +static int slaveirq_release(struct inode *inode, struct file *file) +{ + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + dev_dbg(data->dev.this_device, "slaveirq_release\n"); + return 0; +} + +/* read function called when from /dev/slaveirq is read */ +static ssize_t slaveirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + if (!data->data_ready && data->timeout && + !(file->f_flags & O_NONBLOCK)) { + wait_event_interruptible_timeout(data->slaveirq_wait, + data->data_ready, + data->timeout); + } + + if (data->data_ready && NULL != buf && count >= sizeof(data->data)) { + err = copy_to_user(buf, &data->data, sizeof(data->data)); + data->data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(data->dev.this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + data->data_ready = 0; + len = sizeof(data->data); + return len; +} + +static unsigned int slaveirq_poll(struct file *file, + struct poll_table_struct *poll) +{ + int mask = 0; + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + poll_wait(file, &data->slaveirq_wait, poll); + if (data->data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long slaveirq_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int tmp; + struct slaveirq_dev_data *data = + container_of(file->private_data, struct slaveirq_dev_data, dev); + + switch (cmd) { + case SLAVEIRQ_SET_TIMEOUT: + data->timeout = arg; + break; + + case SLAVEIRQ_GET_INTERRUPT_CNT: + tmp = data->data.interruptcount - 1; + if (data->data.interruptcount > 1) + data->data.interruptcount = 1; + + if (copy_to_user((int *)arg, &tmp, sizeof(int))) + return -EFAULT; + break; + case SLAVEIRQ_GET_IRQ_TIME: + if (copy_to_user((int *)arg, &data->data.irqtime, + sizeof(data->data.irqtime))) + return -EFAULT; + data->data.irqtime = 0; + break; + default: + retval = -EINVAL; + } + return retval; +} + +static irqreturn_t slaveirq_handler(int irq, void *dev_id) +{ + struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id; + static int mycount; + struct timeval irqtime; + mycount++; + + data->data.interruptcount++; + + /* wake up (unblock) for reading data from userspace */ + data->data_ready = 1; + + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long)irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; + + wake_up_interruptible(&data->slaveirq_wait); + + return IRQ_HANDLED; + +} + +/* define which file operations are supported */ +static const struct file_operations slaveirq_fops = { + .owner = THIS_MODULE, + .read = slaveirq_read, + .poll = slaveirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = slaveirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = slaveirq_ioctl, +#endif + .open = slaveirq_open, + .release = slaveirq_release, +}; + +int slaveirq_init(struct i2c_adapter *slave_adapter, + struct ext_slave_platform_data *pdata, char *name) +{ + + int res; + struct slaveirq_dev_data *data; + + if (!pdata->irq) + return -EINVAL; + + pdata->irq_data = kzalloc(sizeof(*data), GFP_KERNEL); + data = (struct slaveirq_dev_data *)pdata->irq_data; + if (!data) + return -ENOMEM; + + data->dev.minor = MISC_DYNAMIC_MINOR; + data->dev.name = name; + data->dev.fops = &slaveirq_fops; + data->irq = pdata->irq; + data->pid = 0; + data->data_ready = 0; + data->timeout = 0; + + init_waitqueue_head(&data->slaveirq_wait); + + res = request_irq(data->irq, slaveirq_handler, + IRQF_TRIGGER_RISING | IRQF_SHARED, + data->dev.name, data); + + if (res) { + dev_err(&slave_adapter->dev, + "myirqtest: cannot register IRQ %d\n", data->irq); + goto out_request_irq; + } + + res = misc_register(&data->dev); + if (res < 0) { + dev_err(&slave_adapter->dev, + "misc_register returned %d\n", res); + goto out_misc_register; + } + + return res; + +out_misc_register: + free_irq(data->irq, data); +out_request_irq: + kfree(pdata->irq_data); + pdata->irq_data = NULL; + + return res; +} + +void slaveirq_exit(struct ext_slave_platform_data *pdata) +{ + struct slaveirq_dev_data *data = pdata->irq_data; + + if (!pdata->irq_data || data->irq <= 0) + return; + + dev_info(data->dev.this_device, "Unregistering %s\n", data->dev.name); + + free_irq(data->irq, data); + misc_deregister(&data->dev); + kfree(pdata->irq_data); + pdata->irq_data = NULL; +} diff --git a/drivers/misc/inv_mpu/slaveirq.h b/drivers/misc/inv_mpu/slaveirq.h new file mode 100644 index 000000000000..6926634ff94c --- /dev/null +++ b/drivers/misc/inv_mpu/slaveirq.h @@ -0,0 +1,36 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +#ifndef __SLAVEIRQ__ +#define __SLAVEIRQ__ + +#include + +#include +#include "mpuirq.h" + +#define SLAVEIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x50, unsigned long) +#define SLAVEIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x51, unsigned long) +#define SLAVEIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x52, unsigned long) + +void slaveirq_exit(struct ext_slave_platform_data *pdata); +int slaveirq_init(struct i2c_adapter *slave_adapter, + struct ext_slave_platform_data *pdata, char *name); + +#endif diff --git a/drivers/misc/inv_mpu/timerirq.c b/drivers/misc/inv_mpu/timerirq.c new file mode 100755 index 000000000000..601858f9c4d5 --- /dev/null +++ b/drivers/misc/inv_mpu/timerirq.c @@ -0,0 +1,296 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mltypes.h" +#include "timerirq.h" + +/* function which gets timer data and sends it to TIMER */ +struct timerirq_data { + int pid; + int data_ready; + int run; + int timeout; + unsigned long period; + struct mpuirq_data data; + struct completion timer_done; + wait_queue_head_t timerirq_wait; + struct timer_list timer; + struct miscdevice *dev; +}; + +static struct miscdevice *timerirq_dev_data; + +static void timerirq_handler(unsigned long arg) +{ + struct timerirq_data *data = (struct timerirq_data *)arg; + struct timeval irqtime; + + data->data.interruptcount++; + + data->data_ready = 1; + + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long)irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; + + dev_dbg(data->dev->this_device, + "%s, %lld, %ld\n", __func__, data->data.irqtime, + (unsigned long)data); + + wake_up_interruptible(&data->timerirq_wait); + + if (data->run) + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); + else + complete(&data->timer_done); +} + +static int start_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + + /* Timer already running... success */ + if (data->run) + return 0; + + /* Don't allow a period of 0 since this would fire constantly */ + if (!data->period) + return -EINVAL; + + data->run = true; + data->data_ready = false; + + init_completion(&data->timer_done); + setup_timer(&data->timer, timerirq_handler, (unsigned long)data); + + return mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); +} + +static int stop_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %lx\n", __func__, (unsigned long)data); + + if (data->run) { + data->run = false; + mod_timer(&data->timer, jiffies + 1); + wait_for_completion(&data->timer_done); + } + return 0; +} + +/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 + * drivers: misc: pass miscdevice pointer via file private data + */ +static int timerirq_open(struct inode *inode, struct file *file) +{ + /* Device node is availabe in the file->private_data, this is + * exactly what we want so we leave it there */ + struct miscdevice *dev_data = file->private_data; + struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev_data; + file->private_data = data; + data->pid = current->pid; + init_waitqueue_head(&data->timerirq_wait); + + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + return 0; +} + +static int timerirq_release(struct inode *inode, struct file *file) +{ + struct timerirq_data *data = file->private_data; + dev_dbg(data->dev->this_device, "timerirq_release\n"); + if (data->run) + stop_timerirq(data); + kfree(data); + return 0; +} + +/* read function called when from /dev/timerirq is read */ +static ssize_t timerirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct timerirq_data *data = file->private_data; + + if (!data->data_ready && data->timeout && + !(file->f_flags & O_NONBLOCK)) { + wait_event_interruptible_timeout(data->timerirq_wait, + data->data_ready, + data->timeout); + } + + if (data->data_ready && NULL != buf && count >= sizeof(data->data)) { + err = copy_to_user(buf, &data->data, sizeof(data->data)); + data->data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(data->dev->this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + data->data_ready = 0; + len = sizeof(data->data); + return len; +} + +static unsigned int timerirq_poll(struct file *file, + struct poll_table_struct *poll) +{ + int mask = 0; + struct timerirq_data *data = file->private_data; + + poll_wait(file, &data->timerirq_wait, poll); + if (data->data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long timerirq_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int tmp; + struct timerirq_data *data = file->private_data; + + dev_dbg(data->dev->this_device, + "%s current->pid %d, %d, %ld\n", + __func__, current->pid, cmd, arg); + + if (!data) + return -EFAULT; + + switch (cmd) { + case TIMERIRQ_SET_TIMEOUT: + data->timeout = arg; + break; + case TIMERIRQ_GET_INTERRUPT_CNT: + tmp = data->data.interruptcount - 1; + if (data->data.interruptcount > 1) + data->data.interruptcount = 1; + + if (copy_to_user((int *)arg, &tmp, sizeof(int))) + return -EFAULT; + break; + case TIMERIRQ_START: + data->period = arg; + retval = start_timerirq(data); + break; + case TIMERIRQ_STOP: + retval = stop_timerirq(data); + break; + default: + retval = -EINVAL; + } + return retval; +} + +/* define which file operations are supported */ +static const struct file_operations timerirq_fops = { + .owner = THIS_MODULE, + .read = timerirq_read, + .poll = timerirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = timerirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = timerirq_ioctl, +#endif + .open = timerirq_open, + .release = timerirq_release, +}; + +static int __init timerirq_init(void) +{ + + int res; + static struct miscdevice *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + timerirq_dev_data = data; + data->minor = MISC_DYNAMIC_MINOR; + data->name = "timerirq"; + data->fops = &timerirq_fops; + + res = misc_register(data); + if (res < 0) { + dev_err(data->this_device, "misc_register returned %d\n", res); + return res; + } + + return res; +} + +module_init(timerirq_init); + +static void __exit timerirq_exit(void) +{ + struct miscdevice *data = timerirq_dev_data; + + dev_info(data->this_device, "Unregistering %s\n", data->name); + + misc_deregister(data); + kfree(data); + + timerirq_dev_data = NULL; +} + +module_exit(timerirq_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Timer IRQ device driver."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("timerirq"); diff --git a/drivers/misc/inv_mpu/timerirq.h b/drivers/misc/inv_mpu/timerirq.h new file mode 100644 index 000000000000..f69f07a45a3b --- /dev/null +++ b/drivers/misc/inv_mpu/timerirq.h @@ -0,0 +1,30 @@ +/* + $License: + Copyright (C) 2011 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 . + $ + */ + +#ifndef __TIMERIRQ__ +#define __TIMERIRQ__ + +#include + +#define TIMERIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x60, unsigned long) +#define TIMERIRQ_GET_INTERRUPT_CNT _IOW(MPU_IOCTL, 0x61, unsigned long) +#define TIMERIRQ_START _IOW(MPU_IOCTL, 0x62, unsigned long) +#define TIMERIRQ_STOP _IO(MPU_IOCTL, 0x63) + +#endif diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig deleted file mode 100755 index 210953f35095..000000000000 --- a/drivers/misc/mpu3050/Kconfig +++ /dev/null @@ -1,213 +0,0 @@ - -menu "Motion Sensors Support" - -choice - tristate "Motion Processing Unit" - depends on I2C - default MPU_NONE - -config MPU_NONE - bool "None" - help - This disables support for motion processing using the MPU family of - motion processing units. - -config MPU_SENSORS_MPU3050 - tristate "MPU3050" - 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 MPU_SENSORS_MPU6000 - tristate "MPU6000" - depends on I2C - help - If you say yes here you get support for the MPU6000 Gyroscope driver - This driver can also be built as a module. If so, the module - will be called mpu6000. - -endchoice - -choice - prompt "Accelerometer Type" - depends on MPU_SENSORS_MPU3050 - default MPU_SENSORS_BMA150 - -config MPU_SENSORS_ACCELEROMETER_NONE - bool "NONE" - depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000 - help - This disables accelerometer support for the MPU3050 - -config MPU_SENSORS_ADXL346 - bool "ADI adxl346" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the ADI adxl346 accelerometer - -config MPU_SENSORS_BMA150 - bool "Bosch BMA150" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Bosch BMA150 accelerometer - -config MPU_SENSORS_BMA222 - bool "Bosch BMA222" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Bosch BMA222 accelerometer - -config MPU_SENSORS_KXSD9 - bool "Kionix KXSD9" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Kionix KXSD9 accelerometer - -config MPU_SENSORS_KXTF9 - bool "Kionix KXTF9" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Kionix KXFT9 accelerometer - -config MPU_SENSORS_LIS331DLH - bool "ST lis331dlh" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the ST lis331dlh accelerometer - -config MPU_SENSORS_LIS3DH - bool "ST lis3dh" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the ST lis3dh accelerometer - -config MPU_SENSORS_LSM303DLHA - bool "ST lsm303dlh" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the ST lsm303dlh accelerometer - -config MPU_SENSORS_MMA8450 - bool "Freescale mma8450" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Freescale mma8450 accelerometer - -config MPU_SENSORS_MMA845X - bool "Freescale mma8451/8452/8453" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Freescale mma8451/8452/8453 accelerometer - -endchoice - -choice - prompt "Compass Type" - depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 - default MPU_SENSORS_AK8975 - -config MPU_SENSORS_COMPASS_NONE - bool "NONE" - depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 - help - This disables compass support for the MPU6000 - -config MPU_SENSORS_AK8975 - bool "AKM ak8975" - depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 - help - This enables support for the AKM ak8975 compass - -config MPU_SENSORS_MMC314X - bool "MEMSIC mmc314x" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the MEMSIC mmc314x compass - -config MPU_SENSORS_AMI30X - bool "Aichi Steel ami30X" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Aichi Steel ami304/ami305 compass - -config MPU_SENSORS_AMI306 - bool "Aichi Steel ami306" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Aichi Steel ami306 compass - -config MPU_SENSORS_HMC5883 - bool "Honeywell hmc5883" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Honeywell hmc5883 compass - -config MPU_SENSORS_LSM303DLHM - bool "ST lsm303dlh" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the ST lsm303dlh compass - -config MPU_SENSORS_MMC314X - bool "MEMSIC mmc314xMS" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the MEMSIC mmc314xMS compass - -config MPU_SENSORS_YAS529 - bool "Yamaha yas529" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Yamaha yas529 compass - -config MPU_SENSORS_YAS530 - bool "Yamaha yas530" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Yamaha yas530 compass - -config MPU_SENSORS_HSCDTD002B - bool "Alps hscdtd002b" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Alps hscdtd002b compass - -config MPU_SENSORS_HSCDTD004A - bool "Alps hscdtd004a" - depends on MPU_SENSORS_MPU3050 - help - This enables support for the Alps hscdtd004a compass - -endchoice - -choice - prompt "Pressure Type" - depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 - default MPU_SENSORS_BMA085 - -config MPU_SENSORS_PRESSURE_NONE - bool "NONE" - depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 - help - This disables pressure sensor support for the MPU6000 - -config MPU_SENSORS_BMA085 - bool "Bosch BMA085" - depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 - help - This enables support for the Bosch bma085 pressure sensor - -endchoice - -config MPU_SENSORS_TIMERIRQ - tristate "Timer IRQ" - help - If you say yes here you get access to the timerirq device handle which - can be used to select on. This can be used instead of IRQ's, sleeping, - or timer threads. Reading from this device returns the same type of - information as reading from the MPU and slave IRQ's. - -endmenu - diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile deleted file mode 100755 index 935915ad01dc..000000000000 --- a/drivers/misc/mpu3050/Makefile +++ /dev/null @@ -1,132 +0,0 @@ - -# Kernel makefile for motions sensors -# -# - -# MPU -obj-$(CONFIG_MPU_SENSORS_MPU3050) += mpu3050.o -mpu3050-objs += mpuirq.o \ - slaveirq.o \ - mpu-dev.o \ - mpu-i2c.o \ - mlsl-kernel.o \ - mlos-kernel.o \ - $(MLLITE_DIR)mldl_cfg.o - -# -# Accel options -# -ifdef CONFIG_MPU_SENSORS_ADXL346 -mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o -endif - -ifdef CONFIG_MPU_SENSORS_BMA150 -mpu3050-objs += $(MLLITE_DIR)accel/bma150.o -endif - -ifdef CONFIG_MPU_SENSORS_BMA222 -mpu3050-objs += $(MLLITE_DIR)accel/bma222.o -endif - -ifdef CONFIG_MPU_SENSORS_KXSD9 -mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o -endif - -ifdef CONFIG_MPU_SENSORS_KXTF9 -mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o -endif - -ifdef CONFIG_MPU_SENSORS_LIS331DLH -mpu3050-objs += $(MLLITE_DIR)accel/lis331.o -endif - -ifdef CONFIG_MPU_SENSORS_LIS3DH -mpu3050-objs += $(MLLITE_DIR)accel/lis3dh.o -endif - -ifdef CONFIG_MPU_SENSORS_LSM303DLHA -mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o -endif - -ifdef CONFIG_MPU_SENSORS_MMA8450 -mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o -endif - -ifdef CONFIG_MPU_SENSORS_MMA845X -mpu3050-objs += $(MLLITE_DIR)accel/mma845x.o -endif - -# -# Compass options -# -ifdef CONFIG_MPU_SENSORS_AK8975 -mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o -endif - -ifdef CONFIG_MPU_SENSORS_AMI30X -mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o -endif - -ifdef CONFIG_MPU_SENSORS_AMI306 -mpu3050-objs += $(MLLITE_DIR)compass/ami306.o -endif - -ifdef CONFIG_MPU_SENSORS_HMC5883 -mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o -endif - -ifdef CONFIG_MPU_SENSORS_LSM303DLHM -mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o -endif - -ifdef CONFIG_MPU_SENSORS_MMC314X -mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o -endif - -ifdef CONFIG_MPU_SENSORS_YAS529 -mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o -endif - -ifdef CONFIG_MPU_SENSORS_YAS530 -mpu3050-objs += $(MLLITE_DIR)compass/yas530.o -endif - -ifdef CONFIG_MPU_SENSORS_HSCDTD002B -mpu3050-objs += $(MLLITE_DIR)compass/hscdtd002b.o -endif - -ifdef CONFIG_MPU_SENSORS_HSCDTD004A -mpu3050-objs += $(MLLITE_DIR)compass/hscdtd004a.o -endif -# -# Pressure options -# -ifdef CONFIG_MPU_SENSORS_BMA085 -mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o -endif - -EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \ - -I$(M)/../../include \ - -Idrivers/misc/mpu3050 \ - -Iinclude/linux - -obj-$(CONFIG_MPU_SENSORS_MPU6000)+= mpu6000.o -mpu6000-objs += mpuirq.o \ - slaveirq.o \ - mpu-dev.o \ - mpu-i2c.o \ - mlsl-kernel.o \ - mlos-kernel.o \ - $(MLLITE_DIR)mldl_cfg.o \ - $(MLLITE_DIR)accel/mantis.o - -ifdef CONFIG_MPU_SENSORS_AK8975 -mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o -endif - -ifdef CONFIG_MPU_SENSORS_MPU6000 -EXTRA_CFLAGS += -DM_HW -endif - -obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o - diff --git a/drivers/misc/mpu3050/README b/drivers/misc/mpu3050/README deleted file mode 100755 index 047b6ba37c1d..000000000000 --- a/drivers/misc/mpu3050/README +++ /dev/null @@ -1,270 +0,0 @@ -Kernel driver mpu -===================== - -Supported chips: - * InvenSense IMU3050 - Prefix: 'mpu3050' - Datasheet: - PS-MPU-3000A-00.2.4b.pdf - - * InvenSense IMU6000 - Prefix: 'mpu6000' - Datasheet: - MPU-6000A-00 v1.0.pdf - -Author: InvenSense - -Description ------------ -The mpu is a motion processor unit that controls the mpu3050 gyroscope, a slave -accelerometer, a compass and a pressure sensor, or the mpu6000 and slave -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 -/dev/accelirq -/dev/compassirq -/dev/pressureirq - -General Remarks MPU3050 ------------------------ -* Valid addresses for the MPU3050 is 0x68. -* Accelerometer must be on the secondary I2C bus for MPU3050, the - magnetometer must be on the primary bus and pressure sensor must - be on the primary bus. - -General Remarks MPU6000 ------------------------ -* Valid addresses for the MPU6000 is 0x68. -* Magnetometer must be on the secondary I2C bus for the MPU6000. -* Accelerometer slave address must be set to 0x68 -* Gyro and Accel orientation matrices should be the same - -Programming the chip using /dev/mpu ----------------------------------- -Programming of MPU3050 or MPU6000 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 mpu.h. Typically this is done by the mllite library in user -space. - -Adding to a Kernel -================== - -The mpu driver is designed to be inserted in the drivers/misc part of the -kernel. Extracting the tarball from the root kernel dir will place the -contents of the tarball here: - - /drivers/misc/mpu3050 - /include/linux/mpu.h - /include/linux/mpu3050.h - /include/linux/mpu6000.h - -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. - -NOTE: This driver depends on a kernel patch to drivers/char/char.c. This patch -started to be included in most 2.6.35 based kernels. -drivers: misc: pass miscdevice pointer via file private data -https://patchwork.kernel.org/patch/96412/ - ---- - drivers/char/misc.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - - -diff --git a/drivers/char/misc.c b/drivers/char/misc.c -index 92ab03d..cd650ca 100644 ---- a/drivers/char/misc.c -+++ b/drivers/char/misc.c -@@ -144,6 +144,7 @@ static int misc_open(struct inode * inode, struct file * file) - old_fops = file->f_op; - file->f_op = new_fops; - if (file->f_op->open) { -+ file->private_data = c; - err=file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); ---- - -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 populated and set in the i2c_board_info_structure. For details -of each structure member see mpu.h. All values below are simply an example and -should be modified for your platform. - -#include - -#if defined(CONFIG_MPU_SENSORS_MPU3050) || defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) - -#define SENSOR_MPU_NAME "mpu3050" - -static struct mpu3050_platform_data mpu_data = { - .int_config = 0x10, - .orientation = { -1, 0, 0, - 0, 1, 0, - 0, 0, -1 }, - /* accel */ - .accel = { -#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE - .get_slave_descr = NULL, -#else - .get_slave_descr = get_accel_slave_descr, -#endif - .adapt_num = 2, - .bus = EXT_SLAVE_BUS_SECONDARY, - .address = 0x0F, - .orientation = { -1, 0, 0, - 0, 1, 0, - 0, 0, -1 }, - }, - /* compass */ - .compass = { -#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE - .get_slave_descr = NULL, -#else - .get_slave_descr = get_compass_slave_descr, -#endif - .adapt_num = 2, - .bus = EXT_SLAVE_BUS_PRIMARY, - .address = 0x0E, - .orientation = { 1, 0, 0, - 0, 1, 0, - 0, 0, 1 }, - }, - /* pressure */ - .pressure = { -#ifdef CONFIG_MPU_SENSORS_MPU3050_MODULE - .get_slave_descr = NULL, -#else - .get_slave_descr = get_pressure_slave_descr, -#endif - .adapt_num = 2, - .bus = EXT_SLAVE_BUS_PRIMARY, - .address = 0x77, - .orientation = { 1, 0, 0, - 0, 1, 0, - 0, 0, 1 }, - }, -}; -#endif - -#if defined(CONFIG_MPU_SENSORS_MPU6000) || defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) - -#define SENSOR_MPU_NAME "mpu6000" - -static struct mpu3050_platform_data mpu_data = { - .int_config = 0x10, - .orientation = { -1, 0, 0, - 0, 1, 0, - 0, 0, -1 }, - /* accel */ - .accel = { -#ifdef CONFIG_MPU_SENSORS_MPU6000_MODULE - .get_slave_descr = NULL, -#else - .get_slave_descr = get_accel_slave_descr, -#endif - .adapt_num = 2, - .bus = EXT_SLAVE_BUS_PRIMARY, - .address = 0x68, - .orientation = { -1, 0, 0, - 0, 1, 0, - 0, 0, -1 }, - }, - /* compass */ - .compass = { -#ifdef CONFIG_MPU_SENSORS_MPU6000_MODULE - .get_slave_descr = NULL, -#else - .get_slave_descr = get_compass_slave_descr, -#endif - .adapt_num = 2, - .bus = EXT_SLAVE_BUS_SECONDARY, - .address = 0x0E, - .orientation = { 1, 0, 0, - 0, 1, 0, - 0, 0, 1 }, - }, - /* pressure */ - .pressure = { -#ifdef CONFIG_MPU_SENSORS_MPU6000_MODULE - .get_slave_descr = NULL, -#else - .get_slave_descr = get_pressure_slave_descr, -#endif - .adapt_num = 2, - .bus = EXT_SLAVE_BUS_PRIMARY, - .address = 0x77, - .orientation = { 1, 0, 0, - 0, 1, 0, - 0, 0, 1 }, - }, - -}; -#endif - -static struct i2c_board_info __initdata beagle_i2c_2_boardinfo[] = { - { - I2C_BOARD_INFO(SENSOR_MPU_NAME, 0x68), - .irq = (IH_GPIO_BASE + MPU_GPIO_IRQ), - .platform_data = &mpu_data, - }, -}; - -Typically the IRQ is a GPIO input pin and needs to be configured properly. If -in the above example GPIO 168 corresponds to IRQ 299, the following should be -done as well: - -#define MPU_GPIO_IRQ 168 - - gpio_request(MPU_GPIO_IRQ,"MPUIRQ"); - gpio_direction_input(MPU_GPIO_IRQ) - -NOTE: -===== -In previous releases, the sensors were defined using CONFIG_SENSORS_SENSORNAME convention. -From this release onwards this convention will be changed to CONFIG_MPU_SENSORS_SENSORNAME. -Please make note of this change. - -Dynamic Debug -============= - -The mpu3050 makes use of dynamic debug. For details on how to use this -refer to Documentation/dynamic-debug-howto.txt - -Android File Permissions -======================== - -To set up the file permissions on an android system, the /dev/mpu and -/dev/mpuirq files needs to be added to the system/core/init/devices.c file -inside the perms_ structure. - -static struct perms_ devperms[] = { - { "/dev/mpu" ,0660, AID_SYSTEM, AID_SYSTEM, 1 }, -}; - -Sufficient file permissions need to be give to read and write it by the system. - -For gingerbread and later the system/core/rootdir/ueventd.rc file needs to be -modified with the appripriate lines added. - -# MPU sensors and IRQ -/dev/mpu 0660 system system -/dev/mpuirq 0660 system system -/dev/accelirq 0660 system system -/dev/compassirq 0660 system system -/dev/pressureirq 0660 system system diff --git a/drivers/misc/mpu3050/accel/adxl346.c b/drivers/misc/mpu3050/accel/adxl346.c deleted file mode 100755 index 14cb38a829ee..000000000000 --- a/drivers/misc/mpu3050/accel/adxl346.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 adxl346.c - * @brief Accelerometer setup and handling methods for AD adxl346. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -#define ACCEL_ADI346_SLEEP_REG (0x2D) -#define ACCEL_ADI346_SLEEP_MASK (0x04) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int adxl346_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - result = - MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_ADI346_SLEEP_REG, 1, ®); - ERROR_CHECK(result); - reg |= ACCEL_ADI346_SLEEP_MASK; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_ADI346_SLEEP_REG, reg); - ERROR_CHECK(result); - return result; -} - -/* full scale setting - register & mask */ -#define ACCEL_ADI346_CTRL_REG (0x31) -#define ACCEL_ADI346_CTRL_MASK (0x03) - -int adxl346_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_ADI346_SLEEP_REG, 1, ®); - ERROR_CHECK(result); - reg &= ~ACCEL_ADI346_SLEEP_MASK; - /*wake up if sleeping */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_ADI346_SLEEP_REG, reg); - ERROR_CHECK(result); - /*MLOSSleep(10) */ - - /* Full Scale */ - reg = 0x04; - reg &= ~ACCEL_ADI346_CTRL_MASK; - if (slave->range.mantissa == 4) - reg |= 0x1; - else if (slave->range.mantissa == 8) - reg |= 0x2; - else if (slave->range.mantissa == 16) - reg |= 0x3; - else { - slave->range.mantissa = 2; - reg |= 0x0; - } - slave->range.fraction = 0; - - /* DATA_FORMAT: full resolution of +/-2g; data is left justified */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x31, reg); - ERROR_CHECK(result); - /* BW_RATE: normal power operation with output data rate of 200Hz */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x2C, 0x0B); - ERROR_CHECK(result); - /* POWER_CTL: power on in measurement mode */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x2D, 0x28); - ERROR_CHECK(result); - /*--- after wake up, it takes at least [1/(data rate) + 1.1]ms ==> - 6.1ms to get valid sensor data ---*/ - MLOSSleep(10); - - return result; -} - -int adxl346_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -struct ext_slave_descr adxl346_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ adxl346_suspend, - /*.resume = */ adxl346_resume, - /*.read = */ adxl346_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "adx1346", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_ADI346, - /*.reg = */ 0x32, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *adxl346_get_slave_descr(void) -{ - return &adxl346_descr; -} -EXPORT_SYMBOL(adxl346_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/bma150.c b/drivers/misc/mpu3050/accel/bma150.c deleted file mode 100755 index 30fed1564850..000000000000 --- a/drivers/misc/mpu3050/accel/bma150.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 bma150.c - * @brief Accelerometer setup and handling methods. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlos.h" -#include "mlsl.h" - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/********************************************* - Accelerometer Initialization Functions -**********************************************/ - -static int bma150_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0a, 0x01); - MLOSSleep(3); /* 3 ms powerup time maximum */ - ERROR_CHECK(result); - return result; -} - -/* full scale setting - register and mask */ -#define ACCEL_BOSCH_CTRL_REG (0x14) -#define ACCEL_BOSCH_CTRL_MASK (0x18) - -static int bma150_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg = 0; - - /* Soft reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0a, 0x02); - ERROR_CHECK(result); - MLOSSleep(3); - - result = - MLSLSerialRead(mlsl_handle, pdata->address, 0x14, 1, ®); - ERROR_CHECK(result); - - /* Bandwidth */ - reg &= 0xc0; - reg |= 3; /* 3=190 Hz */ - - /* Full Scale */ - reg &= ~ACCEL_BOSCH_CTRL_MASK; - if (slave->range.mantissa == 4) - reg |= 0x08; - else if (slave->range.mantissa == 8) - reg |= 0x10; - else { - slave->range.mantissa = 2; - reg |= 0x00; - } - slave->range.fraction = 0; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x14, reg); - ERROR_CHECK(result); - - return result; -} - -static int bma150_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -static struct ext_slave_descr bma150_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ bma150_suspend, - /*.resume = */ bma150_resume, - /*.read = */ bma150_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "bma150", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_BMA150, - /*.reg = */ 0x02, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *bma150_get_slave_descr(void) -{ - return &bma150_descr; -} -EXPORT_SYMBOL(bma150_get_slave_descr); - -#ifdef __KERNEL__ -MODULE_AUTHOR("Invensense"); -MODULE_DESCRIPTION("User space IRQ handler for MPU3xxx devices"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("bma"); -#endif - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/accel/bma222.c b/drivers/misc/mpu3050/accel/bma222.c deleted file mode 100755 index 534a1e5fa64b..000000000000 --- a/drivers/misc/mpu3050/accel/bma222.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - $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 . - $ - */ - -/* - * @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 bma222.c - * @brief Accelerometer setup and handling methods. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlos.h" -#include "mlsl.h" - -#define ACCEL_BMA222_RANGE_REG (0x0F) -#define ACCEL_BMA222_BW_REG (0x10) -#define ACCEL_BMA222_SUSPEND_REG (0x11) -#define ACCEL_BMA222_SFT_RST_REG (0x14) - -/********************************************* - Accelerometer Initialization Functions -**********************************************/ - -static int bma222_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_BMA222_SUSPEND_REG, 0x80); - ERROR_CHECK(result); - - return result; -} - -static int bma222_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg = 0; - - /* Soft reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_BMA222_SFT_RST_REG, 0xB6); - ERROR_CHECK(result); - MLOSSleep(10); - - /*Bandwidth */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_BMA222_BW_REG, 0x0C); - ERROR_CHECK(result); - - /* Full Scale */ - if (slave->range.mantissa == 4) - reg |= 0x05; - else if (slave->range.mantissa == 8) - reg |= 0x08; - else if (slave->range.mantissa == 16) - reg |= 0x0C; - else { - slave->range.mantissa = 2; - reg |= 0x03; - } - slave->range.fraction = 0; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_BMA222_RANGE_REG, reg); - ERROR_CHECK(result); - - return result; -} - -static int bma222_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -static struct ext_slave_descr bma222_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ bma222_suspend, - /*.resume = */ bma222_resume, - /*.read = */ bma222_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "bma222", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_BMA222, - /*.reg = */ 0x02, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *bma222_get_slave_descr(void) -{ - return &bma222_descr; -} -EXPORT_SYMBOL(bma222_get_slave_descr); - -/* - * @} - */ diff --git a/drivers/misc/mpu3050/accel/cma3000.c b/drivers/misc/mpu3050/accel/cma3000.c deleted file mode 100755 index 05925951c628..000000000000 --- a/drivers/misc/mpu3050/accel/cma3000.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 cma3000.c - * @brief Accelerometer setup and handling methods for VTI CMA3000 - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" -#include "accel.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int cma3000_suspend(void *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; -} - -int cma3000_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - - - return ML_SUCCESS; -} - -int cma3000_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -struct ext_slave_descr cma3000_descr = { - /*.suspend = */ cma3000_suspend, - /*.resume = */ cma3000_resume, - /*.read = */ cma3000_read, - /*.name = */ "cma3000", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ID_INVALID, - /* fixme - id to added when support becomes available */ - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ 65536, -}; - -struct ext_slave_descr *cma3000_get_slave_descr(void) -{ - return &cma3000_descr; -} -EXPORT_SYMBOL(cma3000_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/kxsd9.c b/drivers/misc/mpu3050/accel/kxsd9.c deleted file mode 100755 index 77bc52c8e586..000000000000 --- a/drivers/misc/mpu3050/accel/kxsd9.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 kxsd9.c - * @brief Accelerometer setup and handling methods. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -static int kxsd9_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - /* CTRL_REGB: low-power standby mode */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0d, 0x0); - ERROR_CHECK(result); - return result; -} - -/* full scale setting - register and mask */ -#define ACCEL_KIONIX_CTRL_REG (0x0C) -#define ACCEL_KIONIX_CTRL_MASK (0x3) - -static int kxsd9_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - - /* Full Scale */ - reg = 0x0; - reg &= ~ACCEL_KIONIX_CTRL_MASK; - reg |= 0x00; - if (slave->range.mantissa == 4) { /* 4g scale = 4.9951 */ - reg |= 0x2; - slave->range.fraction = 9951; - } else if (slave->range.mantissa == 7) { /* 6g scale = 7.5018 */ - reg |= 0x1; - slave->range.fraction = 5018; - } else if (slave->range.mantissa == 9) { /* 8g scale = 9.9902 */ - reg |= 0x0; - slave->range.fraction = 9902; - } else { - slave->range.mantissa = 2; /* 2g scale = 2.5006 */ - slave->range.fraction = 5006; - reg |= 0x3; - } - reg |= 0xC0; /* 100Hz LPF */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_KIONIX_CTRL_REG, reg); - ERROR_CHECK(result); - /* normal operation */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0d, 0x40); - ERROR_CHECK(result); - - return ML_SUCCESS; -} - -static int kxsd9_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -static struct ext_slave_descr kxsd9_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ kxsd9_suspend, - /*.resume = */ kxsd9_resume, - /*.read = */ kxsd9_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "kxsd9", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_KXSD9, - /*.reg = */ 0x00, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {2, 5006}, -}; - -struct ext_slave_descr *kxsd9_get_slave_descr(void) -{ - return &kxsd9_descr; -} -EXPORT_SYMBOL(kxsd9_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c deleted file mode 100755 index e2490af1ca77..000000000000 --- a/drivers/misc/mpu3050/accel/kxtf9.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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. - */ -/* ------------------ */ - -#undef MPL_LOG_NDEBUG -#define MPL_LOG_NDEBUG 1 - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -#define KXTF9_XOUT_HPF_L (0x00) /* 0000 0000 */ -#define KXTF9_XOUT_HPF_H (0x01) /* 0000 0001 */ -#define KXTF9_YOUT_HPF_L (0x02) /* 0000 0010 */ -#define KXTF9_YOUT_HPF_H (0x03) /* 0000 0011 */ -#define KXTF9_ZOUT_HPF_L (0x04) /* 0001 0100 */ -#define KXTF9_ZOUT_HPF_H (0x05) /* 0001 0101 */ -#define KXTF9_XOUT_L (0x06) /* 0000 0110 */ -#define KXTF9_XOUT_H (0x07) /* 0000 0111 */ -#define KXTF9_YOUT_L (0x08) /* 0000 1000 */ -#define KXTF9_YOUT_H (0x09) /* 0000 1001 */ -#define KXTF9_ZOUT_L (0x0A) /* 0001 1010 */ -#define KXTF9_ZOUT_H (0x0B) /* 0001 1011 */ -#define KXTF9_ST_RESP (0x0C) /* 0000 1100 */ -#define KXTF9_WHO_AM_I (0x0F) /* 0000 1111 */ -#define KXTF9_TILT_POS_CUR (0x10) /* 0001 0000 */ -#define KXTF9_TILT_POS_PRE (0x11) /* 0001 0001 */ -#define KXTF9_INT_SRC_REG1 (0x15) /* 0001 0101 */ -#define KXTF9_INT_SRC_REG2 (0x16) /* 0001 0110 */ -#define KXTF9_STATUS_REG (0x18) /* 0001 1000 */ -#define KXTF9_INT_REL (0x1A) /* 0001 1010 */ -#define KXTF9_CTRL_REG1 (0x1B) /* 0001 1011 */ -#define KXTF9_CTRL_REG2 (0x1C) /* 0001 1100 */ -#define KXTF9_CTRL_REG3 (0x1D) /* 0001 1101 */ -#define KXTF9_INT_CTRL_REG1 (0x1E) /* 0001 1110 */ -#define KXTF9_INT_CTRL_REG2 (0x1F) /* 0001 1111 */ -#define KXTF9_INT_CTRL_REG3 (0x20) /* 0010 0000 */ -#define KXTF9_DATA_CTRL_REG (0x21) /* 0010 0001 */ -#define KXTF9_TILT_TIMER (0x28) /* 0010 1000 */ -#define KXTF9_WUF_TIMER (0x29) /* 0010 1001 */ -#define KXTF9_TDT_TIMER (0x2B) /* 0010 1011 */ -#define KXTF9_TDT_H_THRESH (0x2C) /* 0010 1100 */ -#define KXTF9_TDT_L_THRESH (0x2D) /* 0010 1101 */ -#define KXTF9_TDT_TAP_TIMER (0x2E) /* 0010 1110 */ -#define KXTF9_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */ -#define KXTF9_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */ -#define KXTF9_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */ -#define KXTF9_WUF_THRESH (0x5A) /* 0101 1010 */ -#define KXTF9_TILT_ANGLE (0x5C) /* 0101 1100 */ -#define KXTF9_HYST_SET (0x5F) /* 0101 1111 */ - -#define KXTF9_MAX_DUR (0xFF) -#define KXTF9_MAX_THS (0xFF) -#define KXTF9_THS_COUNTS_P_G (32) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -struct kxtf9_config { - unsigned int odr; /* Output data rate mHz */ - unsigned int fsr; /* full scale range mg */ - unsigned int ths; /* Motion no-motion thseshold mg */ - unsigned int dur; /* Motion no-motion duration ms */ - unsigned int irq_type; - unsigned char reg_ths; - unsigned char reg_dur; - unsigned char reg_odr; - unsigned char reg_int_cfg1; - unsigned char reg_int_cfg2; - unsigned char ctrl_reg1; -}; - -struct kxtf9_private_data { - struct kxtf9_config suspend; - struct kxtf9_config resume; -}; - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -static int kxtf9_set_ths(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct kxtf9_config *config, - int apply, - long ths) -{ - int result = ML_SUCCESS; - if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS) - ths = (KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G; - - if (ths < 0) - ths = 0; - - config->ths = ths; - config->reg_ths = (unsigned char) - ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000); - MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_WUF_THRESH, - config->reg_ths); - return result; -} - -static int kxtf9_set_dur(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct kxtf9_config *config, - int apply, - long dur) -{ - int result = ML_SUCCESS; - long reg_dur = (dur * config->odr) / 1000000; - config->dur = dur; - - if (reg_dur > KXTF9_MAX_DUR) - reg_dur = KXTF9_MAX_DUR; - - config->reg_dur = (unsigned char) reg_dur; - MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_WUF_TIMER, - (unsigned char)reg_dur); - return result; -} - -/** - * Sets the IRQ to fire when one of the IRQ events occur. Threshold and - * duration will not be used uless the type is MOT or NMOT. - * - * @param config configuration to apply to, suspend or resume - * @param irq_type The type of IRQ. Valid values are - * - MPU_SLAVE_IRQ_TYPE_NONE - * - MPU_SLAVE_IRQ_TYPE_MOTION - * - MPU_SLAVE_IRQ_TYPE_DATA_READY - */ -static int kxtf9_set_irq(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct kxtf9_config *config, - int apply, - long irq_type) -{ - int result = ML_SUCCESS; - struct kxtf9_private_data *private_data = pdata->private_data; - - config->irq_type = (unsigned char)irq_type; - config->ctrl_reg1 &= ~0x22; - if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - config->ctrl_reg1 |= 0x20; - config->reg_int_cfg1 = 0x38; - config->reg_int_cfg2 = 0x00; - } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { - config->ctrl_reg1 |= 0x02; - if ((unsigned long) config == - (unsigned long) &private_data->suspend) - config->reg_int_cfg1 = 0x34; - else - config->reg_int_cfg1 = 0x24; - config->reg_int_cfg2 = 0xE0; - } else { - config->reg_int_cfg1 = 0x00; - config->reg_int_cfg2 = 0x00; - } - - if (apply) { - /* Must clear bit 7 before writing new configuration */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, 0x40); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_INT_CTRL_REG1, - config->reg_int_cfg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_INT_CTRL_REG2, - config->reg_int_cfg2); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, - config->ctrl_reg1); - } - MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n", - (unsigned long)config->ctrl_reg1, - (unsigned long)config->reg_int_cfg1, - (unsigned long)config->reg_int_cfg2); - - return result; -} - -/** - * Set the Output data rate for the particular configuration - * - * @param config Config to modify with new ODR - * @param odr Output data rate in units of 1/1000Hz - */ -static int kxtf9_set_odr(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct kxtf9_config *config, - int apply, - long odr) -{ - unsigned char bits; - int result = ML_SUCCESS; - - /* Data sheet says there is 12.5 hz, but that seems to produce a single - * correct data value, thus we remove it from the table */ - if (odr > 400000) { - config->odr = 800000; - bits = 0x06; - } else if (odr > 200000) { - config->odr = 400000; - bits = 0x05; - } else if (odr > 100000) { - config->odr = 200000; - bits = 0x04; - } else if (odr > 50000) { - config->odr = 100000; - bits = 0x03; - } else if (odr > 25000) { - config->odr = 50000; - bits = 0x02; - } else if (odr != 0) { - config->odr = 25000; - bits = 0x01; - } else { - config->odr = 0; - bits = 0; - } - - if (odr != 0) - config->ctrl_reg1 |= 0x80; - - config->reg_odr = bits; - kxtf9_set_dur(mlsl_handle, pdata, - config, apply, config->dur); - MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); - if (apply) { - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_DATA_CTRL_REG, - config->reg_odr); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, - 0x40); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, - config->ctrl_reg1); - } - return result; -} - -/** - * Set the full scale range of the accels - * - * @param config pointer to configuration - * @param fsr requested full scale range - */ -static int kxtf9_set_fsr(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct kxtf9_config *config, - int apply, - long fsr) -{ - int result = ML_SUCCESS; - - config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7); - if (fsr <= 2000) { - config->fsr = 2000; - config->ctrl_reg1 |= 0x00; - } else if (fsr <= 4000) { - config->fsr = 4000; - config->ctrl_reg1 |= 0x08; - } else { - config->fsr = 8000; - config->ctrl_reg1 |= 0x10; - } - - MPL_LOGV("FSR: %d\n", config->fsr); - if (apply) { - /* Must clear bit 7 before writing new configuration */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, 0x40); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, config->ctrl_reg1); - } - return result; -} - -static int kxtf9_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char data; - struct kxtf9_private_data *private_data = pdata->private_data; - - /* Wake up */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, 0x40); - ERROR_CHECK(result); - /* INT_CTRL_REG1: */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_INT_CTRL_REG1, - private_data->suspend.reg_int_cfg1); - ERROR_CHECK(result); - /* WUF_THRESH: */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_WUF_THRESH, - private_data->suspend.reg_ths); - ERROR_CHECK(result); - /* DATA_CTRL_REG */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_DATA_CTRL_REG, - private_data->suspend.reg_odr); - ERROR_CHECK(result); - /* WUF_TIMER */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_WUF_TIMER, private_data->suspend.reg_dur); - ERROR_CHECK(result); - - /* Normal operation */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, - private_data->suspend.ctrl_reg1); - ERROR_CHECK(result); - result = MLSLSerialRead(mlsl_handle, pdata->address, - KXTF9_INT_REL, 1, &data); - ERROR_CHECK(result); - - return result; -} - -/* full scale setting - register and mask */ -#define ACCEL_KIONIX_CTRL_REG (0x1b) -#define ACCEL_KIONIX_CTRL_MASK (0x18) - -static int kxtf9_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char data; - struct kxtf9_private_data *private_data = pdata->private_data; - - /* Wake up */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, 0x40); - ERROR_CHECK(result); - /* INT_CTRL_REG1: */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_INT_CTRL_REG1, - private_data->resume.reg_int_cfg1); - ERROR_CHECK(result); - /* WUF_THRESH: */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_WUF_THRESH, private_data->resume.reg_ths); - ERROR_CHECK(result); - /* DATA_CTRL_REG */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_DATA_CTRL_REG, - private_data->resume.reg_odr); - ERROR_CHECK(result); - /* WUF_TIMER */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_WUF_TIMER, private_data->resume.reg_dur); - ERROR_CHECK(result); - - /* Normal operation */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, - private_data->resume.ctrl_reg1); - ERROR_CHECK(result); - result = MLSLSerialRead(mlsl_handle, pdata->address, - KXTF9_INT_REL, 1, &data); - ERROR_CHECK(result); - - return ML_SUCCESS; -} - -static int kxtf9_init(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - - struct kxtf9_private_data *private_data; - int result = ML_SUCCESS; - - private_data = (struct kxtf9_private_data *) - MLOSMalloc(sizeof(struct kxtf9_private_data)); - - if (!private_data) - return ML_ERROR_MEMORY_EXAUSTED; - - /* RAM reset */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG1, - 0x40); /* Fastest Reset */ - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_DATA_CTRL_REG, - 0x36); /* Fastest Reset */ - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - KXTF9_CTRL_REG3, 0xcd); /* Reset */ - ERROR_CHECK(result); - MLOSSleep(2); - - pdata->private_data = private_data; - - private_data->resume.ctrl_reg1 = 0xC0; - private_data->suspend.ctrl_reg1 = 0x40; - - result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend, - FALSE, 1000); - ERROR_CHECK(result); - result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume, - FALSE, 2540); - ERROR_CHECK(result); - - result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend, - FALSE, 50000); - ERROR_CHECK(result); - result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume, - FALSE, 200000); - - result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend, - FALSE, 2000); - ERROR_CHECK(result); - result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume, - FALSE, 2000); - ERROR_CHECK(result); - - result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend, - FALSE, 80); - ERROR_CHECK(result); - result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume, - FALSE, 40); - ERROR_CHECK(result); - - result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend, - FALSE, - MPU_SLAVE_IRQ_TYPE_NONE); - ERROR_CHECK(result); - result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume, - FALSE, - MPU_SLAVE_IRQ_TYPE_NONE); - ERROR_CHECK(result); - return result; -} - -static int kxtf9_exit(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - if (pdata->private_data) - return MLOSFree(pdata->private_data); - else - return ML_SUCCESS; -} - -static int kxtf9_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct kxtf9_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - return kxtf9_set_odr(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_ODR_RESUME: - return kxtf9_set_odr(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - return kxtf9_set_fsr(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_FSR_RESUME: - return kxtf9_set_fsr(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_MOT_THS: - return kxtf9_set_ths(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_NMOT_THS: - return kxtf9_set_ths(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_MOT_DUR: - return kxtf9_set_dur(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_NMOT_DUR: - return kxtf9_set_dur(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - return kxtf9_set_irq(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_IRQ_RESUME: - return kxtf9_set_irq(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -static int kxtf9_get_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct kxtf9_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.odr; - break; - case MPU_SLAVE_CONFIG_ODR_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.odr; - break; - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.fsr; - break; - case MPU_SLAVE_CONFIG_FSR_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.fsr; - break; - case MPU_SLAVE_CONFIG_MOT_THS: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.ths; - break; - case MPU_SLAVE_CONFIG_NMOT_THS: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.ths; - break; - case MPU_SLAVE_CONFIG_MOT_DUR: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.dur; - break; - case MPU_SLAVE_CONFIG_NMOT_DUR: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.dur; - break; - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.irq_type; - break; - case MPU_SLAVE_CONFIG_IRQ_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.irq_type; - break; - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -static int kxtf9_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - unsigned char reg; - result = MLSLSerialRead(mlsl_handle, pdata->address, - KXTF9_INT_SRC_REG2, 1, ®); - ERROR_CHECK(result); - - if (!(reg & 0x10)) - return ML_ERROR_ACCEL_DATA_NOT_READY; - - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - ERROR_CHECK(result); - return result; -} - -static struct ext_slave_descr kxtf9_descr = { - /*.init = */ kxtf9_init, - /*.exit = */ kxtf9_exit, - /*.suspend = */ kxtf9_suspend, - /*.resume = */ kxtf9_resume, - /*.read = */ kxtf9_read, - /*.config = */ kxtf9_config, - /*.get_config = */ kxtf9_get_config, - /*.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; -} -EXPORT_SYMBOL(kxtf9_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/lis331.c b/drivers/misc/mpu3050/accel/lis331.c deleted file mode 100755 index 53c599b2ef27..000000000000 --- a/drivers/misc/mpu3050/accel/lis331.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 lis331.c - * @brief Accelerometer setup and handling methods for ST LIS331 - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#undef MPL_LOG_NDEBUG -#define MPL_LOG_NDEBUG 1 - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -/* full scale setting - register & mask */ -#define LIS331_CTRL_REG1 (0x20) -#define LIS331_CTRL_REG2 (0x21) -#define LIS331_CTRL_REG3 (0x22) -#define LIS331_CTRL_REG4 (0x23) -#define LIS331_CTRL_REG5 (0x24) -#define LIS331_HP_FILTER_RESET (0x25) -#define LIS331_REFERENCE (0x26) -#define LIS331_STATUS_REG (0x27) -#define LIS331_OUT_X_L (0x28) -#define LIS331_OUT_X_H (0x29) -#define LIS331_OUT_Y_L (0x2a) -#define LIS331_OUT_Y_H (0x2b) -#define LIS331_OUT_Z_L (0x2b) -#define LIS331_OUT_Z_H (0x2d) - -#define LIS331_INT1_CFG (0x30) -#define LIS331_INT1_SRC (0x31) -#define LIS331_INT1_THS (0x32) -#define LIS331_INT1_DURATION (0x33) - -#define LIS331_INT2_CFG (0x34) -#define LIS331_INT2_SRC (0x35) -#define LIS331_INT2_THS (0x36) -#define LIS331_INT2_DURATION (0x37) - -#define LIS331_CTRL_MASK (0x30) -#define LIS331_SLEEP_MASK (0x20) - -#define LIS331_MAX_DUR (0x7F) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -struct lis331dlh_config { - unsigned int odr; - unsigned int fsr; /* full scale range mg */ - unsigned int ths; /* Motion no-motion thseshold mg */ - unsigned int dur; /* Motion no-motion duration ms */ - unsigned char reg_ths; - unsigned char reg_dur; - unsigned char ctrl_reg1; - unsigned char irq_type; - unsigned char mot_int1_cfg; -}; - -struct lis331dlh_private_data { - struct lis331dlh_config suspend; - struct lis331dlh_config resume; -}; - - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -static int lis331dlh_set_ths(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis331dlh_config *config, - int apply, - long ths) -{ - int result = ML_SUCCESS; - if ((unsigned int) ths >= config->fsr) - ths = (long) config->fsr - 1; - - if (ths < 0) - ths = 0; - - config->ths = ths; - config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); - MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_THS, - config->reg_ths); - return result; -} - -static int lis331dlh_set_dur(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis331dlh_config *config, - int apply, - long dur) -{ - int result = ML_SUCCESS; - long reg_dur = (dur * config->odr) / 1000000L; - config->dur = dur; - - if (reg_dur > LIS331_MAX_DUR) - reg_dur = LIS331_MAX_DUR; - - config->reg_dur = (unsigned char) reg_dur; - MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_DURATION, - (unsigned char)reg_dur); - return result; -} - -/** - * Sets the IRQ to fire when one of the IRQ events occur. Threshold and - * duration will not be used uless the type is MOT or NMOT. - * - * @param config configuration to apply to, suspend or resume - * @param irq_type The type of IRQ. Valid values are - * - MPU_SLAVE_IRQ_TYPE_NONE - * - MPU_SLAVE_IRQ_TYPE_MOTION - * - MPU_SLAVE_IRQ_TYPE_DATA_READY - */ -static int lis331dlh_set_irq(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis331dlh_config *config, - int apply, - long irq_type) -{ - int result = ML_SUCCESS; - unsigned char reg1; - unsigned char reg2; - - config->irq_type = (unsigned char)irq_type; - if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - reg1 = 0x02; - reg2 = 0x00; - } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { - reg1 = 0x00; - reg2 = config->mot_int1_cfg; - } else { - reg1 = 0x00; - reg2 = 0x00; - } - - if (apply) { - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG3, reg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_CFG, reg2); - } - - return result; -} - -/** - * Set the Output data rate for the particular configuration - * - * @param config Config to modify with new ODR - * @param odr Output data rate in units of 1/1000Hz - */ -static int lis331dlh_set_odr(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis331dlh_config *config, - int apply, - long odr) -{ - unsigned char bits; - int result = ML_SUCCESS; - - if (odr > 400000) { - config->odr = 1000000; - bits = 0x38; - } else if (odr > 100000) { - config->odr = 400000; - bits = 0x30; - } else if (odr > 50000) { - config->odr = 100000; - bits = 0x28; - } else if (odr > 10000) { - config->odr = 50000; - bits = 0x20; - } else if (odr > 5000) { - config->odr = 10000; - bits = 0xC0; - } else if (odr > 2000) { - config->odr = 5000; - bits = 0xB0; - } else if (odr > 1000) { - config->odr = 2000; - bits = 0x80; - } else if (odr > 500) { - config->odr = 1000; - bits = 0x60; - } else if (odr > 0) { - config->odr = 500; - bits = 0x40; - } else { - config->odr = 0; - bits = 0; - } - - config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7); - lis331dlh_set_dur(mlsl_handle, pdata, - config, apply, config->dur); - MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG1, - config->ctrl_reg1); - return result; -} - -/** - * Set the full scale range of the accels - * - * @param config pointer to configuration - * @param fsr requested full scale range - */ -static int lis331dlh_set_fsr(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis331dlh_config *config, - int apply, - long fsr) -{ - unsigned char reg1 = 0x40; - int result = ML_SUCCESS; - - if (fsr <= 2048) { - config->fsr = 2048; - } else if (fsr <= 4096) { - reg1 |= 0x30; - config->fsr = 4096; - } else { - reg1 |= 0x10; - config->fsr = 8192; - } - - lis331dlh_set_ths(mlsl_handle, pdata, - config, apply, config->ths); - MPL_LOGV("FSR: %d\n", config->fsr); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG4, reg1); - - return result; -} - -static int lis331dlh_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg1; - unsigned char reg2; - struct lis331dlh_private_data *private_data = pdata->private_data; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG1, - private_data->suspend.ctrl_reg1); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG2, 0x0f); - reg1 = 0x40; - if (private_data->suspend.fsr == 8192) - reg1 |= 0x30; - else if (private_data->suspend.fsr == 4096) - reg1 |= 0x10; - /* else bits [4..5] are already zero */ - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG4, reg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_THS, - private_data->suspend.reg_ths); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_DURATION, - private_data->suspend.reg_dur); - - if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - reg1 = 0x02; - reg2 = 0x00; - } else if (private_data->suspend.irq_type == - MPU_SLAVE_IRQ_TYPE_MOTION) { - reg1 = 0x00; - reg2 = private_data->suspend.mot_int1_cfg; - } else { - reg1 = 0x00; - reg2 = 0x00; - } - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG3, reg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_CFG, reg2); - result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS331_HP_FILTER_RESET, 1, ®1); - return result; -} - -static int lis331dlh_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg1; - unsigned char reg2; - struct lis331dlh_private_data *private_data = pdata->private_data; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG1, - private_data->resume.ctrl_reg1); - ERROR_CHECK(result); - MLOSSleep(6); - - /* Full Scale */ - reg1 = 0x40; - if (private_data->resume.fsr == 8192) - reg1 |= 0x30; - else if (private_data->resume.fsr == 4096) - reg1 |= 0x10; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG4, reg1); - ERROR_CHECK(result); - - /* Configure high pass filter */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG2, 0x0F); - ERROR_CHECK(result); - - if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - reg1 = 0x02; - reg2 = 0x00; - } else if (private_data->resume.irq_type == - MPU_SLAVE_IRQ_TYPE_MOTION) { - reg1 = 0x00; - reg2 = private_data->resume.mot_int1_cfg; - } else { - reg1 = 0x00; - reg2 = 0x00; - } - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_CTRL_REG3, reg1); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_THS, - private_data->resume.reg_ths); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_DURATION, - private_data->resume.reg_dur); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS331_INT1_CFG, reg2); - ERROR_CHECK(result); - result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS331_HP_FILTER_RESET, 1, ®1); - ERROR_CHECK(result); - return result; -} - -static int lis331dlh_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result = ML_SUCCESS; - result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS331_STATUS_REG, 1, data); - if (data[0] & 0x0F) { - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; - } else - return ML_ERROR_ACCEL_DATA_NOT_READY; -} - -static int lis331dlh_init(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - struct lis331dlh_private_data *private_data; - private_data = (struct lis331dlh_private_data *) - MLOSMalloc(sizeof(struct lis331dlh_private_data)); - - if (!private_data) - return ML_ERROR_MEMORY_EXAUSTED; - - pdata->private_data = private_data; - - private_data->resume.ctrl_reg1 = 0x37; - private_data->suspend.ctrl_reg1 = 0x47; - private_data->resume.mot_int1_cfg = 0x95; - private_data->suspend.mot_int1_cfg = 0x2a; - - lis331dlh_set_odr(mlsl_handle, pdata, &private_data->suspend, - FALSE, 0); - lis331dlh_set_odr(mlsl_handle, pdata, &private_data->resume, - FALSE, 200000); - lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->suspend, - FALSE, 2048); - lis331dlh_set_fsr(mlsl_handle, pdata, &private_data->resume, - FALSE, 2048); - lis331dlh_set_ths(mlsl_handle, pdata, &private_data->suspend, - FALSE, 80); - lis331dlh_set_ths(mlsl_handle, pdata, &private_data->resume, - FALSE, 40); - lis331dlh_set_dur(mlsl_handle, pdata, &private_data->suspend, - FALSE, 1000); - lis331dlh_set_dur(mlsl_handle, pdata, &private_data->resume, - FALSE, 2540); - lis331dlh_set_irq(mlsl_handle, pdata, &private_data->suspend, - FALSE, - MPU_SLAVE_IRQ_TYPE_NONE); - lis331dlh_set_irq(mlsl_handle, pdata, &private_data->resume, - FALSE, - MPU_SLAVE_IRQ_TYPE_NONE); - return ML_SUCCESS; -} - -static int lis331dlh_exit(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - if (pdata->private_data) - return MLOSFree(pdata->private_data); - else - return ML_SUCCESS; -} - -static int lis331dlh_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct lis331dlh_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - return lis331dlh_set_odr(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_ODR_RESUME: - return lis331dlh_set_odr(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - return lis331dlh_set_fsr(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_FSR_RESUME: - return lis331dlh_set_fsr(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_MOT_THS: - return lis331dlh_set_ths(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_NMOT_THS: - return lis331dlh_set_ths(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_MOT_DUR: - return lis331dlh_set_dur(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_NMOT_DUR: - return lis331dlh_set_dur(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - return lis331dlh_set_irq(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_IRQ_RESUME: - return lis331dlh_set_irq(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -static int lis331dlh_get_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct lis331dlh_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.odr; - break; - case MPU_SLAVE_CONFIG_ODR_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.odr; - break; - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.fsr; - break; - case MPU_SLAVE_CONFIG_FSR_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.fsr; - break; - case MPU_SLAVE_CONFIG_MOT_THS: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.ths; - break; - case MPU_SLAVE_CONFIG_NMOT_THS: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.ths; - break; - case MPU_SLAVE_CONFIG_MOT_DUR: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.dur; - break; - case MPU_SLAVE_CONFIG_NMOT_DUR: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.dur; - break; - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.irq_type; - break; - case MPU_SLAVE_CONFIG_IRQ_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.irq_type; - break; - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -static struct ext_slave_descr lis331dlh_descr = { - /*.init = */ lis331dlh_init, - /*.exit = */ lis331dlh_exit, - /*.suspend = */ lis331dlh_suspend, - /*.resume = */ lis331dlh_resume, - /*.read = */ lis331dlh_read, - /*.config = */ lis331dlh_config, - /*.get_config = */ lis331dlh_get_config, - /*.name = */ "lis331dlh", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_LIS331, - /*.reg = */ (0x28 | 0x80), /* 0x80 for burst reads */ - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {2, 480}, -}; - -struct ext_slave_descr *lis331dlh_get_slave_descr(void) -{ - return &lis331dlh_descr; -} -EXPORT_SYMBOL(lis331dlh_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/lis3dh.c b/drivers/misc/mpu3050/accel/lis3dh.c deleted file mode 100755 index ee5e3539b988..000000000000 --- a/drivers/misc/mpu3050/accel/lis3dh.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 lis3dh.c - * @brief Accelerometer setup and handling methods for ST LIS3DH - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#undef MPL_LOG_NDEBUG -#define MPL_LOG_NDEBUG 0 - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -/* full scale setting - register & mask */ -#define LIS3DH_CTRL_REG1 (0x20) -#define LIS3DH_CTRL_REG2 (0x21) -#define LIS3DH_CTRL_REG3 (0x22) -#define LIS3DH_CTRL_REG4 (0x23) -#define LIS3DH_CTRL_REG5 (0x24) -#define LIS3DH_CTRL_REG6 (0x25) -#define LIS3DH_REFERENCE (0x26) -#define LIS3DH_STATUS_REG (0x27) -#define LIS3DH_OUT_X_L (0x28) -#define LIS3DH_OUT_X_H (0x29) -#define LIS3DH_OUT_Y_L (0x2a) -#define LIS3DH_OUT_Y_H (0x2b) -#define LIS3DH_OUT_Z_L (0x2b) -#define LIS3DH_OUT_Z_H (0x2d) - -#define LIS3DH_INT1_CFG (0x30) -#define LIS3DH_INT1_SRC (0x31) -#define LIS3DH_INT1_THS (0x32) -#define LIS3DH_INT1_DURATION (0x33) - -#define LIS3DH_MAX_DUR (0x7F) - - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -struct lis3dh_config { - unsigned int odr; - unsigned int fsr; /* full scale range mg */ - unsigned int ths; /* Motion no-motion thseshold mg */ - unsigned int dur; /* Motion no-motion duration ms */ - unsigned char reg_ths; - unsigned char reg_dur; - unsigned char ctrl_reg1; - unsigned char irq_type; - unsigned char mot_int1_cfg; -}; - -struct lis3dh_private_data { - struct lis3dh_config suspend; - struct lis3dh_config resume; -}; - - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -static int lis3dh_set_ths(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis3dh_config *config, - int apply, - long ths) -{ - int result = ML_SUCCESS; - if ((unsigned int) ths > 1000 * config->fsr) - ths = (long) 1000 * config->fsr; - - if (ths < 0) - ths = 0; - - config->ths = ths; - config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr)); - MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_THS, - config->reg_ths); - return result; -} - -static int lis3dh_set_dur(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis3dh_config *config, - int apply, - long dur) -{ - int result = ML_SUCCESS; - long reg_dur = (dur * config->odr) / 1000000L; - config->dur = dur; - - if (reg_dur > LIS3DH_MAX_DUR) - reg_dur = LIS3DH_MAX_DUR; - - config->reg_dur = (unsigned char) reg_dur; - MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_DURATION, - (unsigned char)reg_dur); - return result; -} - -/** - * Sets the IRQ to fire when one of the IRQ events occur. Threshold and - * duration will not be used uless the type is MOT or NMOT. - * - * @param config configuration to apply to, suspend or resume - * @param irq_type The type of IRQ. Valid values are - * - MPU_SLAVE_IRQ_TYPE_NONE - * - MPU_SLAVE_IRQ_TYPE_MOTION - * - MPU_SLAVE_IRQ_TYPE_DATA_READY - */ -static int lis3dh_set_irq(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis3dh_config *config, - int apply, - long irq_type) -{ - int result = ML_SUCCESS; - unsigned char reg1; - unsigned char reg2; - - config->irq_type = (unsigned char)irq_type; - if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - reg1 = 0x10; - reg2 = 0x00; - } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { - reg1 = 0x40; - reg2 = config->mot_int1_cfg; - } else { - reg1 = 0x00; - reg2 = 0x00; - } - - if (apply) { - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG3, reg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_CFG, reg2); - } - - return result; -} - -/** - * Set the Output data rate for the particular configuration - * - * @param config Config to modify with new ODR - * @param odr Output data rate in units of 1/1000Hz - */ -static int lis3dh_set_odr(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis3dh_config *config, - int apply, - long odr) -{ - unsigned char bits; - int result = ML_SUCCESS; - - if (odr > 400000) { - config->odr = 1250000; - bits = 0x90; - } else if (odr > 200000) { - config->odr = 400000; - bits = 0x70; - } else if (odr > 100000) { - config->odr = 200000; - bits = 0x60; - } else if (odr > 50000) { - config->odr = 100000; - bits = 0x50; - } else if (odr > 25000) { - config->odr = 50000; - bits = 0x40; - } else if (odr > 10000) { - config->odr = 25000; - bits = 0x30; - } else if (odr > 1000) { - config->odr = 10000; - bits = 0x20; - } else if (odr > 500) { - config->odr = 1000; - bits = 0x10; - } else { - config->odr = 0; - bits = 0; - } - - config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0xf); - lis3dh_set_dur(mlsl_handle, pdata, - config, apply, config->dur); - MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG1, - config->ctrl_reg1); - return result; -} - -/** - * Set the full scale range of the accels - * - * @param config pointer to configuration - * @param fsr requested full scale range - */ -static int lis3dh_set_fsr(void *mlsl_handle, - struct ext_slave_platform_data *pdata, - struct lis3dh_config *config, - int apply, - long fsr) -{ - int result = ML_SUCCESS; - unsigned char reg1 = 0x48; - - if (fsr <= 2048) { - config->fsr = 2048; - } else if (fsr <= 4096) { - reg1 |= 0x10; - config->fsr = 4096; - } else if (fsr <= 8192) { - reg1 |= 0x20; - config->fsr = 8192; - } else { - reg1 |= 0x30; - config->fsr = 16348; - } - - lis3dh_set_ths(mlsl_handle, pdata, - config, apply, config->ths); - MPL_LOGV("FSR: %d\n", config->fsr); - if (apply) - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG4, reg1); - - return result; -} - -static int lis3dh_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg1; - unsigned char reg2; - struct lis3dh_private_data *private_data = pdata->private_data; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG1, - private_data->suspend.ctrl_reg1); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG2, 0x31); - reg1 = 0x48; - if (private_data->suspend.fsr == 16384) - reg1 |= 0x30; - else if (private_data->suspend.fsr == 8192) - reg1 |= 0x20; - else if (private_data->suspend.fsr == 4096) - reg1 |= 0x10; - else if (private_data->suspend.fsr == 2048) - reg1 |= 0x00; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG4, reg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_THS, - private_data->suspend.reg_ths); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_DURATION, - private_data->suspend.reg_dur); - - if (private_data->suspend.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - reg1 = 0x10; - reg2 = 0x00; - } else if (private_data->suspend.irq_type == - MPU_SLAVE_IRQ_TYPE_MOTION) { - reg1 = 0x40; - reg2 = private_data->suspend.mot_int1_cfg; - } else { - reg1 = 0x00; - reg2 = 0x00; - } - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG3, reg1); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_CFG, reg2); - result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG6, 1, ®1); - - return result; -} - -static int lis3dh_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - tMLError result; - unsigned char reg1; - unsigned char reg2; - struct lis3dh_private_data *private_data = pdata->private_data; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG1, - private_data->resume.ctrl_reg1); - ERROR_CHECK(result); - MLOSSleep(6); - - /* Full Scale */ - reg1 = 0x48; - if (private_data->suspend.fsr == 16384) - reg1 |= 0x30; - else if (private_data->suspend.fsr == 8192) - reg1 |= 0x20; - else if (private_data->suspend.fsr == 4096) - reg1 |= 0x10; - else if (private_data->suspend.fsr == 2048) - reg1 |= 0x00; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG4, reg1); - ERROR_CHECK(result); - - /* Configure high pass filter */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG2, 0x31); - ERROR_CHECK(result); - - if (private_data->resume.irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { - reg1 = 0x10; - reg2 = 0x00; - } else if (private_data->resume.irq_type == - MPU_SLAVE_IRQ_TYPE_MOTION) { - reg1 = 0x40; - reg2 = private_data->resume.mot_int1_cfg; - } else { - reg1 = 0x00; - reg2 = 0x00; - } - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG3, reg1); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_THS, - private_data->resume.reg_ths); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_DURATION, - private_data->resume.reg_dur); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_INT1_CFG, reg2); - ERROR_CHECK(result); - result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG6, 1, ®1); - ERROR_CHECK(result); - return result; -} - -static int lis3dh_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result = ML_SUCCESS; - result = MLSLSerialRead(mlsl_handle, pdata->address, - LIS3DH_STATUS_REG, 1, data); - if (data[0] & 0x0F) { - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; - } else - return ML_ERROR_ACCEL_DATA_NOT_READY; -} - -static int lis3dh_init(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - tMLError result; - - struct lis3dh_private_data *private_data; - private_data = (struct lis3dh_private_data *) - MLOSMalloc(sizeof(struct lis3dh_private_data)); - - if (!private_data) - return ML_ERROR_MEMORY_EXAUSTED; - - pdata->private_data = private_data; - - private_data->resume.ctrl_reg1 = 0x67; - private_data->suspend.ctrl_reg1 = 0x18; - private_data->resume.mot_int1_cfg = 0x95; - private_data->suspend.mot_int1_cfg = 0x2a; - - lis3dh_set_odr(mlsl_handle, pdata, &private_data->suspend, - FALSE, 0); - lis3dh_set_odr(mlsl_handle, pdata, &private_data->resume, - FALSE, 200000); - lis3dh_set_fsr(mlsl_handle, pdata, &private_data->suspend, - FALSE, 2048); - lis3dh_set_fsr(mlsl_handle, pdata, &private_data->resume, - FALSE, 2048); - lis3dh_set_ths(mlsl_handle, pdata, &private_data->suspend, - FALSE, 80); - lis3dh_set_ths(mlsl_handle, pdata, &private_data->resume, - FALSE, 40); - lis3dh_set_dur(mlsl_handle, pdata, &private_data->suspend, - FALSE, 1000); - lis3dh_set_dur(mlsl_handle, pdata, &private_data->resume, - FALSE, 2540); - lis3dh_set_irq(mlsl_handle, pdata, &private_data->suspend, - FALSE, - MPU_SLAVE_IRQ_TYPE_NONE); - lis3dh_set_irq(mlsl_handle, pdata, &private_data->resume, - FALSE, - MPU_SLAVE_IRQ_TYPE_NONE); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LIS3DH_CTRL_REG1, 0x07); - MLOSSleep(6); - - return ML_SUCCESS; -} - -static int lis3dh_exit(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - if (pdata->private_data) - return MLOSFree(pdata->private_data); - else - return ML_SUCCESS; -} - -static int lis3dh_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct lis3dh_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - return lis3dh_set_odr(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_ODR_RESUME: - return lis3dh_set_odr(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - return lis3dh_set_fsr(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_FSR_RESUME: - return lis3dh_set_fsr(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_MOT_THS: - return lis3dh_set_ths(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_NMOT_THS: - return lis3dh_set_ths(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_MOT_DUR: - return lis3dh_set_dur(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_NMOT_DUR: - return lis3dh_set_dur(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - return lis3dh_set_irq(mlsl_handle, pdata, - &private_data->suspend, - data->apply, - *((long *)data->data)); - case MPU_SLAVE_CONFIG_IRQ_RESUME: - return lis3dh_set_irq(mlsl_handle, pdata, - &private_data->resume, - data->apply, - *((long *)data->data)); - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - return ML_SUCCESS; -} - -static int lis3dh_get_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct lis3dh_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.odr; - break; - case MPU_SLAVE_CONFIG_ODR_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.odr; - break; - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.fsr; - break; - case MPU_SLAVE_CONFIG_FSR_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.fsr; - break; - case MPU_SLAVE_CONFIG_MOT_THS: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.ths; - break; - case MPU_SLAVE_CONFIG_NMOT_THS: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.ths; - break; - case MPU_SLAVE_CONFIG_MOT_DUR: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.dur; - break; - case MPU_SLAVE_CONFIG_NMOT_DUR: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.dur; - break; - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - (*(unsigned long *)data->data) = - (unsigned long) private_data->suspend.irq_type; - break; - case MPU_SLAVE_CONFIG_IRQ_RESUME: - (*(unsigned long *)data->data) = - (unsigned long) private_data->resume.irq_type; - break; - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -static struct ext_slave_descr lis3dh_descr = { - /*.init = */ lis3dh_init, - /*.exit = */ lis3dh_exit, - /*.suspend = */ lis3dh_suspend, - /*.resume = */ lis3dh_resume, - /*.read = */ lis3dh_read, - /*.config = */ lis3dh_config, - /*.get_config = */ lis3dh_get_config, - /*.name = */ "lis3dh", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_LIS3DH, - /*.reg = */ 0x28 | 0x80, /* 0x80 for burst reads */ - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {2, 480}, -}; - -struct ext_slave_descr *lis3dh_get_slave_descr(void) -{ - return &lis3dh_descr; -} -EXPORT_SYMBOL(lis3dh_get_slave_descr); - -/* - * @} -*/ diff --git a/drivers/misc/mpu3050/accel/lsm303a.c b/drivers/misc/mpu3050/accel/lsm303a.c deleted file mode 100755 index b8494962d3ac..000000000000 --- a/drivers/misc/mpu3050/accel/lsm303a.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 lsm303a.c - * @brief Accelerometer setup and handling methods for ST LSM303 - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -#define ACCEL_ST_SLEEP_REG (0x20) -#define ACCEL_ST_SLEEP_MASK (0x20) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int lsm303dlha_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, ACCEL_ST_SLEEP_REG, - 1, ®); - ERROR_CHECK(result); - reg &= ~(0x27); - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_ST_SLEEP_REG, reg); - ERROR_CHECK(result); - return result; -} - -/* full scale setting - register & mask */ -#define ACCEL_ST_CTRL_REG (0x23) -#define ACCEL_ST_CTRL_MASK (0x30) - -int lsm303dlha_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, ACCEL_ST_SLEEP_REG, - 1, ®); - ERROR_CHECK(result); - reg |= 0x27; - /*wake up if sleeping */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_ST_SLEEP_REG, reg); - ERROR_CHECK(result); - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x20, 0x37); - ERROR_CHECK(result); - MLOSSleep(500); - - reg = 0x40; - - /* Full Scale */ - reg &= ~ACCEL_ST_CTRL_MASK; - if (slave->range.mantissa == 4) { - slave->range.fraction = 960; - reg |= 0x10; - } else if (slave->range.mantissa == 8) { - slave->range.fraction = 1920; - reg |= 0x30; - } else { - slave->range.mantissa = 2; - slave->range.fraction = 480; - reg |= 0x00; - } - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x23, reg); - ERROR_CHECK(result); - - /* Configure high pass filter */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x0F); - ERROR_CHECK(result); - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x32, 0x00); - ERROR_CHECK(result); - /* Configure INT1_DURATION */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x33, 0x7F); - ERROR_CHECK(result); - /* Configure INT1_CFG */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x30, 0x95); - ERROR_CHECK(result); - MLOSSleep(50); - return result; -} - -int lsm303dlha_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -struct ext_slave_descr lsm303dlha_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ lsm303dlha_suspend, - /*.resume = */ lsm303dlha_resume, - /*.read = */ lsm303dlha_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "lsm303dlha", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_LSM303, - /*.reg = */ (0x28 | 0x80), /* 0x80 for burst reads */ - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {2, 480}, -}; - -struct ext_slave_descr *lsm303dlha_get_slave_descr(void) -{ - return &lsm303dlha_descr; -} -EXPORT_SYMBOL(lsm303dlha_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/mantis.c b/drivers/misc/mpu3050/accel/mantis.c deleted file mode 100755 index 1cb9847fee05..000000000000 --- a/drivers/misc/mpu3050/accel/mantis.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - $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 . - $ - */ -/** - * @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 lis331.c - * @brief Accelerometer setup and handling methods for Invensense MANTIS - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -struct mantis_config { - unsigned int odr; /* output data rate 1/1000 Hz*/ - unsigned int fsr; /* full scale range mg */ - unsigned int ths; /* Motion no-motion thseshold mg */ - unsigned int dur; /* Motion no-motion duration ms */ -}; - -struct mantis_private_data { - struct mantis_config suspend; - struct mantis_config resume; -}; - - -/***************************************** - *Accelerometer Initialization Functions - *****************************************/ -/** - * Record the odr for use in computing duration values. - * - * @param config Config to set, suspend or resume structure - * @param odr output data rate in 1/1000 hz - */ -void mantis_set_odr(struct mantis_config *config, - long odr) -{ - config->odr = odr; -} - -void mantis_set_ths(struct mantis_config *config, - long ths) -{ - if (ths < 0) - ths = 0; - - config->ths = ths; - MPL_LOGV("THS: %d\n", config->ths); -} - -void mantis_set_dur(struct mantis_config *config, - long dur) -{ - if (dur < 0) - dur = 0; - - config->dur = dur; - MPL_LOGV("DUR: %d\n", config->dur); -} - -static void mantis_set_fsr( - struct mantis_config *config, - long fsr) -{ - if (fsr <= 2000) - config->fsr = 2000; - else if (fsr <= 4000) - config->fsr = 4000; - else - config->fsr = 8000; - - MPL_LOGV("FSR: %d\n", config->fsr); -} - -static int mantis_init(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - struct mantis_private_data *private_data; - private_data = (struct mantis_private_data *) - MLOSMalloc(sizeof(struct mantis_private_data)); - - if (!private_data) - return ML_ERROR_MEMORY_EXAUSTED; - - pdata->private_data = private_data; - - mantis_set_odr(&private_data->suspend, 0); - mantis_set_odr(&private_data->resume, 200000); - mantis_set_fsr(&private_data->suspend, 2000); - mantis_set_fsr(&private_data->resume, 2000); - mantis_set_ths(&private_data->suspend, 80); - mantis_set_ths(&private_data->resume, 40); - mantis_set_dur(&private_data->suspend, 1000); - mantis_set_dur(&private_data->resume, 2540); - return ML_SUCCESS; -} - -static int mantis_exit(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - if (pdata->private_data) - return MLOSFree(pdata->private_data); - else - return ML_SUCCESS; -} - -int mantis_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - unsigned char reg; - int result; - - result = MLSLSerialRead(mlsl_handle, pdata->address, - MPUREG_PWR_MGMT_2, 1, ®); - ERROR_CHECK(result); - reg |= (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_PWR_MGMT_2, reg); - ERROR_CHECK(result); - - return ML_SUCCESS; -} - -int mantis_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - struct mantis_private_data *private_data; - - private_data = (struct mantis_private_data *) pdata->private_data; - - MLSLSerialRead(mlsl_handle, pdata->address, - MPUREG_PWR_MGMT_2, 1, ®); - - reg &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_PWR_MGMT_2, reg); - ERROR_CHECK(result); - - if (slave->range.mantissa == 2) - reg = 0; - else if (slave->range.mantissa == 4) - reg = 1 << 3; - else if (slave->range.mantissa == 8) - reg = 2 << 3; - else if (slave->range.mantissa == 16) - reg = 3 << 3; - else - return ML_ERROR; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_ACCEL_CONFIG, reg); - ERROR_CHECK(result); - - reg = (unsigned char) private_data->suspend.ths / ACCEL_MOT_THR_LSB; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_ACCEL_MOT_THR, reg); - ERROR_CHECK(result); - - reg = (unsigned char) - ACCEL_ZRMOT_THR_LSB_CONVERSION(private_data->resume.ths); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_ACCEL_ZRMOT_THR, reg); - ERROR_CHECK(result); - - reg = (unsigned char) private_data->suspend.ths / ACCEL_MOT_DUR_LSB; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_ACCEL_MOT_DUR, reg); - ERROR_CHECK(result); - - reg = (unsigned char) private_data->resume.ths / ACCEL_ZRMOT_DUR_LSB; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MPUREG_ACCEL_ZRMOT_DUR, reg); - ERROR_CHECK(result); - return result; -} - -int mantis_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, unsigned char *data) -{ - int result; - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, slave->len, data); - return result; -} - -static int mantis_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - struct mantis_private_data *private_data = pdata->private_data; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - mantis_set_odr(&private_data->suspend, - *((long *)data->data)); - break; - case MPU_SLAVE_CONFIG_ODR_RESUME: - mantis_set_odr(&private_data->resume, - *((long *)data->data)); - break; - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - mantis_set_fsr(&private_data->suspend, - *((long *)data->data)); - break; - case MPU_SLAVE_CONFIG_FSR_RESUME: - mantis_set_fsr(&private_data->resume, - *((long *)data->data)); - break; - case MPU_SLAVE_CONFIG_MOT_THS: - mantis_set_ths(&private_data->suspend, - (*((long *)data->data))); - break; - case MPU_SLAVE_CONFIG_NMOT_THS: - mantis_set_ths(&private_data->resume, - (*((long *)data->data))); - break; - case MPU_SLAVE_CONFIG_MOT_DUR: - mantis_set_dur(&private_data->suspend, - (*((long *)data->data))); - break; - case MPU_SLAVE_CONFIG_NMOT_DUR: - mantis_set_dur(&private_data->resume, - (*((long *)data->data))); - break; - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -struct ext_slave_descr mantis_descr = { - /*.init = */ mantis_init, - /*.exit = */ mantis_exit, - /*.suspend = */ mantis_suspend, - /*.resume = */ mantis_resume, - /*.read = */ mantis_read, - /*.config = */ mantis_config, - /*.get_config = */ NULL, - /*.name = */ "mantis", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_MPU6000, - /*.reg = */ 0xA8, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *mantis_get_slave_descr(void) -{ - return &mantis_descr; -} -EXPORT_SYMBOL(mantis_get_slave_descr); - -/** - * @} - */ - diff --git a/drivers/misc/mpu3050/accel/mma8450.c b/drivers/misc/mpu3050/accel/mma8450.c deleted file mode 100755 index ffc92fd8bbdf..000000000000 --- a/drivers/misc/mpu3050/accel/mma8450.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 mma8450.c - * @brief Accelerometer setup and handling methods for Freescale MMA8450 - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#include -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" -#include - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -#define ACCEL_MMA8450_SLEEP_REG (0x38) -#define ACCEL_MMA8450_SLEEP_MASK (0x3) - - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int mma8450_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - result = - MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_MMA8450_SLEEP_REG, 1, ®); - ERROR_CHECK(result); - reg &= ~ACCEL_MMA8450_SLEEP_MASK; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_MMA8450_SLEEP_REG, reg); - ERROR_CHECK(result); - return result; -} - -/* full scale setting - register & mask */ -#define ACCEL_MMA8450_CTRL_REG (0x38) -#define ACCEL_MMA8450_CTRL_MASK (0x3) - -int mma8450_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_MMA8450_CTRL_REG, 1, ®); - ERROR_CHECK(result); - - /* data rate = 200Hz */ - reg &= 0xE3; - reg |= 0x4; - - /* Full Scale */ - reg &= ~ACCEL_MMA8450_CTRL_MASK; - if (slave->range.mantissa == 4) - reg |= 0x2; - else if (slave->range.mantissa == 8) - reg |= 0x3; - else { - slave->range.mantissa = 2; - reg |= 0x1; - } - slave->range.fraction = 0; - - /* XYZ_DATA_CFG: event flag enabled on all axis */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - 0x16, 0x05); - ERROR_CHECK(result); - /* CTRL_REG1: rate + scale config + wakeup */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_MMA8450_CTRL_REG, reg); - ERROR_CHECK(result); - - return result; -} - -int mma8450_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - unsigned char local_data[4]; /* Status register + 3 bytes data */ - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, sizeof(local_data), local_data); - ERROR_CHECK(result); - memcpy(data, &local_data[1], (slave->len)-1); - return result; -} - -struct ext_slave_descr mma8450_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ mma8450_suspend, - /*.resume = */ mma8450_resume, - /*.read = */ mma8450_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "mma8450", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_MMA8450, - /*.reg = */ 0x00, - /*.len = */ 4, - /*.endian = */ EXT_SLAVE_FS8_BIG_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *mma8450_get_slave_descr(void) -{ - return &mma8450_descr; -} -EXPORT_SYMBOL(mma8450_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/mma8451.c b/drivers/misc/mpu3050/accel/mma8451.c deleted file mode 100644 index 4acf449d170d..000000000000 --- a/drivers/misc/mpu3050/accel/mma8451.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - $License: - Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. - $ - */ - -/** - * @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 mma8451.c - * @brief Accelerometer setup and handling methods for Freescale MMA8451 - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -#define ACCEL_MMA8451_SLEEP_REG (0x2A) -#define ACCEL_MMA8451_SLEEP_MASK (0x01) - - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int mma8451_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - result = - MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_MMA8451_SLEEP_REG, 1, ®); - ERROR_CHECK(result); - reg &= ~ACCEL_MMA8451_SLEEP_MASK; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_MMA8451_SLEEP_REG, reg); - ERROR_CHECK(result); - return result; -} - -/* full scale setting - register & mask */ -#define ACCEL_MMA8451_CTRL_REG (0x0E) -#define ACCEL_MMA8451_CTRL_MASK (0x03) - -int mma8451_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, 0x0E, 1, ®); - ERROR_CHECK(result); - - /* data rate = 200Hz */ - - /* Full Scale */ - reg &= ~ACCEL_MMA8451_CTRL_MASK; - if (slave->range.mantissa == 4) - reg |= 0x1; - else if (slave->range.mantissa == 8) - reg |= 0x2; - else { - slave->range.mantissa = 2; - reg |= 0x0; - } - slave->range.fraction = 0; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0E, reg); - ERROR_CHECK(result); - /* 200Hz + active mode */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x2A, 0x11); - ERROR_CHECK(result); - - return result; -} - -int mma8451_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; -} - -struct ext_slave_descr mma8451_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ mma8451_suspend, - /*.resume = */ mma8451_resume, - /*.read = */ mma8451_read, - /*.config = */ NULL, - /*.name = */ "mma8451", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_MMA8451, - /*.reg = */ 0x00, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_FS16_BIG_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *mma8451_get_slave_descr(void) -{ - return &mma8451_descr; -} -EXPORT_SYMBOL(mma8451_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/accel/mma845x.c b/drivers/misc/mpu3050/accel/mma845x.c deleted file mode 100755 index 648cddbaa935..000000000000 --- a/drivers/misc/mpu3050/accel/mma845x.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 mma845x.c - * @brief Accelerometer setup and handling methods for Freescale MMA845X - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -//#include -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" -//#include - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -#define ACCEL_MMA845X_CTRL_REG1 (0x2A) -#define ACCEL_MMA845X_SLEEP_MASK (0x01) - -/* full scale setting - register & mask */ -#define ACCEL_MMA845X_CFG_REG (0x0E) -#define ACCEL_MMA845X_CTRL_MASK (0x03) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int mma845x_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - result = - MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_MMA845X_CTRL_REG1, 1, ®); - ERROR_CHECK(result); - reg &= ~ACCEL_MMA845X_SLEEP_MASK; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_MMA845X_CTRL_REG1, reg); - ERROR_CHECK(result); - return result; -} - - -int mma845x_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char reg; - - result = MLSLSerialRead(mlsl_handle, pdata->address, - ACCEL_MMA845X_CFG_REG, 1, ®); - ERROR_CHECK(result); - - /* data rate = 200Hz */ - - /* Full Scale */ - reg &= ~ACCEL_MMA845X_CTRL_MASK; - if (slave->range.mantissa == 4) - reg |= 0x1; - else if (slave->range.mantissa == 8) - reg |= 0x2; - else { - slave->range.mantissa = 2; - reg |= 0x0; - } - slave->range.fraction = 0; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_MMA845X_CFG_REG, reg); - ERROR_CHECK(result); - /* 200Hz + active mode */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - ACCEL_MMA845X_CTRL_REG1, 0x11); - ERROR_CHECK(result); - - return result; -} - -int mma845x_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result; - unsigned char local_data[7]; /* Status register + 6 bytes data */ - result = MLSLSerialRead(mlsl_handle, pdata->address, - slave->reg, sizeof(local_data), local_data); - ERROR_CHECK(result); - memcpy(data, &local_data[1], slave->len); - return result; -} - -struct ext_slave_descr mma845x_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ mma845x_suspend, - /*.resume = */ mma845x_resume, - /*.read = */ mma845x_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "mma845x", - /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, - /*.id = */ ACCEL_ID_MMA845X, - /*.reg = */ 0x00, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_FS16_BIG_ENDIAN, - /*.range = */ {2, 0}, -}; - -struct ext_slave_descr *mma845x_get_slave_descr(void) -{ - return &mma845x_descr; -} -EXPORT_SYMBOL(mma845x_get_slave_descr); - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c deleted file mode 100755 index b8aed30ba39b..000000000000 --- a/drivers/misc/mpu3050/compass/ak8975.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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. - */ -/* ------------------ */ - -#include - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#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(void *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); - MLOSSleep(1); /* wait at least 100us */ - ERROR_CHECK(result); - return result; -} - -int ak8975_resume(void *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); - ERROR_CHECK(result); - return result; -} - -int ak8975_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, unsigned char *data) -{ - unsigned char regs[8]; - unsigned char *stat = ®s[0]; - unsigned char *stat2 = ®s[7]; - int result = ML_SUCCESS; - int status = ML_SUCCESS; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1, - 8, regs); - ERROR_CHECK(result); - - /* - * ST : data ready - - * Measurement has been completed and data is ready to be read. - */ - if (*stat & 0x01) { - memcpy(data, ®s[1], 6); - status = ML_SUCCESS; - } - - /* - * ST2 : data error - - * occurs when data read is started outside of a readable period; - * data read would not be correct. - * Valid in continuous measurement mode only. - * In single measurement mode this error should not occour but we - * stil account for it and return an error, since the data would be - * corrupted. - * DERR bit is self-clearing when ST2 register is read. - */ - if (*stat2 & 0x04) - status = ML_ERROR_COMPASS_DATA_ERROR; - /* - * ST2 : overflow - - * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT. - * This is likely to happen in presence of an external magnetic - * disturbance; it indicates, the sensor data is incorrect and should - * be ignored. - * An error is returned. - * HOFL bit clears when a new measurement starts. - */ - if (*stat2 & 0x08) - status = ML_ERROR_COMPASS_DATA_OVERFLOW; - /* - * ST : overrun - - * the previous sample was not fetched and lost. - * Valid in continuous measurement mode only. - * In single measurement mode this error should not occour and we - * don't consider this condition an error. - * DOR bit is self-clearing when ST2 or any meas. data register is - * read. - */ - if (*stat & 0x02) { - /* status = ML_ERROR_COMPASS_DATA_UNDERFLOW; */ - status = ML_SUCCESS; - } - - /* - * trigger next measurement if: - * - stat is non zero; - * - if stat is zero and stat2 is non zero. - * Won't trigger if data is not ready and there was no error. - */ - if (*stat != 0x00 || *stat2 != 0x00) { - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AK8975_REG_CNTL, - AK8975_CNTL_MODE_SINGLE_MEASUREMENT); - ERROR_CHECK(result); - } - - return status; -} - -static int ak8975_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - int result; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_WRITE_REGISTERS: - result = MLSLSerialWrite(mlsl_handle, pdata->address, - data->len, - (unsigned char *)data->data); - ERROR_CHECK(result); - break; - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - case MPU_SLAVE_CONFIG_ODR_RESUME: - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - case MPU_SLAVE_CONFIG_FSR_RESUME: - case MPU_SLAVE_CONFIG_MOT_THS: - case MPU_SLAVE_CONFIG_NMOT_THS: - case MPU_SLAVE_CONFIG_MOT_DUR: - case MPU_SLAVE_CONFIG_NMOT_DUR: - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - case MPU_SLAVE_CONFIG_IRQ_RESUME: - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -static int ak8975_get_config(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config *data) -{ - int result; - if (!data->data) - return ML_ERROR_INVALID_PARAMETER; - - switch (data->key) { - case MPU_SLAVE_READ_REGISTERS: - { - unsigned char *serial_data = (unsigned char *)data->data; - result = MLSLSerialRead(mlsl_handle, pdata->address, - serial_data[0], - data->len - 1, - &serial_data[1]); - ERROR_CHECK(result); - break; - } - case MPU_SLAVE_CONFIG_ODR_SUSPEND: - case MPU_SLAVE_CONFIG_ODR_RESUME: - case MPU_SLAVE_CONFIG_FSR_SUSPEND: - case MPU_SLAVE_CONFIG_FSR_RESUME: - case MPU_SLAVE_CONFIG_MOT_THS: - case MPU_SLAVE_CONFIG_NMOT_THS: - case MPU_SLAVE_CONFIG_MOT_DUR: - case MPU_SLAVE_CONFIG_NMOT_DUR: - case MPU_SLAVE_CONFIG_IRQ_SUSPEND: - case MPU_SLAVE_CONFIG_IRQ_RESUME: - default: - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - }; - - return ML_SUCCESS; -} - -struct ext_slave_descr ak8975_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ ak8975_suspend, - /*.resume = */ ak8975_resume, - /*.read = */ ak8975_read, - /*.config = */ ak8975_config, - /*.get_config = */ ak8975_get_config, - /*.name = */ "ak8975", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_AKM, - /*.reg = */ 0x01, - /*.len = */ 9, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {9830, 4000} -}; - -struct ext_slave_descr *ak8975_get_slave_descr(void) -{ - return &ak8975_descr; -} -EXPORT_SYMBOL(ak8975_get_slave_descr); - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/compass/ami306.c b/drivers/misc/mpu3050/compass/ami306.c deleted file mode 100755 index 75ca007ef01c..000000000000 --- a/drivers/misc/mpu3050/compass/ami306.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 ami306.c - * @brief Magnetometer setup and handling methods for Aichi AMI306 - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -#define AMI306_REG_DATAX (0x10) -#define AMI306_REG_STAT1 (0x18) -#define AMI306_REG_CNTL1 (0x1B) -#define AMI306_REG_CNTL2 (0x1C) -#define AMI306_REG_CNTL3 (0x1D) -#define AMI306_REG_CNTL4_1 (0x5C) -#define AMI306_REG_CNTL4_2 (0x5D) - -#define AMI306_BIT_CNTL1_PC1 (0x80) -#define AMI306_BIT_CNTL1_ODR1 (0x10) -#define AMI306_BIT_CNTL1_FS1 (0x02) - -#define AMI306_BIT_CNTL2_IEN (0x10) -#define AMI306_BIT_CNTL2_DREN (0x08) -#define AMI306_BIT_CNTL2_DRP (0x04) -#define AMI306_BIT_CNTL3_F0RCE (0x40) - -int ami306_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - result = - MLSLSerialRead(mlsl_handle, pdata->address, AMI306_REG_CNTL1, - 1, ®); - ERROR_CHECK(result); - - reg &= ~(AMI306_BIT_CNTL1_PC1|AMI306_BIT_CNTL1_FS1); - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI306_REG_CNTL1, reg); - ERROR_CHECK(result); - - return result; -} - -int ami306_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - unsigned char regs[] = { - AMI306_REG_CNTL4_1, - 0x7E, - 0xA0 - }; - /* Step1. Set CNTL1 reg to power model active (Write CNTL1:PC1=1) */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI306_REG_CNTL1, - AMI306_BIT_CNTL1_PC1|AMI306_BIT_CNTL1_FS1); - ERROR_CHECK(result); - - /* Step2. Set CNTL2 reg to DRDY active high and enabled - (Write CNTL2:DREN=1) */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI306_REG_CNTL2, - AMI306_BIT_CNTL2_DREN | - AMI306_BIT_CNTL2_DRP); - ERROR_CHECK(result); - - /* Step3. Set CNTL4 reg to for measurement speed (Write CNTL4, 0xA07E) */ - result = - MLSLSerialWrite(mlsl_handle, pdata->address, DIM(regs), regs); - ERROR_CHECK(result); - - /* Step4. skipped */ - - /* Step5. Set CNTL3 reg to forced measurement period - (Write CNTL3:FORCE=1) */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI306_REG_CNTL3, AMI306_BIT_CNTL3_F0RCE); - - return result; -} - -int ami306_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, unsigned char *data) -{ - unsigned char stat; - int result = ML_SUCCESS; - int status = ML_SUCCESS; - - - /* Measurement(x,y,z) */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI306_REG_CNTL3, - AMI306_BIT_CNTL3_F0RCE); - ERROR_CHECK(result); - udelay(500); - - /* Step6. Read status reg and check if data ready (DRDY) */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, AMI306_REG_STAT1, - 1, &stat); - ERROR_CHECK(result); - - /* Step6. Does DRDY output the rising edge? */ - if (stat & 0x40) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - AMI306_REG_DATAX, 6, - (unsigned char *) data); - ERROR_CHECK(result); - status = ML_SUCCESS; - } else if (stat & 0x20) - status = ML_ERROR_COMPASS_DATA_OVERFLOW; - - return status; -} - -struct ext_slave_descr ami306_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ ami306_suspend, - /*.resume = */ ami306_resume, - /*.read = */ ami306_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "ami306", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_AMI306, - /*.reg = */ 0x10, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {5461, 3333} - /* For AMI305,the range field needs to be modified to {9830.4f}*/ -}; - -struct ext_slave_descr *ami306_get_slave_descr(void) -{ - return &ami306_descr; -} -EXPORT_SYMBOL(ami306_get_slave_descr); - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/compass/ami30x.c b/drivers/misc/mpu3050/compass/ami30x.c deleted file mode 100755 index 5e4a33efc7f2..000000000000 --- a/drivers/misc/mpu3050/compass/ami30x.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 ami30x.c - * @brief Magnetometer setup and handling methods for Aichi AMI304/AMI305 - * compass. -*/ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -#define AMI30X_REG_DATAX (0x10) -#define AMI30X_REG_STAT1 (0x18) -#define AMI30X_REG_CNTL1 (0x1B) -#define AMI30X_REG_CNTL2 (0x1C) -#define AMI30X_REG_CNTL3 (0x1D) - -#define AMI30X_BIT_CNTL1_PC1 (0x80) -#define AMI30X_BIT_CNTL1_ODR1 (0x10) -#define AMI30X_BIT_CNTL1_FS1 (0x02) - -#define AMI30X_BIT_CNTL2_IEN (0x10) -#define AMI30X_BIT_CNTL2_DREN (0x08) -#define AMI30X_BIT_CNTL2_DRP (0x04) -#define AMI30X_BIT_CNTL3_F0RCE (0x40) - -int ami30x_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result; - unsigned char reg; - result = - MLSLSerialRead(mlsl_handle, pdata->address, AMI30X_REG_CNTL1, - 1, ®); - ERROR_CHECK(result); - - reg &= ~(AMI30X_BIT_CNTL1_PC1|AMI30X_BIT_CNTL1_FS1); - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI30X_REG_CNTL1, reg); - ERROR_CHECK(result); - - return result; -} - -int ami30x_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Set CNTL1 reg to power model active */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI30X_REG_CNTL1, - AMI30X_BIT_CNTL1_PC1|AMI30X_BIT_CNTL1_FS1); - ERROR_CHECK(result); - /* Set CNTL2 reg to DRDY active high and enabled */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI30X_REG_CNTL2, - AMI30X_BIT_CNTL2_DREN | - AMI30X_BIT_CNTL2_DRP); - ERROR_CHECK(result); - /* Set CNTL3 reg to forced measurement period */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI30X_REG_CNTL3, AMI30X_BIT_CNTL3_F0RCE); - - return result; -} - -int ami30x_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, unsigned char *data) -{ - unsigned char stat; - int result = ML_SUCCESS; - - /* Read status reg and check if data ready (DRDY) */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, AMI30X_REG_STAT1, - 1, &stat); - ERROR_CHECK(result); - - if (stat & 0x40) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - AMI30X_REG_DATAX, 6, - (unsigned char *) data); - ERROR_CHECK(result); - /* start another measurement */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - AMI30X_REG_CNTL3, - AMI30X_BIT_CNTL3_F0RCE); - ERROR_CHECK(result); - - return ML_SUCCESS; - } - - return ML_ERROR_COMPASS_DATA_NOT_READY; -} - -struct ext_slave_descr ami30x_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ ami30x_suspend, - /*.resume = */ ami30x_resume, - /*.read = */ ami30x_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "ami30x", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_AMI30X, - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {5461, 3333} - /* For AMI305,the range field needs to be modified to {9830.4f}*/ -}; - -struct ext_slave_descr *ami30x_get_slave_descr(void) -{ - return &ami30x_descr; -} -EXPORT_SYMBOL(ami30x_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/hmc5883.c b/drivers/misc/mpu3050/compass/hmc5883.c deleted file mode 100755 index 02afd58fd7b7..000000000000 --- a/drivers/misc/mpu3050/compass/hmc5883.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @brief Provides the interface to setup and handle a compass - * connected to the primary I2C interface of the gyroscope. - * - * @{ - * @file hmc5883.c - * @brief Magnetometer setup and handling methods for honeywell hmc5883 - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/*-----HONEYWELL HMC5883 Registers ------*/ -enum HMC_REG { - HMC_REG_CONF_A = 0x0, - HMC_REG_CONF_B = 0x1, - HMC_REG_MODE = 0x2, - HMC_REG_X_M = 0x3, - HMC_REG_X_L = 0x4, - HMC_REG_Z_M = 0x5, - HMC_REG_Z_L = 0x6, - HMC_REG_Y_M = 0x7, - HMC_REG_Y_L = 0x8, - HMC_REG_STATUS = 0x9, - HMC_REG_ID_A = 0xA, - HMC_REG_ID_B = 0xB, - HMC_REG_ID_C = 0xC -}; - -enum HMC_CONF_A { - HMC_CONF_A_DRATE_MASK = 0x1C, - HMC_CONF_A_DRATE_0_75 = 0x00, - HMC_CONF_A_DRATE_1_5 = 0x04, - HMC_CONF_A_DRATE_3 = 0x08, - HMC_CONF_A_DRATE_7_5 = 0x0C, - HMC_CONF_A_DRATE_15 = 0x10, - HMC_CONF_A_DRATE_30 = 0x14, - HMC_CONF_A_DRATE_75 = 0x18, - HMC_CONF_A_MEAS_MASK = 0x3, - HMC_CONF_A_MEAS_NORM = 0x0, - HMC_CONF_A_MEAS_POS = 0x1, - HMC_CONF_A_MEAS_NEG = 0x2 -}; - -enum HMC_CONF_B{ - HMC_CONF_B_GAIN_MASK = 0xE0, - HMC_CONF_B_GAIN_0_9 = 0x00, - HMC_CONF_B_GAIN_1_2 = 0x20, - HMC_CONF_B_GAIN_1_9 = 0x40, - HMC_CONF_B_GAIN_2_5 = 0x60, - HMC_CONF_B_GAIN_4_0 = 0x80, - HMC_CONF_B_GAIN_4_6 = 0xA0, - HMC_CONF_B_GAIN_5_5 = 0xC0, - HMC_CONF_B_GAIN_7_9 = 0xE0 -}; - -enum HMC_MODE { - HMC_MODE_MASK = 0x3, - HMC_MODE_CONT = 0x0, - HMC_MODE_SINGLE = 0x1, - HMC_MODE_IDLE = 0x2, - HMC_MODE_SLEEP = 0x3 -}; - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int hmc5883_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - HMC_REG_MODE, HMC_MODE_SLEEP); - ERROR_CHECK(result); - MLOSSleep(3); - - return result; -} - -int hmc5883_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Use single measurement mode. Start at sleep state. */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - HMC_REG_MODE, HMC_MODE_SLEEP); - ERROR_CHECK(result); - /* Config normal measurement */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - HMC_REG_CONF_A, 0); - ERROR_CHECK(result); - /* Adjust gain to 307 LSB/Gauss */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - HMC_REG_CONF_B, HMC_CONF_B_GAIN_5_5); - ERROR_CHECK(result); - - return result; -} - -int hmc5883_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - unsigned char stat; - tMLError result = ML_SUCCESS; - unsigned char tmp; - short axisFixed; - - /* Read status reg. to check if data is ready */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, HMC_REG_STATUS, 1, - &stat); - ERROR_CHECK(result); - if (stat & 0x01) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - HMC_REG_X_M, 6, (unsigned char *) data); - ERROR_CHECK(result); - - /* switch YZ axis to proper position */ - tmp = data[2]; - data[2] = data[4]; - data[4] = tmp; - tmp = data[3]; - data[3] = data[5]; - data[5] = tmp; - - /*drop data if overflows */ - if ((data[0] == 0xf0) || (data[2] == 0xf0) - || (data[4] == 0xf0)) { - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, - pdata->address, - HMC_REG_MODE, - HMC_MODE_SINGLE); - ERROR_CHECK(result); - return ML_ERROR_COMPASS_DATA_OVERFLOW; - } - /* convert to fixed point and apply sensitivity correction for - Z-axis */ - axisFixed = - (short) ((unsigned short) data[5] + - (unsigned short) data[4] * 256); - /* scale up by 1.125 (36/32) */ - axisFixed = (short) (axisFixed * 36); - data[4] = axisFixed >> 8; - data[5] = axisFixed & 0xFF; - - axisFixed = - (short) ((unsigned short) data[3] + - (unsigned short) data[2] * 256); - axisFixed = (short) (axisFixed * 32); - data[2] = axisFixed >> 8; - data[3] = axisFixed & 0xFF; - - axisFixed = - (short) ((unsigned short) data[1] + - (unsigned short) data[0] * 256); - axisFixed = (short) (axisFixed * 32); - data[0] = axisFixed >> 8; - data[1] = axisFixed & 0xFF; - - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - HMC_REG_MODE, HMC_MODE_SINGLE); - ERROR_CHECK(result); - - return ML_SUCCESS; - } else { - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - HMC_REG_MODE, HMC_MODE_SINGLE); - ERROR_CHECK(result); - - return ML_ERROR_COMPASS_DATA_NOT_READY; - } -} - -struct ext_slave_descr hmc5883_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ hmc5883_suspend, - /*.resume = */ hmc5883_resume, - /*.read = */ hmc5883_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "hmc5883", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_HMC5883, - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {10673, 6156}, -}; - -struct ext_slave_descr *hmc5883_get_slave_descr(void) -{ - return &hmc5883_descr; -} -EXPORT_SYMBOL(hmc5883_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/hscdtd002b.c b/drivers/misc/mpu3050/compass/hscdtd002b.c deleted file mode 100755 index bf26cae06d2d..000000000000 --- a/drivers/misc/mpu3050/compass/hscdtd002b.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @brief Provides the interface to setup and handle a compass - * connected to the primary I2C interface of the gyroscope. - * - * @{ - * @file hscdtd002b.c - * @brief Magnetometer setup and handling methods for Alps hscdtd002b - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/*----- ALPS HSCDTD002B Registers ------*/ -#define COMPASS_HSCDTD002B_STAT (0x18) -#define COMPASS_HSCDTD002B_CTRL1 (0x1B) -#define COMPASS_HSCDTD002B_CTRL2 (0x1C) -#define COMPASS_HSCDTD002B_CTRL3 (0x1D) -#define COMPASS_HSCDTD002B_DATAX (0x10) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Compass Initialization Functions -*****************************************/ - -int hscdtd002b_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Power mode: stand-by */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_CTRL1, 0x00); - ERROR_CHECK(result); - MLOSSleep(1); /* turn-off time */ - - return result; -} - -int hscdtd002b_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Soft reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_CTRL3, 0x80); - ERROR_CHECK(result); - /* Force state; Power mode: active */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_CTRL1, 0x82); - ERROR_CHECK(result); - /* Data ready enable */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_CTRL2, 0x08); - ERROR_CHECK(result); - MLOSSleep(1); /* turn-on time */ - - return result; -} - -int hscdtd002b_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - unsigned char stat; - tMLError result = ML_SUCCESS; - int status = ML_SUCCESS; - - /* Read status reg. to check if data is ready */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_STAT, 1, &stat); - ERROR_CHECK(result); - if (stat & 0x40) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_DATAX, 6, - (unsigned char *) data); - ERROR_CHECK(result); - status = ML_SUCCESS; - } else if (stat & 0x20) { - status = ML_ERROR_COMPASS_DATA_OVERFLOW; - } else { - status = ML_ERROR_COMPASS_DATA_NOT_READY; - } - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD002B_CTRL3, 0x40); - ERROR_CHECK(result); - - return status; -} - -struct ext_slave_descr hscdtd002b_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ hscdtd002b_suspend, - /*.resume = */ hscdtd002b_resume, - /*.read = */ hscdtd002b_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "hscdtd002b", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_HSCDTD002B, - /*.reg = */ 0x10, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {9830, 4000}, -}; - -struct ext_slave_descr *hscdtd002b_get_slave_descr(void) -{ - return &hscdtd002b_descr; -} -EXPORT_SYMBOL(hscdtd002b_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/hscdtd004a.c b/drivers/misc/mpu3050/compass/hscdtd004a.c deleted file mode 100755 index 43fc14a23fc4..000000000000 --- a/drivers/misc/mpu3050/compass/hscdtd004a.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @brief Provides the interface to setup and handle a compass - * connected to the primary I2C interface of the gyroscope. - * - * @{ - * @file hscdtd004a.c - * @brief Magnetometer setup and handling methods for Alps hscdtd004a - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/*----- ALPS HSCDTD004A Registers ------*/ -#define COMPASS_HSCDTD004A_STAT (0x18) -#define COMPASS_HSCDTD004A_CTRL1 (0x1B) -#define COMPASS_HSCDTD004A_CTRL2 (0x1C) -#define COMPASS_HSCDTD004A_CTRL3 (0x1D) -#define COMPASS_HSCDTD004A_DATAX (0x10) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Compass Initialization Functions -*****************************************/ - -int hscdtd004a_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Power mode: stand-by */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_CTRL1, 0x00); - ERROR_CHECK(result); - MLOSSleep(1); /* turn-off time */ - - return result; -} - -int hscdtd004a_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Soft reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_CTRL3, 0x80); - ERROR_CHECK(result); - /* Normal state; Power mode: active */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_CTRL1, 0x82); - ERROR_CHECK(result); - /* Data ready enable */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_CTRL2, 0x7C); - ERROR_CHECK(result); - MLOSSleep(1); /* turn-on time */ - return result; -} - -int hscdtd004a_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - unsigned char stat; - tMLError result = ML_SUCCESS; - int status = ML_SUCCESS; - - /* Read status reg. to check if data is ready */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_STAT, 1, &stat); - ERROR_CHECK(result); - if (stat & 0x48) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_DATAX, 6, - (unsigned char *) data); - ERROR_CHECK(result); - status = ML_SUCCESS; - } else if (stat & 0x68) { - status = ML_ERROR_COMPASS_DATA_OVERFLOW; - } else { - status = ML_ERROR_COMPASS_DATA_NOT_READY; - } - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD004A_CTRL3, 0x40); - ERROR_CHECK(result); - return status; - -} - -struct ext_slave_descr hscdtd004a_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ hscdtd004a_suspend, - /*.resume = */ hscdtd004a_resume, - /*.read = */ hscdtd004a_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "hscdtd004a", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_HSCDTD004A, - /*.reg = */ 0x10, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {9830, 4000}, -}; - -struct ext_slave_descr *hscdtd004a_get_slave_descr(void) -{ - return &hscdtd004a_descr; -} -EXPORT_SYMBOL(hscdtd004a_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/hscdtd00xx.c b/drivers/misc/mpu3050/compass/hscdtd00xx.c deleted file mode 100644 index 69aa3bb39042..000000000000 --- a/drivers/misc/mpu3050/compass/hscdtd00xx.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - $License: - Copyright (C) 2010 InvenSense Corporation, All Rights Reserved. - $ - */ - -/** - * @brief Provides the interface to setup and handle a compass - * connected to the primary I2C interface of the gyroscope. - * - * @{ - * @file hscdtd00xx.c - * @brief Magnetometer setup and handling methods for Alps hscdtd00xx - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/*----- ALPS HSCDTD00XX Registers ------*/ -#define COMPASS_HSCDTD00XX_STAT (0x18) -#define COMPASS_HSCDTD00XX_CTRL1 (0x1B) -#define COMPASS_HSCDTD00XX_CTRL2 (0x1C) -#define COMPASS_HSCDTD00XX_CTRL3 (0x1D) -#define COMPASS_HSCDTD00XX_DATAX (0x10) - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Compass Initialization Functions -*****************************************/ - -int hscdtd00xx_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Power mode: stand-by */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL1, 0x00); - ERROR_CHECK(result); - MLOSSleep(1); /* turn-off time */ - - return result; -} - -int hscdtd00xx_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Soft reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL3, 0x80); - ERROR_CHECK(result); - /* Force state; Power mode: active */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL1, 0x82); - ERROR_CHECK(result); - /* Data ready enable */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL2, 0x08); - ERROR_CHECK(result); - MLOSSleep(1); /* turn-on time */ - - return result; -} - -int hscdtd00xx_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - unsigned char stat; - tMLError result = ML_SUCCESS; - - /* Read status reg. to check if data is ready */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_STAT, 1, &stat); - ERROR_CHECK(result); - if (stat & 0x40) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_DATAX, 6, - (unsigned char *) data); - ERROR_CHECK(result); - - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL3, 0x40); - ERROR_CHECK(result); - - return ML_SUCCESS; - } else if (stat & 0x20) { - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL3, 0x40); - ERROR_CHECK(result); - return ML_ERROR_COMPASS_DATA_OVERFLOW; - } else { - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - COMPASS_HSCDTD00XX_CTRL3, 0x40); - ERROR_CHECK(result); - return ML_ERROR_COMPASS_DATA_NOT_READY; - } -} - -struct ext_slave_descr hscdtd00xx_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ hscdtd00xx_suspend, - /*.resume = */ hscdtd00xx_resume, - /*.read = */ hscdtd00xx_read, - /*.config = */ NULL, - /*.name = */ "hscdtd00xx", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_HSCDTD00XX, - /*.reg = */ 0x10, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN, - /*.range = */ {9830, 4000}, -}; - -struct ext_slave_descr *hscdtd00xx_get_slave_descr(void) -{ - return &hscdtd00xx_descr; -} -EXPORT_SYMBOL(hscdtd00xx_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/lsm303m.c b/drivers/misc/mpu3050/compass/lsm303m.c deleted file mode 100755 index 871d002fd364..000000000000 --- a/drivers/misc/mpu3050/compass/lsm303m.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @brief Provides the interface to setup and handle a compass - * connected to the primary I2C interface of the gyroscope. - * - * @{ - * @file lsm303m.c - * @brief Magnetometer setup and handling methods for ST LSM303. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/*----- ST LSM303 Registers ------*/ -enum LSM_REG { - LSM_REG_CONF_A = 0x0, - LSM_REG_CONF_B = 0x1, - LSM_REG_MODE = 0x2, - LSM_REG_X_M = 0x3, - LSM_REG_X_L = 0x4, - LSM_REG_Z_M = 0x5, - LSM_REG_Z_L = 0x6, - LSM_REG_Y_M = 0x7, - LSM_REG_Y_L = 0x8, - LSM_REG_STATUS = 0x9, - LSM_REG_ID_A = 0xA, - LSM_REG_ID_B = 0xB, - LSM_REG_ID_C = 0xC -}; - -enum LSM_CONF_A { - LSM_CONF_A_DRATE_MASK = 0x1C, - LSM_CONF_A_DRATE_0_75 = 0x00, - LSM_CONF_A_DRATE_1_5 = 0x04, - LSM_CONF_A_DRATE_3 = 0x08, - LSM_CONF_A_DRATE_7_5 = 0x0C, - LSM_CONF_A_DRATE_15 = 0x10, - LSM_CONF_A_DRATE_30 = 0x14, - LSM_CONF_A_DRATE_75 = 0x18, - LSM_CONF_A_MEAS_MASK = 0x3, - LSM_CONF_A_MEAS_NORM = 0x0, - LSM_CONF_A_MEAS_POS = 0x1, - LSM_CONF_A_MEAS_NEG = 0x2 -}; - -enum LSM_CONF_B { - LSM_CONF_B_GAIN_MASK = 0xE0, - LSM_CONF_B_GAIN_0_9 = 0x00, - LSM_CONF_B_GAIN_1_2 = 0x20, - LSM_CONF_B_GAIN_1_9 = 0x40, - LSM_CONF_B_GAIN_2_5 = 0x60, - LSM_CONF_B_GAIN_4_0 = 0x80, - LSM_CONF_B_GAIN_4_6 = 0xA0, - LSM_CONF_B_GAIN_5_5 = 0xC0, - LSM_CONF_B_GAIN_7_9 = 0xE0 -}; - -enum LSM_MODE { - LSM_MODE_MASK = 0x3, - LSM_MODE_CONT = 0x0, - LSM_MODE_SINGLE = 0x1, - LSM_MODE_IDLE = 0x2, - LSM_MODE_SLEEP = 0x3 -}; - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int lsm303dlhm_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LSM_REG_MODE, LSM_MODE_SLEEP); - ERROR_CHECK(result); - MLOSSleep(3); - - return result; -} - -int lsm303dlhm_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - /* Use single measurement mode. Start at sleep state. */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LSM_REG_MODE, LSM_MODE_SLEEP); - ERROR_CHECK(result); - /* Config normal measurement */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LSM_REG_CONF_A, 0); - ERROR_CHECK(result); - /* Adjust gain to 320 LSB/Gauss */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LSM_REG_CONF_B, LSM_CONF_B_GAIN_5_5); - ERROR_CHECK(result); - - return result; -} - -int lsm303dlhm_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - unsigned char stat; - tMLError result = ML_SUCCESS; - short axisFixed; - - /* Read status reg. to check if data is ready */ - result = - MLSLSerialRead(mlsl_handle, pdata->address, LSM_REG_STATUS, 1, - &stat); - ERROR_CHECK(result); - if (stat & 0x01) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - LSM_REG_X_M, 6, (unsigned char *) data); - ERROR_CHECK(result); - - /*drop data if overflows */ - if ((data[0] == 0xf0) || (data[2] == 0xf0) - || (data[4] == 0xf0)) { - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, - pdata->address, - LSM_REG_MODE, - LSM_MODE_SINGLE); - ERROR_CHECK(result); - return ML_ERROR_COMPASS_DATA_OVERFLOW; - } - /* convert to fixed point and apply sensitivity correction for - Z-axis */ - axisFixed = - (short) ((unsigned short) data[5] + - (unsigned short) data[4] * 256); - /* scale up by 1.125 (36/32) approximate of 1.122 (320/285) */ - axisFixed = (short) (axisFixed * 36); - data[4] = axisFixed >> 8; - data[5] = axisFixed & 0xFF; - - axisFixed = - (short) ((unsigned short) data[3] + - (unsigned short) data[2] * 256); - axisFixed = (short) (axisFixed * 32); - data[2] = axisFixed >> 8; - data[3] = axisFixed & 0xFF; - - axisFixed = - (short) ((unsigned short) data[1] + - (unsigned short) data[0] * 256); - axisFixed = (short) (axisFixed * 32); - data[0] = axisFixed >> 8; - data[1] = axisFixed & 0xFF; - - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LSM_REG_MODE, LSM_MODE_SINGLE); - ERROR_CHECK(result); - - return ML_SUCCESS; - } else { - /* trigger next measurement read */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - LSM_REG_MODE, LSM_MODE_SINGLE); - ERROR_CHECK(result); - - return ML_ERROR_COMPASS_DATA_NOT_READY; - } -} - -struct ext_slave_descr lsm303dlhm_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ lsm303dlhm_suspend, - /*.resume = */ lsm303dlhm_resume, - /*.read = */ lsm303dlhm_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "lsm303dlhm", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_LSM303, - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {10240, 0}, -}; - -struct ext_slave_descr *lsm303dlhm_get_slave_descr(void) -{ - return &lsm303dlhm_descr; -} -EXPORT_SYMBOL(lsm303dlhm_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/mmc314x.c b/drivers/misc/mpu3050/compass/mmc314x.c deleted file mode 100755 index 010d7a78d149..000000000000 --- a/drivers/misc/mpu3050/compass/mmc314x.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 mmc314x.c - * @brief Magnetometer setup and handling methods for ???? compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -static int reset_int = 1000; -static int read_count = 1; -static char reset_mode; /* in Z-init section */ - -#define MMC314X_REG_ST (0x00) -#define MMC314X_REG_X_MSB (0x01) - -#define MMC314X_CNTL_MODE_WAKE_UP (0x01) -#define MMC314X_CNTL_MODE_SET (0x02) -#define MMC314X_CNTL_MODE_RESET (0x04) - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int mmc314x_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - return result; -} - -int mmc314x_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - - int result; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MMC314X_REG_ST, MMC314X_CNTL_MODE_RESET); - ERROR_CHECK(result); - MLOSSleep(10); - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MMC314X_REG_ST, MMC314X_CNTL_MODE_SET); - ERROR_CHECK(result); - MLOSSleep(10); - read_count = 1; - return ML_SUCCESS; -} - -int mmc314x_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data) -{ - int result, ii; - short tmp[3]; - unsigned char tmpdata[6]; - - - if (read_count > 1000) - read_count = 1; - - result = - MLSLSerialRead(mlsl_handle, pdata->address, MMC314X_REG_X_MSB, - 6, (unsigned char *) data); - ERROR_CHECK(result); - - for (ii = 0; ii < 6; ii++) - tmpdata[ii] = data[ii]; - - for (ii = 0; ii < 3; ii++) { - tmp[ii] = - (short) ((tmpdata[2 * ii] << 8) + tmpdata[2 * ii + 1]); - tmp[ii] = tmp[ii] - 4096; - tmp[ii] = tmp[ii] * 16; - } - - for (ii = 0; ii < 3; ii++) { - data[2 * ii] = (unsigned char) (tmp[ii] >> 8); - data[2 * ii + 1] = (unsigned char) (tmp[ii]); - } - - if (read_count % reset_int == 0) { - if (reset_mode) { - result = - MLSLSerialWriteSingle(mlsl_handle, - pdata->address, - MMC314X_REG_ST, - MMC314X_CNTL_MODE_RESET); - ERROR_CHECK(result); - reset_mode = 0; - return ML_ERROR_COMPASS_DATA_NOT_READY; - } else { - result = - MLSLSerialWriteSingle(mlsl_handle, - pdata->address, - MMC314X_REG_ST, - MMC314X_CNTL_MODE_SET); - ERROR_CHECK(result); - reset_mode = 1; - read_count++; - return ML_ERROR_COMPASS_DATA_NOT_READY; - } - } - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - MMC314X_REG_ST, - MMC314X_CNTL_MODE_WAKE_UP); - ERROR_CHECK(result); - read_count++; - - return ML_SUCCESS; -} - -struct ext_slave_descr mmc314x_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ mmc314x_suspend, - /*.resume = */ mmc314x_resume, - /*.read = */ mmc314x_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "mmc314x", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_MMC314X, - /*.reg = */ 0x01, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {400, 0}, -}; - -struct ext_slave_descr *mmc314x_get_slave_descr(void) -{ - return &mmc314x_descr; -} -EXPORT_SYMBOL(mmc314x_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/compass/yas529-kernel.c b/drivers/misc/mpu3050/compass/yas529-kernel.c deleted file mode 100755 index 239ab669cc1b..000000000000 --- a/drivers/misc/mpu3050/compass/yas529-kernel.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - $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 . - $ - */ -/** - * @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 yas529.c - * @brief Magnetometer setup and handling methods for Yamaha yas529 - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#include -#endif - -#include "mpu.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-acc" - -/*----- YAMAHA YAS529 Registers ------*/ -enum YAS_REG { - YAS_REG_CMDR = 0x00, /* 000 < 5 */ - YAS_REG_XOFFSETR = 0x20, /* 001 < 5 */ - YAS_REG_Y1OFFSETR = 0x40, /* 010 < 5 */ - YAS_REG_Y2OFFSETR = 0x60, /* 011 < 5 */ - YAS_REG_ICOILR = 0x80, /* 100 < 5 */ - YAS_REG_CAL = 0xA0, /* 101 < 5 */ - YAS_REG_CONFR = 0xC0, /* 110 < 5 */ - YAS_REG_DOUTR = 0xE0 /* 111 < 5 */ -}; - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -static long a1; -static long a2; -static long a3; -static long a4; -static long a5; -static long a6; -static long a7; -static long a8; -static long a9; - -/***************************************** - Yamaha I2C access functions -*****************************************/ - -static int yas529_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; -} - -static int yas529_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 = I2C_M_RD; - msgs[0].buf = data; - msgs[0].len = len; - - res = i2c_transfer(i2c_adap, msgs, 1); - if (res < 1) - return res; - else - return 0; -} - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int yas529_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - return result; -} - -int yas529_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - unsigned char dummyData[1] = { 0 }; - unsigned char dummyRegister = 0; - unsigned char rawData[6]; - unsigned char calData[9]; - - short xoffset, y1offset, y2offset; - short d2, d3, d4, d5, d6, d7, d8, d9; - - /* YAS529 Application Manual MS-3C - Section 4.4.5 */ - /* =============================================== */ - /* Step 1 - register initialization */ - /* zero initialization coil register - "100 00 000" */ - dummyData[0] = YAS_REG_ICOILR | 0x00; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - /* zero config register - "110 00 000" */ - dummyData[0] = YAS_REG_CONFR | 0x00; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - - /* Step 2 - initialization coil operation */ - dummyData[0] = YAS_REG_ICOILR | 0x11; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x01; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x12; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x02; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x13; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x03; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x14; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x04; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x15; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x05; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x16; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x06; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x17; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x07; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x10; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_ICOILR | 0x00; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - - /* Step 3 - rough offset measurement */ - /* Config register - Measurements results - "110 00 000" */ - dummyData[0] = YAS_REG_CONFR | 0x00; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - /* Measurements command register - Rough offset measurement - - "000 00001" */ - dummyData[0] = YAS_REG_CMDR | 0x01; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - MLOSSleep(2); /* wait at least 1.5ms */ - - /* Measurement data read */ - result = - yas529_sensor_i2c_read(mlsl_handle, pdata->address, - dummyRegister, 6, rawData); - ERROR_CHECK(result); - xoffset = - (short) ((unsigned short) rawData[5] + - ((unsigned short) rawData[4] & 0x7) * 256) - 5; - if (xoffset < 0) - xoffset = 0; - y1offset = - (short) ((unsigned short) rawData[3] + - ((unsigned short) rawData[2] & 0x7) * 256) - 5; - if (y1offset < 0) - y1offset = 0; - y2offset = - (short) ((unsigned short) rawData[1] + - ((unsigned short) rawData[0] & 0x7) * 256) - 5; - if (y2offset < 0) - y2offset = 0; - - /* Step 4 - rough offset setting */ - /* Set rough offset register values */ - dummyData[0] = YAS_REG_XOFFSETR | xoffset; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_Y1OFFSETR | y1offset; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - dummyData[0] = YAS_REG_Y2OFFSETR | y2offset; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - - /* CAL matrix read (first read is invalid) */ - /* Config register - CAL register read - "110 01 000" */ - dummyData[0] = YAS_REG_CONFR | 0x08; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - /* CAL data read */ - result = - yas529_sensor_i2c_read(mlsl_handle, pdata->address, - dummyRegister, 9, calData); - ERROR_CHECK(result); - /* Config register - CAL register read - "110 01 000" */ - dummyData[0] = YAS_REG_CONFR | 0x08; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - /* CAL data read */ - result = - yas529_sensor_i2c_read(mlsl_handle, pdata->address, - dummyRegister, 9, calData); - ERROR_CHECK(result); - - /* Calculate coefficients of the sensitivity corrcetion matrix */ -#if 1 /* production sensor */ - a1 = 100; - d2 = (calData[0] & 0xFC) >> 2; /* [71..66] 6bit */ - a2 = (short) (d2 - 32); - /* [65..62] 4bit */ - d3 = ((calData[0] & 0x03) << 2) | ((calData[1] & 0xC0) >> 6); - a3 = (short) (d3 - 8); - d4 = (calData[1] & 0x3F); /* [61..56] 6bit */ - a4 = (short) (d4 - 32); - d5 = (calData[2] & 0xFC) >> 2; /* [55..50] 6bit */ - a5 = (short) (d5 - 32) + 70; - /* [49..44] 6bit */ - d6 = ((calData[2] & 0x03) << 4) | ((calData[3] & 0xF0) >> 4); - a6 = (short) (d6 - 32); - /* [43..38] 6bit */ - d7 = ((calData[3] & 0x0F) << 2) | ((calData[4] & 0xC0) >> 6); - a7 = (short) (d7 - 32); - d8 = (calData[4] & 0x3F); /* [37..32] 6bit */ - a8 = (short) (d8 - 32); - d9 = (calData[5] & 0xFE) >> 1; /* [31..25] 7bit */ - a9 = (short) (d9 - 64) + 130; -#else /* evaluation sensor */ - a1 = 1.0f; - /* [71..66] 6bit */ - d2 = (calData[0] & 0xFC) >> 2; - a2 = (short) d2; - /* [65..60] 6bit */ - d3 = ((calData[0] & 0x03) << 4) | ((calData[1] & 0xF0) >> 4); - a3 = (short) d3; - /* [59..54] 6bit */ - d4 = ((calData[1] & 0x0F) << 2) | ((calData[2] & 0xC0) >> 6); - a4 = (short) d4; - /* [53..48] 6bit */ - d5 = (calData[2] & 0x3F); - a5 = (short) (d5 + 70); - /* [47..42] 6bit */ - d6 = ((calData[3] & 0xFC) >> 2); - a6 = (short) d6; - /* [41..36] 6bit */ - d7 = ((calData[3] & 0x03) << 4) | ((calData[4] & 0xF0) >> 4); - a7 = (short) d7; - /* [35..30] 6bit */ - d8 = ((calData[4] & 0x0F) << 2) | ((calData[5] & 0xC0) >> 6); - a8 = (short) d8; - /* [29..24] 6bit */ - d9 = (calData[5] & 0x3F); - a9 = (short) (d9 + 150); -#endif - - return result; -} - -int yas529_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, unsigned char *data) -{ - unsigned char stat; - unsigned char rawData[6]; - unsigned char dummyData[1] = { 0 }; - unsigned char dummyRegister = 0; - tMLError result = ML_SUCCESS; - short SX, SY1, SY2, SY, SZ; - short row1fixed, row2fixed, row3fixed; - - /* Config register - Measurements results - "110 00 000" */ - dummyData[0] = YAS_REG_CONFR | 0x00; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - /* Measurements command register - Normal magnetic field measurement - - "000 00000" */ - dummyData[0] = YAS_REG_CMDR | 0x00; - result = - yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1, - dummyData); - ERROR_CHECK(result); - MLOSSleep(10); - /* Measurement data read */ - result = - yas529_sensor_i2c_read(mlsl_handle, pdata->address, - dummyRegister, 6, - (unsigned char *) &rawData); - ERROR_CHECK(result); - - stat = rawData[0] & 0x80; - if (stat == 0x00) { - /* Extract raw data */ - SX = (short) ((unsigned short) rawData[5] + - ((unsigned short) rawData[4] & 0x7) * 256); - SY1 = - (short) ((unsigned short) rawData[3] + - ((unsigned short) rawData[2] & 0x7) * 256); - SY2 = - (short) ((unsigned short) rawData[1] + - ((unsigned short) rawData[0] & 0x7) * 256); - if ((SX <= 1) || (SY1 <= 1) || (SY2 <= 1)) - return ML_ERROR_COMPASS_DATA_UNDERFLOW; - if ((SX >= 1024) || (SY1 >= 1024) || (SY2 >= 1024)) - return ML_ERROR_COMPASS_DATA_OVERFLOW; - /* Convert to XYZ axis */ - SX = -1 * SX; - SY = SY2 - SY1; - SZ = SY1 + SY2; - - /* Apply sensitivity correction matrix */ - row1fixed = - (short) ((a1 * SX + a2 * SY + a3 * SZ) >> 7) * 41; - row2fixed = - (short) ((a4 * SX + a5 * SY + a6 * SZ) >> 7) * 41; - row3fixed = - (short) ((a7 * SX + a8 * SY + a9 * SZ) >> 7) * 41; - - data[0] = row1fixed >> 8; - data[1] = row1fixed & 0xFF; - data[2] = row2fixed >> 8; - data[3] = row2fixed & 0xFF; - data[4] = row3fixed >> 8; - data[5] = row3fixed & 0xFF; - - return ML_SUCCESS; - } else { - return ML_ERROR_COMPASS_DATA_NOT_READY; - } -} - -struct ext_slave_descr yas529_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ yas529_suspend, - /*.resume = */ yas529_resume, - /*.read = */ yas529_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "yas529", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_YAS529, - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {19660, 8000}, -}; - -struct ext_slave_descr *yas529_get_slave_descr(void) -{ - return &yas529_descr; -} -EXPORT_SYMBOL(yas529_get_slave_descr); - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/compass/yas530-kernel.c b/drivers/misc/mpu3050/compass/yas530-kernel.c deleted file mode 100755 index f6dbb5691eb6..000000000000 --- a/drivers/misc/mpu3050/compass/yas530-kernel.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - $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 . - $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 . - $ - */ - /** - * @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 yas530.c - * @brief Magnetometer setup and handling methods for Yamaha yas530 - * compass. - */ - - /* ------------------ */ - /* - Include Files. - */ - /* ------------------ */ - -#include "mpu.h" -#include "mltypes.h" - -#include "mlsl.h" -#include "mlos.h" - -#ifdef __KERNEL__ -#include -#include -#include -#endif - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-yas530:" - - -extern int geomagnetic_api_resume(void); -extern int geomagnetic_api_suspend(void); -extern int geomagnetic_api_read(int *xyz, int *raw, int *xy1y2, int *accuracy); - - /***************************************** - Compass Initialization Functions - *****************************************/ - -static int -yas530_suspend -( - void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata -) -{ - int result = ML_SUCCESS; - - geomagnetic_api_suspend(); - - return result; -} - - -static int -yas530_resume -( - void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata -) -{ - geomagnetic_api_resume(); - return ML_SUCCESS; -} - - -static int -yas530_read -( - void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - unsigned char *data -) -{ - int xyz[3]; - int raw[3]; - short rawfixed[3]; - int xy1y2[3]; - int accuracy; - - geomagnetic_api_read(xyz, raw, xy1y2, &accuracy); - - rawfixed[0] = (short) (xyz[0]/100); - rawfixed[1] = (short) (xyz[1]/100); - rawfixed[2] = (short) (xyz[2]/100); - - data[0] = rawfixed[0] >> 8; - data[1] = rawfixed[0] & 0xFF; - data[2] = rawfixed[1] >> 8; - data[3] = rawfixed[1] & 0xFF; - data[4] = rawfixed[2] >> 8; - data[5] = rawfixed[2] & 0xFF; - - return ML_SUCCESS; -} - - - -struct ext_slave_descr yas530_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ yas530_suspend, - /*.resume = */ yas530_resume, - /*.read = */ yas530_read, - /*.config = */ NULL, - /*.name = */ "yas530", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_YAS530, - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {3276, 8001}, -}; - -struct ext_slave_descr *yas530_get_slave_descr(void) -{ - return &yas530_descr; -} - -#ifdef __KERNEL__ - EXPORT_SYMBOL(yas530_get_slave_descr); -#endif - - /** - * @} - **/ diff --git a/drivers/misc/mpu3050/compass/yas530.c b/drivers/misc/mpu3050/compass/yas530.c deleted file mode 100755 index 9fc9acbde65b..000000000000 --- a/drivers/misc/mpu3050/compass/yas530.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - $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 . - $ - */ -/** - * @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 yas530.c - * @brief Magnetometer setup and handling methods for Yamaha yas530 - * compass. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mlsl.h" -#include "mlos.h" - -#include -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "MPL-compass" - -/*----- YAMAHA YAS529 Registers ------*/ -#define YAS530_REGADDR_DEVICE_ID (0x80) -#define YAS530_REGADDR_ACTUATE_INIT_COIL (0x81) -#define YAS530_REGADDR_MEASURE_COMMAND (0x82) -#define YAS530_REGADDR_CONFIG (0x83) -#define YAS530_REGADDR_MEASURE_INTERVAL (0x84) -#define YAS530_REGADDR_OFFSET_X (0x85) -#define YAS530_REGADDR_OFFSET_Y1 (0x86) -#define YAS530_REGADDR_OFFSET_Y2 (0x87) -#define YAS530_REGADDR_TEST1 (0x88) -#define YAS530_REGADDR_TEST2 (0x89) -#define YAS530_REGADDR_CAL (0x90) -#define YAS530_REGADDR_MEASURE_DATA (0xb0) - - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ -static int Cx, Cy1, Cy2; -static int /*a1, */a2, a3, a4, a5, a6, a7, a8, a9; -static int k; - -static char dx, dy1, dy2; -static char d2, d3, d4, d5, d6, d7, d8, d9, d0; -static char dck; - -/***************************************** - Accelerometer Initialization Functions -*****************************************/ - -int set_hardware_offset(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - char offset_x, char offset_y1, char offset_y2) -{ - char data; - int result = ML_SUCCESS; - - data = offset_x & 0x3f; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_OFFSET_X, data); - ERROR_CHECK(result); - - data = offset_y1 & 0x3f; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_OFFSET_Y1, data); - ERROR_CHECK(result); - - data = offset_y2 & 0x3f; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_OFFSET_Y2, data); - ERROR_CHECK(result); - - return result; -} - -int set_measure_command(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - int ldtc, int fors, int dlymes) -{ - int result = ML_SUCCESS; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_MEASURE_COMMAND, 0x01); - ERROR_CHECK(result); - - return result; -} - -int measure_normal(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - int *busy, unsigned short *t, - unsigned short *x, unsigned short *y1, unsigned short *y2) -{ - unsigned char data[8]; - unsigned short b, to, xo, y1o, y2o; - int result; - - result = set_measure_command(mlsl_handle, slave, pdata, 0, 0, 0); - MLOSSleep(2); - - result = MLSLSerialRead(mlsl_handle, pdata->address, - YAS530_REGADDR_MEASURE_DATA, 8, data); - ERROR_CHECK(result); - MLOSSleep(2); - - b = (data[0]>>7) & 0x01; - to = ((data[0]<<2) & 0x1fc) | ((data[1]>>6) & 0x03); - xo = ((data[2]<<5) & 0xfe0) | ((data[3]>>3) & 0x1f); - y1o = ((data[4]<<5) & 0xfe0) | ((data[5]>>3) & 0x1f); - y2o = ((data[6]<<5) & 0xfe0) | ((data[7]>>3) & 0x1f); - - *busy = b; - *t = to; - *x = xo; - *y1 = y1o; - *y2 = y2o; - - return result; -} - -int check_offset(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - char offset_x, char offset_y1, char offset_y2, - int *flag_x, int *flag_y1, int *flag_y2) -{ - int result; - int busy; - short t, x, y1, y2; - - result = set_hardware_offset(mlsl_handle, slave, pdata, - offset_x, offset_y1, offset_y2); - ERROR_CHECK(result); - - result = measure_normal(mlsl_handle, slave, pdata, - &busy, &t, &x, &y1, &y2); - ERROR_CHECK(result); - - *flag_x = 0; - *flag_y1 = 0; - *flag_y2 = 0; - - if (x > 2048) - *flag_x = 1; - if (y1 > 2048) - *flag_y1 = 1; - if (y2 > 2048) - *flag_y2 = 1; - if (x < 2048) - *flag_x = -1; - if (y1 < 2048) - *flag_y1 = -1; - if (y2 < 2048) - *flag_y2 = -1; - - return result; -} - -int measure_and_set_offset(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - char *offset) -{ - int i; - int result = ML_SUCCESS; - char offset_x = 0, offset_y1 = 0, offset_y2 = 0; - int flag_x = 0, flag_y1 = 0, flag_y2 = 0; - static const int correct[5] = {16, 8, 4, 2, 1}; - - for (i = 0; i < 5; i++) { - result = check_offset(mlsl_handle, slave, pdata, - offset_x, offset_y1, offset_y2, - &flag_x, &flag_y1, &flag_y2); - ERROR_CHECK(result); - - if (flag_x) - offset_x += flag_x * correct[i]; - if (flag_y1) - offset_y1 += flag_y1 * correct[i]; - if (flag_y2) - offset_y2 += flag_y2 * correct[i]; - } - - result = set_hardware_offset(mlsl_handle, slave, pdata, - offset_x, offset_y1, offset_y2); - ERROR_CHECK(result); - - offset[0] = offset_x; - offset[1] = offset_y1; - offset[2] = offset_y2; - - return result; -} - -void coordinate_conversion(short x, short y1, short y2, short t, - int *xo, int *yo, int *zo) -{ - int sx, sy1, sy2, sy, sz; - int hx, hy, hz; - - sx = x - (Cx * t) / 100; - sy1 = y1 - (Cy1 * t) / 100; - sy2 = y2 - (Cy2 * t) / 100; - - sy = sy1 - sy2; - sz = -sy1 - sy2; - - hx = k * ((100 * sx + a2 * sy + a3 * sz) / 10); - hy = k * ((a4 * sx + a5 * sy + a6 * sz) / 10); - hz = k * ((a7 * sx + a8 * sy + a9 * sz) / 10); - - *xo = hx; - *yo = hy; - *zo = hz; -} - -int yas530_suspend(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - return result; -} - -int yas530_resume(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata) -{ - int result = ML_SUCCESS; - - unsigned char dummyData = 0x00; - char offset[3] = {0, 0, 0}; - unsigned char data[16]; - unsigned char read_reg[1]; - - /* =============================================== */ - - /* Step 1 - Test register initialization */ - dummyData = 0x00; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_TEST1, dummyData); - ERROR_CHECK(result); - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_TEST2, dummyData); - ERROR_CHECK(result); - - /* Device ID read */ - result = MLSLSerialRead(mlsl_handle, pdata->address, - YAS530_REGADDR_DEVICE_ID, 1, read_reg); - - /*Step 2 Read the CAL register */ - /* CAL data read */ - result = MLSLSerialRead(mlsl_handle, pdata->address, - YAS530_REGADDR_CAL, 16, data); - ERROR_CHECK(result); - /* CAL data Second Read */ - result = MLSLSerialRead(mlsl_handle, pdata->address, - YAS530_REGADDR_CAL, 16, data); - ERROR_CHECK(result); - - /*Cal data */ - dx = data[0]; - dy1 = data[1]; - dy2 = data[2]; - d2 = (data[3]>>2) & 0x03f; - d3 = ((data[3]<<2) & 0x0c) | ((data[4]>>6) & 0x03); - d4 = data[4] & 0x3f; - d5 = (data[5]>>2) & 0x3f; - d6 = ((data[5]<<4) & 0x30) | ((data[6]>>4) & 0x0f); - d7 = ((data[6]<<3) & 0x78) | ((data[7]>>5) & 0x07); - d8 = ((data[7]<<1) & 0x3e) | ((data[8]>>7) & 0x01); - d9 = ((data[8]<<1) & 0xfe) | ((data[9]>>7) & 0x01); - d0 = (data[9]>>2) & 0x1f; - dck = ((data[9]<<1) & 0x06) | ((data[10]>>7) & 0x01); - - - /*Correction Data */ - Cx = dx * 6 - 768; - Cy1 = dy1 * 6 - 768; - Cy2 = dy2 * 6 - 768; - a2 = d2 - 32; - a3 = d3 - 8; - a4 = d4 - 32; - a5 = d5 + 38; - a6 = d6 - 32; - a7 = d7 - 64; - a8 = d8 - 32; - a9 = d9; - k = d0 + 10; - - /*Obtain the [49:47] bits */ - dck &= 0x07; - - /*Step 3 : Storing the CONFIG with the CLK value */ - dummyData = 0x00 | (dck << 2); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_CONFIG, dummyData); - ERROR_CHECK(result); - - /*Step 4 : Set Acquisition Interval Register */ - dummyData = 0x00; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_MEASURE_INTERVAL, dummyData); - ERROR_CHECK(result); - - /*Step 5 : Reset Coil */ - dummyData = 0x00; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, - YAS530_REGADDR_ACTUATE_INIT_COIL, dummyData); - ERROR_CHECK(result); - - /* Offset Measurement and Set*/ - result = measure_and_set_offset(mlsl_handle, slave, pdata, offset); - ERROR_CHECK(result); - - return result; -} - -int yas530_read(void *mlsl_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, unsigned char *data) -{ - int result = ML_SUCCESS; - - int busy; - short t, x, y1, y2; - int xyz[3]; - short rawfixed[3]; - - result = measure_normal(mlsl_handle, slave, pdata, - &busy, &t, &x, &y1, &y2); - ERROR_CHECK(result); - - coordinate_conversion(x, y1, y2, t, &xyz[0], &xyz[1], &xyz[2]); - - rawfixed[0] = (short) (xyz[0]/100); - rawfixed[1] = (short) (xyz[1]/100); - rawfixed[2] = (short) (xyz[2]/100); - - data[0] = rawfixed[0]>>8; - data[1] = rawfixed[0] & 0xFF; - data[2] = rawfixed[1]>>8; - data[3] = rawfixed[1] & 0xFF; - data[4] = rawfixed[2]>>8; - data[5] = rawfixed[2] & 0xFF; - - return result; -} - -struct ext_slave_descr yas530_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, - /*.suspend = */ yas530_suspend, - /*.resume = */ yas530_resume, - /*.read = */ yas530_read, - /*.config = */ NULL, - /*.get_config = */ NULL, - /*.name = */ "yas530", - /*.type = */ EXT_SLAVE_TYPE_COMPASS, - /*.id = */ COMPASS_ID_YAS530, - /*.reg = */ 0x06, - /*.len = */ 6, - /*.endian = */ EXT_SLAVE_BIG_ENDIAN, - /*.range = */ {3276, 8001}, -}; - -struct ext_slave_descr *yas530_get_slave_descr(void) -{ - return &yas530_descr; -} -EXPORT_SYMBOL(yas530_get_slave_descr); - -/** - * @} -**/ diff --git a/drivers/misc/mpu3050/log.h b/drivers/misc/mpu3050/log.h deleted file mode 100755 index f2f9ea7ece8e..000000000000 --- a/drivers/misc/mpu3050/log.h +++ /dev/null @@ -1,306 +0,0 @@ -/* - * 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 - -#ifdef ANDROID -#include /* For the LOG macro */ -#endif - -#ifdef __KERNEL__ -#include -#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. - */ -#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. - */ -#ifndef MPL_LOGV -#if MPL_LOG_NDEBUG -#define MPL_LOGV(fmt, ...) \ - do { \ - if (0) \ - MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__);\ - } while (0) -#else -#define MPL_LOGV(fmt, ...) MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__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, fmt, ...) \ - do { if (0) MPL_LOG(fmt, ##__VA_ARGS__); } while (0) -#else -#define MPL_LOGV_IF(cond, fmt, ...) \ - ((CONDITION(cond)) \ - ? MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__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(fmt, ...) MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) -#endif - -#ifndef MPL_LOGD_IF -#define MPL_LOGD_IF(cond, fmt, ...) \ - ((CONDITION(cond)) \ - ? MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__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(fmt, ...) MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__) -#endif - -#ifndef MPL_LOGI_IF -#define MPL_LOGI_IF(cond, fmt, ...) \ - ((CONDITION(cond)) \ - ? MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ - : (void)0) -#endif - -/* - * Simplified macro to send a warning log message using the current MPL_LOG_TAG. - */ -#ifndef MPL_LOGW -#ifdef __KERNEL__ -#define MPL_LOGW(fmt, ...) printk(KERN_WARNING MPL_LOG_TAG fmt, ##__VA_ARGS__) -#else -#define MPL_LOGW(fmt, ...) MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__) -#endif -#endif - -#ifndef MPL_LOGW_IF -#define MPL_LOGW_IF(cond, fmt, ...) \ - ((CONDITION(cond)) \ - ? MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \ - : (void)0) -#endif - -/* - * Simplified macro to send an error log message using the current MPL_LOG_TAG. - */ -#ifndef MPL_LOGE -#ifdef __KERNEL__ -#define MPL_LOGE(fmt, ...) printk(KERN_ERR MPL_LOG_TAG fmt, ##__VA_ARGS__) -#else -#define MPL_LOGE(fmt, ...) MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__VA_ARGS__) -#endif -#endif - -#ifndef MPL_LOGE_IF -#define MPL_LOGE_IF(cond, fmt, ...) \ - ((CONDITION(cond)) \ - ? MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__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, fmt, ...) \ - ((CONDITION(cond)) \ - ? ((void)android_printAssert(#cond, MPL_LOG_TAG, \ - fmt, ##__VA_ARGS__)) \ - : (void)0) - -#define MPL_LOG_ALWAYS_FATAL(fmt, ...) \ - (((void)android_printAssert(NULL, MPL_LOG_TAG, fmt, ##__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, fmt, ...) \ - do { \ - if (0) \ - MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__); \ - } while (0) -#define MPL_LOG_FATAL(fmt, ...) \ - do { \ - if (0) \ - MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) \ - } while (0) -#else -#define MPL_LOG_FATAL_IF(cond, fmt, ...) \ - MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__) -#define MPL_LOG_FATAL(fmt, ...) \ - MPL_LOG_ALWAYS_FATAL(fmt, ##__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, fmt, ...) \ - MPL_LOG_FATAL_IF(!(cond), fmt, ##__VA_ARGS__) - -/* --------------------------------------------------------------------- */ - -/* - * 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, fmt, ...) \ - MPL_LOG_PRI(priority, tag, fmt, ##__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, fmt, ...) \ - LOG(priority, tag, fmt, ##__VA_ARGS__) -#elif defined __KERNEL__ -#define MPL_LOG_PRI(priority, tag, fmt, ...) \ - pr_debug(MPL_##priority tag fmt, ##__VA_ARGS__) -#else -#define MPL_LOG_PRI(priority, tag, fmt, ...) \ - _MLPrintLog(MPL_##priority, tag, fmt, ##__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__ -/* not allowed in the Kernel because there is no dev_dbg that takes a va_list */ -#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 deleted file mode 100755 index 9cc4cf690386..000000000000 --- a/drivers/misc/mpu3050/mldl_cfg.c +++ /dev/null @@ -1,1739 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @addtogroup MLDL - * - * @{ - * @file mldl_cfg.c - * @brief The Motion Library Driver Layer. - */ - -/* ------------------ */ -/* - Include Files. - */ -/* ------------------ */ - -#include - -#include "mldl_cfg.h" -#include "mpu.h" - -#include "mlsl.h" -#include "mlos.h" - -#include "log.h" -#undef MPL_LOG_TAG -#define MPL_LOG_TAG "mldl_cfg:" - -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ -#ifdef M_HW -#define SLEEP 0 -#define WAKE_UP 7 -#define RESET 1 -#define STANDBY 1 -#else -/* licteral significance of all parameters used in MLDLPowerMgmtMPU */ -#define SLEEP 1 -#define WAKE_UP 0 -#define RESET 1 -#define STANDBY 1 -#endif - -/*---------------------*/ -/*- Prototypes. -*/ -/*---------------------*/ - -/*----------------------*/ -/*- Static Functions. -*/ -/*----------------------*/ - -static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle) -{ - unsigned char userCtrlReg; - int result; - - if (!mldl_cfg->dmp_is_running) - return ML_SUCCESS; - - result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, 1, &userCtrlReg); - ERROR_CHECK(result); - userCtrlReg = (userCtrlReg & (~BIT_FIFO_EN)) | BIT_FIFO_RST; - userCtrlReg = (userCtrlReg & (~BIT_DMP_EN)) | BIT_DMP_RST; - - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, userCtrlReg); - ERROR_CHECK(result); - mldl_cfg->dmp_is_running = 0; - - return result; - -} -/** - * @brief Starts the DMP running - * - * @return ML_SUCCESS or non-zero error code - */ -static int dmp_start(struct mldl_cfg *pdata, void *mlsl_handle) -{ - unsigned char userCtrlReg; - int result; - - if (pdata->dmp_is_running == pdata->dmp_enable) - return ML_SUCCESS; - - result = MLSLSerialRead(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, 1, &userCtrlReg); - ERROR_CHECK(result); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, - ((userCtrlReg & (~BIT_FIFO_EN)) - | BIT_FIFO_RST)); - ERROR_CHECK(result); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, userCtrlReg); - ERROR_CHECK(result); - - result = MLSLSerialRead(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, 1, &userCtrlReg); - ERROR_CHECK(result); - - if (pdata->dmp_enable) - userCtrlReg |= BIT_DMP_EN; - else - userCtrlReg &= ~BIT_DMP_EN; - - if (pdata->fifo_enable) - userCtrlReg |= BIT_FIFO_EN; - else - userCtrlReg &= ~BIT_FIFO_EN; - - userCtrlReg |= BIT_DMP_RST; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, userCtrlReg); - ERROR_CHECK(result); - pdata->dmp_is_running = pdata->dmp_enable; - - return result; -} - -/** - * @brief enables/disables the I2C bypass to an external device - * connected to MPU's secondary I2C bus. - * @param enable - * Non-zero to enable pass through. - * @return ML_SUCCESS if successful, a non-zero error code otherwise. - */ -static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, - unsigned char enable) -{ - unsigned char b; - int result; - - if ((mldl_cfg->gyro_is_bypassed && enable) || - (!mldl_cfg->gyro_is_bypassed && !enable)) - return ML_SUCCESS; - - /*---- get current 'USER_CTRL' into b ----*/ - result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, 1, &b); - ERROR_CHECK(result); - - 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 several erratta. Do not - * modify this algorithm - */ - /* - * 1) wait for the right time and send the command to change - * the aux i2c slave address to an invalid address that will - * get nack'ed - * - * 0x00 is broadcast. 0x7F is unlikely to be used by any aux. - */ - 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(SAMPLING_PERIOD_US(mldl_cfg) / 1000); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_AUX_SLV_ADDR, - mldl_cfg->pdata-> - accel.address); - ERROR_CHECK(result); - - /* - * 4) reset the ime interface - */ -#ifdef M_HW - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, - (b | BIT_I2C_MST_RST)); - -#else - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, - (b | BIT_AUX_IF_RST)); -#endif - ERROR_CHECK(result); - MLOSSleep(2); - } - mldl_cfg->gyro_is_bypassed = enable; - - return result; -} - -struct tsProdRevMap { - unsigned char siliconRev; - unsigned short sensTrim; -}; - -#define NUM_OF_PROD_REVS (DIM(prodRevsMap)) - -/* NOTE : 'npp' is a non production part */ -#ifdef M_HW -#define OLDEST_PROD_REV_SUPPORTED 1 -static struct tsProdRevMap prodRevsMap[] = { - {0, 0}, - {MPU_SILICON_REV_A1, 131}, /* 1 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 2 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 3 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 4 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 5 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 6 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 7 A1 (npp) */ - {MPU_SILICON_REV_A1, 131}, /* 8 A1 (npp) */ -}; - -#else /* !M_HW */ -#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 (B6/A9) */ - {MPU_SILICON_REV_B4, 115}, /* 22 B4 (B7/A10) */ - {MPU_SILICON_REV_B6, 0}, /* 23 B6 (npp) */ - {MPU_SILICON_REV_B6, 0}, /* 24 | (npp) */ - {MPU_SILICON_REV_B6, 0}, /* 25 V (npp) */ - {MPU_SILICON_REV_B6, 131}, /* 26 (B6/A11) */ -}; -#endif /* !M_HW */ - -/** - * @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, - void *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); - ERROR_CHECK(result); - if (result) - return result; - index >>= 2; - - /* clean the prefetch and cfg user bank bits */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_BANK_SEL, 0); - ERROR_CHECK(result); - if (result) - return result; - - if (index < OLDEST_PROD_REV_SUPPORTED || NUM_OF_PROD_REVS <= index) { - pdata->silicon_revision = 0; - pdata->trim = 0; - MPL_LOGE("Unsupported Product Revision Detected : %d\n", index); - return ML_ERROR_INVALID_MODULE; - } - - pdata->silicon_revision = prodRevsMap[index].siliconRev; - pdata->trim = prodRevsMap[index].sensTrim; - - if (pdata->trim == 0) { - MPL_LOGE("sensitivity trim is 0" - " - unsupported non production part.\n"); - return ML_ERROR_INVALID_MODULE; - } - - return result; -} - -/** - * @brief Enable / Disable the use MPU's secondary I2C interface level - * shifters. - * When enabled the secondary I2C interface to which the external - * device is connected runs at VDD voltage (main supply). - * When disabled the 2nd interface runs at VDDIO voltage. - * See the device specification for more details. - * - * @note using this API may produce unpredictable results, depending on how - * the MPU and slave device are setup on the target platform. - * Use of this API should entirely be restricted to system - * integrators. Once the correct value is found, there should be no - * need to change the level shifter at runtime. - * - * @pre Must be called after MLSerialOpen(). - * @note Typically called before MLDmpOpen(). - * - * @param[in] enable: - * 0 to run at VDDIO (default), - * 1 to run at VDD. - * - * @return ML_SUCCESS if successfull, a non-zero error code otherwise. - */ -static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char enable) -{ -#ifndef M_HW - int result; - unsigned char reg; - unsigned char mask; - unsigned char regval; - - if (0 == pdata->silicon_revision) - return ML_ERROR_INVALID_PARAMETER; - - /*-- on parts before B6 the VDDIO bit is bit 7 of ACCEL_BURST_ADDR -- - NOTE: this is incompatible with ST accelerometers where the VDDIO - bit MUST be set to enable ST's internal logic to autoincrement - the register address on burst reads --*/ - if ((pdata->silicon_revision & 0xf) < MPU_SILICON_REV_B6) { - reg = MPUREG_ACCEL_BURST_ADDR; - mask = 0x80; - } else { - /*-- on B6 parts the VDDIO bit was moved to FIFO_EN2 => - the mask is always 0x04 --*/ - reg = MPUREG_FIFO_EN2; - mask = 0x04; - } - - result = MLSLSerialRead(mlsl_handle, pdata->addr, reg, 1, ®val); - if (result) - return result; - - if (enable) - regval |= mask; - else - regval &= ~mask; - - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->addr, reg, regval); - - return result; -#else - return ML_SUCCESS; -#endif -} - - -#ifdef M_HW -/** - * @internal - * @param reset 1 to reset hardware - */ -static tMLError mpu60xx_pwr_mgmt(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char reset, - unsigned char powerselection) -{ - unsigned char b; - tMLError result; - - if (powerselection < 0 || powerselection > 7) - return ML_ERROR_INVALID_PARAMETER; - - result = - MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_1, 1, - &b); - ERROR_CHECK(result); - - b &= ~(BITS_PWRSEL); - - if (reset) { - /* Current sillicon has an errata where the reset will get - * nacked. Ignore the error code for now. */ - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b | BIT_H_RESET); -#define M_HW_RESET_ERRATTA -#ifndef M_HW_RESET_ERRATTA - ERROR_CHECK(result); -#else - MLOSSleep(50); -#endif - } - - b |= (powerselection << 4); - - if (b & BITS_PWRSEL) - pdata->gyro_is_suspended = FALSE; - else - pdata->gyro_is_suspended = TRUE; - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b); - ERROR_CHECK(result); - - return ML_SUCCESS; -} - -/** - * @internal - */ -static tMLError MLDLStandByGyros(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char disable_gx, - unsigned char disable_gy, - unsigned char disable_gz) -{ - unsigned char b; - tMLError result; - - result = - MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1, - &b); - ERROR_CHECK(result); - - b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG); - b |= (disable_gx << 2 | disable_gy << 1 | disable_gz); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGMT_2, b); - ERROR_CHECK(result); - - return ML_SUCCESS; -} - -/** - * @internal - */ -static tMLError MLDLStandByAccels(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char disable_ax, - unsigned char disable_ay, - unsigned char disable_az) -{ - unsigned char b; - tMLError result; - - result = - MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1, - &b); - ERROR_CHECK(result); - - b &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA); - b |= (disable_ax << 2 | disable_ay << 1 | disable_az); - - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGMT_2, b); - ERROR_CHECK(result); - - return ML_SUCCESS; -} - -#else /* ! M_HW */ - -/** - * @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 being applied. - * @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, - void *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); - - /* If we are awake, we need stop the dmp sleeping */ - if ((!(b & BIT_SLEEP)) && sleep) - dmp_stop(pdata, mlsl_handle); - - /* Reset if requested */ - if (reset) { - MPL_LOGV("Reset MPU3050\n"); - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b | BIT_H_RESET); - ERROR_CHECK(result); - MLOSSleep(5); - pdata->gyro_needs_reset = FALSE; - /* 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->gyro_is_suspended = TRUE; - else - pdata->gyro_is_suspended = FALSE; - - /* if power status match requested, nothing else's left to do */ - if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == - (((sleep != 0) * BIT_SLEEP) | - ((disable_gx != 0) * BIT_STBY_XG) | - ((disable_gy != 0) * BIT_STBY_YG) | - ((disable_gz != 0) * 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) is (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) - && ((!sleep) && disable_gx && disable_gy && disable_gz)) { - 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 != 0) * 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->gyro_is_suspended = TRUE; - } else { - b &= ~BIT_SLEEP; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b); - ERROR_CHECK(result); - pdata->gyro_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 != 0) * 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 != 0) * 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 != 0) * BIT_STBY_ZG)) { - b ^= BIT_STBY_ZG; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b); - ERROR_CHECK(result); - } - - return ML_SUCCESS; -} -#endif /* M_HW */ - - -void mpu_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; - struct ext_slave_platform_data *pressure = - &mldl_cfg->pdata->pressure; - - 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); - MPL_LOGD("mldl_cfg.requested_sensors= %04lx\n", - mldl_cfg->requested_sensors); - - 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"); - } - - if (mldl_cfg->pressure) { - MPL_LOGD("slave_pressure->suspend = %02x\n", - (int) mldl_cfg->pressure->suspend); - MPL_LOGD("slave_pressure->resume = %02x\n", - (int) mldl_cfg->pressure->resume); - MPL_LOGD("slave_pressure->read = %02x\n", - (int) mldl_cfg->pressure->read); - MPL_LOGD("slave_pressure->type = %02x\n", - mldl_cfg->pressure->type); - MPL_LOGD("slave_pressure->reg = %02x\n", - mldl_cfg->pressure->reg); - MPL_LOGD("slave_pressure->len = %02x\n", - mldl_cfg->pressure->len); - MPL_LOGD("slave_pressure->endian = %02x\n", - mldl_cfg->pressure->endian); - MPL_LOGD("slave_pressure->range.mantissa= %02lx\n", - mldl_cfg->pressure->range.mantissa); - MPL_LOGD("slave_pressure->range.fraction= %02lx\n", - mldl_cfg->pressure->range.fraction); - - } else { - MPL_LOGD("slave_pressure = NULL\n"); - } - MPL_LOGD("accel->get_slave_descr = %x\n", - (unsigned int) accel->get_slave_descr); - MPL_LOGD("accel->irq = %02x\n", accel->irq); - 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->irq = %02x\n", compass->irq); - 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("pressure->get_slave_descr = %x\n", - (unsigned int) pressure->get_slave_descr); - MPL_LOGD("pressure->irq = %02x\n", pressure->irq); - MPL_LOGD("pressure->adapt_num = %02x\n", pressure->adapt_num); - MPL_LOGD("pressure->bus = %02x\n", pressure->bus); - MPL_LOGD("pressure->address = %02x\n", pressure->address); - MPL_LOGD("pressure->orientation =\n" - " %2d %2d %2d\n" - " %2d %2d %2d\n" - " %2d %2d %2d\n", - pressure->orientation[0], pressure->orientation[1], - pressure->orientation[2], pressure->orientation[3], - pressure->orientation[4], pressure->orientation[5], - pressure->orientation[6], pressure->orientation[7], - pressure->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)); -} - -int mpu_set_slave(struct mldl_cfg *mldl_cfg, - void *gyro_handle, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *slave_pdata) -{ - int result; - unsigned char reg; - unsigned char slave_reg; - unsigned char slave_len; - unsigned char slave_endian; - unsigned char slave_address; - - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); - - if (NULL == slave || NULL == slave_pdata) { - slave_reg = 0; - slave_len = 0; - slave_endian = 0; - slave_address = 0; - } else { - slave_reg = slave->reg; - slave_len = slave->len; - slave_endian = slave->endian; - slave_address = slave_pdata->address; - } - - /* Address */ - result = MLSLSerialWriteSingle(gyro_handle, - mldl_cfg->addr, - MPUREG_AUX_SLV_ADDR, - slave_address); - ERROR_CHECK(result); - /* Register */ - result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, - MPUREG_ACCEL_BURST_ADDR, 1, - ®); - ERROR_CHECK(result); - reg = ((reg & 0x80) | slave_reg); - result = MLSLSerialWriteSingle(gyro_handle, - mldl_cfg->addr, - MPUREG_ACCEL_BURST_ADDR, - reg); - ERROR_CHECK(result); - -#ifdef M_HW - /* Length, byte swapping, grouping & enable */ - if (slave_len > BITS_SLV_LENG) { - MPL_LOGW("Limiting slave burst read length to " - "the allowed maximum (15B, req. %d)\n", - slave_len); - slave_len = BITS_SLV_LENG; - } - reg = slave_len; - if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN) - reg |= BIT_SLV_BYTE_SW; - reg |= BIT_SLV_GRP; - reg |= BIT_SLV_ENABLE; - - result = MLSLSerialWriteSingle(gyro_handle, - mldl_cfg->addr, - MPUREG_I2C_SLV0_CTRL, - reg); -#else - /* Length */ - result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, 1, ®); - ERROR_CHECK(result); - reg = (reg & ~BIT_AUX_RD_LENG); - result = MLSLSerialWriteSingle(gyro_handle, - mldl_cfg->addr, - MPUREG_USER_CTRL, reg); - ERROR_CHECK(result); -#endif - - if (slave_address) { - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, FALSE); - ERROR_CHECK(result); - } - return result; -} - -/** - * Check to see if the gyro was reset by testing a couple of registers known - * to change on reset. - * - * @param mldl_cfg mldl configuration structure - * @param gyro_handle handle used to communicate with the gyro - * - * @return ML_SUCCESS or non-zero error code - */ -static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle) -{ - int result = ML_SUCCESS; - unsigned char reg; - - result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, - MPUREG_DMP_CFG_2, 1, ®); - ERROR_CHECK(result); - - if (mldl_cfg->dmp_cfg2 != reg) - return TRUE; - - if (0 != mldl_cfg->dmp_cfg1) - return FALSE; - - result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, - MPUREG_SMPLRT_DIV, 1, ®); - ERROR_CHECK(result); - if (reg != mldl_cfg->divider) - return TRUE; - - if (0 != mldl_cfg->divider) - return FALSE; - - /* Inconclusive assume it was reset */ - return TRUE; -} - -static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle) -{ - int result; - int ii; - int jj; - unsigned char reg; - unsigned char regs[7]; - - /* Wake up the part */ -#ifdef M_HW - result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, RESET, - WAKE_UP); - ERROR_CHECK(result); - - /* Configure the MPU */ - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1); - ERROR_CHECK(result); - /* setting int_config with the propert flag BIT_BYPASS_EN - should be done by the setup functions */ - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_INT_PIN_CFG, - (mldl_cfg->pdata->int_config | - BIT_BYPASS_EN)); - ERROR_CHECK(result); - /* temporary: masking out higher bits to avoid switching - intelligence */ - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_INT_ENABLE, - (mldl_cfg->int_config)); - ERROR_CHECK(result); -#else - result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 0, 0, - mldl_cfg->gyro_power & BIT_STBY_XG, - mldl_cfg->gyro_power & BIT_STBY_YG, - mldl_cfg->gyro_power & BIT_STBY_ZG); - - if (!mldl_cfg->gyro_needs_reset && - !mpu_was_reset(mldl_cfg, gyro_handle)) { - return ML_SUCCESS; - } - - result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 1, 0, - mldl_cfg->gyro_power & BIT_STBY_XG, - mldl_cfg->gyro_power & BIT_STBY_YG, - mldl_cfg->gyro_power & BIT_STBY_ZG); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_INT_CFG, - (mldl_cfg->int_config | - mldl_cfg->pdata->int_config)); - ERROR_CHECK(result); -#endif - - result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, - MPUREG_PWR_MGM, 1, ®); - ERROR_CHECK(result); - reg &= ~BITS_CLKSEL; - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_PWR_MGM, - mldl_cfg->clk_src | reg); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_SMPLRT_DIV, - mldl_cfg->divider); - ERROR_CHECK(result); - -#ifdef M_HW - reg = DLPF_FS_SYNC_VALUE(0, mldl_cfg->full_scale, 0); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_GYRO_CONFIG, reg); - reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, 0, mldl_cfg->lpf); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_CONFIG, reg); -#else - reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, - mldl_cfg->full_scale, mldl_cfg->lpf); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_DLPF_FS_SYNC, reg); -#endif - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_DMP_CFG_1, - mldl_cfg->dmp_cfg1); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(gyro_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[MPU_MEM_BANK_SIZE]; - - result = MLSLSerialWriteMem(gyro_handle, - mldl_cfg->addr, - ((ii << 8) | 0x00), - MPU_MEM_BANK_SIZE, - mldl_cfg->ram[ii]); - ERROR_CHECK(result); - result = MLSLSerialReadMem(gyro_handle, mldl_cfg->addr, - ((ii << 8) | 0x00), - MPU_MEM_BANK_SIZE, read); - ERROR_CHECK(result); - -#ifdef M_HW -#define ML_SKIP_CHECK 38 -#else -#define ML_SKIP_CHECK 20 -#endif - for (jj = 0; jj < MPU_MEM_BANK_SIZE; jj++) { - /* skip the register memory locations */ - if (ii == 0 && jj < ML_SKIP_CHECK) - continue; - if (mldl_cfg->ram[ii][jj] != read[jj]) { - result = ML_ERROR_SERIAL_WRITE; - break; - } - } - ERROR_CHECK(result); - } - - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_XG_OFFS_TC, - mldl_cfg->offset_tc[0]); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_YG_OFFS_TC, - mldl_cfg->offset_tc[1]); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, - MPUREG_ZG_OFFS_TC, - mldl_cfg->offset_tc[2]); - ERROR_CHECK(result); - - regs[0] = MPUREG_X_OFFS_USRH; - for (ii = 0; ii < DIM(mldl_cfg->offset); ii++) { - regs[1 + ii * 2] = - (unsigned char)(mldl_cfg->offset[ii] >> 8) - & 0xff; - regs[1 + ii * 2 + 1] = - (unsigned char)(mldl_cfg->offset[ii] & 0xff); - } - result = MLSLSerialWrite(gyro_handle, mldl_cfg->addr, 7, regs); - ERROR_CHECK(result); - - /* Configure slaves */ - result = MLDLSetLevelShifterBit(mldl_cfg, gyro_handle, - mldl_cfg->pdata->level_shifter); - ERROR_CHECK(result); - return result; -} -/******************************************************************************* - ******************************************************************************* - * 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, - void *mlsl_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle) -{ - int result; - /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */ - mldl_cfg->ignore_system_suspend = FALSE; - 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; - mldl_cfg->gyro_power = 0; - mldl_cfg->gyro_is_bypassed = TRUE; - mldl_cfg->dmp_is_running = FALSE; - mldl_cfg->gyro_is_suspended = TRUE; - mldl_cfg->accel_is_suspended = TRUE; - mldl_cfg->compass_is_suspended = TRUE; - mldl_cfg->pressure_is_suspended = TRUE; - mldl_cfg->gyro_needs_reset = FALSE; - 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 - */ -#ifdef M_HW - result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle, - RESET, WAKE_UP); -#else - result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, RESET, 0, 0, 0, 0); -#endif - ERROR_CHECK(result); - - result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle); - ERROR_CHECK(result); -#ifndef M_HW - result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, - MPUREG_PRODUCT_ID, 1, - &mldl_cfg->product_id); - ERROR_CHECK(result); -#endif - - /* 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 */ -#ifdef M_HW - result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle, - FALSE, SLEEP); -#else - result = - MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, SLEEP, 0, 0, 0); -#endif - ERROR_CHECK(result); - - if (mldl_cfg->accel && mldl_cfg->accel->init) { - result = mldl_cfg->accel->init(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - ERROR_CHECK(result); - } - - if (mldl_cfg->compass && mldl_cfg->compass->init) { - result = mldl_cfg->compass->init(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); - if (ML_SUCCESS != result) { - MPL_LOGE("mldl_cfg->compass->init returned %d\n", - result); - goto out_accel; - } - } - if (mldl_cfg->pressure && mldl_cfg->pressure->init) { - result = mldl_cfg->pressure->init(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure); - if (ML_SUCCESS != result) { - MPL_LOGE("mldl_cfg->pressure->init returned %d\n", - result); - goto out_compass; - } - } - - mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO; - if (mldl_cfg->accel && mldl_cfg->accel->resume) - mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL; - - if (mldl_cfg->compass && mldl_cfg->compass->resume) - mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS; - - if (mldl_cfg->pressure && mldl_cfg->pressure->resume) - mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE; - - return result; - -out_compass: - if (mldl_cfg->compass->init) - mldl_cfg->compass->exit(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); -out_accel: - if (mldl_cfg->accel->init) - mldl_cfg->accel->exit(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - return result; - -} - -/** - * Close the mpu3050 interface - * - * @param mldl_cfg pointer to the configuration structure - * @param mlsl_handle pointer to the serial layer handle - * - * @return ML_SUCCESS or non-zero error code - */ -int mpu3050_close(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle) -{ - int result = ML_SUCCESS; - int ret_result = ML_SUCCESS; - - if (mldl_cfg->accel && mldl_cfg->accel->exit) { - result = mldl_cfg->accel->exit(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - if (ML_SUCCESS != result) - MPL_LOGE("Accel exit failed %d\n", result); - ret_result = result; - } - if (ML_SUCCESS == ret_result) - ret_result = result; - - if (mldl_cfg->compass && mldl_cfg->compass->exit) { - result = mldl_cfg->compass->exit(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); - if (ML_SUCCESS != result) - MPL_LOGE("Compass exit failed %d\n", result); - } - if (ML_SUCCESS == ret_result) - ret_result = result; - - if (mldl_cfg->pressure && mldl_cfg->pressure->exit) { - result = mldl_cfg->pressure->exit(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure); - if (ML_SUCCESS != result) - MPL_LOGE("Pressure exit failed %d\n", result); - } - if (ML_SUCCESS == ret_result) - ret_result = result; - - return ret_result; -} - -/** - * @brief resume the MPU3050 device and all the other sensor - * devices from their low power state. - * - * @param mldl_cfg - * pointer to the configuration structure - * @param gyro_handle - * the main file handle to the MPU3050 device. - * @param accel_handle - * an handle to the accelerometer device, if sitting - * onto a separate bus. Can match mlsl_handle if - * the accelerometer device operates on the same - * primary bus of MPU. - * @param compass_handle - * an handle to the compass device, if sitting - * onto a separate bus. Can match mlsl_handle if - * the compass device operates on the same - * primary bus of MPU. - * @param pressure_handle - * an handle to the pressure sensor device, if sitting - * onto a separate bus. Can match mlsl_handle if - * the pressure sensor device operates on the same - * primary bus of MPU. - * @param resume_gyro - * whether resuming the gyroscope device is - * actually needed (if the device supports low power - * mode of some sort). - * @param resume_accel - * whether resuming the accelerometer device is - * actually needed (if the device supports low power - * mode of some sort). - * @param resume_compass - * whether resuming the compass device is - * actually needed (if the device supports low power - * mode of some sort). - * @param resume_pressure - * whether resuming the pressure sensor device is - * actually needed (if the device supports low power - * mode of some sort). - * @return ML_SUCCESS or a non-zero error code. - */ -int mpu3050_resume(struct mldl_cfg *mldl_cfg, - void *gyro_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle, - bool resume_gyro, - bool resume_accel, - bool resume_compass, - bool resume_pressure) -{ - int result = ML_SUCCESS; - -#ifdef CONFIG_MPU_SENSORS_DEBUG - mpu_print_cfg(mldl_cfg); -#endif - - if (resume_accel && - ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume))) - return ML_ERROR_INVALID_PARAMETER; - if (resume_compass && - ((!mldl_cfg->compass) || (!mldl_cfg->compass->resume))) - return ML_ERROR_INVALID_PARAMETER; - if (resume_pressure && - ((!mldl_cfg->pressure) || (!mldl_cfg->pressure->resume))) - return ML_ERROR_INVALID_PARAMETER; - - if (resume_gyro && mldl_cfg->gyro_is_suspended) { - result = gyro_resume(mldl_cfg, gyro_handle); - ERROR_CHECK(result); - } - - if (resume_accel && mldl_cfg->accel_is_suspended) { - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); - ERROR_CHECK(result); - } - result = mldl_cfg->accel->resume(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - ERROR_CHECK(result); - mldl_cfg->accel_is_suspended = FALSE; - } - - if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->accel_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { - result = mpu_set_slave(mldl_cfg, - gyro_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - ERROR_CHECK(result); - } - - if (resume_compass && mldl_cfg->compass_is_suspended) { - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); - ERROR_CHECK(result); - } - result = mldl_cfg->compass->resume(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata-> - compass); - ERROR_CHECK(result); - mldl_cfg->compass_is_suspended = FALSE; - } - - if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->compass_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { - result = mpu_set_slave(mldl_cfg, - gyro_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); - ERROR_CHECK(result); - } - - if (resume_pressure && mldl_cfg->pressure_is_suspended) { - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); - ERROR_CHECK(result); - } - result = mldl_cfg->pressure->resume(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata-> - pressure); - ERROR_CHECK(result); - mldl_cfg->pressure_is_suspended = FALSE; - } - - if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->pressure_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { - result = mpu_set_slave(mldl_cfg, - gyro_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure); - ERROR_CHECK(result); - } - - /* Now start */ - if (resume_gyro) { - result = dmp_start(mldl_cfg, gyro_handle); - ERROR_CHECK(result); - } - - return result; -} - -/** - * @brief suspend the MPU3050 device and all the other sensor - * devices into their low power state. - * @param gyro_handle - * the main file handle to the MPU3050 device. - * @param accel_handle - * an handle to the accelerometer device, if sitting - * onto a separate bus. Can match gyro_handle if - * the accelerometer device operates on the same - * primary bus of MPU. - * @param compass_handle - * an handle to the compass device, if sitting - * onto a separate bus. Can match gyro_handle if - * the compass device operates on the same - * primary bus of MPU. - * @param pressure_handle - * an handle to the pressure sensor device, if sitting - * onto a separate bus. Can match gyro_handle if - * the pressure sensor device operates on the same - * primary bus of MPU. - * @param accel - * whether suspending the accelerometer device is - * actually needed (if the device supports low power - * mode of some sort). - * @param compass - * whether suspending the compass device is - * actually needed (if the device supports low power - * mode of some sort). - * @param pressure - * whether suspending the pressure sensor device is - * actually needed (if the device supports low power - * mode of some sort). - * @return ML_SUCCESS or a non-zero error code. - */ -int mpu3050_suspend(struct mldl_cfg *mldl_cfg, - void *gyro_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle, - bool suspend_gyro, - bool suspend_accel, - bool suspend_compass, - bool suspend_pressure) -{ - int result = ML_SUCCESS; - - if (suspend_gyro && !mldl_cfg->gyro_is_suspended) { -#ifdef M_HW - return ML_SUCCESS; - /* This puts the bus into bypass mode */ - result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1); - ERROR_CHECK(result); - result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP); -#else - result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, - 0, SLEEP, 0, 0, 0); -#endif - ERROR_CHECK(result); - } - - if (!mldl_cfg->accel_is_suspended && suspend_accel && - mldl_cfg->accel && mldl_cfg->accel->suspend) { - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { - result = mpu_set_slave(mldl_cfg, gyro_handle, - NULL, NULL); - ERROR_CHECK(result); - } - result = mldl_cfg->accel->suspend(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); - ERROR_CHECK(result); - mldl_cfg->accel_is_suspended = TRUE; - } - - if (!mldl_cfg->compass_is_suspended && suspend_compass && - mldl_cfg->compass && mldl_cfg->compass->suspend) { - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { - result = mpu_set_slave(mldl_cfg, gyro_handle, - NULL, NULL); - ERROR_CHECK(result); - } - result = mldl_cfg->compass->suspend(compass_handle, - mldl_cfg->compass, - &mldl_cfg-> - pdata->compass); - ERROR_CHECK(result); - mldl_cfg->compass_is_suspended = TRUE; - } - - if (!mldl_cfg->pressure_is_suspended && suspend_pressure && - mldl_cfg->pressure && mldl_cfg->pressure->suspend) { - if (!mldl_cfg->gyro_is_suspended && - EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { - result = mpu_set_slave(mldl_cfg, gyro_handle, - NULL, NULL); - ERROR_CHECK(result); - } - result = mldl_cfg->pressure->suspend(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg-> - pdata->pressure); - ERROR_CHECK(result); - mldl_cfg->pressure_is_suspended = TRUE; - } - return result; -} - - -/** - * @brief read raw sensor data from the accelerometer device - * in use. - * @param mldl_cfg - * A pointer to the struct mldl_cfg data structure. - * @param accel_handle - * The handle to the device the accelerometer is connected to. - * @param data - * a buffer to store the raw sensor data. - * @return ML_SUCCESS if successful, a non-zero error code otherwise. - */ -int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, - void *accel_handle, unsigned char *data) -{ - if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read) - if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) - && (!mldl_cfg->gyro_is_bypassed)) - return ML_ERROR_FEATURE_NOT_ENABLED; - else - return mldl_cfg->accel->read(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; -} - -/** - * @brief read raw sensor data from the compass device - * in use. - * @param mldl_cfg - * A pointer to the struct mldl_cfg data structure. - * @param compass_handle - * The handle to the device the compass is connected to. - * @param data - * a buffer to store the raw sensor data. - * @return ML_SUCCESS if successful, a non-zero error code otherwise. - */ -int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, - void *compass_handle, unsigned char *data) -{ - if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read) - if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) - && (!mldl_cfg->gyro_is_bypassed)) - return ML_ERROR_FEATURE_NOT_ENABLED; - else - return mldl_cfg->compass->read(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; -} - -/** - * @brief read raw sensor data from the pressure device - * in use. - * @param mldl_cfg - * A pointer to the struct mldl_cfg data structure. - * @param pressure_handle - * The handle to the device the pressure sensor is connected to. - * @param data - * a buffer to store the raw sensor data. - * @return ML_SUCCESS if successful, a non-zero error code otherwise. - */ -int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, - void *pressure_handle, unsigned char *data) -{ - if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->read) - if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) - && (!mldl_cfg->gyro_is_bypassed)) - return ML_ERROR_FEATURE_NOT_ENABLED; - else - return mldl_cfg->pressure->read( - pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; -} - -int mpu3050_config_accel(struct mldl_cfg *mldl_cfg, - void *accel_handle, - struct ext_slave_config *data) -{ - if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->config) - return mldl_cfg->accel->config(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - -} - -int mpu3050_config_compass(struct mldl_cfg *mldl_cfg, - void *compass_handle, - struct ext_slave_config *data) -{ - if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->config) - return mldl_cfg->compass->config(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - -} - -int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg, - void *pressure_handle, - struct ext_slave_config *data) -{ - if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->config) - return mldl_cfg->pressure->config(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; -} - -int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg, - void *accel_handle, - struct ext_slave_config *data) -{ - if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->get_config) - return mldl_cfg->accel->get_config(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - -} - -int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg, - void *compass_handle, - struct ext_slave_config *data) -{ - if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->get_config) - return mldl_cfg->compass->get_config(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; - -} - -int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg, - void *pressure_handle, - struct ext_slave_config *data) -{ - if (NULL != mldl_cfg->pressure && - NULL != mldl_cfg->pressure->get_config) - return mldl_cfg->pressure->get_config(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - data); - else - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; -} - - -/** - *@} - */ diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h deleted file mode 100755 index ad6a211c5d86..000000000000 --- a/drivers/misc/mpu3050/mldl_cfg.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @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 "mpu.h" - -/* --------------------- */ -/* - Defines. - */ -/* --------------------- */ - - /*************************************************************************/ - /* Sensors */ - /*************************************************************************/ - -#define ML_X_GYRO (0x0001) -#define ML_Y_GYRO (0x0002) -#define ML_Z_GYRO (0x0004) -#define ML_DMP_PROCESSOR (0x0008) - -#define ML_X_ACCEL (0x0010) -#define ML_Y_ACCEL (0x0020) -#define ML_Z_ACCEL (0x0040) - -#define ML_X_COMPASS (0x0080) -#define ML_Y_COMPASS (0x0100) -#define ML_Z_COMPASS (0x0200) - -#define ML_X_PRESSURE (0x0300) -#define ML_Y_PRESSURE (0x0800) -#define ML_Z_PRESSURE (0x1000) - -#define ML_TEMPERATURE (0x2000) -#define ML_TIME (0x4000) - -#define ML_THREE_AXIS_GYRO (0x000F) -#define ML_THREE_AXIS_ACCEL (0x0070) -#define ML_THREE_AXIS_COMPASS (0x0380) -#define ML_THREE_AXIS_PRESSURE (0x1C00) - -#define ML_FIVE_AXIS (0x007B) -#define ML_SIX_AXIS_GYRO_ACCEL (0x007F) -#define ML_SIX_AXIS_ACCEL_COMPASS (0x03F0) -#define ML_NINE_AXIS (0x03FF) -#define ML_ALL_SENSORS (0x7FFF) - -#define SAMPLING_RATE_HZ(mldl_cfg) \ - ((((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \ - ? (8000) \ - : (1000)) \ - / ((mldl_cfg)->divider + 1)) - -#define SAMPLING_PERIOD_US(mldl_cfg) \ - ((1000000L * ((mldl_cfg)->divider + 1)) / \ - (((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \ - ? (8000) \ - : (1000))) -/* --------------------- */ -/* - Variables. - */ -/* --------------------- */ - -/* Platform data for the MPU */ -struct mldl_cfg { - /* MPU related configuration */ - unsigned long requested_sensors; - unsigned char ignore_system_suspend; - 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 gyro_power; - unsigned char offset_tc[MPU_NUM_AXES]; - unsigned short offset[MPU_NUM_AXES]; - 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 gyro_is_bypassed; - int dmp_is_running; - int gyro_is_suspended; - int accel_is_suspended; - int compass_is_suspended; - int pressure_is_suspended; - int gyro_needs_reset; - - /* Slave related information */ - struct ext_slave_descr *accel; - struct ext_slave_descr *compass; - struct ext_slave_descr *pressure; - - /* Platform Data */ - struct mpu3050_platform_data *pdata; -}; - - -int mpu3050_open(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle); -int mpu3050_close(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle); -int mpu3050_resume(struct mldl_cfg *mldl_cfg, - void *gyro_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle, - bool resume_gyro, - bool resume_accel, - bool resume_compass, - bool resume_pressure); -int mpu3050_suspend(struct mldl_cfg *mldl_cfg, - void *gyro_handle, - void *accel_handle, - void *compass_handle, - void *pressure_handle, - bool suspend_gyro, - bool suspend_accel, - bool suspend_compass, - bool suspend_pressure); -int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, - void *accel_handle, - unsigned char *data); -int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, - void *compass_handle, - unsigned char *data); -int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, void *mlsl_handle, - unsigned char *data); - -int mpu3050_config_accel(struct mldl_cfg *mldl_cfg, - void *accel_handle, - struct ext_slave_config *data); -int mpu3050_config_compass(struct mldl_cfg *mldl_cfg, - void *compass_handle, - struct ext_slave_config *data); -int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg, - void *pressure_handle, - struct ext_slave_config *data); - -int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg, - void *accel_handle, - struct ext_slave_config *data); -int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg, - void *compass_handle, - struct ext_slave_config *data); -int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg, - void *pressure_handle, - struct ext_slave_config *data); - - -#endif /* __MLDL_CFG_H__ */ - -/** - *@} - */ diff --git a/drivers/misc/mpu3050/mlos-kernel.c b/drivers/misc/mpu3050/mlos-kernel.c deleted file mode 100755 index ced9ba4f6f3c..000000000000 --- a/drivers/misc/mpu3050/mlos-kernel.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - $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 . - $ - */ -/** - * @defgroup - * @brief - * - * @{ - * @file mlos-kernel.c - * @brief - * - * - */ - -#include "mlos.h" -#include -#include - -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 deleted file mode 100755 index 4ebb86c9fa5c..000000000000 --- a/drivers/misc/mpu3050/mlos.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - $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 . - $ - */ - -#ifndef _MLOS_H -#define _MLOS_H - -#ifndef __KERNEL__ -#include -#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 deleted file mode 100755 index cb1605131cbf..000000000000 --- a/drivers/misc/mpu3050/mlsl-kernel.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - $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 . - $ - */ - -#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, void **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(void *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(void *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(void *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 write multiple bytes of data from registers. - * This should be sent by I2C. - * - * @param slaveAddr I2C slave address of device. - * @param registerAddr Register address to write. - * @param length Length of burst of data. - * @param data Pointer to block of data. - * - * @return ML_SUCCESS if successful, a non-zero error code otherwise. - */ -tMLError MLSLSerialWrite(void *sl_handle, - unsigned char slaveAddr, - unsigned short length, - unsigned char const *data) -{ - tMLError result; - const unsigned short dataLength = length - 1; - const unsigned char startRegAddr = data[0]; - unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1]; - unsigned short bytesWritten = 0; - - while (bytesWritten < dataLength) { - unsigned short thisLen = min(SERIAL_MAX_TRANSFER_SIZE, - dataLength - bytesWritten); - if (bytesWritten == 0) { - result = sensor_i2c_write((struct i2c_adapter *) - sl_handle, slaveAddr, - 1 + thisLen, data); - } else { - /* manually increment register addr between chunks */ - i2cWrite[0] = startRegAddr + bytesWritten; - memcpy(&i2cWrite[1], &data[1 + bytesWritten], - thisLen); - result = sensor_i2c_write((struct i2c_adapter *) - sl_handle, slaveAddr, - 1 + thisLen, i2cWrite); - } - if (ML_SUCCESS != result) - return result; - bytesWritten += thisLen; - } - return ML_SUCCESS; -} - - -/** - * @brief used to read multiple bytes of data from registers. - * This should be sent by I2C. - * - * @param slaveAddr I2C slave address of device. - * @param registerAddr Register address to read. - * @param length Length of burst of data. - * @param data Pointer to block of data. - * - * @return Zero if successful; an error code otherwise - */ -tMLError MLSLSerialRead(void *sl_handle, - unsigned char slaveAddr, - unsigned char registerAddr, - unsigned short length, unsigned char *data) -{ - tMLError result; - unsigned short bytesRead = 0; - - if (registerAddr == MPUREG_FIFO_R_W - || registerAddr == MPUREG_MEM_R_W) { - return ML_ERROR_INVALID_PARAMETER; - } - while (bytesRead < length) { - unsigned short thisLen = - min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead); - result = - sensor_i2c_read((struct i2c_adapter *) sl_handle, - slaveAddr, registerAddr + bytesRead, - thisLen, &data[bytesRead]); - if (ML_SUCCESS != result) - return result; - bytesRead += thisLen; - } - return ML_SUCCESS; -} - - -/** - * @brief used to write multiple bytes of data to the memory. - * This should be sent by I2C. - * - * @param slaveAddr I2C slave address of device. - * @param memAddr The location in the memory to write to. - * @param length Length of burst data. - * @param data Pointer to block of data. - * - * @return Zero if successful; an error code otherwise - */ -tMLError MLSLSerialWriteMem(void *sl_handle, - unsigned char slaveAddr, - unsigned short memAddr, - unsigned short length, - unsigned char const *data) -{ - tMLError result; - unsigned short bytesWritten = 0; - - if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) { - pr_err("memory read length (%d B) extends beyond its" - " limits (%d) if started at location %d\n", length, - MPU_MEM_BANK_SIZE, memAddr & 0xFF); - return ML_ERROR_INVALID_PARAMETER; - } - while (bytesWritten < length) { - unsigned short thisLen = - min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten); - result = - mpu_memory_write((struct i2c_adapter *) sl_handle, - slaveAddr, memAddr + bytesWritten, - thisLen, &data[bytesWritten]); - if (ML_SUCCESS != result) - return result; - bytesWritten += thisLen; - } - return ML_SUCCESS; -} - - -/** - * @brief used to read multiple bytes of data from the memory. - * This should be sent by I2C. - * - * @param slaveAddr I2C slave address of device. - * @param memAddr The location in the memory to read from. - * @param length Length of burst data. - * @param data Pointer to block of data. - * - * @return Zero if successful; an error code otherwise - */ -tMLError MLSLSerialReadMem(void *sl_handle, - unsigned char slaveAddr, - unsigned short memAddr, - unsigned short length, unsigned char *data) -{ - tMLError result; - unsigned short bytesRead = 0; - - if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) { - printk - ("memory read length (%d B) extends beyond its limits (%d) " - "if started at location %d\n", length, - MPU_MEM_BANK_SIZE, memAddr & 0xFF); - return ML_ERROR_INVALID_PARAMETER; - } - while (bytesRead < length) { - unsigned short thisLen = - min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead); - result = - mpu_memory_read((struct i2c_adapter *) sl_handle, - slaveAddr, memAddr + bytesRead, - thisLen, &data[bytesRead]); - if (ML_SUCCESS != result) - return result; - bytesRead += thisLen; - } - return ML_SUCCESS; -} - - -/** - * @brief used to write multiple bytes of data to the fifo. - * This should be sent by I2C. - * - * @param slaveAddr I2C slave address of device. - * @param length Length of burst of data. - * @param data Pointer to block of data. - * - * @return Zero if successful; an error code otherwise - */ -tMLError MLSLSerialWriteFifo(void *sl_handle, - unsigned char slaveAddr, - unsigned short length, - unsigned char const *data) -{ - tMLError result; - unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1]; - unsigned short bytesWritten = 0; - - if (length > FIFO_HW_SIZE) { - printk(KERN_ERR - "maximum fifo write length is %d\n", FIFO_HW_SIZE); - return ML_ERROR_INVALID_PARAMETER; - } - while (bytesWritten < length) { - unsigned short thisLen = - min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten); - i2cWrite[0] = MPUREG_FIFO_R_W; - memcpy(&i2cWrite[1], &data[bytesWritten], thisLen); - result = sensor_i2c_write((struct i2c_adapter *) sl_handle, - slaveAddr, thisLen + 1, - i2cWrite); - if (ML_SUCCESS != result) - return result; - bytesWritten += thisLen; - } - return ML_SUCCESS; -} - - -/** - * @brief used to read multiple bytes of data from the fifo. - * This should be sent by I2C. - * - * @param slaveAddr I2C slave address of device. - * @param length Length of burst of data. - * @param data Pointer to block of data. - * - * @return Zero if successful; an error code otherwise - */ -tMLError MLSLSerialReadFifo(void *sl_handle, - unsigned char slaveAddr, - unsigned short length, unsigned char *data) -{ - tMLError result; - unsigned short bytesRead = 0; - - if (length > FIFO_HW_SIZE) { - printk(KERN_ERR - "maximum fifo read length is %d\n", FIFO_HW_SIZE); - return ML_ERROR_INVALID_PARAMETER; - } - while (bytesRead < length) { - unsigned short thisLen = - min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead); - result = - sensor_i2c_read((struct i2c_adapter *) sl_handle, - slaveAddr, MPUREG_FIFO_R_W, thisLen, - &data[bytesRead]); - if (ML_SUCCESS != result) - return result; - bytesRead += thisLen; - } - - return ML_SUCCESS; -} - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/mlsl.h b/drivers/misc/mpu3050/mlsl.h deleted file mode 100755 index 76f69c77ba98..000000000000 --- a/drivers/misc/mpu3050/mlsl.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - $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 . - $ - */ - -#ifndef __MSSL_H__ -#define __MSSL_H__ - -#include "mltypes.h" -#include "mpu.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------ */ -/* - Defines. - */ -/* ------------ */ - -/* - * NOTE : to properly support Yamaha compass reads, - * the max transfer size should be at least 9 B. - * Length in bytes, typically a power of 2 >= 2 - */ -#define SERIAL_MAX_TRANSFER_SIZE 128 - -/* ---------------------- */ -/* - Types definitions. - */ -/* ---------------------- */ - -/* --------------------- */ -/* - Function p-types. - */ -/* --------------------- */ - - tMLError MLSLSerialOpen(char const *port, - void **sl_handle); - tMLError MLSLSerialReset(void *sl_handle); - tMLError MLSLSerialClose(void *sl_handle); - - tMLError MLSLSerialWriteSingle(void *sl_handle, - unsigned char slaveAddr, - unsigned char registerAddr, - unsigned char data); - - tMLError MLSLSerialRead(void *sl_handle, - unsigned char slaveAddr, - unsigned char registerAddr, - unsigned short length, - unsigned char *data); - - tMLError MLSLSerialWrite(void *sl_handle, - unsigned char slaveAddr, - unsigned short length, - unsigned char const *data); - - tMLError MLSLSerialReadMem(void *sl_handle, - unsigned char slaveAddr, - unsigned short memAddr, - unsigned short length, - unsigned char *data); - - tMLError MLSLSerialWriteMem(void *sl_handle, - unsigned char slaveAddr, - unsigned short memAddr, - unsigned short length, - unsigned char const *data); - - tMLError MLSLSerialReadFifo(void *sl_handle, - unsigned char slaveAddr, - unsigned short length, - unsigned char *data); - - tMLError MLSLSerialWriteFifo(void *sl_handle, - unsigned char slaveAddr, - unsigned short length, - unsigned char const *data); - - tMLError MLSLWriteCal(unsigned char *cal, unsigned int len); - tMLError MLSLReadCal(unsigned char *cal, unsigned int len); - tMLError MLSLGetCalLength(unsigned int *len); - -#ifdef __cplusplus -} -#endif - -/** - * @} - */ -#endif /* MLSL_H */ diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h deleted file mode 100755 index d0b27fa89e78..000000000000 --- a/drivers/misc/mpu3050/mltypes.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @defgroup MLERROR - * @brief Motion Library - Error definitions. - * 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 - * - (73) ML_ERROR_COMPASS_DATA_ERROR - * - (75) ML_ERROR_CALIBRATION_LOAD - * - (76) ML_ERROR_CALIBRATION_STORE - * - (77) ML_ERROR_CALIBRATION_LEN - * - (78) ML_ERROR_CALIBRATION_CHECKSUM - * - * @{ - * @file mltypes.h - * @} - */ - -#ifndef MLTYPES_H -#define MLTYPES_H - -#ifdef __KERNEL__ -#include -#else -#include "stdint_invensense.h" -#endif -#include "log.h" - -/*--------------------------- - ML Types ----------------------------*/ - -/** - * @struct tMLError mltypes.h "mltypes" - * @brief 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) \ - do { \ - if (ML_SUCCESS != x) { \ - MPL_LOGE("%s|%s|%d returning %d\n", \ - __FILE__, __func__, __LINE__, x); \ - return x; \ - } \ - } while (0) - -#define ERROR_CHECK_FIRST(first, x) \ - { if (ML_SUCCESS == first) first = x; } - -#define ML_SUCCESS (0) -/* Generic Error code. Proprietary 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) -#define ML_ERROR_INVALID_CONFIGURATION (17) - -/* 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) -#define ML_ERROR_COMPASS_DATA_ERROR (73) - -/* Load/Store calibration */ -#define ML_ERROR_CALIBRATION_LOAD (75) -#define ML_ERROR_CALIBRATION_STORE (76) -#define ML_ERROR_CALIBRATION_LEN (77) -#define ML_ERROR_CALIBRATION_CHECKSUM (78) - -/* Accel errors */ -#define ML_ERROR_ACCEL_DATA_OVERFLOW (79) -#define ML_ERROR_ACCEL_DATA_UNDERFLOW (80) -#define ML_ERROR_ACCEL_DATA_NOT_READY (81) -#define ML_ERROR_ACCEL_DATA_ERROR (82) - -/* For Linux coding compliance */ -#ifndef __KERNEL__ -#define EXPORT_SYMBOL(x) -#endif - -/*--------------------------- - p-Types ----------------------------*/ - -#endif /* MLTYPES_H */ diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c deleted file mode 100755 index 34f6ba44ea31..000000000000 --- a/drivers/misc/mpu3050/mpu-dev.c +++ /dev/null @@ -1,1299 +0,0 @@ -/* - $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 . - $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HAS_EARLYSUSPEND -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "mpuirq.h" -#include "slaveirq.h" -#include "mlsl.h" -#include "mpu-i2c.h" -#include "mldl_cfg.h" -#include "mpu.h" - -#define MPU3050_EARLY_SUSPEND_IN_DRIVER 0 - -/* Platform data for the MPU */ -struct mpu_private_data { - struct mldl_cfg mldl_cfg; - -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif - struct mutex mutex; - wait_queue_head_t mpu_event_wait; - struct completion completion; - struct timer_list timeout; - struct notifier_block nb; - struct mpuirq_data mpu_pm_event; - int response_timeout; /* In seconds */ - unsigned long event; - int pid; -}; - -static struct i2c_client *this_client; - - -static void -mpu_pm_timeout(u_long data) -{ - struct mpu_private_data *mpu = (struct mpu_private_data *) data; - dev_dbg(&this_client->adapter->dev, "%s\n", __func__); - complete(&mpu->completion); -} - -static int mpu_pm_notifier_callback(struct notifier_block *nb, - unsigned long event, - void *unused) -{ - struct mpu_private_data *mpu = - container_of(nb, struct mpu_private_data, nb); - struct timeval event_time; - dev_dbg(&this_client->adapter->dev, "%s: %ld\n", __func__, event); - - /* Prevent the file handle from being closed before we initialize - the completion event */ - mutex_lock(&mpu->mutex); - if (!(mpu->pid) || - (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) { - mutex_unlock(&mpu->mutex); - return NOTIFY_OK; - } - - do_gettimeofday(&event_time); - mpu->mpu_pm_event.interruptcount++; - mpu->mpu_pm_event.irqtime = - (((long long) event_time.tv_sec) << 32) + - event_time.tv_usec; - mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT; - mpu->mpu_pm_event.data_size = sizeof(unsigned long); - mpu->mpu_pm_event.data = &mpu->event; - - if (event == PM_SUSPEND_PREPARE) - mpu->event = MPU_PM_EVENT_SUSPEND_PREPARE; - if (event == PM_POST_SUSPEND) - mpu->event = MPU_PM_EVENT_POST_SUSPEND; - - if (mpu->response_timeout > 0) { - mpu->timeout.expires = jiffies + mpu->response_timeout * HZ; - add_timer(&mpu->timeout); - } - INIT_COMPLETION(mpu->completion); - mutex_unlock(&mpu->mutex); - - wake_up_interruptible(&mpu->mpu_event_wait); - wait_for_completion(&mpu->completion); - del_timer_sync(&mpu->timeout); - dev_dbg(&this_client->adapter->dev, "%s: %ld DONE\n", __func__, event); - return NOTIFY_OK; -} - -static int mpu_open(struct inode *inode, struct file *file) -{ - struct mpu_private_data *mpu = - (struct mpu_private_data *) i2c_get_clientdata(this_client); - struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; - int result; - dev_dbg(&this_client->adapter->dev, "mpu_open\n"); - dev_dbg(&this_client->adapter->dev, "current->pid %d\n", - current->pid); - mpu->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 */ - - /* Reset the sensors to the default */ - result = mutex_lock_interruptible(&mpu->mutex); - if (result) { - dev_err(&this_client->adapter->dev, - "%s: mutex_lock_interruptible returned %d\n", - __func__, result); - return result; - } - mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO; - if (mldl_cfg->accel && mldl_cfg->accel->resume) - mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL; - - if (mldl_cfg->compass && mldl_cfg->compass->resume) - mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS; - - if (mldl_cfg->pressure && mldl_cfg->pressure->resume) - mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE; - mutex_unlock(&mpu->mutex); - 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; - struct i2c_adapter *accel_adapter; - struct i2c_adapter *compass_adapter; - struct i2c_adapter *pressure_adapter; - int result = 0; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - mutex_lock(&mpu->mutex); - result = mpu3050_suspend(mldl_cfg, client->adapter, - accel_adapter, compass_adapter, - pressure_adapter, - TRUE, TRUE, TRUE, TRUE); - mpu->pid = 0; - mutex_unlock(&mpu->mutex); - complete(&mpu->completion); - dev_dbg(&this_client->adapter->dev, "mpu_release\n"); - return result; -} - -/* 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) -{ - struct mpuirq_data local_mpu_pm_event; - struct i2c_client *client = - (struct i2c_client *) file->private_data; - struct mpu_private_data *mpu = - (struct mpu_private_data *) i2c_get_clientdata(client); - size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long); - int err; - - if (!mpu->event && (!(file->f_flags & O_NONBLOCK))) - wait_event_interruptible(mpu->mpu_event_wait, mpu->event); - - if (!mpu->event || NULL == buf - || count < sizeof(mpu->mpu_pm_event) + sizeof(unsigned long)) - return 0; - - err = copy_from_user(&local_mpu_pm_event, buf, - sizeof(mpu->mpu_pm_event)); - if (err != 0) { - dev_err(&this_client->adapter->dev, - "Copy from user returned %d\n", err); - return -EFAULT; - } - - mpu->mpu_pm_event.data = local_mpu_pm_event.data; - err = copy_to_user((unsigned long __user *)local_mpu_pm_event.data, - &mpu->event, - sizeof(mpu->event)); - if (err != 0) { - dev_err(&this_client->adapter->dev, - "Copy to user returned %d\n", err); - return -EFAULT; - } - err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event)); - if (err != 0) { - dev_err(&this_client->adapter->dev, - "Copy to user returned %d\n", err); - return -EFAULT; - } - mpu->event = 0; - return len; -} - -static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll) -{ - struct i2c_client *client = - (struct i2c_client *) file->private_data; - struct mpu_private_data *mpu = - (struct mpu_private_data *) i2c_get_clientdata(client); - int mask = 0; - - poll_wait(file, &mpu->mpu_event_wait, poll); - if (mpu->event) - mask |= POLLIN | POLLRDNORM; - return mask; -} - -static int -mpu_ioctl_set_mpu_pdata(struct i2c_client *client, unsigned long arg) -{ - int ii; - struct mpu_private_data *mpu = - (struct mpu_private_data *) i2c_get_clientdata(client); - struct mpu3050_platform_data *pdata = mpu->mldl_cfg.pdata; - struct mpu3050_platform_data local_pdata; - - if (copy_from_user(&local_pdata, (unsigned char __user *) arg, - sizeof(local_pdata))) - return -EFAULT; - - pdata->int_config = local_pdata.int_config; - for (ii = 0; ii < DIM(pdata->orientation); ii++) - pdata->orientation[ii] = local_pdata.orientation[ii]; - pdata->level_shifter = local_pdata.level_shifter; - - pdata->accel.address = local_pdata.accel.address; - for (ii = 0; ii < DIM(pdata->accel.orientation); ii++) - pdata->accel.orientation[ii] = - local_pdata.accel.orientation[ii]; - - pdata->compass.address = local_pdata.compass.address; - for (ii = 0; ii < DIM(pdata->compass.orientation); ii++) - pdata->compass.orientation[ii] = - local_pdata.compass.orientation[ii]; - - pdata->pressure.address = local_pdata.pressure.address; - for (ii = 0; ii < DIM(pdata->pressure.orientation); ii++) - pdata->pressure.orientation[ii] = - local_pdata.pressure.orientation[ii]; - - dev_dbg(&client->adapter->dev, "%s\n", __func__); - - return ML_SUCCESS; -} - -static int -mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg) -{ - int ii; - int result = ML_SUCCESS; - struct mpu_private_data *mpu = - (struct mpu_private_data *) i2c_get_clientdata(client); - struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; - struct mldl_cfg *temp_mldl_cfg; - - dev_dbg(&this_client->adapter->dev, "%s\n", __func__); - - temp_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL); - if (NULL == temp_mldl_cfg) - return -ENOMEM; - - /* - * User space is not allowed to modify accel compass pressure or - * pdata structs, as well as silicon_revision product_id or trim - */ - if (copy_from_user(temp_mldl_cfg, (struct mldl_cfg __user *) arg, - offsetof(struct mldl_cfg, silicon_revision))) { - result = -EFAULT; - goto out; - } - - if (mldl_cfg->gyro_is_suspended) { - if (mldl_cfg->addr != temp_mldl_cfg->addr) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->int_config != temp_mldl_cfg->int_config) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->ext_sync != temp_mldl_cfg->ext_sync) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->full_scale != temp_mldl_cfg->full_scale) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->lpf != temp_mldl_cfg->lpf) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->clk_src != temp_mldl_cfg->clk_src) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->divider != temp_mldl_cfg->divider) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->dmp_enable != temp_mldl_cfg->dmp_enable) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->fifo_enable != temp_mldl_cfg->fifo_enable) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->dmp_cfg1 != temp_mldl_cfg->dmp_cfg1) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->dmp_cfg2 != temp_mldl_cfg->dmp_cfg2) - mldl_cfg->gyro_needs_reset = TRUE; - - if (mldl_cfg->gyro_power != temp_mldl_cfg->gyro_power) - mldl_cfg->gyro_needs_reset = TRUE; - - for (ii = 0; ii < MPU_NUM_AXES; ii++) - if (mldl_cfg->offset_tc[ii] != - temp_mldl_cfg->offset_tc[ii]) - mldl_cfg->gyro_needs_reset = TRUE; - - for (ii = 0; ii < MPU_NUM_AXES; ii++) - if (mldl_cfg->offset[ii] != temp_mldl_cfg->offset[ii]) - mldl_cfg->gyro_needs_reset = TRUE; - - if (memcmp(mldl_cfg->ram, temp_mldl_cfg->ram, - MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE * - sizeof(unsigned char))) - mldl_cfg->gyro_needs_reset = TRUE; - } - - memcpy(mldl_cfg, temp_mldl_cfg, - offsetof(struct mldl_cfg, silicon_revision)); - -out: - kfree(temp_mldl_cfg); - return result; -} - -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 = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL); - if (NULL == local_mldl_cfg) - return -ENOMEM; - - retval = - copy_from_user(local_mldl_cfg, (struct mldl_cfg __user *) arg, - sizeof(struct mldl_cfg)); - if (retval) { - dev_err(&this_client->adapter->dev, - "%s|%s:%d: EFAULT on arg\n", - __FILE__, __func__, __LINE__); - retval = -EFAULT; - goto out; - } - - /* Fill in the accel, compass, pressure and pdata pointers */ - if (mldl_cfg->accel) { - retval = copy_to_user((void __user *)local_mldl_cfg->accel, - mldl_cfg->accel, - sizeof(*mldl_cfg->accel)); - if (retval) { - dev_err(&this_client->adapter->dev, - "%s|%s:%d: EFAULT on accel\n", - __FILE__, __func__, __LINE__); - retval = -EFAULT; - goto out; - } - } - - if (mldl_cfg->compass) { - retval = copy_to_user((void __user *)local_mldl_cfg->compass, - mldl_cfg->compass, - sizeof(*mldl_cfg->compass)); - if (retval) { - dev_err(&this_client->adapter->dev, - "%s|%s:%d: EFAULT on compass\n", - __FILE__, __func__, __LINE__); - retval = -EFAULT; - goto out; - } - } - - if (mldl_cfg->pressure) { - retval = copy_to_user((void __user *)local_mldl_cfg->pressure, - mldl_cfg->pressure, - sizeof(*mldl_cfg->pressure)); - if (retval) { - dev_err(&this_client->adapter->dev, - "%s|%s:%d: EFAULT on pressure\n", - __FILE__, __func__, __LINE__); - retval = -EFAULT; - goto out; - } - } - - if (mldl_cfg->pdata) { - retval = copy_to_user((void __user *)local_mldl_cfg->pdata, - mldl_cfg->pdata, - sizeof(*mldl_cfg->pdata)); - if (retval) { - dev_err(&this_client->adapter->dev, - "%s|%s:%d: EFAULT on pdata\n", - __FILE__, __func__, __LINE__); - retval = -EFAULT; - goto out; - } - } - - /* Do not modify the accel, compass, pressure and pdata pointers */ - retval = copy_to_user((struct mldl_cfg __user *) arg, - mldl_cfg, offsetof(struct mldl_cfg, accel)); - - if (retval) - retval = -EFAULT; -out: - kfree(local_mldl_cfg); - return retval; -} - -/** - * Pass a requested slave configuration to the slave sensor - * - * @param adapter the adaptor to use to communicate with the slave - * @param mldl_cfg the mldl configuration structuer - * @param slave pointer to the slave descriptor - * @param usr_config The configuration to pass to the slave sensor - * - * @return 0 or non-zero error code - */ -static int slave_config(void *adapter, - struct mldl_cfg *mldl_cfg, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config __user *usr_config) -{ - int retval = ML_SUCCESS; - struct ext_slave_config config; - if ((!slave) || (!slave->config)) - return retval; - - retval = copy_from_user(&config, usr_config, sizeof(config)); - if (retval) - return -EFAULT; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) - return ML_ERROR_MEMORY_EXAUSTED; - - retval = copy_from_user(data, - (void __user *)config.data, - config.len); - if (retval) { - retval = -EFAULT; - kfree(data); - return retval; - } - config.data = data; - } - retval = slave->config(adapter, slave, pdata, &config); - kfree(config.data); - return retval; -} - -/** - * Get a requested slave configuration from the slave sensor - * - * @param adapter the adaptor to use to communicate with the slave - * @param mldl_cfg the mldl configuration structuer - * @param slave pointer to the slave descriptor - * @param usr_config The configuration for the slave to fill out - * - * @return 0 or non-zero error code - */ -static int slave_get_config(void *adapter, - struct mldl_cfg *mldl_cfg, - struct ext_slave_descr *slave, - struct ext_slave_platform_data *pdata, - struct ext_slave_config __user *usr_config) -{ - int retval = ML_SUCCESS; - struct ext_slave_config config; - void *user_data; - if (!(slave) || !(slave->get_config)) - return ML_SUCCESS; - - retval = copy_from_user(&config, usr_config, sizeof(config)); - if (retval) - return -EFAULT; - - user_data = config.data; - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) - return ML_ERROR_MEMORY_EXAUSTED; - - retval = copy_from_user(data, - (void __user *)config.data, - config.len); - if (retval) { - retval = -EFAULT; - kfree(data); - return retval; - } - config.data = data; - } - retval = slave->get_config(adapter, slave, pdata, &config); - if (retval) { - kfree(config.data); - return retval; - } - retval = copy_to_user((unsigned char __user *) user_data, - config.data, - config.len); - kfree(config.data); - return retval; -} - -static int mpu_handle_mlsl(void *sl_handle, - unsigned char addr, - unsigned int cmd, - struct mpu_read_write __user *usr_msg) -{ - int retval = ML_SUCCESS; - struct mpu_read_write msg; - unsigned char *user_data; - retval = copy_from_user(&msg, usr_msg, sizeof(msg)); - if (retval) - return -EFAULT; - - user_data = msg.data; - if (msg.length && msg.data) { - unsigned char *data; - data = kzalloc(msg.length, GFP_KERNEL); - if (!data) - return ML_ERROR_MEMORY_EXAUSTED; - - retval = copy_from_user(data, - (void __user *)msg.data, - msg.length); - if (retval) { - retval = -EFAULT; - kfree(data); - return retval; - } - msg.data = data; - } else { - return ML_ERROR_INVALID_PARAMETER; - } - - switch (cmd) { - case MPU_READ: - retval = MLSLSerialRead(sl_handle, addr, - msg.address, msg.length, msg.data); - break; - case MPU_WRITE: - retval = MLSLSerialWrite(sl_handle, addr, - msg.length, msg.data); - break; - case MPU_READ_MEM: - retval = MLSLSerialReadMem(sl_handle, addr, - msg.address, msg.length, msg.data); - break; - case MPU_WRITE_MEM: - retval = MLSLSerialWriteMem(sl_handle, addr, - msg.address, msg.length, msg.data); - break; - case MPU_READ_FIFO: - retval = MLSLSerialReadFifo(sl_handle, addr, - msg.length, msg.data); - break; - case MPU_WRITE_FIFO: - retval = MLSLSerialWriteFifo(sl_handle, addr, - msg.length, msg.data); - break; - - }; - retval = copy_to_user((unsigned char __user *) user_data, - msg.data, - msg.length); - kfree(msg.data); - 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; - struct i2c_adapter *pressure_adapter; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - retval = mutex_lock_interruptible(&mpu->mutex); - if (retval) { - dev_err(&this_client->adapter->dev, - "%s: mutex_lock_interruptible returned %d\n", - __func__, retval); - return retval; - } - - switch (cmd) { - case MPU_SET_MPU_CONFIG: - retval = mpu_ioctl_set_mpu_config(client, arg); - break; - case MPU_SET_PLATFORM_DATA: - retval = mpu_ioctl_set_mpu_pdata(client, arg); - break; - case MPU_GET_MPU_CONFIG: - retval = mpu_ioctl_get_mpu_config(client, arg); - break; - case MPU_READ: - case MPU_WRITE: - case MPU_READ_MEM: - case MPU_WRITE_MEM: - case MPU_READ_FIFO: - case MPU_WRITE_FIFO: - retval = mpu_handle_mlsl(client->adapter, mldl_cfg->addr, cmd, - (struct mpu_read_write __user *) arg); - break; - case MPU_CONFIG_ACCEL: - retval = slave_config(accel_adapter, mldl_cfg, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - (struct ext_slave_config __user *) arg); - break; - case MPU_CONFIG_COMPASS: - retval = slave_config(compass_adapter, mldl_cfg, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - (struct ext_slave_config __user *) arg); - break; - case MPU_CONFIG_PRESSURE: - retval = slave_config(pressure_adapter, mldl_cfg, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - (struct ext_slave_config __user *) arg); - break; - case MPU_GET_CONFIG_ACCEL: - retval = slave_get_config(accel_adapter, mldl_cfg, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - (struct ext_slave_config __user *) arg); - break; - case MPU_GET_CONFIG_COMPASS: - retval = slave_get_config(compass_adapter, mldl_cfg, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - (struct ext_slave_config __user *) arg); - break; - case MPU_GET_CONFIG_PRESSURE: - retval = slave_get_config(pressure_adapter, mldl_cfg, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - (struct ext_slave_config __user *) arg); - break; - case MPU_SUSPEND: - { - unsigned long sensors; - sensors = ~(mldl_cfg->requested_sensors); - retval = mpu3050_suspend(mldl_cfg, - client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - ((sensors & ML_THREE_AXIS_GYRO) - == ML_THREE_AXIS_GYRO), - ((sensors & ML_THREE_AXIS_ACCEL) - == ML_THREE_AXIS_ACCEL), - ((sensors & ML_THREE_AXIS_COMPASS) - == ML_THREE_AXIS_COMPASS), - ((sensors & ML_THREE_AXIS_PRESSURE) - == ML_THREE_AXIS_PRESSURE)); - } - break; - case MPU_RESUME: - { - unsigned long sensors; - sensors = mldl_cfg->requested_sensors; - retval = mpu3050_resume(mldl_cfg, - client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - sensors & ML_THREE_AXIS_GYRO, - sensors & ML_THREE_AXIS_ACCEL, - sensors & ML_THREE_AXIS_COMPASS, - sensors & ML_THREE_AXIS_PRESSURE); - } - break; - case MPU_PM_EVENT_HANDLED: - dev_dbg(&this_client->adapter->dev, - "%s: %d\n", __func__, cmd); - complete(&mpu->completion); - break; - case MPU_READ_ACCEL: - { - unsigned char data[6]; - retval = mpu3050_read_accel(mldl_cfg, client->adapter, - data); - if ((ML_SUCCESS == retval) && - (copy_to_user((unsigned char __user *) arg, - data, sizeof(data)))) - retval = -EFAULT; - } - 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) && - (copy_to_user((unsigned char *) arg, - data, sizeof(data)))) - retval = -EFAULT; - } - break; - case MPU_READ_PRESSURE: - { - unsigned char data[3]; - struct i2c_adapter *pressure_adapt = - i2c_get_adapter(mldl_cfg->pdata->pressure. - adapt_num); - retval = - mpu3050_read_pressure(mldl_cfg, pressure_adapt, - data); - if ((ML_SUCCESS == retval) && - (copy_to_user((unsigned char __user *) arg, - data, sizeof(data)))) - retval = -EFAULT; - } - break; - default: - dev_err(&this_client->adapter->dev, - "%s: Unknown cmd %x, arg %lu\n", __func__, cmd, - arg); - retval = -EINVAL; - } - - mutex_unlock(&mpu->mutex); - 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; - struct i2c_adapter *pressure_adapter; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - dev_dbg(&this_client->adapter->dev, "%s: %d, %d\n", __func__, - h->level, mpu->mldl_cfg.gyro_is_suspended); - if (MPU3050_EARLY_SUSPEND_IN_DRIVER) { - mutex_lock(&mpu->mutex); - (void) mpu3050_suspend(mldl_cfg, this_client->adapter, - accel_adapter, compass_adapter, - pressure_adapter, TRUE, TRUE, TRUE, TRUE); - mutex_unlock(&mpu->mutex); - } -} - -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; - struct i2c_adapter *pressure_adapter; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - if (MPU3050_EARLY_SUSPEND_IN_DRIVER) { - if (mpu->pid) { - unsigned long sensors = mldl_cfg->requested_sensors; - mutex_lock(&mpu->mutex); - (void) mpu3050_resume(mldl_cfg, - this_client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - sensors & ML_THREE_AXIS_GYRO, - sensors & ML_THREE_AXIS_ACCEL, - sensors & ML_THREE_AXIS_COMPASS, - sensors & ML_THREE_AXIS_PRESSURE); - mutex_unlock(&mpu->mutex); - dev_dbg(&this_client->adapter->dev, - "%s for pid %d\n", __func__, mpu->pid); - } - } - dev_dbg(&this_client->adapter->dev, "%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; - struct i2c_adapter *pressure_adapter; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - mutex_lock(&mpu->mutex); - (void) mpu3050_suspend(mldl_cfg, this_client->adapter, - accel_adapter, compass_adapter, pressure_adapter, - TRUE, TRUE, TRUE, TRUE); - mutex_unlock(&mpu->mutex); - dev_dbg(&this_client->adapter->dev, "%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; - struct i2c_adapter *pressure_adapter; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - mutex_lock(&mpu->mutex); - if (!mldl_cfg->ignore_system_suspend) { - dev_dbg(&this_client->adapter->dev, - "%s: suspending on event %d\n", __func__, - mesg.event); - (void) mpu3050_suspend(mldl_cfg, this_client->adapter, - accel_adapter, compass_adapter, - pressure_adapter, - TRUE, TRUE, TRUE, TRUE); - } else { - dev_dbg(&this_client->adapter->dev, - "%s: Already suspended %d\n", __func__, - mesg.event); - } - mutex_unlock(&mpu->mutex); - 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; - struct i2c_adapter *pressure_adapter; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - mutex_lock(&mpu->mutex); - if (mpu->pid && !mldl_cfg->ignore_system_suspend) { - unsigned long sensors = mldl_cfg->requested_sensors; - (void) mpu3050_resume(mldl_cfg, this_client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - sensors & ML_THREE_AXIS_GYRO, - sensors & ML_THREE_AXIS_ACCEL, - sensors & ML_THREE_AXIS_COMPASS, - sensors & ML_THREE_AXIS_PRESSURE); - dev_dbg(&this_client->adapter->dev, - "%s for pid %d\n", __func__, mpu->pid); - } - mutex_unlock(&mpu->mutex); - return 0; -} - -/* define which file operations are supported */ -static const struct file_operations mpu_fops = { - .owner = THIS_MODULE, - .read = mpu_read, - .poll = mpu_poll, - -#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", /* Same for both 3050 and 6000 */ - .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; - struct mldl_cfg *mldl_cfg; - int res = 0; - struct i2c_adapter *accel_adapter = NULL; - struct i2c_adapter *compass_adapter = NULL; - struct i2c_adapter *pressure_adapter = NULL; - - dev_dbg(&client->adapter->dev, "%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; - mldl_cfg = &mpu->mldl_cfg; - - init_waitqueue_head(&mpu->mpu_event_wait); - - mutex_init(&mpu->mutex); - init_completion(&mpu->completion); - - mpu->response_timeout = 60; /* Seconds */ - mpu->timeout.function = mpu_pm_timeout; - mpu->timeout.data = (u_long) mpu; - init_timer(&mpu->timeout); - - mpu->nb.notifier_call = mpu_pm_notifier_callback; - mpu->nb.priority = 0; - register_pm_notifier(&mpu->nb); - - pdata = (struct mpu3050_platform_data *) client->dev.platform_data; - if (!pdata) { - dev_WARN(&this_client->adapter->dev, - "Missing platform data for mpu3050\n"); - } else { - mldl_cfg->pdata = pdata; - -#if defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) || \ - defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) - pdata->accel.get_slave_descr = get_accel_slave_descr; - pdata->compass.get_slave_descr = get_compass_slave_descr; - pdata->pressure.get_slave_descr = get_pressure_slave_descr; -#endif - - if (pdata->accel.get_slave_descr) { - mldl_cfg->accel = - pdata->accel.get_slave_descr(); - dev_info(&this_client->adapter->dev, - "%s: +%s\n", MPU_NAME, - mldl_cfg->accel->name); - accel_adapter = - i2c_get_adapter(pdata->accel.adapt_num); - if (pdata->accel.irq > 0) { - dev_info(&this_client->adapter->dev, - "Installing Accel irq using %d\n", - pdata->accel.irq); - res = slaveirq_init(accel_adapter, - &pdata->accel, - "accelirq"); - if (res) - goto out_accelirq_failed; - } else { - dev_warn(&this_client->adapter->dev, - "WARNING: Accel irq not assigned\n"); - } - } else { - dev_warn(&this_client->adapter->dev, - "%s: No Accel Present\n", MPU_NAME); - } - - if (pdata->compass.get_slave_descr) { - mldl_cfg->compass = - pdata->compass.get_slave_descr(); - dev_info(&this_client->adapter->dev, - "%s: +%s\n", MPU_NAME, - mldl_cfg->compass->name); - compass_adapter = - i2c_get_adapter(pdata->compass.adapt_num); - if (pdata->compass.irq > 0) { - dev_info(&this_client->adapter->dev, - "Installing Compass irq using %d\n", - pdata->compass.irq); - res = slaveirq_init(compass_adapter, - &pdata->compass, - "compassirq"); - if (res) - goto out_compassirq_failed; - } else { - dev_warn(&this_client->adapter->dev, - "WARNING: Compass irq not assigned\n"); - } - } else { - dev_warn(&this_client->adapter->dev, - "%s: No Compass Present\n", MPU_NAME); - } - - if (pdata->pressure.get_slave_descr) { - mldl_cfg->pressure = - pdata->pressure.get_slave_descr(); - dev_info(&this_client->adapter->dev, - "%s: +%s\n", MPU_NAME, - mldl_cfg->pressure->name); - pressure_adapter = - i2c_get_adapter(pdata->pressure.adapt_num); - - if (pdata->pressure.irq > 0) { - dev_info(&this_client->adapter->dev, - "Installing Pressure irq using %d\n", - pdata->pressure.irq); - res = slaveirq_init(pressure_adapter, - &pdata->pressure, - "pressureirq"); - if (res) - goto out_pressureirq_failed; - } else { - dev_warn(&this_client->adapter->dev, - "WARNING: Pressure irq not assigned\n"); - } - } else { - dev_warn(&this_client->adapter->dev, - "%s: No Pressure Present\n", MPU_NAME); - } - } - - mldl_cfg->addr = client->addr; - res = mpu3050_open(&mpu->mldl_cfg, client->adapter, - accel_adapter, compass_adapter, pressure_adapter); - - if (res) { - dev_err(&this_client->adapter->dev, - "Unable to open %s %d\n", MPU_NAME, res); - res = -ENODEV; - goto out_whoami_failed; - } - - res = misc_register(&i2c_mpu_device); - if (res < 0) { - dev_err(&this_client->adapter->dev, - "ERROR: misc_register returned %d\n", res); - goto out_misc_register_failed; - } - - if (this_client->irq > 0) { - dev_info(&this_client->adapter->dev, - "Installing irq using %d\n", this_client->irq); - res = mpuirq_init(this_client); - if (res) - goto out_mpuirq_failed; - } else { - dev_WARN(&this_client->adapter->dev, - "Missing %s IRQ\n", MPU_NAME); - } - - -#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 - return res; - -out_mpuirq_failed: - misc_deregister(&i2c_mpu_device); -out_misc_register_failed: - mpu3050_close(&mpu->mldl_cfg, client->adapter, - accel_adapter, compass_adapter, pressure_adapter); -out_whoami_failed: - if (pdata && - pdata->pressure.get_slave_descr && - pdata->pressure.irq) - slaveirq_exit(&pdata->pressure); -out_pressureirq_failed: - if (pdata && - pdata->compass.get_slave_descr && - pdata->compass.irq) - slaveirq_exit(&pdata->compass); -out_compassirq_failed: - if (pdata && - pdata->accel.get_slave_descr && - pdata->accel.irq) - slaveirq_exit(&pdata->accel); -out_accelirq_failed: - kfree(mpu); -out_alloc_data_failed: -out_check_functionality_failed: - dev_err(&this_client->adapter->dev, "%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); - struct i2c_adapter *accel_adapter; - struct i2c_adapter *compass_adapter; - struct i2c_adapter *pressure_adapter; - struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; - struct mpu3050_platform_data *pdata = mldl_cfg->pdata; - - accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - - dev_dbg(&client->adapter->dev, "%s\n", __func__); - -#ifdef CONFIG_HAS_EARLYSUSPEND - unregister_early_suspend(&mpu->early_suspend); -#endif - mpu3050_close(mldl_cfg, client->adapter, - accel_adapter, compass_adapter, pressure_adapter); - - if (client->irq) - mpuirq_exit(); - - if (pdata && - pdata->pressure.get_slave_descr && - pdata->pressure.irq) - slaveirq_exit(&pdata->pressure); - - if (pdata && - pdata->compass.get_slave_descr && - pdata->compass.irq) - slaveirq_exit(&pdata->compass); - - if (pdata && - pdata->accel.get_slave_descr && - pdata->accel.irq) - slaveirq_exit(&pdata->accel); - - misc_deregister(&i2c_mpu_device); - kfree(mpu); - - return 0; -} - -static const struct i2c_device_id mpu3050_id[] = { - {MPU_NAME, 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 = MPU_NAME, - }, -#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); - pr_debug("%s\n", __func__); - if (res) - pr_err("%s failed\n", - __func__); - return res; -} - -static void __exit mpu_exit(void) -{ - pr_debug("%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(MPU_NAME); diff --git a/drivers/misc/mpu3050/mpu-i2c.c b/drivers/misc/mpu3050/mpu-i2c.c deleted file mode 100755 index f3d8188fea99..000000000000 --- a/drivers/misc/mpu3050/mpu-i2c.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - $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 . - $ - */ - -/** - * @defgroup - * @brief - * - * @{ - * @file mpu-i2c.c - * @brief - * - */ - -#include -#include "mpu.h" - -#define MPU_I2C_RATE 100*1000 - -int sensor_i2c_write(struct i2c_adapter *i2c_adap, - unsigned char address, - unsigned int len, unsigned char const *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; - msgs[0].scl_rate = MPU_I2C_RATE; - - res = i2c_transfer(i2c_adap, msgs, 1); - if (res == 1) - return 0; - else if(res == 0) - return -EBUSY; - else - return res; -} - -int sensor_i2c_write_register(struct i2c_adapter *i2c_adap, - unsigned char address, - unsigned char reg, unsigned char value) -{ - unsigned char data[2]; - - data[0] = reg; - data[1] = value; - return sensor_i2c_write(i2c_adap, address, 2, data); -} - -int sensor_i2c_read(struct i2c_adapter *i2c_adap, - unsigned char address, - unsigned char reg, - unsigned int len, unsigned char *data) -{ - struct i2c_msg msgs[2]; - int res; - - if (NULL == data || NULL == i2c_adap) - return -EINVAL; - - msgs[0].addr = address; - msgs[0].flags = 0; /* write */ - msgs[0].buf = ® - msgs[0].len = 1; - msgs[0].scl_rate = MPU_I2C_RATE; - - msgs[1].addr = address; - msgs[1].flags = I2C_M_RD; - msgs[1].buf = data; - msgs[1].len = len; - msgs[1].scl_rate = MPU_I2C_RATE; - - res = i2c_transfer(i2c_adap, msgs, 2); - if (res == 2) - return 0; - else if(res == 0) - return -EBUSY; - else - return res; -} - -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] = MPUREG_BANK_SEL; - bank[1] = mem_addr >> 8; - - addr[0] = MPUREG_MEM_START_ADDR; - addr[1] = mem_addr & 0xFF; - - buf = 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[0].scl_rate = MPU_I2C_RATE; - - msgs[1].addr = mpu_addr; - msgs[1].flags = 0; - msgs[1].buf = addr; - msgs[1].len = sizeof(addr); - msgs[1].scl_rate = MPU_I2C_RATE; - - msgs[2].addr = mpu_addr; - msgs[2].flags = 0; - msgs[2].buf = &buf; - msgs[2].len = 1; - msgs[2].scl_rate = MPU_I2C_RATE; - - msgs[3].addr = mpu_addr; - msgs[3].flags = I2C_M_RD; - msgs[3].buf = data; - msgs[3].len = len; - msgs[3].scl_rate = MPU_I2C_RATE; - - ret = i2c_transfer(i2c_adap, msgs, 4); - if (ret == 4) - return 0; - else if(ret == 0) - return -EBUSY; - else - return ret; -} - -int mpu_memory_write(struct i2c_adapter *i2c_adap, - unsigned char mpu_addr, - unsigned short mem_addr, - unsigned int len, unsigned char const *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] = MPUREG_BANK_SEL; - bank[1] = mem_addr >> 8; - - addr[0] = MPUREG_MEM_START_ADDR; - addr[1] = mem_addr & 0xFF; - - buf[0] = 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[0].scl_rate = MPU_I2C_RATE; - - msgs[1].addr = mpu_addr; - msgs[1].flags = 0; - msgs[1].buf = addr; - msgs[1].len = sizeof(addr); - msgs[1].scl_rate = MPU_I2C_RATE; - - msgs[2].addr = mpu_addr; - msgs[2].flags = 0; - msgs[2].buf = (unsigned char *) buf; - msgs[2].len = len + 1; - msgs[2].scl_rate = MPU_I2C_RATE; - - ret = i2c_transfer(i2c_adap, msgs, 3); - if (ret == 3) - return 0; - else if(ret == 0) - return -EBUSY; - else - return ret; -} - -/** - * @} - */ diff --git a/drivers/misc/mpu3050/mpu-i2c.h b/drivers/misc/mpu3050/mpu-i2c.h deleted file mode 100755 index 0bbc8c64594e..000000000000 --- a/drivers/misc/mpu3050/mpu-i2c.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - $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 . - $ - */ -/** - * @defgroup - * @brief - * - * @{ - * @file mpu-i2c.c - * @brief - * - * - */ - -#ifndef __MPU_I2C_H__ -#define __MPU_I2C_H__ - -#include - -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 deleted file mode 100755 index 1aaaa685b827..000000000000 --- a/drivers/misc/mpu3050/mpuirq.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - $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 . - $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "mpu.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 && - mpuirq_dev_data.timeout && - (!(file->f_flags & O_NONBLOCK))) { - 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)); - mpuirq_data.data_type = 0; - } 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; - - poll_wait(file, &mpuirq_wait, poll); - if (mpuirq_dev_data.data_ready) - mask |= POLLIN | POLLRDNORM; - 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(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 */ - 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 */ -const 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; - /* mpu irq register xxm*/ - res = gpio_request(mpuirq_dev_data.irq, "mpu3050_int"); - if(res) - { - printk("failed to request mpu3050_int GPIO %d\n", - gpio_to_irq(mpuirq_dev_data.irq)); - return res; - } - res = gpio_direction_input(mpuirq_dev_data.irq); - if(res) - { - printk("failed to set mpu3050_int GPIO input\n"); - return res; - } - printk("gpio_to_irq(mpuirq_dev_data.irq) == %d \r\n", - gpio_to_irq(mpuirq_dev_data.irq)); - res =request_irq(gpio_to_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 deleted file mode 100755 index a71c79c75e8c..000000000000 --- a/drivers/misc/mpu3050/mpuirq.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - $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 . - $ - */ - -#ifndef __MPUIRQ__ -#define __MPUIRQ__ - -#ifdef __KERNEL__ -#include -#include -#else -#include -#endif - -#define MPUIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x40, unsigned long) -#define MPUIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x41, unsigned long) -#define MPUIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x42, struct timeval) -#define MPUIRQ_SET_FREQUENCY_DIVIDER _IOW(MPU_IOCTL, 0x43, unsigned long) - -#ifdef __KERNEL__ - -void mpuirq_exit(void); -int mpuirq_init(struct i2c_client *mpu_client); - -#endif - -#endif diff --git a/drivers/misc/mpu3050/slaveirq.c b/drivers/misc/mpu3050/slaveirq.c deleted file mode 100755 index 0276ddb173fc..000000000000 --- a/drivers/misc/mpu3050/slaveirq.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - $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 . - $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpu.h" -#include "slaveirq.h" -#include "mldl_cfg.h" -#include "mpu-i2c.h" - -/* function which gets slave data and sends it to SLAVE */ - -struct slaveirq_dev_data { - struct miscdevice dev; - struct i2c_client *slave_client; - struct mpuirq_data data; - wait_queue_head_t slaveirq_wait; - int irq; - int pid; - int data_ready; - int timeout; -}; - -/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 - * drivers: misc: pass miscdevice pointer via file private data - */ -static int slaveirq_open(struct inode *inode, struct file *file) -{ - /* Device node is availabe in the file->private_data, this is - * exactly what we want so we leave it there */ - struct slaveirq_dev_data *data = - container_of(file->private_data, struct slaveirq_dev_data, dev); - - dev_dbg(data->dev.this_device, - "%s current->pid %d\n", __func__, current->pid); - data->pid = current->pid; - return 0; -} - -static int slaveirq_release(struct inode *inode, struct file *file) -{ - struct slaveirq_dev_data *data = - container_of(file->private_data, struct slaveirq_dev_data, dev); - dev_dbg(data->dev.this_device, "slaveirq_release\n"); - return 0; -} - -/* read function called when from /dev/slaveirq is read */ -static ssize_t slaveirq_read(struct file *file, - char *buf, size_t count, loff_t *ppos) -{ - int len, err; - struct slaveirq_dev_data *data = - container_of(file->private_data, struct slaveirq_dev_data, dev); - - if (!data->data_ready && - data->timeout && - !(file->f_flags & O_NONBLOCK)) { - wait_event_interruptible_timeout(data->slaveirq_wait, - data->data_ready, - data->timeout); - } - - if (data->data_ready && NULL != buf - && count >= sizeof(data->data)) { - err = copy_to_user(buf, &data->data, sizeof(data->data)); - data->data.data_type = 0; - } else { - return 0; - } - if (err != 0) { - dev_err(data->dev.this_device, - "Copy to user returned %d\n", err); - return -EFAULT; - } - data->data_ready = 0; - len = sizeof(data->data); - return len; -} - -static unsigned int slaveirq_poll(struct file *file, - struct poll_table_struct *poll) -{ - int mask = 0; - struct slaveirq_dev_data *data = - container_of(file->private_data, struct slaveirq_dev_data, dev); - - poll_wait(file, &data->slaveirq_wait, poll); - if (data->data_ready) - mask |= POLLIN | POLLRDNORM; - return mask; -} - -/* ioctl - I/O control */ -static long slaveirq_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int retval = 0; - int tmp; - struct slaveirq_dev_data *data = - container_of(file->private_data, struct slaveirq_dev_data, dev); - - switch (cmd) { - case SLAVEIRQ_SET_TIMEOUT: - data->timeout = arg; - break; - - case SLAVEIRQ_GET_INTERRUPT_CNT: - tmp = data->data.interruptcount - 1; - if (data->data.interruptcount > 1) - data->data.interruptcount = 1; - - if (copy_to_user((int *) arg, &tmp, sizeof(int))) - return -EFAULT; - break; - case SLAVEIRQ_GET_IRQ_TIME: - if (copy_to_user((int *) arg, &data->data.irqtime, - sizeof(data->data.irqtime))) - return -EFAULT; - data->data.irqtime = 0; - break; - default: - retval = -EINVAL; - } - return retval; -} - -static irqreturn_t slaveirq_handler(int irq, void *dev_id) -{ - struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id; - static int mycount; - struct timeval irqtime; - mycount++; - - data->data.interruptcount++; - - /* wake up (unblock) for reading data from userspace */ - data->data_ready = 1; - - do_gettimeofday(&irqtime); - data->data.irqtime = (((long long) irqtime.tv_sec) << 32); - data->data.irqtime += irqtime.tv_usec; - data->data.data_type |= 1; - - wake_up_interruptible(&data->slaveirq_wait); - - return IRQ_HANDLED; - -} - -/* define which file operations are supported */ -static const struct file_operations slaveirq_fops = { - .owner = THIS_MODULE, - .read = slaveirq_read, - .poll = slaveirq_poll, - -#if HAVE_COMPAT_IOCTL - .compat_ioctl = slaveirq_ioctl, -#endif -#if HAVE_UNLOCKED_IOCTL - .unlocked_ioctl = slaveirq_ioctl, -#endif - .open = slaveirq_open, - .release = slaveirq_release, -}; - -int slaveirq_init(struct i2c_adapter *slave_adapter, - struct ext_slave_platform_data *pdata, - char *name) -{ - - int res; - struct slaveirq_dev_data *data; - - if (!pdata->irq) - return -EINVAL; - - pdata->irq_data = kzalloc(sizeof(*data), - GFP_KERNEL); - data = (struct slaveirq_dev_data *) pdata->irq_data; - if (!data) - return -ENOMEM; - - data->dev.minor = MISC_DYNAMIC_MINOR; - data->dev.name = name; - data->dev.fops = &slaveirq_fops; - data->irq = pdata->irq; - data->pid = 0; - data->data_ready = 0; - data->timeout = 0; - - /* mpu irq register xxm*/ - res = gpio_request(data->irq, name); - if(res) - { - printk("failed to request %s GPIO %d\n", - name,data->irq); - return res; - } - res = gpio_direction_input(data->irq); - if(res) - { - printk("failed to set %s GPIO input\n",name); - return res; - } - printk("%s registing irq == %d \r\n",name,gpio_to_irq(data->irq)); - //gpio_pull_updown(data->irq, GPIOPullUp); - //gpio_set_value(data->irq,GPIO_HIGH); - init_waitqueue_head(&data->slaveirq_wait); - res = request_irq(gpio_to_irq(data->irq), slaveirq_handler, IRQF_TRIGGER_FALLING,data->dev.name, data); - - if (res) { - dev_err(&slave_adapter->dev, - "myirqtest: cannot register IRQ %d\n", - data->irq); - goto out_request_irq; - } - - res = misc_register(&data->dev); - if (res < 0) { - dev_err(&slave_adapter->dev, - "misc_register returned %d\n", - res); - goto out_misc_register; - } - - return res; - -out_misc_register: - free_irq(data->irq, data); -out_request_irq: - kfree(pdata->irq_data); - pdata->irq_data = NULL; - - return res; -} - -void slaveirq_exit(struct ext_slave_platform_data *pdata) -{ - struct slaveirq_dev_data *data = pdata->irq_data; - - if (!pdata->irq_data || data->irq <= 0) - return; - - dev_info(data->dev.this_device, "Unregistering %s\n", - data->dev.name); - - free_irq(data->irq, data); - misc_deregister(&data->dev); - kfree(pdata->irq_data); - pdata->irq_data = NULL; -} diff --git a/drivers/misc/mpu3050/slaveirq.h b/drivers/misc/mpu3050/slaveirq.h deleted file mode 100755 index b4e1115f1b0a..000000000000 --- a/drivers/misc/mpu3050/slaveirq.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - $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 . - $ - */ - -#ifndef __SLAVEIRQ__ -#define __SLAVEIRQ__ - -#ifdef __KERNEL__ -#include -#endif - -#include "mpu.h" -#include "mpuirq.h" - -#define SLAVEIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x50, unsigned long) -#define SLAVEIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x51, unsigned long) -#define SLAVEIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x52, unsigned long) - -#ifdef __KERNEL__ - -void slaveirq_exit(struct ext_slave_platform_data *pdata); -int slaveirq_init(struct i2c_adapter *slave_adapter, - struct ext_slave_platform_data *pdata, - char *name); - -#endif - -#endif diff --git a/drivers/misc/mpu3050/timerirq.c b/drivers/misc/mpu3050/timerirq.c deleted file mode 100755 index 41c3ac981016..000000000000 --- a/drivers/misc/mpu3050/timerirq.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - $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 . - $ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpu.h" -#include "mltypes.h" -#include "timerirq.h" - -/* function which gets timer data and sends it to TIMER */ -struct timerirq_data { - int pid; - int data_ready; - int run; - int timeout; - unsigned long period; - struct mpuirq_data data; - struct completion timer_done; - wait_queue_head_t timerirq_wait; - struct timer_list timer; - struct miscdevice *dev; -}; - -static struct miscdevice *timerirq_dev_data; - -static void timerirq_handler(unsigned long arg) -{ - struct timerirq_data *data = (struct timerirq_data *)arg; - struct timeval irqtime; - - data->data.interruptcount++; - - data->data_ready = 1; - - do_gettimeofday(&irqtime); - data->data.irqtime = (((long long) irqtime.tv_sec) << 32); - data->data.irqtime += irqtime.tv_usec; - data->data.data_type |= 1; - - dev_dbg(data->dev->this_device, - "%s, %lld, %ld\n", __func__, data->data.irqtime, - (unsigned long)data); - - wake_up_interruptible(&data->timerirq_wait); - - if (data->run) - mod_timer(&data->timer, - jiffies + msecs_to_jiffies(data->period)); - else - complete(&data->timer_done); -} - -static int start_timerirq(struct timerirq_data *data) -{ - dev_dbg(data->dev->this_device, - "%s current->pid %d\n", __func__, current->pid); - - /* Timer already running... success */ - if (data->run) - return 0; - - /* Don't allow a period of 0 since this would fire constantly */ - if (!data->period) - return -EINVAL; - - data->run = TRUE; - data->data_ready = FALSE; - - init_completion(&data->timer_done); - setup_timer(&data->timer, timerirq_handler, (unsigned long)data); - - return mod_timer(&data->timer, - jiffies + msecs_to_jiffies(data->period)); -} - -static int stop_timerirq(struct timerirq_data *data) -{ - dev_dbg(data->dev->this_device, - "%s current->pid %lx\n", __func__, (unsigned long)data); - - if (data->run) { - data->run = FALSE; - mod_timer(&data->timer, jiffies + 1); - wait_for_completion(&data->timer_done); - } - return 0; -} - -/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 - * drivers: misc: pass miscdevice pointer via file private data - */ -static int timerirq_open(struct inode *inode, struct file *file) -{ - /* Device node is availabe in the file->private_data, this is - * exactly what we want so we leave it there */ - struct miscdevice *dev_data = file->private_data; - struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->dev = dev_data; - file->private_data = data; - data->pid = current->pid; - init_waitqueue_head(&data->timerirq_wait); - - dev_dbg(data->dev->this_device, - "%s current->pid %d\n", __func__, current->pid); - return 0; -} - -static int timerirq_release(struct inode *inode, struct file *file) -{ - struct timerirq_data *data = file->private_data; - dev_dbg(data->dev->this_device, "timerirq_release\n"); - if (data->run) - stop_timerirq(data); - kfree(data); - return 0; -} - -/* read function called when from /dev/timerirq is read */ -static ssize_t timerirq_read(struct file *file, - char *buf, size_t count, loff_t *ppos) -{ - int len, err; - struct timerirq_data *data = file->private_data; - - if (!data->data_ready && - data->timeout && - !(file->f_flags & O_NONBLOCK)) { - wait_event_interruptible_timeout(data->timerirq_wait, - data->data_ready, - data->timeout); - } - - if (data->data_ready && NULL != buf - && count >= sizeof(data->data)) { - err = copy_to_user(buf, &data->data, sizeof(data->data)); - data->data.data_type = 0; - } else { - return 0; - } - if (err != 0) { - dev_err(data->dev->this_device, - "Copy to user returned %d\n", err); - return -EFAULT; - } - data->data_ready = 0; - len = sizeof(data->data); - return len; -} - -static unsigned int timerirq_poll(struct file *file, - struct poll_table_struct *poll) -{ - int mask = 0; - struct timerirq_data *data = file->private_data; - - poll_wait(file, &data->timerirq_wait, poll); - if (data->data_ready) - mask |= POLLIN | POLLRDNORM; - return mask; -} - -/* ioctl - I/O control */ -static long timerirq_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int retval = 0; - int tmp; - struct timerirq_data *data = file->private_data; - - dev_dbg(data->dev->this_device, - "%s current->pid %d, %d, %ld\n", - __func__, current->pid, cmd, arg); - - if (!data) - return -EFAULT; - - switch (cmd) { - case TIMERIRQ_SET_TIMEOUT: - data->timeout = arg; - break; - case TIMERIRQ_GET_INTERRUPT_CNT: - tmp = data->data.interruptcount - 1; - if (data->data.interruptcount > 1) - data->data.interruptcount = 1; - - if (copy_to_user((int *) arg, &tmp, sizeof(int))) - return -EFAULT; - break; - case TIMERIRQ_START: - data->period = arg; - retval = start_timerirq(data); - break; - case TIMERIRQ_STOP: - retval = stop_timerirq(data); - break; - default: - retval = -EINVAL; - } - return retval; -} - -/* define which file operations are supported */ -static const struct file_operations timerirq_fops = { - .owner = THIS_MODULE, - .read = timerirq_read, - .poll = timerirq_poll, - -#if HAVE_COMPAT_IOCTL - .compat_ioctl = timerirq_ioctl, -#endif -#if HAVE_UNLOCKED_IOCTL - .unlocked_ioctl = timerirq_ioctl, -#endif - .open = timerirq_open, - .release = timerirq_release, -}; - -static int __init timerirq_init(void) -{ - - int res; - static struct miscdevice *data; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - timerirq_dev_data = data; - data->minor = MISC_DYNAMIC_MINOR; - data->name = "timerirq"; - data->fops = &timerirq_fops; - - res = misc_register(data); - if (res < 0) { - dev_err(data->this_device, - "misc_register returned %d\n", - res); - return res; - } - - return res; -} -module_init(timerirq_init); - -static void __exit timerirq_exit(void) -{ - struct miscdevice *data = timerirq_dev_data; - - dev_info(data->this_device, "Unregistering %s\n", - data->name); - - misc_deregister(data); - kfree(data); - - timerirq_dev_data = NULL; -} -module_exit(timerirq_exit); - -MODULE_AUTHOR("Invensense Corporation"); -MODULE_DESCRIPTION("Timer IRQ device driver."); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("timerirq"); diff --git a/drivers/misc/mpu3050/timerirq.h b/drivers/misc/mpu3050/timerirq.h deleted file mode 100755 index ec2c1e29f080..000000000000 --- a/drivers/misc/mpu3050/timerirq.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - $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 . - $ - */ - -#ifndef __TIMERIRQ__ -#define __TIMERIRQ__ - -#include "mpu.h" - -#define TIMERIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x60, unsigned long) -#define TIMERIRQ_GET_INTERRUPT_CNT _IOW(MPU_IOCTL, 0x61, unsigned long) -#define TIMERIRQ_START _IOW(MPU_IOCTL, 0x62, unsigned long) -#define TIMERIRQ_STOP _IO(MPU_IOCTL, 0x63) - -#endif diff --git a/include/linux/mpu.h b/include/linux/mpu.h index d66d9e76b9af..00d9e6c62405 100755 --- a/include/linux/mpu.h +++ b/include/linux/mpu.h @@ -1,20 +1,7 @@ /* $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 . - $ + Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. + $ */ #ifndef __MPU_H_ @@ -25,12 +12,9 @@ #include #elif defined LINUX #include -#endif - -#ifdef M_HW -#include "mpu6000.h" +#include #else -#include "mpu3050.h" +#include "mltypes.h" #endif /* Number of axes on each sensor */ @@ -38,73 +22,29 @@ #define ACCEL_NUM_AXES (3) #define COMPASS_NUM_AXES (3) -#if defined __KERNEL__ || defined LINUX -#define MPU_IOCTL (0x81) /* Magic number for MPU Iocts */ -/* IOCTL commands for /dev/mpu */ -#define MPU_SET_MPU_CONFIG _IOW(MPU_IOCTL, 0x00, struct mldl_cfg) -#define MPU_GET_MPU_CONFIG _IOR(MPU_IOCTL, 0x00, struct mldl_cfg) - -#define MPU_SET_PLATFORM_DATA _IOW(MPU_IOCTL, 0x01, struct mldl_cfg) - -#define MPU_READ _IOR(MPU_IOCTL, 0x10, struct mpu_read_write) -#define MPU_WRITE _IOW(MPU_IOCTL, 0x10, struct mpu_read_write) -#define MPU_READ_MEM _IOR(MPU_IOCTL, 0x11, struct mpu_read_write) -#define MPU_WRITE_MEM _IOW(MPU_IOCTL, 0x11, struct mpu_read_write) -#define MPU_READ_FIFO _IOR(MPU_IOCTL, 0x12, struct mpu_read_write) -#define MPU_WRITE_FIFO _IOW(MPU_IOCTL, 0x12, struct mpu_read_write) - -#define MPU_READ_COMPASS _IOR(MPU_IOCTL, 0x12, unsigned char) -#define MPU_READ_ACCEL _IOR(MPU_IOCTL, 0x13, unsigned char) -#define MPU_READ_PRESSURE _IOR(MPU_IOCTL, 0x14, unsigned char) - -#define MPU_CONFIG_ACCEL _IOW(MPU_IOCTL, 0x20, struct ext_slave_config) -#define MPU_CONFIG_COMPASS _IOW(MPU_IOCTL, 0x21, struct ext_slave_config) -#define MPU_CONFIG_PRESSURE _IOW(MPU_IOCTL, 0x22, struct ext_slave_config) - -#define MPU_GET_CONFIG_ACCEL _IOR(MPU_IOCTL, 0x20, struct ext_slave_config) -#define MPU_GET_CONFIG_COMPASS _IOR(MPU_IOCTL, 0x21, struct ext_slave_config) -#define MPU_GET_CONFIG_PRESSURE _IOR(MPU_IOCTL, 0x22, struct ext_slave_config) - -#define MPU_SUSPEND _IO(MPU_IOCTL, 0x30) -#define MPU_RESUME _IO(MPU_IOCTL, 0x31) -/* Userspace PM Event response */ -#define MPU_PM_EVENT_HANDLED _IO(MPU_IOCTL, 0x32) - -#endif -/* Structure for the following IOCTL's: - MPU_READ - MPU_WRITE - MPU_READ_MEM - MPU_WRITE_MEM - MPU_READ_FIFO - MPU_WRITE_FIFO -*/ struct mpu_read_write { /* Memory address or register address depending on ioctl */ - unsigned short address; - unsigned short length; - unsigned char *data; + __u16 address; + __u16 length; + __u8 *data; }; enum mpuirq_data_type { - MPUIRQ_DATA_TYPE_MPU_IRQ, - MPUIRQ_DATA_TYPE_SLAVE_IRQ, - MPUIRQ_DATA_TYPE_PM_EVENT, - MPUIRQ_DATA_TYPE_NUM_TYPES, + MPUIRQ_DATA_TYPE_MPU_IRQ, + MPUIRQ_DATA_TYPE_SLAVE_IRQ, + MPUIRQ_DATA_TYPE_PM_EVENT, + MPUIRQ_DATA_TYPE_NUM_TYPES, }; /* User space PM event notification */ #define MPU_PM_EVENT_SUSPEND_PREPARE (3) #define MPU_PM_EVENT_POST_SUSPEND (4) -#define MAX_MPUIRQ_DATA_SIZE (32) - struct mpuirq_data { - int interruptcount; - unsigned long long irqtime; - int data_type; - int data_size; - void *data; + __u32 interruptcount; + __u64 irqtime; + __u32 data_type; + __s32 data; }; enum ext_slave_config_key { @@ -120,7 +60,36 @@ enum ext_slave_config_key { MPU_SLAVE_CONFIG_IRQ_RESUME, MPU_SLAVE_WRITE_REGISTERS, MPU_SLAVE_READ_REGISTERS, - MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS, + MPU_SLAVE_CONFIG_INTERNAL_REFERENCE, + /* AMI 306 specific config keys */ + MPU_SLAVE_PARAM, + MPU_SLAVE_WINDOW, + MPU_SLAVE_READWINPARAMS, + MPU_SLAVE_SEARCHOFFSET, + /* AKM specific config keys */ + MPU_SLAVE_READ_SCALE, + /* MPU3050 and MPU6050 Keys */ + MPU_SLAVE_INT_CONFIG, + MPU_SLAVE_EXT_SYNC, + MPU_SLAVE_FULL_SCALE, + MPU_SLAVE_LPF, + MPU_SLAVE_CLK_SRC, + MPU_SLAVE_DIVIDER, + MPU_SLAVE_DMP_ENABLE, + MPU_SLAVE_FIFO_ENABLE, + MPU_SLAVE_DMP_CFG1, + MPU_SLAVE_DMP_CFG2, + MPU_SLAVE_TC, + MPU_SLAVE_GYRO, + MPU_SLAVE_ADDR, + MPU_SLAVE_PRODUCT_REVISION, + MPU_SLAVE_SILICON_REVISION, + MPU_SLAVE_PRODUCT_ID, + MPU_SLAVE_GYRO_SENS_TRIM, + MPU_SLAVE_ACCEL_SENS_TRIM, + MPU_SLAVE_RAM, + /* -------------------------- */ + MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS }; /* For the MPU_SLAVE_CONFIG_IRQ_SUSPEND and MPU_SLAVE_CONFIG_IRQ_RESUME */ @@ -131,50 +100,66 @@ enum ext_slave_config_irq_type { }; /* Structure for the following IOCTS's + * MPU_CONFIG_GYRO * MPU_CONFIG_ACCEL * MPU_CONFIG_COMPASS * MPU_CONFIG_PRESSURE + * MPU_GET_CONFIG_GYRO * MPU_GET_CONFIG_ACCEL * MPU_GET_CONFIG_COMPASS * MPU_GET_CONFIG_PRESSURE + * + * @key one of enum ext_slave_config_key + * @len length of data pointed to by data + * @apply zero if communication with the chip is not necessary, false otherwise + * This flag can be used to select cached data or to refresh cashed data + * cache data to be pushed later or push immediately. If true and the + * slave is on the secondary bus the MPU will first enger bypass mode + * before calling the slaves .config or .get_config funcion + * @data pointer to the data to confgure or get */ struct ext_slave_config { - int key; - int len; - int apply; + __u8 key; + __u16 len; + __u8 apply; void *data; }; enum ext_slave_type { EXT_SLAVE_TYPE_GYROSCOPE, - EXT_SLAVE_TYPE_ACCELEROMETER, + EXT_SLAVE_TYPE_ACCEL, EXT_SLAVE_TYPE_COMPASS, EXT_SLAVE_TYPE_PRESSURE, /*EXT_SLAVE_TYPE_TEMPERATURE */ + + EXT_SLAVE_NUM_TYPES }; enum ext_slave_id { ID_INVALID = 0, ACCEL_ID_LIS331, - ACCEL_ID_LSM303, + ACCEL_ID_LSM303DLX, ACCEL_ID_LIS3DH, ACCEL_ID_KXSD9, ACCEL_ID_KXTF9, ACCEL_ID_BMA150, ACCEL_ID_BMA222, - ACCEL_ID_ADI346, + ACCEL_ID_BMA250, + ACCEL_ID_ADXL34X, ACCEL_ID_MMA8450, ACCEL_ID_MMA845X, - ACCEL_ID_MPU6000, + ACCEL_ID_MPU6050, - COMPASS_ID_AKM, + COMPASS_ID_AK8975, + COMPASS_ID_AK8972, COMPASS_ID_AMI30X, COMPASS_ID_AMI306, COMPASS_ID_YAS529, COMPASS_ID_YAS530, COMPASS_ID_HMC5883, - COMPASS_ID_LSM303, + COMPASS_ID_LSM303DLH, + COMPASS_ID_LSM303DLM, COMPASS_ID_MMC314X, COMPASS_ID_HSCDTD002B, COMPASS_ID_HSCDTD004A, @@ -197,10 +182,11 @@ enum ext_slave_bus { /** - * struct ext_slave_platform_data - Platform data for mpu3050 slave devices + * struct ext_slave_platform_data - Platform data for mpu3050 and mpu6050 + * slave devices * - * @get_slave_descr: Function pointer to retrieve the struct ext_slave_descr - * for this slave + * @type: the type of slave device based on the enum ext_slave_type + * definitions. * @irq: the irq number attached to the slave if any. * @adapt_num: the I2C adapter number. * @bus: the bus the slave is attached to: enum ext_slave_bus @@ -216,20 +202,29 @@ enum ext_slave_bus { * column should have exactly 1 non-zero value. */ struct ext_slave_platform_data { - struct ext_slave_descr *(*get_slave_descr) (void); - int irq; - int adapt_num; - int bus; - unsigned char address; - signed char orientation[9]; + __u8 type; + __u32 irq; + __u32 adapt_num; + __u32 bus; + __u8 address; + __s8 orientation[9]; void *irq_data; void *private_data; }; +struct fix_pnt_range { + __s32 mantissa; + __s32 fraction; +}; + +static inline long range_fixedpoint_to_long_mg(struct fix_pnt_range rng) +{ + return (long)(rng.mantissa * 1000 + rng.fraction / 10); +} -struct tFixPntRange { - long mantissa; - long fraction; +struct ext_slave_read_trigger { + __u8 reg; + __u8 value; }; /** @@ -246,13 +241,15 @@ struct tFixPntRange { * @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. + * @read_reg: starting register address to retrieve data. + * @read_len: length in bytes of the sensor data. Typically 6. * @endian: byte order of the data. enum ext_slave_endian - * @range: full scale range of the slave ouput: struct tFixPntRange + * @range: full scale range of the slave ouput: struct fix_pnt_range + * @trigger: If reading data first requires writing a register this is the + * data to write. * - * Defines the functions and information about the slave the mpu3050 needs to - * use the slave device. + * Defines the functions and information about the slave the mpu3050 and + * mpu6050 needs to use the slave device. */ struct ext_slave_descr { int (*init) (void *mlsl_handle, @@ -270,7 +267,7 @@ struct ext_slave_descr { int (*read) (void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata, - unsigned char *data); + __u8 *data); int (*config) (void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata, @@ -281,22 +278,20 @@ struct ext_slave_descr { struct ext_slave_config *config); char *name; - unsigned char type; - unsigned char id; - unsigned char reg; - unsigned int len; - unsigned char endian; - struct tFixPntRange range; + __u8 type; + __u8 id; + __u8 read_reg; + __u8 read_len; + __u8 endian; + struct fix_pnt_range range; + struct ext_slave_read_trigger *trigger; }; /** - * struct mpu3050_platform_data - Platform data for the mpu3050 driver + * struct mpu_platform_data - Platform data for the mpu 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 - * @pressure: Pressure platform data + * @orientation: Orientation matrix of the gyroscope * * Contains platform specific information on how to configure the MPU3050 to * work on this platform. The orientation matricies are 3x3 rotation matricies @@ -304,164 +299,64 @@ struct ext_slave_descr { * platform orientation. The values must be one of 0, 1, or -1 and each row and * column should have exactly 1 non-zero value. */ -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; - struct ext_slave_platform_data pressure; +struct mpu_platform_data { + __u8 int_config; + __u8 level_shifter; + __s8 orientation[GYRO_NUM_AXES * GYRO_NUM_AXES]; }; +#if defined __KERNEL__ || defined LINUX +#define MPU_IOCTL (0x81) /* Magic number for MPU Iocts */ +/* IOCTL commands for /dev/mpu */ -/* - Accelerometer -*/ -#define get_accel_slave_descr NULL - -#ifdef CONFIG_MPU_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_MPU_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_MPU_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_MPU_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_MPU_SENSORS_KXTF9 /* 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_MPU_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_MPU_SENSORS_LIS3DH /* ST accelerometer */ -struct ext_slave_descr *lis3dh_get_slave_descr(void); -#undef get_accel_slave_descr -#define get_accel_slave_descr lis3dh_get_slave_descr -#endif - -#ifdef CONFIG_MPU_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 - -/* MPU6000 Accel */ -#if defined(CONFIG_MPU_SENSORS_MPU6000) || \ - defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) -struct ext_slave_descr *mantis_get_slave_descr(void); -#undef get_accel_slave_descr -#define get_accel_slave_descr mantis_get_slave_descr -#endif - -#ifdef CONFIG_MPU_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_MPU_SENSORS_MMA845X /* Freescale accelerometer */ -struct ext_slave_descr *mma845x_get_slave_descr(void); -#undef get_accel_slave_descr -#define get_accel_slave_descr mma845x_get_slave_descr -#endif - - -/* - Compass -*/ -#define get_compass_slave_descr NULL - -#ifdef CONFIG_MPU_SENSORS_AK8975 /* 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_MPU_SENSORS_AMI30X /* AICHI Steel AMI304/305 compass */ -struct ext_slave_descr *ami30x_get_slave_descr(void); -#undef get_compass_slave_descr -#define get_compass_slave_descr ami30x_get_slave_descr -#endif - -#ifdef CONFIG_MPU_SENSORS_AMI306 /* AICHI Steel AMI306 compass */ -struct ext_slave_descr *ami306_get_slave_descr(void); -#undef get_compass_slave_descr -#define get_compass_slave_descr ami306_get_slave_descr -#endif - -#ifdef CONFIG_MPU_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_MPU_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_MPU_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_MPU_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 - -#ifdef CONFIG_MPU_SENSORS_YAS530 /* Yamaha compass */ -struct ext_slave_descr *yas530_get_slave_descr(void); -#undef get_compass_slave_descr -#define get_compass_slave_descr yas530_get_slave_descr -#endif +/*-------------------------------------------------------------------------- + * Deprecated, debugging only + */ +#define MPU_SET_MPU_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x01, struct mpu_platform_data) +#define MPU_SET_EXT_SLAVE_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x01, struct ext_slave_platform_data) +/*--------------------------------------------------------------------------*/ +#define MPU_GET_EXT_SLAVE_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x02, struct ext_slave_platform_data) +#define MPU_GET_MPU_PLATFORM_DATA \ + _IOWR(MPU_IOCTL, 0x02, struct mpu_platform_data) +#define MPU_GET_EXT_SLAVE_DESCR \ + _IOWR(MPU_IOCTL, 0x02, struct ext_slave_descr) + +#define MPU_READ _IOWR(MPU_IOCTL, 0x10, struct mpu_read_write) +#define MPU_WRITE _IOW(MPU_IOCTL, 0x10, struct mpu_read_write) +#define MPU_READ_MEM _IOWR(MPU_IOCTL, 0x11, struct mpu_read_write) +#define MPU_WRITE_MEM _IOW(MPU_IOCTL, 0x11, struct mpu_read_write) +#define MPU_READ_FIFO _IOWR(MPU_IOCTL, 0x12, struct mpu_read_write) +#define MPU_WRITE_FIFO _IOW(MPU_IOCTL, 0x12, struct mpu_read_write) + +#define MPU_READ_COMPASS _IOR(MPU_IOCTL, 0x12, __u8) +#define MPU_READ_ACCEL _IOR(MPU_IOCTL, 0x13, __u8) +#define MPU_READ_PRESSURE _IOR(MPU_IOCTL, 0x14, __u8) + +#define MPU_CONFIG_GYRO _IOW(MPU_IOCTL, 0x20, struct ext_slave_config) +#define MPU_CONFIG_ACCEL _IOW(MPU_IOCTL, 0x21, struct ext_slave_config) +#define MPU_CONFIG_COMPASS _IOW(MPU_IOCTL, 0x22, struct ext_slave_config) +#define MPU_CONFIG_PRESSURE _IOW(MPU_IOCTL, 0x23, struct ext_slave_config) + +#define MPU_GET_CONFIG_GYRO _IOWR(MPU_IOCTL, 0x20, struct ext_slave_config) +#define MPU_GET_CONFIG_ACCEL _IOWR(MPU_IOCTL, 0x21, struct ext_slave_config) +#define MPU_GET_CONFIG_COMPASS _IOWR(MPU_IOCTL, 0x22, struct ext_slave_config) +#define MPU_GET_CONFIG_PRESSURE _IOWR(MPU_IOCTL, 0x23, struct ext_slave_config) + +#define MPU_SUSPEND _IOW(MPU_IOCTL, 0x30, __u32) +#define MPU_RESUME _IOW(MPU_IOCTL, 0x31, __u32) +/* Userspace PM Event response */ +#define MPU_PM_EVENT_HANDLED _IO(MPU_IOCTL, 0x32) -#ifdef CONFIG_MPU_SENSORS_HSCDTD002B /* Alps HSCDTD002B compass */ -struct ext_slave_descr *hscdtd002b_get_slave_descr(void); -#undef get_compass_slave_descr -#define get_compass_slave_descr hscdtd002b_get_slave_descr -#endif +#define MPU_GET_REQUESTED_SENSORS _IOR(MPU_IOCTL, 0x40, __u8) +#define MPU_SET_REQUESTED_SENSORS _IOW(MPU_IOCTL, 0x40, __u8) +#define MPU_GET_IGNORE_SYSTEM_SUSPEND _IOR(MPU_IOCTL, 0x41, __u8) +#define MPU_SET_IGNORE_SYSTEM_SUSPEND _IOW(MPU_IOCTL, 0x41, __u8) +#define MPU_GET_MLDL_STATUS _IOR(MPU_IOCTL, 0x42, __u8) +#define MPU_GET_I2C_SLAVES_ENABLED _IOR(MPU_IOCTL, 0x43, __u8) -#ifdef CONFIG_MPU_SENSORS_HSCDTD004A /* Alps HSCDTD004A compass */ -struct ext_slave_descr *hscdtd004a_get_slave_descr(void); -#undef get_compass_slave_descr -#define get_compass_slave_descr hscdtd004a_get_slave_descr -#endif -/* - Pressure -*/ -#define get_pressure_slave_descr NULL - -#ifdef CONFIG_MPU_SENSORS_BMA085 /* BMA pressure */ -struct ext_slave_descr *bma085_get_slave_descr(void); -#undef get_pressure_slave_descr -#define get_pressure_slave_descr bma085_get_slave_descr #endif #endif /* __MPU_H_ */