GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
SDK_DIR ?= $(shell cd $(CURDIR)/../../../.. && /bin/pwd)
include $(SDK_DIR)/build/base.mk
objects :=
objects += msensor
obj-$(XMEDIA_DRV_BUILDTYPE) += ${addsuffix /,${objects}}
objects_clean := $(addsuffix _clean, $(objects))
.PHONY: all clean prepare $(objects) $(objects_clean)
all: prepare $(objects)
clean: $(objects_clean)
$(objects):
$(AT)$(MAKE) -C $@
$(objects_clean):
$(AT)$(MAKE) -C $(patsubst %_clean, %, $@) clean
prepare:
+26
View File
@@ -0,0 +1,26 @@
ifneq ($(srctree),)
KERNEL_DIR := $(srctree)
SDK_DIR := $(shell cd $(KERNEL_DIR)/../../.. && /bin/pwd)
else
SDK_DIR := $(shell cd $(CURDIR)/../../../../.. && /bin/pwd)
endif
include $(SDK_DIR)/build/base.mk
objects := msensor_spi msensor_mng msensor_chip
objects_clean := $(addsuffix _clean, $(objects))
obj-y += $(addsuffix /, $(objects))
.PHONY: all clean $(objects) $(objects_clean)
all: $(objects)
# $(AT)cp -rf $(BUILD_DIR)/load $(SDK_KO_DIR)
clean: $(objects_clean)
$(objects):
$(AT)$(MAKE) -C $@
$(objects_clean):
$(AT)$(MAKE) -C $(patsubst %_clean, %, $@) clean
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (c) XMEDIA. All rights reserved.
*/
#ifndef __DRV_MSENSOR_H__
#define __DRV_MSENSOR_H__
#include "xmedia_msensor.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
xmedia_s32 msensor_buf_add_user(xmedia_s32 dev, xmedia_s32 *id);
xmedia_s32 msensor_buf_delete_user(xmedia_s32 dev, const xmedia_s32 *id);
xmedia_s32 msensor_buf_get_data(xmedia_s32 dev, xmedia_msensor_data_info *msensor_data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif //__DRV_MSENSOR_H__
@@ -0,0 +1,56 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef MOTIONSENSOR_EXT_H
#define MOTIONSENSOR_EXT_H
#include "common.h"
#include "xmedia_debug.h"
#include "xmedia_msensor.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
typedef struct {
xmedia_s32 (*pfn_get_config_from_chip) (xmedia_s32 dev, xmedia_msensor_param *param);
xmedia_s32 (*pfn_write_data_to_buf) (xmedia_s32 dev);
} msensor_mng_callback;
/* debug print format */
#define MSENSOR_ERR_TRACE(fmt, ...) \
printk(KERN_ERR "" fmt, \
##__VA_ARGS__)
#define msensor_warn_trace(fmt, ...) \
printk(KERN_WARN "[Func]:%s [Line]:%d [Info]:" fmt, __FUNCTION__, __LINE__, \
##__VA_ARGS__)
#define msensor_notice_trace(fmt, ...) \
printk(KERN_NOTICE "[Func]:%s [Line]:%d [Info]:" fmt, __FUNCTION__, __LINE__, \
##__VA_ARGS__)
#define msensor_info_trace(fmt, ...) \
printk(KERN_INFO "[Func]:%s [Line]:%d [Info]:" fmt, __FUNCTION__, __LINE__, \
##__VA_ARGS__)
#define msensor_debug_trace(fmt, ...) \
printk(KERN_DEBUG "[Func]:%s [Line]:%d [Info]:" fmt, __FUNCTION__, __LINE__, \
##__VA_ARGS__)
xmedia_s32 msensor_mng_register_call_back(xmedia_s32 dev, const msensor_mng_callback *callback);
xmedia_void msensor_mng_unregister_call_back(xmedia_s32 dev);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,44 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_CHIP_IOCTL_H__
#define __MSENSOR_CHIP_IOCTL_H__
#include "xmedia_msensor.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* end of #ifdef __cplusplus */
#define MSENSOR_TYPE_CHIP 12
typedef enum {
IOC_NR_MSENSOR_CHIP_BIND_FLAG2FD = 0,
IOC_NR_MSENSOR_CHIP_CREATE,
IOC_NR_MSENSOR_CHIP_DESTROY,
IOC_NR_MSENSOR_CHIP_START,
IOC_NR_MSENSOR_CHIP_STOP,
IOC_NR_MSENSOR_CHIP_GET_PARAM,
IOC_NR_MSENSOR_CHIP_MNG_INIT,
IOC_NR_MSENSOR_CHIP_MAX
} ioc_nr_msensor_chip;
#define MSENSOR_CMD_CHIP_BIND_FLAG2FD _IOW(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_BIND_FLAG2FD, xmedia_s32)
#define MSENSOR_CMD_START _IO(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_START)
#define MSENSOR_CMD_STOP _IO(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_STOP)
#define MSENSOR_CMD_CREATE _IOW(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_CREATE, xmedia_msensor_param)
#define MSENSOR_CMD_DESTROY _IO(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_DESTROY)
#define MSENSOR_CMD_GET_PARAM _IOR(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_GET_PARAM, xmedia_msensor_param)
#define MSENSOR_CMD_MNG_INIT _IOW(MSENSOR_TYPE_CHIP, IOC_NR_MSENSOR_CHIP_MNG_INIT, xmedia_msensor_param)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,46 @@
ifneq ($(srctree),)
KERNEL_DIR := $(srctree)
SDK_DIR := $(shell cd $(KERNEL_DIR)/../../.. && /bin/pwd)
else
SDK_DIR := $(shell cd $(CURDIR)/../../../../../.. && /bin/pwd)
endif
include $(SDK_DIR)/build/base.mk
export TRANSFER_TYPE := SPI
MOD_NAME := xm_msensor_chip
SRCS := ./main/msensor.c
SRCS += ./proc/msensor_chip_proc.c
SRCS += ./sensor_dev/icm42670/icm42670.c
SRCS += ./sensor_dev/icm42670/msensor_gpio.c
SRCS += ./transfer_type/spi/spi_dev.c
SDK_KER_CFLAGS += -I$(GMP_DIR)/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/usr/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/osal/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_chip/proc
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_chip/sensor_dev/icm42670
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_chip/transfer_type/spi
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_spi/spi
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_chip/main
#SDK_KER_CFLAGS += -I$(PWD)/pub
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/ext_inc
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_spi
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_mng/include
SDK_KER_CFLAGS += -DTRANSFER_SPI
SDK_KER_CFLAGS += -DICM42670_PARAM_PROC
SDK_KER_CFLAGS += -DCONFIG_PROC_SHOW_SUPPORT
$(info SDK_KER_CFLAGS=$(SDK_KER_CFLAGS))
$(info SRCS=$(SRCS))
$(info SDK_DIR=$(SDK_DIR))
$(info CURDIR=$(CURDIR))
include $(SDK_DIR)/build/sdk_ko_rules.mk
@@ -0,0 +1,712 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor.h"
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/semaphore.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/hrtimer.h>
#include "osal.h"
#include "mmz.h"
#include "msensor_ext.h"
#include "msensor_chip_ioctl.h"
#include "msensor.h"
#include "msensor_exe.h"
#include "icm42670.h"
#define UMAP_MSENSOR_CHIP_MINOR_BASE 153
#define UMAP_DEVNANME_MSENSOR_CHIP_BASE "msensor_chip"
#if (defined CONFIG_PROC_SHOW_SUPPORT)
#include "msensor_chip_proc.h"
#endif
static osal_dev_t *g_msensor_chip_dev = XMEDIA_NULL;
static xmedia_s32 g_msensor_init[XMEDIA_MSENSOR_MAX_DEV_NUM] = { XMEDIA_FALSE};
static xmedia_bool g_msensor_start[XMEDIA_MSENSOR_MAX_DEV_NUM] = { XMEDIA_FALSE};
xmedia_msensor_param *g_msensor_param [XMEDIA_MSENSOR_MAX_DEV_NUM] = { XMEDIA_NULL};
static triger_config g_triger_data[XMEDIA_MSENSOR_MAX_DEV_NUM] = { 0 };
static osal_atomic_t g_msensor_chip_user_ref[XMEDIA_MSENSOR_MAX_DEV_NUM] = { 0 };
#define safe_kfree(memory) \
do { \
if ((memory) != XMEDIA_NULL) { \
osal_kfree(memory); \
memory = XMEDIA_NULL; \
} \
} while (0)
xmedia_msensor_param *msensor_chip_get_param(xmedia_s32 dev)
{
return g_msensor_param[dev];
}
xmedia_bool msensor_chip_get_status(xmedia_s32 dev)
{
return g_msensor_start[dev];
}
#ifdef MNGBUFF_ENABLE
xmedia_s32 msensor_chip_int_callback(xmedia_s32 dev, xmedia_msensor_data *msensor_data)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
if (msensor_data == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d msensor_data is null\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
ret = msensor_mng_write_data_to_buf(dev, msensor_data);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d write data tobuf failed!(ret:0x%x)\n", dev, ret);
return ret;
}
return ret;
}
static xmedia_s32 msensor_chip_init_mng_buf(xmedia_s32 dev, xmedia_msensor_attr msensor_attr,
xmedia_msensor_buf_attr *msensor_buf_attr, xmedia_msensor_config *msensor_config)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
if ((msensor_buf_attr == XMEDIA_NULL) || (msensor_config == XMEDIA_NULL)) {
MSENSOR_ERR_TRACE("dev %d msensor_buf_attr or msensor_config is null!\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
ret = msensor_mng_buf_init(dev, &msensor_attr, msensor_buf_attr, msensor_config);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d init mng buff failed!(ret:0x%x)\n", dev, ret);
return ret;
}
return ret;
}
static xmedia_s32 msensor_chip_exit_mng_buf(xmedia_s32 dev)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
ret = msensor_mng_buf_exit(dev);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d exit mng buff failed!(ret:0x%x)\n", dev, ret);
return ret;
}
return ret;
}
//todo,待确认,释放需要通过ioctl开放get cfg接口
static xmedia_s32 msensor_chip_get_cfg(xmedia_s32 dev, xmedia_msensor_param *msensor_param)
{
if (g_msensor_param[dev] == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d msensor_param is null\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
if (msensor_param == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d input param is null\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
osal_memcpy(msensor_param, g_msensor_param[dev], sizeof(xmedia_msensor_param));
return XMEDIA_SUCCESS;
}
// todo,通过ioctl开放get data接口
xmedia_s32 msensor_chip_get_data(xmedia_s32 dev)
{
xmedia_s32 ret;
ret = chip_get_data_for_one_frm(dev);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d get data failed!\n", dev);
}
return ret;
}
static xmedia_s32 msensor_chip_register_mng_callback(xmedia_s32 dev)
{
xmedia_s32 ret;
msensor_mng_callback callback = { 0 };
callback.pfn_get_config_from_chip = msensor_chip_get_cfg;
callback.pfn_write_data_to_buf = msensor_chip_get_data;
ret = msensor_mng_register_call_back(dev, &callback);
if(ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d register msensor callback failed\n", dev);
return XMEDIA_FAILURE;
}
return ret;
}
static xmedia_void msensor_chip_unregister_mng_callback(xmedia_s32 dev)
{
msensor_mng_unregister_call_back(dev);
return;
}
#endif
static xmedia_s32 msensor_chip_open(xmedia_void *private_data)
{
xmedia_unused(private_data);
MSENSOR_ERR_TRACE("msensor open\n");
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_chip_release(xmedia_void *private_data)
{
xmedia_unused(private_data);
MSENSOR_ERR_TRACE("msensor close\n");
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_chip_freeze(osal_dev_t *dev)
{
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_chip_restore(osal_dev_t *dev)
{
return XMEDIA_SUCCESS;
}
/* msensor chip ioctl functions */
static xmedia_s32 msensor_chip_drv_user_start(xmedia_s32 dev, xmedia_uintptr_t arg)
{
if (g_msensor_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d msensor is not init!\n", dev);
return XMEDIA_FAILURE;
}
if (g_msensor_start[dev] == XMEDIA_TRUE) {
MSENSOR_ERR_TRACE("dev %d msensor is already start!\n", dev);
return XMEDIA_SUCCESS;
}
xmedia_unused(arg);
chip_fifo_data_reset(dev);
osal_msleep(100); // 1.16 fix acc && gyro pts not sync problem
if (g_triger_data[dev].triger_mode == TRIGER_TIMER) {
chip_timer_run(dev);
} else if (g_triger_data[dev].triger_mode == TRIGER_EXTERN_INTERRUPT) {
chip_interrupt_run(dev);
} else {
MSENSOR_ERR_TRACE("not triger_mode %d\n",g_triger_data[dev].triger_mode);
return XMEDIA_FAILURE;
}
g_msensor_start[dev] = XMEDIA_TRUE;
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_chip_drv_user_stop(xmedia_s32 dev, xmedia_uintptr_t arg)
{
if (g_msensor_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d msensor is not init!\n", dev);
return XMEDIA_FAILURE;
}
if (g_msensor_start[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d msensor is already stop!\n", dev);
return XMEDIA_SUCCESS;
}
xmedia_unused(arg);
if (g_triger_data[dev].triger_mode == TRIGER_TIMER) {
chip_timer_stop(dev);
} else if (g_triger_data[dev].triger_mode == TRIGER_EXTERN_INTERRUPT) {
chip_interrupt_stop(dev);
} else {
MSENSOR_ERR_TRACE("not triger_mode %d\n",g_triger_data[dev].triger_mode);
return XMEDIA_FAILURE;
}
g_msensor_start[dev] = XMEDIA_FALSE;
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_chip_drv_user_init(xmedia_s32 dev, xmedia_uintptr_t arg)
{
xmedia_s32 ret;
xmedia_msensor_param *msensor_param;
if (g_msensor_init[dev] == XMEDIA_TRUE) {
MSENSOR_ERR_TRACE("dev %d msensor is already inited!\n", dev);
return XMEDIA_FAILURE;
}
msensor_param = (xmedia_msensor_param *)(arg);
ret = mmz_check_phyaddr(msensor_param->buf_attr.phys_addr, msensor_param->buf_attr.buf_len);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d check mem share failed, buf_attr.phys_addr is 0x%llx\n", dev,
msensor_param->buf_attr.phys_addr);
return XMEDIA_FAILURE;
}
osal_memcpy(g_msensor_param[dev], (xmedia_void *)arg, sizeof(xmedia_msensor_param));
if (((XMEDIA_MSENSOR_DEVICE_GYRO & g_msensor_param[dev]->attr.device_mask) &&
(g_msensor_param[dev]->config.gyro_config.odr == 0)) ||
((XMEDIA_MSENSOR_DEVICE_ACC & g_msensor_param[dev]->attr.device_mask) &&
(g_msensor_param[dev]->config.acc_config.odr == 0))) {
MSENSOR_ERR_TRACE("dev %d msensor param err!\n", dev);
return XMEDIA_FAILURE;
}
g_msensor_param[dev]->config.gyro_config.temperature_max = MOTIONSENSOR_MAX_TEMP;
g_msensor_param[dev]->config.gyro_config.temperature_min = MOTIONSENSOR_MIN_TEMP;
g_msensor_param[dev]->config.acc_config.temperature_max = MOTIONSENSOR_MAX_TEMP;
g_msensor_param[dev]->config.acc_config.temperature_min = MOTIONSENSOR_MIN_TEMP;
/* init senser */
ret = chip_dev_init(dev, g_msensor_param[dev]);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d chip dev init failed! ret=%x\n", dev, ret);
return ret;
}
ret = chip_get_triger_config(dev, &g_triger_data[dev]);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d imu get triger config failed! ret=%x\n", dev, ret);
return ret;
}
#ifdef MNGBUFF_ENABLE
/* buff init, fix in this */
msensor_chip_init_mng_buf(dev, g_msensor_param[dev]->attr, &g_msensor_param[dev]->buf_attr,
&g_msensor_param[dev]->config);
#endif
g_msensor_init[dev] = XMEDIA_TRUE;
return ret;
}
static xmedia_s32 msensor_chip_drv_user_deinit(xmedia_s32 dev, xmedia_uintptr_t arg)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
if (g_msensor_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d msensor has not inited!\n", dev);
return XMEDIA_FAILURE;
}
if (g_msensor_start[dev] == XMEDIA_TRUE) {
MSENSOR_ERR_TRACE("dev %d please stop msensor first!\n", dev);
return XMEDIA_FAILURE;
}
xmedia_unused(arg);
g_msensor_init[dev] = XMEDIA_FALSE;
chip_dev_exit(dev, g_msensor_param[dev]);
#ifdef MNGBUFF_ENABLE
ret = msensor_chip_exit_mng_buf(dev);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d exit mng buf failed! ret=%x\n", dev, ret);
return ret;
}
#endif
return ret;
}
static xmedia_s32 msensor_chip_drv_user_get_param(xmedia_s32 dev, xmedia_uintptr_t arg)
{
xmedia_s32 ret;
ret = mmz_check_phyaddr(g_msensor_param[dev]->buf_attr.phys_addr, g_msensor_param[dev]->buf_attr.buf_len);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d check mem share failed, buf_attr.phys_addr is 0x%llx\n", dev,
g_msensor_param[dev]->buf_attr.phys_addr);
return ret;
}
osal_memcpy((xmedia_msensor_param *)arg, g_msensor_param[dev], sizeof(xmedia_msensor_param));
return XMEDIA_SUCCESS;
}
/* only for debug: send and save yuv */
static xmedia_s32 msensor_chip_drv_user_mng_init(xmedia_s32 dev, xmedia_uintptr_t arg)
{
xmedia_s32 ret;
xmedia_msensor_param *msensor_param = XMEDIA_NULL;
if (g_msensor_init[dev] == XMEDIA_TRUE) {
MSENSOR_ERR_TRACE("dev %d msensor is already inited!\n", dev);
return XMEDIA_FAILURE;
}
msensor_param = (xmedia_msensor_param *)(arg);
ret = mmz_check_phyaddr(msensor_param->buf_attr.phys_addr, msensor_param->buf_attr.buf_len);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d check mem share failed, buf_attr.phys_addr is 0x%llx\n",
dev, msensor_param->buf_attr.phys_addr);
return ret;
}
osal_memcpy(g_msensor_param[dev], (xmedia_void *)arg, sizeof(xmedia_msensor_param));
if (((XMEDIA_MSENSOR_DEVICE_GYRO & g_msensor_param[dev]->attr.device_mask) &&
(g_msensor_param[dev]->config.gyro_config.odr == 0)) ||
((XMEDIA_MSENSOR_DEVICE_ACC & g_msensor_param[dev]->attr.device_mask) &&
(g_msensor_param[dev]->config.acc_config.odr == 0))) {
MSENSOR_ERR_TRACE("dev %d msensor param error\n", dev);
return ret;
}
/* init senser */
ret = chip_dev_mng_init(dev, g_msensor_param[dev]);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d mng init failed! ret=%x\n", dev, ret);
return ret;
}
#ifdef MNGBUFF_ENABLE
/* buff init, fix in this */
msensor_chip_init_mng_buf(dev, g_msensor_param[dev]->attr, &g_msensor_param[dev]->buf_attr,
&g_msensor_param[dev]->config);
#endif
g_msensor_init[dev] = XMEDIA_TRUE;
return ret;
}
static xmedia_s32 msensor_chip_drv_start(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_chip_drv_user_start(dev, (xmedia_uintptr_t)arg);
}
static xmedia_s32 msensor_chip_drv_stop(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_chip_drv_user_stop(dev, (xmedia_uintptr_t)arg);
}
static xmedia_s32 msensor_chip_drv_init(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_chip_drv_user_init(dev, (xmedia_uintptr_t)arg);
}
static xmedia_s32 msensor_chip_drv_deinit(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_chip_drv_user_deinit(dev, (xmedia_uintptr_t)arg);
}
static xmedia_s32 msensor_chip_drv_get_param(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_chip_drv_user_get_param(dev, (xmedia_uintptr_t)arg);
}
/* only for debug: send and save yuv */
static xmedia_s32 msensor_chip_drv_mng_init(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_chip_drv_user_mng_init(dev, (xmedia_uintptr_t)arg);
}
typedef xmedia_s32 (*msensor_ctl_ptr_func)(xmedia_s32 dev, xmedia_ulong arg);
typedef struct {
xmedia_u32 cmd;
msensor_ctl_ptr_func ptr_func;
} msensor_ioctl_func_item;
static msensor_ioctl_func_item g_msensor_chip_cmd_list[] = {
{ MSENSOR_CMD_START, msensor_chip_drv_start },
{ MSENSOR_CMD_STOP, msensor_chip_drv_stop },
{ MSENSOR_CMD_CREATE, msensor_chip_drv_init },
{ MSENSOR_CMD_DESTROY, msensor_chip_drv_deinit },
{ MSENSOR_CMD_GET_PARAM, msensor_chip_drv_get_param },
{ MSENSOR_CMD_MNG_INIT, msensor_chip_drv_mng_init }, /* only for debug: send and save yuv */
};
static xmedia_s32 msensor_chip_do_ioctl(xmedia_s32 dev, xmedia_u32 cmd, xmedia_ulong arg)
{
xmedia_s32 i;
for (i = 0; i < sizeof(g_msensor_chip_cmd_list) / sizeof(g_msensor_chip_cmd_list[0]); i++) {
if (cmd == g_msensor_chip_cmd_list[i].cmd) {
return g_msensor_chip_cmd_list[i].ptr_func(dev, arg);
}
}
MSENSOR_ERR_TRACE("dev %d msensor chip ioctl cmd 0x%x not supported!\n", dev, cmd);
return XMEDIA_ERRCODE_NOT_SUPPORT;
}
xmedia_slong msensor_chip_ioctl(xmedia_u32 cmd, xmedia_ulong arg, xmedia_void *private_data)
{
xmedia_s32 ret;
xmedia_s32 dev;
if (cmd == MSENSOR_CMD_CHIP_BIND_FLAG2FD) {
*(xmedia_u32 *)private_data = *(xmedia_u32 *)arg;
return XMEDIA_SUCCESS;
}
dev = *(xmedia_u32 *)private_data;
osal_atomic_inc_return(&g_msensor_chip_user_ref[dev]);
ret = msensor_chip_do_ioctl(dev, cmd, arg);
osal_atomic_dec_return(&g_msensor_chip_user_ref[dev]);
return ret;
}
static struct osal_fileops g_msensor_chip_fileop = {
.open = msensor_chip_open,
.unlocked_ioctl = msensor_chip_ioctl,
.release = msensor_chip_release,
};
struct osal_pmops g_msensor_chip_drv_ops = {
.pm_freeze = msensor_chip_freeze,
.pm_restore = msensor_chip_restore,
};
static xmedia_s32 msensor_chip_param_init(xmedia_void)
{
xmedia_s32 i ,j;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
g_msensor_param[i] = (xmedia_msensor_param *)osal_kmalloc(sizeof(xmedia_msensor_param), osal_gfp_kernel);
if (g_msensor_param[i] == XMEDIA_NULL) {
osal_printk("kmalloc memory failed\n");
goto failed;
}
(xmedia_void) osal_memset(g_msensor_param[i], 0, sizeof(xmedia_msensor_param));
g_msensor_start[i] = XMEDIA_FALSE;
}
return XMEDIA_SUCCESS;
failed:
for (j = i - 1; j >= 0; j--) {
osal_kfree(g_msensor_param[j]);
}
return -ENOMEM;
}
static xmedia_s32 msensor_chip_param_exit(xmedia_void)
{
xmedia_s32 i;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
if(g_msensor_param[i] == XMEDIA_NULL) {
osal_printk("msensor_param is null, nothing to exit \n");
} else {
osal_kfree(g_msensor_param[i]);
g_msensor_param[i] = XMEDIA_NULL;
}
g_msensor_start[i] = XMEDIA_FALSE;
}
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_chip_sensor_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_s32 i , j;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
ret = chip_sensor_init(i);
if (ret != XMEDIA_SUCCESS) {
osal_printk("init sensor! failed ret=%x\n", ret);
goto failed;
}
}
return XMEDIA_SUCCESS;
failed:
for (j = i - 1; j >= 0; j--) {
chip_sensor_exit(j);
}
return ret;
}
static xmedia_void msensor_chip_sensor_exit(xmedia_void)
{
xmedia_s32 i;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
chip_sensor_exit(i);
}
return;
}
static xmedia_s32 msensor_chip_register_mng_callback_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_s32 i;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
ret = msensor_chip_register_mng_callback(i);
if (ret != XMEDIA_SUCCESS) {
osal_printk("register mng callback failed! ret=%x\n", ret);
return XMEDIA_FAILURE;
}
}
return XMEDIA_SUCCESS;
}
static xmedia_void msensor_chip_register_mng_callback_exit(xmedia_void)
{
xmedia_s32 i;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
msensor_chip_unregister_mng_callback(i);
}
return;
}
static xmedia_s32 msensor_chip_atomic_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_s32 i ,j;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
ret = osal_atomic_init(&g_msensor_chip_user_ref[i]);
if (ret != XMEDIA_SUCCESS) {
osal_printk("atomic init failed. \n");
goto failed;
}
osal_atomic_set(&g_msensor_chip_user_ref[i], 0);
}
return XMEDIA_SUCCESS;
failed:
for (j = i - 1; j >= 0; j--) {
osal_atomic_destory(&g_msensor_chip_user_ref[j]);
}
return ret;
}
static xmedia_void msensor_chip_atomic_exit(xmedia_void)
{
xmedia_s32 i;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
osal_atomic_destroy(&g_msensor_chip_user_ref[i]);
}
return;
}
xmedia_s32 msensor_chip_module_init(xmedia_void)
{
xmedia_s32 ret;
ret = msensor_chip_param_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("init param failed! ret=%x\n", ret);
goto FAIL0;
}
ret = msensor_chip_sensor_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("init sensor failed! ret=%x\n", ret);
goto FAIL1;
}
#ifdef MNGBUFF_ENABLE
ret = msensor_chip_register_mng_callback_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("init sensor failed! ret=%x\n", ret);
goto FAIL2;
}
#endif
ret = msensor_chip_atomic_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("init sensor failed! ret=%x\n", ret);
goto FAIL3;
}
g_msensor_chip_dev = osal_createdev(UMAP_DEVNANME_MSENSOR_CHIP_BASE);
if (g_msensor_chip_dev == XMEDIA_NULL) {
osal_printk("msensor: create device failed\n");
goto FAIL4;
}
g_msensor_chip_dev->fops = &g_msensor_chip_fileop;
g_msensor_chip_dev->minor = UMAP_MSENSOR_CHIP_MINOR_BASE;
g_msensor_chip_dev->osal_pmops = &g_msensor_chip_drv_ops;
ret = osal_registerdevice(g_msensor_chip_dev);
if (ret != XMEDIA_SUCCESS) {
osal_printk("register msensor device failed!\n");
goto FAIL5;
}
#if (defined CONFIG_PROC_SHOW_SUPPORT) && (defined ICM42670_PARAM_PROC)
ret = mpu_proc_init();
if (ret != XMEDIA_SUCCESS) {
goto FAIL6;
}
#endif
osal_printk("load xm_msensor_chip.ko OK!\n");
return XMEDIA_SUCCESS;
FAIL6:
osal_deregisterdevice(g_msensor_chip_dev);
FAIL5:
osal_destroydev(g_msensor_chip_dev);
FAIL4:
msensor_chip_atomic_exit();
FAIL3:
msensor_chip_register_mng_callback_exit();
FAIL2:
msensor_chip_sensor_exit();
FAIL1:
msensor_chip_param_exit();
FAIL0:
osal_printk("load xm_msensor_chip.ko failed !\n");
return XMEDIA_FAILURE;
}
xmedia_void msensor_chip_module_exit(xmedia_void)
{
msensor_chip_atomic_exit();
#ifdef MNGBUFF_ENABLE
msensor_chip_register_mng_callback_exit();
#endif
msensor_chip_sensor_exit();
msensor_chip_param_exit();
osal_deregisterdevice(g_msensor_chip_dev);
osal_destroydev(g_msensor_chip_dev);
#if (defined CONFIG_PROC_SHOW_SUPPORT)
mpu_proc_exit();
#endif
osal_printk("unload xm_msensor_chip.ko OK!\n");
}
#ifdef MODULE
module_init(msensor_chip_module_init);
module_exit(msensor_chip_module_exit);
MODULE_AUTHOR("otlicon");
MODULE_DESCRIPTION("motion_sensor driver");
MODULE_LICENSE("GPL");
#else
int __init msensor_chip_driver_init(void)
{
return msensor_chip_module_init();
}
#endif
@@ -0,0 +1,178 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_H__
#define __MSENSOR_H__
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include "xmedia_msensor.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#define MNGBUFF_ENABLE
#define DATA_RATE_RESERVED 0x00
#define DATA_RATE_25HZ 0x06
#define DATA_RATE_50HZ 0x07
#define DATA_RATE_100HZ 0x08
#define DATA_RATE_200HZ 0x09
#define DATA_RATE_400HZ 0x0A
#define DATA_RATE_800HZ 0x0B
#define DATA_RATE_1600HZ 0x0C
#define DATA_RATE_3200HZ 0x0D
#define GYRO_FULL_SCALE_RANGE_250DPS (250 << 10)
#define GYRO_FULL_SCALE_RANGE_500DPS (500 << 10)
#define GYRO_FULL_SCALE_RANGE_1KDPS (1000 << 10)
#define GYRO_FULL_SCALE_RANGE_2KDPS (2000 << 10)
#define GYRO_FULL_SCALE_RANGE_31DPS ((3125 << 10) / 100)
#define GYRO_FULL_SCALE_RANGE_62DPS ((625 << 10) / 10)
#define GYRO_FULL_SCALE_RANGE_125DPS (125 << 10)
#define ACCEL_UI_FULL_SCALE_RANGE_2G 1
#define ACCEL_UI_FULL_SCALE_RANGE_4G 2
#define ACCEL_UI_FULL_SCALE_RANGE_8G 3
#define ACCEL_UI_FULL_SCALE_RANGE_16G 4
#define ACCEL_OIS_FULL_SCALE_RANGE_1G 5
#define ACCEL_OIS_FULL_SCALE_RANGE_2G 6
#define ACCEL_OIS_FULL_SCALE_RANGE_4G 7
#define ACCEL_OIS_FULL_SCALE_RANGE_8G 8
#define MOTIONSENSOR_MAX_TEMP 85
#define MOTIONSENSOR_MIN_TEMP (-40)
typedef enum {
GYRO_OUTPUT_DATA_RATE_32KHZ = 32000,
GYRO_OUTPUT_DATA_RATE_8KHZ = 8000,
GYRO_OUTPUT_DATA_RATE_3200HZ = 3200,
GYRO_OUTPUT_DATA_RATE_1600HZ = 1600,
GYRO_OUTPUT_DATA_RATE_800HZ = 800,
GYRO_OUTPUT_DATA_RATE_400HZ = 400,
GYRO_OUTPUT_DATA_RATE_200HZ = 200,
GYRO_OUTPUT_DATA_RATE_100HZ = 100,
GYRO_OUTPUT_DATA_RATE_50HZ = 50,
GYRO_OUTPUT_DATA_RATE_25HZ = 25,
GYRO_OUTPUT_DATA_RATE_UNDER_1KHZ,
GYRO_OUTPUT_DATA_RATE_BUTT
} msensor_gyro_output_data_rate;
typedef enum {
GYRO_BAND_WIDTH_16HZ,
GYRO_BAND_WIDTH_25HZ,
GYRO_BAND_WIDTH_34HZ,
GYRO_BAND_WIDTH_53HZ,
GYRO_BAND_WIDTH_73HZ,
GYRO_BAND_WIDTH_121HZ,
GYRO_BAND_WIDTH_180HZ,
GYRO_BAND_WIDTH_BUTT
} msensor_gyro_band_width;
typedef enum {
ACCEL_OUTPUT_DATA_RATE_4KHZ = 4000,
ACCEL_OUTPUT_DATA_RATE_1KHZ = 1000,
ACCEL_OUTPUT_DATA_RATE_1600HZ = 1600,
ACCEL_OUTPUT_DATA_RATE_800HZ = 800,
ACCEL_OUTPUT_DATA_RATE_400HZ = 400,
ACCEL_OUTPUT_DATA_RATE_200HZ = 200,
ACCEL_OUTPUT_DATA_RATE_100HZ = 100,
ACCEL_OUTPUT_DATA_RATE_50HZ = 50,
ACCEL_OUTPUT_DATA_RATE_25HZ = 25,
ACCEL_OUTPUT_DATA_RATE_UNDER_1KHZ,
ACCEL_OUTPUT_DATA_RATE_BUTT
} msensor_accel_output_data_rate;
typedef enum {
GYRO_FULL_SCALE_SET_250DPS = 250 << 10, /* 250 dps */
GYRO_FULL_SCALE_SET_500DPS = 500 << 10, /* 500 dps */
GYRO_FULL_SCALE_SET_1KDPS = 1000 << 10, /* 1000 dps */
GYRO_FULL_SCALE_SET_2KDPS = 2000 << 10, /* 2000 dps */
GYRO_FULL_SCALE_SET_31DPS = (3125 << 10) / 100, /* 31.25 dps : 3125 / 100 */
GYRO_FULL_SCALE_SET_62DPS = (625 << 10) / 10, /* 62.5 dps : 625 / 10 */
GYRO_FULL_SCALE_SET_125DPS = 125 << 10, /* 125 dps */
GYRO_FULL_SCALE_SET_BUTT
} msensor_gyro_full_scale_range;
typedef enum {
ACCEL_UI_FULL_SCALE_SET_2G = 2 << 10,
ACCEL_UI_FULL_SCALE_SET_4G = 4 << 10,
ACCEL_UI_FULL_SCALE_SET_8G = 8 << 10,
ACCEL_UI_FULL_SCALE_SET_16G = 16 << 10,
ACCEL_UI_FULL_SCALE_SET_BUTT
} msensor_accel_ui_full_scale_range;
typedef enum {
ACCEL_OIS_FULL_SCALE_SET_1G = 1,
ACCEL_OIS_FULL_SCALE_SET_2G = 2,
ACCEL_OIS_FULL_SCALE_SET_4G = 4,
ACCEL_OIS_FULL_SCALE_SET_8G = 8,
ACCEL_OIS_FULL_SCALE_SET_BUTT
} msensor_accel_ois_full_scale_range;
typedef enum {
ACCEL_BAND_WIDTH_16HZ,
ACCEL_BAND_WIDTH_25HZ,
ACCEL_BAND_WIDTH_34HZ,
ACCEL_BAND_WIDTH_53HZ,
ACCEL_BAND_WIDTH_73HZ,
ACCEL_BAND_WIDTH_121HZ,
ACCEL_BAND_WIDTH_180HZ,
ACCEL_BAND_WIDTH_BUTT
} msensor_accel_band_width;
typedef enum {
TRIGER_TIMER = 0,
TRIGER_EXTERN_INTERRUPT,
TRIGER_BUTT
} msensor_triger_mode;
typedef struct {
xmedia_u32 interval; /* unit :us */
} timer_param;
typedef struct {
xmedia_u32 interrupt_num;
} extern_interrupt_param;
typedef union {
timer_param timer_config;
extern_interrupt_param extern_interrupt_config;
} msensor_triger_info;
typedef struct {
msensor_triger_mode triger_mode;
msensor_triger_info triger_info;
} triger_config;
typedef struct {
xmedia_u32 cmd;
xmedia_s32 (*func)(xmedia_uintptr_t arg);
} msensor_chip_info;
xmedia_msensor_param *msensor_chip_get_param(xmedia_s32 dev);
xmedia_bool msensor_chip_get_status(xmedia_s32 dev);
xmedia_s32 msensor_chip_int_callback(xmedia_s32 dev, xmedia_msensor_data *msensor_data);
#define print_info(fmt, arg...) osal_printk("fun:%s,%d " fmt, __func__, __LINE__, ##arg)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,113 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor_chip_proc.h"
#include <linux/kernel.h>
#include "osal.h"
#include "msensor.h"
#include "icm42670.h"
#define MSENSOR_CHIP_INFO "msensor_chip"
#define MSENSOR_CHIP_VERSION_INFO "msensor_chip debug 0.0.0.1"
static xmedia_char *msensor_triger_mode2_str(msensor_triger_mode mode)
{
switch (mode) {
case TRIGER_TIMER:
return "TIMER";
case TRIGER_EXTERN_INTERRUPT:
return "GPIO_INTERRUPT";
default:
return "error";
}
return "0";
}
static xmedia_void msensor_print_proc_title(osal_proc_entry_t *s, xmedia_char *title)
{
xmedia_s32 i;
for (i = 0; i < 50; i++) {
osal_seq_printf(s, "-");
}
osal_seq_printf(s, title);
for (i = 0; i < 50; i++) {
osal_seq_printf(s, "-");
}
osal_seq_printf(s, "\n");
}
static xmedia_s32 msensor_chip_proc_show(osal_proc_entry_t *s)
{
xmedia_s32 i;
xmedia_msensor_param *msensor_param = XMEDIA_NULL;
icm42670_dev_info *dev_info = XMEDIA_NULL;
osal_seq_printf(s,
"[msensor] version:[" MSENSOR_CHIP_VERSION_INFO "], build time["__DATE__
", "__TIME__
"]\n");
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
if(msensor_chip_get_status(i) == XMEDIA_FALSE) {
continue;
}
msensor_param = msensor_chip_get_param(i);
dev_info = chip_get_dev_info(i);
msensor_print_proc_title(s, "common parameter");
osal_seq_printf(s, "%24s %24s %24s\n", "dev_no", "trigle_mode", "fifo_en");
osal_seq_printf(s, "%24d %24s %24d\n", i, msensor_triger_mode2_str(dev_info->triger_data.triger_mode), dev_info->fifo_en);
if (msensor_param->attr.device_mask & XMEDIA_MSENSOR_DEVICE_GYRO) {
msensor_print_proc_title(s, "gyro parameter");
osal_seq_printf(s, "%24s\n", "##ICM42670##");
osal_seq_printf(s, "%24s %24s %24s %24s %24s\n", "sample_rate", "full-scale-range", "datawidth",
"max-chip-temperature", "min-chip-temperature");
osal_seq_printf(s, "%24d %24d %24d %24d %24d\n", msensor_param->config.gyro_config.odr,
msensor_param->config.gyro_config.fsr, msensor_param->config.gyro_config.data_width,
msensor_param->config.gyro_config.temperature_max,
msensor_param->config.gyro_config.temperature_min);
}
if (msensor_param->attr.device_mask & XMEDIA_MSENSOR_DEVICE_ACC) {
msensor_print_proc_title(s, "accelerometer parameter");
osal_seq_printf(s, "%24s\n", "##ICM42670##");
osal_seq_printf(s, "%24s %24s %24s %24s %24s\n", "sample_rate", "full-scale-range", "datawidth",
"max-chip-temperature", "min-chip-temperature");
osal_seq_printf(s, "%24d %24d %24d %24d %24d\n", msensor_param->config.acc_config.odr,
msensor_param->config.acc_config.fsr, msensor_param->config.acc_config.data_width,
msensor_param->config.acc_config.temperature_max,
msensor_param->config.acc_config.temperature_min);
}
}
return 0;
}
xmedia_s32 mpu_proc_init(xmedia_void)
{
osal_proc_entry_t *msensor_chip_entry = XMEDIA_NULL;
msensor_chip_entry = osal_create_proc_entry(MSENSOR_CHIP_INFO, XMEDIA_NULL);
if (msensor_chip_entry == XMEDIA_NULL) {
printk("osal_create_proc_entry failed!\n");
return XMEDIA_FAILURE;
}
msensor_chip_entry->read = msensor_chip_proc_show;
msensor_chip_entry->write = XMEDIA_NULL;
return XMEDIA_SUCCESS;
}
void mpu_proc_exit(xmedia_void)
{
osal_remove_proc_entry(MSENSOR_CHIP_INFO, 0);
return;
}
@@ -0,0 +1,28 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_CHIP_PROC_H__
#define __MSENSOR_CHIP_PROC_H__
#include "xmedia_type.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define MAX_LEN 32
xmedia_s32 mpu_proc_init(xmedia_void);
xmedia_void mpu_proc_exit(xmedia_void);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,162 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef ICM42670_H
#define ICM42670_H
#include "msensor.h"
#include "osal.h"
#include "linux/workqueue.h"
#include "linux/hrtimer.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#define ICM42670_DEV_ADDR 0x68
#define I2C_DEV_NUM 0x1
#define ICM42670_VALID_DATA_BIT 16
#define div_0_to_1(a) (((a) == 0) ? 1 : (a))
#define TRUE_REGISTER_VALUE 0x01
#define RESET_OFFSET 0x04
#define CLKSET_VALUE 0x01
// MREGs
#define MREG1 0
#define MREG2 1
#define MREG3 2
#define ICM42670_SELFID 0x67 // ICM42670 device id default value
#define ICM42670_FIFO_MAX_RECORD 140
#define ICM42670_FIFO_R_MAX_SIZE 1152
#define ROOMTEMP_OFFSET (25 * (0x1 << 10))
#define GRADIENT_TEMP (0x1 << 10)
#define TEMP_SENSITIVITY 128
/* icm42670 interrupt pin reg */
#define INT_GPIO_CHIP 4 //7
#define INT_GPIO_OFFSET 6 //2
#define TIME_RECORD_CNT 10
#define DATA_RECORD_CNT (TIME_RECORD_CNT)
typedef struct {
xmedia_msensor_gyro_config gyro_config;
xmedia_u32 band_width;
xmedia_u64 last_pts;
} msensor_gyro_status;
typedef struct {
xmedia_msensor_acc_config acc_config;
xmedia_u32 band_width;
xmedia_u64 last_pts;
} msensor_acc_status;
typedef struct {
xmedia_msensor_sample_data accel_cur_data;
xmedia_msensor_sample_data gyro_cur_data;
xmedia_msensor_sample_data magn_data;
struct i2c_client *client;
struct spi_device *xmedia_spi;
struct task_struct *read_data_task;
struct task_struct *get_data_kthread;
osal_work_struct_t work;
xmedia_u8 power_mode;
xmedia_u8 flag_acc_fifo_enabled;
xmedia_u8 flag_gyro_fifo_enabled;
xmedia_u8 flag_fifo_incomming;
xmedia_u8 *fifo_buf;
xmedia_u32 fifo_length;
xmedia_u8 record_num;
xmedia_u8 enable_kthread;
xmedia_u8 fifo_en;
triger_config triger_data;
struct hrtimer hrtimer;
xmedia_u8 thread_wakeup;
osal_semaphore_t g_sem;
msensor_acc_status acc_status;
msensor_gyro_status gyro_status;
xmedia_s32 temperature;
xmedia_s32 irq_num;
xmedia_s32 workqueue_call_times;
osal_wait_t wait_call_stop_working;
} icm42670_dev_info;
icm42670_dev_info *chip_get_dev_info(xmedia_s32 dev);
xmedia_s32 chip_fifo_data_reset(xmedia_s32 dev);
xmedia_s32 chip_get_triger_config(xmedia_s32 dev, triger_config *triger_data);
xmedia_s32 chip_dev_init(xmedia_s32 dev, xmedia_msensor_param *msensor_param);
xmedia_s32 chip_dev_mng_init(xmedia_s32 dev, xmedia_msensor_param *msensor_param);
xmedia_void chip_dev_exit(xmedia_s32 dev, xmedia_msensor_param *msensor_param);
xmedia_s32 chip_sensor_init(xmedia_s32 dev);
xmedia_void chip_sensor_exit(xmedia_s32 dev);
xmedia_s32 chip_timer_run(xmedia_s32 dev);
xmedia_s32 chip_interrupt_run(xmedia_s32 dev);
xmedia_s32 chip_timer_stop(xmedia_s32 dev);
xmedia_s32 chip_interrupt_stop(xmedia_s32 dev);
xmedia_s32 chip_get_data_for_one_frm(xmedia_s32 dev);
/*
* otp_pwr_down
* 0: to power up OTP for read/write operation.
* 1: to power down OTP to save power.
* This bit is automatically set to 1 when OTP copy operation is complete.
*/
#define OTP_CTRL7_OTP_PWR_DOWN_POS 0x01
#define OTP_CTRL7_OTP_PWR_DOWN_MASK (0x01 << OTP_CTRL7_OTP_PWR_DOWN_POS)
/* ---------------------------------------------------------------------------
* register MREG_FPGA
* ---------------------------------------------------------------------------*/
/* ---------------------------------------------------------------------------
* register ROM
* ---------------------------------------------------------------------------*/
#define ACCEL_DATA_SIZE 6
#define GYRO_DATA_SIZE 6
#define TEMP_DATA_SIZE 2
#define FIFO_HEADER_SIZE 1
#define FIFO_ACCEL_DATA_SIZE ACCEL_DATA_SIZE
#define FIFO_GYRO_DATA_SIZE GYRO_DATA_SIZE
#define FIFO_TEMP_DATA_SIZE 1
#define FIFO_TS_FSYNC_SIZE 2
#define FIFO_TEMP_HIGH_RES_SIZE 1
#define FIFO_ACCEL_GYRO_HIGH_RES_SIZE 3
/*
* Hysteresis high peak threshold (mg) added to the threshold after the initial threshold is met.
* Use type APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t to define highG peak hysteresis
* These types are defined in inv_imu_defs.h.
*/
#define HIGHG_PEAK_HYSTERESIS APEX_CONFIG5_HIGHG_PEAK_TH_HYST_156MG
/* Initial WOM threshold to be applied to IMU in mg */
#define WOM_THRESHOLD_INITIAL_MG 200
/*
* HighG frequencies
* Use type APEX_CONFIG1_DMP_ODR_t to define DMP frequency
* These types are defined in inv_imu_defs.h.
*
* \note The frequency modes to run the HighG are :
* APEX_CONFIG1_DMP_ODR_25Hz (Low Power mode),
* APEX_CONFIG1_DMP_ODR_50Hz (Performance mode)
*/
#define HIGHG_FREQUENCY_MODE APEX_CONFIG1_DMP_ODR_50Hz
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,188 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup Apex APEX
* @brief High-level functions to drive APEX features
* @{
*/
/** @file inv_imu_apex.h */
#ifndef _INV_IMU_APEX_H_
#define _INV_IMU_APEX_H_
#include "inv_imu_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
struct inv_imu_device;
/** IMU APEX inputs parameters definition */
typedef struct {
APEX_CONFIG3_PEDO_AMP_TH_t pedo_amp_th;
uint8_t pedo_step_cnt_th;
uint8_t pedo_step_det_th;
APEX_CONFIG4_PEDO_SB_TIMER_TH_t pedo_sb_timer_th;
APEX_CONFIG4_PEDO_HI_ENRGY_TH_t pedo_hi_enrgy_th;
APEX_CONFIG5_TILT_WAIT_TIME_t tilt_wait_time;
APEX_CONFIG2_DMP_POWER_SAVE_TIME_t power_save_time;
APEX_CONFIG0_DMP_POWER_SAVE_t power_save;
APEX_CONFIG9_SENSITIVITY_MODE_t sensitivity_mode;
APEX_CONFIG2_LOW_ENERGY_AMP_TH_t low_energy_amp_th;
APEX_CONFIG9_SMD_SENSITIVITY_t smd_sensitivity;
APEX_CONFIG9_FF_DEBOUNCE_DURATION_t ff_debounce_duration;
APEX_CONFIG12_FF_MAX_DURATION_t ff_max_duration_cm;
APEX_CONFIG12_FF_MIN_DURATION_t ff_min_duration_cm;
APEX_CONFIG10_LOWG_PEAK_TH_t lowg_peak_th;
APEX_CONFIG5_LOWG_PEAK_TH_HYST_t lowg_peak_hyst;
APEX_CONFIG10_LOWG_TIME_TH_SAMPLES_t lowg_samples_th;
APEX_CONFIG11_HIGHG_PEAK_TH_t highg_peak_th;
APEX_CONFIG5_HIGHG_PEAK_TH_HYST_t highg_peak_hyst;
APEX_CONFIG11_HIGHG_TIME_TH_SAMPLES_t highg_samples_th;
} inv_imu_apex_parameters_t;
/** APEX pedometer outputs */
typedef struct inv_imu_apex_step_activity {
/** Number of steps taken */
uint16_t step_cnt;
/** Walk/run cadence in number of samples.
* Format is u6.2. (at 50Hz and 2Hz walk frequency, if the cadency
* is 25 samples, the register will output 100).
*/
uint8_t step_cadence;
/** Detected activity.
* Unknown (0), Walk (1) or Run (2)
*/
uint8_t activity_class;
} inv_imu_apex_step_activity_t;
/** @brief Enable Free Fall.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_ff(struct inv_imu_device *s);
/** @brief Disable Free Fall.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_ff(struct inv_imu_device *s);
/** @brief Enable Significant Motion Detection.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
* @warning SMD requires to have the pedometer enabled to work.
*/
int inv_imu_apex_enable_smd(struct inv_imu_device *s);
/** @brief Disable Significant Motion Detection.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_smd(struct inv_imu_device *s);
/** @brief Fill the APEX parameters structure with all the default parameters for APEX algorithms.
* @param[in] s Pointer to device.
* @param[out] apex_inputs Default input parameters.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_init_parameters_struct(struct inv_imu_device * s,
inv_imu_apex_parameters_t *apex_inputs);
/** @brief Configures DMP parameters for APEX algorithms.
* @param[in] s Pointer to device.
* @param[in] apex_inputs The requested input parameters.
* @return 0 on success, negative value on error.
* @warning APEX inputs can't change on the fly, this should be called before enabling
* any APEX features.
* @warning This API can't be called twice within 10 ms.
*/
int inv_imu_apex_configure_parameters(struct inv_imu_device * s,
const inv_imu_apex_parameters_t *apex_inputs);
/** @brief Returns current DMP parameters for APEX algorithms.
* @param[in] s Pointer to device.
* @param[out] apex_params The current parameter, fetched from registers.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_get_parameters(struct inv_imu_device *s, inv_imu_apex_parameters_t *apex_params);
/** @brief Configure DMP Output Data Rate for APEX algorithms.
* @param[in] s Pointer to device.
* @param[in] frequency The requested frequency.
* @return 0 on success, negative value on error.
* @warning Accel frequency must be higher or equal to DMP frequency.
*/
int inv_imu_apex_set_frequency(struct inv_imu_device *s, const APEX_CONFIG1_DMP_ODR_t frequency);
/** @brief Enable APEX algorithm Pedometer.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_pedometer(struct inv_imu_device *s);
/** @brief Disable APEX algorithm Pedometer.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_pedometer(struct inv_imu_device *s);
/** @brief Enable APEX algorithm Tilt.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_enable_tilt(struct inv_imu_device *s);
/** @brief Disable APEX algorithm Tilt.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_disable_tilt(struct inv_imu_device *s);
/** @brief Retrieve APEX pedometer outputs and format them
* @param[in] s Pointer to device.
* @param[out] apex_activity Apex step and activity data value.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_get_data_activity(struct inv_imu_device * s,
inv_imu_apex_step_activity_t *apex_activity);
/** @brief Retrieve APEX free fall outputs and format them
* @param[in] s Pointer to device.
* @param[out] freefall_duration Free fall duration in number of sample.
* @return 0 on success, negative value on error.
*/
int inv_imu_apex_get_data_free_fall(struct inv_imu_device *s, uint16_t *freefall_duration);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_APEX_H_ */
/** @} */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,444 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2017 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup Driver Driver
* @brief High-level functions to drive the device
* @{
*/
/** @file inv_imu_driver.h */
#ifndef _INV_IMU_DRIVER_H_
#define _INV_IMU_DRIVER_H_
#include "inv_imu_defs.h"
#include "inv_imu_transport.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Max FSR values for accel */
#define ACCEL_CONFIG0_FS_SEL_MAX ACCEL_CONFIG0_FS_SEL_16g
/** Max FSR values for gyro */
#define GYRO_CONFIG0_FS_SEL_MAX GYRO_CONFIG0_FS_SEL_2000dps
/** Max user offset value for accel (mg) */
#define ACCEL_OFFUSER_MAX_MG 1000
/** Max user offset value for gyro (dps) */
#define GYRO_OFFUSER_MAX_DPS 64
/** Max buffer size mirrored from FIFO at polling time */
#define FIFO_MIRRORING_SIZE 16 * 258 // packet size * max_count = 4kB
/** Accel start-up time */
#define ACC_STARTUP_TIME_US 10000
/** Gyro start-up time */
#define GYR_STARTUP_TIME_US 70000
/** Sensor identifier for UI control function */
enum inv_imu_sensor {
INV_SENSOR_ACCEL, /**< Accelerometer */
INV_SENSOR_GYRO, /**< Gyroscope */
INV_SENSOR_FSYNC_EVENT, /**< FSYNC */
INV_SENSOR_TEMPERATURE, /**< Chip temperature */
INV_SENSOR_DMP_PEDOMETER_EVENT, /**< Pedometer: step detected */
INV_SENSOR_DMP_PEDOMETER_COUNT, /**< Pedometer: step counter */
INV_SENSOR_DMP_TILT, /**< Tilt */
INV_SENSOR_DMP_FF, /**< FreeFall */
INV_SENSOR_DMP_LOWG, /**< Low G */
INV_SENSOR_DMP_SMD, /**< Significant Motion Detection */
INV_SENSOR_MAX
};
/** Configure Fifo usage */
typedef enum {
INV_IMU_FIFO_DISABLED = 0, /**< Fifo is disabled and data source is sensors registers */
INV_IMU_FIFO_ENABLED = 1, /**< Fifo is used as data source */
} INV_IMU_FIFO_CONFIG_t;
/** Sensor event structure definition */
typedef struct {
xmedia_s32 sensor_mask;
xmedia_u16 timestamp_fsync;
xmedia_s16 accel[3];
xmedia_s16 gyro[3];
xmedia_s16 temperature;
xmedia_s8 accel_high_res[3];
xmedia_s8 gyro_high_res[3];
} inv_imu_sensor_event_t;
/** IMU driver states definition */
struct inv_imu_device {
/** Transport layer.
* @warning Must be the first one of struct inv_imu_device
*/
struct inv_imu_transport transport;
/** callback executed by:
* * inv_imu_get_data_from_fifo (if FIFO is used).
* * inv_imu_get_data_from_registers (if FIFO isn't used).
* May be NULL if above API are not used by application
*/
void (*sensor_event_cb)(xmedia_s32 dev, xmedia_u16 packet_count, xmedia_u16 idx, xmedia_u64 time_inter,
inv_imu_sensor_event_t *event);
xmedia_u8 fifo_data[FIFO_MIRRORING_SIZE]; /**< FIFO mirroring memory area */
xmedia_u8 dmp_is_on; /**< DMP started status */
xmedia_u8 endianness_data; /**< Data endianness configuration */
xmedia_u8 fifo_highres_enabled; /**< Highres mode configuration */
INV_IMU_FIFO_CONFIG_t fifo_is_used; /**< FIFO configuration */
xmedia_u64 gyro_start_time_us; /**< Gyro start time used to discard first samples */
xmedia_u64 accel_start_time_us; /**< Accel start time used to discard first samples */
};
/** Interrupt enum state for INT1, INT2, and IBI */
typedef enum {
INV_IMU_DISABLE = 0,
INV_IMU_ENABLE
} inv_imu_interrupt_value;
/** Interrupt definition */
typedef struct {
inv_imu_interrupt_value INV_UI_FSYNC;
inv_imu_interrupt_value INV_UI_DRDY;
inv_imu_interrupt_value INV_FIFO_THS;
inv_imu_interrupt_value INV_FIFO_FULL;
inv_imu_interrupt_value INV_SMD;
inv_imu_interrupt_value INV_WOM_X;
inv_imu_interrupt_value INV_WOM_Y;
inv_imu_interrupt_value INV_WOM_Z;
inv_imu_interrupt_value INV_FF;
inv_imu_interrupt_value INV_LOWG;
inv_imu_interrupt_value INV_STEP_DET;
inv_imu_interrupt_value INV_STEP_CNT_OVFL;
inv_imu_interrupt_value INV_TILT_DET;
} inv_imu_interrupt_parameter_t;
/** @brief Initializes device.
* @param[in] s Pointer to device.
* @param[in] serif Pointer on serial interface structure.
* @param[in] sensor_event_cb Callback executed when a new sensor event is available. *
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_init(xmedia_s32 dev, struct inv_imu_device *s, struct inv_imu_serif *serif,
void (*sensor_event_cb)(xmedia_s32 dev, xmedia_u16 packet_count, xmedia_u16 idx, xmedia_u64 time_inter,
inv_imu_sensor_event_t *event));
/** @brief Reset device by reloading OTPs.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_device_reset(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief return WHOAMI value.
* @param[in] s Pointer to device.
* @param[out] who_am_i WHOAMI for device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_who_am_i(xmedia_s32 dev, struct inv_imu_device *s, xmedia_u8 *who_am_i);
/** @brief Enable/put accel in low power mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_enable_accel_low_power_mode(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Enable/put accel in low noise mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_enable_accel_low_noise_mode(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Disable all 3 axes of accel.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_disable_accel(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Enable/put gyro in low noise mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_enable_gyro_low_noise_mode(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Disable all 3 axes of gyro.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_disable_gyro(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Enable fsync tagging functionality.
* * Enables fsync.
* * Enables timestamp to registers. Once fsync is enabled fsync counter is pushed to
* fifo instead of timestamp. So timestamp is made available in registers. Note that
* this increase power consumption.
* * Enables fsync related interrupt.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_enable_fsync(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Disable fsync tagging functionality.
* * Disables fsync.
* * Disables timestamp to registers. Once fsync is disabled timestamp is pushed to fifo
* instead of fsync counter. So in order to decrease power consumption, timestamp is no
* more available in registers.
* * Disables fsync related interrupt.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_disable_fsync(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Configure which interrupt source can trigger INT1.
* @param[in] s Pointer to device.
* @param[in] interrupt_to_configure Structure with the corresponding state to manage INT1.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_config_int1(xmedia_s32 dev, struct inv_imu_device *s, inv_imu_interrupt_parameter_t *interrupt_to_configure);
/** @brief Retrieve interrupts configuration.
* @param[in] s Pointer to device.
* @param[in] interrupt_to_configure Structure with the corresponding state to manage INT1.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_config_int1(xmedia_s32 dev, struct inv_imu_device *s, inv_imu_interrupt_parameter_t *interrupt_to_configure);
/** @brief Configure which interrupt source can trigger INT2.
* @param[in] s Pointer to device.
* @param[in] interrupt_to_configure Structure with the corresponding state to INT2.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_config_int2(xmedia_s32 dev, struct inv_imu_device *s, inv_imu_interrupt_parameter_t *interrupt_to_configure);
/** @brief Retrieve interrupts configuration.
* @param[in] s Pointer to device.
* @param[in] interrupt_to_configure Structure with the corresponding state to manage INT2.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_config_int2(xmedia_s32 dev, struct inv_imu_device *s, inv_imu_interrupt_parameter_t *interrupt_to_configure);
/** @brief Read all registers containing data (temperature, accelerometer and gyroscope).
* Then it calls sensor_event_cb function passed at init for each packet.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_data_from_registers(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Read all available packets from the FIFO.
* For each packet function builds a sensor event containing packet data
* and validity information. Then it calls sensor_event_cb funtion passed
* at init for each packet.
* @param[in] s Pointer to device.
* @return Number of valid packets read on success, negative value on error.
*/
xmedia_s32 inv_imu_get_data_from_fifo(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Converts ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enums to period expressed in us.
* @param[in] odr_bitfield An ACCEL_CONFIG0_ODR_t or GYRO_CONFIG0_ODR_t enum.
* @return The corresponding period expressed in us.
*/
xmedia_u32 inv_imu_convert_odr_bitfield_to_us(xmedia_s32 dev, xmedia_u32 odr_bitfield);
/** @brief Configure accel Output Data Rate.
* @param[in] s Pointer to device.
* @param[in] frequency The requested frequency.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_accel_frequency(xmedia_s32 dev, struct inv_imu_device *s, const ACCEL_CONFIG0_ODR_t frequency);
/** @brief Configure gyro Output Data Rate.
* @param[in] s Pointer to device.
* @param[in] frequency The requested frequency.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_gyro_frequency(xmedia_s32 dev, struct inv_imu_device *s, const GYRO_CONFIG0_ODR_t frequency);
/** @brief Set accel full scale range.
* @param[in] s Pointer to device.
* @param[in] accel_fsr_g Requested full scale range.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_accel_fsr(xmedia_s32 dev, struct inv_imu_device *s, ACCEL_CONFIG0_FS_SEL_t accel_fsr_g);
/** @brief Access accel full scale range.
* @param[in] s Pointer to device.
* @param[out] accel_fsr_g Current full scale range.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_accel_fsr(xmedia_s32 dev, struct inv_imu_device *s, ACCEL_CONFIG0_FS_SEL_t *accel_fsr_g);
/** @brief Set gyro full scale range.
* @param[in] s Pointer to device.
* @param[in] gyro_fsr_dps Requested full scale range.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_gyro_fsr(xmedia_s32 dev, struct inv_imu_device *s, GYRO_CONFIG0_FS_SEL_t gyro_fsr_dps);
/** @brief Access gyro full scale range.
* @param[in] s Pointer to device.
* @param[out] gyro_fsr_dps Current full scale range.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_gyro_fsr(xmedia_s32 dev, struct inv_imu_device *s, GYRO_CONFIG0_FS_SEL_t *gyro_fsr_dps);
/** @brief Set accel Low-Power averaging value.
* @param[in] s Pointer to device.
* @param[in] acc_avg Requested averaging value.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_accel_lp_avg(xmedia_s32 dev, struct inv_imu_device *s, ACCEL_CONFIG1_ACCEL_FILT_AVG_t acc_avg);
/** @brief Set accel Low-Noise bandwidth value.
* @param[in] s Pointer to device.
* @param[in] acc_bw Requested averaging value.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_accel_ln_bw(xmedia_s32 dev, struct inv_imu_device *s, ACCEL_CONFIG1_ACCEL_FILT_BW_t acc_bw);
/** @brief Set gyro Low-Noise bandwidth value.
* @param[in] s Pointer to device.
* @param[in] gyr_bw Requested averaging value.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_gyro_ln_bw(xmedia_s32 dev, struct inv_imu_device *s, GYRO_CONFIG1_GYRO_FILT_BW_t gyr_bw);
/** @brief Set timestamp resolution.
* @param[in] s Pointer to device.
* @param[in] timestamp_resol Requested timestamp resolution.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_timestamp_resolution(xmedia_s32 dev, struct inv_imu_device *s, const TMST_CONFIG1_RESOL_t timestamp_resol);
/** @brief Reset IMU fifo.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_reset_fifo(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Enable 20 bits raw acc and raw gyr data in fifo.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_enable_high_resolution_fifo(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Disable 20 bits raw acc and raw gyr data in fifo.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_disable_high_resolution_fifo(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Configure Fifo.
* @param[in] s Pointer to device.
* @param[in] fifo_config Fifo configuration method.
* Enabled: data are pushed to FIFO and FIFO THS interrupt is set.
* Disabled: data are not pused to FIFO and DRDY interrupt is set.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_configure_fifo(xmedia_s32 dev, struct inv_imu_device *s, INV_IMU_FIFO_CONFIG_t fifo_config);
/** @brief Get timestamp resolution
* @param[in] s Pointer to device.
* @return The timestamp resolution in us or 0 in case of error
*/
xmedia_u32 inv_imu_get_timestamp_resolution_us(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Enable Wake On Motion.
* @param[in] s Pointer to device.
* @param[in] wom_x_th Threshold value for the Wake on Motion Interrupt for X-axis accel.
* @param[in] wom_y_th Threshold value for the Wake on Motion Interrupt for Y-axis accel.
* @param[in] wom_z_th Threshold value for the Wake on Motion Interrupt for Z-axis accel.
* @param[in] wom_int Select which mode between AND/OR is used to generate interrupt.
* @param[in] wom_dur Select the number of overthreshold event to wait
* before generating interrupt.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_configure_wom(xmedia_s32 dev, struct inv_imu_device *s, const xmedia_u8 wom_x_th, const xmedia_u8 wom_y_th,
const xmedia_u8 wom_z_th, WOM_CONFIG_WOM_INT_MODE_t wom_int,
WOM_CONFIG_WOM_INT_DUR_t wom_dur);
/** @brief Enable Wake On Motion.
* WoM requests to have the accelerometer enabled to work.
* As a consequence Fifo water-mark interrupt is disabled to only trigger WoM interrupts.
* To have good performance, it's recommended to set accel ODR to 20ms
* and in Low Power Mode.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_enable_wom(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Disable Wake On Motion.
* Fifo water-mark interrupt is re-enabled when WoM is disabled.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_disable_wom(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Start DMP for APEX algorithms and selftest.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_start_dmp(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Reset DMP for APEX algorithms and selftest.
* @param[in] s Pointer to device.
* @param[in] sram_reset Reset mode for the SRAM.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_reset_dmp(xmedia_s32 dev, struct inv_imu_device *s, const APEX_CONFIG0_DMP_MEM_RESET_t sram_reset);
/** @brief Set the UI endianness and set the inv_device endianness field.
* @param[in] s Pointer to device.
* @param[in] endianness Endianness to be set.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_set_endianness(xmedia_s32 dev, struct inv_imu_device *s, INTF_CONFIG0_DATA_ENDIAN_t endianness);
/** @brief Read the UI endianness and set the inv_device endianness field.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_get_endianness(xmedia_s32 dev, struct inv_imu_device *s);
/** @brief Configure Fifo decimation.
* @param[in] s Pointer to device.
* @param[in] dec_factor Requested decimation factor value from 2 to 256.
* @return 0 on success, negative value on error.
*/
xmedia_s32 inv_imu_configure_fifo_data_rate(xmedia_s32 dev, struct inv_imu_device *s, FDR_CONFIG_FDR_SEL_t dec_factor);
/** @brief Return driver version x.y.z-suffix as a xmedia_char array
* @return driver version a xmedia_char array "x.y.z-suffix"
*/
const xmedia_char *inv_imu_get_version(void);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_DRIVER_H_ */
/** @} */
@@ -0,0 +1,119 @@
/*
* ________________________________________________________________________________________________________
* Copyright (c) 2015-2015 InvenSense Inc. All rights reserved.
*
* This software, related documentation and any modifications thereto (collectively "Software") is subject
* to InvenSense and its licensors' intellectual property rights under U.S. and international copyright
* and other intellectual property rights laws.
*
* InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software
* and any use, reproduction, disclosure or distribution of the Software without an express license agreement
* from InvenSense is strictly prohibited.
*
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS
* PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL
* INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THE SOFTWARE.
* ________________________________________________________________________________________________________
*/
/** @defgroup Transport Transport
* @brief Abstraction layer to access device's registers
* @{
*/
/** @file inv_imu_transport.h */
#ifndef _INV_IMU_TRANSPORT_H_
#define _INV_IMU_TRANSPORT_H_
#ifdef __cplusplus
extern "C" {
#endif
/* forward declaration */
struct inv_imu_device;
/** Available serial interface type. */
typedef enum {
UI_I2C, /**< Selects I2C interface. */
UI_SPI4, /**< Selects 4-wire SPI interface. */
UI_SPI3 /**< Selects 3-wire SPI interface. */
} SERIAL_IF_TYPE_t;
/** Serial interface definition */
struct inv_imu_serif {
void *context;
int (*read_reg)(xmedia_s32 dev, struct inv_imu_serif *serif, uint8_t reg, uint8_t *buf, uint32_t len);
int (*write_reg)(xmedia_s32 dev, struct inv_imu_serif *serif, uint8_t reg, const uint8_t *buf, uint32_t len);
uint32_t max_read;
uint32_t max_write;
SERIAL_IF_TYPE_t serif_type;
};
/** Transport interface definition. */
struct inv_imu_transport {
/** Serial interface object.
* @warning Must be the first object in this structure.
*/
struct inv_imu_serif serif;
/** Contains mirrored values of some IP registers. */
struct register_cache {
uint8_t pwr_mgmt0_reg;
uint8_t gyro_config0_reg;
uint8_t accel_config0_reg;
uint8_t tmst_config1_reg;
} register_cache;
/** Internal counter for MCLK requests. */
uint8_t need_mclk_cnt;
};
/** @brief Init cache variable.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_init_transport(int32_t dev, struct inv_imu_device *s);
/** @brief Reads data from a register on IMU.
* @param[in] s Pointer to device.
* @param[in] reg Register address to be read.
* @param[in] len Number of byte to be read.
* @param[out] buf Output data from the register.
* @return 0 on success, negative value on error.
*/
int inv_imu_read_reg(int32_t dev, struct inv_imu_device *s, uint32_t reg, uint32_t len, uint8_t *buf);
/** @brief Writes data to a register on IMU.
* @param[in] s Pointer to device.
* @param[in] reg Register address to be written.
* @param[in] len Number of byte to be written.
* @param[in] buf Input data to write.
* @return 0 on success, negative value on error.
*/
int inv_imu_write_reg(int32_t dev, struct inv_imu_device *s, uint32_t reg, uint32_t len, const uint8_t *buf);
/** @brief Enable MCLK.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_switch_on_mclk(int32_t dev, struct inv_imu_device *s);
/** @brief Disable MCLK.
* @param[in] s Pointer to device.
* @return 0 on success, negative value on error.
*/
int inv_imu_switch_off_mclk(int32_t dev, struct inv_imu_device *s);
#ifdef __cplusplus
}
#endif
#endif /* _INV_IMU_TRANSPORT_H_ */
/** @} */
@@ -0,0 +1,40 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor_gpio.h"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "icm42670.h"
xmedia_s32 gpio_init(xmedia_void)
{
xmedia_s32 ret;
ret = gpio_request(gpio_num(INT_GPIO_CHIP, INT_GPIO_OFFSET), "icm42670_irq");
if (ret != XMEDIA_SUCCESS) {
print_info("irq GPIO request failed: %d", ret);
return ret;
}
gpio_direction_input(gpio_num(INT_GPIO_CHIP, INT_GPIO_OFFSET));
return XMEDIA_SUCCESS;
}
xmedia_s32 gpio_deinit(xmedia_void)
{
gpio_free(gpio_num(INT_GPIO_CHIP, INT_GPIO_OFFSET));
return XMEDIA_SUCCESS;
}
@@ -0,0 +1,30 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_GPIO_H__
#define __MSENSOR_GPIO_H__
#include "xmedia_type.h"
#include <linux/gpio.h>
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#define gpio_num(gpio_chip_num, gpio_offset_num) ((gpio_chip_num) * 8 + (gpio_offset_num))
xmedia_s32 gpio_init(xmedia_void);
xmedia_s32 gpio_deinit(xmedia_void);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,88 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
/* include <liteos/i2c.h> */
#include "i2c_dev.h"
#include "linux/i2c.h"
#include "msensor.h"
struct i2c_client g_i2c_client_obj; /* i2c control struct */
#define SLAVE_ADDR 0x34 /* i2c dev addr */
#define SLAVE_REG_ADDR 0x300f /* i2c dev register */
/* client initial */
static xmedia_s32 i2c_client_init(struct i2c_client **xmedia_i2c_client)
{
xmedia_s32 ret;
/* struct i2c_client * i2c_client0 is &g_i2c_client_obj */
/* i2c_client0->addr is SLAVE_ADDR >> 1 */
xmedia_i2c_client->addr = ICM40690_DEV_ADDR;
ret = client_attach(*xmedia_i2c_client, 0);
if (ret != XMEDIA_SUCCESS) {
dprintf("fail to attach client!\n");
return -1;
}
return 0;
}
static xmedia_s32 sample_i2c_write(struct i2c_client *xmedia_i2c_client, xmedia_u8 reg_addr, const xmedia_u8 *reg_data,
xmedia_u32 cnt)
{
xmedia_s32 ret;
/* struct i2c_client * i2c_client0 is & g_i2c_client_obj */
xmedia_char buf[4] = { 0 }; /* 4 buf */
/* i2c_client_init */
buf[0] = reg_addr & 0xff;
osal_memcpy(&buf[1], reg_data, cnt);
/* buf[1] is (SLAVE_REG_ADDR >> 8) & 0xff */
/* buf[2] is 0x03 write value to i2c */
/* call I2C standard function drv to write */
ret = i2c_master_send(xmedia_i2c_client, &buf, cnt + 1);
return ret;
}
static xmedia_s32 sample_i2c_read(struct i2c_client *xmedia_i2c_client, xmedia_u8 reg_addr, xmedia_u8 *reg_data,
xmedia_u32 cnt)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
/* struct i2c_client *i2c_client0 is & g_i2c_client_obj */
struct i2c_rdwr_data rdwr;
struct i2c_msg msg[2]; /* 2 msg */
xmedia_u8 recvbuf[4]; /* 4 bytes */
(xmedia_void) osal_memset(recvbuf, 0x0, sizeof(recvbuf));
/* i2c_client_init */
msg[0].addr = xmedia_i2c_client->addr;
msg[0].flags = xmedia_i2c_client->flags & I2C_M_TEN;
msg[0].len = 1;
msg[0].buf = reg_addr;
msg[1].addr = xmedia_i2c_client->addr;
msg[1].flags = xmedia_i2c_client->flags & I2C_M_TEN;
msg[1].flags |= I2C_M_RD;
msg[1].len = cnt;
msg[1].buf = reg_data;
/* rdwr.msgs = &msg[0] */
rdwr.nmsgs = 2; /* 2 msg */
recvbuf[0] = SLAVE_REG_ADDR & 0xff;
recvbuf[1] = (SLAVE_REG_ADDR >> 8) & 0xff; /* 8 bits */
i2c_transfer(xmedia_i2c_client->adapter, msg, rdwr.nmsgs);
/* dprintf("val is 0x%x\n",recvbuf[0]) buf[0] save the value read from i2c dev */
return ret;
}
xmedia_u8 msensor_i2c_write(struct i2c_client *xmedia_i2c_client, xmedia_u8 reg_addr, const xmedia_u8 *reg_data,
xmedia_u32 cnt)
{
return sample_i2c_write(xmedia_i2c_client, reg_addr, reg_data, cnt);
}
xmedia_u8 msensor_i2c_read(struct i2c_client *xmedia_i2c_client, xmedia_u8 reg_addr, xmedia_u8 *reg_data,
xmedia_u32 cnt)
{
return sample_i2c_read(xmedia_i2c_client, reg_addr, reg_data, cnt);
}
@@ -0,0 +1,34 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __I2C_DEV_H__
#define __I2C_DEV_H__
#include <linux/i2c.h>
#include "xmedia_type.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
xmedia_u8 msensor_i2c_write(struct i2c_client *xmedia_i2c_client,
xmedia_u8 reg_addr, const xmedia_u8 *reg_data,xmedia_u32 cnt);
xmedia_u8 msensor_i2c_read(struct i2c_client *xmedia_i2c_client,
xmedia_u8 reg_addr, xmedia_u8 *reg_data, xmedia_u32 cnt);
xmedia_u32 msensor_i2c_get_frequency(struct i2c_client *xmedia_i2c_client, xmedia_s32 *frequency);
xmedia_u32 msensor_i2c_init(struct i2c_client **xmedia_i2c_client,
struct i2c_board_info xmedia_i2c_board_info, xmedia_s32 adapt_num);
xmedia_void msensor_i2c_exit(struct i2c_client **xmedia_i2c_client);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,195 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "spi_dev.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/spinlock.h>
#include "common.h"
#include "msensor.h"
#define REG_WIDTH 1
static xmedia_u32 g_csn = 0;
static spinlock_t g_lock_rd;
static xmedia_u32 g_bus_num = 1;
module_param(g_bus_num, uint, S_IRUGO);
MODULE_PARM_DESC(g_bus_num, "spi bus number");
module_param(g_csn, uint, S_IRUGO);
MODULE_PARM_DESC(g_csn, "chip select number");
struct spi_master *g_xmedia_master;
static xmedia_s32 ssp_func_write(struct spi_device *xmedia_spi, xmedia_u8 addr, const xmedia_u8 *data, xmedia_u32 cnt)
{
struct spi_master *master = g_xmedia_master;
static struct spi_transfer t;
static struct spi_message msg;
static xmedia_u8 buf[4] = { 0 }; /* 4 byte buf */
xmedia_s16 ret;
xmedia_ulong flags;
if (xmedia_spi == XMEDIA_NULL) {
return -ENODEV;
}
xmedia_unused(cnt);
/* check spi_message is or no finish */
spin_lock_irqsave(&master->queue_lock, flags);
if (msg.state != XMEDIA_NULL) {
MSENSOR_ERR_TRACE("msg.state not null!!\n");
return -EFAULT;
}
spin_unlock_irqrestore(&master->queue_lock, flags);
buf[0] = addr;
buf[0] &= (~0x80);
buf[1] = *data;
t.tx_buf = buf;
t.len = 2; /* length 2 */
spi_message_init(&msg);
spi_message_add_tail(&t, &msg);
msg.state = &msg;
ret = spi_sync(xmedia_spi, &msg);
if (ret != 0) {
MSENSOR_ERR_TRACE(" spi_async() error(%d)!\n", ret);
return -EAGAIN;
}
return ret;
}
static xmedia_s32 ssp_func_read(struct spi_device *xmedia_spi, xmedia_u8 addr, xmedia_u8 *data, xmedia_u32 cnt)
{
struct spi_master *master = g_xmedia_master;
static struct spi_transfer t;
static struct spi_message msg;
static xmedia_u8 buf[4] = { 0 }; /* 4 byte buf */
xmedia_s16 ret;
xmedia_ulong flags;
static xmedia_u8 body[1024] = { 0 }; /* 1024 byte buf */
if (xmedia_spi == XMEDIA_NULL) {
return -ENODEV;
}
/* check spi_message is or no finish */
spin_lock_irqsave(&master->queue_lock, flags);
if (msg.state != XMEDIA_NULL) {
MSENSOR_ERR_TRACE("msg.state not null!!(%x)\n", addr);
spin_unlock_irqrestore(&master->queue_lock, flags);
return -EFAULT;
}
spin_unlock_irqrestore(&master->queue_lock, flags);
buf[0] = addr;
buf[0] |= 0x80;
buf[1] = 0;
t.tx_buf = buf;
t.rx_buf = body;
t.len = cnt + 1;
spi_message_init(&msg);
spi_message_add_tail(&t, &msg);
msg.state = &msg;
ret = spi_sync(xmedia_spi, &msg);
if (ret != 0) {
MSENSOR_ERR_TRACE(" spi_async() error(%d)!\n", ret);
return -EAGAIN;
}
osal_memcpy(data, body + 1, cnt);
return ret;
}
xmedia_s32 msensor_spi_write(struct spi_device *xmedia_spi, xmedia_u8 addr, const xmedia_u8 *data, xmedia_u32 cnt)
{
return ssp_func_write(xmedia_spi, addr, data, cnt);
}
xmedia_s32 msensor_spi_read(struct spi_device *xmedia_spi, xmedia_u8 addr, xmedia_u8 *data, xmedia_u32 cnt)
{
xmedia_s16 ret;
ret = ssp_func_read(xmedia_spi, addr, data, cnt);
return ret;
}
xmedia_s32 msensor_spi_init(struct spi_device **xmedia_spi)
{
xmedia_s32 status = XMEDIA_SUCCESS;
struct device *d = XMEDIA_NULL;
xmedia_char *spi_name = XMEDIA_NULL;
xmedia_s32 spi_name_len;
g_xmedia_master = spi_busnum_to_master(g_bus_num);
if (g_xmedia_master == XMEDIA_NULL) {
status = -ENXIO;
goto err0;
}
spi_name_len = strlen(dev_name(&g_xmedia_master->dev)) + 10; /* extend 10 */
spi_name = osal_kmalloc(spi_name_len, osal_gfp_kernel);
if (spi_name == XMEDIA_NULL) {
status = -ENOMEM;
goto err0;
}
(xmedia_void) osal_memset(spi_name, 0, spi_name_len);
if (osal_sprintf(spi_name, "%s.%u", dev_name(&g_xmedia_master->dev), g_csn) == XMEDIA_FAILURE) {
status = XMEDIA_FAILURE;
goto err1;
}
d = bus_find_device_by_name(&spi_bus_type, XMEDIA_NULL, spi_name);
if (d == XMEDIA_NULL) {
status = -ENXIO;
goto err1;
}
*xmedia_spi = to_spi_device(d);
if (*xmedia_spi == XMEDIA_NULL) {
status = -ENXIO;
goto err2;
}
spin_lock_init(&g_lock_rd);
err2:
put_device(d);
err1:
if (spi_name != XMEDIA_NULL) {
osal_kfree(spi_name);
spi_name = XMEDIA_NULL;
}
err0:
return status;
}
xmedia_s32 msensor_spi_deinit(const struct spi_device *spi_device)
{
xmedia_unused(spi_device);
return XMEDIA_SUCCESS;
}
@@ -0,0 +1,37 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __SPI_DEV_H__
#define __SPI_DEV_H__
#include "xmedia_type.h"
#include "osal.h"
#include "xmedia_debug.h"
#include <linux/spi/spi.h>
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
xmedia_s32 msensor_spi_write(struct spi_device *xmedia_spi, xmedia_u8 addr, const xmedia_u8 *data, xmedia_u32 cnt);
xmedia_s32 msensor_spi_read(struct spi_device *xmedia_spi, xmedia_u8 addr, xmedia_u8 *data, xmedia_u32 cnt);
xmedia_s32 msensor_spi_init(struct spi_device **xmedia_spi);
xmedia_s32 msensor_spi_deinit(const struct spi_device *spi_device);
#ifndef MSENSOR_ERR_TRACE
#define MSENSOR_ERR_TRACE(fmt, ...) \
printk(KERN_ERR "[Func]:%s [Line]:%d [Info]:" fmt, __FUNCTION__, __LINE__, \
##__VA_ARGS__)
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,29 @@
ifneq ($(srctree),)
KERNEL_DIR := $(srctree)
SDK_DIR := $(shell cd $(KERNEL_DIR)/../../.. && /bin/pwd)
else
SDK_DIR := $(shell cd $(CURDIR)/../../../../../.. && /bin/pwd)
endif
include $(SDK_DIR)/build/base.mk
MOD_NAME := xm_msensor_mng
SRCS = ./src/msensor_exe.c
SRCS += ./src/msensor_buf.c
SRCS += ./src/msensor_mng_proc.c
SDK_KER_CFLAGS += -I$(GMP_DIR)/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/usr/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/osal/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/msensor_mng/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/ext/msensor/ext_inc
#SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/msensor/msensor_chip/main/
SDK_KER_CFLAGS += -DCONFIG_PROC_SHOW_SUPPORT
include $(SDK_DIR)/build/sdk_ko_rules.mk
@@ -0,0 +1,76 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_BUF_H__
#define __MSENSOR_BUF_H__
#include "msensor_ext.h"
#include "osal.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#define BUF_BLOCK_NUM 6
#define MAX_USER_NUM 10
/*
* min msensor gap between reader pointer and write pointer,
* to prevent new data overlap with reading/processing data
*/
#define WR_GAP 100
typedef struct {
xmedia_void *start_addr; /* start address */
xmedia_void *write_ptr; /* write pointer */
} msensor_buf_info;
typedef enum {
DATA_X,
DATA_Y,
DATA_Z,
DATA_TEMP,
DATA_PTS,
DATA_BUTT
} msensor_buf_data_type;
typedef struct {
xmedia_void *read_ptr[XMEDIA_MSENSOR_DATA_TYPE_MAX][DATA_BUTT];
xmedia_s32 reverd3[4]; /* array 4 */
} msensor_buf_user_context;
typedef struct {
xmedia_u32 user_cnt;
osal_spinlock_t mng_lock;
osal_spinlock_t read_lock[MAX_USER_NUM];
msensor_buf_user_context *user_ctx[MAX_USER_NUM];
osal_mutex_t mng_mutex;
} msensor_buf_user_mng;
msensor_buf_info **msensor_buf_get_info(xmedia_s32 dev);
osal_spinlock_t *msensor_buf_get_lock(xmedia_s32 dev);
xmedia_s32 msensor_buf_lock_init(xmedia_void);
xmedia_void msensor_buf_lock_exit(xmedia_void);
xmedia_s32 msensor_buf_init(xmedia_s32 dev, const xmedia_msensor_buf_attr *buf_attr,
xmedia_u32 gyro_freq, xmedia_u32 accel_freq, xmedia_u32 mag_freq);
xmedia_s32 msensor_buf_exit(xmedia_s32 dev);
xmedia_s32 msensor_buf_write_data(xmedia_s32 dev, xmedia_msensor_data_type data_type,
const xmedia_msensor_sample_data *sample_data);
xmedia_s32 msensor_buf_get_data(xmedia_s32 dev, xmedia_msensor_data_info *msensor_data);
xmedia_s32 msensor_buf_release_data(xmedia_s32 dev, xmedia_msensor_data_info *msensor_data_info);
xmedia_s32 msensor_buf_add_user(xmedia_s32 dev, xmedia_s32 *id);
xmedia_s32 msensor_buf_delete_user(xmedia_s32 dev, const xmedia_s32 *id);
xmedia_bool msensor_buf_get_status(xmedia_s32 dev);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,80 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_EXE_H__
#define __MSENSOR_EXE_H__
#include "xmedia_debug.h"
#include "xmedia_type.h"
#include "xmedia_msensor.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
/* name MAG INTERFACE */
#define C_BMI160_BYTE_COUNT 2
#define BMI160_SLEEP_STATE 0x00
#define BMI160_WAKEUP_INTR 0x00
#define BMI160_SLEEP_TRIGGER 0x04
#define BMI160_WAKEUP_TRIGGER 0x02
#define BMI160_ENABLE_FIFO_WM 0x02
#define BMI160_MAG_INTERFACE_OFF_PRIMARY_ON 0x00
#define BMI160_MAG_INTERFACE_ON_PRIMARY_ON 0x02
#define BMI160_MODE_SWITCHING_DELAY 30
#define msensor_return_if_null_ptr(ptr) \
do { \
if ((ptr) == XMEDIA_NULL) { \
printk("input null ptr\n"); \
return XMEDIA_FAILURE; \
} \
} while (0)
typedef struct {
xmedia_u32 cmd;
xmedia_s32 (*func)(xmedia_uintptr_t arg);
} msensor_mng_info;
/* for msensor_mng proc */
#define MNG_MAX_LEN 10
typedef struct {
xmedia_char gyro_name[MNG_MAX_LEN];
xmedia_char accel_name[MNG_MAX_LEN];
xmedia_char mag_name[MNG_MAX_LEN];
xmedia_u64 buf_addr[XMEDIA_MSENSOR_DATA_TYPE_MAX];
xmedia_u32 buf_size[XMEDIA_MSENSOR_DATA_TYPE_MAX];
xmedia_u32 buf_overflow[XMEDIA_MSENSOR_DATA_TYPE_MAX];
xmedia_u32 buf_data_unmatch[XMEDIA_MSENSOR_DATA_TYPE_MAX];
xmedia_s32 buf_overflow_id[XMEDIA_MSENSOR_DATA_TYPE_MAX];
xmedia_s32 buf_data_unmatch_id[XMEDIA_MSENSOR_DATA_TYPE_MAX];
} msensor_mng_proc_info;
msensor_mng_proc_info *msensor_mng_get_proc_info(xmedia_s32 dev);
xmedia_s32 msensor_mng_proc_info_init(xmedia_s32 dev);
xmedia_s32 msensor_mng_buf_init(xmedia_s32 dev,
const xmedia_msensor_attr *motion_attr,
const xmedia_msensor_buf_attr *msensor_buf_attr,
const xmedia_msensor_config *msensor_config);
xmedia_s32 msensor_mng_buf_exit(xmedia_s32 dev);
xmedia_s32 msensor_mng_write_data_to_buf(xmedia_s32 dev, xmedia_msensor_data *msensor_data);
xmedia_s32 msensor_mng_write_data_2_buf(xmedia_s32 dev);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,42 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_MNG_IOCTL_H__
#define __MSENSOR_MNG_IOCTL_H__
#include "xmedia_msensor.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* end of #ifdef __cplusplus */
#define MSENSOR_TYPE_MNG 10
typedef enum {
IOC_NR_MSENSOR_MNG_FLAG2FD,
IOC_NR_MSENSOR_MNG_GET_DATA,
IOC_NR_MSENSOR_MNG_RELEASE_BUF,
IOC_NR_MSENSOR_MNG_ADD_USER,
IOC_NR_MSENSOR_MNG_DELETE_USER,
IOC_NR_MSENSOR_MNG_SEND_DATA,
IOC_NR_MSENSOR_MNG_BUTT
} ioc_nr_msensor_mng;
#define MSENSOR_CMD_MNG_BIND_FLAG2FD _IOW(MSENSOR_TYPE_MNG, IOC_NR_MSENSOR_MNG_FLAG2FD, xmedia_u32)
#define MSENSOR_CMD_GET_DATA _IOWR(MSENSOR_TYPE_MNG, IOC_NR_MSENSOR_MNG_GET_DATA, xmedia_msensor_data_info)
#define MSENSOR_CMD_RELEASE_BUF _IOWR(MSENSOR_TYPE_MNG, IOC_NR_MSENSOR_MNG_RELEASE_BUF, xmedia_msensor_data_info)
#define MSENSOR_CMD_ADD_USER _IOWR(MSENSOR_TYPE_MNG, IOC_NR_MSENSOR_MNG_ADD_USER, xmedia_s32)
#define MSENSOR_CMD_DELETE_USER _IOWR(MSENSOR_TYPE_MNG, IOC_NR_MSENSOR_MNG_DELETE_USER, xmedia_s32)
#define MSENSOR_CMD_SEND_DATA _IOW(MSENSOR_TYPE_MNG, IOC_NR_MSENSOR_MNG_SEND_DATA, xmedia_msensor_data)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,26 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_MNG_PROC__
#define __MSENSOR_MNG_PROC__
#include "msensor_ext.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
int msensor_proc_init(xmedia_void);
void msensor_proc_exit(xmedia_void);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif
@@ -0,0 +1,832 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor_buf.h"
#include <linux/kernel.h>
#include "msensor_exe.h"
#include "osal.h"
static xmedia_bool g_forward[XMEDIA_MSENSOR_MAX_DEV_NUM] = { XMEDIA_TRUE };
static xmedia_bool g_buf_init[XMEDIA_MSENSOR_MAX_DEV_NUM] = { XMEDIA_FALSE };
msensor_buf_info g_buf_info[XMEDIA_MSENSOR_MAX_DEV_NUM][XMEDIA_MSENSOR_DATA_TYPE_MAX][DATA_BUTT];
static xmedia_s64 g_offset[XMEDIA_MSENSOR_MAX_DEV_NUM] = { 0 };
xmedia_bool g_already_released[XMEDIA_MSENSOR_MAX_DEV_NUM][MAX_USER_NUM] = { XMEDIA_FALSE };
msensor_buf_user_mng g_user_mng[XMEDIA_MSENSOR_MAX_DEV_NUM];
static unsigned long g_msensor_buf_len[XMEDIA_MSENSOR_MAX_DEV_NUM] = { 0 };
#define DATA_RESERVE_NUM 50
#define xmedia_align(x, a) ((a) * (((x) + (a) - 1) / (a)))
#define x_start_addr(dev, data_type) g_buf_info[dev][data_type][DATA_X].start_addr
#define y_start_addr(dev, data_type) g_buf_info[dev][data_type][DATA_Y].start_addr
#define z_start_addr(dev, data_type) g_buf_info[dev][data_type][DATA_Z].start_addr
#define temp_start_addr(dev, data_type) g_buf_info[dev][data_type][DATA_TEMP].start_addr
#define pts_start_addr(dev, data_type) g_buf_info[dev][data_type][DATA_PTS].start_addr
#define x_write_ptr(dev, data_type) g_buf_info[dev][data_type][DATA_X].write_ptr
#define y_write_ptr(dev, data_type) g_buf_info[dev][data_type][DATA_Y].write_ptr
#define z_write_ptr(dev, data_type) g_buf_info[dev][data_type][DATA_Z].write_ptr
#define temp_write_ptr(dev, data_type) g_buf_info[dev][data_type][DATA_TEMP].write_ptr
#define pts_write_ptr(dev, data_type) g_buf_info[dev][data_type][DATA_PTS].write_ptr
#define x_read_ptr(dev, i, data_type) g_user_mng[dev].user_ctx[i]->read_ptr[data_type][DATA_X]
#define y_read_ptr(dev, i, data_type) g_user_mng[dev].user_ctx[i]->read_ptr[data_type][DATA_Y]
#define z_read_ptr(dev, i, data_type) g_user_mng[dev].user_ctx[i]->read_ptr[data_type][DATA_Z]
#define temp_read_ptr(dev, i, data_type) g_user_mng[dev].user_ctx[i]->read_ptr[data_type][DATA_TEMP]
#define pts_read_ptr(dev, i, data_type) g_user_mng[dev].user_ctx[i]->read_ptr[data_type][DATA_PTS]
msensor_buf_info **msensor_buf_get_info(xmedia_s32 dev)
{
return (msensor_buf_info **)g_buf_info[dev];
}
xmedia_bool msensor_buf_get_status(xmedia_s32 dev)
{
return g_buf_init[dev];
}
osal_spinlock_t *msensor_buf_get_lock(xmedia_s32 dev)
{
return &g_user_mng[dev].mng_lock;
}
static xmedia_s32 msensor_buf_get_user_id(xmedia_s32 dev, xmedia_s32 *id)
{
xmedia_s32 i;
for (i = 0; i < MAX_USER_NUM; i++) {
if (g_user_mng[dev].user_ctx[i] == XMEDIA_NULL) {
*id = i;
return XMEDIA_SUCCESS;
}
}
MSENSOR_ERR_TRACE("dev %d no id for user.\n", dev);
return XMEDIA_FAILURE;
}
static xmedia_s32 msensor_buf_add_user_create_ctx(xmedia_s32 dev, const xmedia_s32 *id)
{
xmedia_s32 i;
xmedia_s32 j;
xmedia_ulong flags;
msensor_buf_user_context *user_ctx = XMEDIA_NULL;
msensor_mng_proc_info *proc_info = XMEDIA_NULL;
proc_info = msensor_mng_get_proc_info(dev);
user_ctx = (msensor_buf_user_context *)osal_vmalloc(sizeof(msensor_buf_user_context));
if (user_ctx == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d osal_vmalloc failed.\n", dev);
return XMEDIA_FAILURE;
}
(xmedia_void) osal_memset(user_ctx, 0, sizeof(msensor_buf_user_context));
osal_spin_lock_irqsave(&g_user_mng[dev].read_lock[*id], &flags);
for (i = 0; i < DATA_BUTT; i++) {
if (i == DATA_PTS) {
for (j = 0; j < XMEDIA_MSENSOR_DATA_TYPE_MAX; j++) {
user_ctx->read_ptr[j][i] = (proc_info->buf_size[j] > DATA_RESERVE_NUM * BUF_BLOCK_NUM)
? (xmedia_u64 *)g_buf_info[dev][j][i].write_ptr
: g_buf_info[dev][j][i].write_ptr;
}
} else {
for (j = 0; j < XMEDIA_MSENSOR_DATA_TYPE_MAX; j++) {
user_ctx->read_ptr[j][i] = (int *)g_buf_info[dev][j][i].write_ptr;
}
}
}
g_forward[dev] = XMEDIA_TRUE;
g_user_mng[dev].user_ctx[*id] = user_ctx;
g_user_mng[dev].user_cnt++;
osal_spin_unlock_irqrestore(&g_user_mng[dev].read_lock[*id], &flags);
return XMEDIA_SUCCESS;
}
xmedia_s32 msensor_buf_add_user(xmedia_s32 dev, xmedia_s32 *id)
{
xmedia_s32 ret;
if (id == NULL) {
MSENSOR_ERR_TRACE("dev %d msensor id is null.\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
if (g_buf_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d buf not init, g_buf_init:%d\n", dev, g_buf_init[dev]);
return XMEDIA_FAILURE;
}
osal_mutex_lock(&g_user_mng[dev].mng_mutex);
/* step 1: get available ID */
if (g_user_mng[dev].user_cnt > MAX_USER_NUM) {
MSENSOR_ERR_TRACE("dev %d msensor id has reached toplimit.\n", dev);
goto err0;
}
/* get user id for use */
ret = msensor_buf_get_user_id(dev, id);
if (ret != XMEDIA_SUCCESS) {
*id = -1;
MSENSOR_ERR_TRACE("dev %d get_user_id failed.\n", dev);
goto err0;
}
if ((*id < 0) || (*id >= MAX_USER_NUM)) {
MSENSOR_ERR_TRACE("dev %d id(%d) out of range[0,%d].\n", dev, *id, MAX_USER_NUM);
goto err0;
}
/* step 2: create context for new ID */
ret = msensor_buf_add_user_create_ctx(dev, id);
if (ret != XMEDIA_SUCCESS) {
goto err0;
}
osal_mutex_unlock(&g_user_mng[dev].mng_mutex);
osal_msleep(200); /* 200ms */
return XMEDIA_SUCCESS;
err0:
osal_mutex_unlock(&g_user_mng[dev].mng_mutex);
return XMEDIA_FAILURE;
}
xmedia_s32 msensor_buf_delete_user(xmedia_s32 dev, const xmedia_s32 *id)
{
msensor_buf_user_context *msenser_buf_user_contex_temp = XMEDIA_NULL;
xmedia_ulong flags;
if (id == NULL) {
MSENSOR_ERR_TRACE("dev %d msensor id is null.\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
if ((*id < 0) || (*id >= MAX_USER_NUM)) {
MSENSOR_ERR_TRACE("dev %d id(%d) out of range[0,%d].\n", dev, *id, MAX_USER_NUM);
return XMEDIA_FAILURE;
}
if (g_buf_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d msensor buffer not inited.\n", dev);
return XMEDIA_FAILURE;
}
if (g_user_mng[dev].user_ctx[*id] == XMEDIA_NULL) {
msensor_debug_trace("dev %d id is null.\n", dev);
return XMEDIA_SUCCESS;
}
osal_mutex_lock(&g_user_mng[dev].mng_mutex);
osal_spin_lock_irqsave(&g_user_mng[dev].mng_lock, &flags);
/* release context */
msenser_buf_user_contex_temp = g_user_mng[dev].user_ctx[*id];
g_user_mng[dev].user_ctx[*id] = XMEDIA_NULL;
g_user_mng[dev].user_cnt--;
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
osal_mutex_unlock(&g_user_mng[dev].mng_mutex);
if (msenser_buf_user_contex_temp != XMEDIA_NULL) {
osal_vfree(msenser_buf_user_contex_temp);
msenser_buf_user_contex_temp = XMEDIA_NULL;
}
return XMEDIA_SUCCESS;
}
static xmedia_void msensor_buf_init_proc(xmedia_s32 dev, const xmedia_u32 *gyro_block_size,
const xmedia_u32 *acc_block_size, const xmedia_u32 *mag_block_size)
{
msensor_mng_proc_info *proc_info = XMEDIA_NULL;
proc_info = msensor_mng_get_proc_info(dev);
proc_info->buf_addr[XMEDIA_MSENSOR_DATA_TYPE_GYRO] =
(xmedia_u64)(xmedia_uintptr_t)g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_X].start_addr;
proc_info->buf_addr[XMEDIA_MSENSOR_DATA_TYPE_ACC] =
(xmedia_u64)(xmedia_uintptr_t)g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_X].start_addr;
proc_info->buf_size[XMEDIA_MSENSOR_DATA_TYPE_GYRO] = *gyro_block_size * BUF_BLOCK_NUM;
proc_info->buf_size[XMEDIA_MSENSOR_DATA_TYPE_ACC] = *acc_block_size * BUF_BLOCK_NUM;
msensor_debug_trace("##### dev %d gyro-au64_buf_addr:%llu acc-au64_buf_addr:%llu\n", dev,
proc_info->buf_addr[XMEDIA_MSENSOR_DATA_TYPE_GYRO],
proc_info->buf_addr[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
return;
}
static xmedia_void msensor_buf_allocation_init(xmedia_s32 dev, xmedia_u32 buflen, xmedia_u32 gyro_odr,
xmedia_u32 accel_odr, xmedia_u32 mag_odr, const xmedia_void *vir_addr)
{
xmedia_s32 i;
xmedia_u32 gyro_block_size;
xmedia_u32 acc_block_size;
xmedia_u32 mag_block_size;
gyro_block_size = buflen * gyro_odr / (gyro_odr + accel_odr + mag_odr) / BUF_BLOCK_NUM / 32 * 32; /* align by 32 */
acc_block_size = buflen * accel_odr / (gyro_odr + accel_odr + mag_odr) / BUF_BLOCK_NUM / 32 * 32; /* align by 32 */
mag_block_size = (buflen / BUF_BLOCK_NUM - gyro_block_size - acc_block_size) / 32 * 32; /* align by 32 */
msensor_debug_trace("dev %d gyro block size %u, acc block size %d, mag block size %u\n", dev, gyro_block_size,
acc_block_size, mag_block_size);
for (i = 0; i < DATA_BUTT; i++) {
g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_GYRO][i].start_addr = (xmedia_u8 *)vir_addr + gyro_block_size * i;
g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_GYRO][i].write_ptr =
g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_GYRO][i].start_addr;
g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_ACC][i].start_addr =
(xmedia_u8 *)vir_addr + gyro_block_size * BUF_BLOCK_NUM + acc_block_size * i;
g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_ACC][i].write_ptr =
g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_ACC][i].start_addr;
}
msensor_debug_trace("**pts-write_pointer:%p\n", g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_PTS].write_ptr);
msensor_buf_init_proc(dev, &gyro_block_size, &acc_block_size, &mag_block_size);
return;
}
xmedia_s32 msensor_buf_init(xmedia_s32 dev, const xmedia_msensor_buf_attr *buf_attr, xmedia_u32 gyro_odr,
xmedia_u32 accel_odr, xmedia_u32 mag_odr)
{
xmedia_void *vir_addr = XMEDIA_NULL;
xmedia_s32 i;
if (g_buf_init[dev] == XMEDIA_TRUE) {
MSENSOR_ERR_TRACE("dev %d buf already inited\n", dev);
return XMEDIA_SUCCESS;
}
if ((buf_attr->phys_addr == 0) || (buf_attr->buf_len == 0)) {
MSENSOR_ERR_TRACE("dev %d buf addr can not be null and buf size must lager than 0\n", dev);
return XMEDIA_FAILURE;
}
if ((gyro_odr == 0) && (accel_odr == 0) && (mag_odr == 0)) {
MSENSOR_ERR_TRACE("dev %d can't all frequency be 0\n", dev);
return XMEDIA_FAILURE;
}
/* modify for 64bit chip */
vir_addr = osal_ioremap_wc((xmedia_u64)buf_attr->phys_addr, xmedia_align(buf_attr->buf_len, 4));
if (vir_addr == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d ioremap err\n", dev);
return XMEDIA_FAILURE;
}
g_msensor_buf_len[dev] = xmedia_align(buf_attr->buf_len, 4);
(xmedia_void) osal_memset(vir_addr, 0, buf_attr->buf_len);
msensor_debug_trace("dev %d phy_addr:%llx vir_addr:%p buflen:%d\n", dev, buf_attr->phys_addr, vir_addr,
buf_attr->buf_len);
g_offset[dev] = buf_attr->phys_addr - (xmedia_u64)(xmedia_uintptr_t)vir_addr;
msensor_buf_allocation_init(dev, buf_attr->buf_len, gyro_odr, accel_odr, mag_odr, vir_addr);
osal_mutex_init(&g_user_mng[dev].mng_mutex);
for (i = 0; i < MAX_USER_NUM; i++) {
g_already_released[dev][i] = XMEDIA_TRUE;
}
g_buf_init[dev] = XMEDIA_TRUE;
return XMEDIA_SUCCESS;
}
xmedia_s32 msensor_buf_exit(xmedia_s32 dev)
{
xmedia_s32 i;
xmedia_s32 ret;
if (g_buf_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d buf already deinited\n", dev);
return XMEDIA_SUCCESS;
}
for (i = 0; i < MAX_USER_NUM; i++) {
ret = msensor_buf_delete_user(dev, &i);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d msensor delete user failed\n", dev);
}
}
osal_iounmap(g_buf_info[dev][XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_X].start_addr);
g_msensor_buf_len[dev] = 0;
(xmedia_void) osal_memset(&g_buf_info[dev], 0, sizeof(g_buf_info[dev]));
g_buf_init[dev] = XMEDIA_FALSE;
return ret;
}
static xmedia_void msensor_buf_write(xmedia_s32 dev, xmedia_msensor_data_type data_type,
const xmedia_msensor_sample_data *sample_data)
{
xmedia_void *next_write_pointer = XMEDIA_NULL;
/* step 2:write data */
*(xmedia_s32 *)x_write_ptr(dev, data_type) = sample_data->x;
*(xmedia_s32 *)y_write_ptr(dev, data_type) = sample_data->y;
*(xmedia_s32 *)z_write_ptr(dev, data_type) = sample_data->z;
*(xmedia_s32 *)temp_write_ptr(dev, data_type) = sample_data->temperature;
*(xmedia_u64 *)pts_write_ptr(dev, data_type) = sample_data->pts;
/* step 3:calculate next write pointer */
next_write_pointer = (xmedia_u8 *)x_write_ptr(dev, data_type) + sizeof(sample_data->x);
if (next_write_pointer >= y_start_addr(dev, data_type)) {
x_write_ptr(dev, data_type) = x_start_addr(dev, data_type);
y_write_ptr(dev, data_type) = y_start_addr(dev, data_type);
z_write_ptr(dev, data_type) = z_start_addr(dev, data_type);
temp_write_ptr(dev, data_type) = temp_start_addr(dev, data_type);
pts_write_ptr(dev, data_type) = pts_start_addr(dev, data_type);
} else {
x_write_ptr(dev, data_type) = (xmedia_u8 *)x_write_ptr(dev, data_type) + sizeof(sample_data->x);
y_write_ptr(dev, data_type) = (xmedia_u8 *)y_write_ptr(dev, data_type) + sizeof(sample_data->y);
z_write_ptr(dev, data_type) = (xmedia_u8 *)z_write_ptr(dev, data_type) + sizeof(sample_data->z);
temp_write_ptr(dev, data_type) = (xmedia_u8 *)temp_write_ptr(dev, data_type) + sizeof(sample_data->temperature);
pts_write_ptr(dev, data_type) = (xmedia_u8 *)pts_write_ptr(dev, data_type) + sizeof(sample_data->pts);
}
return;
}
xmedia_s32 msensor_buf_write_data(xmedia_s32 dev, xmedia_msensor_data_type data_type,
const xmedia_msensor_sample_data *sample_data)
{
xmedia_s32 i;
xmedia_void *tmp_ptr = XMEDIA_NULL;
xmedia_bool condition;
msensor_mng_proc_info *proc_info = XMEDIA_NULL;
xmedia_ulong flags;
proc_info = msensor_mng_get_proc_info(dev);
if (g_buf_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d when write_data(pts:%lld),msensor buf not be inited yet\n", dev, sample_data->pts);
return XMEDIA_FAILURE;
}
/* step 1:judge if any user overflow */
if ((xmedia_u8 *)y_start_addr(dev, data_type) - (xmedia_u8 *)x_write_ptr(dev, data_type) >
(xmedia_s32)(sizeof(sample_data->x) * WR_GAP)) {
tmp_ptr = (xmedia_u8 *)x_write_ptr(dev, data_type) + sizeof(sample_data->x) * WR_GAP;
} else {
tmp_ptr = (xmedia_u8 *)x_start_addr(dev, data_type) + sizeof(sample_data->x) * WR_GAP -
((xmedia_u8 *)y_start_addr(dev, data_type) - (xmedia_u8 *)x_write_ptr(dev, data_type));
}
for (i = 0; i < MAX_USER_NUM; i++) {
if (g_user_mng[dev].user_ctx[i] != XMEDIA_NULL) {
if (((tmp_ptr == y_start_addr(dev, data_type)) &&
(x_read_ptr(dev, i, data_type) == x_start_addr(dev, data_type))) ||
(tmp_ptr == x_read_ptr(dev, i, data_type))) {
proc_info->buf_overflow[data_type]++;
proc_info->buf_overflow_id[data_type] = i;
osal_spin_lock_irqsave(&g_user_mng[dev].read_lock[i], &flags);
condition =
((xmedia_u32 *)x_read_ptr(dev, i, data_type) + 1) >= (xmedia_u32 *)y_start_addr(dev, data_type);
x_read_ptr(dev, i, data_type) =
condition ? x_start_addr(dev, data_type) : (xmedia_u32 *)x_read_ptr(dev, i, data_type) + 1;
y_read_ptr(dev, i, data_type) =
condition ? y_start_addr(dev, data_type) : (xmedia_u32 *)y_read_ptr(dev, i, data_type) + 1;
z_read_ptr(dev, i, data_type) =
condition ? z_start_addr(dev, data_type) : (xmedia_u32 *)z_read_ptr(dev, i, data_type) + 1;
temp_read_ptr(dev, i, data_type) =
condition ? temp_start_addr(dev, data_type) : (xmedia_u32 *)temp_read_ptr(dev, i, data_type) + 1;
pts_read_ptr(dev, i, data_type) =
condition ? pts_start_addr(dev, data_type) : (xmedia_u64 *)pts_read_ptr(dev, i, data_type) + 1;
osal_spin_unlock_irqrestore(&g_user_mng[dev].read_lock[i], &flags);
}
}
}
/* write data */
msensor_buf_write(dev, data_type, sample_data);
return XMEDIA_SUCCESS;
}
static xmedia_void msensor_buf_release(xmedia_s32 dev, xmedia_msensor_data_info *data_info)
{
xmedia_s32 id = data_info->id;
xmedia_msensor_data_type data_type = data_info->data_type;
xmedia_ulong flags;
osal_spin_lock_irqsave(&g_user_mng[dev].read_lock[id], &flags);
if (data_info->data[1].num == 0) {
if (data_info->data[0].num > 0) {
if (((xmedia_u64)(xmedia_uintptr_t)data_info->data[0].x_phys_addr +
data_info->data[0].num * sizeof(xmedia_s32) - g_offset[dev]) >=
((xmedia_u64)(xmedia_uintptr_t)y_start_addr(dev, data_type))) {
x_read_ptr(dev, id, data_type) = x_start_addr(dev, data_type);
y_read_ptr(dev, id, data_type) = y_start_addr(dev, data_type);
z_read_ptr(dev, id, data_type) = z_start_addr(dev, data_type);
temp_read_ptr(dev, id, data_type) = temp_start_addr(dev, data_type);
pts_read_ptr(dev, id, data_type) = pts_start_addr(dev, data_type);
} else {
x_read_ptr(dev, id, data_type) = (xmedia_u8 *)data_info->data[0].x_phys_addr +
data_info->data[0].num * sizeof(xmedia_s32) - g_offset[dev];
y_read_ptr(dev, id, data_type) = (xmedia_u8 *)data_info->data[0].y_phys_addr +
data_info->data[0].num * sizeof(xmedia_s32) - g_offset[dev];
z_read_ptr(dev, id, data_type) = (xmedia_u8 *)data_info->data[0].z_phys_addr +
data_info->data[0].num * sizeof(xmedia_s32) - g_offset[dev];
temp_read_ptr(dev, id, data_type) = (xmedia_u8 *)data_info->data[0].temperature_phys_addr +
data_info->data[0].num * sizeof(xmedia_s32) - g_offset[dev];
pts_read_ptr(dev, id, data_type) = (xmedia_u8 *)data_info->data[0].pts_phys_addr +
data_info->data[0].num * sizeof(xmedia_u64) - g_offset[dev];
}
}
} else {
x_read_ptr(dev, id, data_type) =
(xmedia_u8 *)data_info->data[1].x_phys_addr + data_info->data[1].num * sizeof(xmedia_s32) - g_offset[dev];
y_read_ptr(dev, id, data_type) =
(xmedia_u8 *)data_info->data[1].y_phys_addr + data_info->data[1].num * sizeof(xmedia_s32) - g_offset[dev];
z_read_ptr(dev, id, data_type) =
(xmedia_u8 *)data_info->data[1].z_phys_addr + data_info->data[1].num * sizeof(xmedia_s32) - g_offset[dev];
temp_read_ptr(dev, id, data_type) = (xmedia_u8 *)data_info->data[1].temperature_phys_addr +
data_info->data[1].num * sizeof(xmedia_s32) - g_offset[dev];
pts_read_ptr(dev, id, data_type) =
(xmedia_u8 *)data_info->data[1].pts_phys_addr + data_info->data[1].num * sizeof(xmedia_u64) - g_offset[dev];
}
data_info->data[0].num = 0;
data_info->data[1].num = 0;
g_already_released[dev][id] = XMEDIA_TRUE;
osal_spin_unlock_irqrestore(&g_user_mng[dev].read_lock[id], &flags);
return;
}
xmedia_s32 msensor_buf_release_data(xmedia_s32 dev, xmedia_msensor_data_info *data_info)
{
xmedia_ulong flags;
if (data_info == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d data info is null\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
osal_spin_lock_irqsave(&g_user_mng[dev].mng_lock, &flags);
if ((data_info->id < 0) || (data_info->id >= MAX_USER_NUM)) {
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
MSENSOR_ERR_TRACE("dev %d *id(%d) is out of range[0,%d].\n", dev, data_info->id, MAX_USER_NUM);
return XMEDIA_FAILURE;
}
if (g_buf_init[dev] == XMEDIA_FALSE) {
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
MSENSOR_ERR_TRACE("dev %d when release_data, msensor buf not be inited yet\n", dev);
return XMEDIA_FAILURE;
}
if (g_user_mng[dev].user_ctx[data_info->id] == XMEDIA_NULL) {
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
MSENSOR_ERR_TRACE("dev %d msensor buf release: id is null.\n", dev);
return XMEDIA_FAILURE;
}
if (data_info->data_type >= XMEDIA_MSENSOR_DATA_TYPE_MAX) {
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
MSENSOR_ERR_TRACE("dev %d data_type:%d is out of range.\n", dev, data_info->data_type);
return XMEDIA_FAILURE;
}
if (g_already_released[dev][data_info->id] == XMEDIA_TRUE) {
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
return XMEDIA_SUCCESS;
}
/* release data */
msensor_buf_release(dev, data_info);
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_buf_arrive_back_start_addr(xmedia_s32 dev, const xmedia_msensor_data_info *data_info)
{
xmedia_s32 length[2] = { 0 }; /* 2 : cycle buf */
xmedia_s32 buftotal_len;
xmedia_bool loop_flag = XMEDIA_FALSE;
xmedia_u32 interval;
xmedia_u64 *p_pts_read_ptr = XMEDIA_NULL;
xmedia_msensor_data_type data_type = data_info->data_type;
xmedia_s32 id = data_info->id;
buftotal_len = (xmedia_u32 *)y_start_addr(dev, data_type) - (xmedia_u32 *)x_start_addr(dev, data_type);
p_pts_read_ptr = pts_read_ptr(dev, id, data_type);
while (1) {
if ((*p_pts_read_ptr <= data_info->begin_pts) || (p_pts_read_ptr == pts_write_ptr(dev, data_type))) {
if (p_pts_read_ptr == pts_write_ptr(dev, data_type)) {
MSENSOR_ERR_TRACE("dev %d arrive to write_addr!\n", dev);
}
break;
}
if (p_pts_read_ptr == pts_start_addr(dev, data_type)) {
loop_flag = XMEDIA_TRUE;
p_pts_read_ptr = (xmedia_u64 *)pts_start_addr(dev, data_type) + buftotal_len - 1;
} else {
p_pts_read_ptr--;
}
g_forward[dev] = XMEDIA_FALSE;
/* msensor_debug_trace("#####pts_read_pointer:%p %lld\n", pts_read_ptr, *pts_read_ptr) */
if (loop_flag == XMEDIA_TRUE) {
length[1]++;
} else {
length[0]++;
}
}
if (length[1] > 0) {
interval = (xmedia_u64 *)pts_start_addr(dev, data_type) + buftotal_len - p_pts_read_ptr;
x_read_ptr(dev, id, data_type) = (xmedia_u32 *)y_start_addr(dev, data_type) - interval;
y_read_ptr(dev, id, data_type) = (xmedia_u32 *)z_start_addr(dev, data_type) - interval;
z_read_ptr(dev, id, data_type) = (xmedia_u32 *)temp_start_addr(dev, data_type) - interval;
temp_read_ptr(dev, id, data_type) = (xmedia_u32 *)pts_start_addr(dev, data_type) - interval;
pts_read_ptr(dev, id, data_type) = p_pts_read_ptr;
} else {
interval = (xmedia_u64 *)pts_read_ptr(dev, id, data_type) - p_pts_read_ptr;
x_read_ptr(dev, id, data_type) = (xmedia_u32 *)x_read_ptr(dev, id, data_type) - interval;
y_read_ptr(dev, id, data_type) = (xmedia_u32 *)y_read_ptr(dev, id, data_type) - interval;
z_read_ptr(dev, id, data_type) = (xmedia_u32 *)z_read_ptr(dev, id, data_type) - interval;
temp_read_ptr(dev, id, data_type) = (xmedia_u32 *)temp_read_ptr(dev, id, data_type) - interval;
pts_read_ptr(dev, id, data_type) = p_pts_read_ptr;
}
return XMEDIA_SUCCESS;
}
static xmedia_void msensor_buf_get_data_assign(xmedia_s32 dev, xmedia_msensor_data_info *data_info)
{
xmedia_s32 id = data_info->id;
xmedia_msensor_data_type data_type = data_info->data_type;
xmedia_u32 interval;
msensor_mng_proc_info *proc_info = XMEDIA_NULL;
proc_info = msensor_mng_get_proc_info(dev);
if (data_info->data[0].num > 0) {
data_info->data[0].x_phys_addr = (xmedia_void *)((xmedia_u8 *)x_read_ptr(dev, id, data_type) + g_offset[dev]);
data_info->data[0].y_phys_addr = (xmedia_void *)((xmedia_u8 *)y_read_ptr(dev, id, data_type) + g_offset[dev]);
data_info->data[0].z_phys_addr = (xmedia_void *)((xmedia_u8 *)z_read_ptr(dev, id, data_type) + g_offset[dev]);
data_info->data[0].temperature_phys_addr =
(xmedia_void *)((xmedia_u8 *)temp_read_ptr(dev, id, data_type) + g_offset[dev]);
data_info->data[0].pts_phys_addr =
(xmedia_void *)((xmedia_u8 *)pts_read_ptr(dev, id, data_type) + g_offset[dev]);
}
if (data_info->data[1].num > 0) {
data_info->data[1].x_phys_addr = (xmedia_void *)((xmedia_u8 *)x_start_addr(dev, data_type) + g_offset[dev]);
data_info->data[1].y_phys_addr = (xmedia_void *)((xmedia_u8 *)y_start_addr(dev, data_type) + g_offset[dev]);
data_info->data[1].z_phys_addr = (xmedia_void *)((xmedia_u8 *)z_start_addr(dev, data_type) + g_offset[dev]);
data_info->data[1].temperature_phys_addr =
(xmedia_void *)((xmedia_u8 *)temp_start_addr(dev, data_type) + g_offset[dev]);
data_info->data[1].pts_phys_addr = (xmedia_void *)((xmedia_u8 *)pts_start_addr(dev, data_type) + g_offset[dev]);
}
if ((data_info->data[0].num == 0) && (data_info->data[1].num == 0)) {
g_already_released[dev][id] = XMEDIA_TRUE;
proc_info->buf_data_unmatch[data_type]++;
proc_info->buf_data_unmatch_id[data_type] = id;
interval = (xmedia_u32)(xmedia_uintptr_t)((xmedia_u8 *)pts_read_ptr(dev, id, data_type) -
(xmedia_u8 *)pts_start_addr(dev, data_type)) >>
1;
x_read_ptr(dev, id, data_type) = (xmedia_u8 *)x_start_addr(dev, data_type) + interval;
y_read_ptr(dev, id, data_type) = (xmedia_u8 *)y_start_addr(dev, data_type) + interval;
z_read_ptr(dev, id, data_type) = (xmedia_u8 *)z_start_addr(dev, data_type) + interval;
temp_read_ptr(dev, id, data_type) = (xmedia_u8 *)temp_start_addr(dev, data_type) + interval;
pts_read_ptr(dev, id, data_type) = pts_read_ptr(dev, id, data_type);
} else {
g_already_released[dev][id] = XMEDIA_FALSE;
}
data_info->addr_offset = g_offset[dev];
return;
}
static xmedia_void msensor_buf_get_data_process(xmedia_s32 dev, xmedia_msensor_data_info *data_info)
{
xmedia_bool loop_flag = XMEDIA_FALSE;
xmedia_bool first_found = XMEDIA_FALSE;
xmedia_u32 interval;
xmedia_u64 *pts_read_ptr = XMEDIA_NULL;
xmedia_void *pts_start_ptr = XMEDIA_NULL;
xmedia_s32 id = data_info->id;
xmedia_msensor_data_type data_type = data_info->data_type;
pts_read_ptr = pts_read_ptr(dev, id, data_type);
pts_start_ptr = pts_start_addr(dev, data_type);
while (1) {
if (((pts_read_ptr == pts_write_ptr(dev, data_type)) && (g_forward[dev] == XMEDIA_TRUE)) ||
(*pts_read_ptr > data_info->end_pts)) {
break;
}
if ((*pts_read_ptr >= data_info->begin_pts) && (*pts_read_ptr <= data_info->end_pts)) {
if (loop_flag == XMEDIA_TRUE) {
data_info->data[1].num++;
} else if (first_found == XMEDIA_FALSE) {
data_info->data[0].num++;
interval = (xmedia_u32)(xmedia_uintptr_t)((xmedia_u8 *)pts_read_ptr - (xmedia_u8 *)pts_start_ptr) >> 1;
x_read_ptr(dev, id, data_type) = (xmedia_u8 *)x_start_addr(dev, data_type) + interval;
y_read_ptr(dev, id, data_type) = (xmedia_u8 *)y_start_addr(dev, data_type) + interval;
z_read_ptr(dev, id, data_type) = (xmedia_u8 *)z_start_addr(dev, data_type) + interval;
temp_read_ptr(dev, id, data_type) = (xmedia_u8 *)temp_start_addr(dev, data_type) + interval;
pts_read_ptr(dev, id, data_type) = pts_read_ptr;
first_found = XMEDIA_TRUE;
} else {
data_info->data[0].num++;
}
}
pts_read_ptr++;
g_forward[dev] = XMEDIA_TRUE;
if (pts_read_ptr >= ((xmedia_u64 *)pts_start_ptr +
((xmedia_u8 *)y_start_addr(dev, data_type) - (xmedia_u8 *)x_start_addr(dev, data_type)) /
sizeof(xmedia_s32))) {
pts_read_ptr = pts_start_ptr;
if (first_found == XMEDIA_TRUE) {
loop_flag = XMEDIA_TRUE;
}
}
}
return;
}
static xmedia_s32 msensor_buf_data_check(xmedia_s32 dev, const xmedia_msensor_data_info *msensor_data)
{
if (g_buf_init[dev] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d get data, but msensor buffer hasn't been initialised.\n", dev);
return XMEDIA_FAILURE;
}
if (msensor_data == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d msensor_data(%p) is null!!!\n", dev, msensor_data);
return XMEDIA_FAILURE;
}
if ((msensor_data->id < 0) || (msensor_data->id >= MAX_USER_NUM)) {
MSENSOR_ERR_TRACE("dev %d id(%d) is out of range[0, %d].\n", dev, msensor_data->id, MAX_USER_NUM);
return XMEDIA_FAILURE;
}
if (msensor_data->data_type >= XMEDIA_MSENSOR_DATA_TYPE_MAX) {
MSENSOR_ERR_TRACE("dev %d data_type:%d out of range.\n", dev, msensor_data->data_type);
return XMEDIA_FAILURE;
}
/* Check whether user is created. */
if (g_user_mng[dev].user_ctx[msensor_data->id] == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d msensor_buf_read_data: id:%d is null.\n", dev, msensor_data->id);
return XMEDIA_FAILURE;
}
if (g_already_released[dev][msensor_data->id] == XMEDIA_FALSE) {
MSENSOR_ERR_TRACE("dev %d please release last read\n", dev);
return XMEDIA_FAILURE;
}
if ((msensor_data->end_pts - msensor_data->begin_pts) > 5000000) { /* 5000000us */
MSENSOR_ERR_TRACE("dev %d end pts[%llu] - begin pts[%llu] = %llu, more than 5000000\n", dev,
msensor_data->end_pts, msensor_data->begin_pts,
msensor_data->end_pts - msensor_data->begin_pts);
return XMEDIA_FAILURE;
}
if (msensor_data->end_pts <= msensor_data->begin_pts) {
MSENSOR_ERR_TRACE("dev %d end_pts[%llu] <= begin_pts[%llu]\n", dev, msensor_data->end_pts,
msensor_data->begin_pts);
return XMEDIA_FAILURE;
}
return XMEDIA_SUCCESS;
}
xmedia_s32 msensor_buf_get_data(xmedia_s32 dev, xmedia_msensor_data_info *msensor_data)
{
xmedia_s32 ret;
xmedia_ulong flags;
xmedia_ulong flags_read;
xmedia_msensor_data_info data_info = { 0 };
ret = msensor_buf_data_check(dev, msensor_data);
if (ret != XMEDIA_SUCCESS) {
return ret;
}
/* remain check user id to be done */
osal_memcpy(&data_info, msensor_data, sizeof(xmedia_msensor_data_info));
if (msensor_data->data_type == XMEDIA_MSENSOR_DATA_TYPE_GYRO) {
msensor_mng_write_data_2_buf(dev);
}
osal_spin_lock_irqsave(&g_user_mng[dev].mng_lock, &flags);
ret = msensor_buf_data_check(dev, msensor_data);
if (ret != XMEDIA_SUCCESS) {
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
return ret;
}
ret = msensor_buf_arrive_back_start_addr(dev, &data_info);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d data_type:%d has no data.\n", dev, msensor_data->data_type);
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
return XMEDIA_FAILURE;
}
data_info.data[0].num = 0;
data_info.data[1].num = 0;
osal_spin_lock_irqsave(&g_user_mng[dev].read_lock[msensor_data->id], &flags_read);
msensor_buf_get_data_process(dev, &data_info);
msensor_buf_get_data_assign(dev, &data_info);
osal_spin_unlock_irqrestore(&g_user_mng[dev].read_lock[msensor_data->id], &flags_read);
osal_memcpy(msensor_data, &data_info, sizeof(xmedia_msensor_data_info));
osal_spin_unlock_irqrestore(&g_user_mng[dev].mng_lock, &flags);
ret = msensor_buf_release_data(dev, &data_info);
return ret;
}
static xmedia_s32 msensor_buf_sync_init(xmedia_s32 dev)
{
xmedia_s32 ret;
xmedia_s32 i;
for (i = 0; i < MAX_USER_NUM; i++) {
ret = osal_spin_lock_init(&g_user_mng[dev].read_lock[i]);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d spin_lock_init failed!!!!\n", dev);
return XMEDIA_FAILURE;
}
}
return XMEDIA_SUCCESS;
}
static xmedia_void msensor_buf_sync_deinit(xmedia_s32 dev)
{
xmedia_s32 i;
for (i = 0; i < MAX_USER_NUM; i++) {
osal_spin_lock_destroy(&g_user_mng[dev].read_lock[i]);
}
return;
}
xmedia_s32 msensor_buf_lock_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_s32 dev;
for (dev = 0; dev < XMEDIA_MSENSOR_MAX_DEV_NUM; dev++) {
(xmedia_void) osal_memset(&g_user_mng[dev], 0, sizeof(msensor_buf_user_mng));
ret = osal_spin_lock_init(&g_user_mng[dev].mng_lock);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("spin_lock_init failed!!!!\n");
return XMEDIA_FAILURE;
}
ret = msensor_buf_sync_init(dev);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("msensor buf sync init failed!!!!\n");
return XMEDIA_FAILURE;
}
osal_mutex_init(&g_user_mng[dev].mng_mutex);
}
return XMEDIA_SUCCESS;
}
xmedia_void msensor_buf_lock_exit(xmedia_void)
{
xmedia_s32 dev;
for (dev = 0; dev < XMEDIA_MSENSOR_MAX_DEV_NUM; dev++) {
osal_mutex_destroy(&g_user_mng[dev].mng_mutex);
msensor_buf_sync_deinit(dev);
osal_spin_lock_destroy(&g_user_mng[dev].mng_lock);
}
return;
}
@@ -0,0 +1,560 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor_exe.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include "osal.h"
#include "mmz.h"
#include "common.h"
#include "msensor_ext.h"
#include "msensor_buf.h"
#ifdef CONFIG_PROC_SHOW_SUPPORT
#include "msensor_mng_proc.h"
#endif
#include "msensor_mng_ioctl.h"
#define UMAP_MSENSOR_MNG_MINOR_BASE 154
#define UMAP_DEVNANME_MSENSOR_MNG_BASE "msensor_mng"
static osal_dev_t *g_msensor_mng_dev = XMEDIA_NULL;
msensor_mng_proc_info g_mng_proc_info[XMEDIA_MSENSOR_MAX_DEV_NUM] = { 0 };
static msensor_mng_callback g_msensor_mng_callback[XMEDIA_MSENSOR_MAX_DEV_NUM] = { XMEDIA_NULL };
static osal_atomic_t g_msensor_mng_user_ref[XMEDIA_MSENSOR_MAX_DEV_NUM] = { 0 };
#define USER_SEND_DATA 1
#define GYRO_NAME "ICM42670"
msensor_mng_proc_info *msensor_mng_get_proc_info(xmedia_s32 dev)
{
return &g_mng_proc_info[dev];
}
xmedia_s32 msensor_mng_proc_info_init(xmedia_s32 dev)
{
msensor_mng_proc_info *proc_info = XMEDIA_NULL;
proc_info = msensor_mng_get_proc_info(dev);
osal_memcpy(proc_info->gyro_name, "ICM42670", sizeof("ICM42670"));
osal_memcpy(proc_info->accel_name, "ICM42670", sizeof("ICM42670"));
return XMEDIA_SUCCESS;
}
xmedia_s32 msensor_mng_write_data_to_buf(xmedia_s32 dev, xmedia_msensor_data *msensor_data)
{
xmedia_u32 i;
xmedia_s32 ret = XMEDIA_SUCCESS;
osal_spinlock_t *mng_lock = msensor_buf_get_lock(dev);
xmedia_ulong flags;
if (msensor_data == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d msensor data is null\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
if ((msensor_data->gyro_buf.data_num > XMEDIA_MSENSOR_MAX_DATA_NUM) ||
(msensor_data->acc_buf.data_num > XMEDIA_MSENSOR_MAX_DATA_NUM)) {
return XMEDIA_FAILURE;
}
osal_spin_lock_irqsave(mng_lock, &flags);
if ((msensor_data->attr.device_mask & XMEDIA_MSENSOR_DEVICE_GYRO) == XMEDIA_MSENSOR_DEVICE_GYRO) {
for (i = 0; i < msensor_data->gyro_buf.data_num; i++) {
if ((msensor_data->attr.temperature_mask & XMEDIA_MSENSOR_TEMP_GYRO) != XMEDIA_MSENSOR_TEMP_GYRO) {
msensor_data->gyro_buf.gyro_data[i].temperature = 0xffffffff;
}
ret = msensor_buf_write_data(dev, XMEDIA_MSENSOR_DATA_TYPE_GYRO, &(msensor_data->gyro_buf.gyro_data[i]));
}
}
if ((msensor_data->attr.device_mask & XMEDIA_MSENSOR_DEVICE_ACC) == XMEDIA_MSENSOR_DEVICE_ACC) {
for (i = 0; i < msensor_data->acc_buf.data_num; i++) {
if ((msensor_data->attr.temperature_mask & XMEDIA_MSENSOR_TEMP_ACC) != XMEDIA_MSENSOR_TEMP_ACC) {
msensor_data->acc_buf.acc_data[i].temperature = 0xffffffff;
}
ret = msensor_buf_write_data(dev, XMEDIA_MSENSOR_DATA_TYPE_ACC, &(msensor_data->acc_buf.acc_data[i]));
}
}
osal_spin_unlock_irqrestore(mng_lock, &flags);
return ret;
}
static xmedia_s32 msensor_buf_check_phys_addr(xmedia_s32 dev, xmedia_msensor_data_info *data_info)
{
xmedia_s32 ret = XMEDIA_SUCCESS;
xmedia_unused(dev);
if (data_info->data[0].num > 0) {
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[0].x_phys_addr,
sizeof(xmedia_s32) * data_info->data[0].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[0].y_phys_addr,
sizeof(xmedia_s32) * data_info->data[0].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[0].z_phys_addr,
sizeof(xmedia_s32) * data_info->data[0].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[0].temperature_phys_addr,
sizeof(xmedia_s32) * data_info->data[0].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[0].pts_phys_addr,
sizeof(xmedia_u64) * data_info->data[0].num);
}
if (data_info->data[1].num > 0) {
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[1].x_phys_addr,
sizeof(xmedia_s32) * data_info->data[1].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[1].y_phys_addr,
sizeof(xmedia_s32) * data_info->data[1].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[1].z_phys_addr,
sizeof(xmedia_s32) * data_info->data[1].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[1].temperature_phys_addr,
sizeof(xmedia_s32) * data_info->data[1].num);
ret |= mmz_check_phyaddr((xmedia_u64)(xmedia_uintptr_t)data_info->data[1].pts_phys_addr,
sizeof(xmedia_u64) * data_info->data[1].num);
}
return ret;
}
/* msensor mng ioctl functions */
static xmedia_s32 msensor_mng_drv_user_get_data(xmedia_s32 dev, xmedia_ulong arg)
{
xmedia_s32 ret;
ret = msensor_buf_get_data(dev, (xmedia_msensor_data_info *)arg);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d get data failed! ret=%x\n", dev, ret);
return ret;
}
ret = msensor_buf_check_phys_addr(dev, (xmedia_msensor_data_info *)arg);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d check msensor data addr share failed\n", dev);
return ret;
}
return ret;
}
static xmedia_s32 msensor_mng_drv_user_release_buf(xmedia_s32 dev, xmedia_ulong arg)
{
xmedia_s32 ret;
ret = msensor_buf_check_phys_addr(dev, (xmedia_msensor_data_info *)arg);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d check msensor_data_addr share failed\n", dev);
return XMEDIA_FAILURE;
}
ret = msensor_buf_release_data(dev, (xmedia_msensor_data_info *)arg);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d buf release failed! ret=%x\n", dev, ret);
return XMEDIA_FAILURE;
}
return ret;
}
static xmedia_s32 msensor_mng_drv_user_add_user(xmedia_s32 dev, xmedia_ulong arg)
{
xmedia_s32 ret;
ret = msensor_buf_add_user(dev, (xmedia_s32 *)arg);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d msensor buf add_user failed! ret=%x\n", dev, ret);
return ret;
}
return ret;
}
static xmedia_s32 msensor_mng_drv_user_delete_user(xmedia_s32 dev, xmedia_ulong arg)
{
xmedia_s32 ret;
ret = msensor_buf_delete_user(dev, (xmedia_s32 *)arg);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d msensor buf delete user failed! ret=%x\n", dev, ret);
return ret;
}
return ret;
}
static xmedia_s32 msensor_mng_drv_user_send_data(xmedia_s32 dev, xmedia_ulong arg)
{
#ifdef USER_SEND_DATA
xmedia_s32 ret;
xmedia_msensor_data *msensor_data;
msensor_data = (xmedia_msensor_data *)arg;
ret = msensor_mng_write_data_to_buf(dev, msensor_data);
if (ret != XMEDIA_SUCCESS) {
MSENSOR_ERR_TRACE("dev %d write data to buf failed! ret=%x\n", dev, ret);
return ret;
}
return ret;
#else
MSENSOR_ERR_TRACE("dev %d msensor send data not support\n", dev);
return XMEDIA_FAILURE;
#endif
}
xmedia_s32 msensor_mng_drv_get_data(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_mng_drv_user_get_data(dev, arg);
}
xmedia_s32 msensor_mng_drv_release_buf(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_mng_drv_user_release_buf(dev, arg);
}
xmedia_s32 msensor_mng_drv_add_user(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_mng_drv_user_add_user(dev, arg);
}
xmedia_s32 msensor_mng_drv_delete_user(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_mng_drv_user_delete_user(dev, arg);
}
xmedia_s32 msensor_mng_drv_send_data(xmedia_s32 dev, xmedia_ulong arg)
{
return msensor_mng_drv_user_send_data(dev, arg);
}
typedef xmedia_s32 (*msensor_ctl_ptr_func)(xmedia_s32 dev_id, xmedia_ulong arg);
typedef struct {
xmedia_u32 cmd;
msensor_ctl_ptr_func ptr_func;
} msensor_ioctl_func_item;
static msensor_ioctl_func_item g_msensor_mng_cmd_list[] = {
{ MSENSOR_CMD_GET_DATA, msensor_mng_drv_get_data }, { MSENSOR_CMD_RELEASE_BUF, msensor_mng_drv_release_buf },
{ MSENSOR_CMD_ADD_USER, msensor_mng_drv_add_user }, { MSENSOR_CMD_DELETE_USER, msensor_mng_drv_delete_user },
{ MSENSOR_CMD_SEND_DATA, msensor_mng_drv_send_data },
};
static xmedia_s32 msensor_mng_do_ioctl(xmedia_s32 dev, xmedia_u32 cmd, xmedia_ulong arg)
{
xmedia_s32 i;
for (i = 0; i < sizeof(g_msensor_mng_cmd_list) / sizeof(g_msensor_mng_cmd_list[0]); i++) {
if (cmd == g_msensor_mng_cmd_list[i].cmd) {
return g_msensor_mng_cmd_list[i].ptr_func(dev, arg);
}
}
MSENSOR_ERR_TRACE("dev %d msensor chip ioctl cmd 0x%x not supported!\n", dev, cmd);
return XMEDIA_ERRCODE_NOT_SUPPORT;
}
xmedia_slong msensor_mng_ioctl(xmedia_u32 cmd, xmedia_ulong arg, xmedia_void *private_data)
{
xmedia_s32 ret;
xmedia_s32 dev;
if (cmd == MSENSOR_CMD_MNG_BIND_FLAG2FD) {
*(xmedia_u32 *)private_data = *(xmedia_u32 *)arg;
return XMEDIA_SUCCESS;
}
dev = *(xmedia_u32 *)private_data;
osal_atomic_inc_return(&g_msensor_mng_user_ref[dev]);
ret = msensor_mng_do_ioctl(dev, cmd, arg);
osal_atomic_dec_return(&g_msensor_mng_user_ref[dev]);
return ret;
}
static xmedia_s32 msensor_mng_open(xmedia_void *private_data)
{
xmedia_unused(private_data);
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_mng_release(xmedia_void *private_data)
{
xmedia_unused(private_data);
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_mng_freeze(osal_dev_t *dev)
{
return XMEDIA_SUCCESS;
}
static xmedia_s32 msensor_mng_restore(osal_dev_t *dev)
{
return XMEDIA_SUCCESS;
}
// todo,待实现 init 函数
// static xmedia_s32 msensor_mng_fn_init(xmedia_void *args)
// {
// xmedia_unused(args);
// return XMEDIA_SUCCESS;
// }
xmedia_s32 msensor_mng_buf_init(xmedia_s32 dev, const xmedia_msensor_attr *motion_attr,
const xmedia_msensor_buf_attr *msensor_buf_attr,
const xmedia_msensor_config *msensor_config)
{
xmedia_u32 gyro_odr;
xmedia_u32 acc_odr;
xmedia_u32 magn_odr;
xmedia_s32 ret;
if (motion_attr == XMEDIA_NULL || msensor_buf_attr == XMEDIA_NULL || msensor_config == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("input NULL\n");
return XMEDIA_FAILURE;
}
switch (motion_attr->device_mask) {
case XMEDIA_MSENSOR_DEVICE_GYRO | XMEDIA_MSENSOR_DEVICE_ACC: {
/* only for american present */
gyro_odr = msensor_config->gyro_config.odr;
acc_odr = msensor_config->acc_config.odr;
magn_odr = 0;
msensor_debug_trace("dev %d odr:gyro_odr:%d acc_odr:%d magn_odr:%d\n", dev, gyro_odr, acc_odr, magn_odr);
ret = msensor_buf_init(dev, msensor_buf_attr, gyro_odr, acc_odr, magn_odr);
break;
}
case XMEDIA_MSENSOR_DEVICE_GYRO: {
/* only for american present */
gyro_odr = msensor_config->gyro_config.odr;
acc_odr = 0;
magn_odr = 0;
msensor_debug_trace("dev %d gyro_odr:%d acc_odr:%d magn_odr:%d\n", dev, gyro_odr, acc_odr, magn_odr);
ret = msensor_buf_init(dev, msensor_buf_attr, gyro_odr, acc_odr, magn_odr);
break;
}
#if 0
case XMEDIA_MSENSOR_DEVICE_ALL: {
/* only for american present */
gyro_odr = msensor_config->gyro_config.odr;
acc_odr = msensor_config->acc_config.odr;
magn_odr = msensor_config->acc_config.odr;
msensor_debug_trace("dev %d gyro_odr:%d acc_odr:%d magn_odr:%d\n", dev, gyro_odr, acc_odr, magn_odr);
ret = msensor_buf_init(dev, msensor_buf_attr, gyro_odr, acc_odr, magn_odr);
break;
}
#endif
default: {
gyro_odr = 0;
acc_odr = 0;
magn_odr = 0;
MSENSOR_ERR_TRACE("dev %d msensor mng init buf(gyro_odr:%d acc_odr:%d magn_odr:%d) err!\n", dev, gyro_odr,
acc_odr, magn_odr);
ret = XMEDIA_FAILURE;
break;
}
}
return ret;
}
xmedia_s32 msensor_mng_buf_exit(xmedia_s32 dev)
{
return msensor_buf_exit(dev);
}
xmedia_s32 msensor_mng_get_chip_cfg(xmedia_s32 dev, xmedia_msensor_param *msensor_param)
{
if (g_msensor_mng_callback[dev].pfn_get_config_from_chip == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d null point!\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
return g_msensor_mng_callback[dev].pfn_get_config_from_chip(dev, msensor_param);
}
xmedia_s32 msensor_mng_write_data_2_buf(xmedia_s32 dev)
{
if (g_msensor_mng_callback[dev].pfn_write_data_to_buf == XMEDIA_NULL) {
MSENSOR_ERR_TRACE("dev %d nul point!\n", dev);
return XMEDIA_ERRCODE_NULL_PTR;
}
return g_msensor_mng_callback[dev].pfn_write_data_to_buf(dev);
}
xmedia_s32 msensor_mng_register_call_back(xmedia_s32 dev, const msensor_mng_callback *callback)
{
msensor_return_if_null_ptr(callback);
g_msensor_mng_callback[dev].pfn_get_config_from_chip = callback->pfn_get_config_from_chip;
g_msensor_mng_callback[dev].pfn_write_data_to_buf = callback->pfn_write_data_to_buf;
return XMEDIA_SUCCESS;
}
xmedia_void msensor_mng_unregister_call_back(xmedia_s32 dev)
{
g_msensor_mng_callback[dev].pfn_get_config_from_chip = XMEDIA_NULL;
g_msensor_mng_callback[dev].pfn_write_data_to_buf = XMEDIA_NULL;
return;
}
static struct osal_fileops g_msensor_mng_fops = {
.open = msensor_mng_open,
.unlocked_ioctl = msensor_mng_ioctl,
.release = msensor_mng_release,
};
struct osal_pmops g_msensor_mng_drv_ops = {
.pm_freeze = msensor_mng_freeze,
.pm_restore = msensor_mng_restore,
};
static xmedia_s32 msensor_mng_atomic_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_s32 i, j;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
ret = osal_atomic_init(&g_msensor_mng_user_ref[i]);
if (ret != XMEDIA_SUCCESS) {
osal_printk("atomic init failed. \n");
goto failed;
}
osal_atomic_set(&g_msensor_mng_user_ref[i], 0);
}
return XMEDIA_SUCCESS;
failed:
for (j = i - 1; j >= 0; j--) {
osal_atomic_destory(&g_msensor_mng_user_ref[j]);
}
return ret;
}
static xmedia_void msensor_mng_atomic_exit(xmedia_void)
{
xmedia_s32 i;
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
osal_atomic_destroy(&g_msensor_mng_user_ref[i]);
}
return;
}
xmedia_s32 msensor_mng_module_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_s32 i;
#ifdef CONFIG_PROC_SHOW_SUPPORT
ret = msensor_proc_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("msensor proc init failed\n");
goto FAIL0;
}
#endif
g_msensor_mng_dev = osal_createdev(UMAP_DEVNANME_MSENSOR_MNG_BASE);
if (g_msensor_mng_dev == XMEDIA_NULL) {
osal_printk("msensor: create device failed\n");
goto FAIL1;
}
g_msensor_mng_dev->fops = &g_msensor_mng_fops;
g_msensor_mng_dev->minor = UMAP_MSENSOR_MNG_MINOR_BASE;
g_msensor_mng_dev->osal_pmops = &g_msensor_mng_drv_ops;
ret = osal_registerdevice(g_msensor_mng_dev);
if (ret != XMEDIA_SUCCESS) {
osal_printk("register msensor device failed!\n");
goto FAIL2;
}
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
(xmedia_void) osal_memset(&g_mng_proc_info[i], 0, sizeof(g_mng_proc_info[i]));
}
ret = msensor_buf_lock_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("register msensor buf lock init failed!\n");
goto FAIL3;
}
ret = msensor_mng_atomic_init();
if (ret != XMEDIA_SUCCESS) {
osal_printk("register msensor device failed!\n");
goto FAIL4;
}
osal_printk("load xm_msensor_mng.ko OK!\n");
return XMEDIA_SUCCESS;
FAIL4:
msensor_buf_lock_exit();
FAIL3:
osal_deregisterdevice(g_msensor_mng_dev);
FAIL2:
osal_destroydev(g_msensor_mng_dev);
FAIL1:
#ifdef CONFIG_PROC_SHOW_SUPPORT
msensor_proc_exit();
FAIL0:
#endif
return XMEDIA_FAILURE;
}
/* if static, liteos warning */
xmedia_void msensor_mng_module_exit(xmedia_void)
{
xmedia_s32 i;
msensor_mng_atomic_exit();
msensor_buf_lock_exit();
for (i = 0; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
(xmedia_void) osal_memset(&g_mng_proc_info[i], 0, sizeof(g_mng_proc_info[i]));
}
osal_deregisterdevice(g_msensor_mng_dev);
osal_destroydev(g_msensor_mng_dev);
#ifdef CONFIG_PROC_SHOW_SUPPORT
msensor_proc_exit();
#endif
osal_printk("unload msensor_mng.ko OK!\n");
}
#ifdef MODULE
EXPORT_SYMBOL(msensor_mng_buf_init);
EXPORT_SYMBOL(msensor_mng_buf_exit);
EXPORT_SYMBOL(msensor_mng_write_data_to_buf);
EXPORT_SYMBOL(msensor_mng_register_call_back);
EXPORT_SYMBOL(msensor_mng_unregister_call_back);
module_init(msensor_mng_module_init);
module_exit(msensor_mng_module_exit);
MODULE_DESCRIPTION("msensor driver");
MODULE_LICENSE("GPL");
#else
int __init msensor_mng_driver_init(void)
{
return msensor_mng_module_init();
}
#endif
@@ -0,0 +1,158 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor_mng_proc.h"
#include <linux/kernel.h>
#include "osal.h"
#include "msensor_buf.h"
#include "msensor_exe.h"
#define MSENSOR_MNG_INFO "msensor_mng"
#define MSENSOR_MNG_VERSION_INFO "msensor_mng debug V0.0.0.1"
static xmedia_void msensor_print_proc_title(osal_proc_entry_t *s, xmedia_char *title)
{
xmedia_s32 i;
for (i = 0; i < 50; i++) {
osal_seq_printf(s, "-");
}
osal_seq_printf(s, title);
for (i = 0; i < 50; i++) {
osal_seq_printf(s, "-");
}
osal_seq_printf(s, "\n");
}
static xmedia_void msensor_proc_show_gyro(xmedia_s32 dev, osal_proc_entry_t *s, msensor_buf_info (*buf_info)[DATA_BUTT])
{
msensor_mng_proc_info *proc_info = msensor_mng_get_proc_info(dev);
if (proc_info->gyro_name[0] == 0) {
return;
}
msensor_print_proc_title(s, "gyro sensor name");
osal_seq_printf(s, "%20s\n", proc_info->gyro_name);
msensor_print_proc_title(s, "gyro sensor param");
osal_seq_printf(s, "%16s%20s%16s%16s%16s%16s%16s\n", "dev_no", "buf_addr", "buf_size",
"overflow", "data_unmatch", "overflow_id", "data_unmatch_id");
osal_seq_printf(s, "%16d", dev);
osal_seq_printf(s, "%20llx", proc_info->buf_addr[XMEDIA_MSENSOR_DATA_TYPE_GYRO]);
osal_seq_printf(s, "%16u", proc_info->buf_size[XMEDIA_MSENSOR_DATA_TYPE_GYRO]);
osal_seq_printf(s, "%16u", proc_info->buf_overflow[XMEDIA_MSENSOR_DATA_TYPE_GYRO]);
osal_seq_printf(s, "%16u", proc_info->buf_data_unmatch[XMEDIA_MSENSOR_DATA_TYPE_GYRO]);
osal_seq_printf(s, "%16d", proc_info->buf_overflow_id[XMEDIA_MSENSOR_DATA_TYPE_GYRO]);
osal_seq_printf(s, "%16d\n", proc_info->buf_data_unmatch_id[XMEDIA_MSENSOR_DATA_TYPE_GYRO]);
msensor_print_proc_title(s, "gyro sensor addr");
osal_seq_printf(s, "%10s%20s%20s", "", "start_addr", "write_addr");
osal_seq_printf(s, "\n%10s%20px%20px", "x", buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_X].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_X].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px", "y", buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_Y].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_Y].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px", "z", buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_Z].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_Z].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px", "temp", buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_TEMP].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_TEMP].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px\n", "pts", buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_PTS].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_GYRO][DATA_PTS].write_ptr);
return;
}
static xmedia_void msensor_proc_show_acc(xmedia_s32 dev, osal_proc_entry_t *s, msensor_buf_info (*buf_info)[DATA_BUTT])
{
msensor_mng_proc_info *proc_info = msensor_mng_get_proc_info(dev);
if (proc_info->accel_name[0] == 0) {
return;
}
msensor_print_proc_title(s, "acc sensor name");
osal_seq_printf(s, "%21s\n", proc_info->accel_name);
msensor_print_proc_title(s, "acc sensor param");
osal_seq_printf(s, "%16s%20s%16s%16s%16s%16s%16s\n", "dev_no", "buf_addr", "buf_size",
"overflow", "data_unmatch", "overflow_id", "data_unmatch_id");
osal_seq_printf(s, "%16d", dev);
osal_seq_printf(s, "%20llx", proc_info->buf_addr[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
osal_seq_printf(s, "%16u", proc_info->buf_size[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
osal_seq_printf(s, "%16u", proc_info->buf_overflow[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
osal_seq_printf(s, "%16u", proc_info->buf_data_unmatch[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
osal_seq_printf(s, "%16d", proc_info->buf_overflow_id[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
osal_seq_printf(s, "%16d\n", proc_info->buf_data_unmatch_id[XMEDIA_MSENSOR_DATA_TYPE_ACC]);
msensor_print_proc_title(s, "acc sensor addr");
osal_seq_printf(s, "%10s%20s%20s\n", "", "start_addr", "write_addr");
osal_seq_printf(s, "%10s%20px%20px", "x", buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_X].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_X].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px", "y", buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_Y].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_Y].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px", "z", buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_Z].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_Z].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px", "temp", buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_TEMP].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_TEMP].write_ptr);
osal_seq_printf(s, "\n%10s%20px%20px\n", "pts", buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_PTS].start_addr,
buf_info[XMEDIA_MSENSOR_DATA_TYPE_ACC][DATA_PTS].write_ptr);
return;
}
static xmedia_s32 msensor_proc_show(osal_proc_entry_t *s)
{
xmedia_s32 ret;
msensor_buf_info(*buf_info)[DATA_BUTT] = XMEDIA_NULL;
xmedia_s32 i;
osal_seq_printf(s,
"[msensor] version:[" MSENSOR_MNG_VERSION_INFO "], build time["__DATE__
", "__TIME__
"]\n");
for (i = 0 ; i < XMEDIA_MSENSOR_MAX_DEV_NUM; i++) {
if (msensor_buf_get_status(i) == XMEDIA_FALSE) {
continue;
}
ret = msensor_mng_proc_info_init(i);
if (ret != XMEDIA_SUCCESS) {
continue;
}
buf_info = (msensor_buf_info(*)[DATA_BUTT])msensor_buf_get_info(i);
msensor_proc_show_gyro(i, s, buf_info);
msensor_proc_show_acc(i, s, buf_info);
}
return 0;
}
xmedia_s32 msensor_proc_init(xmedia_void)
{
osal_proc_entry_t *msensor_entry = XMEDIA_NULL;
msensor_entry = osal_create_proc_entry(MSENSOR_MNG_INFO, XMEDIA_NULL);
if (msensor_entry == XMEDIA_NULL) {
printk("osal_create_proc_entry failed!\n");
return -1;
}
msensor_entry->read = msensor_proc_show;
msensor_entry->write = XMEDIA_NULL;
return 0;
}
void msensor_proc_exit(xmedia_void)
{
osal_remove_proc_entry(MSENSOR_MNG_INFO, XMEDIA_NULL);
return;
}
@@ -0,0 +1,22 @@
ifneq ($(srctree),)
KERNEL_DIR := $(srctree)
SDK_DIR := $(shell cd $(KERNEL_DIR)/../../.. && /bin/pwd)
else
SDK_DIR := $(shell cd $(CURDIR)/../../../../../.. && /bin/pwd)
endif
include $(SDK_DIR)/build/base.mk
MOD_NAME := xm_msensor_spi
SRCS := msensor_spi.c
SDK_KER_CFLAGS += -I$(GMP_DIR)/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/osal/include
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/include
$(info SDK_KER_CFLAGS=$(SDK_KER_CFLAGS))
$(info SRCS=$(SRCS))
$(info SDK_DIR=$(SDK_DIR))
include $(SDK_DIR)/build/sdk_ko_rules.mk
@@ -0,0 +1,581 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#include "msensor_spi.h"
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include "osal.h"
#define xmedia_unused(x) ((xmedia_void)(x))
#define SSP_DBG_ERR KERN_ALERT
#define SSP_DBG_INFO KERN_DEBUG
#define ssp_trace(level, fmt, ...) printk(level fmt, ##__VA_ARGS__)
#define SPI_DATAWIDTH_8 0
#define DEV_NAME "ssp"
#define MAX_MSENSOR_DEV_NUM 2
#define SSP_DEV_NUM 3
#define ssp_readw(addr, ret) ((ret) = (*(volatile xmedia_u32 *)(addr)))
#define ssp_writew(addr, value) ((*(volatile xmedia_u32 *)(addr)) = (value))
#define xmedia_reg_read(addr, ret) ((ret) = (*(volatile xmedia_u32 *)(addr)))
#define xmedia_reg_write(addr, value) ((*(volatile xmedia_u32 *)(addr)) = (value))
#define SSP_BASE 0x12070000
#define SSP_SIZE 0x10000 /* 64KB */
#define CRG_BASE 0x12010000
#define CRG_SIZE 0x10000
#define SSP_CRG_OFFSET 0x01bc
//spi 管脚复用基地址,需要根据对应芯片做修改
#define XM7206_GPIO_BASE 0x100c0000 // 管脚复用基地址
#define IO1_SIZE 0x1000
#define CS_SIZE 0x4
#define SPI1_CS_BASE_ADDRS 0x12028000
static xmedia_void __iomem *g_reg_ssp_base_va = XMEDIA_NULL;
static xmedia_void __iomem *g_reg_crg_base_va = XMEDIA_NULL;
static xmedia_void __iomem *g_reg_io1_base_va = XMEDIA_NULL;
static xmedia_void __iomem *g_reg_spi1_cs_base_va = XMEDIA_NULL;
#define io_address_verify(x) ((xmedia_ulong)(xmedia_uintptr_t)g_reg_ssp_base_va + ((x) - (SSP_BASE)))
#define SSP_CRG_ADDRESS ((xmedia_ulong)(xmedia_uintptr_t)g_reg_crg_base_va + SSP_CRG_OFFSET)
#define io1_addr(offset) ((xmedia_ulong)(xmedia_uintptr_t)g_reg_io1_base_va + offset)
#define spi1_cs_addr(offset) ((xmedia_ulong)(xmedia_uintptr_t)g_reg_spi1_cs_base_va + offset)
/* SSP register definition . */
#define ssp_cr0(ssp_no) io_address_verify(SSP_BASE + 0x00 + ((ssp_no) * 0x1000))
#define ssp_cr1(ssp_no) io_address_verify(SSP_BASE + 0x04 + ((ssp_no) * 0x1000))
#define ssp_dr(ssp_no) io_address_verify(SSP_BASE + 0x08 + ((ssp_no) * 0x1000))
#define ssp_sr(ssp_no) io_address_verify(SSP_BASE + 0x0C + ((ssp_no) * 0x1000))
#define ssp_cpsr(ssp_no) io_address_verify(SSP_BASE + 0x10 + ((ssp_no) * 0x1000))
#define ssp_imsc(ssp_no) io_address_verify(SSP_BASE + 0x14 + ((ssp_no) * 0x1000))
#define ssp_ris(ssp_no) io_address_verify(SSP_BASE + 0x18 + ((ssp_no) * 0x1000))
#define ssp_mis(ssp_no) io_address_verify(SSP_BASE + 0x1C + ((ssp_no) * 0x1000))
#define ssp_icr(ssp_no) io_address_verify(SSP_BASE + 0x20 + ((ssp_no) * 0x1000))
#define ssp_dmacr(ssp_no) io_address_verify(SSP_BASE + 0x24 + ((ssp_no) * 0x1000))
#define ssp_csr(ssp_no) io_address_verify(SSP_BASE + 0x30 + ((ssp_no) * 0x1000))
static xmedia_u32 g_dev_ssp_no[MAX_MSENSOR_DEV_NUM] = {2,};
static spinlock_t g_ssp_lock[SSP_DEV_NUM];
#define ssp_spin_lock_init(ssp_no) spin_lock_init(&g_ssp_lock[ssp_no])
#define ssp_spin_lock(ssp_no, flags) spin_lock_irqsave(&g_ssp_lock[ssp_no], flags)
#define ssp_spin_unlock(ssp_no, flags) spin_unlock_irqrestore(&g_ssp_lock[ssp_no], flags)
static spinlock_t g_ssp_crg_lock;
#define ssp_crg_spin_lock_init() spin_lock_init(&g_ssp_crg_lock)
#define ssp_crg_spin_lock(flags) spin_lock_irqsave(&g_ssp_crg_lock, flags)
#define ssp_crg_spin_unlock(flags) spin_unlock_irqrestore(&g_ssp_crg_lock, flags)
static xmedia_void xmedia_ssp_clock_enable(xmedia_u32 ssp_no)
{
xmedia_u32 ret = 0;
xmedia_ulong flags;
ssp_crg_spin_lock(flags);
xmedia_reg_read(SSP_CRG_ADDRESS, ret);
ret |= 0x1 << (12 + ssp_no); /* ssp clock enable bit: 4 */
xmedia_reg_write(SSP_CRG_ADDRESS, ret);
ssp_crg_spin_unlock(flags);
return;
}
static xmedia_void xmedia_ssp_clock_disable(xmedia_u32 ssp_no)
{
xmedia_u32 ret = 0;
xmedia_ulong flags;
ssp_crg_spin_lock(flags);
xmedia_reg_read(SSP_CRG_ADDRESS, ret);
ret = ret & (~(0x1 << (12 + ssp_no))); /* ssp clock enable bit: 4 */
xmedia_reg_write(SSP_CRG_ADDRESS, ret);
ssp_crg_spin_unlock(flags);
return;
}
static xmedia_void xmedia_ssp_clock_reset(xmedia_u32 ssp_no)
{
#ifdef MSENSOR_SPI_DEBUG
xmedia_u32 ret = 0;
xmedia_ulong flags;
ssp_crg_spin_lock(flags);
xmedia_reg_read(SSP_CRG_ADDRESS, ret);
ret |= 0x1 << (16 + ssp_no); /* ssp clock reset bit: 0 */
xmedia_reg_write(SSP_CRG_ADDRESS, ret);
ssp_crg_spin_unlock(flags);
#endif
}
static xmedia_void xmedia_ssp_clock_unreset(xmedia_u32 ssp_no)
{
#ifdef MSENSOR_SPI_DEBUG
xmedia_u32 ret = 0;
xmedia_ulong flags;
ssp_crg_spin_lock(flags);
xmedia_reg_read(SSP_CRG_ADDRESS, ret);
ret = ret & (~(0x1 << (16 + ssp_no))); /* ssp clock reset bit: 0 */
xmedia_reg_write(SSP_CRG_ADDRESS, ret);
ssp_crg_spin_unlock(flags);
#endif
}
/*
* set SSP frame form routine.
*
* @param framemode: frame form
* 00: Motorola SPI frame form.
* when set the mode,need set SSPCLKOUT phase and SSPCLKOUT voltage level.
* 01: TI synchronous serial frame form
* 10: National Microwire frame form
* 11: reserved
* @param sphvalue: SSPCLKOUT phase (0/1)
* @param sp0: SSPCLKOUT voltage level (0/1)
* @param datavalue: data bit
* 0000: reserved 0001: reserved 0010: reserved 0011: 4bit data
* 0100: 5bit data 0101: 6bit data 0110:7bit data 0111: 8bit data
* 1000: 9bit data 1001: 10bit data 1010:11bit data 1011: 12bit data
* 1100: 13bit data 1101: 14bit data 1110:15bit data 1111: 16bit data
*
* @return value: 0--success; -1--error.
*/
static xmedia_s32 xmedia_ssp_set_frameform(xmedia_u32 ssp_no, xmedia_u8 framemode,
xmedia_u8 spo, xmedia_u8 sph, xmedia_u8 datawidth)
{
xmedia_u32 ret = 0;
ssp_readw(ssp_cr0(ssp_no), ret);
if (framemode > 3) { /* frame form 3 */
ssp_trace(SSP_DBG_ERR, "set framemode failed.\n");
return -1;
}
ret = (ret & 0xFFCF) | (framemode << 4); /* 4 bits */
if ((ret & 0x30) == 0) {
if (spo > 1) {
ssp_trace(SSP_DBG_ERR, "set spo failed.\n");
return -1;
}
if (sph > 1) {
ssp_trace(SSP_DBG_ERR, "set sph failed.\n");
return -1;
}
ret = (ret & 0xFF3F) | (sph << 7) | (spo << 6); /* sph 7 bits, spo 6 bits */
}
if ((datawidth > 16) || (datawidth < 4)) { /* datawidth between 4 bits and 16 bits */
ssp_trace(SSP_DBG_ERR, "set datawidth parameter err.\n");
return -1;
}
ret = (ret & 0xFFF0) | (datawidth - 1);
ssp_writew(ssp_cr0(ssp_no), ret);
return 0;
}
/*
* set SSP serial clock rate routine.
*
* @param scr: scr value.(0-255,usually it is 0)
* @param cpsdvsr: clock prescale divisor.(2-254 even)
*
* @return value: 0--success; -1--error.
*/
static xmedia_s32 xmedia_ssp_set_serialclock(xmedia_u32 ssp_no, xmedia_u8 scr, xmedia_u8 cpsdvsr)
{
xmedia_u32 ret = 0;
ssp_readw(ssp_cr0(ssp_no), ret);
ret = (ret & 0xFF) | (scr << 8); /* 8 bits */
ssp_writew(ssp_cr0(ssp_no), ret);
if ((cpsdvsr & 0x1)) {
ssp_trace(SSP_DBG_ERR, "set cpsdvsr failed.\n");
return -1;
}
ssp_writew(ssp_cpsr(ssp_no), cpsdvsr);
return 0;
}
static xmedia_s32 xmedia_ssp_big_end_set(xmedia_u32 ssp_no)
{
xmedia_u32 ret = 0;
ssp_readw(ssp_cr1(ssp_no), ret);
ret = (ret & 0xFF) & 0xEF;
ssp_writew(ssp_cr1(ssp_no), ret);
return 0;
}
static xmedia_s32 xmedia_ssp_alt_mode_set(xmedia_u32 ssp_no, xmedia_s32 enable)
{
xmedia_u32 ret = 0;
ssp_readw(ssp_cr1(ssp_no), ret);
if (enable == 0) {
ret = ret & (~0x40);
} else {
ret = (ret & 0xFF) | 0x40;
}
ssp_writew(ssp_cr1(ssp_no), ret);
return 0;
}
static xmedia_u32 xmedia_ssp_is_fifo_busy(xmedia_u32 ssp_no)
{
xmedia_u32 ret = 0;
ssp_readw(ssp_sr(ssp_no), ret);
return (ret & 0x10);
}
static xmedia_u32 xmedia_ssp_is_fifo_empty(xmedia_u32 ssp_no, xmedia_s32 send)
{
xmedia_u32 ret = 0;
ssp_readw(ssp_sr(ssp_no), ret);
if (send != 0) {
if ((ret & 0x1) == 0x1) { /* send fifo */
return 0;
} else {
return 1;
}
} else {
if ((ret & 0x4) == 0x4) { /* receive fifo */
return 0;
} else {
return 1;
}
}
}
/* fsspclkout is fsspclk / (cpsdvsr * (1 + scr)) */
static xmedia_s32 xmedia_ssp_init_cfg(xmedia_u32 ssp_no)
{
const xmedia_u8 framemode = 0;
const xmedia_u8 spo = 1;
const xmedia_u8 sph = 1;
#if SPI_DATAWIDTH_8
const xmedia_u8 datawidth = 8;
#else
const xmedia_u8 datawidth = 16;
#endif
const xmedia_u8 scr = 29; /* scr 4 */
const xmedia_u8 cpsdvsr = 2; /* cpsdvsr 2 */
xmedia_ssp_set_frameform(ssp_no, framemode, spo, sph, datawidth);
xmedia_ssp_set_serialclock(ssp_no, scr, cpsdvsr);
xmedia_ssp_big_end_set(ssp_no);
/* altasens mode, which CS won't be pull high between 16bit data transfer */
xmedia_ssp_alt_mode_set(ssp_no, 0);
return 0;
}
static xmedia_void spi_enable(xmedia_u32 ssp_no)
{
xmedia_u32 ret = 0;
xmedia_ssp_clock_enable(ssp_no);
xmedia_ssp_clock_unreset(ssp_no);
/* little endian */
xmedia_reg_read(ssp_cr1(ssp_no), ret);
ret = (ret & 0xff) | 0x2;
xmedia_reg_write(ssp_cr1(ssp_no), ret); /* 0x2 */
xmedia_ssp_init_cfg(ssp_no);
return;
}
static xmedia_void spi_disable(xmedia_u32 ssp_no)
{
xmedia_u32 ret = 0;
xmedia_reg_read(ssp_cr1(ssp_no), ret);
ret = (ret & 0xff) & (~0x2);
xmedia_reg_write(ssp_cr1(ssp_no), ret); /* 0x0 */
xmedia_ssp_clock_reset(ssp_no);
xmedia_ssp_clock_disable(ssp_no);
return;
}
xmedia_u16 xmedia_msensor_ssp_read_alt(xmedia_s32 dev, xmedia_u8 reg_addr,
xmedia_u8 *reg_data, xmedia_u32 cnt, xmedia_bool fifo_mode)
{
xmedia_u32 ret = 0;
xmedia_ulong flags;
xmedia_s32 ssp_no = 0;
#if SPI_DATAWIDTH_8
xmedia_u8 buf[2] = { 0 }; /* 2 buf */
#else
xmedia_u16 buf_16;
#endif
xmedia_u32 i;
ssp_no = g_dev_ssp_no[dev];
ssp_spin_lock(ssp_no, flags);
spi_enable(ssp_no);
for (i = 0; i < cnt; i++) {
#if SPI_DATAWIDTH_8
if (fifo_mode != XMEDIA_FALSE) {
buf[0] = reg_addr | 0x80;
buf[1] = 0x0;
} else {
buf[0] = (reg_addr + i) | 0x80;
buf[1] = 0x0;
}
ssp_writew(ssp_dr(ssp_no), buf[0]);
ssp_writew(ssp_dr(ssp_no), buf[1]);
#else
if (fifo_mode != XMEDIA_FALSE) {
buf_16 = (reg_addr | 0x80) << 8; /* 8 bit */
} else {
buf_16 = ((reg_addr + i) | 0x80) << 8; /* 8 bit */
}
ssp_writew(ssp_dr(ssp_no), buf_16);
#endif
while (xmedia_ssp_is_fifo_busy(ssp_no) != 0) {
}
while (xmedia_ssp_is_fifo_empty(ssp_no, 1) != 0) {
}
while (xmedia_ssp_is_fifo_empty(ssp_no, 0) != 0) {
}
while (xmedia_ssp_is_fifo_empty(ssp_no, 0) == 0) {
ssp_readw(ssp_dr(ssp_no), ret);
}
reg_data[i] = ret & 0xff;
}
spi_disable(ssp_no);
ssp_spin_unlock(ssp_no, flags);
return 0;
}
xmedia_s32 xmedia_msensor_ssp_write_alt(xmedia_s32 dev, xmedia_u8 reg_addr, const xmedia_u8 *data)
{
xmedia_u32 ret;
xmedia_s32 ssp_no = 0;
xmedia_ulong flags;
#if SPI_DATAWIDTH_8
xmedia_u8 buf[2] = { 0 }; /* 2 buf */
#else
xmedia_u16 buf_16;
#endif
ssp_no = g_dev_ssp_no[dev];
ssp_spin_lock(ssp_no, flags);
spi_enable(ssp_no);
#if SPI_DATAWIDTH_8
buf[0] = reg_addr & (~0x80);
buf[1] = *data;
ssp_writew(ssp_dr(ssp_no), buf[0]);
ssp_writew(ssp_dr(ssp_no), buf[1]);
#else
buf_16 = (reg_addr & (~0x80)) << 8; /* 8 bit */
buf_16 = buf_16 | *data;
ssp_writew(ssp_dr(ssp_no), buf_16);
#endif
while (xmedia_ssp_is_fifo_busy(ssp_no) != 0) {
}
while (xmedia_ssp_is_fifo_empty(ssp_no, 1) != 0) {
}
while (xmedia_ssp_is_fifo_empty(ssp_no, 0) != 0) {
}
while (xmedia_ssp_is_fifo_empty(ssp_no, 0) == 0) {
ssp_readw(ssp_dr(ssp_no), ret);
}
xmedia_unused(ret);
spi_disable(ssp_no);
ssp_spin_unlock(ssp_no, flags);
return 0;
}
// 根据实际使用gpio 正确复用spi 功能管脚
static xmedia_void spi_pin_muxing(xmedia_void)
{
// xm7206 默认使用一路spi spi2
xmedia_reg_write(io1_addr(0x28), 0x1204); /* SPI2_SCLK gpio4_7 打开上拉 */
xmedia_reg_write(io1_addr(0x2c), 0x1004); /* SPI2_SDO gpio5_0 */
xmedia_reg_write(io1_addr(0x30), 0x1004); /* SPI2_CSN gpio5_1 */
xmedia_reg_write(io1_addr(0x34), 0x1004); /* SPI2_SDI gpio5_2 */
ssp_trace(SSP_DBG_INFO, "use spi12\n");
}
static struct file_operations g_ssp_fops = {
.owner = THIS_MODULE,
};
static struct miscdevice g_ssp_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEV_NAME,
.fops = &g_ssp_fops,
};
xmedia_s32 xmedia_msensor_spi_base_addr(xmedia_u32 *base_addr)
{
*base_addr = XM7206_GPIO_BASE;
return XMEDIA_SUCCESS;
}
/*
* initializes SSP interface routine.
* @return value:0--success.
*/
static xmedia_s32 __init xmedia_msensor_ssp_init(xmedia_void)
{
xmedia_s32 ret;
xmedia_u32 ssp_no;
xmedia_u32 spi_base_addr = 0x12345678;
g_reg_ssp_base_va = ioremap((unsigned long)SSP_BASE, (unsigned long)(SSP_SIZE * SSP_DEV_NUM));
if (g_reg_ssp_base_va == XMEDIA_NULL) {
ssp_trace(SSP_DBG_ERR, "ioremap ssp base failed!\n");
return -ENOMEM;
}
g_reg_crg_base_va = ioremap((unsigned long)CRG_BASE, (unsigned long)(CRG_SIZE));
if (g_reg_crg_base_va == XMEDIA_NULL) {
ssp_trace(SSP_DBG_ERR, "ioremap ssp crg failed!\n");
ret = -ENOMEM;
goto err0;
}
ret = xmedia_msensor_spi_base_addr(&spi_base_addr);
if (ret != XMEDIA_SUCCESS) {
goto err1;
}
g_reg_io1_base_va = ioremap((unsigned long)spi_base_addr, (unsigned long)(IO1_SIZE));
if (g_reg_io1_base_va == XMEDIA_NULL) {
ssp_trace(SSP_DBG_ERR, "ioremap ssp io failed!\n");
ret = -ENOMEM;
goto err1;
}
g_reg_spi1_cs_base_va = ioremap((unsigned long)SPI1_CS_BASE_ADDRS, (unsigned long)(CS_SIZE));
if (g_reg_spi1_cs_base_va == XMEDIA_NULL) {
ssp_trace(SSP_DBG_ERR, "ioremap ssp gpio failed!\n");
ret = -ENOMEM;
goto err2;
}
spi_pin_muxing();
ret = misc_register(&g_ssp_dev);
if (ret != XMEDIA_SUCCESS) {
ssp_trace(SSP_DBG_ERR, "register ssp_0 device failed!");
ret = XMEDIA_FAILURE;
goto err3;
}
for (ssp_no = 0; ssp_no < SSP_DEV_NUM; ssp_no++) {
ssp_spin_lock_init(ssp_no);
}
ssp_crg_spin_lock_init();
ssp_trace(SSP_DBG_INFO, "kernel: ssp initial ok!\n");
printk(KERN_INFO "load xm_msensor_spi.ko OK!\n");
return 0;
err3:
iounmap((xmedia_void *)g_reg_spi1_cs_base_va);
g_reg_spi1_cs_base_va = XMEDIA_NULL;
err2:
iounmap((xmedia_void *)g_reg_io1_base_va);
g_reg_io1_base_va = XMEDIA_NULL;
err1:
iounmap((xmedia_void *)g_reg_crg_base_va);
g_reg_crg_base_va = XMEDIA_NULL;
err0:
iounmap((xmedia_void *)g_reg_ssp_base_va);
g_reg_ssp_base_va = XMEDIA_NULL;
return ret;
}
static xmedia_void __exit xmedia_msensor_ssp_exit(xmedia_void)
{
misc_deregister(&g_ssp_dev);
iounmap((xmedia_void *)g_reg_spi1_cs_base_va);
g_reg_spi1_cs_base_va = XMEDIA_NULL;
iounmap((xmedia_void *)g_reg_io1_base_va);
g_reg_io1_base_va = XMEDIA_NULL;
iounmap((xmedia_void *)g_reg_crg_base_va);
g_reg_crg_base_va = XMEDIA_NULL;
iounmap((xmedia_void *)g_reg_ssp_base_va);
g_reg_ssp_base_va = XMEDIA_NULL;
printk(KERN_INFO "unload xm_msensor_spi.ko OK!\n");
}
#ifdef MODULE
EXPORT_SYMBOL(xmedia_msensor_ssp_read_alt);
EXPORT_SYMBOL(xmedia_msensor_ssp_write_alt);
module_init(xmedia_msensor_ssp_init);
module_exit(xmedia_msensor_ssp_exit);
MODULE_DESCRIPTION("ssp driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("otlicon");
#else
int __init msensor_spi_driver_init(void)
{
return xmedia_msensor_ssp_init();
}
#endif
@@ -0,0 +1,40 @@
/*
* Copyright (c); XMEDIA. All rights reserved.
*/
#ifndef __MSENSOR_SPI_H__
#define __MSENSOR_SPI_H__
#include "xmedia_type.h"
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#define SSP_READ_ALT 0x1
#define SSP_WRITE_ALT 0X3
typedef struct {
xmedia_u32 spi_no;
xmedia_u8 dev_addr;
xmedia_u32 dev_byte_num;
xmedia_u32 reg_addr;
xmedia_u32 addr_byte_num;
xmedia_u32 data;
xmedia_u32 data_byte_num;
} spi_data;
xmedia_s32 xmedia_msensor_ssp_write_alt(xmedia_s32 dev, xmedia_u8 reg_addr, const xmedia_u8 *data);
xmedia_u16 xmedia_msensor_ssp_read_alt(xmedia_s32 dev, xmedia_u8 reg_addr,
xmedia_u8 *reg_data, xmedia_u32 cnt, xmedia_bool fifo_mode);
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* end of #ifdef __cplusplus */
#endif