android13/hardware/rockchip/sensor/st/akm09911/AKMD_Driver.c

516 lines
13 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
*
* $Id: AKMD_Driver.c 982 2013-02-08 04:20:37Z miyazaki.hr $
*
* -- Copyright Notice --
*
* Copyright (c) 2004 Asahi Kasei Microdevices Corporation, Japan
* All Rights Reserved.
*
* This software program is the proprietary program of Asahi Kasei Microdevices
* Corporation("AKM") licensed to authorized Licensee under the respective
* agreement between the Licensee and AKM only for use with AKM's electronic
* compass IC.
*
* THIS SOFTWARE IS PROVIDED TO YOU "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABLITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT OF
* THIRD PARTY RIGHTS, AND WE SHALL NOT BE LIABLE FOR ANY LOSSES AND DAMAGES
* WHICH MAY OCCUR THROUGH USE OF THIS SOFTWARE.
*
* -- End Asahi Kasei Microdevices Copyright Notice --
*
******************************************************************************/
#include <fcntl.h>
#include "AKCommon.h" // DBGPRINT()
#include "AKMD_Driver.h"
#include "Acc_mma8452.h"
#define AKM_MEASURE_RETRY_NUM 3
int s_fdDev = -1;
void Android2AK(const float fData[], int16_t data[3]);
/* Include proper acceleration file. */
#ifdef AKMD_ACC_EXTERNAL
#include "Acc_aot.h"
static ACCFNC_INITDEVICE Acc_InitDevice = AOT_InitDevice;
static ACCFNC_DEINITDEVICE Acc_DeinitDevice = AOT_DeinitDevice;
static ACCFNC_SET_ENABLE Acc_SetEnable = AOT_SetEnable;
static ACCFNC_SET_DELAY Acc_SetDelay = AOT_SetDelay;
static ACCFNC_GETACCDATA Acc_GetAccData = AOT_GetAccData;
static ACCFNC_GETACCOFFSET Acc_GetAccOffset = AOT_GetAccOffset;
static ACCFNC_GETACCVEC Acc_GetAccVector = AOT_GetAccVector;
#else
#ifdef AKMD_ACC_ADXL346
#include "Acc_adxl34x.h"
static ACCFNC_INITDEVICE Acc_InitDevice = ADXL_InitDevice;
static ACCFNC_DEINITDEVICE Acc_DeinitDevice = ADXL_DeinitDevice;
static ACCFNC_SET_ENABLE Acc_SetEnable = ADXL_SetEnable;
static ACCFNC_SET_DELAY Acc_SetDelay = ADXL_SetDelay;
static ACCFNC_GETACCDATA Acc_GetAccData = ADXL_GetAccData;
static ACCFNC_GETACCOFFSET Acc_GetAccOffset = ADXL_GetAccOffset;
static ACCFNC_GETACCVEC Acc_GetAccVector = ADXL_GetAccVector;
#endif
#ifdef AKMD_ACC_KXTF9
#include "Acc_kxtf9.h"
static ACCFNC_INITDEVICE Acc_InitDevice = KXTF9_InitDevice;
static ACCFNC_DEINITDEVICE Acc_DeinitDevice = KXTF9_DeinitDevice;
static ACCFNC_SET_ENABLE Acc_SetEnable = KXTF9_SetEnable;
static ACCFNC_SET_DELAY Acc_SetDelay = KXTF9_SetDelay;
static ACCFNC_GETACCDATA Acc_GetAccData = KXTF9_GetAccData;
static ACCFNC_GETACCOFFSET Acc_GetAccOffset = KXTF9_GetAccOffset;
static ACCFNC_GETACCVEC Acc_GetAccVector = KXTF9_GetAccVector;
#endif
#ifdef AKMD_ACC_DUMMY
#include "Acc_dummy.h"
static ACCFNC_INITDEVICE Acc_InitDevice = ACC_DUMMY_InitDevice;
static ACCFNC_DEINITDEVICE Acc_DeinitDevice = ACC_DUMMY_DeinitDevice;
static ACCFNC_SET_ENABLE Acc_SetEnable = ACC_DUMMY_SetEnable;
static ACCFNC_SET_DELAY Acc_SetDelay = ACC_DUMMY_SetDelay;
static ACCFNC_GETACCDATA Acc_GetAccData = ACC_DUMMY_GetAccData;
static ACCFNC_GETACCOFFSET Acc_GetAccOffset = ACC_DUMMY_GetAccOffset;
static ACCFNC_GETACCVEC Acc_GetAccVector = ACC_DUMMY_GetAccVector;
#endif
#endif
/*!
Open device driver.
This function opens both device drivers of magnetic sensor and acceleration
sensor. Additionally, some initial hardware settings are done, such as
measurement range, built-in filter function and etc.
@return If this function succeeds, the return value is #AKD_SUCCESS.
Otherwise the return value is #AKD_FAIL.
*/
int16_t AKD_InitDevice(void)
{
if (s_fdDev < 0) {
// Open magnetic sensor's device driver.
if ((s_fdDev = open("/dev/" AKM_MISCDEV_NAME, O_RDWR)) < 0) {
AKMERROR_STR("open");
goto INIT_FAIL;
}
}
if (Acc_InitDevice() != AKD_SUCCESS) {
goto INIT_FAIL;
}
return AKD_SUCCESS;
INIT_FAIL:
AKD_DeinitDevice();
return AKD_FAIL;
}
/*!
Close device driver.
This function closes both device drivers of magnetic sensor and acceleration
sensor.
*/
void AKD_DeinitDevice(void)
{
if (s_fdDev >= 0) {
close(s_fdDev);
s_fdDev = -1;
}
Acc_DeinitDevice();
}
/*!
Writes data to a register of the AKM E-Compass. When more than one byte of
data is specified, the data is written in contiguous locations starting at an
address specified in \a address.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[in] address Specify the address of a register in which data is to be
written.
@param[in] data Specify data to write or a pointer to a data array containing
the data. When specifying more than one byte of data, specify the starting
address of the array.
@param[in] numberOfBytesToWrite Specify the number of bytes that make up the
data to write. When a pointer to an array is specified in data, this argument
equals the number of elements of the array.
*/
int16_t AKD_TxData(
const BYTE address,
const BYTE * data,
const uint16_t numberOfBytesToWrite)
{
int i;
char buf[AKM_RWBUF_SIZE];
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (numberOfBytesToWrite > (AKM_RWBUF_SIZE-2)) {
AKMERROR;
return AKD_FAIL;
}
buf[0] = numberOfBytesToWrite + 1;
buf[1] = address;
for (i = 0; i < numberOfBytesToWrite; i++) {
buf[i + 2] = data[i];
}
if (ioctl(s_fdDev, ECS_IOCTL_WRITE, buf) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
} else {
#if ENABLE_AKMDEBUG
AKMDEBUG(AKMDBG_MAGDRV, "addr(HEX)=%02x data(HEX)=", address);
for (i = 0; i < numberOfBytesToWrite; i++) {
AKMDEBUG(AKMDBG_MAGDRV, " %02x", data[i]);
}
AKMDEBUG(AKMDBG_MAGDRV, "\n");
#endif
return AKD_SUCCESS;
}
}
/*!
Acquires data from a register or the EEPROM of the AKM E-Compass.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[in] address Specify the address of a register from which data is to be
read.
@param[out] data Specify a pointer to a data array which the read data are
stored.
@param[in] numberOfBytesToRead Specify the number of bytes that make up the
data to read. When a pointer to an array is specified in data, this argument
equals the number of elements of the array.
*/
int16_t AKD_RxData(
const BYTE address,
BYTE * data,
const uint16_t numberOfBytesToRead)
{
int i;
char buf[AKM_RWBUF_SIZE];
memset(data, 0, numberOfBytesToRead);
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (numberOfBytesToRead > (AKM_RWBUF_SIZE-1)) {
AKMERROR;
return AKD_FAIL;
}
buf[0] = numberOfBytesToRead;
buf[1] = address;
if (ioctl(s_fdDev, ECS_IOCTL_READ, buf) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
} else {
for (i = 0; i < numberOfBytesToRead; i++) {
data[i] = buf[i + 1];
}
#if ENABLE_AKMDEBUG
AKMDEBUG(AKMDBG_MAGDRV, "addr(HEX)=%02x len=%d data(HEX)=",
address, numberOfBytesToRead);
for (i = 0; i < numberOfBytesToRead; i++) {
AKMDEBUG(AKMDBG_MAGDRV, " %02x", data[i]);
}
AKMDEBUG(AKMDBG_MAGDRV, "\n");
#endif
return AKD_SUCCESS;
}
}
/*!
Reset the e-compass.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
*/
int16_t AKD_Reset(void) {
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_RESET, NULL) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Get magnetic sensor information from device. This function returns WIA value.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] data An information data array. The size should be larger than
#AKM_SENSOR_INFO_SIZE
*/
int16_t AKD_GetSensorInfo(BYTE data[AKM_SENSOR_INFO_SIZE])
{
memset(data, 0, AKM_SENSOR_INFO_SIZE);
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_GET_INFO, data) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Get magnetic sensor configuration from device. This function returns ASA value.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] data An configuration data array. The size should be larger than
#AKM_SENSOR_CONF_SIZE
*/
int16_t AKD_GetSensorConf(BYTE data[AKM_SENSOR_CONF_SIZE])
{
memset(data, 0, AKM_SENSOR_CONF_SIZE);
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_GET_CONF, data) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Acquire magnetic data from AKM E-Compass. If measurement is not done, this
function waits until measurement completion.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] data A magnetic data array. The size should be larger than
#AKM_SENSOR_DATA_SIZE.
*/
int16_t AKD_GetMagneticData(BYTE data[AKM_SENSOR_DATA_SIZE])
{
int ret;
int i;
memset(data, 0, AKM_SENSOR_DATA_SIZE);
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
for (i = 0; i < AKM_MEASURE_RETRY_NUM; i++) {
ret = ioctl(s_fdDev, ECS_IOCTL_GETDATA, data);
if (ret >= 0) {
/* Success */
break;
}
if (errno != EAGAIN) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
AKMDEBUG(AKMDBG_MAGDRV, "Try Again.");
usleep(AKM_MEASURE_TIME_US);
}
if (i >= AKM_MEASURE_RETRY_NUM) {
AKMERROR;
return AKD_FAIL;
}
AKMDEBUG(AKMDBG_MAGDRV,
"bdata(HEX)= %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8]);
return AKD_SUCCESS;
}
/*!
Set calculated data to device driver.
@param[in] buf
*/
void AKD_SetYPR(const int buf[AKM_YPR_DATA_SIZE])
{
if (s_fdDev < 0) {
AKMERROR;
return;
}
if (ioctl(s_fdDev, ECS_IOCTL_SET_YPR, buf) < 0) {
AKMERROR_STR("ioctl");
}
}
/*!
*/
int16_t AKD_GetOpenStatus(int* status)
{
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_GET_OPEN_STATUS, status) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
*/
int16_t AKD_GetCloseStatus(int* status)
{
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_GET_CLOSE_STATUS, status) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Set AKM E-Compass to the specific mode.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[in] mode This value should be one of the AKM_MODE which is defined in
header file.
*/
int16_t AKD_SetMode(const BYTE mode)
{
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_SET_MODE, & mode) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Acquire delay
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] delay A delay in microsecond.
*/
int16_t AKD_GetDelay(int64_t delay[AKM_NUM_SENSORS])
{
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_GET_DELAY, delay) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Get layout information from device driver, i.e. platform data.
*/
int16_t AKD_GetLayout(int16_t* layout)
{
char tmp;
if (s_fdDev < 0) {
AKMERROR;
return AKD_FAIL;
}
if (ioctl(s_fdDev, ECS_IOCTL_GET_LAYOUT, &tmp) < 0) {
AKMERROR_STR("ioctl");
return AKD_FAIL;
}
*layout = tmp;
return AKD_SUCCESS;
}
/*! */
int16_t AKD_AccSetEnable(int8_t enabled)
{
return Acc_SetEnable(enabled);
}
/*! */
int16_t AKD_AccSetDelay(int64_t delay)
{
return Acc_SetDelay(delay);
}
#if 0
/*! */
int16_t AKD_GetAccelerationData(int16_t data[3])
{
return Acc_GetAccData(data);
}
#endif
/*! */
int16_t AKD_GetAccelerationOffset(int16_t offset[3])
{
return Acc_GetAccOffset(offset);
}
/*! */
void AKD_GetAccelerationVector(
const int16_t data[3],
const int16_t offset[3],
int16_t vec[3])
{
Acc_GetAccVector(data, offset, vec);
}
/*!
Acquire acceleration data from acceleration sensor.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] data A acceleration data array. The coordinate system of the
acquired data follows the definition of AK.
*/
int16_t AKD_GetAccelerationData(int16_t data[3])
{
float fData[3];
if (Acc_GetAccelerationData(fData) != AKD_SUCCESS) {
return AKD_FAIL;
} else {
Android2AK(fData, data);
return AKD_SUCCESS;
}
}
/*!
Convert Acceleration sensor coordinate system from Android's one to AK's one.
In Android coordinate system, 1G = 9.8f (m/s^2). In AK coordinate system,
1G = 720 (LSB).
@param[in] fData A acceleration data array. The coordinate system of this data
should follows the definition of Android.
@param[out] data A acceleration data array. The coordinate system of the
acquired data follows the definition of AK.
*/
void Android2AK(const float fData[], int16_t data[3])
{
/*
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> AKSC_DirectionS3() <20><> acc <20><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9> SmartCompass <20><><EFBFBD><EFBFBD>ϵ, ...
* .! : <20><><EFBFBD><EFBFBD> acc <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EAB6A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7>.
*/
data[0] = fData[0] / 9.8f * 720;
data[1] = fData[1] / 9.8f * 720;
data[2] = fData[2] / 9.8f * 720;
}