ST各类传感器MCU驱动程序总资源包
资源包:包含内容:
folderpart numberMEMS type
AccAIS328DQ三轴加速度计(车规)
H3LIS331DL三轴加速度计(high g)
LIS2DE12三轴加速度计
LIS2DH12三轴加速度计
LIS2DS12三轴加速度计(计步)
LIS2DW12三轴加速度计(低功耗)
LIS2HH12三轴加速度计
LIS3DSH三轴加速度计
Acc_GyroLSM6DS0加速度+陀螺仪
LSM6DS3加速度+陀螺仪
LSM6DSL加速度+陀螺仪
LSM6DSO加速度+陀螺仪
LSM330加速度+陀螺仪
Acc_MagLSM303AH加速度+磁力计
LSM303C加速度+磁力计
AmbientHTS221温湿度传感器
LPS22HB气压传感器
LPS25HB气压传感器
LPS35HW气压传感器(防水)
GyroA3G4250D三轴陀螺仪(车规)
L3GD20H三轴陀螺仪
MagLIS2MDL磁力计
LIS3MDL磁力计
资源包未包含相关资源更新记录
LSM6DSL(加速度+陀螺仪)驱动例程ver1.8
LIS2DH12(三轴加速度计)驱动例程ver2.3
LPS22HB(气压传感器)驱动例程ver1.2
LIS2MDL(磁力计)驱动例程ver1.2
LIS3MDL(磁力计)驱动例程ver1.3
:),支持一下,收下备用。 看了一个,这个驱动太毕了{:1_103:}{:1_103:}
/******************** (C) COPYRIGHT 2016 STMicroelectronics ********************
* File Name : main_LIS3DSH_example_.c
* Author : MEMS Application Team
* Version : v1.1
* Date : 05 May 2016
* Description : EKSTM32 main file
*
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
//include files for MKI109V1 board
#include "stm32f10x.h"
#include "i2c_mems.h"
#include "hw_config.h"
//include MEMS driver
#include "LIS3DSH_ACC_driver.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void Function_Error(void);
/*******************************************************************************
* Function Name: main.
* Description : Main routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int main(void)
{
u8_t dummy=0;
Type3Axis16bit_U data;
//Initialize your hardware here
//function for MKI109V1 board
InitHardware();
I2C_MEMS_Init();
//Get device information to check
if(! LIS3DSH_ACC_GetWHO_AM_I(0, &dummy))
Function_Error();
if ( dummy != LIS3DSH_ACC_I_AM_LIS3DSH )
Function_Error();
//Set device parameter
if(! LIS3DSH_ACC_SetFullScale(0, LIS3DSH_ACC_FULLSCALE_2))
Function_Error();
if(! LIS3DSH_ACC_SetAxis(0, LIS3DSH_ACC_X_ENABLE | LIS3DSH_ACC_Y_ENABLE | LIS3DSH_ACC_Z_ENABLE))
Function_Error();
if(!LIS3DSH_ACC_SetODR(0, LIS3DSH_ACC_ODR_3_125))
Function_Error();
while(1){
//Get Device Status
if(! LIS3DSH_ACC_GetSatusReg(0, &dummy))
Function_Error();
//Check if new data are available
if ( dummy&LIS3DSH_ACC_STATUS_REG_ZYXDA ){
//Get new data
if(! LIS3DSH_ACC_GetAccAxesRaw(0, &data))
Function_Error();
}
}
} // end main
/*******************************************************************************
* Function Name: Function_Error
* Description : Generic Error function
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Function_Error(void)
{
while(1);
}
//function for MKI109V1 board
#ifdef USE_FULL_ASSERT
/*******************************************************************************
* Function Name: assert_failed
* Description : Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* Input : - file: pointer to the source file name
* - line: assert_param error line source number
* Output : None
* Return : None
*******************************************************************************/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{}
}
#endif
/******************* (C) COPYRIGHT 2013 STMicroelectronics *****END OF FILE****/
/******************** (C) COPYRIGHT 2016 STMicroelectronics ********************
* File Name : LIS3DSH_ACC_driver.c
* Author : MEMS Application Team
* Version : v1.1
* Date : 05 Maggio 2016
* Description : LIS3DSH Platform Independent Driver
*
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "LIS3DSH_ACC_driver.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/************** Generic Function*******************/
/*******************************************************************************
* Function Name : LIS3DSH_ACC_ReadReg
* Description : Generic Reading function. It must be fullfilled with either
* : I2C or SPI reading functions
* Input : Register Address
* Output : Data REad
* Return : None
*******************************************************************************/
status_t LIS3DSH_ACC_ReadReg(void *handle, u8_t Reg, u8_t *Bufp, u16_t len)
{
//To be completed with either I2c or SPI writing function
//i.e.: SPI_Mems_Write_Reg(Reg, Data);
//I2Cx_Read(Bufp, LIS3DSH_ACC_I2C_ADDRESS_HIGH, Reg, len); //
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name : LIS3DSH_ACC_WriteReg
* Description : Generic Writing function. It must be fullfilled with either
* : I2C or SPI writing function
* Input : Register Address, Data to be written
* Output : None
* Return : None
*******************************************************************************/
status_t LIS3DSH_ACC_WriteReg(void *handle, u8_t Reg, u8_t *Bufp, u16_t len)
{
//To be completed with either I2c or SPI writing function
//i.e.: SPI_Mems_Write_Reg(Reg, Data);
//I2Cx_Write(Bufp, LIS3DSH_ACC_I2C_ADDRESS_HIGH, Reg, len); //
return MEMS_SUCCESS;
}
/**************** Base Function*******************/
/*******************************************************************************
* Function Name: GetWHO_AM_I
* Description : Read identification code by WHO_AM_I register
* Input : Char to empty by Device identification Value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetWHO_AM_I(void *handle, u8_t* val){
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_WHO_AM_I, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetOUT_T
* Description : Read temperature register 1LSB/deg (00h = 25degC)
* Input : Char to empty by temperature value (8bit 2's complement)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetOUT_T(void *handle, u8_t* val){
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_T, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetODR
* Description : Sets Output Data Rate
* Input : Output Data Rate typedef
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetODR(void *handle, LIS3DSH_ACC_ODR_t ov){
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL4, &value, 1) )
return MEMS_ERROR;
value &= 0x0f;
value |= ov<<LIS3DSH_ACC_ODR_BIT;
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL4, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetAxis
* Description : Enable/Disable Acc. Axis
* Input : X_ENABLE/X_DISABLE | Y_ENABLE/Y_DISABLE | Z_ENABLE/Z_DISABLE
* Output : None
* Note : You MUST use all input variable in the argument
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetAxis(void *handle, LIS3DSH_ACC_Axis_t axis) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL4, &value, 1) )
return MEMS_ERROR;
value &= 0xF8;
value |= (0x07 & axis);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL4, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetFullScale
* Description : Set FullScale by typedef definition
* Input : FULLSCALE_2/FULLSCALE_4/FULLSCALE_8/FULLSCALE_16
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetFullScale(void *handle, LIS3DSH_ACC_Fullscale_t fs) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
value &= 0xC7;
value |= (fs<<LIS3DSH_ACC_FSCALE);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetBDU
* Description : Enable/Disable Block Data Update Functionality
* Input : ENABLE/DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetBDU(void *handle, LIS3DSH_ACC_State_t bdu) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL4, &value, 1) )
return MEMS_ERROR;
value &= 0xF7;
value |= (bdu<<LIS3DSH_ACC_BDU);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL4, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetSelfTest
* Description : Set Self Test Modality
* Input : SELF_TEST_NORMAL/SELF_TEST_POSITIVE/SELF_TEST_NEGATIVE...
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetSelfTest(void *handle, LIS3DSH_ACC_SelfTest_t st) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
value &= 0xF9;
value |= (st<<LIS3DSH_ACC_ST);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: BandWidth
* Description : Set BandWidth filter by typedef definition
* Input : BANDWIDTH_1/BANDWIDTH_2/BANDWIDTH_3...
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_BandWidth(void *handle, LIS3DSH_ACC_BandWidth_t bw) {
u8_t value;
bw &= 0x03;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
value &= 0x3F;
value |= (bw<<LIS3DSH_ACC_BW);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: Int1Enable
* Description : Set Interrupt1 Enable-Disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_Int1Enable(void *handle, LIS3DSH_ACC_State_t conf) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0xF7;
value |= (conf<<LIS3DSH_ACC_INT1_EN);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: Int2Enable
* Description : Set Interrupt2 Enable-Disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_Int2Enable(void *handle, LIS3DSH_ACC_State_t conf) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0xEF;
value |= (conf<<LIS3DSH_ACC_INT2_EN);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: IntLatchEnable
* Description : Enable Interrupt Latching function
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_IntLatchEnable(void *handle, LIS3DSH_ACC_State_t latch) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0xDF;
value |= (latch<<LIS3DSH_ACC_IEL);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: IntSignPol
* Description : Interrupt Polarity
* Input : POL_HIGH/POL_LOW
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_IntSignPol(void *handle, LIS3DSH_ACC_Polarity_t pol) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0xDF;
value |= (pol<<LIS3DSH_ACC_IEA);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: DataReadyInt
* Description : Data ready connect to interrupt 1 Enable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_DataReadyInt(void *handle, LIS3DSH_ACC_State_t drdy) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0x7F;
value |= (drdy<<LIS3DSH_ACC_DR_EN);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: ReBootEnable
* Description : Force Reboot
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_ReBootEnable(void *handle, LIS3DSH_ACC_State_t boot) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
value &= 0x7F;
value |= (boot<<LIS3DSH_ACC_BOOT);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: FIFOEnable
* Description : FIFO enable/disable
* Input : MEMS_ENABLE/MEMS_DISABLE, n max sample in FIFO (must be < 30)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_FIFOEnable(void *handle, LIS3DSH_ACC_State_t fifo, u8_t nMax) {
u8_t value;
//check n max of sample in FIFO
if(nMax > 30) return MEMS_ERROR;
//only stream mode fifo
if(! LIS3DSH_ACC_FIFOMode(handle, LIS3DSH_ACC_FIFO_STREAM_MODE))
return MEMS_ERROR;
//set WTM > n sample in FIFO
if(! LIS3DSH_ACC_SetWaterMark(handle, nMax))
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
value &= 0xBF;
value |= (fifo<<LIS3DSH_ACC_FIFO_EN);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: FIFOMode
* Description : Sets FIFO Modality
* Input : FIFO_BYPASS_MODE, FIFO_MODE...
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_FIFOMode(void *handle, LIS3DSH_ACC_FifoMode_t fm) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_FIFO_CTRL, &value, 1) )
return MEMS_ERROR;
value &= 0x1f;
value |= (fm<<LIS3DSH_ACC_FMODE);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_FIFO_CTRL, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetWaterMark
* Description : Sets Watermark Value
* Input : Watermark =
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetWaterMark(void *handle, u8_t wtm) {
u8_t value;
if(wtm > 31)
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_FIFO_CTRL, &value, 1) )
return MEMS_ERROR;
value &= 0xE0;
value |= wtm;
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_FIFO_CTRL, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: AddIncEnable
* Description : Register address increment (during multiple byte access) enable/disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_AddIncEnable(void *handle, LIS3DSH_ACC_State_t addinc) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
value &= 0xEF;
value |= (addinc<<LIS3DSH_ACC_ADD_INC);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: FifoEmptyInt1
* Description : FIFO empty indication on INT1 enable/disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_FifoEmptyInt1(void *handle, LIS3DSH_ACC_State_t empty) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
value &= 0xF7;
value |= (empty<<LIS3DSH_ACC_I1_EMPTY);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: FifoOvrInt1
* Description : FIFO Overrun interrupt on INT1 enable/disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_FifoOvrInt1(void *handle, LIS3DSH_ACC_State_t overrun) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
value &= 0xFD;
value |= (overrun<<LIS3DSH_ACC_I1_OVERRUN);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: BootInt2
* Description : Boot Interrupt on INT2 enable/disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_BootInt2(void *handle, LIS3DSH_ACC_State_t booti2) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
value &= 0xFE;
value |= (booti2<<LIS3DSH_ACC_I2_BOOT);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL6, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: VectFiltEnable
* Description : Vector Filter Enable-Disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_VectFiltEnable(void *handle, LIS3DSH_ACC_State_t vfe) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0x7F;
value |= (vfe<<LIS3DSH_ACC_VFILT);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SoftReset
* Description : Soft Reset BIT Enable-Disable
* Input : MEMS_ENABLE/MEMS_DISABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SoftReset(void *handle, LIS3DSH_ACC_State_t strt) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
value &= 0xFE;
value |= (strt<<LIS3DSH_ACC_STRT);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL3, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetOFFSET
* Description : Set offset Value
* Input : AXIS: SET_AXIS_X/SET_AXSIS_Y/SET_AXIS_Z, Offest value =
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetOFFSET(void *handle, LIS3DSH_ACC_SET_AXIS_t axis, u8_t val) {
u8_t reg=0;
if(!((axis==LIS3DSH_ACC_SET_AXIS_X)||(axis==LIS3DSH_ACC_SET_AXIS_Y)||(axis==LIS3DSH_ACC_SET_AXIS_Z)))
return MEMS_ERROR;
switch(axis){
case LIS3DSH_ACC_SET_AXIS_X: reg=LIS3DSH_ACC_OFF_X; break;
case LIS3DSH_ACC_SET_AXIS_Y: reg=LIS3DSH_ACC_OFF_Y; break;
case LIS3DSH_ACC_SET_AXIS_Z: reg=LIS3DSH_ACC_OFF_Z; break;
}
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetCS
* Description : Set Constant Shift Value
* Input : AXIS: SET_AXIS_X/SET_AXSIS_Y/SET_AXIS_Z, Constant shift value =
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetCS(void *handle, LIS3DSH_ACC_SET_AXIS_t axis, u8_t val) {
u8_t reg=0;
if(!((axis==LIS3DSH_ACC_SET_AXIS_X)||(axis==LIS3DSH_ACC_SET_AXIS_Y)||(axis==LIS3DSH_ACC_SET_AXIS_Z)))
return MEMS_ERROR;
switch(axis){
case LIS3DSH_ACC_SET_AXIS_X: reg=LIS3DSH_ACC_CS_X; break;
case LIS3DSH_ACC_SET_AXIS_Y: reg=LIS3DSH_ACC_CS_Y; break;
case LIS3DSH_ACC_SET_AXIS_Z: reg=LIS3DSH_ACC_CS_Z; break;
}
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetLC
* Description : Set Long Counter Register Value
* Input : Long Counter 16Bit value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetLC(void *handle, u16_t val) {
u8_t val_L=0;
u8_t val_H=0;
val_L = (u8_t) (val & 0x00FF);
val_H = (u8_t) ((val & 0xFF00)>>8);
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_LC_L, &val_L, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_LC_H, &val_H, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetLC
* Description : Get Long Counter Register Value
* Input : 16Bit Variable to empty by Counter value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetLC(void *handle, i16_t* val) {
u8_t val_L=0;
u8_t val_H=0;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_LC_L, &val_L, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_LC_H, &val_H, 1) )
return MEMS_ERROR;
*val = (i16_t)((val_H<<8) + val_L);
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetVectorCoeff
* Description : Set Vector Coefficient Value for Differential filter
* Input : SET_VFC_1/SET_VFC_2/SET_VFC_3, Coefficient value =
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetVectorCoeff(void *handle, LIS3DSH_ACC_SET_VFC_t vfc, u8_t val) {
u8_t reg=0;
if(!((vfc==LIS3DSH_ACC_SET_VFC_1)||(vfc==LIS3DSH_ACC_SET_VFC_2)||(vfc==LIS3DSH_ACC_SET_VFC_3)||(vfc==LIS3DSH_ACC_SET_VFC_4)))
return MEMS_ERROR;
switch(vfc){
case LIS3DSH_ACC_SET_VFC_1: reg=LIS3DSH_ACC_VFC_1; break;
case LIS3DSH_ACC_SET_VFC_2: reg=LIS3DSH_ACC_VFC_2; break;
case LIS3DSH_ACC_SET_VFC_3: reg=LIS3DSH_ACC_VFC_3; break;
case LIS3DSH_ACC_SET_VFC_4: reg=LIS3DSH_ACC_VFC_4; break;
}
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetVectorCoeff
* Description : Get Vector Coefficient Value for Differential filter
* Input : SET_VFC_1/SET_VFC_2/SET_VFC_3, variable to empty
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetVectorCoeff(void *handle, LIS3DSH_ACC_SET_VFC_t vfc, u8_t* val) {
u8_t reg;
if(!((vfc==LIS3DSH_ACC_SET_VFC_1)||(vfc==LIS3DSH_ACC_SET_VFC_2)||(vfc==LIS3DSH_ACC_SET_VFC_3)||(vfc==LIS3DSH_ACC_SET_VFC_4)))
return MEMS_ERROR;
switch(vfc){
case LIS3DSH_ACC_SET_VFC_1: reg = LIS3DSH_ACC_VFC_1; break;
case LIS3DSH_ACC_SET_VFC_2: reg = LIS3DSH_ACC_VFC_2; break;
case LIS3DSH_ACC_SET_VFC_3: reg = LIS3DSH_ACC_VFC_3; break;
case LIS3DSH_ACC_SET_VFC_4: reg = LIS3DSH_ACC_VFC_4; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetThrs3
* Description : set Threshold3 Coefficient Value
* Input : Value of threshold
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetThrs3(void *handle, u8_t val) {
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_THRS3, &val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetThrs3
* Description : Get Threshold3 Coefficient Value
* Input : Variable to empty
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetThrs3(void *handle, u8_t* val) {
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_THRS3, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetThrsSM
* Description : Get Threshold 1 or 2 by SM1 or SM2
* Input : SM1/SM2, THRS1/THRS2, Variable to empty
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetThrsSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_THRS_t thrs, u8_t* val) {
u8_t reg=0;
switch(thrs){
case LIS3DSH_ACC_THRS_1:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_THRS1_1;
else reg = LIS3DSH_ACC_THRS1_2;
break;
case LIS3DSH_ACC_THRS_2:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_THRS2_1;
else reg = LIS3DSH_ACC_THRS2_2;
break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetThrsSM
* Description : Set Threshold 1 or 2 for SM1 or SM2
* Input : SM1/SM2, THRS1/THRS2, Threshold Value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetThrsSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_THRS_t thrs, u8_t val) {
u8_t reg=0;
switch(thrs){
case LIS3DSH_ACC_THRS_1:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_THRS1_1;
else reg = LIS3DSH_ACC_THRS1_2;
break;
case LIS3DSH_ACC_THRS_2:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_THRS2_1;
else reg = LIS3DSH_ACC_THRS2_2;
break;
}
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetTimerSM
* Description : Set Timer 1(16bit),2(16bit),3(8bit),4(8bit) for SM1 or SM2
* Input : SM1/SM2, TIM1/TIM2..., Timer Value (8bit or 16bit)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetTimerSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_TIM_t timer, u16_t val) {
u8_t reg=0;
u8_t val_L=0;
u8_t val_H=0;
switch(timer){
case LIS3DSH_ACC_TIM_1:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_TIM1_1_L;
else reg = LIS3DSH_ACC_TIM1_2_L;
break;
case LIS3DSH_ACC_TIM_2:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_TIM2_1_L;
else reg = LIS3DSH_ACC_TIM2_2_L;
break;
case LIS3DSH_ACC_TIM_3:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_TIM3_1;
else reg = LIS3DSH_ACC_TIM3_2;
break;
case LIS3DSH_ACC_TIM_4:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_TIM4_1;
else reg = LIS3DSH_ACC_TIM4_2;
break;
}
//for 8bit register
if((timer==LIS3DSH_ACC_TIM_3)||(timer==LIS3DSH_ACC_TIM_4)){
val_L = (u8_t) val;
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val_L, 1) )
return MEMS_ERROR;
}
//for 16bit register
else{
val_L = (u8_t)val;
val_H = (u8_t) (val>>8);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val_L, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_WriteReg(handle, reg+1, &val_H, 1) )
return MEMS_ERROR;
}
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetMaskSM
* Description : Set Mask A or B for SM1 or SM2
* Input : SM1/SM2, MASK_A/MASK_B, Mask Value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetMaskSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_MASK_t mask, u8_t val) {
u8_t reg=0;
switch(mask){
case LIS3DSH_ACC_MASK_A:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_MASKA_1;
else reg = LIS3DSH_ACC_MASKA_2;
break;
case LIS3DSH_ACC_MASK_B:if(sm==LIS3DSH_ACC_SM1) reg = LIS3DSH_ACC_MASKB_1;
else reg = LIS3DSH_ACC_MASKB_2;
break;
}
if( !LIS3DSH_ACC_WriteReg(handle, reg, &val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetProgPointSM
* Description : Get Program pointer for SM1 or SM2
* Input : Byte to empty by Program pointer value (4bit)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetProgPointSM(void *handle, LIS3DSH_ACC_SM_t sm, u8_t* val) {
u8_t reg=0;
switch(sm){
case LIS3DSH_ACC_SM1 : reg = LIS3DSH_ACC_PR1; break;
case LIS3DSH_ACC_SM2 : reg = LIS3DSH_ACC_PR2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, val, 1) )
return MEMS_ERROR;
*val = (*val & 0xF0) >> 4;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetResetPointSM
* Description : Get Reset pointer for SM1 or SM2
* Input : Byte to empty by Reset pointer value (4bit)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetResetPointSM(void *handle, LIS3DSH_ACC_SM_t sm, u8_t* val) {
u8_t reg=0;
switch(sm){
case LIS3DSH_ACC_SM1 : reg = LIS3DSH_ACC_PR1; break;
case LIS3DSH_ACC_SM2 : reg = LIS3DSH_ACC_PR2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, val, 1) )
return MEMS_ERROR;
*val = (*val & 0x0F);
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetTCSM
* Description : Get 16bit general Timer Value for SM1 or SM2
* Input : SM1/SM2, 16bit Variable to empty by timer value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetTCSM(void *handle, LIS3DSH_ACC_SM_t sm, u16_t* val) {
u8_t val_L=0;
u8_t val_H=0;
u8_t reg=0;
switch(sm){
case LIS3DSH_ACC_SM1: reg = LIS3DSH_ACC_TC1_L;break;
case LIS3DSH_ACC_SM2: reg = LIS3DSH_ACC_TC2_L;break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &val_L, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, reg+1, &val_H, 1) )
return MEMS_ERROR;
*val = (u16_t)((val_H<<8) + val_L);
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetOutSBitSM
* Description : Read the output flags for interrupt by SM1 or SM2
* Input : Out interrupt Bit to read (P_X/P_Y/N_Z/N_V....)
* Output : None
* Return : Status of BIT
*******************************************************************************/
status_t LIS3DSH_ACC_GetOutSBitSM(void *handle, LIS3DSH_ACC_SM_t sm, u8_t FLAG_INT_OUT) {
u8_t value;
u8_t reg;
switch(sm){
case LIS3DSH_ACC_SM1: reg = LIS3DSH_ACC_OUTS1;break;
case LIS3DSH_ACC_SM2: reg = LIS3DSH_ACC_OUTS2;break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
switch (FLAG_INT_OUT){
case LIS3DSH_ACC_F_P_X : if(value & LIS3DSH_ACC_F_P_X) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_N_X : if(value & LIS3DSH_ACC_F_N_X) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_P_Y : if(value & LIS3DSH_ACC_F_P_Y) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_N_Y : if(value & LIS3DSH_ACC_F_N_Y) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_P_Z : if(value & LIS3DSH_ACC_F_P_Z) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_N_Z : if(value & LIS3DSH_ACC_F_N_Z) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_P_V : if(value & LIS3DSH_ACC_F_P_V) return MEMS_SUCCESS;
else return MEMS_ERROR;
case LIS3DSH_ACC_F_N_V : if(value & LIS3DSH_ACC_F_N_V) return MEMS_SUCCESS;
else return MEMS_ERROR;
}
return MEMS_ERROR;
}
/*******************************************************************************
* Function Name: GetPeakSM
* Description : Read the Peak detection Register value by SM1 or SM2
* Input : SM1/SM2, Variable (8bit) to empty by Peak Register Value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetPeakSM(void *handle, LIS3DSH_ACC_SM_t sm, u8_t* val) {
u8_t reg;
switch(sm){
case LIS3DSH_ACC_SM1: reg = LIS3DSH_ACC_PEAK1; break;
case LIS3DSH_ACC_SM2: reg = LIS3DSH_ACC_PEAK2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetDecimSM2
* Description : Read the Decimator counter Register value by SM2
* Input : Variable (8bit) to empty by Decimator counter Value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetDecimSM2(void *handle, u8_t* val) {
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_DES2, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetIntPinSM
* Description : Set SMx Interrupt PIN routed to INT1 or INT2
* Input : SMx, MEMS_DISABLE/ENABLE(MEMS_DISABLE = routed INT1)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetIntPinSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value=0;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_CNTL1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_CNTL2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xF7;
value |= (state<<LIS3DSH_ACC_SM_PIN);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetIntEnaSM
* Description : Set SMx Interrupt Enable for SM1 or SM2
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetIntEnaSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value=0;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_CNTL1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_CNTL2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xFE;
value |= (state<<LIS3DSH_ACC_SM_EN);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetPeakDetSM
* Description : Set SMx Peak Detection Enable
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetPeakDetSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_SETT1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_SETT2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0x7F;
value |= (state<<LIS3DSH_ACC_P_DET);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetThr3SaSM
* Description : Set SMx threshold3 limit value for axis and sign mask reset (MASKB_x)
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetThr3SaSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_SETT1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_SETT2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xBF;
value |= (state<<LIS3DSH_ACC_THR3_SA);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetThr3MaSM
* Description : Set SMx threshold3 limit value for axis and sign mask reset (MASKA_x)
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetThr3MaSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_SETT1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_SETT2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xFB;
value |= (state<<LIS3DSH_ACC_THR3_MA);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetAbsSM
* Description : Set SMx absolute value enable
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetAbsSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_SETT1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_SETT2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xDF;
value |= (state<<LIS3DSH_ACC_ABS);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetRTamSM
* Description : Set SMx next condition validation flag
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetRTamSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_SETT1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_SETT2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xFD;
value |= (state<<LIS3DSH_ACC_R_TAM);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetSitrSM
* Description : Set SMx program flow can be modified by STOP and COUNT
* Input : SMx, MEMS_DISABLE/ENABLE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetSitrSM(void *handle, LIS3DSH_ACC_SM_t sm, LIS3DSH_ACC_State_t state) {
u8_t reg=0;
u8_t value;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_SETT1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_SETT2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &value, 1) )
return MEMS_ERROR;
value &= 0xFE;
value |= (state<<LIS3DSH_ACC_SITR);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetHystSM
* Description : Set Hysteresis for SM1 or SM2
* Input : SM1/SM2, Hysteresis Value (3bit)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetHystSM(void *handle, LIS3DSH_ACC_SM_tsm, u8_t val) {
u8_t reg=0;
u8_t read=0;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_CNTL1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_CNTL2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg, &read, 1) )
return MEMS_ERROR;
read &= 0x1F;
read |= (val<<LIS3DSH_ACC_HYST);
if( !LIS3DSH_ACC_WriteReg(handle, reg, &read, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetSatusReg
* Description : Read the status register
* Input : char to empty by Status Reg Value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetSatusReg(void *handle, u8_t* val) {
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_STATUS, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetSatusBIT
* Description : Read the status register BIT
* Input : STATUS_REG_ZYXOR, STATUS_REG_ZOR, STATUS_REG_YOR, STATUS_REG_XOR,
STATUS_REG_ZYXDA, STATUS_REG_ZDA, STATUS_REG_YDA, STATUS_REG_XDA, DATAREADY_BIT
* Output : status register BIT
* Return : Status of BIT
*******************************************************************************/
status_t LIS3DSH_ACC_GetSatusBit(void *handle, u8_t statusBIT) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_STATUS, &value, 1) )
return MEMS_ERROR;
switch (statusBIT){
case LIS3DSH_ACC_STATUS_REG_ZYXOR: if(value & LIS3DSH_ACC_STATUS_REG_ZYXOR) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_ZOR: if(value & LIS3DSH_ACC_STATUS_REG_ZOR) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_YOR: if(value & LIS3DSH_ACC_STATUS_REG_YOR) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_XOR: if(value & LIS3DSH_ACC_STATUS_REG_XOR) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_ZYXDA: if(value & LIS3DSH_ACC_STATUS_REG_ZYXDA) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_ZDA: if(value & LIS3DSH_ACC_STATUS_REG_ZDA) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_YDA: if(value & LIS3DSH_ACC_STATUS_REG_YDA) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
case LIS3DSH_ACC_STATUS_REG_XDA: if(value & LIS3DSH_ACC_STATUS_REG_XDA) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
}
return MEMS_ERROR;
}
/*******************************************************************************
* Function Name: GetAccAxesRaw
* Description : Read the Acceleration Values Output Registers
* Input : buffer to empty by AccAxesRaw_t Typedef
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetAccAxesRaw(void *handle, Type3Axis16bit_U* buff) {
u8_t valueL;
u8_t valueH;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_X_L, &valueL, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_X_H, &valueH, 1) )
return MEMS_ERROR;
buff->i16bit = (i16_t)( (valueH << 8) | valueL )/16;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_Y_L, &valueL, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_Y_H, &valueH, 1) )
return MEMS_ERROR;
buff->i16bit = (i16_t)( (valueH << 8) | valueL )/16;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_Z_L, &valueL, 1) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_OUT_Z_H, &valueH, 1) )
return MEMS_ERROR;
buff->i16bit = (i16_t)( (valueH << 8) | valueL )/16;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetStatBIT
* Description : Read single BIT status of STAT register
* Input : Stat BIT Mask Flag (F_LONG,F_SYNC1...)
* Output : None
* Return : Status of BIT
*******************************************************************************/
status_t LIS3DSH_ACC_GetStatBIT(void *handle, u8_t StatBITMask) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_STAT, &value, 1) )
return MEMS_ERROR;
if(value & StatBITMask) return MEMS_SUCCESS;
return MEMS_ERROR;
}
/*******************************************************************************
* Function Name: GetFifoSourceReg
* Description : Read Fifo source Register
* Input : Byte to empty by FIFO source register value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetFifoSourceReg(void *handle, u8_t* val) {
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_FIFO_SRC, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetFifoSourceBit
* Description : Read Fifo WaterMark source bit
* Input : FIFO_WTM_S, FIFO_EMPTY_S, FIFO_EMPTY_S...
* Output : None
* Return : Status of BIT
*******************************************************************************/
status_t LIS3DSH_ACC_GetFifoSourceBit(void *handle, u8_t statusBIT){
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_FIFO_SRC, &value, 1) )
return MEMS_ERROR;
if(statusBIT == LIS3DSH_ACC_FIFO_WTM_S){
if(value & LIS3DSH_ACC_FIFO_WTM_S) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
}
if(statusBIT == LIS3DSH_ACC_FIFO_OVRN_S){
if(value & LIS3DSH_ACC_FIFO_OVRN_S) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
}
if(statusBIT == LIS3DSH_ACC_FIFO_EMPTY_S){
if(value & LIS3DSH_ACC_FIFO_EMPTY_S) return MEMS_SUCCESS;
elsereturn MEMS_ERROR;
}
return MEMS_ERROR;
}
/*******************************************************************************
* Function Name: GetFifoSourceFSS
* Description : Read Fifo source Data Stored
* Input : Byte to empty by FIFO source Data Stored value
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetFifoSourceFSS(void *handle, u8_t* val) {
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_FIFO_SRC, val, 1) )
return MEMS_ERROR;
*val &= 0x1F;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: ReadFifoData
* Description : Read all Fifo Data stored
* Input : AccAxesRaw_t Buffer to empty by FIFO Data Stored value, Byte to empty by depth of FIFO
* Note : Must call this function every seconds max (or more fastly)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_ReadFifoData(void *handle, Type3Axis16bit_U* FifoBuff, u8_t* depth) {
u8_t val=0;
u8_t i=0;
i8_t j=0;
Type3Axis16bit_U data;
if(! LIS3DSH_ACC_GetFifoSourceFSS(handle, &val))//read FSS fifo value
return MEMS_ERROR;
if(val<1) return MEMS_ERROR; //there aren't fifo value
//read n data from FIFO
for(j=val;j>=0;j--){
LIS3DSH_ACC_GetAccAxesRaw(handle, &data);
FifoBuff.i16bit = data.i16bit;
FifoBuff.i16bit = data.i16bit;
FifoBuff.i16bit = data.i16bit;
i++;
}
*depth = val;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetSPIInterface
* Description : Set SPI mode: 3 Wire Interface OR 4 Wire Interface
* Input : SPI_3_WIRE, SPI_4_WIRE
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetSPIInterface(void *handle, LIS3DSH_ACC_SPIMode_t spi) {
u8_t value;
if( !LIS3DSH_ACC_ReadReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
value &= 0xFE;
value |= spi<<LIS3DSH_ACC_SIM;
if( !LIS3DSH_ACC_WriteReg(handle, LIS3DSH_ACC_CNTL5, &value, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetSMCodeReg
* Description : Set single SMx Code Register byte
* Input : Code Address, Code (Byte)
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetSMCodeReg(void *handle, u8_t CodeADD, u8_t CodeByte) {
//check correct address
if(! (((CodeADD >= 0x40)&&(CodeADD <= 0x4F)) || ((CodeADD >= 0x60)&&(CodeADD <= 0x6F))) )
return MEMS_ERROR;
if( !LIS3DSH_ACC_WriteReg(handle, CodeADD, &CodeByte, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: SetSMBufferCodeReg
* Description : Set All SMx Code Registers by Buffer input
* Input : SMx, Code Buffer
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_SetSMBufferCodeReg(void *handle, LIS3DSH_ACC_SM_t sm, u8_t* CodeBuff) {
u8_t reg=0;
u8_t i=0;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_ST1_1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_ST1_2; break;
}
for(i=0;i<16;i++){
if( !LIS3DSH_ACC_WriteReg(handle, reg+i, &CodeBuff, 1) )
return MEMS_ERROR;
}
return MEMS_SUCCESS;
}
/*******************************************************************************
* Function Name: GetSMCodeRegister
* Description : Get single code register number of SMx
* Input : SMx, Register Number , variable to empty
* Output : None
* Return : Status
*******************************************************************************/
status_t LIS3DSH_ACC_GetSMCodeRegister(void *handle, LIS3DSH_ACC_SM_t sm, u8_t RegNumber, u8_t* val) {
u8_t reg=0;
if((RegNumber==0)||(RegNumber>16)) return MEMS_ERROR;
switch(sm){
case LIS3DSH_ACC_SM1:reg = LIS3DSH_ACC_ST1_1; break;
case LIS3DSH_ACC_SM2:reg = LIS3DSH_ACC_ST1_2; break;
}
if( !LIS3DSH_ACC_ReadReg(handle, reg + RegNumber-1, val, 1) )
return MEMS_ERROR;
return MEMS_SUCCESS;
}
{:1_103:} 多谢来分享啊
{:1_103:}{:1_103:}{:1_103:}
牛 多谢分享~ {:1_103:}{:1_103:} 太牛了,多谢分享! LIS3DSH的有限状态机实现运动识别功能怎么配置,大家有demo吗?谢谢 恒丶佣兵 发表于 2017-8-8 11:07
LIS3DSH的有限状态机实现运动识别功能怎么配置,大家有demo吗?谢谢
去论坛直接发帖,看到的网友更多。回复帖关注度很少的 看起来很不错的样子 恒丶佣兵 发表于 2017-8-8 11:07
LIS3DSH的有限状态机实现运动识别功能怎么配置,大家有demo吗?谢谢
这个驱动包里有状态机的配置函数状态机的具体使用网上的资料不多
你可以多看看数据手册
或者参考一下这个驱动
/******************** (C) COPYRIGHT 2012 STMicroelectronics ********************
*
* File Name : lis3dsh_acc.c
* Authors : MSH - Motion Mems BU - Application Team
* : Matteo Dameno (matteo.dameno@st.com)
* : Denis Ciocca (denis.ciocca@st.com)
* : Author is willing to be considered the contact
* : and update point for the driver.
* Version : V.1.2.2
* Date : 2012/Dec/15
* Description : LIS3DSH accelerometer driver
*
*******************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
*
******************************************************************************
Version History.
V 1.0.0 First Release
V 1.0.2 I2C address bugfix
V 1.2.0 Registers names compliant to correct datasheet
V.1.2.1 Removed enable_interrupt_output sysfs file, manage int1
and int2, implements int1 isr.
V.1.2.2 Modified state program loadiing defines, removed
state machine program.
******************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
/* #include "lis3dsh.h" */
#include <linux/input/lis3dsh.h>
//#define DEBUG
/* set to 1 to enable SM program and parameters loading */
/* set to 0 to leave unused */
#define LOAD_SM1_PROGRAM 1
#define LOAD_SP1_PARAMETERS 1
#define LOAD_SM2_PROGRAM 1
#define LOAD_SP2_PARAMETERS 1
#define G_MAX 23920640 /* ug */
#define I2C_RETRY_DELAY 5 /* Waiting for signals */
#define I2C_RETRIES 5 /* Number of retries */
#define I2C_AUTO_INCREMENT 0x00 /* Autoincrement i2c address */
#define SENSITIVITY_2G 60 /* ug/LSB */
#define SENSITIVITY_4G 120 /* ug/LSB */
#define SENSITIVITY_6G 180 /* ug/LSB */
#define SENSITIVITY_8G 240 /* ug/LSB */
#define SENSITIVITY_16G 730 /* ug/LSB */
#define LIS3DSH_FS_MASK (0x38)
/* Output Data Rates ODR */
#define LIS3DSH_ODR_MASK (0XF0)
#define LIS3DSH_PM_OFF (0x00) /* OFF */
#define LIS3DSH_ODR3_125 (0x10) /* 3.125 Hz */
#define LIS3DSH_ODR6_25 (0x20) /* 6.25Hz */
#define LIS3DSH_ODR12_5 (0x30) /* 12.5 Hz */
#define LIS3DSH_ODR25 (0x40) /* 25 Hz */
#define LIS3DSH_ODR50 (0x50) /* 50 Hz */
#define LIS3DSH_ODR100 (0x60) /*100 Hz */
#define LIS3DSH_ODR400 (0x70) /*400 Hz */
#define LIS3DSH_ODR800 (0x80) /*800 Hz */
#define LIS3DSH_ODR1600 (0x90) /* 1600 Hz */
/* Registers configuration Mask and settings */
/* ----CTRLREGx */
#define LIS3DSH_INTEN_MASK (0x01)
#define LIS3DSH_INTEN_OFF (0x00)
#define LIS3DSH_INTEN_ON (0x01)
/* CTRLREG1 */
#define LIS3DSH_HIST1_MASK (0xE0)
#define LIS3DSH_SM1INT_PIN_MASK (0x08)
#define LIS3DSH_SM1INT_PININT2 (0x08)
#define LIS3DSH_SM1INT_PININT1 (0x00)
#define LIS3DSH_SM1_EN_MASK (0x01)
#define LIS3DSH_SM1_EN_ON (0x01)
#define LIS3DSH_SM1_EN_OFF (0x00)
/* */
/* CTRLREG2 */
#define LIS3DSH_HIST2_MASK (0xE0)
#define LIS3DSH_SM2INT_PIN_MASK (0x08)
#define LIS3DSH_SM2INT_PININT2 (0x08)
#define LIS3DSH_SM2INT_PININT1 (0x00)
#define LIS3DSH_SM2_EN_MASK (0x01)
#define LIS3DSH_SM2_EN_ON (0x01)
#define LIS3DSH_SM2_EN_OFF (0x00)
/* */
/* CTRLREG3 */
#define LIS3DSH_INT_ACT_MASK (0x01 << 6)
#define LIS3DSH_INT_ACT_H (0x01 << 6)
#define LIS3DSH_INT_ACT_L (0x00)
#define LIS3DSH_INT2_EN_MASK (0x01 << 4)
#define LIS3DSH_INT2_EN_ON (0x01 << 4)
#define LIS3DSH_INT2_EN_OFF (0x00)
#define LIS3DSH_INT1_EN_MASK (0x01 << 3)
#define LIS3DSH_INT1_EN_ON (0x01 << 3)
#define LIS3DSH_INT1_EN_OFF (0x00)
/* */
/* CTRLREG4 */
#define LIS3DSH_BDU_EN (0x08)
#define LIS3DSH_ALL_AXES (0x07)
/* */
/* STATUS REG BITS */
#define LIS3DSH_STAT_INTSM1_BIT (0x01 << 3)
#define LIS3DSH_STAT_INTSM2_BIT (0x01 << 2)
#define OUT_AXISDATA_REG LIS3DSH_OUTX_L
#define WHOAMI_LIS3DSH_ACC (0x3F) /* Expected content for WAI */
/* CONTROL REGISTERS */
#define LIS3DSH_WHO_AM_I (0x0F) /* WhoAmI register Address */
#define LIS3DSH_OUTX_L (0x28) /* Output X LSByte */
#define LIS3DSH_OUTX_H (0x29) /* Output X MSByte */
#define LIS3DSH_OUTY_L (0x2A) /* Output Y LSByte */
#define LIS3DSH_OUTY_H (0x2B) /* Output Y MSByte */
#define LIS3DSH_OUTZ_L (0x2C) /* Output Z LSByte */
#define LIS3DSH_OUTZ_H (0x2D) /* Output Z MSByte */
#define LIS3DSH_LC_L (0x16) /* LSByte Long Counter Status */
#define LIS3DSH_LC_H (0x17) /* MSByte Long Counter Status */
#define LIS3DSH_INTERR_STAT (0x18) /* Interrupt Status */
#define LIS3DSH_STATUS_REG (0x27) /* Status */
#define LIS3DSH_CTRL_REG1 (0x21) /* control reg 1 */
#define LIS3DSH_CTRL_REG2 (0x22) /* control reg 2 */
#define LIS3DSH_CTRL_REG3 (0x23) /* control reg 3 */
#define LIS3DSH_CTRL_REG4 (0x20) /* control reg 4 */
#define LIS3DSH_CTRL_REG5 (0x24) /* control reg 5 */
#define LIS3DSH_CTRL_REG6 (0x25) /* control reg 6 */
#define LIS3DSH_OFF_X (0x10) /* Offset X Corr */
#define LIS3DSH_OFF_Y (0x11) /* Offset Y Corr */
#define LIS3DSH_OFF_Z (0x12) /* Offset Z Corr */
#define LIS3DSH_CS_X (0x13) /* Const Shift X */
#define LIS3DSH_CS_Y (0x14) /* Const Shift Y */
#define LIS3DSH_CS_Z (0x15) /* Const Shift Z */
#define LIS3DSH_VFC_1 (0x1B) /* Vect Filter Coeff 1 */
#define LIS3DSH_VFC_2 (0x1C) /* Vect Filter Coeff 2 */
#define LIS3DSH_VFC_3 (0x1D) /* Vect Filter Coeff 3 */
#define LIS3DSH_VFC_4 (0x1E) /* Vect Filter Coeff 4 */
/* state program 1 */
#define LIS3DSH_STATEPR1 (0X40) /* State Program 1 16 bytes */
#define LIS3DSH_TIM4_1 (0X50) /* SPr1 Timer4 */
#define LIS3DSH_TIM3_1 (0X51) /* SPr1 Timer3 */
#define LIS3DSH_TIM2_1 (0X52) /* SPr1 Timer2 2bytes */
#define LIS3DSH_TIM1_1 (0X54) /* SPr1 Timer1 2bytes */
#define LIS3DSH_THRS2_1 (0X56) /* SPr1 Threshold1 */
#define LIS3DSH_THRS1_1 (0X57) /* SPr1 Threshold2 */
#define LIS3DSH_SA_1 (0X59) /* SPr1 Swap Axis Sign Msk */
#define LIS3DSH_MA_1 (0X5A) /* SPr1 Axis Sign Msk */
#define LIS3DSH_SETT_1 (0X5B) /* SPr1 */
#define LIS3DSH_PPRP_1 (0X5C) /* SPr1 ProgPointer ResetPointer */
#define LIS3DSH_TC_1 (0X5D) /* SPr1 2bytes */
#define LIS3DSH_OUTS_1 (0X5F) /* SPr1 */
/* state program 2 */
#define LIS3DSH_STATEPR2 (0X60) /* State Program 2 16 bytes */
#define LIS3DSH_TIM4_2 (0X70) /* SPr2 Timer4 */
#define LIS3DSH_TIM3_2 (0X71) /* SPr2 Timer3 */
#define LIS3DSH_TIM2_2 (0X72) /* SPr2 Timer2 2bytes */
#define LIS3DSH_TIM1_2 (0X74) /* SPr2 Timer1 2bytes */
#define LIS3DSH_THRS2_2 (0X76) /* SPr2 Threshold1 */
#define LIS3DSH_THRS1_2 (0X77) /* SPr2 Threshold2 */
#define LIS3DSH_DES_2 (0X78) /* SPr2 Decimation */
#define LIS3DSH_SA_2 (0X79) /* SPr2 Swap Axis Sign Msk */
#define LIS3DSH_MA_2 (0X7A) /* SPr2 Axis Sign Msk */
#define LIS3DSH_SETT_2 (0X7B) /* SPr2 */
#define LIS3DSH_PPRP_2 (0X7C) /* SPr2 ProgPointer ResetPointer */
#define LIS3DSH_TC_2 (0X7D) /* SPr2 2bytes */
#define LIS3DSH_OUTS_2 (0X7F) /* SPr2 */
/* end CONTROL REGISTRES */
/* RESUME STATE INDICES */
#define RES_LIS3DSH_LC_L 0
#define RES_LIS3DSH_LC_H 1
#define RES_LIS3DSH_CTRL_REG4 2
#define RES_LIS3DSH_CTRL_REG1 3
#define RES_LIS3DSH_CTRL_REG2 4
#define RES_LIS3DSH_CTRL_REG3 5
#define RES_LIS3DSH_CTRL_REG5 6
#define RES_LIS3DSH_CTRL_REG6 7
#define RES_LIS3DSH_OFF_X 8
#define RES_LIS3DSH_OFF_Y 9
#define RES_LIS3DSH_OFF_Z 10
#define RES_LIS3DSH_CS_X 11
#define RES_LIS3DSH_CS_Y 12
#define RES_LIS3DSH_CS_Z 13
#define RES_LIS3DSH_VFC_1 14
#define RES_LIS3DSH_VFC_2 15
#define RES_LIS3DSH_VFC_3 16
#define RES_LIS3DSH_VFC_4 17
#define RES_LIS3DSH_THRS3 18
#define RES_LIS3DSH_TIM4_1 20
#define RES_LIS3DSH_TIM3_1 21
#define RES_LIS3DSH_TIM2_1_L 22
#define RES_LIS3DSH_TIM2_1_H 23
#define RES_LIS3DSH_TIM1_1_L 24
#define RES_LIS3DSH_TIM1_1_H 25
#define RES_LIS3DSH_THRS2_1 26
#define RES_LIS3DSH_THRS1_1 27
#define RES_LIS3DSH_SA_1 28
#define RES_LIS3DSH_MA_1 29
#define RES_LIS3DSH_SETT_1 30
#define RES_LIS3DSH_TIM4_2 31
#define RES_LIS3DSH_TIM3_2 32
#define RES_LIS3DSH_TIM2_2_L 33
#define RES_LIS3DSH_TIM2_2_H 34
#define RES_LIS3DSH_TIM1_2_L 35
#define RES_LIS3DSH_TIM1_2_H 36
#define RES_LIS3DSH_THRS2_2 37
#define RES_LIS3DSH_THRS1_2 38
#define RES_LIS3DSH_DES_2 39
#define RES_LIS3DSH_SA_2 40
#define RES_LIS3DSH_MA_2 41
#define RES_LIS3DSH_SETT_2 42
#define LIS3DSH_RESUME_ENTRIES 43
#define LIS3DSH_STATE_PR_SIZE 16
/* end RESUME STATE INDICES */
/* STATE PROGRAMS ENABLE CONTROLS */
#define LIS3DSH_SM1_DIS_SM2_DIS (0x00)
#define LIS3DSH_SM1_EN_SM2_DIS (0x01)
#define LIS3DSH_SM1_DIS_SM2_EN (0x02)
#define LIS3DSH_SM1_EN_SM2_EN (0x03)
/* INTERRUPTS ENABLE CONTROLS */
#define LIS3DSH_INT1_DIS_INT2_DIS (0x00)
#define LIS3DSH_INT1_EN_INT2_DIS (0x01)
#define LIS3DSH_INT1_DIS_INT2_EN (0x02)
#define LIS3DSH_INT1_EN_INT2_EN (0x03)
struct {
unsigned int cutoff_ms;
unsigned int mask;
} lis3dsh_acc_odr_table[] = {
{ 1, LIS3DSH_ODR1600 },
{ 3, LIS3DSH_ODR400},
{ 10, LIS3DSH_ODR100},
{ 20, LIS3DSH_ODR50 },
{ 40, LIS3DSH_ODR25 },
{ 80, LIS3DSH_ODR12_5 },
{160, LIS3DSH_ODR6_25 },
{320, LIS3DSH_ODR3_125},
};
static struct lis3dsh_acc_platform_data default_lis3dsh_acc_pdata = {
.fs_range = LIS3DSH_ACC_G_2G,
.axis_map_x = 0,
.axis_map_y = 1,
.axis_map_z = 2,
.negate_x = 0,
.negate_y = 0,
.negate_z = 0,
.poll_interval = 10,
.min_interval = LIS3DSH_ACC_MIN_POLL_PERIOD_MS,
.gpio_int1 = LIS3DSH_ACC_DEFAULT_INT1_GPIO,
.gpio_int2 = LIS3DSH_ACC_DEFAULT_INT2_GPIO,
};
static int int1_gpio = LIS3DSH_ACC_DEFAULT_INT1_GPIO;
static int int2_gpio = LIS3DSH_ACC_DEFAULT_INT2_GPIO;
module_param(int1_gpio, int, S_IRUGO);
module_param(int2_gpio, int, S_IRUGO);
MODULE_PARM_DESC(int1_gpio, "integer: gpio number being assined to interrupt PIN1");
MODULE_PARM_DESC(int2_gpio, "integer: gpio number being assined to interrupt PIN2");
struct lis3dsh_acc_data {
struct i2c_client *client;
struct lis3dsh_acc_platform_data *pdata;
struct mutex lock;
struct delayed_work input_work;
struct input_dev *input_dev;
int hw_initialized;
/* hw_working=-1 means not tested yet */
int hw_working;
atomic_t enabled;
int on_before_suspend;
int use_smbus;
u16 sensitivity;
u8 stateprogs_enable_setting;
u8 resume_state;
u8 resume_stmach_program1;
u8 resume_stmach_program2;
int irq1;
struct work_struct irq1_work;
struct workqueue_struct *irq1_work_queue;
int irq2;
struct work_struct irq2_work;
struct workqueue_struct *irq2_work_queue;
#ifdef DEBUG
u8 reg_addr;
#endif
};
/* sets default init values to be written in registers at probe stage */
static void lis3dsh_acc_set_init_register_values(struct lis3dsh_acc_data *acc)
{
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = (0x00 | LIS3DSH_SM1INT_PININT1);
acc->resume_state = (0x00 | LIS3DSH_SM2INT_PININT1);
acc->resume_state = LIS3DSH_INT_ACT_H;
if(acc->pdata->gpio_int1 >= 0)
acc->resume_state =
acc->resume_state | \
LIS3DSH_INT1_EN_ON;
if(acc->pdata->gpio_int2 >= 0)
acc->resume_state =
acc->resume_state | \
LIS3DSH_INT2_EN_ON;
acc->resume_state = (LIS3DSH_BDU_EN |
LIS3DSH_ALL_AXES);
acc->resume_state = 0x00;
acc->resume_state = 0x10;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
}
static void lis3dsh_acc_set_init_statepr1_inst(struct lis3dsh_acc_data *acc)
{
#if (LOAD_SM1_PROGRAM == 1)
/* Place here state machine 1 program */
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0X00;
acc->resume_stmach_program1 = 0X00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
#else
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0X00;
acc->resume_stmach_program1 = 0X00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
acc->resume_stmach_program1 = 0x00;
#endif /* LOAD_SM1_PROGRAM */
}
static void lis3dsh_acc_set_init_statepr2_inst(struct lis3dsh_acc_data *acc)
{
#if (LOAD_SM2_PROGRAM == 1)
/* Place here state machine 2 program */
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0X00;
acc->resume_stmach_program2 = 0X00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
#else
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0X00;
acc->resume_stmach_program2 = 0X00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
acc->resume_stmach_program2 = 0x00;
#endif /* LOAD_SM2_PROGRAM */
}
static void lis3dsh_acc_set_init_statepr1_param(struct lis3dsh_acc_data *acc)
{
#if (LOAD_SP1_PARAMETERS == 1)
/* Place here state machine 1 parameters */
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
/* DES1 not available*/
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
#else
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
/* DES1 not available*/
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
#endif
}
static void lis3dsh_acc_set_init_statepr2_param(struct lis3dsh_acc_data *acc)
{
#if (LOAD_SP2_PARAMETERS == 1)
/* Place here state machine 2 parameters */
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
#else
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
acc->resume_state = 0x00;
#endif
}
static int lis3dsh_acc_i2c_read(struct lis3dsh_acc_data *acc,
u8 * buf, int len)
{
int err;
int tries = 0;
struct i2c_msg msgs[] = {
{
.addr = acc->client->addr,
.flags = acc->client->flags & I2C_M_TEN,
.len = 1,
.buf = buf,
},
{
.addr = acc->client->addr,
.flags = (acc->client->flags & I2C_M_TEN) | I2C_M_RD,
.len = len,
.buf = buf,
},
};
do {
err = i2c_transfer(acc->client->adapter, msgs, 2);
if (err != 2)
msleep_interruptible(I2C_RETRY_DELAY);
} while ((err != 2) && (++tries < I2C_RETRIES));
if (err != 2) {
dev_err(&acc->client->dev, "read transfer error\n");
err = -EIO;
} else {
err = 0;
}
return err;
}
static int lis3dsh_acc_i2c_write(struct lis3dsh_acc_data *acc, u8 * buf,
int len)
{
int err;
int tries = 0;
struct i2c_msg msgs[] = {
{
.addr = acc->client->addr,
.flags = acc->client->flags & I2C_M_TEN,
.len = len + 1,
.buf = buf,
},
};
do {
err = i2c_transfer(acc->client->adapter, msgs, 1);
if (err != 1)
msleep_interruptible(I2C_RETRY_DELAY);
} while ((err != 1) && (++tries < I2C_RETRIES));
if (err != 1) {
dev_err(&acc->client->dev, "write transfer error\n");
err = -EIO;
} else {
err = 0;
}
return err;
}
static int lis3dsh_acc_i2c_update(struct lis3dsh_acc_data *acc,
u8 reg_address, u8 mask, u8 new_bit_values)
{
int err = -1;
u8 rdbuf = { reg_address };
u8 wrbuf = { reg_address , 0x00 };
u8 init_val;
u8 updated_val;
err = lis3dsh_acc_i2c_read(acc, rdbuf, 1);
if (!(err < 0)) {
init_val = rdbuf;
updated_val = ((mask & new_bit_values) | ((~mask) & init_val));
wrbuf = updated_val;
err = lis3dsh_acc_i2c_write(acc, wrbuf, 1);
}
return err;
}
static int lis3dsh_acc_hw_init(struct lis3dsh_acc_data *acc)
{
int i;
int err = -1;
u8 buf;
pr_info("%s: hw init start\n", LIS3DSH_ACC_DEV_NAME);
buf = LIS3DSH_WHO_AM_I;
err = lis3dsh_acc_i2c_read(acc, buf, 1);
if (err < 0) {
dev_warn(&acc->client->dev, "Error reading WHO_AM_I: is device "
"available/working?\n");
goto err_firstread;
} else
acc->hw_working = 1;
if (buf != WHOAMI_LIS3DSH_ACC) {
dev_err(&acc->client->dev,
"device unknown. Expected: 0x%02x,"
" Replies: 0x%02x\n", WHOAMI_LIS3DSH_ACC, buf);
err = -1; /* choose the right coded error */
goto err_unknown_device;
}
buf = (I2C_AUTO_INCREMENT | LIS3DSH_LC_L);
buf = acc->resume_state;
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 2);
if (err < 0)
goto err_resume_state;
buf = (I2C_AUTO_INCREMENT | LIS3DSH_TIM4_1);
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 8);
if (err < 0)
goto err_resume_state;
buf = (I2C_AUTO_INCREMENT | LIS3DSH_SA_1);
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 3);
if (err < 0)
goto err_resume_state;
buf = (I2C_AUTO_INCREMENT | LIS3DSH_TIM4_2);
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 12);
if (err < 0)
goto err_resume_state;
/* state program 1 */
buf = (I2C_AUTO_INCREMENT | LIS3DSH_STATEPR1);
for (i = 1; i <= LIS3DSH_STATE_PR_SIZE; i++) {
buf = acc->resume_stmach_program1;
pr_debug("i=%d,sm pr1 buf[%d]=0x%02x\n", i, i, buf);
};
err = lis3dsh_acc_i2c_write(acc, buf, LIS3DSH_STATE_PR_SIZE);
if (err < 0)
goto err_resume_state;
/* state program 2 */
buf = (I2C_AUTO_INCREMENT | LIS3DSH_STATEPR2);
for(i = 1; i <= LIS3DSH_STATE_PR_SIZE; i++){
buf = acc->resume_stmach_program2;
pr_debug("i=%d,sm pr2 buf[%d]=0x%02x\n", i, i, buf);
};
err = lis3dsh_acc_i2c_write(acc, buf, LIS3DSH_STATE_PR_SIZE);
if (err < 0)
goto err_resume_state;
buf = (I2C_AUTO_INCREMENT | LIS3DSH_CTRL_REG5);
buf = acc->resume_state;
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 2);
if (err < 0)
goto err_resume_state;
buf = (I2C_AUTO_INCREMENT | LIS3DSH_CTRL_REG1);
buf = acc->resume_state;
buf = acc->resume_state;
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 3);
if (err < 0)
goto err_resume_state;
buf = (LIS3DSH_CTRL_REG4);
buf = acc->resume_state;
err = lis3dsh_acc_i2c_write(acc, buf, 1);
if (err < 0)
goto err_resume_state;
acc->hw_initialized = 1;
pr_info("%s: hw init done\n", LIS3DSH_ACC_DEV_NAME);
return 0;
err_firstread:
acc->hw_working = 0;
err_unknown_device:
err_resume_state:
acc->hw_initialized = 0;
dev_err(&acc->client->dev, "hw init error 0x%02x,0x%02x: %d\n", buf,
buf, err);
return err;
}
static void lis3dsh_acc_device_power_off(struct lis3dsh_acc_data *acc)
{
int err;
err = lis3dsh_acc_i2c_update(acc, LIS3DSH_CTRL_REG4,
LIS3DSH_ODR_MASK, LIS3DSH_PM_OFF);
if (err < 0)
dev_err(&acc->client->dev, "soft power off failed: %d\n", err);
if (acc->pdata->power_off) {
if(acc->pdata->gpio_int1)
disable_irq_nosync(acc->irq1);
if(acc->pdata->gpio_int2)
disable_irq_nosync(acc->irq2);
acc->pdata->power_off();
acc->hw_initialized = 0;
}
if (acc->hw_initialized) {
if(acc->pdata->gpio_int1 >= 0)
disable_irq_nosync(acc->irq1);
if(acc->pdata->gpio_int2 >= 0)
disable_irq_nosync(acc->irq2);
acc->hw_initialized = 0;
}
}
static int lis3dsh_acc_device_power_on(struct lis3dsh_acc_data *acc)
{
int err = -1;
if (acc->pdata->power_on) {
err = acc->pdata->power_on();
if (err < 0) {
dev_err(&acc->client->dev,
"power_on failed: %d\n", err);
return err;
}
if(acc->pdata->gpio_int1 >= 0)
enable_irq(acc->irq1);
if(acc->pdata->gpio_int2 >= 0)
enable_irq(acc->irq2);
}
if (!acc->hw_initialized) {
err = lis3dsh_acc_hw_init(acc);
if (acc->hw_working == 1 && err < 0) {
lis3dsh_acc_device_power_off(acc);
return err;
}
}
if (acc->hw_initialized) {
if(acc->pdata->gpio_int1 >= 0)
enable_irq(acc->irq1);
if(acc->pdata->gpio_int2 >= 0)
enable_irq(acc->irq2);
}
return 0;
}
static irqreturn_t lis3dsh_acc_isr1(int irq, void *dev)
{
struct lis3dsh_acc_data *acc = dev;
disable_irq_nosync(irq);
queue_work(acc->irq1_work_queue, &acc->irq1_work);
pr_debug("%s: isr1 queued\n", LIS3DSH_ACC_DEV_NAME);
return IRQ_HANDLED;
}
static irqreturn_t lis3dsh_acc_isr2(int irq, void *dev)
{
struct lis3dsh_acc_data *acc = dev;
disable_irq_nosync(irq);
queue_work(acc->irq2_work_queue, &acc->irq2_work);
pr_debug("%s: isr2 queued\n", LIS3DSH_ACC_DEV_NAME);
return IRQ_HANDLED;
}
static void lis3dsh_acc_irq1_work_func(struct work_struct *work)
{
int err = -1;
u8 rbuf, status;
struct lis3dsh_acc_data *acc;
acc = container_of(work, struct lis3dsh_acc_data, irq1_work);
/* TODOadd interrupt service procedure.
ie:lis3dsh_acc_get_int_source(acc); */
pr_debug("%s: IRQ1 triggered\n", LIS3DSH_ACC_DEV_NAME);
/**/
rbuf = LIS3DSH_INTERR_STAT;
err = lis3dsh_acc_i2c_read(acc, rbuf, 1);
pr_debug("%s: INTERR_STAT_REG: 0x%02x\n",
LIS3DSH_ACC_DEV_NAME, rbuf);
status = rbuf;
if(status & LIS3DSH_STAT_INTSM1_BIT) {
rbuf = LIS3DSH_OUTS_1;
err = lis3dsh_acc_i2c_read(acc, rbuf, 1);
pr_debug("%s: OUTS_1: 0x%02x\n",
LIS3DSH_ACC_DEV_NAME, rbuf);
}
if(status & LIS3DSH_STAT_INTSM2_BIT) {
rbuf = LIS3DSH_OUTS_2;
err = lis3dsh_acc_i2c_read(acc, rbuf, 1);
pr_debug("%s: OUTS_2: 0x%02x\n",
LIS3DSH_ACC_DEV_NAME, rbuf);
}
pr_debug("%s: IRQ1 served\n", LIS3DSH_ACC_DEV_NAME);
exit:
enable_irq(acc->irq1);
pr_debug("%s: IRQ1 re-enabled\n", LIS3DSH_ACC_DEV_NAME);
}
static void lis3dsh_acc_irq2_work_func(struct work_struct *work)
{
struct lis3dsh_acc_data *acc;
acc = container_of(work, struct lis3dsh_acc_data, irq2_work);
pr_debug("%s: IRQ2 triggered\n", LIS3DSH_ACC_DEV_NAME);
/* TODOadd interrupt service procedure.
ie:lis3dsh_acc_get_stat_source(acc); */
/* ; */
pr_debug("%s: IRQ2 served\n", LIS3DSH_ACC_DEV_NAME);
exit:
enable_irq(acc->irq2);
pr_debug("%s: IRQ2 re-enabled\n", LIS3DSH_ACC_DEV_NAME);
}
static int lis3dsh_acc_register_masked_update(struct lis3dsh_acc_data *acc,
u8 reg_address, u8 mask, u8 new_bit_values, int resume_index)
{
u8 config = {0};
u8 init_val, updated_val;
int err;
int step = 0;
config = reg_address;
err = lis3dsh_acc_i2c_read(acc, config, 1);
if (err < 0)
goto error;
init_val = config;
acc->resume_state = init_val;
step = 1;
updated_val = ((mask & new_bit_values) | ((~mask) & init_val));
config = reg_address;
config = updated_val;
err = lis3dsh_acc_i2c_write(acc, config, 1);
if (err < 0)
goto error;
acc->resume_state = updated_val;
return err;
error:
dev_err(&acc->client->dev,
"register 0x%02x update failed at step %d, error: %d\n",
config, step, err);
return err;
}
static int lis3dsh_acc_update_fs_range(struct lis3dsh_acc_data *acc,
u8 new_fs_range)
{
int err=-1;
u16 sensitivity;
switch (new_fs_range) {
case LIS3DSH_ACC_G_2G:
sensitivity = SENSITIVITY_2G;
break;
case LIS3DSH_ACC_G_4G:
sensitivity = SENSITIVITY_4G;
break;
case LIS3DSH_ACC_G_6G:
sensitivity = SENSITIVITY_6G;
break;
case LIS3DSH_ACC_G_8G:
sensitivity = SENSITIVITY_8G;
break;
case LIS3DSH_ACC_G_16G:
sensitivity = SENSITIVITY_16G;
break;
default:
dev_err(&acc->client->dev, "invalid g range requested: %u\n",
new_fs_range);
return -EINVAL;
}
if (atomic_read(&acc->enabled)) {
/* Updates configuration register 1,
* which contains g range setting */
err = lis3dsh_acc_register_masked_update(acc, LIS3DSH_CTRL_REG5,
LIS3DSH_FS_MASK, new_fs_range, RES_LIS3DSH_CTRL_REG5);
if(err < 0) {
dev_err(&acc->client->dev, "update g range failed\n");
return err;
}
else
acc->sensitivity = sensitivity;
}
if(err < 0)
dev_err(&acc->client->dev, "update g range not executed "
"because the device is off\n");
return err;
}
static int lis3dsh_acc_update_odr(struct lis3dsh_acc_data *acc,
int poll_interval_ms)
{
int err = -1;
int i;
u8 new_odr;
/* Following, looks for the longest possible odr interval scrolling the
* odr_table vector from the end (shortest interval) backward (longest
* interval), to support the poll_interval requested by the system.
* It must be the longest interval lower then the poll interval.*/
for (i = ARRAY_SIZE(lis3dsh_acc_odr_table) - 1; i >= 0; i--) {
if (lis3dsh_acc_odr_table.cutoff_ms <= poll_interval_ms)
break;
}
new_odr = lis3dsh_acc_odr_table.mask;
/* If device is currently enabled, we need to write new
*configuration out to it */
if (atomic_read(&acc->enabled)) {
err = lis3dsh_acc_register_masked_update(acc,
LIS3DSH_CTRL_REG4, LIS3DSH_ODR_MASK, new_odr,
RES_LIS3DSH_CTRL_REG4);
}
if(err < 0)
dev_err(&acc->client->dev, "update odr failed\n");
return err;
}
#ifdef DEBUG
static int lis3dsh_acc_register_write(struct lis3dsh_acc_data *acc, u8 *buf,
u8 reg_address, u8 new_value)
{
int err = -1;
/* Sets configuration register at reg_address
*NOTE: this is a straight overwrite*/
buf = reg_address;
buf = new_value;
err = lis3dsh_acc_i2c_write(acc, buf, 1);
if (err < 0)
return err;
return err;
}
static int lis3dsh_acc_register_read(struct lis3dsh_acc_data *acc, u8 *buf,
u8 reg_address)
{
int err = -1;
buf = (reg_address);
err = lis3dsh_acc_i2c_read(acc, buf, 1);
return err;
}
static int lis3dsh_acc_register_update(struct lis3dsh_acc_data *acc, u8 *buf,
u8 reg_address, u8 mask, u8 new_bit_values)
{
int err = -1;
u8 init_val;
u8 updated_val;
err = lis3dsh_acc_register_read(acc, buf, reg_address);
if (!(err < 0)) {
init_val = buf;
updated_val = ((mask & new_bit_values) | ((~mask) & init_val));
err = lis3dsh_acc_register_write(acc, buf, reg_address,
updated_val);
}
return err;
}
#endif
static int lis3dsh_acc_get_acceleration_data(struct lis3dsh_acc_data *acc,
int *xyz)
{
int err = -1;
/* Data bytes from hardware xL, xH, yL, yH, zL, zH */
u8 acc_data;
/* x,y,z hardware data */
s32 hw_d = { 0 };
acc_data = (I2C_AUTO_INCREMENT | OUT_AXISDATA_REG);
err = lis3dsh_acc_i2c_read(acc, acc_data, 6);
if (err < 0)
return err;
hw_d = ((s16) ((acc_data << 8) | acc_data));
hw_d = ((s16) ((acc_data << 8) | acc_data));
hw_d = ((s16) ((acc_data << 8) | acc_data));
hw_d = hw_d * acc->sensitivity;
hw_d = hw_d * acc->sensitivity;
hw_d = hw_d * acc->sensitivity;
xyz = ((acc->pdata->negate_x) ? (-hw_d)
: (hw_d));
xyz = ((acc->pdata->negate_y) ? (-hw_d)
: (hw_d));
xyz = ((acc->pdata->negate_z) ? (-hw_d)
: (hw_d));
pr_debug("%s read x=%d, y=%d, z=%d\n",
LIS3DSH_ACC_DEV_NAME, xyz, xyz, xyz);
return err;
}
static void lis3dsh_acc_report_values(struct lis3dsh_acc_data *acc,
int *xyz)
{
input_report_abs(acc->input_dev, ABS_X, xyz);
input_report_abs(acc->input_dev, ABS_Y, xyz);
input_report_abs(acc->input_dev, ABS_Z, xyz);
input_sync(acc->input_dev);
}
static int lis3dsh_acc_enable(struct lis3dsh_acc_data *acc)
{
int err;
if (!atomic_cmpxchg(&acc->enabled, 0, 1)) {
err = lis3dsh_acc_device_power_on(acc);
if (err < 0) {
atomic_set(&acc->enabled, 0);
return err;
}
schedule_delayed_work(&acc->input_work,
msecs_to_jiffies(acc->pdata->poll_interval));
}
return 0;
}
static int lis3dsh_acc_disable(struct lis3dsh_acc_data *acc)
{
if (atomic_cmpxchg(&acc->enabled, 1, 0)) {
cancel_delayed_work_sync(&acc->input_work);
lis3dsh_acc_device_power_off(acc);
}
return 0;
}
static ssize_t attr_get_polling_rate(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int val;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
mutex_lock(&acc->lock);
val = acc->pdata->poll_interval;
mutex_unlock(&acc->lock);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_polling_rate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int err;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
unsigned long interval_ms;
if (strict_strtoul(buf, 10, &interval_ms))
return -EINVAL;
if (!interval_ms)
return -EINVAL;
mutex_lock(&acc->lock);
err = lis3dsh_acc_update_odr(acc, interval_ms);
if(err >= 0)
{
acc->pdata->poll_interval = interval_ms;
}
mutex_unlock(&acc->lock);
return size;
}
static ssize_t attr_get_range(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 val;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
int range = 2;
mutex_lock(&acc->lock);
val = acc->pdata->fs_range ;
switch(val) {
case LIS3DSH_ACC_G_2G:
range = 2;
break;
case LIS3DSH_ACC_G_4G:
range = 4;
break;
case LIS3DSH_ACC_G_6G:
range = 6;
break;
case LIS3DSH_ACC_G_8G:
range = 8;
break;
case LIS3DSH_ACC_G_16G:
range = 16;
break;
}
mutex_unlock(&acc->lock);
return sprintf(buf, "%d\n", range);
}
static ssize_t attr_set_range(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int err;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
unsigned long val;
u8 range;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
switch(val) {
case 2:
range = LIS3DSH_ACC_G_2G;
break;
case 4:
range = LIS3DSH_ACC_G_4G;
break;
case 6:
range = LIS3DSH_ACC_G_6G;
break;
case 8:
range = LIS3DSH_ACC_G_8G;
break;
case 16:
range = LIS3DSH_ACC_G_16G;
break;
default:
return -1;
}
mutex_lock(&acc->lock);
err = lis3dsh_acc_update_fs_range(acc, range);
if(err >= 0)
{
acc->pdata->fs_range = range;
}
mutex_unlock(&acc->lock);
return size;
}
static ssize_t attr_get_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
int val = atomic_read(&acc->enabled);
return sprintf(buf, "%d\n", val);
}
static ssize_t attr_set_enable(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
unsigned long val;
if (strict_strtoul(buf, 10, &val))
return -EINVAL;
if (val)
lis3dsh_acc_enable(acc);
else
lis3dsh_acc_disable(acc);
return size;
}
static int lis3dsh_acc_state_progrs_enable_control(
struct lis3dsh_acc_data *acc, u8 settings)
{
u8 val1, val2;
int err = -1;
//settings = settings & 0x03;
switch ( settings ) {
case LIS3DSH_SM1_DIS_SM2_DIS:
val1 = LIS3DSH_SM1_EN_OFF;
val2 = LIS3DSH_SM2_EN_OFF;
break;
case LIS3DSH_SM1_DIS_SM2_EN:
val1 = LIS3DSH_SM1_EN_OFF;
val2 = LIS3DSH_SM2_EN_ON;
break;
case LIS3DSH_SM1_EN_SM2_DIS:
val1 = LIS3DSH_SM1_EN_ON;
val2 = LIS3DSH_SM2_EN_OFF;
break;
case LIS3DSH_SM1_EN_SM2_EN:
val1 = LIS3DSH_SM1_EN_ON;
val2 = LIS3DSH_SM2_EN_ON;
break;
default :
pr_err("invalid state program setting : 0x%02x\n",settings);
return err;
}
err = lis3dsh_acc_register_masked_update(acc,
LIS3DSH_CTRL_REG1, LIS3DSH_SM1_EN_MASK, val1,
RES_LIS3DSH_CTRL_REG1);
if (err < 0 )
return err;
err = lis3dsh_acc_register_masked_update(acc,
LIS3DSH_CTRL_REG2, LIS3DSH_SM2_EN_MASK, val2,
RES_LIS3DSH_CTRL_REG2);
if (err < 0 )
return err;
acc->stateprogs_enable_setting = settings;
pr_debug("state program setting : 0x%02x\n",
acc->stateprogs_enable_setting);
return err;
}
static ssize_t attr_set_enable_state_prog(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int err = -1;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
long val=0;
if (strict_strtoul(buf, 16, &val))
return -EINVAL;
if ( val < 0x00 || val > LIS3DSH_SM1_EN_SM2_EN){
pr_warn("invalid state program setting, val: %ld\n",val);
return -EINVAL;
}
mutex_lock(&acc->lock);
err = lis3dsh_acc_state_progrs_enable_control(acc, val);
mutex_unlock(&acc->lock);
if (err < 0)
return err;
return size;
}
static ssize_t attr_get_enable_state_prog(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 val;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
mutex_lock(&acc->lock);
val = acc->stateprogs_enable_setting;
mutex_unlock(&acc->lock);
return sprintf(buf, "0x%02x\n", val);
}
#ifdef DEBUG
/* PAY ATTENTION: These DEBUG funtions don't manage resume_state */
static ssize_t attr_reg_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
int rc;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
u8 x;
unsigned long val;
if (strict_strtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&acc->lock);
x = acc->reg_addr;
mutex_unlock(&acc->lock);
x = val;
rc = lis3dsh_acc_i2c_write(acc, x, 1);
/*TODO: error need to be managed */
return size;
}
static ssize_t attr_reg_get(struct device *dev, struct device_attribute *attr,
char *buf)
{
ssize_t ret;
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
int rc;
u8 data;
mutex_lock(&acc->lock);
data = acc->reg_addr;
mutex_unlock(&acc->lock);
rc = lis3dsh_acc_i2c_read(acc, &data, 1);
/*TODO: error need to be managed */
ret = sprintf(buf, "0x%02x\n", data);
return ret;
}
static ssize_t attr_addr_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t size)
{
struct lis3dsh_acc_data *acc = dev_get_drvdata(dev);
unsigned long val;
if (strict_strtoul(buf, 16, &val))
return -EINVAL;
mutex_lock(&acc->lock);
acc->reg_addr = val;
mutex_unlock(&acc->lock);
return size;
}
#endif
static struct device_attribute attributes[] = {
__ATTR(poll_period_ms, 0664, attr_get_polling_rate,
attr_set_polling_rate),
__ATTR(range, 0664, attr_get_range, attr_set_range),
__ATTR(enable_device, 0664, attr_get_enable, attr_set_enable),
__ATTR(enable_state_prog, 0664, attr_get_enable_state_prog,
attr_set_enable_state_prog),
#ifdef DEBUG
__ATTR(reg_value, 0600, attr_reg_get, attr_reg_set),
__ATTR(reg_addr, 0200, NULL, attr_addr_set),
#endif
};
static int create_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
if (device_create_file(dev, attributes + i))
goto error;
return 0;
error:
for ( ; i >= 0; i--)
device_remove_file(dev, attributes + i);
dev_err(dev, "%s:Unable to create interface\n", __func__);
return -1;
}
static int remove_sysfs_interfaces(struct device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(dev, attributes + i);
return 0;
}
static void lis3dsh_acc_input_work_func(struct work_struct *work)
{
struct lis3dsh_acc_data *acc;
int xyz = { 0 };
int err;
acc = container_of((struct delayed_work *)work,
struct lis3dsh_acc_data, input_work);
mutex_lock(&acc->lock);
err = lis3dsh_acc_get_acceleration_data(acc, xyz);
if (err < 0)
dev_err(&acc->client->dev, "get_acceleration_data failed\n");
else
lis3dsh_acc_report_values(acc, xyz);
schedule_delayed_work(&acc->input_work, msecs_to_jiffies(
acc->pdata->poll_interval));
mutex_unlock(&acc->lock);
}
int lis3dsh_acc_input_open(struct input_dev *input)
{
struct lis3dsh_acc_data *acc = input_get_drvdata(input);
return lis3dsh_acc_enable(acc);
}
void lis3dsh_acc_input_close(struct input_dev *dev)
{
struct lis3dsh_acc_data *acc = input_get_drvdata(dev);
lis3dsh_acc_disable(acc);
}
static int lis3dsh_acc_validate_pdata(struct lis3dsh_acc_data *acc)
{
acc->pdata->poll_interval = max(acc->pdata->poll_interval,
acc->pdata->min_interval);
if (acc->pdata->axis_map_x > 2 ||
acc->pdata->axis_map_y > 2 ||
acc->pdata->axis_map_z > 2) {
dev_err(&acc->client->dev, "invalid axis_map value "
"x:%u y:%u z%u\n", acc->pdata->axis_map_x,
acc->pdata->axis_map_y, acc->pdata->axis_map_z);
return -EINVAL;
}
/* Only allow 0 and 1 for negation boolean flag */
if (acc->pdata->negate_x > 1 || acc->pdata->negate_y > 1
|| acc->pdata->negate_z > 1) {
dev_err(&acc->client->dev, "invalid negate value "
"x:%u y:%u z:%u\n", acc->pdata->negate_x,
acc->pdata->negate_y, acc->pdata->negate_z);
return -EINVAL;
}
/* Enforce minimum polling interval */
if (acc->pdata->poll_interval < acc->pdata->min_interval) {
dev_err(&acc->client->dev, "minimum poll interval violated\n");
return -EINVAL;
}
return 0;
}
static int lis3dsh_acc_input_init(struct lis3dsh_acc_data *acc)
{
int err;
INIT_DELAYED_WORK(&acc->input_work, lis3dsh_acc_input_work_func);
acc->input_dev = input_allocate_device();
if (!acc->input_dev) {
err = -ENOMEM;
dev_err(&acc->client->dev, "input device allocation failed\n");
goto err0;
}
acc->input_dev->open = lis3dsh_acc_input_open;
acc->input_dev->close = lis3dsh_acc_input_close;
acc->input_dev->name = LIS3DSH_ACC_DEV_NAME;
acc->input_dev->id.bustype = BUS_I2C;
acc->input_dev->dev.parent = &acc->client->dev;
input_set_drvdata(acc->input_dev, acc);
set_bit(EV_ABS, acc->input_dev->evbit);
/* next is used for interruptA sources data if the case */
set_bit(ABS_MISC, acc->input_dev->absbit);
/* next is used for interruptB sources data if the case */
set_bit(ABS_WHEEL, acc->input_dev->absbit);
input_set_abs_params(acc->input_dev, ABS_X, -G_MAX, G_MAX, 0, 0);
input_set_abs_params(acc->input_dev, ABS_Y, -G_MAX, G_MAX, 0, 0);
input_set_abs_params(acc->input_dev, ABS_Z, -G_MAX, G_MAX, 0, 0);
/* next is used for interruptA sources data if the case */
//input_set_abs_params(acc->input_dev, ABS_MISC, INT_MIN, INT_MAX, 0, 0);
/* next is used for interruptB sources data if the case */
//input_set_abs_params(acc->input_dev, ABS_WHEEL, INT_MIN, INT_MAX, 0, 0);
err = input_register_device(acc->input_dev);
if (err) {
dev_err(&acc->client->dev,
"unable to register input device %s\n",
acc->input_dev->name);
goto err1;
}
return 0;
err1:
input_free_device(acc->input_dev);
err0:
return err;
}
static void lis3dsh_acc_input_cleanup(struct lis3dsh_acc_data *acc)
{
input_unregister_device(acc->input_dev);
input_free_device(acc->input_dev);
}
static int lis3dsh_acc_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lis3dsh_acc_data *acc;
u32 smbus_func = I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK ;
int err = -1;
dev_info(&client->dev, "probe start.\n");
acc = kzalloc(sizeof(struct lis3dsh_acc_data), GFP_KERNEL);
if (acc == NULL) {
err = -ENOMEM;
dev_err(&client->dev,
"failed to allocate memory for module data: "
"%d\n", err);
goto exit_check_functionality_failed;
}
/* Support for both I2C and SMBUS adapter interfaces. */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_warn(&client->dev, "client not i2c capable\n");
if (i2c_check_functionality(client->adapter, smbus_func)){
acc->use_smbus = 1;
dev_warn(&client->dev, "client using SMBUS\n");
} else {
err = -ENODEV;
dev_err(&client->dev, "client nor SMBUS capable\n");
acc->use_smbus = 0;
goto exit_check_functionality_failed;
}
} else {
acc->use_smbus = 0;
}
mutex_init(&acc->lock);
mutex_lock(&acc->lock);
acc->client = client;
i2c_set_clientdata(client, acc);
acc->pdata = kmalloc(sizeof(*acc->pdata), GFP_KERNEL);
if (acc->pdata == NULL) {
err = -ENOMEM;
dev_err(&client->dev,
"failed to allocate memory for pdata: %d\n",
err);
goto err_mutexunlock;
}
if(client->dev.platform_data == NULL) {
default_lis3dsh_acc_pdata.gpio_int1 = int1_gpio;
default_lis3dsh_acc_pdata.gpio_int2 = int2_gpio;
memcpy(acc->pdata, &default_lis3dsh_acc_pdata,
sizeof(*acc->pdata));
dev_info(&client->dev, "using default platform_data\n");
} else {
memcpy(acc->pdata, client->dev.platform_data,
sizeof(*acc->pdata));
}
err = lis3dsh_acc_validate_pdata(acc);
if (err < 0) {
dev_err(&client->dev, "failed to validate platform data\n");
goto exit_kfree_pdata;
}
if (acc->pdata->init) {
err = acc->pdata->init();
if (err < 0) {
dev_err(&client->dev, "init failed: %d\n", err);
goto err_pdata_init;
}
}
if(acc->pdata->gpio_int1 >= 0){
acc->irq1 = gpio_to_irq(acc->pdata->gpio_int1);
pr_info("%s: %s has set irq1 to irq: %d "
"mapped on gpio:%d\n",
LIS3DSH_ACC_DEV_NAME, __func__, acc->irq1,
acc->pdata->gpio_int1);
}
if(acc->pdata->gpio_int2 >= 0){
acc->irq2 = gpio_to_irq(acc->pdata->gpio_int2);
pr_info("%s: %s has set irq2 to irq: %d "
"mapped on gpio:%d\n",
LIS3DSH_ACC_DEV_NAME, __func__, acc->irq2,
acc->pdata->gpio_int2);
}
/* resume state init config */
memset(acc->resume_state, 0, ARRAY_SIZE(acc->resume_state));
lis3dsh_acc_set_init_register_values(acc);
//init state program1 and params
lis3dsh_acc_set_init_statepr1_param(acc);
lis3dsh_acc_set_init_statepr1_inst(acc);
//init state program2and params
lis3dsh_acc_set_init_statepr2_param(acc);
lis3dsh_acc_set_init_statepr2_inst(acc);
err = lis3dsh_acc_device_power_on(acc);
if (err < 0) {
dev_err(&client->dev, "power on failed: %d\n", err);
goto err_pdata_init;
}
atomic_set(&acc->enabled, 1);
err = lis3dsh_acc_update_fs_range(acc, acc->pdata->fs_range);
if (err < 0) {
dev_err(&client->dev, "update_fs_range failed\n");
gotoerr_power_off;
}
err = lis3dsh_acc_update_odr(acc, acc->pdata->poll_interval);
if (err < 0) {
dev_err(&client->dev, "update_odr failed\n");
gotoerr_power_off;
}
err = lis3dsh_acc_input_init(acc);
if (err < 0) {
dev_err(&client->dev, "input init failed\n");
goto err_power_off;
}
err = create_sysfs_interfaces(&client->dev);
if (err < 0) {
dev_err(&client->dev,
"device LIS3DSH_ACC_DEV_NAME sysfs register failed\n");
goto err_input_cleanup;
}
lis3dsh_acc_device_power_off(acc);
/* As default, do not report information */
atomic_set(&acc->enabled, 0);
if(acc->pdata->gpio_int1 >= 0){
INIT_WORK(&acc->irq1_work, lis3dsh_acc_irq1_work_func);
acc->irq1_work_queue =
create_singlethread_workqueue("lis3dsh_acc_wq1");
if (!acc->irq1_work_queue) {
err = -ENOMEM;
dev_err(&client->dev,
"cannot create work queue1: %d\n", err);
goto err_remove_sysfs_int;
}
err = request_irq(acc->irq1, lis3dsh_acc_isr1,
IRQF_TRIGGER_RISING, "lis3dsh_acc_irq1", acc);
if (err < 0) {
dev_err(&client->dev, "request irq1 failed: %d\n", err);
goto err_destoyworkqueue1;
}
disable_irq_nosync(acc->irq1);
}
if(acc->pdata->gpio_int2 >= 0){
INIT_WORK(&acc->irq2_work, lis3dsh_acc_irq2_work_func);
acc->irq2_work_queue =
create_singlethread_workqueue("lis3dsh_acc_wq2");
if (!acc->irq2_work_queue) {
err = -ENOMEM;
dev_err(&client->dev,
"cannot create work queue2: %d\n", err);
goto err_free_irq1;
}
err = request_irq(acc->irq2, lis3dsh_acc_isr2,
IRQF_TRIGGER_RISING, "lis3dsh_acc_irq2", acc);
if (err < 0) {
dev_err(&client->dev, "request irq2 failed: %d\n", err);
goto err_destoyworkqueue2;
}
disable_irq_nosync(acc->irq2);
}
mutex_unlock(&acc->lock);
dev_info(&client->dev, "%s: probed\n", LIS3DSH_ACC_DEV_NAME);
return 0;
err_destoyworkqueue2:
if(acc->pdata->gpio_int2 >= 0)
destroy_workqueue(acc->irq2_work_queue);
err_free_irq1:
free_irq(acc->irq1, acc);
err_destoyworkqueue1:
if(acc->pdata->gpio_int1 >= 0)
destroy_workqueue(acc->irq1_work_queue);
err_remove_sysfs_int:
remove_sysfs_interfaces(&client->dev);
err_input_cleanup:
lis3dsh_acc_input_cleanup(acc);
err_power_off:
lis3dsh_acc_device_power_off(acc);
err_pdata_init:
if (acc->pdata->exit)
acc->pdata->exit();
exit_kfree_pdata:
kfree(acc->pdata);
err_mutexunlock:
mutex_unlock(&acc->lock);
//err_freedata:
kfree(acc);
exit_check_functionality_failed:
pr_err("%s: Driver Init failed\n", LIS3DSH_ACC_DEV_NAME);
return err;
}
static int __devexit lis3dsh_acc_remove(struct i2c_client *client)
{
struct lis3dsh_acc_data *acc = i2c_get_clientdata(client);
if(acc->pdata->gpio_int1 >= 0){
free_irq(acc->irq1, acc);
gpio_free(acc->pdata->gpio_int1);
destroy_workqueue(acc->irq1_work_queue);
}
if(acc->pdata->gpio_int2 >= 0){
free_irq(acc->irq2, acc);
gpio_free(acc->pdata->gpio_int2);
destroy_workqueue(acc->irq2_work_queue);
}
if (atomic_cmpxchg(&acc->enabled, 1, 0))
cancel_delayed_work_sync(&acc->input_work);
lis3dsh_acc_device_power_off(acc);
lis3dsh_acc_input_cleanup(acc);
remove_sysfs_interfaces(&client->dev);
if (acc->pdata->exit)
acc->pdata->exit();
kfree(acc->pdata);
kfree(acc);
return 0;
}
#ifdef CONFIG_PM
static int lis3dsh_acc_resume(struct i2c_client *client)
{
struct lis3dsh_acc_data *acc = i2c_get_clientdata(client);
if (acc->on_before_suspend)
return lis3dsh_acc_enable(acc);
return 0;
}
static int lis3dsh_acc_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct lis3dsh_acc_data *acc = i2c_get_clientdata(client);
acc->on_before_suspend = atomic_read(&acc->enabled);
return lis3dsh_acc_disable(acc);
}
#else
#define lis3dsh_acc_suspend NULL
#define lis3dsh_acc_resume NULL
#endif /* CONFIG_PM */
static const struct i2c_device_id lis3dsh_acc_id[]
= { { LIS3DSH_ACC_DEV_NAME, 0 }, { }, };
MODULE_DEVICE_TABLE(i2c, lis3dsh_acc_id);
static struct i2c_driver lis3dsh_acc_driver = {
.driver = {
.owner = THIS_MODULE,
.name = LIS3DSH_ACC_DEV_NAME,
},
.probe = lis3dsh_acc_probe,
.remove = __devexit_p(lis3dsh_acc_remove),
.suspend = lis3dsh_acc_suspend,
.resume = lis3dsh_acc_resume,
.id_table = lis3dsh_acc_id,
};
static int __init lis3dsh_acc_init(void)
{
pr_info("%s accelerometer driver: init\n", LIS3DSH_ACC_DEV_NAME);
return i2c_add_driver(&lis3dsh_acc_driver);
}
static void __exit lis3dsh_acc_exit(void)
{
pr_info("%s accelerometer driver: exit\n", LIS3DSH_ACC_DEV_NAME);
i2c_del_driver(&lis3dsh_acc_driver);
return;
}
module_init(lis3dsh_acc_init);
module_exit(lis3dsh_acc_exit);
MODULE_DESCRIPTION("lis3dsh accelerometer driver");
MODULE_AUTHOR("Matteo Dameno, Denis Ciocca, STMicroelectronics");
MODULE_LICENSE("GPL");
{:1_103:} :tongue::tongue::tongue:找到宝物了, 太牛了,多谢分享! 厉害了,我的哥,谢谢 很好,很好。。 问一下各位大神你们这个驱动文件在哪下的?在官网我怎么找不见 太牛了,多谢分享!{:1_103:}{:1_103:}{:1_103:}
请教各位,
最少硬件与编程来实现羽球拍挥拍路径之侦测,
LSM6DS3是否可行? LSM6DS3内置6D 方向检测与大幅运动检测,
或者其他传感器可行?求帮助。