/****************************************************************************** * $Id: AK8975Driver.c 580 2012-03-29 09:56:21Z yamada.rj $ ****************************************************************************** * * Copyright (C) 2012 Asahi Kasei Microdevices Corporation, Japan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <fcntl.h> #include "AKFS_Common.h" #include "AK8975Driver.h" #define MSENSOR_NAME "/dev/akm8975_dev" static int s_fdDev = -1; /*! 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(MSENSOR_NAME, O_RDWR)) < 0) { AKMERROR_STR("open"); return AKD_FAIL; } } return AKD_SUCCESS; } /*! 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; } } /*! Writes data to a register of the AK8975. 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[RWBUF_SIZE]; if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (numberOfBytesToWrite > (RWBUF_SIZE-2)) { ALOGE("%s: Tx size is too large.", __FUNCTION__); 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 AKMDATA(AKMDATA_DRV, "addr(HEX)=%02x data(HEX)=", address); for (i = 0; i < numberOfBytesToWrite; i++) { AKMDATA(AKMDATA_DRV, " %02x", data[i]); } AKMDATA(AKMDATA_DRV, "\n"); #endif return AKD_SUCCESS; } } /*! Acquires data from a register or the EEPROM of the AK8975. @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[RWBUF_SIZE]; memset(data, 0, numberOfBytesToRead); if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (numberOfBytesToRead > (RWBUF_SIZE-1)) { ALOGE("%s: Rx size is too large.", __FUNCTION__); 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 AKMDATA(AKMDATA_DRV, "addr(HEX)=%02x len=%d data(HEX)=", address, numberOfBytesToRead); for (i = 0; i < numberOfBytesToRead; i++) { AKMDATA(AKMDATA_DRV, " %02x", data[i]); } AKMDATA(AKMDATA_DRV, "\n"); #endif return AKD_SUCCESS; } } /*! Acquire magnetic data from AK8975. 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 #SENSOR_DATA_SIZE. */ int16_t AKD_GetMagneticData(BYTE data[SENSOR_DATA_SIZE]) { memset(data, 0, SENSOR_DATA_SIZE); if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (ioctl(s_fdDev, ECS_IOCTL_GETDATA, data) < 0) { AKMERROR_STR("ioctl"); return AKD_FAIL; } AKMDATA(AKMDATA_DRV, "bdata(HEX)= %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]); return AKD_SUCCESS; } /*! Set calculated data to device driver. @param[in] buf The order of input data depends on driver's specification. */ void AKD_SetYPR(const int buf[YPR_DATA_SIZE]) { if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); } else { if (ioctl(s_fdDev, ECS_IOCTL_SET_YPR, buf) < 0) { AKMERROR_STR("ioctl"); } } } /*! */ int AKD_GetOpenStatus(int* status) { if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (ioctl(s_fdDev, ECS_IOCTL_GET_OPEN_STATUS, status) < 0) { AKMERROR_STR("ioctl"); return AKD_FAIL; } return AKD_SUCCESS; } /*! */ int AKD_GetCloseStatus(int* status) { if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (ioctl(s_fdDev, ECS_IOCTL_GET_CLOSE_STATUS, status) < 0) { AKMERROR_STR("ioctl"); return AKD_FAIL; } return AKD_SUCCESS; } /*! Set AK8975 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 AK8975_Mode which is defined in akm8975.h file. */ int16_t AKD_SetMode(const BYTE mode) { if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); 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 nanosecond. */ int16_t AKD_GetDelay(int64_t delay[AKM_NUM_SENSORS]) { if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.\n", __FUNCTION__); 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) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (ioctl(s_fdDev, ECS_IOCTL_GET_LAYOUT, &tmp) < 0) { AKMERROR_STR("ioctl"); return AKD_FAIL; } *layout = tmp; return AKD_SUCCESS; } /* Get acceleration data. */ int16_t AKD_GetAccelerationData(int16_t data[3]) { if (s_fdDev < 0) { ALOGE("%s: Device file is not opened.", __FUNCTION__); return AKD_FAIL; } if (ioctl(s_fdDev, ECS_IOCTL_GET_ACCEL, data) < 0) { AKMERROR_STR("ioctl"); return AKD_FAIL; } AKMDATA(AKMDATA_DRV, "%s: acc=%d, %d, %d\n", __FUNCTION__, data[0], data[1], data[2]); return AKD_SUCCESS; }