diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/sensor | |
Diffstat (limited to 'drivers/sensor')
| -rw-r--r-- | drivers/sensor/Kconfig | 40 | ||||
| -rw-r--r-- | drivers/sensor/Makefile | 11 | ||||
| -rw-r--r-- | drivers/sensor/bma2x2_driver.c | 6194 | ||||
| -rw-r--r-- | drivers/sensor/bmm050.c | 1159 | ||||
| -rw-r--r-- | drivers/sensor/bmm050.h | 580 | ||||
| -rw-r--r-- | drivers/sensor/bmm050_driver.c | 1593 | ||||
| -rw-r--r-- | drivers/sensor/bs_log.h | 62 | ||||
| -rw-r--r-- | drivers/sensor/bst_sensor_common.c | 56 | ||||
| -rw-r--r-- | drivers/sensor/gp2ap002a00f.c | 647 | ||||
| -rw-r--r-- | drivers/sensor/k2hh.c | 1523 | ||||
| -rw-r--r-- | drivers/sensor/sensors_core.c | 110 |
11 files changed, 11975 insertions, 0 deletions
diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig new file mode 100644 index 00000000..00b0762c --- /dev/null +++ b/drivers/sensor/Kconfig @@ -0,0 +1,40 @@ +menu "Sensor support" + +config SENSORS + bool "Support for sensors" + help + Say Y here to add support for accelerometer sensors + +if SENSORS + +config SENSORS_GP2A + tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" + depends on I2C + help + Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip + hooked to an I2C bus. + To compile this driver as a module, choose M here: the + module will be called gp2ap002a00f. + +config SENSORS_BMA2X2 + tristate "BMA255/BMA250E/BMA222E/BMA280 acceleration sensor support" + depends on I2C + help + If you say yes here you get support for Bosch Sensortec's + acceleration sensors BMA255/BMA250E/BMA222E/BMA280. + + +config SENSORS_BMM050 + tristate "BMM050 Magnetic Sensor Driver" + depends on I2C + help + BMM050 Magnetic Sensor Driver implemented by Bosch-Sensortec. + +config SENSORS_K2HH + tristate "k2hh accelerometer sensor driver" + depends on I2C + help + k2hh accelerometer sensor driver. + +endif +endmenu diff --git a/drivers/sensor/Makefile b/drivers/sensor/Makefile new file mode 100644 index 00000000..d1fe411b --- /dev/null +++ b/drivers/sensor/Makefile @@ -0,0 +1,11 @@ +EXTRA_CFLAGS += -DBMA2X2_SENSOR_IDENTIFICATION_ENABLE +EXTRA_CFLAGS += -DCONFIG_BMA_USE_PLATFORM_DATA + +EXTRA_CFLAGS += -DBMM_USE_BASIC_I2C_FUNC +EXTRA_CFLAGS += -DCONFIG_BMM_USE_PLATFORM_DATA + +obj-$(CONFIG_SENSORS_GP2A) += gp2ap002a00f.o +obj-$(CONFIG_SENSORS_BMA2X2) += bma2x2_driver.o +obj-$(CONFIG_SENSORS_K2HH) += k2hh.o +obj-$(CONFIG_SENSORS_BMM050) += bmm050_driver.o bmm050.o +obj-y += bst_sensor_common.o sensors_core.o diff --git a/drivers/sensor/bma2x2_driver.c b/drivers/sensor/bma2x2_driver.c new file mode 100644 index 00000000..0bcfaa68 --- /dev/null +++ b/drivers/sensor/bma2x2_driver.c @@ -0,0 +1,6194 @@ +/* Date: 2013/06/17 22:13:00 + * Revision: 1.7.2 + */ + +/* + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + + * (C) Copyright 2011 Bosch Sensortec GmbH + * All Rights Reserved + */ + + +/* file BMA2X2.c + brief This file contains all function implementations for the BMA2X2 in linux + +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/sensors_core.h> +#include <linux/bst_sensor_common.h> + + +#define SENSOR_NAME "bma2x2" +#define ABSMIN -512 +#define ABSMAX 512 +#define SLOPE_THRESHOLD_VALUE 32 +#define SLOPE_DURATION_VALUE 1 +#define INTERRUPT_LATCH_MODE 13 +#define INTERRUPT_ENABLE 1 +#define INTERRUPT_DISABLE 0 +#define MAP_SLOPE_INTERRUPT 2 +#define SLOPE_X_INDEX 5 +#define SLOPE_Y_INDEX 6 +#define SLOPE_Z_INDEX 7 +#define BMA2X2_MAX_DELAY 200 +#define BMA2X2_RANGE_SET 3 /* +/- 2G */ +#define BMA2X2_BW_SET 12 /* 125HZ */ + +#define LOW_G_INTERRUPT REL_Z +#define HIGH_G_INTERRUPT REL_HWHEEL +#define SLOP_INTERRUPT REL_DIAL +#define DOUBLE_TAP_INTERRUPT REL_WHEEL +#define SINGLE_TAP_INTERRUPT REL_MISC +#define ORIENT_INTERRUPT ABS_PRESSURE +#define FLAT_INTERRUPT ABS_DISTANCE +#define SLOW_NO_MOTION_INTERRUPT REL_Y + +#define HIGH_G_INTERRUPT_X_HAPPENED 1 +#define HIGH_G_INTERRUPT_Y_HAPPENED 2 +#define HIGH_G_INTERRUPT_Z_HAPPENED 3 +#define HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED 4 +#define HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED 5 +#define HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED 6 +#define SLOPE_INTERRUPT_X_HAPPENED 7 +#define SLOPE_INTERRUPT_Y_HAPPENED 8 +#define SLOPE_INTERRUPT_Z_HAPPENED 9 +#define SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED 10 +#define SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED 11 +#define SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED 12 +#define DOUBLE_TAP_INTERRUPT_HAPPENED 13 +#define SINGLE_TAP_INTERRUPT_HAPPENED 14 +#define UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 15 +#define UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 16 +#define UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 17 +#define UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 18 +#define DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED 19 +#define DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED 20 +#define DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED 21 +#define DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED 22 +#define FLAT_INTERRUPT_TURE_HAPPENED 23 +#define FLAT_INTERRUPT_FALSE_HAPPENED 24 +#define LOW_G_INTERRUPT_HAPPENED 25 +#define SLOW_NO_MOTION_INTERRUPT_HAPPENED 26 + + +#define PAD_LOWG 0 +#define PAD_HIGHG 1 +#define PAD_SLOP 2 +#define PAD_DOUBLE_TAP 3 +#define PAD_SINGLE_TAP 4 +#define PAD_ORIENT 5 +#define PAD_FLAT 6 +#define PAD_SLOW_NO_MOTION 7 + + +#define BMA2X2_EEP_OFFSET 0x16 +#define BMA2X2_IMAGE_BASE 0x38 +#define BMA2X2_IMAGE_LEN 22 + + +#define BMA2X2_CHIP_ID_REG 0x00 +#define BMA2X2_VERSION_REG 0x01 +#define BMA2X2_X_AXIS_LSB_REG 0x02 +#define BMA2X2_X_AXIS_MSB_REG 0x03 +#define BMA2X2_Y_AXIS_LSB_REG 0x04 +#define BMA2X2_Y_AXIS_MSB_REG 0x05 +#define BMA2X2_Z_AXIS_LSB_REG 0x06 +#define BMA2X2_Z_AXIS_MSB_REG 0x07 +#define BMA2X2_TEMPERATURE_REG 0x08 +#define BMA2X2_STATUS1_REG 0x09 +#define BMA2X2_STATUS2_REG 0x0A +#define BMA2X2_STATUS_TAP_SLOPE_REG 0x0B +#define BMA2X2_STATUS_ORIENT_HIGH_REG 0x0C +#define BMA2X2_STATUS_FIFO_REG 0x0E +#define BMA2X2_RANGE_SEL_REG 0x0F +#define BMA2X2_BW_SEL_REG 0x10 +#define BMA2X2_MODE_CTRL_REG 0x11 +#define BMA2X2_LOW_NOISE_CTRL_REG 0x12 +#define BMA2X2_DATA_CTRL_REG 0x13 +#define BMA2X2_RESET_REG 0x14 +#define BMA2X2_INT_ENABLE1_REG 0x16 +#define BMA2X2_INT_ENABLE2_REG 0x17 +#define BMA2X2_INT_SLO_NO_MOT_REG 0x18 +#define BMA2X2_INT1_PAD_SEL_REG 0x19 +#define BMA2X2_INT_DATA_SEL_REG 0x1A +#define BMA2X2_INT2_PAD_SEL_REG 0x1B +#define BMA2X2_INT_SRC_REG 0x1E +#define BMA2X2_INT_SET_REG 0x20 +#define BMA2X2_INT_CTRL_REG 0x21 +#define BMA2X2_LOW_DURN_REG 0x22 +#define BMA2X2_LOW_THRES_REG 0x23 +#define BMA2X2_LOW_HIGH_HYST_REG 0x24 +#define BMA2X2_HIGH_DURN_REG 0x25 +#define BMA2X2_HIGH_THRES_REG 0x26 +#define BMA2X2_SLOPE_DURN_REG 0x27 +#define BMA2X2_SLOPE_THRES_REG 0x28 +#define BMA2X2_SLO_NO_MOT_THRES_REG 0x29 +#define BMA2X2_TAP_PARAM_REG 0x2A +#define BMA2X2_TAP_THRES_REG 0x2B +#define BMA2X2_ORIENT_PARAM_REG 0x2C +#define BMA2X2_THETA_BLOCK_REG 0x2D +#define BMA2X2_THETA_FLAT_REG 0x2E +#define BMA2X2_FLAT_HOLD_TIME_REG 0x2F +#define BMA2X2_FIFO_WML_TRIG 0x30 +#define BMA2X2_SELF_TEST_REG 0x32 +#define BMA2X2_EEPROM_CTRL_REG 0x33 +#define BMA2X2_SERIAL_CTRL_REG 0x34 +#define BMA2X2_EXTMODE_CTRL_REG 0x35 +#define BMA2X2_OFFSET_CTRL_REG 0x36 +#define BMA2X2_OFFSET_PARAMS_REG 0x37 +#define BMA2X2_OFFSET_X_AXIS_REG 0x38 +#define BMA2X2_OFFSET_Y_AXIS_REG 0x39 +#define BMA2X2_OFFSET_Z_AXIS_REG 0x3A +#define BMA2X2_GP0_REG 0x3B +#define BMA2X2_GP1_REG 0x3C +#define BMA2X2_FIFO_MODE_REG 0x3E +#define BMA2X2_FIFO_DATA_OUTPUT_REG 0x3F + + + + +#define BMA2X2_CHIP_ID__POS 0 +#define BMA2X2_CHIP_ID__MSK 0xFF +#define BMA2X2_CHIP_ID__LEN 8 +#define BMA2X2_CHIP_ID__REG BMA2X2_CHIP_ID_REG + +#define BMA2X2_VERSION__POS 0 +#define BMA2X2_VERSION__LEN 8 +#define BMA2X2_VERSION__MSK 0xFF +#define BMA2X2_VERSION__REG BMA2X2_VERSION_REG + +#define BMA2x2_SLO_NO_MOT_DUR__POS 2 +#define BMA2x2_SLO_NO_MOT_DUR__LEN 6 +#define BMA2x2_SLO_NO_MOT_DUR__MSK 0xFC +#define BMA2x2_SLO_NO_MOT_DUR__REG BMA2X2_SLOPE_DURN_REG + +#define BMA2X2_NEW_DATA_X__POS 0 +#define BMA2X2_NEW_DATA_X__LEN 1 +#define BMA2X2_NEW_DATA_X__MSK 0x01 +#define BMA2X2_NEW_DATA_X__REG BMA2X2_X_AXIS_LSB_REG + +#define BMA2X2_ACC_X14_LSB__POS 2 +#define BMA2X2_ACC_X14_LSB__LEN 6 +#define BMA2X2_ACC_X14_LSB__MSK 0xFC +#define BMA2X2_ACC_X14_LSB__REG BMA2X2_X_AXIS_LSB_REG + +#define BMA2X2_ACC_X12_LSB__POS 4 +#define BMA2X2_ACC_X12_LSB__LEN 4 +#define BMA2X2_ACC_X12_LSB__MSK 0xF0 +#define BMA2X2_ACC_X12_LSB__REG BMA2X2_X_AXIS_LSB_REG + +#define BMA2X2_ACC_X10_LSB__POS 6 +#define BMA2X2_ACC_X10_LSB__LEN 2 +#define BMA2X2_ACC_X10_LSB__MSK 0xC0 +#define BMA2X2_ACC_X10_LSB__REG BMA2X2_X_AXIS_LSB_REG + +#define BMA2X2_ACC_X8_LSB__POS 0 +#define BMA2X2_ACC_X8_LSB__LEN 0 +#define BMA2X2_ACC_X8_LSB__MSK 0x00 +#define BMA2X2_ACC_X8_LSB__REG BMA2X2_X_AXIS_LSB_REG + +#define BMA2X2_ACC_X_MSB__POS 0 +#define BMA2X2_ACC_X_MSB__LEN 8 +#define BMA2X2_ACC_X_MSB__MSK 0xFF +#define BMA2X2_ACC_X_MSB__REG BMA2X2_X_AXIS_MSB_REG + +#define BMA2X2_NEW_DATA_Y__POS 0 +#define BMA2X2_NEW_DATA_Y__LEN 1 +#define BMA2X2_NEW_DATA_Y__MSK 0x01 +#define BMA2X2_NEW_DATA_Y__REG BMA2X2_Y_AXIS_LSB_REG + +#define BMA2X2_ACC_Y14_LSB__POS 2 +#define BMA2X2_ACC_Y14_LSB__LEN 6 +#define BMA2X2_ACC_Y14_LSB__MSK 0xFC +#define BMA2X2_ACC_Y14_LSB__REG BMA2X2_Y_AXIS_LSB_REG + +#define BMA2X2_ACC_Y12_LSB__POS 4 +#define BMA2X2_ACC_Y12_LSB__LEN 4 +#define BMA2X2_ACC_Y12_LSB__MSK 0xF0 +#define BMA2X2_ACC_Y12_LSB__REG BMA2X2_Y_AXIS_LSB_REG + +#define BMA2X2_ACC_Y10_LSB__POS 6 +#define BMA2X2_ACC_Y10_LSB__LEN 2 +#define BMA2X2_ACC_Y10_LSB__MSK 0xC0 +#define BMA2X2_ACC_Y10_LSB__REG BMA2X2_Y_AXIS_LSB_REG + +#define BMA2X2_ACC_Y8_LSB__POS 0 +#define BMA2X2_ACC_Y8_LSB__LEN 0 +#define BMA2X2_ACC_Y8_LSB__MSK 0x00 +#define BMA2X2_ACC_Y8_LSB__REG BMA2X2_Y_AXIS_LSB_REG + +#define BMA2X2_ACC_Y_MSB__POS 0 +#define BMA2X2_ACC_Y_MSB__LEN 8 +#define BMA2X2_ACC_Y_MSB__MSK 0xFF +#define BMA2X2_ACC_Y_MSB__REG BMA2X2_Y_AXIS_MSB_REG + +#define BMA2X2_NEW_DATA_Z__POS 0 +#define BMA2X2_NEW_DATA_Z__LEN 1 +#define BMA2X2_NEW_DATA_Z__MSK 0x01 +#define BMA2X2_NEW_DATA_Z__REG BMA2X2_Z_AXIS_LSB_REG + +#define BMA2X2_ACC_Z14_LSB__POS 2 +#define BMA2X2_ACC_Z14_LSB__LEN 6 +#define BMA2X2_ACC_Z14_LSB__MSK 0xFC +#define BMA2X2_ACC_Z14_LSB__REG BMA2X2_Z_AXIS_LSB_REG + +#define BMA2X2_ACC_Z12_LSB__POS 4 +#define BMA2X2_ACC_Z12_LSB__LEN 4 +#define BMA2X2_ACC_Z12_LSB__MSK 0xF0 +#define BMA2X2_ACC_Z12_LSB__REG BMA2X2_Z_AXIS_LSB_REG + +#define BMA2X2_ACC_Z10_LSB__POS 6 +#define BMA2X2_ACC_Z10_LSB__LEN 2 +#define BMA2X2_ACC_Z10_LSB__MSK 0xC0 +#define BMA2X2_ACC_Z10_LSB__REG BMA2X2_Z_AXIS_LSB_REG + +#define BMA2X2_ACC_Z8_LSB__POS 0 +#define BMA2X2_ACC_Z8_LSB__LEN 0 +#define BMA2X2_ACC_Z8_LSB__MSK 0x00 +#define BMA2X2_ACC_Z8_LSB__REG BMA2X2_Z_AXIS_LSB_REG + +#define BMA2X2_ACC_Z_MSB__POS 0 +#define BMA2X2_ACC_Z_MSB__LEN 8 +#define BMA2X2_ACC_Z_MSB__MSK 0xFF +#define BMA2X2_ACC_Z_MSB__REG BMA2X2_Z_AXIS_MSB_REG + +#define BMA2X2_TEMPERATURE__POS 0 +#define BMA2X2_TEMPERATURE__LEN 8 +#define BMA2X2_TEMPERATURE__MSK 0xFF +#define BMA2X2_TEMPERATURE__REG BMA2X2_TEMP_RD_REG + +#define BMA2X2_LOWG_INT_S__POS 0 +#define BMA2X2_LOWG_INT_S__LEN 1 +#define BMA2X2_LOWG_INT_S__MSK 0x01 +#define BMA2X2_LOWG_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_HIGHG_INT_S__POS 1 +#define BMA2X2_HIGHG_INT_S__LEN 1 +#define BMA2X2_HIGHG_INT_S__MSK 0x02 +#define BMA2X2_HIGHG_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_SLOPE_INT_S__POS 2 +#define BMA2X2_SLOPE_INT_S__LEN 1 +#define BMA2X2_SLOPE_INT_S__MSK 0x04 +#define BMA2X2_SLOPE_INT_S__REG BMA2X2_STATUS1_REG + + +#define BMA2X2_SLO_NO_MOT_INT_S__POS 3 +#define BMA2X2_SLO_NO_MOT_INT_S__LEN 1 +#define BMA2X2_SLO_NO_MOT_INT_S__MSK 0x08 +#define BMA2X2_SLO_NO_MOT_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_DOUBLE_TAP_INT_S__POS 4 +#define BMA2X2_DOUBLE_TAP_INT_S__LEN 1 +#define BMA2X2_DOUBLE_TAP_INT_S__MSK 0x10 +#define BMA2X2_DOUBLE_TAP_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_SINGLE_TAP_INT_S__POS 5 +#define BMA2X2_SINGLE_TAP_INT_S__LEN 1 +#define BMA2X2_SINGLE_TAP_INT_S__MSK 0x20 +#define BMA2X2_SINGLE_TAP_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_ORIENT_INT_S__POS 6 +#define BMA2X2_ORIENT_INT_S__LEN 1 +#define BMA2X2_ORIENT_INT_S__MSK 0x40 +#define BMA2X2_ORIENT_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_FLAT_INT_S__POS 7 +#define BMA2X2_FLAT_INT_S__LEN 1 +#define BMA2X2_FLAT_INT_S__MSK 0x80 +#define BMA2X2_FLAT_INT_S__REG BMA2X2_STATUS1_REG + +#define BMA2X2_FIFO_FULL_INT_S__POS 5 +#define BMA2X2_FIFO_FULL_INT_S__LEN 1 +#define BMA2X2_FIFO_FULL_INT_S__MSK 0x20 +#define BMA2X2_FIFO_FULL_INT_S__REG BMA2X2_STATUS2_REG + +#define BMA2X2_FIFO_WM_INT_S__POS 6 +#define BMA2X2_FIFO_WM_INT_S__LEN 1 +#define BMA2X2_FIFO_WM_INT_S__MSK 0x40 +#define BMA2X2_FIFO_WM_INT_S__REG BMA2X2_STATUS2_REG + +#define BMA2X2_DATA_INT_S__POS 7 +#define BMA2X2_DATA_INT_S__LEN 1 +#define BMA2X2_DATA_INT_S__MSK 0x80 +#define BMA2X2_DATA_INT_S__REG BMA2X2_STATUS2_REG + +#define BMA2X2_SLOPE_FIRST_X__POS 0 +#define BMA2X2_SLOPE_FIRST_X__LEN 1 +#define BMA2X2_SLOPE_FIRST_X__MSK 0x01 +#define BMA2X2_SLOPE_FIRST_X__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_SLOPE_FIRST_Y__POS 1 +#define BMA2X2_SLOPE_FIRST_Y__LEN 1 +#define BMA2X2_SLOPE_FIRST_Y__MSK 0x02 +#define BMA2X2_SLOPE_FIRST_Y__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_SLOPE_FIRST_Z__POS 2 +#define BMA2X2_SLOPE_FIRST_Z__LEN 1 +#define BMA2X2_SLOPE_FIRST_Z__MSK 0x04 +#define BMA2X2_SLOPE_FIRST_Z__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_SLOPE_SIGN_S__POS 3 +#define BMA2X2_SLOPE_SIGN_S__LEN 1 +#define BMA2X2_SLOPE_SIGN_S__MSK 0x08 +#define BMA2X2_SLOPE_SIGN_S__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_TAP_FIRST_X__POS 4 +#define BMA2X2_TAP_FIRST_X__LEN 1 +#define BMA2X2_TAP_FIRST_X__MSK 0x10 +#define BMA2X2_TAP_FIRST_X__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_TAP_FIRST_Y__POS 5 +#define BMA2X2_TAP_FIRST_Y__LEN 1 +#define BMA2X2_TAP_FIRST_Y__MSK 0x20 +#define BMA2X2_TAP_FIRST_Y__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_TAP_FIRST_Z__POS 6 +#define BMA2X2_TAP_FIRST_Z__LEN 1 +#define BMA2X2_TAP_FIRST_Z__MSK 0x40 +#define BMA2X2_TAP_FIRST_Z__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_TAP_SIGN_S__POS 7 +#define BMA2X2_TAP_SIGN_S__LEN 1 +#define BMA2X2_TAP_SIGN_S__MSK 0x80 +#define BMA2X2_TAP_SIGN_S__REG BMA2X2_STATUS_TAP_SLOPE_REG + +#define BMA2X2_HIGHG_FIRST_X__POS 0 +#define BMA2X2_HIGHG_FIRST_X__LEN 1 +#define BMA2X2_HIGHG_FIRST_X__MSK 0x01 +#define BMA2X2_HIGHG_FIRST_X__REG BMA2X2_STATUS_ORIENT_HIGH_REG + +#define BMA2X2_HIGHG_FIRST_Y__POS 1 +#define BMA2X2_HIGHG_FIRST_Y__LEN 1 +#define BMA2X2_HIGHG_FIRST_Y__MSK 0x02 +#define BMA2X2_HIGHG_FIRST_Y__REG BMA2X2_STATUS_ORIENT_HIGH_REG + +#define BMA2X2_HIGHG_FIRST_Z__POS 2 +#define BMA2X2_HIGHG_FIRST_Z__LEN 1 +#define BMA2X2_HIGHG_FIRST_Z__MSK 0x04 +#define BMA2X2_HIGHG_FIRST_Z__REG BMA2X2_STATUS_ORIENT_HIGH_REG + +#define BMA2X2_HIGHG_SIGN_S__POS 3 +#define BMA2X2_HIGHG_SIGN_S__LEN 1 +#define BMA2X2_HIGHG_SIGN_S__MSK 0x08 +#define BMA2X2_HIGHG_SIGN_S__REG BMA2X2_STATUS_ORIENT_HIGH_REG + +#define BMA2X2_ORIENT_S__POS 4 +#define BMA2X2_ORIENT_S__LEN 3 +#define BMA2X2_ORIENT_S__MSK 0x70 +#define BMA2X2_ORIENT_S__REG BMA2X2_STATUS_ORIENT_HIGH_REG + +#define BMA2X2_FLAT_S__POS 7 +#define BMA2X2_FLAT_S__LEN 1 +#define BMA2X2_FLAT_S__MSK 0x80 +#define BMA2X2_FLAT_S__REG BMA2X2_STATUS_ORIENT_HIGH_REG + +#define BMA2X2_FIFO_FRAME_COUNTER_S__POS 0 +#define BMA2X2_FIFO_FRAME_COUNTER_S__LEN 7 +#define BMA2X2_FIFO_FRAME_COUNTER_S__MSK 0x7F +#define BMA2X2_FIFO_FRAME_COUNTER_S__REG BMA2X2_STATUS_FIFO_REG + +#define BMA2X2_FIFO_OVERRUN_S__POS 7 +#define BMA2X2_FIFO_OVERRUN_S__LEN 1 +#define BMA2X2_FIFO_OVERRUN_S__MSK 0x80 +#define BMA2X2_FIFO_OVERRUN_S__REG BMA2X2_STATUS_FIFO_REG + +#define BMA2X2_RANGE_SEL__POS 0 +#define BMA2X2_RANGE_SEL__LEN 4 +#define BMA2X2_RANGE_SEL__MSK 0x0F +#define BMA2X2_RANGE_SEL__REG BMA2X2_RANGE_SEL_REG + +#define BMA2X2_BANDWIDTH__POS 0 +#define BMA2X2_BANDWIDTH__LEN 5 +#define BMA2X2_BANDWIDTH__MSK 0x1F +#define BMA2X2_BANDWIDTH__REG BMA2X2_BW_SEL_REG + +#define BMA2X2_SLEEP_DUR__POS 1 +#define BMA2X2_SLEEP_DUR__LEN 4 +#define BMA2X2_SLEEP_DUR__MSK 0x1E +#define BMA2X2_SLEEP_DUR__REG BMA2X2_MODE_CTRL_REG + +#define BMA2X2_MODE_CTRL__POS 5 +#define BMA2X2_MODE_CTRL__LEN 3 +#define BMA2X2_MODE_CTRL__MSK 0xE0 +#define BMA2X2_MODE_CTRL__REG BMA2X2_MODE_CTRL_REG + +#define BMA2X2_DEEP_SUSPEND__POS 5 +#define BMA2X2_DEEP_SUSPEND__LEN 1 +#define BMA2X2_DEEP_SUSPEND__MSK 0x20 +#define BMA2X2_DEEP_SUSPEND__REG BMA2X2_MODE_CTRL_REG + +#define BMA2X2_EN_LOW_POWER__POS 6 +#define BMA2X2_EN_LOW_POWER__LEN 1 +#define BMA2X2_EN_LOW_POWER__MSK 0x40 +#define BMA2X2_EN_LOW_POWER__REG BMA2X2_MODE_CTRL_REG + +#define BMA2X2_EN_SUSPEND__POS 7 +#define BMA2X2_EN_SUSPEND__LEN 1 +#define BMA2X2_EN_SUSPEND__MSK 0x80 +#define BMA2X2_EN_SUSPEND__REG BMA2X2_MODE_CTRL_REG + +#define BMA2X2_SLEEP_TIMER__POS 5 +#define BMA2X2_SLEEP_TIMER__LEN 1 +#define BMA2X2_SLEEP_TIMER__MSK 0x20 +#define BMA2X2_SLEEP_TIMER__REG BMA2X2_LOW_NOISE_CTRL_REG + +#define BMA2X2_LOW_POWER_MODE__POS 6 +#define BMA2X2_LOW_POWER_MODE__LEN 1 +#define BMA2X2_LOW_POWER_MODE__MSK 0x40 +#define BMA2X2_LOW_POWER_MODE__REG BMA2X2_LOW_NOISE_CTRL_REG + +#define BMA2X2_EN_LOW_NOISE__POS 7 +#define BMA2X2_EN_LOW_NOISE__LEN 1 +#define BMA2X2_EN_LOW_NOISE__MSK 0x80 +#define BMA2X2_EN_LOW_NOISE__REG BMA2X2_LOW_NOISE_CTRL_REG + +#define BMA2X2_DIS_SHADOW_PROC__POS 6 +#define BMA2X2_DIS_SHADOW_PROC__LEN 1 +#define BMA2X2_DIS_SHADOW_PROC__MSK 0x40 +#define BMA2X2_DIS_SHADOW_PROC__REG BMA2X2_DATA_CTRL_REG + +#define BMA2X2_EN_DATA_HIGH_BW__POS 7 +#define BMA2X2_EN_DATA_HIGH_BW__LEN 1 +#define BMA2X2_EN_DATA_HIGH_BW__MSK 0x80 +#define BMA2X2_EN_DATA_HIGH_BW__REG BMA2X2_DATA_CTRL_REG + +#define BMA2X2_EN_SOFT_RESET__POS 0 +#define BMA2X2_EN_SOFT_RESET__LEN 8 +#define BMA2X2_EN_SOFT_RESET__MSK 0xFF +#define BMA2X2_EN_SOFT_RESET__REG BMA2X2_RESET_REG + +#define BMA2X2_EN_SOFT_RESET_VALUE 0xB6 + +#define BMA2X2_EN_SLOPE_X_INT__POS 0 +#define BMA2X2_EN_SLOPE_X_INT__LEN 1 +#define BMA2X2_EN_SLOPE_X_INT__MSK 0x01 +#define BMA2X2_EN_SLOPE_X_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_SLOPE_Y_INT__POS 1 +#define BMA2X2_EN_SLOPE_Y_INT__LEN 1 +#define BMA2X2_EN_SLOPE_Y_INT__MSK 0x02 +#define BMA2X2_EN_SLOPE_Y_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_SLOPE_Z_INT__POS 2 +#define BMA2X2_EN_SLOPE_Z_INT__LEN 1 +#define BMA2X2_EN_SLOPE_Z_INT__MSK 0x04 +#define BMA2X2_EN_SLOPE_Z_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_DOUBLE_TAP_INT__POS 4 +#define BMA2X2_EN_DOUBLE_TAP_INT__LEN 1 +#define BMA2X2_EN_DOUBLE_TAP_INT__MSK 0x10 +#define BMA2X2_EN_DOUBLE_TAP_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_SINGLE_TAP_INT__POS 5 +#define BMA2X2_EN_SINGLE_TAP_INT__LEN 1 +#define BMA2X2_EN_SINGLE_TAP_INT__MSK 0x20 +#define BMA2X2_EN_SINGLE_TAP_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_ORIENT_INT__POS 6 +#define BMA2X2_EN_ORIENT_INT__LEN 1 +#define BMA2X2_EN_ORIENT_INT__MSK 0x40 +#define BMA2X2_EN_ORIENT_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_FLAT_INT__POS 7 +#define BMA2X2_EN_FLAT_INT__LEN 1 +#define BMA2X2_EN_FLAT_INT__MSK 0x80 +#define BMA2X2_EN_FLAT_INT__REG BMA2X2_INT_ENABLE1_REG + +#define BMA2X2_EN_HIGHG_X_INT__POS 0 +#define BMA2X2_EN_HIGHG_X_INT__LEN 1 +#define BMA2X2_EN_HIGHG_X_INT__MSK 0x01 +#define BMA2X2_EN_HIGHG_X_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_EN_HIGHG_Y_INT__POS 1 +#define BMA2X2_EN_HIGHG_Y_INT__LEN 1 +#define BMA2X2_EN_HIGHG_Y_INT__MSK 0x02 +#define BMA2X2_EN_HIGHG_Y_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_EN_HIGHG_Z_INT__POS 2 +#define BMA2X2_EN_HIGHG_Z_INT__LEN 1 +#define BMA2X2_EN_HIGHG_Z_INT__MSK 0x04 +#define BMA2X2_EN_HIGHG_Z_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_EN_LOWG_INT__POS 3 +#define BMA2X2_EN_LOWG_INT__LEN 1 +#define BMA2X2_EN_LOWG_INT__MSK 0x08 +#define BMA2X2_EN_LOWG_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_EN_NEW_DATA_INT__POS 4 +#define BMA2X2_EN_NEW_DATA_INT__LEN 1 +#define BMA2X2_EN_NEW_DATA_INT__MSK 0x10 +#define BMA2X2_EN_NEW_DATA_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_INT_FFULL_EN_INT__POS 5 +#define BMA2X2_INT_FFULL_EN_INT__LEN 1 +#define BMA2X2_INT_FFULL_EN_INT__MSK 0x20 +#define BMA2X2_INT_FFULL_EN_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_INT_FWM_EN_INT__POS 6 +#define BMA2X2_INT_FWM_EN_INT__LEN 1 +#define BMA2X2_INT_FWM_EN_INT__MSK 0x40 +#define BMA2X2_INT_FWM_EN_INT__REG BMA2X2_INT_ENABLE2_REG + +#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__POS 0 +#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__LEN 1 +#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__MSK 0x01 +#define BMA2X2_INT_SLO_NO_MOT_EN_X_INT__REG BMA2X2_INT_SLO_NO_MOT_REG + +#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__POS 1 +#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__LEN 1 +#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__MSK 0x02 +#define BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__REG BMA2X2_INT_SLO_NO_MOT_REG + +#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__POS 2 +#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__LEN 1 +#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__MSK 0x04 +#define BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__REG BMA2X2_INT_SLO_NO_MOT_REG + +#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__POS 3 +#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__LEN 1 +#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__MSK 0x08 +#define BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG BMA2X2_INT_SLO_NO_MOT_REG + +#define BMA2X2_EN_INT1_PAD_LOWG__POS 0 +#define BMA2X2_EN_INT1_PAD_LOWG__LEN 1 +#define BMA2X2_EN_INT1_PAD_LOWG__MSK 0x01 +#define BMA2X2_EN_INT1_PAD_LOWG__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_HIGHG__POS 1 +#define BMA2X2_EN_INT1_PAD_HIGHG__LEN 1 +#define BMA2X2_EN_INT1_PAD_HIGHG__MSK 0x02 +#define BMA2X2_EN_INT1_PAD_HIGHG__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_SLOPE__POS 2 +#define BMA2X2_EN_INT1_PAD_SLOPE__LEN 1 +#define BMA2X2_EN_INT1_PAD_SLOPE__MSK 0x04 +#define BMA2X2_EN_INT1_PAD_SLOPE__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__POS 3 +#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__LEN 1 +#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__MSK 0x08 +#define BMA2X2_EN_INT1_PAD_SLO_NO_MOT__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_DB_TAP__POS 4 +#define BMA2X2_EN_INT1_PAD_DB_TAP__LEN 1 +#define BMA2X2_EN_INT1_PAD_DB_TAP__MSK 0x10 +#define BMA2X2_EN_INT1_PAD_DB_TAP__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_SNG_TAP__POS 5 +#define BMA2X2_EN_INT1_PAD_SNG_TAP__LEN 1 +#define BMA2X2_EN_INT1_PAD_SNG_TAP__MSK 0x20 +#define BMA2X2_EN_INT1_PAD_SNG_TAP__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_ORIENT__POS 6 +#define BMA2X2_EN_INT1_PAD_ORIENT__LEN 1 +#define BMA2X2_EN_INT1_PAD_ORIENT__MSK 0x40 +#define BMA2X2_EN_INT1_PAD_ORIENT__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_FLAT__POS 7 +#define BMA2X2_EN_INT1_PAD_FLAT__LEN 1 +#define BMA2X2_EN_INT1_PAD_FLAT__MSK 0x80 +#define BMA2X2_EN_INT1_PAD_FLAT__REG BMA2X2_INT1_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_LOWG__POS 0 +#define BMA2X2_EN_INT2_PAD_LOWG__LEN 1 +#define BMA2X2_EN_INT2_PAD_LOWG__MSK 0x01 +#define BMA2X2_EN_INT2_PAD_LOWG__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_HIGHG__POS 1 +#define BMA2X2_EN_INT2_PAD_HIGHG__LEN 1 +#define BMA2X2_EN_INT2_PAD_HIGHG__MSK 0x02 +#define BMA2X2_EN_INT2_PAD_HIGHG__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_SLOPE__POS 2 +#define BMA2X2_EN_INT2_PAD_SLOPE__LEN 1 +#define BMA2X2_EN_INT2_PAD_SLOPE__MSK 0x04 +#define BMA2X2_EN_INT2_PAD_SLOPE__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__POS 3 +#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__LEN 1 +#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__MSK 0x08 +#define BMA2X2_EN_INT2_PAD_SLO_NO_MOT__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_DB_TAP__POS 4 +#define BMA2X2_EN_INT2_PAD_DB_TAP__LEN 1 +#define BMA2X2_EN_INT2_PAD_DB_TAP__MSK 0x10 +#define BMA2X2_EN_INT2_PAD_DB_TAP__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_SNG_TAP__POS 5 +#define BMA2X2_EN_INT2_PAD_SNG_TAP__LEN 1 +#define BMA2X2_EN_INT2_PAD_SNG_TAP__MSK 0x20 +#define BMA2X2_EN_INT2_PAD_SNG_TAP__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_ORIENT__POS 6 +#define BMA2X2_EN_INT2_PAD_ORIENT__LEN 1 +#define BMA2X2_EN_INT2_PAD_ORIENT__MSK 0x40 +#define BMA2X2_EN_INT2_PAD_ORIENT__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT2_PAD_FLAT__POS 7 +#define BMA2X2_EN_INT2_PAD_FLAT__LEN 1 +#define BMA2X2_EN_INT2_PAD_FLAT__MSK 0x80 +#define BMA2X2_EN_INT2_PAD_FLAT__REG BMA2X2_INT2_PAD_SEL_REG + +#define BMA2X2_EN_INT1_PAD_NEWDATA__POS 0 +#define BMA2X2_EN_INT1_PAD_NEWDATA__LEN 1 +#define BMA2X2_EN_INT1_PAD_NEWDATA__MSK 0x01 +#define BMA2X2_EN_INT1_PAD_NEWDATA__REG BMA2X2_INT_DATA_SEL_REG + +#define BMA2X2_EN_INT1_PAD_FWM__POS 1 +#define BMA2X2_EN_INT1_PAD_FWM__LEN 1 +#define BMA2X2_EN_INT1_PAD_FWM__MSK 0x02 +#define BMA2X2_EN_INT1_PAD_FWM__REG BMA2X2_INT_DATA_SEL_REG + +#define BMA2X2_EN_INT1_PAD_FFULL__POS 2 +#define BMA2X2_EN_INT1_PAD_FFULL__LEN 1 +#define BMA2X2_EN_INT1_PAD_FFULL__MSK 0x04 +#define BMA2X2_EN_INT1_PAD_FFULL__REG BMA2X2_INT_DATA_SEL_REG + +#define BMA2X2_EN_INT2_PAD_FFULL__POS 5 +#define BMA2X2_EN_INT2_PAD_FFULL__LEN 1 +#define BMA2X2_EN_INT2_PAD_FFULL__MSK 0x20 +#define BMA2X2_EN_INT2_PAD_FFULL__REG BMA2X2_INT_DATA_SEL_REG + +#define BMA2X2_EN_INT2_PAD_FWM__POS 6 +#define BMA2X2_EN_INT2_PAD_FWM__LEN 1 +#define BMA2X2_EN_INT2_PAD_FWM__MSK 0x40 +#define BMA2X2_EN_INT2_PAD_FWM__REG BMA2X2_INT_DATA_SEL_REG + +#define BMA2X2_EN_INT2_PAD_NEWDATA__POS 7 +#define BMA2X2_EN_INT2_PAD_NEWDATA__LEN 1 +#define BMA2X2_EN_INT2_PAD_NEWDATA__MSK 0x80 +#define BMA2X2_EN_INT2_PAD_NEWDATA__REG BMA2X2_INT_DATA_SEL_REG + +#define BMA2X2_UNFILT_INT_SRC_LOWG__POS 0 +#define BMA2X2_UNFILT_INT_SRC_LOWG__LEN 1 +#define BMA2X2_UNFILT_INT_SRC_LOWG__MSK 0x01 +#define BMA2X2_UNFILT_INT_SRC_LOWG__REG BMA2X2_INT_SRC_REG + +#define BMA2X2_UNFILT_INT_SRC_HIGHG__POS 1 +#define BMA2X2_UNFILT_INT_SRC_HIGHG__LEN 1 +#define BMA2X2_UNFILT_INT_SRC_HIGHG__MSK 0x02 +#define BMA2X2_UNFILT_INT_SRC_HIGHG__REG BMA2X2_INT_SRC_REG + +#define BMA2X2_UNFILT_INT_SRC_SLOPE__POS 2 +#define BMA2X2_UNFILT_INT_SRC_SLOPE__LEN 1 +#define BMA2X2_UNFILT_INT_SRC_SLOPE__MSK 0x04 +#define BMA2X2_UNFILT_INT_SRC_SLOPE__REG BMA2X2_INT_SRC_REG + +#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__POS 3 +#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__LEN 1 +#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__MSK 0x08 +#define BMA2X2_UNFILT_INT_SRC_SLO_NO_MOT__REG BMA2X2_INT_SRC_REG + +#define BMA2X2_UNFILT_INT_SRC_TAP__POS 4 +#define BMA2X2_UNFILT_INT_SRC_TAP__LEN 1 +#define BMA2X2_UNFILT_INT_SRC_TAP__MSK 0x10 +#define BMA2X2_UNFILT_INT_SRC_TAP__REG BMA2X2_INT_SRC_REG + +#define BMA2X2_UNFILT_INT_SRC_DATA__POS 5 +#define BMA2X2_UNFILT_INT_SRC_DATA__LEN 1 +#define BMA2X2_UNFILT_INT_SRC_DATA__MSK 0x20 +#define BMA2X2_UNFILT_INT_SRC_DATA__REG BMA2X2_INT_SRC_REG + +#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__POS 0 +#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__LEN 1 +#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__MSK 0x01 +#define BMA2X2_INT1_PAD_ACTIVE_LEVEL__REG BMA2X2_INT_SET_REG + +#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__POS 2 +#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__LEN 1 +#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__MSK 0x04 +#define BMA2X2_INT2_PAD_ACTIVE_LEVEL__REG BMA2X2_INT_SET_REG + +#define BMA2X2_INT1_PAD_OUTPUT_TYPE__POS 1 +#define BMA2X2_INT1_PAD_OUTPUT_TYPE__LEN 1 +#define BMA2X2_INT1_PAD_OUTPUT_TYPE__MSK 0x02 +#define BMA2X2_INT1_PAD_OUTPUT_TYPE__REG BMA2X2_INT_SET_REG + +#define BMA2X2_INT2_PAD_OUTPUT_TYPE__POS 3 +#define BMA2X2_INT2_PAD_OUTPUT_TYPE__LEN 1 +#define BMA2X2_INT2_PAD_OUTPUT_TYPE__MSK 0x08 +#define BMA2X2_INT2_PAD_OUTPUT_TYPE__REG BMA2X2_INT_SET_REG + +#define BMA2X2_INT_MODE_SEL__POS 0 +#define BMA2X2_INT_MODE_SEL__LEN 4 +#define BMA2X2_INT_MODE_SEL__MSK 0x0F +#define BMA2X2_INT_MODE_SEL__REG BMA2X2_INT_CTRL_REG + +#define BMA2X2_RESET_INT__POS 7 +#define BMA2X2_RESET_INT__LEN 1 +#define BMA2X2_RESET_INT__MSK 0x80 +#define BMA2X2_RESET_INT__REG BMA2X2_INT_CTRL_REG + +#define BMA2X2_LOWG_DUR__POS 0 +#define BMA2X2_LOWG_DUR__LEN 8 +#define BMA2X2_LOWG_DUR__MSK 0xFF +#define BMA2X2_LOWG_DUR__REG BMA2X2_LOW_DURN_REG + +#define BMA2X2_LOWG_THRES__POS 0 +#define BMA2X2_LOWG_THRES__LEN 8 +#define BMA2X2_LOWG_THRES__MSK 0xFF +#define BMA2X2_LOWG_THRES__REG BMA2X2_LOW_THRES_REG + +#define BMA2X2_LOWG_HYST__POS 0 +#define BMA2X2_LOWG_HYST__LEN 2 +#define BMA2X2_LOWG_HYST__MSK 0x03 +#define BMA2X2_LOWG_HYST__REG BMA2X2_LOW_HIGH_HYST_REG + +#define BMA2X2_LOWG_INT_MODE__POS 2 +#define BMA2X2_LOWG_INT_MODE__LEN 1 +#define BMA2X2_LOWG_INT_MODE__MSK 0x04 +#define BMA2X2_LOWG_INT_MODE__REG BMA2X2_LOW_HIGH_HYST_REG + +#define BMA2X2_HIGHG_DUR__POS 0 +#define BMA2X2_HIGHG_DUR__LEN 8 +#define BMA2X2_HIGHG_DUR__MSK 0xFF +#define BMA2X2_HIGHG_DUR__REG BMA2X2_HIGH_DURN_REG + +#define BMA2X2_HIGHG_THRES__POS 0 +#define BMA2X2_HIGHG_THRES__LEN 8 +#define BMA2X2_HIGHG_THRES__MSK 0xFF +#define BMA2X2_HIGHG_THRES__REG BMA2X2_HIGH_THRES_REG + +#define BMA2X2_HIGHG_HYST__POS 6 +#define BMA2X2_HIGHG_HYST__LEN 2 +#define BMA2X2_HIGHG_HYST__MSK 0xC0 +#define BMA2X2_HIGHG_HYST__REG BMA2X2_LOW_HIGH_HYST_REG + +#define BMA2X2_SLOPE_DUR__POS 0 +#define BMA2X2_SLOPE_DUR__LEN 2 +#define BMA2X2_SLOPE_DUR__MSK 0x03 +#define BMA2X2_SLOPE_DUR__REG BMA2X2_SLOPE_DURN_REG + +#define BMA2X2_SLO_NO_MOT_DUR__POS 2 +#define BMA2X2_SLO_NO_MOT_DUR__LEN 6 +#define BMA2X2_SLO_NO_MOT_DUR__MSK 0xFC +#define BMA2X2_SLO_NO_MOT_DUR__REG BMA2X2_SLOPE_DURN_REG + +#define BMA2X2_SLOPE_THRES__POS 0 +#define BMA2X2_SLOPE_THRES__LEN 8 +#define BMA2X2_SLOPE_THRES__MSK 0xFF +#define BMA2X2_SLOPE_THRES__REG BMA2X2_SLOPE_THRES_REG + +#define BMA2X2_SLO_NO_MOT_THRES__POS 0 +#define BMA2X2_SLO_NO_MOT_THRES__LEN 8 +#define BMA2X2_SLO_NO_MOT_THRES__MSK 0xFF +#define BMA2X2_SLO_NO_MOT_THRES__REG BMA2X2_SLO_NO_MOT_THRES_REG + +#define BMA2X2_TAP_DUR__POS 0 +#define BMA2X2_TAP_DUR__LEN 3 +#define BMA2X2_TAP_DUR__MSK 0x07 +#define BMA2X2_TAP_DUR__REG BMA2X2_TAP_PARAM_REG + +#define BMA2X2_TAP_SHOCK_DURN__POS 6 +#define BMA2X2_TAP_SHOCK_DURN__LEN 1 +#define BMA2X2_TAP_SHOCK_DURN__MSK 0x40 +#define BMA2X2_TAP_SHOCK_DURN__REG BMA2X2_TAP_PARAM_REG + +#define BMA2X2_ADV_TAP_INT__POS 5 +#define BMA2X2_ADV_TAP_INT__LEN 1 +#define BMA2X2_ADV_TAP_INT__MSK 0x20 +#define BMA2X2_ADV_TAP_INT__REG BMA2X2_TAP_PARAM_REG + +#define BMA2X2_TAP_QUIET_DURN__POS 7 +#define BMA2X2_TAP_QUIET_DURN__LEN 1 +#define BMA2X2_TAP_QUIET_DURN__MSK 0x80 +#define BMA2X2_TAP_QUIET_DURN__REG BMA2X2_TAP_PARAM_REG + +#define BMA2X2_TAP_THRES__POS 0 +#define BMA2X2_TAP_THRES__LEN 5 +#define BMA2X2_TAP_THRES__MSK 0x1F +#define BMA2X2_TAP_THRES__REG BMA2X2_TAP_THRES_REG + +#define BMA2X2_TAP_SAMPLES__POS 6 +#define BMA2X2_TAP_SAMPLES__LEN 2 +#define BMA2X2_TAP_SAMPLES__MSK 0xC0 +#define BMA2X2_TAP_SAMPLES__REG BMA2X2_TAP_THRES_REG + +#define BMA2X2_ORIENT_MODE__POS 0 +#define BMA2X2_ORIENT_MODE__LEN 2 +#define BMA2X2_ORIENT_MODE__MSK 0x03 +#define BMA2X2_ORIENT_MODE__REG BMA2X2_ORIENT_PARAM_REG + +#define BMA2X2_ORIENT_BLOCK__POS 2 +#define BMA2X2_ORIENT_BLOCK__LEN 2 +#define BMA2X2_ORIENT_BLOCK__MSK 0x0C +#define BMA2X2_ORIENT_BLOCK__REG BMA2X2_ORIENT_PARAM_REG + +#define BMA2X2_ORIENT_HYST__POS 4 +#define BMA2X2_ORIENT_HYST__LEN 3 +#define BMA2X2_ORIENT_HYST__MSK 0x70 +#define BMA2X2_ORIENT_HYST__REG BMA2X2_ORIENT_PARAM_REG + +#define BMA2X2_ORIENT_AXIS__POS 7 +#define BMA2X2_ORIENT_AXIS__LEN 1 +#define BMA2X2_ORIENT_AXIS__MSK 0x80 +#define BMA2X2_ORIENT_AXIS__REG BMA2X2_THETA_BLOCK_REG + +#define BMA2X2_ORIENT_UD_EN__POS 6 +#define BMA2X2_ORIENT_UD_EN__LEN 1 +#define BMA2X2_ORIENT_UD_EN__MSK 0x40 +#define BMA2X2_ORIENT_UD_EN__REG BMA2X2_THETA_BLOCK_REG + +#define BMA2X2_THETA_BLOCK__POS 0 +#define BMA2X2_THETA_BLOCK__LEN 6 +#define BMA2X2_THETA_BLOCK__MSK 0x3F +#define BMA2X2_THETA_BLOCK__REG BMA2X2_THETA_BLOCK_REG + +#define BMA2X2_THETA_FLAT__POS 0 +#define BMA2X2_THETA_FLAT__LEN 6 +#define BMA2X2_THETA_FLAT__MSK 0x3F +#define BMA2X2_THETA_FLAT__REG BMA2X2_THETA_FLAT_REG + +#define BMA2X2_FLAT_HOLD_TIME__POS 4 +#define BMA2X2_FLAT_HOLD_TIME__LEN 2 +#define BMA2X2_FLAT_HOLD_TIME__MSK 0x30 +#define BMA2X2_FLAT_HOLD_TIME__REG BMA2X2_FLAT_HOLD_TIME_REG + +#define BMA2X2_FLAT_HYS__POS 0 +#define BMA2X2_FLAT_HYS__LEN 3 +#define BMA2X2_FLAT_HYS__MSK 0x07 +#define BMA2X2_FLAT_HYS__REG BMA2X2_FLAT_HOLD_TIME_REG + +#define BMA2X2_FIFO_WML_TRIG_RETAIN__POS 0 +#define BMA2X2_FIFO_WML_TRIG_RETAIN__LEN 6 +#define BMA2X2_FIFO_WML_TRIG_RETAIN__MSK 0x3F +#define BMA2X2_FIFO_WML_TRIG_RETAIN__REG BMA2X2_FIFO_WML_TRIG + +#define BMA2X2_EN_SELF_TEST__POS 0 +#define BMA2X2_EN_SELF_TEST__LEN 2 +#define BMA2X2_EN_SELF_TEST__MSK 0x03 +#define BMA2X2_EN_SELF_TEST__REG BMA2X2_SELF_TEST_REG + +#define BMA2X2_NEG_SELF_TEST__POS 2 +#define BMA2X2_NEG_SELF_TEST__LEN 1 +#define BMA2X2_NEG_SELF_TEST__MSK 0x04 +#define BMA2X2_NEG_SELF_TEST__REG BMA2X2_SELF_TEST_REG + +#define BMA2X2_SELF_TEST_AMP__POS 4 +#define BMA2X2_SELF_TEST_AMP__LEN 1 +#define BMA2X2_SELF_TEST_AMP__MSK 0x10 +#define BMA2X2_SELF_TEST_AMP__REG BMA2X2_SELF_TEST_REG + + +#define BMA2X2_UNLOCK_EE_PROG_MODE__POS 0 +#define BMA2X2_UNLOCK_EE_PROG_MODE__LEN 1 +#define BMA2X2_UNLOCK_EE_PROG_MODE__MSK 0x01 +#define BMA2X2_UNLOCK_EE_PROG_MODE__REG BMA2X2_EEPROM_CTRL_REG + +#define BMA2X2_START_EE_PROG_TRIG__POS 1 +#define BMA2X2_START_EE_PROG_TRIG__LEN 1 +#define BMA2X2_START_EE_PROG_TRIG__MSK 0x02 +#define BMA2X2_START_EE_PROG_TRIG__REG BMA2X2_EEPROM_CTRL_REG + +#define BMA2X2_EE_PROG_READY__POS 2 +#define BMA2X2_EE_PROG_READY__LEN 1 +#define BMA2X2_EE_PROG_READY__MSK 0x04 +#define BMA2X2_EE_PROG_READY__REG BMA2X2_EEPROM_CTRL_REG + +#define BMA2X2_UPDATE_IMAGE__POS 3 +#define BMA2X2_UPDATE_IMAGE__LEN 1 +#define BMA2X2_UPDATE_IMAGE__MSK 0x08 +#define BMA2X2_UPDATE_IMAGE__REG BMA2X2_EEPROM_CTRL_REG + +#define BMA2X2_EE_REMAIN__POS 4 +#define BMA2X2_EE_REMAIN__LEN 4 +#define BMA2X2_EE_REMAIN__MSK 0xF0 +#define BMA2X2_EE_REMAIN__REG BMA2X2_EEPROM_CTRL_REG + +#define BMA2X2_EN_SPI_MODE_3__POS 0 +#define BMA2X2_EN_SPI_MODE_3__LEN 1 +#define BMA2X2_EN_SPI_MODE_3__MSK 0x01 +#define BMA2X2_EN_SPI_MODE_3__REG BMA2X2_SERIAL_CTRL_REG + +#define BMA2X2_I2C_WATCHDOG_PERIOD__POS 1 +#define BMA2X2_I2C_WATCHDOG_PERIOD__LEN 1 +#define BMA2X2_I2C_WATCHDOG_PERIOD__MSK 0x02 +#define BMA2X2_I2C_WATCHDOG_PERIOD__REG BMA2X2_SERIAL_CTRL_REG + +#define BMA2X2_EN_I2C_WATCHDOG__POS 2 +#define BMA2X2_EN_I2C_WATCHDOG__LEN 1 +#define BMA2X2_EN_I2C_WATCHDOG__MSK 0x04 +#define BMA2X2_EN_I2C_WATCHDOG__REG BMA2X2_SERIAL_CTRL_REG + +#define BMA2X2_EXT_MODE__POS 7 +#define BMA2X2_EXT_MODE__LEN 1 +#define BMA2X2_EXT_MODE__MSK 0x80 +#define BMA2X2_EXT_MODE__REG BMA2X2_EXTMODE_CTRL_REG + +#define BMA2X2_ALLOW_UPPER__POS 6 +#define BMA2X2_ALLOW_UPPER__LEN 1 +#define BMA2X2_ALLOW_UPPER__MSK 0x40 +#define BMA2X2_ALLOW_UPPER__REG BMA2X2_EXTMODE_CTRL_REG + +#define BMA2X2_MAP_2_LOWER__POS 5 +#define BMA2X2_MAP_2_LOWER__LEN 1 +#define BMA2X2_MAP_2_LOWER__MSK 0x20 +#define BMA2X2_MAP_2_LOWER__REG BMA2X2_EXTMODE_CTRL_REG + +#define BMA2X2_MAGIC_NUMBER__POS 0 +#define BMA2X2_MAGIC_NUMBER__LEN 5 +#define BMA2X2_MAGIC_NUMBER__MSK 0x1F +#define BMA2X2_MAGIC_NUMBER__REG BMA2X2_EXTMODE_CTRL_REG + +#define BMA2X2_UNLOCK_EE_WRITE_TRIM__POS 4 +#define BMA2X2_UNLOCK_EE_WRITE_TRIM__LEN 4 +#define BMA2X2_UNLOCK_EE_WRITE_TRIM__MSK 0xF0 +#define BMA2X2_UNLOCK_EE_WRITE_TRIM__REG BMA2X2_CTRL_UNLOCK_REG + +#define BMA2X2_EN_SLOW_COMP_X__POS 0 +#define BMA2X2_EN_SLOW_COMP_X__LEN 1 +#define BMA2X2_EN_SLOW_COMP_X__MSK 0x01 +#define BMA2X2_EN_SLOW_COMP_X__REG BMA2X2_OFFSET_CTRL_REG + +#define BMA2X2_EN_SLOW_COMP_Y__POS 1 +#define BMA2X2_EN_SLOW_COMP_Y__LEN 1 +#define BMA2X2_EN_SLOW_COMP_Y__MSK 0x02 +#define BMA2X2_EN_SLOW_COMP_Y__REG BMA2X2_OFFSET_CTRL_REG + +#define BMA2X2_EN_SLOW_COMP_Z__POS 2 +#define BMA2X2_EN_SLOW_COMP_Z__LEN 1 +#define BMA2X2_EN_SLOW_COMP_Z__MSK 0x04 +#define BMA2X2_EN_SLOW_COMP_Z__REG BMA2X2_OFFSET_CTRL_REG + +#define BMA2X2_FAST_CAL_RDY_S__POS 4 +#define BMA2X2_FAST_CAL_RDY_S__LEN 1 +#define BMA2X2_FAST_CAL_RDY_S__MSK 0x10 +#define BMA2X2_FAST_CAL_RDY_S__REG BMA2X2_OFFSET_CTRL_REG + +#define BMA2X2_CAL_TRIGGER__POS 5 +#define BMA2X2_CAL_TRIGGER__LEN 2 +#define BMA2X2_CAL_TRIGGER__MSK 0x60 +#define BMA2X2_CAL_TRIGGER__REG BMA2X2_OFFSET_CTRL_REG + +#define BMA2X2_RESET_OFFSET_REGS__POS 7 +#define BMA2X2_RESET_OFFSET_REGS__LEN 1 +#define BMA2X2_RESET_OFFSET_REGS__MSK 0x80 +#define BMA2X2_RESET_OFFSET_REGS__REG BMA2X2_OFFSET_CTRL_REG + +#define BMA2X2_COMP_CUTOFF__POS 0 +#define BMA2X2_COMP_CUTOFF__LEN 1 +#define BMA2X2_COMP_CUTOFF__MSK 0x01 +#define BMA2X2_COMP_CUTOFF__REG BMA2X2_OFFSET_PARAMS_REG + +#define BMA2X2_COMP_TARGET_OFFSET_X__POS 1 +#define BMA2X2_COMP_TARGET_OFFSET_X__LEN 2 +#define BMA2X2_COMP_TARGET_OFFSET_X__MSK 0x06 +#define BMA2X2_COMP_TARGET_OFFSET_X__REG BMA2X2_OFFSET_PARAMS_REG + +#define BMA2X2_COMP_TARGET_OFFSET_Y__POS 3 +#define BMA2X2_COMP_TARGET_OFFSET_Y__LEN 2 +#define BMA2X2_COMP_TARGET_OFFSET_Y__MSK 0x18 +#define BMA2X2_COMP_TARGET_OFFSET_Y__REG BMA2X2_OFFSET_PARAMS_REG + +#define BMA2X2_COMP_TARGET_OFFSET_Z__POS 5 +#define BMA2X2_COMP_TARGET_OFFSET_Z__LEN 2 +#define BMA2X2_COMP_TARGET_OFFSET_Z__MSK 0x60 +#define BMA2X2_COMP_TARGET_OFFSET_Z__REG BMA2X2_OFFSET_PARAMS_REG + +#define BMA2X2_FIFO_DATA_SELECT__POS 0 +#define BMA2X2_FIFO_DATA_SELECT__LEN 2 +#define BMA2X2_FIFO_DATA_SELECT__MSK 0x03 +#define BMA2X2_FIFO_DATA_SELECT__REG BMA2X2_FIFO_MODE_REG + +#define BMA2X2_FIFO_TRIGGER_SOURCE__POS 2 +#define BMA2X2_FIFO_TRIGGER_SOURCE__LEN 2 +#define BMA2X2_FIFO_TRIGGER_SOURCE__MSK 0x0C +#define BMA2X2_FIFO_TRIGGER_SOURCE__REG BMA2X2_FIFO_MODE_REG + +#define BMA2X2_FIFO_TRIGGER_ACTION__POS 4 +#define BMA2X2_FIFO_TRIGGER_ACTION__LEN 2 +#define BMA2X2_FIFO_TRIGGER_ACTION__MSK 0x30 +#define BMA2X2_FIFO_TRIGGER_ACTION__REG BMA2X2_FIFO_MODE_REG + +#define BMA2X2_FIFO_MODE__POS 6 +#define BMA2X2_FIFO_MODE__LEN 2 +#define BMA2X2_FIFO_MODE__MSK 0xC0 +#define BMA2X2_FIFO_MODE__REG BMA2X2_FIFO_MODE_REG + + +#define BMA2X2_STATUS1 0 +#define BMA2X2_STATUS2 1 +#define BMA2X2_STATUS3 2 +#define BMA2X2_STATUS4 3 +#define BMA2X2_STATUS5 4 + + +#define BMA2X2_RANGE_2G 3 +#define BMA2X2_RANGE_4G 5 +#define BMA2X2_RANGE_8G 8 +#define BMA2X2_RANGE_16G 12 + + +#define BMA2X2_BW_7_81HZ 0x08 +#define BMA2X2_BW_15_63HZ 0x09 +#define BMA2X2_BW_31_25HZ 0x0A +#define BMA2X2_BW_62_50HZ 0x0B +#define BMA2X2_BW_125HZ 0x0C +#define BMA2X2_BW_250HZ 0x0D +#define BMA2X2_BW_500HZ 0x0E +#define BMA2X2_BW_1000HZ 0x0F + +#define BMA2X2_SLEEP_DUR_0_5MS 0x05 +#define BMA2X2_SLEEP_DUR_1MS 0x06 +#define BMA2X2_SLEEP_DUR_2MS 0x07 +#define BMA2X2_SLEEP_DUR_4MS 0x08 +#define BMA2X2_SLEEP_DUR_6MS 0x09 +#define BMA2X2_SLEEP_DUR_10MS 0x0A +#define BMA2X2_SLEEP_DUR_25MS 0x0B +#define BMA2X2_SLEEP_DUR_50MS 0x0C +#define BMA2X2_SLEEP_DUR_100MS 0x0D +#define BMA2X2_SLEEP_DUR_500MS 0x0E +#define BMA2X2_SLEEP_DUR_1S 0x0F + +#define BMA2X2_LATCH_DUR_NON_LATCH 0x00 +#define BMA2X2_LATCH_DUR_250MS 0x01 +#define BMA2X2_LATCH_DUR_500MS 0x02 +#define BMA2X2_LATCH_DUR_1S 0x03 +#define BMA2X2_LATCH_DUR_2S 0x04 +#define BMA2X2_LATCH_DUR_4S 0x05 +#define BMA2X2_LATCH_DUR_8S 0x06 +#define BMA2X2_LATCH_DUR_LATCH 0x07 +#define BMA2X2_LATCH_DUR_NON_LATCH1 0x08 +#define BMA2X2_LATCH_DUR_250US 0x09 +#define BMA2X2_LATCH_DUR_500US 0x0A +#define BMA2X2_LATCH_DUR_1MS 0x0B +#define BMA2X2_LATCH_DUR_12_5MS 0x0C +#define BMA2X2_LATCH_DUR_25MS 0x0D +#define BMA2X2_LATCH_DUR_50MS 0x0E +#define BMA2X2_LATCH_DUR_LATCH1 0x0F + +#define BMA2X2_MODE_NORMAL 0 +#define BMA2X2_MODE_LOWPOWER1 1 +#define BMA2X2_MODE_SUSPEND 2 +#define BMA2X2_MODE_DEEP_SUSPEND 3 +#define BMA2X2_MODE_LOWPOWER2 4 +#define BMA2X2_MODE_STANDBY 5 + +#define BMA2X2_X_AXIS 0 +#define BMA2X2_Y_AXIS 1 +#define BMA2X2_Z_AXIS 2 + +#define BMA2X2_Low_G_Interrupt 0 +#define BMA2X2_High_G_X_Interrupt 1 +#define BMA2X2_High_G_Y_Interrupt 2 +#define BMA2X2_High_G_Z_Interrupt 3 +#define BMA2X2_DATA_EN 4 +#define BMA2X2_Slope_X_Interrupt 5 +#define BMA2X2_Slope_Y_Interrupt 6 +#define BMA2X2_Slope_Z_Interrupt 7 +#define BMA2X2_Single_Tap_Interrupt 8 +#define BMA2X2_Double_Tap_Interrupt 9 +#define BMA2X2_Orient_Interrupt 10 +#define BMA2X2_Flat_Interrupt 11 +#define BMA2X2_FFULL_INTERRUPT 12 +#define BMA2X2_FWM_INTERRUPT 13 + +#define BMA2X2_INT1_LOWG 0 +#define BMA2X2_INT2_LOWG 1 +#define BMA2X2_INT1_HIGHG 0 +#define BMA2X2_INT2_HIGHG 1 +#define BMA2X2_INT1_SLOPE 0 +#define BMA2X2_INT2_SLOPE 1 +#define BMA2X2_INT1_SLO_NO_MOT 0 +#define BMA2X2_INT2_SLO_NO_MOT 1 +#define BMA2X2_INT1_DTAP 0 +#define BMA2X2_INT2_DTAP 1 +#define BMA2X2_INT1_STAP 0 +#define BMA2X2_INT2_STAP 1 +#define BMA2X2_INT1_ORIENT 0 +#define BMA2X2_INT2_ORIENT 1 +#define BMA2X2_INT1_FLAT 0 +#define BMA2X2_INT2_FLAT 1 +#define BMA2X2_INT1_NDATA 0 +#define BMA2X2_INT2_NDATA 1 +#define BMA2X2_INT1_FWM 0 +#define BMA2X2_INT2_FWM 1 +#define BMA2X2_INT1_FFULL 0 +#define BMA2X2_INT2_FFULL 1 + +#define BMA2X2_SRC_LOWG 0 +#define BMA2X2_SRC_HIGHG 1 +#define BMA2X2_SRC_SLOPE 2 +#define BMA2X2_SRC_SLO_NO_MOT 3 +#define BMA2X2_SRC_TAP 4 +#define BMA2X2_SRC_DATA 5 + +#define BMA2X2_INT1_OUTPUT 0 +#define BMA2X2_INT2_OUTPUT 1 +#define BMA2X2_INT1_LEVEL 0 +#define BMA2X2_INT2_LEVEL 1 + +#define BMA2X2_LOW_DURATION 0 +#define BMA2X2_HIGH_DURATION 1 +#define BMA2X2_SLOPE_DURATION 2 +#define BMA2X2_SLO_NO_MOT_DURATION 3 + +#define BMA2X2_LOW_THRESHOLD 0 +#define BMA2X2_HIGH_THRESHOLD 1 +#define BMA2X2_SLOPE_THRESHOLD 2 +#define BMA2X2_SLO_NO_MOT_THRESHOLD 3 + + +#define BMA2X2_LOWG_HYST 0 +#define BMA2X2_HIGHG_HYST 1 + +#define BMA2X2_ORIENT_THETA 0 +#define BMA2X2_FLAT_THETA 1 + +#define BMA2X2_I2C_SELECT 0 +#define BMA2X2_I2C_EN 1 + +#define BMA2X2_SLOW_COMP_X 0 +#define BMA2X2_SLOW_COMP_Y 1 +#define BMA2X2_SLOW_COMP_Z 2 + +#define BMA2X2_CUT_OFF 0 +#define BMA2X2_OFFSET_TRIGGER_X 1 +#define BMA2X2_OFFSET_TRIGGER_Y 2 +#define BMA2X2_OFFSET_TRIGGER_Z 3 + +#define BMA2X2_GP0 0 +#define BMA2X2_GP1 1 + +#define BMA2X2_SLO_NO_MOT_EN_X 0 +#define BMA2X2_SLO_NO_MOT_EN_Y 1 +#define BMA2X2_SLO_NO_MOT_EN_Z 2 +#define BMA2X2_SLO_NO_MOT_EN_SEL 3 + +#define BMA2X2_WAKE_UP_DUR_20MS 0 +#define BMA2X2_WAKE_UP_DUR_80MS 1 +#define BMA2X2_WAKE_UP_DUR_320MS 2 +#define BMA2X2_WAKE_UP_DUR_2560MS 3 + +#define BMA2X2_SELF_TEST0_ON 1 +#define BMA2X2_SELF_TEST1_ON 2 + +#define BMA2X2_EE_W_OFF 0 +#define BMA2X2_EE_W_ON 1 + +#define BMA2X2_LOW_TH_IN_G(gthres, range) ((256 * gthres) / range) + + +#define BMA2X2_HIGH_TH_IN_G(gthres, range) ((256 * gthres) / range) + + +#define BMA2X2_LOW_HY_IN_G(ghyst, range) ((32 * ghyst) / range) + + +#define BMA2X2_HIGH_HY_IN_G(ghyst, range) ((32 * ghyst) / range) + + +#define BMA2X2_SLOPE_TH_IN_G(gthres, range) ((128 * gthres) / range) + + +#define BMA2X2_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + + +#define BMA2X2_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK)) + + +#define BMA255_CHIP_ID 0XFA +#define BMA250E_CHIP_ID 0XF9 +#define BMA222E_CHIP_ID 0XF8 +#define BMA280_CHIP_ID 0XFB + +#define BMA255_TYPE 0 +#define BMA250E_TYPE 1 +#define BMA222E_TYPE 2 +#define BMA280_TYPE 3 + +#define MAX_FIFO_F_LEVEL 32 +#define MAX_FIFO_F_BYTES 6 +#define BMA_MAX_RETRY_I2C_XFER (100) + +static struct device *bma_device = NULL; +#define CALIBRATION_FILE_PATH "/efs/calibration_data" + +unsigned char *sensor_name[] = { "BMA255", "BMA250E", "BMA222E", "BMA280" }; + +struct bma2x2acc { + s16 x, + y, + z; +} ; + +struct bma2x2_data { + struct i2c_client *bma2x2_client; + atomic_t delay; + atomic_t enable; + atomic_t selftest_result; + unsigned int chip_id; + unsigned char mode; + signed char sensor_type; + struct input_dev *input; + struct bma2x2acc value; + struct mutex value_mutex; + struct mutex enable_mutex; + struct mutex mode_mutex; + struct delayed_work work; + struct work_struct irq_work; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + int IRQ; + +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + struct bosch_sensor_specific *bst_pd; +#endif +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bma2x2_early_suspend(struct early_suspend *h); +static void bma2x2_late_resume(struct early_suspend *h); +#endif + +static void bma2x2_remap_sensor_data(struct bma2x2acc *val, + struct bma2x2_data *client_data) +{ +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + struct bosch_sensor_data bsd; + + if (NULL == client_data->bst_pd) + return; + + bsd.x = val->x; + bsd.y = val->y; + bsd.z = val->z; + + bst_remap_sensor_data_dft_tab(&bsd, + client_data->bst_pd->place); + + val->x = bsd.x; + val->y = bsd.y; + val->z = bsd.z; +#else + (void)val; + (void)client_data; +#endif +} + + +static int bma2x2_smbus_read_byte(struct i2c_client *client, + unsigned char reg_addr, unsigned char *data) +{ + s32 dummy; + dummy = i2c_smbus_read_byte_data(client, reg_addr); + if (dummy < 0) + return -1; + *data = dummy & 0x000000ff; + + return 0; +} + +static int bma2x2_smbus_write_byte(struct i2c_client *client, + unsigned char reg_addr, unsigned char *data) +{ + s32 dummy; + + dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); + if (dummy < 0) + return -1; + return 0; +} + +static int bma2x2_smbus_read_byte_block(struct i2c_client *client, + unsigned char reg_addr, unsigned char *data, unsigned char len) +{ + s32 dummy; + dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data); + if (dummy < 0) + return -1; + return 0; +} + +static int bma_i2c_burst_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u16 len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < BMA_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + mdelay(1); + } + + if (BMA_MAX_RETRY_I2C_XFER <= retry) { + printk(KERN_INFO "I2C xfer error"); + return -EIO; + } + + return 0; +} + + +#ifdef BMA2X2_ENABLE_INT1 +static int bma2x2_set_int1_pad_sel(struct i2c_client *client, unsigned char + int1sel) +{ + int comres = 0; + unsigned char data; + unsigned char state; + state = 0x01; + + + switch (int1sel) { + case 0: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_LOWG__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_LOWG, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_LOWG__REG, &data); + break; + case 1: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_HIGHG__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_HIGHG, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_HIGHG__REG, &data); + break; + case 2: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_SLOPE__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_SLOPE, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_SLOPE__REG, &data); + break; + case 3: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_DB_TAP__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_DB_TAP, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_DB_TAP__REG, &data); + break; + case 4: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_SNG_TAP__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_SNG_TAP, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_SNG_TAP__REG, &data); + break; + case 5: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_ORIENT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_ORIENT, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_ORIENT__REG, &data); + break; + case 6: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_FLAT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_FLAT, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_FLAT__REG, &data); + break; + case 7: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT1_PAD_SLO_NO_MOT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT1_PAD_SLO_NO_MOT, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT1_PAD_SLO_NO_MOT__REG, &data); + break; + + default: + break; + } + + return comres; +} +#endif /* BMA2X2_ENABLE_INT1 */ +#ifdef BMA2X2_ENABLE_INT2 +static int bma2x2_set_int2_pad_sel(struct i2c_client *client, unsigned char + int2sel) +{ + int comres = 0; + unsigned char data; + unsigned char state; + state = 0x01; + + + switch (int2sel) { + case 0: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_LOWG__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_LOWG, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_LOWG__REG, &data); + break; + case 1: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_HIGHG__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_HIGHG, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_HIGHG__REG, &data); + break; + case 2: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_SLOPE__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_SLOPE, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_SLOPE__REG, &data); + break; + case 3: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_DB_TAP__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_DB_TAP, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_DB_TAP__REG, &data); + break; + case 4: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_SNG_TAP__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_SNG_TAP, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_SNG_TAP__REG, &data); + break; + case 5: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_ORIENT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_ORIENT, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_ORIENT__REG, &data); + break; + case 6: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_FLAT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_FLAT, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_FLAT__REG, &data); + break; + case 7: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_EN_INT2_PAD_SLO_NO_MOT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_INT2_PAD_SLO_NO_MOT, + state); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_EN_INT2_PAD_SLO_NO_MOT__REG, &data); + break; + default: + break; + } + + return comres; +} +#endif /* BMA2X2_ENABLE_INT2 */ + +static int bma2x2_set_Int_Enable(struct i2c_client *client, unsigned char + InterruptType , unsigned char value) +{ + int comres = 0; + unsigned char data1, data2; + + if ((11 < InterruptType) && (InterruptType < 16)) { + switch (InterruptType) { + case 12: + /* slow/no motion X Interrupt */ + comres = bma2x2_smbus_read_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_X_INT__REG, &data1); + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_INT_SLO_NO_MOT_EN_X_INT, value); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_X_INT__REG, &data1); + break; + case 13: + /* slow/no motion Y Interrupt */ + comres = bma2x2_smbus_read_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__REG, &data1); + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_INT_SLO_NO_MOT_EN_Y_INT, value); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_Y_INT__REG, &data1); + break; + case 14: + /* slow/no motion Z Interrupt */ + comres = bma2x2_smbus_read_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__REG, &data1); + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_INT_SLO_NO_MOT_EN_Z_INT, value); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_Z_INT__REG, &data1); + break; + case 15: + /* slow / no motion Interrupt select */ + comres = bma2x2_smbus_read_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG, &data1); + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT, value); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_INT_SLO_NO_MOT_EN_SEL_INT__REG, &data1); + } + + return comres; + } + + + comres = bma2x2_smbus_read_byte(client, BMA2X2_INT_ENABLE1_REG, &data1); + comres = bma2x2_smbus_read_byte(client, BMA2X2_INT_ENABLE2_REG, &data2); + + value = value & 1; + switch (InterruptType) { + case 0: + /* Low G Interrupt */ + data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_LOWG_INT, value); + break; + case 1: + /* High G X Interrupt */ + + data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_HIGHG_X_INT, + value); + break; + case 2: + /* High G Y Interrupt */ + + data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_HIGHG_Y_INT, + value); + break; + case 3: + /* High G Z Interrupt */ + + data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_HIGHG_Z_INT, + value); + break; + case 4: + /* New Data Interrupt */ + + data2 = BMA2X2_SET_BITSLICE(data2, BMA2X2_EN_NEW_DATA_INT, + value); + break; + case 5: + /* Slope X Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SLOPE_X_INT, + value); + break; + case 6: + /* Slope Y Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SLOPE_Y_INT, + value); + break; + case 7: + /* Slope Z Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SLOPE_Z_INT, + value); + break; + case 8: + /* Single Tap Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_SINGLE_TAP_INT, + value); + break; + case 9: + /* Double Tap Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_DOUBLE_TAP_INT, + value); + break; + case 10: + /* Orient Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_ORIENT_INT, value); + break; + case 11: + /* Flat Interrupt */ + + data1 = BMA2X2_SET_BITSLICE(data1, BMA2X2_EN_FLAT_INT, value); + break; + default: + break; + } + comres = bma2x2_smbus_write_byte(client, BMA2X2_INT_ENABLE1_REG, + &data1); + comres = bma2x2_smbus_write_byte(client, BMA2X2_INT_ENABLE2_REG, + &data2); + + return comres; +} + + +#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2) +static int bma2x2_get_interruptstatus1(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS1_REG, &data); + *intstatus = data; + + return comres; +} + + +static int bma2x2_get_HIGH_first(struct i2c_client *client, unsigned char + param, unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + switch (param) { + case 0: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_STATUS_ORIENT_HIGH_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_FIRST_X); + *intstatus = data; + break; + case 1: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_STATUS_ORIENT_HIGH_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_FIRST_Y); + *intstatus = data; + break; + case 2: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_STATUS_ORIENT_HIGH_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_FIRST_Z); + *intstatus = data; + break; + default: + break; + } + + return comres; +} + +static int bma2x2_get_HIGH_sign(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_SIGN_S); + *intstatus = data; + + return comres; +} + + +static int bma2x2_get_slope_first(struct i2c_client *client, unsigned char + param, unsigned char *intstatus) +{ + int comres = 0; + unsigned char data; + + switch (param) { + case 0: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_STATUS_TAP_SLOPE_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_FIRST_X); + *intstatus = data; + break; + case 1: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_STATUS_TAP_SLOPE_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_FIRST_Y); + *intstatus = data; + break; + case 2: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_STATUS_TAP_SLOPE_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_FIRST_Z); + *intstatus = data; + break; + default: + break; + } + + return comres; +} + +static int bma2x2_get_slope_sign(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_TAP_SLOPE_REG, + &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_SIGN_S); + *intstatus = data; + + return comres; +} + +static int bma2x2_get_orient_status(struct i2c_client *client, unsigned char + *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_S); + *intstatus = data; + + return comres; +} + +static int bma2x2_get_orient_flat_status(struct i2c_client *client, unsigned + char *intstatus) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_STATUS_ORIENT_HIGH_REG, + &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_FLAT_S); + *intstatus = data; + + return comres; +} +#endif /* defined(BMA2X2_ENABLE_INT1)||defined(BMA2X2_ENABLE_INT2) */ +static int bma2x2_set_Int_Mode(struct i2c_client *client, unsigned char Mode) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_INT_MODE_SEL__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_INT_MODE_SEL, Mode); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_INT_MODE_SEL__REG, &data); + + + return comres; +} + +static int bma2x2_get_Int_Mode(struct i2c_client *client, unsigned char *Mode) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_INT_MODE_SEL__REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_INT_MODE_SEL); + *Mode = data; + + + return comres; +} +static int bma2x2_set_slope_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_SLOPE_DUR__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_SLOPE_DUR, duration); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_SLOPE_DUR__REG, &data); + + + return comres; +} + +static int bma2x2_get_slope_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_SLOPE_DURN_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLOPE_DUR); + *status = data; + + + return comres; +} + +static int bma2x2_set_slope_no_mot_duration(struct i2c_client *client, + unsigned char duration) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2x2_SLO_NO_MOT_DUR__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2x2_SLO_NO_MOT_DUR, duration); + comres = bma2x2_smbus_write_byte(client, + BMA2x2_SLO_NO_MOT_DUR__REG, &data); + + + return comres; +} + +static int bma2x2_get_slope_no_mot_duration(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2x2_SLO_NO_MOT_DUR__REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2x2_SLO_NO_MOT_DUR); + *status = data; + + + return comres; +} + +static int bma2x2_set_slope_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data; + + data = threshold; + comres = bma2x2_smbus_write_byte(client, + BMA2X2_SLOPE_THRES__REG, &data); + + return comres; +} + +static int bma2x2_get_slope_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_SLOPE_THRES_REG, &data); + *status = data; + + return comres; +} + +static int bma2x2_set_slope_no_mot_threshold(struct i2c_client *client, + unsigned char threshold) +{ + int comres = 0; + unsigned char data; + + data = threshold; + comres = bma2x2_smbus_write_byte(client, + BMA2X2_SLO_NO_MOT_THRES_REG, &data); + + return comres; +} + +static int bma2x2_get_slope_no_mot_threshold(struct i2c_client *client, + unsigned char *status) +{ + int comres = 0; + unsigned char data; + + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_SLO_NO_MOT_THRES_REG, &data); + *status = data; + + return comres; +} + + +static int bma2x2_set_low_g_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data; + + data = duration; + comres = bma2x2_smbus_write_byte(client, BMA2X2_LOWG_DUR__REG, &data); + + return comres; +} + +static int bma2x2_get_low_g_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_LOW_DURN_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_LOWG_DUR); + *status = data; + + return comres; +} + +static int bma2x2_set_low_g_threshold(struct i2c_client *client, unsigned char + threshold) +{ + int comres = 0; + unsigned char data; + + data = threshold; + comres = bma2x2_smbus_write_byte(client, BMA2X2_LOWG_THRES__REG, &data); + + return comres; +} + +static int bma2x2_get_low_g_threshold(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_LOW_THRES_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_LOWG_THRES); + *status = data; + + return comres; +} + +static int bma2x2_set_high_g_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data; + + data = duration; + comres = bma2x2_smbus_write_byte(client, BMA2X2_HIGHG_DUR__REG, &data); + + return comres; +} + +static int bma2x2_get_high_g_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_HIGH_DURN_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_DUR); + *status = data; + + return comres; +} + +static int bma2x2_set_high_g_threshold(struct i2c_client *client, unsigned char + threshold) +{ + int comres = 0; + unsigned char data; + + data = threshold; + comres = bma2x2_smbus_write_byte(client, BMA2X2_HIGHG_THRES__REG, + &data); + + return comres; +} + +static int bma2x2_get_high_g_threshold(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_HIGH_THRES_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_HIGHG_THRES); + *status = data; + + return comres; +} + + +static int bma2x2_set_tap_duration(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_DUR__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_DUR, duration); + comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_DUR__REG, &data); + + return comres; +} + +static int bma2x2_get_tap_duration(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_PARAM_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_DUR); + *status = data; + + return comres; +} + +static int bma2x2_set_tap_shock(struct i2c_client *client, unsigned char setval) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_SHOCK_DURN__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_SHOCK_DURN, setval); + comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_SHOCK_DURN__REG, + &data); + + return comres; +} + +static int bma2x2_get_tap_shock(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_PARAM_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_SHOCK_DURN); + *status = data; + + return comres; +} + +static int bma2x2_set_tap_quiet(struct i2c_client *client, unsigned char + duration) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_QUIET_DURN__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_QUIET_DURN, duration); + comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_QUIET_DURN__REG, + &data); + + return comres; +} + +static int bma2x2_get_tap_quiet(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_PARAM_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_QUIET_DURN); + *status = data; + + return comres; +} + +static int bma2x2_set_tap_threshold(struct i2c_client *client, unsigned char + threshold) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_THRES__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_THRES, threshold); + comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_THRES__REG, &data); + + return comres; +} + +static int bma2x2_get_tap_threshold(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_THRES_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_THRES); + *status = data; + + return comres; +} + +static int bma2x2_set_tap_samp(struct i2c_client *client, unsigned char samp) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_SAMPLES__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_TAP_SAMPLES, samp); + comres = bma2x2_smbus_write_byte(client, BMA2X2_TAP_SAMPLES__REG, + &data); + + return comres; +} + +static int bma2x2_get_tap_samp(struct i2c_client *client, unsigned char *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TAP_THRES_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_TAP_SAMPLES); + *status = data; + + return comres; +} + +static int bma2x2_set_orient_mode(struct i2c_client *client, unsigned char mode) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_MODE__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_ORIENT_MODE, mode); + comres = bma2x2_smbus_write_byte(client, BMA2X2_ORIENT_MODE__REG, + &data); + + return comres; +} + +static int bma2x2_get_orient_mode(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_PARAM_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_MODE); + *status = data; + + return comres; +} + +static int bma2x2_set_orient_blocking(struct i2c_client *client, unsigned char + samp) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_BLOCK__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_ORIENT_BLOCK, samp); + comres = bma2x2_smbus_write_byte(client, BMA2X2_ORIENT_BLOCK__REG, + &data); + + return comres; +} + +static int bma2x2_get_orient_blocking(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_PARAM_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_BLOCK); + *status = data; + + return comres; +} + +static int bma2x2_set_orient_hyst(struct i2c_client *client, unsigned char + orienthyst) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_HYST__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_ORIENT_HYST, orienthyst); + comres = bma2x2_smbus_write_byte(client, BMA2X2_ORIENT_HYST__REG, + &data); + + return comres; +} + +static int bma2x2_get_orient_hyst(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_ORIENT_PARAM_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_ORIENT_HYST); + *status = data; + + return comres; +} +static int bma2x2_set_theta_blocking(struct i2c_client *client, unsigned char + thetablk) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_BLOCK__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_THETA_BLOCK, thetablk); + comres = bma2x2_smbus_write_byte(client, BMA2X2_THETA_BLOCK__REG, + &data); + + return comres; +} + +static int bma2x2_get_theta_blocking(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_BLOCK_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_THETA_BLOCK); + *status = data; + + return comres; +} + +static int bma2x2_set_theta_flat(struct i2c_client *client, unsigned char + thetaflat) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_FLAT__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_THETA_FLAT, thetaflat); + comres = bma2x2_smbus_write_byte(client, BMA2X2_THETA_FLAT__REG, &data); + + return comres; +} + +static int bma2x2_get_theta_flat(struct i2c_client *client, unsigned char + *status) +{ + int comres = 0 ; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_THETA_FLAT_REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_THETA_FLAT); + *status = data; + + return comres; +} + +static int bma2x2_set_flat_hold_time(struct i2c_client *client, unsigned char + holdtime) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_FLAT_HOLD_TIME__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_FLAT_HOLD_TIME, holdtime); + comres = bma2x2_smbus_write_byte(client, BMA2X2_FLAT_HOLD_TIME__REG, + &data); + + return comres; +} + +static int bma2x2_get_flat_hold_time(struct i2c_client *client, unsigned char + *holdtime) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_FLAT_HOLD_TIME_REG, + &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_FLAT_HOLD_TIME); + *holdtime = data ; + + return comres; +} + +static int bma2x2_set_mode(struct i2c_client *client, unsigned char Mode) +{ + int comres = 0; + unsigned char data1, data2; + + if (Mode < 6) { + comres = bma2x2_smbus_read_byte(client, BMA2X2_MODE_CTRL_REG, + &data1); + comres = bma2x2_smbus_read_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, + &data2); + switch (Mode) { + case BMA2X2_MODE_NORMAL: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_MODE_CTRL, 0); + data2 = BMA2X2_SET_BITSLICE(data2, + BMA2X2_LOW_POWER_MODE, 0); + bma2x2_smbus_write_byte(client, + BMA2X2_MODE_CTRL_REG, &data1); + mdelay(1); + bma2x2_smbus_write_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case BMA2X2_MODE_LOWPOWER1: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_MODE_CTRL, 2); + data2 = BMA2X2_SET_BITSLICE(data2, + BMA2X2_LOW_POWER_MODE, 0); + bma2x2_smbus_write_byte(client, + BMA2X2_MODE_CTRL_REG, &data1); + mdelay(1); + bma2x2_smbus_write_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case BMA2X2_MODE_SUSPEND: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_MODE_CTRL, 4); + data2 = BMA2X2_SET_BITSLICE(data2, + BMA2X2_LOW_POWER_MODE, 0); + bma2x2_smbus_write_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, &data2); + mdelay(1); + bma2x2_smbus_write_byte(client, + BMA2X2_MODE_CTRL_REG, &data1); + break; + case BMA2X2_MODE_DEEP_SUSPEND: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_MODE_CTRL, 1); + data2 = BMA2X2_SET_BITSLICE(data2, + BMA2X2_LOW_POWER_MODE, 1); + bma2x2_smbus_write_byte(client, + BMA2X2_MODE_CTRL_REG, &data1); + mdelay(1); + bma2x2_smbus_write_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case BMA2X2_MODE_LOWPOWER2: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_MODE_CTRL, 2); + data2 = BMA2X2_SET_BITSLICE(data2, + BMA2X2_LOW_POWER_MODE, 1); + bma2x2_smbus_write_byte(client, + BMA2X2_MODE_CTRL_REG, &data1); + mdelay(1); + bma2x2_smbus_write_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, &data2); + break; + case BMA2X2_MODE_STANDBY: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_MODE_CTRL, 4); + data2 = BMA2X2_SET_BITSLICE(data2, + BMA2X2_LOW_POWER_MODE, 1); + bma2x2_smbus_write_byte(client, + BMA2X2_LOW_NOISE_CTRL_REG, &data2); + mdelay(1); + bma2x2_smbus_write_byte(client, + BMA2X2_MODE_CTRL_REG, &data1); + break; + } + } else { + comres = -1 ; + } + + + return comres; +} + + +static int bma2x2_get_mode(struct i2c_client *client, unsigned char *Mode) +{ + int comres = 0; + unsigned char data1, data2; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_MODE_CTRL_REG, &data1); + comres = bma2x2_smbus_read_byte(client, BMA2X2_LOW_NOISE_CTRL_REG, + &data2); + + data1 = (data1 & 0xE0) >> 5; + data2 = (data2 & 0x40) >> 6; + + + if ((data1 == 0x00) && (data2 == 0x00)) { + *Mode = BMA2X2_MODE_NORMAL; + } else { + if ((data1 == 0x02) && (data2 == 0x00)) { + *Mode = BMA2X2_MODE_LOWPOWER1; + } else { + if ((data1 == 0x04 || data1 == 0x06) && + (data2 == 0x00)) { + *Mode = BMA2X2_MODE_SUSPEND; + } else { + if (((data1 & 0x01) == 0x01)) { + *Mode = BMA2X2_MODE_DEEP_SUSPEND; + } else { + if ((data1 == 0x02) && + (data2 == 0x01)) { + *Mode = BMA2X2_MODE_LOWPOWER2; + } else { + if ((data1 == 0x04) && (data2 == + 0x01)) { + *Mode = + BMA2X2_MODE_STANDBY; + } else { + *Mode = + BMA2X2_MODE_DEEP_SUSPEND; + } + } + } + } + } + } + + return comres; +} + +static int bma2x2_set_range(struct i2c_client *client, unsigned char Range) +{ + int comres = 0 ; + unsigned char data1; + + if ((Range == 3) || (Range == 5) || (Range == 8) || (Range == 12)) { + comres = bma2x2_smbus_read_byte(client, BMA2X2_RANGE_SEL_REG, + &data1); + switch (Range) { + case BMA2X2_RANGE_2G: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_RANGE_SEL, 3); + break; + case BMA2X2_RANGE_4G: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_RANGE_SEL, 5); + break; + case BMA2X2_RANGE_8G: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_RANGE_SEL, 8); + break; + case BMA2X2_RANGE_16G: + data1 = BMA2X2_SET_BITSLICE(data1, + BMA2X2_RANGE_SEL, 12); + break; + } + comres += bma2x2_smbus_write_byte(client, BMA2X2_RANGE_SEL_REG, + &data1); + } else { + comres = -1 ; + } + + return comres; +} + +static int bma2x2_get_range(struct i2c_client *client, unsigned char *Range) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_RANGE_SEL__REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_RANGE_SEL); + *Range = data; + + return comres; +} + + +static int bma2x2_set_bandwidth(struct i2c_client *client, unsigned char BW) +{ + int comres = 0; + unsigned char data; + int Bandwidth = 0; + + if (BW > 7 && BW < 16) { + switch (BW) { + case BMA2X2_BW_7_81HZ: + Bandwidth = BMA2X2_BW_7_81HZ; + + /* 7.81 Hz 64000 uS */ + break; + case BMA2X2_BW_15_63HZ: + Bandwidth = BMA2X2_BW_15_63HZ; + + /* 15.63 Hz 32000 uS */ + break; + case BMA2X2_BW_31_25HZ: + Bandwidth = BMA2X2_BW_31_25HZ; + + /* 31.25 Hz 16000 uS */ + break; + case BMA2X2_BW_62_50HZ: + Bandwidth = BMA2X2_BW_62_50HZ; + + /* 62.50 Hz 8000 uS */ + break; + case BMA2X2_BW_125HZ: + Bandwidth = BMA2X2_BW_125HZ; + + /* 125 Hz 4000 uS */ + break; + case BMA2X2_BW_250HZ: + Bandwidth = BMA2X2_BW_250HZ; + + /* 250 Hz 2000 uS */ + break; + case BMA2X2_BW_500HZ: + Bandwidth = BMA2X2_BW_500HZ; + + /* 500 Hz 1000 uS */ + break; + case BMA2X2_BW_1000HZ: + Bandwidth = BMA2X2_BW_1000HZ; + + /* 1000 Hz 500 uS */ + break; + } + comres = bma2x2_smbus_read_byte(client, BMA2X2_BANDWIDTH__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_BANDWIDTH, Bandwidth); + comres += bma2x2_smbus_write_byte(client, BMA2X2_BANDWIDTH__REG, + &data); + } else { + comres = -1 ; + } + + return comres; +} + +static int bma2x2_get_bandwidth(struct i2c_client *client, unsigned char *BW) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_BANDWIDTH__REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_BANDWIDTH); + *BW = data ; + + return comres; +} + +int bma2x2_get_sleep_duration(struct i2c_client *client, unsigned char + *sleep_dur) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_SLEEP_DUR__REG, &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_SLEEP_DUR); + *sleep_dur = data; + + return comres; +} + +int bma2x2_set_sleep_duration(struct i2c_client *client, unsigned char + sleep_dur) +{ + int comres = 0; + unsigned char data; + int sleep_duration = 0; + + if (sleep_dur > 4 && sleep_dur < 16) { + switch (sleep_dur) { + case BMA2X2_SLEEP_DUR_0_5MS: + sleep_duration = BMA2X2_SLEEP_DUR_0_5MS; + + /* 0.5 MS */ + break; + case BMA2X2_SLEEP_DUR_1MS: + sleep_duration = BMA2X2_SLEEP_DUR_1MS; + + /* 1 MS */ + break; + case BMA2X2_SLEEP_DUR_2MS: + sleep_duration = BMA2X2_SLEEP_DUR_2MS; + + /* 2 MS */ + break; + case BMA2X2_SLEEP_DUR_4MS: + sleep_duration = BMA2X2_SLEEP_DUR_4MS; + + /* 4 MS */ + break; + case BMA2X2_SLEEP_DUR_6MS: + sleep_duration = BMA2X2_SLEEP_DUR_6MS; + + /* 6 MS */ + break; + case BMA2X2_SLEEP_DUR_10MS: + sleep_duration = BMA2X2_SLEEP_DUR_10MS; + + /* 10 MS */ + break; + case BMA2X2_SLEEP_DUR_25MS: + sleep_duration = BMA2X2_SLEEP_DUR_25MS; + + /* 25 MS */ + break; + case BMA2X2_SLEEP_DUR_50MS: + sleep_duration = BMA2X2_SLEEP_DUR_50MS; + + /* 50 MS */ + break; + case BMA2X2_SLEEP_DUR_100MS: + sleep_duration = BMA2X2_SLEEP_DUR_100MS; + + /* 100 MS */ + break; + case BMA2X2_SLEEP_DUR_500MS: + sleep_duration = BMA2X2_SLEEP_DUR_500MS; + + /* 500 MS */ + break; + case BMA2X2_SLEEP_DUR_1S: + sleep_duration = BMA2X2_SLEEP_DUR_1S; + + /* 1 SECS */ + break; + } + comres = bma2x2_smbus_read_byte(client, BMA2X2_SLEEP_DUR__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_SLEEP_DUR, + sleep_duration); + comres = bma2x2_smbus_write_byte(client, BMA2X2_SLEEP_DUR__REG, + &data); + } else { + comres = -1 ; + } + + + return comres; +} + +static int bma2x2_get_fifo_mode(struct i2c_client *client, unsigned char + *fifo_mode) +{ + int comres; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_FIFO_MODE__REG, &data); + *fifo_mode = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_MODE); + + return comres; +} + +static int bma2x2_set_fifo_mode(struct i2c_client *client, unsigned char + fifo_mode) +{ + unsigned char data; + int comres = 0; + + if (fifo_mode < 4) { + comres = bma2x2_smbus_read_byte(client, BMA2X2_FIFO_MODE__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_MODE, fifo_mode); + comres = bma2x2_smbus_write_byte(client, BMA2X2_FIFO_MODE__REG, + &data); + } else { + comres = -1 ; + } + + return comres; +} + + +static int bma2x2_get_fifo_trig(struct i2c_client *client, unsigned char + *fifo_trig) +{ + int comres; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_TRIGGER_ACTION__REG, &data); + *fifo_trig = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_ACTION); + + return comres; +} + +static int bma2x2_set_fifo_trig(struct i2c_client *client, unsigned char + fifo_trig) +{ + unsigned char data; + int comres = 0; + + if (fifo_trig < 4) { + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_TRIGGER_ACTION__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_ACTION, + fifo_trig); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_FIFO_TRIGGER_ACTION__REG, &data); + } else { + comres = -1 ; + } + + return comres; +} + +static int bma2x2_get_fifo_trig_src(struct i2c_client *client, unsigned char + *trig_src) +{ + int comres; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_TRIGGER_SOURCE__REG, &data); + *trig_src = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_SOURCE); + + return comres; +} + + +static int bma2x2_set_fifo_trig_src(struct i2c_client *client, unsigned char + trig_src) +{ + unsigned char data; + int comres = 0; + + if (trig_src < 4) { + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_TRIGGER_SOURCE__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_TRIGGER_SOURCE, + trig_src); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_FIFO_TRIGGER_SOURCE__REG, &data); + } else { + comres = -1 ; + } + + return comres; +} + +static int bma2x2_get_fifo_framecount(struct i2c_client *client, unsigned char + *framecount) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_FRAME_COUNTER_S__REG, &data); + *framecount = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_FRAME_COUNTER_S); + + return comres; +} + +static int bma2x2_get_fifo_data_sel(struct i2c_client *client, unsigned char + *data_sel) +{ + int comres; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_DATA_SELECT__REG, &data); + *data_sel = BMA2X2_GET_BITSLICE(data, BMA2X2_FIFO_DATA_SELECT); + + return comres; +} + +static int bma2x2_set_fifo_data_sel(struct i2c_client *client, unsigned char + data_sel) +{ + unsigned char data; + int comres = 0; + + if (data_sel < 4) { + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_DATA_SELECT__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_FIFO_DATA_SELECT, + data_sel); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_FIFO_DATA_SELECT__REG, + &data); + } else { + comres = -1 ; + } + + return comres; +} + +static int bma2x2_get_fifo_data_out_reg(struct i2c_client *client, unsigned char + *out_reg) +{ + unsigned char data; + int comres = 0; + + comres = bma2x2_smbus_read_byte(client, + BMA2X2_FIFO_DATA_OUTPUT_REG, &data); + *out_reg = data; + + return comres; +} + +static int bma2x2_get_offset_target(struct i2c_client *client, unsigned char + channel, unsigned char *offset) +{ + unsigned char data; + int comres = 0; + + switch (channel) { + case BMA2X2_CUT_OFF: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_CUTOFF__REG, &data); + *offset = BMA2X2_GET_BITSLICE(data, BMA2X2_COMP_CUTOFF); + break; + case BMA2X2_OFFSET_TRIGGER_X: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_TARGET_OFFSET_X__REG, &data); + *offset = BMA2X2_GET_BITSLICE(data, + BMA2X2_COMP_TARGET_OFFSET_X); + break; + case BMA2X2_OFFSET_TRIGGER_Y: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_TARGET_OFFSET_Y__REG, &data); + *offset = BMA2X2_GET_BITSLICE(data, + BMA2X2_COMP_TARGET_OFFSET_Y); + break; + case BMA2X2_OFFSET_TRIGGER_Z: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_TARGET_OFFSET_Z__REG, &data); + *offset = BMA2X2_GET_BITSLICE(data, + BMA2X2_COMP_TARGET_OFFSET_Z); + break; + default: + comres = -1; + break; + } + + return comres; +} + +static int bma2x2_set_offset_target(struct i2c_client *client, unsigned char + channel, unsigned char offset) +{ + unsigned char data; + int comres = 0; + + switch (channel) { + case BMA2X2_CUT_OFF: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_CUTOFF__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_COMP_CUTOFF, + offset); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_COMP_CUTOFF__REG, &data); + break; + case BMA2X2_OFFSET_TRIGGER_X: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_TARGET_OFFSET_X__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, + BMA2X2_COMP_TARGET_OFFSET_X, + offset); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_COMP_TARGET_OFFSET_X__REG, + &data); + break; + case BMA2X2_OFFSET_TRIGGER_Y: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_TARGET_OFFSET_Y__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, + BMA2X2_COMP_TARGET_OFFSET_Y, + offset); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_COMP_TARGET_OFFSET_Y__REG, + &data); + break; + case BMA2X2_OFFSET_TRIGGER_Z: + comres = bma2x2_smbus_read_byte(client, + BMA2X2_COMP_TARGET_OFFSET_Z__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, + BMA2X2_COMP_TARGET_OFFSET_Z, + offset); + comres = bma2x2_smbus_write_byte(client, + BMA2X2_COMP_TARGET_OFFSET_Z__REG, + &data); + break; + default: + comres = -1; + break; + } + + return comres; +} + +static int bma2x2_get_cal_ready(struct i2c_client *client, unsigned char *calrdy + ) +{ + int comres = 0 ; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_FAST_CAL_RDY_S__REG, + &data); + data = BMA2X2_GET_BITSLICE(data, BMA2X2_FAST_CAL_RDY_S); + *calrdy = data; + + return comres; +} + +static int bma2x2_set_cal_trigger(struct i2c_client *client, unsigned char + caltrigger) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_CAL_TRIGGER__REG, &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_CAL_TRIGGER, caltrigger); + comres = bma2x2_smbus_write_byte(client, BMA2X2_CAL_TRIGGER__REG, + &data); + + return comres; +} + +static int bma2x2_write_reg(struct i2c_client *client, unsigned char addr, + unsigned char *data) +{ + int comres = 0 ; + comres = bma2x2_smbus_write_byte(client, addr, data); + + return comres; +} + + +static int bma2x2_set_offset_x(struct i2c_client *client, unsigned char + offsetfilt) +{ + int comres = 0; + unsigned char data; + + data = offsetfilt; + comres = bma2x2_smbus_write_byte(client, BMA2X2_OFFSET_X_AXIS_REG, + &data); + + return comres; +} + + +static int bma2x2_get_offset_x(struct i2c_client *client, unsigned char + *offsetfilt) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_OFFSET_X_AXIS_REG, + &data); + *offsetfilt = data; + + return comres; +} + +static int bma2x2_set_offset_y(struct i2c_client *client, unsigned char + offsetfilt) +{ + int comres = 0; + unsigned char data; + + data = offsetfilt; + comres = bma2x2_smbus_write_byte(client, BMA2X2_OFFSET_Y_AXIS_REG, + &data); + + return comres; +} + +static int bma2x2_get_offset_y(struct i2c_client *client, unsigned char + *offsetfilt) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_OFFSET_Y_AXIS_REG, + &data); + *offsetfilt = data; + + return comres; +} + +static int bma2x2_set_offset_z(struct i2c_client *client, unsigned char + offsetfilt) +{ + int comres = 0; + unsigned char data; + + data = offsetfilt; + comres = bma2x2_smbus_write_byte(client, BMA2X2_OFFSET_Z_AXIS_REG, + &data); + + return comres; +} + +static int bma2x2_get_offset_z(struct i2c_client *client, unsigned char + *offsetfilt) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_OFFSET_Z_AXIS_REG, + &data); + *offsetfilt = data; + + return comres; +} + + +static int bma2x2_set_selftest_st(struct i2c_client *client, unsigned char + selftest) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_EN_SELF_TEST__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_EN_SELF_TEST, selftest); + comres = bma2x2_smbus_write_byte(client, BMA2X2_EN_SELF_TEST__REG, + &data); + + return comres; +} + +static int bma2x2_set_selftest_stn(struct i2c_client *client, unsigned char stn) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_NEG_SELF_TEST__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_NEG_SELF_TEST, stn); + comres = bma2x2_smbus_write_byte(client, BMA2X2_NEG_SELF_TEST__REG, + &data); + + return comres; +} + +static int bma2x2_set_selftest_amp(struct i2c_client *client, unsigned char amp) +{ + int comres = 0; + unsigned char data; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_SELF_TEST_AMP__REG, + &data); + data = BMA2X2_SET_BITSLICE(data, BMA2X2_SELF_TEST_AMP, amp); + comres = bma2x2_smbus_write_byte(client, BMA2X2_SELF_TEST_AMP__REG, + &data); + + return comres; +} + +static int bma2x2_read_accel_x(struct i2c_client *client, + signed char sensor_type, short *a_x) +{ + int comres = 0; + unsigned char data[2]; + + switch (sensor_type) { + case 0: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X12_LSB__REG, data, 2); + *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X12_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X12_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X12_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X12_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + break; + case 1: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X10_LSB__REG, data, 2); + *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X10_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X10_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X10_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X10_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + break; + case 2: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X8_LSB__REG, data, 2); + *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X8_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X8_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X8_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X8_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + break; + case 3: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X14_LSB__REG, data, 2); + *a_x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X14_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X14_LSB__LEN)); + *a_x = *a_x << (sizeof(short)*8-(BMA2X2_ACC_X14_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + *a_x = *a_x >> (sizeof(short)*8-(BMA2X2_ACC_X14_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + break; + default: + break; + } + + return comres; +} + +static int bma2x2_soft_reset(struct i2c_client *client) +{ + int comres = 0; + unsigned char data = BMA2X2_EN_SOFT_RESET_VALUE ; + + comres = bma2x2_smbus_write_byte(client, BMA2X2_EN_SOFT_RESET__REG, + &data); + + return comres; +} + +static int bma2x2_read_accel_y(struct i2c_client *client, + signed char sensor_type, short *a_y) +{ + int comres = 0; + unsigned char data[2]; + + switch (sensor_type) { + case 0: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Y12_LSB__REG, data, 2); + *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y12_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y12_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y12_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y12_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + break; + case 1: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Y10_LSB__REG, data, 2); + *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y10_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y10_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y10_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y10_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + break; + case 2: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Y8_LSB__REG, data, 2); + *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y8_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y8_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y8_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y8_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + break; + case 3: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Y14_LSB__REG, data, 2); + *a_y = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Y14_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y14_LSB__LEN)); + *a_y = *a_y << (sizeof(short)*8-(BMA2X2_ACC_Y14_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + *a_y = *a_y >> (sizeof(short)*8-(BMA2X2_ACC_Y14_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + break; + default: + break; + } + + return comres; +} + +static int bma2x2_read_accel_z(struct i2c_client *client, + signed char sensor_type, short *a_z) +{ + int comres = 0; + unsigned char data[2]; + + switch (sensor_type) { + case 0: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Z12_LSB__REG, data, 2); + *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z12_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z12_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z12_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z12_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + case 1: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Z10_LSB__REG, data, 2); + *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z10_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z10_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z10_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z10_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + case 2: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Z8_LSB__REG, data, 2); + *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z8_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z8_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z8_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z8_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + case 3: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_Z14_LSB__REG, data, 2); + *a_z = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_Z14_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z14_LSB__LEN)); + *a_z = *a_z << (sizeof(short)*8-(BMA2X2_ACC_Z14_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + *a_z = *a_z >> (sizeof(short)*8-(BMA2X2_ACC_Z14_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + default: + break; + } + + return comres; +} + + +static int bma2x2_read_temperature(struct i2c_client *client, + signed char *temperature) +{ + unsigned char data; + int comres = 0; + + comres = bma2x2_smbus_read_byte(client, BMA2X2_TEMPERATURE_REG, &data); + *temperature = (signed char)data; + + return comres; +} + +static int bma2x2_open_cal(struct i2c_client *client) +{ + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + int cal_data[3]; + int err; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[BMC150] %s: Can't open calibration file\n", + __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + + err = cal_filp->f_op->read(cal_filp, + (char *)cal_data, + 3 * sizeof(int), &cal_filp->f_pos); + if (err != 3 * sizeof(int)) { + pr_err("[BMC150] %s: Can't read the cal data from file\n", + __func__); + filp_close(cal_filp, current->files); + set_fs(old_fs); + return -EIO; + } + + printk(KERN_INFO "[BMC150] %s (%d,%d,%d)",__func__, cal_data[0],cal_data[1],cal_data[2]); + + bma2x2_set_offset_x(bma2x2->bma2x2_client, (unsigned char)cal_data[0]); + bma2x2_set_offset_y(bma2x2->bma2x2_client, (unsigned char)cal_data[1]); + bma2x2_set_offset_z(bma2x2->bma2x2_client, (unsigned char)cal_data[2]); + + return 0; + +} +static ssize_t bma2x2_enable_int_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int type, value; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + sscanf(buf, "%d%d", &type, &value); + + if (bma2x2_set_Int_Enable(bma2x2->bma2x2_client, type, value) < 0) + return -EINVAL; + + return count; +} + + +static ssize_t bma2x2_int_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_Int_Mode(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bma2x2_int_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_Int_Mode(bma2x2->bma2x2_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_slope_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_slope_duration(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_slope_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_slope_duration(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_slope_no_mot_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_slope_no_mot_duration(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_slope_no_mot_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_slope_no_mot_duration(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + + +static ssize_t bma2x2_slope_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_slope_threshold(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_slope_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_slope_threshold(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_slope_no_mot_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_slope_no_mot_threshold(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_slope_no_mot_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_slope_no_mot_threshold(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_high_g_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_high_g_duration(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_high_g_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_high_g_duration(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_high_g_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_high_g_threshold(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_high_g_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_high_g_threshold(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_low_g_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_low_g_duration(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_low_g_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_low_g_duration(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_low_g_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_low_g_threshold(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_low_g_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_low_g_threshold(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_tap_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_tap_threshold(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_tap_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_tap_threshold(bma2x2->bma2x2_client, (unsigned char)data) + < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_tap_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_tap_duration(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_tap_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_tap_duration(bma2x2->bma2x2_client, (unsigned char)data) + < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_tap_quiet_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_tap_quiet(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_tap_quiet_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_tap_quiet(bma2x2->bma2x2_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_tap_shock_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_tap_shock(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_tap_shock_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_tap_shock(bma2x2->bma2x2_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_tap_samp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_tap_samp(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_tap_samp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_tap_samp(bma2x2->bma2x2_client, (unsigned char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_orient_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_orient_mode(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_orient_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_orient_mode(bma2x2->bma2x2_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_orient_blocking_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_orient_blocking(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_orient_blocking_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_orient_blocking(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_orient_hyst_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_orient_hyst(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_orient_hyst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_orient_hyst(bma2x2->bma2x2_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_orient_theta_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_theta_blocking(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_orient_theta_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_theta_blocking(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_flat_theta_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_theta_flat(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_flat_theta_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_theta_flat(bma2x2->bma2x2_client, (unsigned char)data) < + 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_flat_hold_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_flat_hold_time(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} +static ssize_t bma2x2_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&bma2x2->selftest_result)); + +} + +static ssize_t bma2x2_softreset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_soft_reset(bma2x2->bma2x2_client) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + unsigned long data; + unsigned char clear_value = 0; + int error; + short value1 = 0; + short value2 = 0; + short diff = 0; + unsigned long result = 0; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + bma2x2_soft_reset(bma2x2->bma2x2_client); + mdelay(5); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (data != 1) + return -EINVAL; + + bma2x2_write_reg(bma2x2->bma2x2_client, 0x32, &clear_value); + + if ((bma2x2->sensor_type == BMA280_TYPE) || + (bma2x2->sensor_type == BMA255_TYPE)) { + /* set to 4 G range */ + if (bma2x2_set_range(bma2x2->bma2x2_client, 5) < 0) + return -EINVAL; + } + + if ((bma2x2->sensor_type == BMA250E_TYPE) || + (bma2x2->sensor_type == BMA222E_TYPE)) { + /* set to 8 G range */ + if (bma2x2_set_range(bma2x2->bma2x2_client, 8) < 0) + return -EINVAL; + if (bma2x2_set_selftest_amp(bma2x2->bma2x2_client, 1) < 0) + return -EINVAL; + } + + bma2x2_set_selftest_st(bma2x2->bma2x2_client, 1); /* 1 for x-axis*/ + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /* positive + direction*/ + mdelay(10); + bma2x2_read_accel_x(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value1); + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /* negative + direction*/ + mdelay(10); + bma2x2_read_accel_x(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value2); + diff = value1-value2; + + printk(KERN_INFO "diff x is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + + if (bma2x2->sensor_type == BMA280_TYPE) { + if (abs(diff) < 1638) + result |= 1; + } + if (bma2x2->sensor_type == BMA255_TYPE) { + if (abs(diff) < 409) + result |= 1; + } + if (bma2x2->sensor_type == BMA250E_TYPE) { + if (abs(diff) < 51) + result |= 1; + } + if (bma2x2->sensor_type == BMA222E_TYPE) { + if (abs(diff) < 12) + result |= 1; + } + + bma2x2_set_selftest_st(bma2x2->bma2x2_client, 2); /* 2 for y-axis*/ + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /* positive + direction*/ + mdelay(10); + bma2x2_read_accel_y(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value1); + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /* negative + direction*/ + mdelay(10); + bma2x2_read_accel_y(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value2); + diff = value1-value2; + printk(KERN_INFO "diff y is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + + if (bma2x2->sensor_type == BMA280_TYPE) { + if (abs(diff) < 1638) + result |= 2; + } + if (bma2x2->sensor_type == BMA255_TYPE) { + if (abs(diff) < 409) + result |= 2; + } + if (bma2x2->sensor_type == BMA250E_TYPE) { + if (abs(diff) < 51) + result |= 2; + } + if (bma2x2->sensor_type == BMA222E_TYPE) { + if (abs(diff) < 12) + result |= 2; + } + + + bma2x2_set_selftest_st(bma2x2->bma2x2_client, 3); /* 3 for z-axis*/ + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /* positive + direction*/ + mdelay(10); + bma2x2_read_accel_z(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value1); + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /* negative + direction*/ + mdelay(10); + bma2x2_read_accel_z(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value2); + diff = value1-value2; + + printk(KERN_INFO "diff z is %d,value1 is %d, value2 is %d\n", diff, + value1, value2); + + if (bma2x2->sensor_type == BMA280_TYPE) { + if (abs(diff) < 819) + result |= 4; + } + if (bma2x2->sensor_type == BMA255_TYPE) { + if (abs(diff) < 204) + result |= 4; + } + if (bma2x2->sensor_type == BMA250E_TYPE) { + if (abs(diff) < 25) + result |= 4; + } + if (bma2x2->sensor_type == BMA222E_TYPE) { + if (abs(diff) < 6) + result |= 4; + } + + /* self test for bma254 */ + if ((bma2x2->sensor_type == BMA255_TYPE) && (result > 0)) { + result = 0; + bma2x2_soft_reset(bma2x2->bma2x2_client); + mdelay(5); + bma2x2_write_reg(bma2x2->bma2x2_client, 0x32, &clear_value); + /* set to 8 G range */ + if (bma2x2_set_range(bma2x2->bma2x2_client, 8) < 0) + return -EINVAL; + if (bma2x2_set_selftest_amp(bma2x2->bma2x2_client, 1) < 0) + return -EINVAL; + + bma2x2_set_selftest_st(bma2x2->bma2x2_client, 1); /* 1 + for x-axis*/ + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /* + positive direction*/ + mdelay(10); + bma2x2_read_accel_x(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value1); + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /* + negative direction*/ + mdelay(10); + bma2x2_read_accel_x(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value2); + diff = value1-value2; + + printk(KERN_INFO "diff x is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + if (abs(diff) < 204) + result |= 1; + + bma2x2_set_selftest_st(bma2x2->bma2x2_client, 2); /* 2 + for y-axis*/ + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /* + positive direction*/ + mdelay(10); + bma2x2_read_accel_y(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value1); + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /* + negative direction*/ + mdelay(10); + bma2x2_read_accel_y(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value2); + diff = value1-value2; + printk(KERN_INFO "diff y is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + + if (abs(diff) < 204) + result |= 2; + + bma2x2_set_selftest_st(bma2x2->bma2x2_client, 3); /* 3 + for z-axis*/ + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 0); /* + positive direction*/ + mdelay(10); + bma2x2_read_accel_z(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value1); + bma2x2_set_selftest_stn(bma2x2->bma2x2_client, 1); /* + negative direction*/ + mdelay(10); + bma2x2_read_accel_z(bma2x2->bma2x2_client, + bma2x2->sensor_type, &value2); + diff = value1-value2; + + printk(KERN_INFO "diff z is %d,value1 is %d, value2 is %d\n", + diff, value1, value2); + if (abs(diff) < 102) + result |= 4; + } + + atomic_set(&bma2x2->selftest_result, (unsigned int)result); + + bma2x2_soft_reset(bma2x2->bma2x2_client); + mdelay(5); + printk(KERN_INFO "self test finished\n"); + + return count; +} + + + +static ssize_t bma2x2_flat_hold_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_flat_hold_time(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + + + +static int bma2x2_read_accel_xyz(struct i2c_client *client, + signed char sensor_type, struct bma2x2acc *acc) +{ + int comres = 0; + unsigned char data[6]; + struct bma2x2_data *client_data = i2c_get_clientdata(client); + +#ifdef BMA2X2_SENSOR_IDENTIFICATION_ENABLE + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X12_LSB__REG, data, 6); + acc->x = (data[1]<<8)|data[0]; + acc->y = (data[3]<<8)|data[2]; + acc->z = (data[5]<<8)|data[4]; + +#else + switch (sensor_type) { + case 0: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X12_LSB__REG, data, 6); + acc->x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X12_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X12_LSB__LEN)); + acc->x = acc->x << (sizeof(short)*8-(BMA2X2_ACC_X12_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + acc->x = acc->x >> (sizeof(short)*8-(BMA2X2_ACC_X12_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + + acc->y = BMA2X2_GET_BITSLICE(data[2], BMA2X2_ACC_Y12_LSB)| + (BMA2X2_GET_BITSLICE(data[3], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y12_LSB__LEN + )); + acc->y = acc->y << (sizeof(short)*8-(BMA2X2_ACC_Y12_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + acc->y = acc->y >> (sizeof(short)*8-(BMA2X2_ACC_Y12_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + + acc->z = BMA2X2_GET_BITSLICE(data[4], BMA2X2_ACC_Z12_LSB)| + (BMA2X2_GET_BITSLICE(data[5], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z12_LSB__LEN)); + acc->z = acc->z << (sizeof(short)*8-(BMA2X2_ACC_Z12_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + acc->z = acc->z >> (sizeof(short)*8-(BMA2X2_ACC_Z12_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + case 1: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X10_LSB__REG, data, 6); + acc->x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X10_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X10_LSB__LEN)); + acc->x = acc->x << (sizeof(short)*8-(BMA2X2_ACC_X10_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + acc->x = acc->x >> (sizeof(short)*8-(BMA2X2_ACC_X10_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + + acc->y = BMA2X2_GET_BITSLICE(data[2], BMA2X2_ACC_Y10_LSB)| + (BMA2X2_GET_BITSLICE(data[3], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y10_LSB__LEN + )); + acc->y = acc->y << (sizeof(short)*8-(BMA2X2_ACC_Y10_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + acc->y = acc->y >> (sizeof(short)*8-(BMA2X2_ACC_Y10_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + + acc->z = BMA2X2_GET_BITSLICE(data[4], BMA2X2_ACC_Z10_LSB)| + (BMA2X2_GET_BITSLICE(data[5], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z10_LSB__LEN)); + acc->z = acc->z << (sizeof(short)*8-(BMA2X2_ACC_Z10_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + acc->z = acc->z >> (sizeof(short)*8-(BMA2X2_ACC_Z10_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + case 2: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X8_LSB__REG, data, 6); + acc->x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X8_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X8_LSB__LEN)); + acc->x = acc->x << (sizeof(short)*8-(BMA2X2_ACC_X8_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + acc->x = acc->x >> (sizeof(short)*8-(BMA2X2_ACC_X8_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + + acc->y = BMA2X2_GET_BITSLICE(data[2], BMA2X2_ACC_Y8_LSB)| + (BMA2X2_GET_BITSLICE(data[3], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y8_LSB__LEN + )); + acc->y = acc->y << (sizeof(short)*8-(BMA2X2_ACC_Y8_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + acc->y = acc->y >> (sizeof(short)*8-(BMA2X2_ACC_Y8_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + + acc->z = BMA2X2_GET_BITSLICE(data[4], BMA2X2_ACC_Z8_LSB)| + (BMA2X2_GET_BITSLICE(data[5], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z8_LSB__LEN)); + acc->z = acc->z << (sizeof(short)*8-(BMA2X2_ACC_Z8_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + acc->z = acc->z >> (sizeof(short)*8-(BMA2X2_ACC_Z8_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + case 3: + comres = bma2x2_smbus_read_byte_block(client, + BMA2X2_ACC_X14_LSB__REG, data, 6); + acc->x = BMA2X2_GET_BITSLICE(data[0], BMA2X2_ACC_X14_LSB)| + (BMA2X2_GET_BITSLICE(data[1], + BMA2X2_ACC_X_MSB)<<(BMA2X2_ACC_X14_LSB__LEN)); + acc->x = acc->x << (sizeof(short)*8-(BMA2X2_ACC_X14_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + acc->x = acc->x >> (sizeof(short)*8-(BMA2X2_ACC_X14_LSB__LEN + + BMA2X2_ACC_X_MSB__LEN)); + + acc->y = BMA2X2_GET_BITSLICE(data[2], BMA2X2_ACC_Y14_LSB)| + (BMA2X2_GET_BITSLICE(data[3], + BMA2X2_ACC_Y_MSB)<<(BMA2X2_ACC_Y14_LSB__LEN + )); + acc->y = acc->y << (sizeof(short)*8-(BMA2X2_ACC_Y14_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + acc->y = acc->y >> (sizeof(short)*8-(BMA2X2_ACC_Y14_LSB__LEN + + BMA2X2_ACC_Y_MSB__LEN)); + + acc->z = BMA2X2_GET_BITSLICE(data[4], BMA2X2_ACC_Z14_LSB)| + (BMA2X2_GET_BITSLICE(data[5], + BMA2X2_ACC_Z_MSB)<<(BMA2X2_ACC_Z14_LSB__LEN)); + acc->z = acc->z << (sizeof(short)*8-(BMA2X2_ACC_Z14_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + acc->z = acc->z >> (sizeof(short)*8-(BMA2X2_ACC_Z14_LSB__LEN + + BMA2X2_ACC_Z_MSB__LEN)); + break; + default: + break; + } +#endif + + bma2x2_remap_sensor_data(acc, client_data); + return comres; +} + +static void bma2x2_work_func(struct work_struct *work) +{ + struct bma2x2_data *bma2x2 = container_of((struct delayed_work *)work, + struct bma2x2_data, work); + static struct bma2x2acc acc; + unsigned long delay = msecs_to_jiffies(atomic_read(&bma2x2->delay)); + + bma2x2_read_accel_xyz(bma2x2->bma2x2_client, bma2x2->sensor_type, + &acc); + input_report_abs(bma2x2->input, ABS_X, acc.x); + input_report_abs(bma2x2->input, ABS_Y, acc.y); + input_report_abs(bma2x2->input, ABS_Z, acc.z); + input_sync(bma2x2->input); + + mutex_lock(&bma2x2->value_mutex); + bma2x2->value.x = acc.x; + bma2x2->value.y = acc.y; + bma2x2->value.z = acc.z; + mutex_unlock(&bma2x2->value_mutex); + + schedule_delayed_work(&bma2x2->work, delay); +} + + +static ssize_t bma2x2_register_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int address, value; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + sscanf(buf, "%d%d", &address, &value); + if (bma2x2_write_reg(bma2x2->bma2x2_client, (unsigned char)address, + (unsigned char *)&value) < 0) + return -EINVAL; + return count; +} +static ssize_t bma2x2_register_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + size_t count = 0; + u8 reg[0x40]; + int i; + + for (i = 0; i < 0x40; i++) { + bma2x2_smbus_read_byte(bma2x2->bma2x2_client, i, reg+i); + + count += sprintf(&buf[count], "0x%x: %d\n", i, reg[i]); + } + return count; + + +} + +static ssize_t bma2x2_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_range(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bma2x2_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_range(bma2x2->bma2x2_client, (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_bandwidth_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_bandwidth(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_bandwidth_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2->sensor_type == BMA280_TYPE) + if ((unsigned char) data > 14) + return -EINVAL; + + if (bma2x2_set_bandwidth(bma2x2->bma2x2_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_mode(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bma2x2_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_mode(bma2x2->bma2x2_client, (unsigned char) data) < 0) + return -EINVAL; + + return count; +} +static ssize_t bma2x2_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bma2x2_data *bma2x2 = input_get_drvdata(input); + struct bma2x2acc acc_value; + +#if 0 + bma2x2_read_accel_xyz(bma2x2->bma2x2_client, bma2x2->sensor_type, + &acc_value); +#else + /* cache of last input event */ + mutex_lock(&bma2x2->value_mutex); + acc_value.x = bma2x2->value.x; + acc_value.y = bma2x2->value.y; + acc_value.z = bma2x2->value.z; + mutex_unlock(&bma2x2->value_mutex); +#endif + + return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y, + acc_value.z); +} + +/* raw-data for sensor test */ +static ssize_t bma2x2_raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bma2x2_data *bma2x2 = input_get_drvdata(input); + struct bma2x2acc acc_value; +#if 0 + bma2x2_read_accel_xyz(bma2x2->bma2x2_client, bma2x2->sensor_type, + &acc_value); +#else + /* cache of last input event */ + mutex_lock(&bma2x2->value_mutex); + acc_value.x = bma2x2->value.x; + acc_value.y = bma2x2->value.y; + acc_value.z = bma2x2->value.z; + mutex_unlock(&bma2x2->value_mutex); + +#endif + + acc_value.x = acc_value.x >>4; + acc_value.y = acc_value.y >>4; + acc_value.z = acc_value.z >>4; + + return sprintf(buf, "%d,%d,%d\n", acc_value.x, acc_value.y, + acc_value.z); +} + +static ssize_t bma2x2_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&bma2x2->delay)); + +} + +static ssize_t bma2x2_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", bma2x2->chip_id); + +} + + +static ssize_t bma2x2_place_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); +#endif + int place = BOSCH_SENSOR_PLACE_UNKNOWN; + +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + if (NULL != bma2x2->bst_pd) + place = bma2x2->bst_pd->place; +#endif + + return sprintf(buf, "%d\n", place); +} + + +static ssize_t bma2x2_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (data > BMA2X2_MAX_DELAY) + data = BMA2X2_MAX_DELAY; + atomic_set(&bma2x2->delay, (unsigned int) data); + + return count; +} + + +static ssize_t bma2x2_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&bma2x2->enable)); + +} + +static void bma2x2_set_enable(struct device *dev, int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + int pre_enable = atomic_read(&bma2x2->enable); + + mutex_lock(&bma2x2->enable_mutex); + if (enable) { + if (pre_enable == 0) { + bma2x2_set_mode(bma2x2->bma2x2_client, + BMA2X2_MODE_NORMAL); + schedule_delayed_work(&bma2x2->work, + msecs_to_jiffies(atomic_read(&bma2x2->delay))); + atomic_set(&bma2x2->enable, 1); + } + + } else { + if (pre_enable == 1) { + bma2x2_set_mode(bma2x2->bma2x2_client, + BMA2X2_MODE_SUSPEND); + cancel_delayed_work_sync(&bma2x2->work); + atomic_set(&bma2x2->enable, 0); + } + } + mutex_unlock(&bma2x2->enable_mutex); + +} + +static ssize_t bma2x2_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if ((data == 0) || (data == 1)) + bma2x2_set_enable(dev, data); + + + return count; +} +static ssize_t bma2x2_fast_calibration_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_offset_target(bma2x2->bma2x2_client, 1, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fast_calibration_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 1, (unsigned + char)data) < 0) + return -EINVAL; + + if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 1) < 0) + return -EINVAL; + + do { + mdelay(2); + bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp); + +/* printk(KERN_INFO "wait 2ms cal ready flag is %d\n", tmp); + */ + timeout++; + if (timeout == 50) { + printk(KERN_INFO "get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + printk(KERN_INFO "x axis fast calibration finished\n"); + return count; +} + +static ssize_t bma2x2_fast_calibration_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_offset_target(bma2x2->bma2x2_client, 2, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fast_calibration_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 2, (unsigned + char)data) < 0) + return -EINVAL; + + if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 2) < 0) + return -EINVAL; + + do { + mdelay(2); + bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp); + +/* printk(KERN_INFO "wait 2ms cal ready flag is %d\n", tmp); + */ + timeout++; + if (timeout == 50) { + printk(KERN_INFO "get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + printk(KERN_INFO "y axis fast calibration finished\n"); + return count; +} + +static ssize_t bma2x2_fast_calibration_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_offset_target(bma2x2->bma2x2_client, 3, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fast_calibration_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + signed char tmp; + unsigned char timeout = 0; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 3, (unsigned + char)data) < 0) + return -EINVAL; + + if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 3) < 0) + return -EINVAL; + + do { + mdelay(2); + bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp); + +/* printk(KERN_INFO "wait 2ms cal ready flag is %d\n", tmp); + */ + timeout++; + if (timeout == 50) { + printk(KERN_INFO "get fast calibration ready error\n"); + return -EINVAL; + }; + + } while (tmp == 0); + + printk(KERN_INFO "z axis fast calibration finished\n"); + return count; +} +static ssize_t accel_calibration_open(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + bma2x2_open_cal(client); + return 1; +} + + +static ssize_t bma2x2_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /*struct i2c_client *client = to_i2c_client(dev);*/ + /*struct bma2x2_data *bma2x2 = i2c_get_clientdata(client);*/ + int cal_data[3]; + int err; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + int result = 1; + + printk(KERN_INFO "[BMC150] %s\n", __func__); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[BMC150] %s: Can't open calibration file\n", + __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + err = cal_filp->f_op->read(cal_filp, + (char *)cal_data, + 3 * sizeof(int), &cal_filp->f_pos); + if (err != 3 * sizeof(int)) { + pr_err("[BMC150] %s: Can't read the cal data from file\n", + __func__); + filp_close(cal_filp, current->files); + set_fs(old_fs); + return -EIO; + } + if (((cal_data[0] == 0) &&(cal_data[1] == 0) &&(cal_data[2] == 0))) + result = 0; + + printk(KERN_INFO "[BMC150] %s: result=%d, (%d,%d,%d)",__func__, result, cal_data[0],cal_data[1],cal_data[2]); + + return sprintf(buf, "%d %d %d %d\n", result, cal_data[0],cal_data[1],cal_data[2]); + +} + +static ssize_t bma2x2_calibration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + int cal_data[3]; + unsigned long data; + unsigned char mode; + signed char tmp; + unsigned char timeout = 0; + int err; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + err = strict_strtoul(buf, 10, &data); + if (err) { + printk(KERN_ERR "[BMC150] %s: error(%d)\n", __func__, (unsigned char) data); + return err; + } + + printk(KERN_INFO "[BMC150] %s: %d\n", __func__, (unsigned char) data); + + if (bma2x2_get_mode(bma2x2->bma2x2_client, &mode) < 0) { + printk(KERN_ERR "[BMC150] %s: bma2x2_get_mode error\n", __func__); + return -EINVAL; + } + + if (mode != BMA2X2_MODE_NORMAL) { + printk(KERN_INFO "[BMC150] %s: bma2x2_get_mode %d\n", __func__, mode); + bma2x2_set_mode(bma2x2->bma2x2_client, BMA2X2_MODE_NORMAL); + } + + if(data){ + /* check the current z value and set offset_target_z based on it */ + short acc_value_z = 0; + unsigned char offset_target_z = 0; + bma2x2_read_accel_z(bma2x2->bma2x2_client, bma2x2->sensor_type, + &acc_value_z); + printk(KERN_INFO "[BMC150] acc_value_z = [%d], while accel calibration\n", acc_value_z); + if(acc_value_z > 0) + offset_target_z = 1; + else + offset_target_z = 2; + + /* x axis fast calibration */ + if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 1, (unsigned + char)0) < 0) + return -EINVAL; + + if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 1) < 0) + return -EINVAL; + + + do { + mdelay(50); + bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp); + timeout++; + if (timeout == 50) { + printk(KERN_INFO "[BMC150] x get fast calibration ready error\n"); + return -EINVAL; + }; + } while (tmp == 0); + + printk(KERN_INFO "[BMC150] x axis fast calibration DONE\n"); + + /* y axis fast calibration */ + if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 2, (unsigned + char)0) < 0) + return -EINVAL; + + if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 2) < 0) + return -EINVAL; + + do { + mdelay(50); + bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp); + timeout++; + if (timeout == 50) { + printk(KERN_INFO "[BMC150] y get fast calibration ready error\n"); + return -EINVAL; + }; + } while (tmp == 0); + + printk(KERN_INFO "[BMC150] y axis fast calibration DONE\n"); + /* z axis fast calibration */ + /* check the current z value and set offset_target_z based on it */ + if (bma2x2_set_offset_target(bma2x2->bma2x2_client, 3, offset_target_z) < 0) + return -EINVAL; + + if (bma2x2_set_cal_trigger(bma2x2->bma2x2_client, 3) < 0) + return -EINVAL; + + do { + mdelay(50); + bma2x2_get_cal_ready(bma2x2->bma2x2_client, &tmp); + timeout++; + if (timeout == 50) { + printk(KERN_INFO "[BMC150] z get fast calibration ready error\n"); + return -EINVAL; + }; + printk(KERN_INFO "[BMC150] z axis fast calibration DONE\n"); + } while (tmp == 0); + + /* calibration */ + bma2x2_get_offset_x(bma2x2->bma2x2_client, (unsigned char*)&cal_data[0]); + bma2x2_get_offset_y(bma2x2->bma2x2_client, (unsigned char*)&cal_data[1]); + bma2x2_get_offset_z(bma2x2->bma2x2_client, (unsigned char*)&cal_data[2]); + + printk(KERN_INFO "[BMC150] %s: (%d,%d,%d)",__func__, cal_data[0],cal_data[1],cal_data[2]); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[BMC150] %s: Can't open calibration file\n", + __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + + err = cal_filp->f_op->write(cal_filp, + (char *)cal_data, + 3 * sizeof(int), &cal_filp->f_pos); + if (err != 3 * sizeof(int)) { + pr_err("[BMC150] %s: Can't write the cal data to file\n", + __func__); + err = -EIO; + } + filp_close(cal_filp, current->files); + set_fs(old_fs); + } + else + { + /* erase cal data */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[BMC150] %s: Can't open calibration file\n", + __func__); + set_fs(old_fs); + err = PTR_ERR(cal_filp); + return err; + } + cal_data[0] = 0; + cal_data[1] = 0; + cal_data[2] = 0; + + err = cal_filp->f_op->write(cal_filp, + (char *)cal_data, + 3 * sizeof(int), &cal_filp->f_pos); + if (err != 3 * sizeof(int)) { + pr_err("[BMC150] %s: Can't write the cal data to file\n", + __func__); + err = -EIO; + } + filp_close(cal_filp, current->files); + set_fs(old_fs); + + bma2x2_set_offset_x(bma2x2->bma2x2_client, (unsigned char)cal_data[0]); + bma2x2_set_offset_y(bma2x2->bma2x2_client, (unsigned char)cal_data[1]); + bma2x2_set_offset_z(bma2x2->bma2x2_client, (unsigned char)cal_data[2]); + } + + return count; +} + + +static ssize_t bma2x2_SleepDur_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_sleep_duration(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_SleepDur_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_sleep_duration(bma2x2->bma2x2_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_fifo_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_fifo_mode(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fifo_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_fifo_mode(bma2x2->bma2x2_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + + + +static ssize_t bma2x2_fifo_trig_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_fifo_trig(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fifo_trig_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_fifo_trig(bma2x2->bma2x2_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + + + +static ssize_t bma2x2_fifo_trig_src_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_fifo_trig_src(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fifo_trig_src_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_fifo_trig_src(bma2x2->bma2x2_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + + + +static ssize_t bma2x2_fifo_data_sel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_fifo_data_sel(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fifo_framecount_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_fifo_framecount(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_temperature_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_read_temperature(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_fifo_data_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + if (bma2x2_set_fifo_data_sel(bma2x2->bma2x2_client, + (unsigned char) data) < 0) + return -EINVAL; + + return count; +} + + + +static ssize_t bma2x2_fifo_data_out_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err, i, len; + signed char fifo_data_out[MAX_FIFO_F_LEVEL * MAX_FIFO_F_BYTES] = {0}; + unsigned char f_count, f_len = 0; + unsigned char fifo_datasel = 0; + + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_fifo_data_sel(bma2x2->bma2x2_client, &fifo_datasel) < 0) + return sprintf(buf, "Read data sel error\n"); + + if (fifo_datasel) + f_len = 2; + else + f_len = 6; + + if (bma2x2_get_fifo_framecount(bma2x2->bma2x2_client, &f_count) < 0) + return sprintf(buf, "Read frame count error\n"); + + + if (bma_i2c_burst_read(bma2x2->bma2x2_client, + BMA2X2_FIFO_DATA_OUTPUT_REG, fifo_data_out, + f_count * f_len) < 0) + return sprintf(buf, "Read byte block error\n"); + + + if (bma2x2_get_fifo_data_out_reg(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + err = 0; + + len = sprintf(buf, "%lu ", jiffies); + buf += len; + err += len; + + len = sprintf(buf, "%u ", f_count); + buf += len; + err += len; + + len = sprintf(buf, "%u ", f_len); + buf += len; + err += len; + + for (i = 0; i < f_count * f_len; i++) { + len = sprintf(buf, "%d ", fifo_data_out[i]); + buf += len; + err += len; + } + + return err; + +} + + + + +static ssize_t bma2x2_offset_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_offset_x(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_offset_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_offset_x(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_offset_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_offset_y(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_offset_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_offset_y(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + +static ssize_t bma2x2_offset_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + if (bma2x2_get_offset_z(bma2x2->bma2x2_client, &data) < 0) + return sprintf(buf, "Read error\n"); + + return sprintf(buf, "%d\n", data); + +} + +static ssize_t bma2x2_offset_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct i2c_client *client = to_i2c_client(dev); + struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); + + error = strict_strtoul(buf, 10, &data); + if (error) + return error; + + if (bma2x2_set_offset_z(bma2x2->bma2x2_client, (unsigned + char)data) < 0) + return -EINVAL; + + return count; +} + + +static DEVICE_ATTR(range, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_range_show, bma2x2_range_store); +static DEVICE_ATTR(bandwidth, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_bandwidth_show, bma2x2_bandwidth_store); +static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_mode_show, bma2x2_mode_store); +static DEVICE_ATTR(value, S_IRUGO, + bma2x2_value_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO | S_IWUSR | S_IWGRP, + bma2x2_raw_data_show, NULL); +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_delay_show, bma2x2_delay_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_enable_show, bma2x2_enable_store); +static DEVICE_ATTR(SleepDur, S_IRUGO|S_IWUSR|S_IWGRP, + bma2x2_SleepDur_show, bma2x2_SleepDur_store); +static DEVICE_ATTR(fast_calibration_x, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fast_calibration_x_show, + bma2x2_fast_calibration_x_store); +static DEVICE_ATTR(fast_calibration_y, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fast_calibration_y_show, + bma2x2_fast_calibration_y_store); +static DEVICE_ATTR(fast_calibration_z, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fast_calibration_z_show, + bma2x2_fast_calibration_z_store); +static DEVICE_ATTR(fifo_mode, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fifo_mode_show, bma2x2_fifo_mode_store); +static DEVICE_ATTR(fifo_framecount, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fifo_framecount_show, NULL); +static DEVICE_ATTR(fifo_trig, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fifo_trig_show, bma2x2_fifo_trig_store); +static DEVICE_ATTR(fifo_trig_src, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fifo_trig_src_show, bma2x2_fifo_trig_src_store); +static DEVICE_ATTR(fifo_data_sel, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_fifo_data_sel_show, bma2x2_fifo_data_sel_store); +static DEVICE_ATTR(fifo_data_out_frame, S_IRUGO, + bma2x2_fifo_data_out_frame_show, NULL); +static DEVICE_ATTR(reg, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_register_show, bma2x2_register_store); +static DEVICE_ATTR(chip_id, S_IRUGO, + bma2x2_chip_id_show, NULL); +static DEVICE_ATTR(offset_x, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_offset_x_show, + bma2x2_offset_x_store); +static DEVICE_ATTR(offset_y, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_offset_y_show, + bma2x2_offset_y_store); +static DEVICE_ATTR(offset_z, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_offset_z_show, + bma2x2_offset_z_store); +static DEVICE_ATTR(enable_int, S_IWUSR|S_IWGRP|S_IWOTH, + NULL, bma2x2_enable_int_store); +static DEVICE_ATTR(int_mode, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_int_mode_show, bma2x2_int_mode_store); +static DEVICE_ATTR(slope_duration, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_slope_duration_show, bma2x2_slope_duration_store); +static DEVICE_ATTR(slope_threshold, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_slope_threshold_show, bma2x2_slope_threshold_store); +static DEVICE_ATTR(slope_no_mot_duration, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_slope_no_mot_duration_show, + bma2x2_slope_no_mot_duration_store); +static DEVICE_ATTR(slope_no_mot_threshold, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_slope_no_mot_threshold_show, + bma2x2_slope_no_mot_threshold_store); +static DEVICE_ATTR(high_g_duration, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_high_g_duration_show, bma2x2_high_g_duration_store); +static DEVICE_ATTR(high_g_threshold, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_high_g_threshold_show, bma2x2_high_g_threshold_store); +static DEVICE_ATTR(low_g_duration, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_low_g_duration_show, bma2x2_low_g_duration_store); +static DEVICE_ATTR(low_g_threshold, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_low_g_threshold_show, bma2x2_low_g_threshold_store); +static DEVICE_ATTR(tap_duration, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_tap_duration_show, bma2x2_tap_duration_store); +static DEVICE_ATTR(tap_threshold, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_tap_threshold_show, bma2x2_tap_threshold_store); +static DEVICE_ATTR(tap_quiet, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_tap_quiet_show, bma2x2_tap_quiet_store); +static DEVICE_ATTR(tap_shock, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_tap_shock_show, bma2x2_tap_shock_store); +static DEVICE_ATTR(tap_samp, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_tap_samp_show, bma2x2_tap_samp_store); +static DEVICE_ATTR(orient_mode, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_orient_mode_show, bma2x2_orient_mode_store); +static DEVICE_ATTR(orient_blocking, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_orient_blocking_show, bma2x2_orient_blocking_store); +static DEVICE_ATTR(orient_hyst, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_orient_hyst_show, bma2x2_orient_hyst_store); +static DEVICE_ATTR(orient_theta, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_orient_theta_show, bma2x2_orient_theta_store); +static DEVICE_ATTR(flat_theta, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_flat_theta_show, bma2x2_flat_theta_store); +static DEVICE_ATTR(flat_hold_time, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_flat_hold_time_show, bma2x2_flat_hold_time_store); +static DEVICE_ATTR(selftest, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_selftest_show, bma2x2_selftest_store); +static DEVICE_ATTR(softreset, S_IWUSR|S_IWGRP|S_IWOTH, + NULL, bma2x2_softreset_store); +static DEVICE_ATTR(temperature, S_IRUGO, + bma2x2_temperature_show, NULL); +static DEVICE_ATTR(place, S_IRUGO, + bma2x2_place_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, + bma2x2_calibration_show, + bma2x2_calibration_store); +static DEVICE_ATTR(accel_cal_open, S_IRUGO, + accel_calibration_open,NULL); + +static struct attribute *bma2x2_attributes[] = { + &dev_attr_range.attr, + &dev_attr_bandwidth.attr, + &dev_attr_mode.attr, + &dev_attr_value.attr, + &dev_attr_delay.attr, + &dev_attr_enable.attr, + &dev_attr_SleepDur.attr, + &dev_attr_reg.attr, + &dev_attr_fast_calibration_x.attr, + &dev_attr_fast_calibration_y.attr, + &dev_attr_fast_calibration_z.attr, + &dev_attr_fifo_mode.attr, + &dev_attr_fifo_framecount.attr, + &dev_attr_fifo_trig.attr, + &dev_attr_fifo_trig_src.attr, + &dev_attr_fifo_data_sel.attr, + &dev_attr_fifo_data_out_frame.attr, + &dev_attr_chip_id.attr, + &dev_attr_offset_x.attr, + &dev_attr_offset_y.attr, + &dev_attr_offset_z.attr, + &dev_attr_enable_int.attr, + &dev_attr_int_mode.attr, + &dev_attr_slope_duration.attr, + &dev_attr_slope_threshold.attr, + &dev_attr_slope_no_mot_duration.attr, + &dev_attr_slope_no_mot_threshold.attr, + &dev_attr_high_g_duration.attr, + &dev_attr_high_g_threshold.attr, + &dev_attr_low_g_duration.attr, + &dev_attr_low_g_threshold.attr, + &dev_attr_tap_threshold.attr, + &dev_attr_tap_duration.attr, + &dev_attr_tap_quiet.attr, + &dev_attr_tap_shock.attr, + &dev_attr_tap_samp.attr, + &dev_attr_orient_mode.attr, + &dev_attr_orient_blocking.attr, + &dev_attr_orient_hyst.attr, + &dev_attr_orient_theta.attr, + &dev_attr_flat_theta.attr, + &dev_attr_flat_hold_time.attr, + &dev_attr_selftest.attr, + &dev_attr_softreset.attr, + &dev_attr_temperature.attr, + &dev_attr_place.attr, + &dev_attr_calibration.attr, + NULL +}; + +static struct attribute_group bma2x2_attribute_group = { + .attrs = bma2x2_attributes +}; + + + + +#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2) +unsigned char *orient[] = {"upward looking portrait upright", \ + "upward looking portrait upside-down", \ + "upward looking landscape left", \ + "upward looking landscape right", \ + "downward looking portrait upright", \ + "downward looking portrait upside-down", \ + "downward looking landscape left", \ + "downward looking landscape right"}; + +static void bma2x2_irq_work_func(struct work_struct *work) +{ + struct bma2x2_data *bma2x2 = container_of((struct work_struct *)work, + struct bma2x2_data, irq_work); + + unsigned char status = 0; + unsigned char i; + unsigned char first_value = 0; + unsigned char sign_value = 0; + + bma2x2_get_interruptstatus1(bma2x2->bma2x2_client, &status); + + switch (status) { + + case 0x01: + printk(KERN_INFO "Low G interrupt happened\n"); + input_report_rel(bma2x2->input, LOW_G_INTERRUPT, + LOW_G_INTERRUPT_HAPPENED); + break; + case 0x02: + for (i = 0; i < 3; i++) { + bma2x2_get_HIGH_first(bma2x2->bma2x2_client, i, + &first_value); + if (first_value == 1) { + + bma2x2_get_HIGH_sign(bma2x2->bma2x2_client, + &sign_value); + + if (sign_value == 1) { + if (i == 0) + input_report_rel(bma2x2->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_X_NEGATIVE_HAPPENED); + if (i == 1) + input_report_rel(bma2x2->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Y_NEGATIVE_HAPPENED); + if (i == 2) + input_report_rel(bma2x2->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Z_NEGATIVE_HAPPENED); + } else { + if (i == 0) + input_report_rel(bma2x2->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_X_HAPPENED); + if (i == 1) + input_report_rel(bma2x2->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Y_HAPPENED); + if (i == 2) + input_report_rel(bma2x2->input, + HIGH_G_INTERRUPT, + HIGH_G_INTERRUPT_Z_HAPPENED); + + } + } + + printk(KERN_INFO "High G interrupt happened,exis is %d," + "first is %d,sign is %d\n", i, + first_value, sign_value); + } + break; + case 0x04: + for (i = 0; i < 3; i++) { + bma2x2_get_slope_first(bma2x2->bma2x2_client, i, + &first_value); + if (first_value == 1) { + + bma2x2_get_slope_sign(bma2x2->bma2x2_client, + &sign_value); + + if (sign_value == 1) { + if (i == 0) + input_report_rel(bma2x2->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_X_NEGATIVE_HAPPENED); + else if (i == 1) + input_report_rel(bma2x2->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Y_NEGATIVE_HAPPENED); + else if (i == 2) + input_report_rel(bma2x2->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Z_NEGATIVE_HAPPENED); + } else { + if (i == 0) + input_report_rel(bma2x2->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_X_HAPPENED); + else if (i == 1) + input_report_rel(bma2x2->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Y_HAPPENED); + else if (i == 2) + input_report_rel(bma2x2->input, + SLOP_INTERRUPT, + SLOPE_INTERRUPT_Z_HAPPENED); + + } + } + + printk(KERN_INFO "Slop interrupt happened,exis is %d," + "first is %d,sign is %d\n", i, + first_value, sign_value); + } + break; + + case 0x08: + printk(KERN_INFO "slow/ no motion interrupt happened\n"); + input_report_rel(bma2x2->input, SLOW_NO_MOTION_INTERRUPT, + SLOW_NO_MOTION_INTERRUPT_HAPPENED); + break; + + case 0x10: + printk(KERN_INFO "double tap interrupt happened\n"); + input_report_rel(bma2x2->input, DOUBLE_TAP_INTERRUPT, + DOUBLE_TAP_INTERRUPT_HAPPENED); + break; + case 0x20: + printk(KERN_INFO "single tap interrupt happened\n"); + input_report_rel(bma2x2->input, SINGLE_TAP_INTERRUPT, + SINGLE_TAP_INTERRUPT_HAPPENED); + break; + case 0x40: + bma2x2_get_orient_status(bma2x2->bma2x2_client, + &first_value); + printk(KERN_INFO "orient interrupt happened,%s\n", + orient[first_value]); + if (first_value == 0) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + UPWARD_PORTRAIT_UP_INTERRUPT_HAPPENED); + else if (first_value == 1) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + UPWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED); + else if (first_value == 2) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + UPWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED); + else if (first_value == 3) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + UPWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED); + else if (first_value == 4) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + DOWNWARD_PORTRAIT_UP_INTERRUPT_HAPPENED); + else if (first_value == 5) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + DOWNWARD_PORTRAIT_DOWN_INTERRUPT_HAPPENED); + else if (first_value == 6) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + DOWNWARD_LANDSCAPE_LEFT_INTERRUPT_HAPPENED); + else if (first_value == 7) + input_report_abs(bma2x2->input, ORIENT_INTERRUPT, + DOWNWARD_LANDSCAPE_RIGHT_INTERRUPT_HAPPENED); + break; + case 0x80: + bma2x2_get_orient_flat_status(bma2x2->bma2x2_client, + &sign_value); + printk(KERN_INFO "flat interrupt happened,flat status is %d\n", + sign_value); + if (sign_value == 1) { + input_report_abs(bma2x2->input, FLAT_INTERRUPT, + FLAT_INTERRUPT_TURE_HAPPENED); + } else { + input_report_abs(bma2x2->input, FLAT_INTERRUPT, + FLAT_INTERRUPT_FALSE_HAPPENED); + } + break; + default: + break; + } + +} + +static irqreturn_t bma2x2_irq_handler(int irq, void *handle) +{ + + + struct bma2x2_data *data = handle; + + + if (data == NULL) + return IRQ_HANDLED; + if (data->bma2x2_client == NULL) + return IRQ_HANDLED; + + + schedule_work(&data->irq_work); + + return IRQ_HANDLED; + + +} +#endif /* defined(BMA2X2_ENABLE_INT1)||defined(BMA2X2_ENABLE_INT2) */ + + + +static struct device_attribute *bma2X2_attrs[] = { + &dev_attr_raw_data, + &dev_attr_fast_calibration_x, + &dev_attr_fast_calibration_y, + &dev_attr_fast_calibration_z, + &dev_attr_calibration, + &dev_attr_accel_cal_open, + NULL, + }; + +static int bma2x2_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + int tempvalue; + unsigned char tmp_chip_id; + struct bma2x2_data *data; + struct input_dev *dev; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + printk(KERN_INFO "i2c_check_functionality error\n"); + goto exit; + } + data = kzalloc(sizeof(struct bma2x2_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + /* read chip id */ + tempvalue = i2c_smbus_read_word_data(client, BMA2X2_CHIP_ID_REG); + tmp_chip_id = tempvalue&0x00ff; + printk(KERN_ALERT" %s : CHIP ID vlaue of accel sensor \n",__func__); + + switch (tmp_chip_id) { + case BMA255_CHIP_ID: + data->sensor_type = BMA255_TYPE; + break; + case BMA250E_CHIP_ID: + data->sensor_type = BMA250E_TYPE; + break; + case BMA222E_CHIP_ID: + data->sensor_type = BMA222E_TYPE; + break; + case BMA280_CHIP_ID: + data->sensor_type = BMA280_TYPE; + break; + default: + data->sensor_type = -1; + } + if (data->sensor_type != -1) { + data->chip_id = tmp_chip_id; + printk(KERN_INFO "Bosch Sensortec Device detected!\n" + "%s registered I2C driver!\n", + sensor_name[data->sensor_type]); + } else{ + printk(KERN_INFO "Bosch Sensortec Device not found" + "i2c error %d\n", tempvalue); + err = -ENODEV; + goto kfree_exit; + } + i2c_set_clientdata(client, data); + data->bma2x2_client = client; + mutex_init(&data->value_mutex); + mutex_init(&data->mode_mutex); + mutex_init(&data->enable_mutex); + + err = bma2x2_set_bandwidth(client, BMA2X2_BW_SET); + if (err < 0){ + printk(KERN_INFO "%s set bandwidth failed!\n", + sensor_name[data->sensor_type]); + } + + err = bma2x2_set_range(client, BMA2X2_RANGE_SET); + if (err < 0){ + printk(KERN_INFO "%s set g-range failed!\n", + sensor_name[data->sensor_type]); + } + + +#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2) + bma2x2_set_Int_Mode(client, 1);/*latch interrupt 250ms*/ +#endif + +#ifdef BMA2X2_ENABLE_INT1 + /* maps interrupt to INT1 pin */ + bma2x2_set_int1_pad_sel(client, PAD_LOWG); + bma2x2_set_int1_pad_sel(client, PAD_HIGHG); + bma2x2_set_int1_pad_sel(client, PAD_SLOP); + bma2x2_set_int1_pad_sel(client, PAD_DOUBLE_TAP); + bma2x2_set_int1_pad_sel(client, PAD_SINGLE_TAP); + bma2x2_set_int1_pad_sel(client, PAD_ORIENT); + bma2x2_set_int1_pad_sel(client, PAD_FLAT); + bma2x2_set_int1_pad_sel(client, PAD_SLOW_NO_MOTION); +#endif + +#ifdef BMA2X2_ENABLE_INT2 + /* maps interrupt to INT2 pin */ + bma2x2_set_int2_pad_sel(client, PAD_LOWG); + bma2x2_set_int2_pad_sel(client, PAD_HIGHG); + bma2x2_set_int2_pad_sel(client, PAD_SLOP); + bma2x2_set_int2_pad_sel(client, PAD_DOUBLE_TAP); + bma2x2_set_int2_pad_sel(client, PAD_SINGLE_TAP); + bma2x2_set_int2_pad_sel(client, PAD_ORIENT); + bma2x2_set_int2_pad_sel(client, PAD_FLAT); + bma2x2_set_int2_pad_sel(client, PAD_SLOW_NO_MOTION); +#endif + +#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2) + data->IRQ = client->irq; + err = request_irq(data->IRQ, bma2x2_irq_handler, IRQF_TRIGGER_RISING, + "bma2x2", data); + if (err) + printk(KERN_ERR "could not request irq\n"); + + INIT_WORK(&data->irq_work, bma2x2_irq_work_func); +#endif + + + INIT_DELAYED_WORK(&data->work, bma2x2_work_func); + atomic_set(&data->delay, BMA2X2_MAX_DELAY); + atomic_set(&data->enable, 0); + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = SENSOR_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_REL, SLOW_NO_MOTION_INTERRUPT); + input_set_capability(dev, EV_REL, LOW_G_INTERRUPT); + input_set_capability(dev, EV_REL, HIGH_G_INTERRUPT); + input_set_capability(dev, EV_REL, SLOP_INTERRUPT); + input_set_capability(dev, EV_REL, DOUBLE_TAP_INTERRUPT); + input_set_capability(dev, EV_REL, SINGLE_TAP_INTERRUPT); + input_set_capability(dev, EV_ABS, ORIENT_INTERRUPT); + input_set_capability(dev, EV_ABS, FLAT_INTERRUPT); + input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, 0, 0); + + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + goto kfree_exit; + } + + data->input = dev; + + err = sysfs_create_group(&data->input->dev.kobj, + &bma2x2_attribute_group); + if (err < 0) + goto error_sysfs; + +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + if (NULL != client->dev.platform_data) { + data->bst_pd = kzalloc(sizeof(*data->bst_pd), + GFP_KERNEL); + + if (NULL != data->bst_pd) { + memcpy(data->bst_pd, client->dev.platform_data, + sizeof(*data->bst_pd)); + printk(KERN_ALERT"bma2x2 " + "place of bma in %s: %d", + data->bst_pd->name, + data->bst_pd->place); + } + } +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + data->early_suspend.suspend = bma2x2_early_suspend; + data->early_suspend.resume = bma2x2_late_resume; + register_early_suspend(&data->early_suspend); +#endif + + err = sensors_register(&bma_device, data,bma2X2_attrs, "accelerometer_sensor"); + if (err < 0 ) + { + pr_err("%s: could not register" "accelerometer_sensor device(%d).\n", __func__, err); + goto error_sysfs; + } + + return 0; + +error_sysfs: + input_unregister_device(data->input); + +kfree_exit: +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + if ((NULL != data) && (NULL != data->bst_pd)) { + kfree(data->bst_pd); + data->bst_pd = NULL; + } +#endif + kfree(data); +exit: + return err; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bma2x2_early_suspend(struct early_suspend *h) +{ + struct bma2x2_data *data = + container_of(h, struct bma2x2_data, early_suspend); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_SUSPEND); + cancel_delayed_work_sync(&data->work); + } + mutex_unlock(&data->enable_mutex); +} + + +static void bma2x2_late_resume(struct early_suspend *h) +{ + struct bma2x2_data *data = + container_of(h, struct bma2x2_data, early_suspend); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_NORMAL); + schedule_delayed_work(&data->work, + msecs_to_jiffies(atomic_read(&data->delay))); + } + mutex_unlock(&data->enable_mutex); +} +#endif + +static int __exit bma2x2_remove(struct i2c_client *client) +{ + struct bma2x2_data *data = i2c_get_clientdata(client); + + bma2x2_set_enable(&client->dev, 0); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + sensors_unregister(bma_device, bma2X2_attrs); + sysfs_remove_group(&data->input->dev.kobj, &bma2x2_attribute_group); + input_unregister_device(data->input); + +#ifdef CONFIG_BMA_USE_PLATFORM_DATA + if (NULL != data->bst_pd) { + kfree(data->bst_pd); + data->bst_pd = NULL; + } +#endif + + kfree(data); + + return 0; +} +#ifdef CONFIG_PM + +static int bma2x2_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct bma2x2_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_SUSPEND); + cancel_delayed_work_sync(&data->work); + } + mutex_unlock(&data->enable_mutex); + + return 0; +} + +static int bma2x2_resume(struct i2c_client *client) +{ + struct bma2x2_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->enable_mutex); + if (atomic_read(&data->enable) == 1) { + bma2x2_set_mode(data->bma2x2_client, BMA2X2_MODE_NORMAL); + schedule_delayed_work(&data->work, + msecs_to_jiffies(atomic_read(&data->delay))); + } + mutex_unlock(&data->enable_mutex); + + return 0; +} + +#else + +#define bma2x2_suspend NULL +#define bma2x2_resume NULL + +#endif /* CONFIG_PM */ + +static const struct i2c_device_id bma2x2_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, bma2x2_id); + +static struct i2c_driver bma2x2_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + }, + .suspend = bma2x2_suspend, + .resume = bma2x2_resume, + .id_table = bma2x2_id, + .probe = bma2x2_probe, + .remove = bma2x2_remove, + +}; + +static int __init BMA2X2_init(void) +{ + return i2c_add_driver(&bma2x2_driver); +} + +static void __exit BMA2X2_exit(void) +{ + i2c_del_driver(&bma2x2_driver); +} + +MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>"); +MODULE_DESCRIPTION("BMA2X2 accelerometer sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(BMA2X2_init); +module_exit(BMA2X2_exit); diff --git a/drivers/sensor/bmm050.c b/drivers/sensor/bmm050.c new file mode 100644 index 00000000..fb3f3fcb --- /dev/null +++ b/drivers/sensor/bmm050.c @@ -0,0 +1,1159 @@ +/* + * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * @date Mar 11th, 2013 + * @version v1.0.1 + * @brief BMM050 Linux Driver API + */ + +#include "bmm050.h" +#include <linux/kernel.h> +static struct bmm050 *p_bmm050; + +BMM050_RETURN_FUNCTION_TYPE bmm050_init(struct bmm050 *bmm050) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char a_data_u8r[2]; + p_bmm050 = bmm050; + + p_bmm050->dev_addr = BMM050_I2C_ADDRESS; + + /* set device from suspend into sleep mode */ + bmm050_set_powermode(BMM050_ON); + + /* wait two millisecond for bmc to settle */ + p_bmm050->delay_msec(BMM050_DELAY_SETTLING_TIME); + + /*Read CHIP_ID and REv. info */ + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_CHIP_ID, a_data_u8r, 1); + p_bmm050->company_id = a_data_u8r[0]; + + /* Function to initialise trim values */ + bmm050_init_trim_registers(); + bmm050_set_presetmode(BMM050_PRESETMODE_REGULAR); + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_presetmode(unsigned char mode) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + switch (mode) { + case BMM050_PRESETMODE_LOWPOWER: + /* Set the data rate for Low Power mode */ + comres = bmm050_set_datarate(BMM050_LOWPOWER_DR); + /* Set the XY-repetitions number for Low Power mode */ + comres |= bmm050_set_repetitions_XY(BMM050_LOWPOWER_REPXY); + /* Set the Z-repetitions number for Low Power mode */ + comres |= bmm050_set_repetitions_Z(BMM050_LOWPOWER_REPZ); + break; + case BMM050_PRESETMODE_REGULAR: + /* Set the data rate for Regular mode */ + comres = bmm050_set_datarate(BMM050_REGULAR_DR); + /* Set the XY-repetitions number for Regular mode */ + comres |= bmm050_set_repetitions_XY(BMM050_REGULAR_REPXY); + /* Set the Z-repetitions number for Regular mode */ + comres |= bmm050_set_repetitions_Z(BMM050_REGULAR_REPZ); + break; + case BMM050_PRESETMODE_HIGHACCURACY: + /* Set the data rate for High Accuracy mode */ + comres = bmm050_set_datarate(BMM050_HIGHACCURACY_DR); + /* Set the XY-repetitions number for High Accuracy mode */ + comres |= bmm050_set_repetitions_XY(BMM050_HIGHACCURACY_REPXY); + /* Set the Z-repetitions number for High Accuracyr mode */ + comres |= bmm050_set_repetitions_Z(BMM050_HIGHACCURACY_REPZ); + break; + case BMM050_PRESETMODE_ENHANCED: + /* Set the data rate for Enhanced Accuracy mode */ + comres = bmm050_set_datarate(BMM050_ENHANCED_DR); + /* Set the XY-repetitions number for High Enhanced mode */ + comres |= bmm050_set_repetitions_XY(BMM050_ENHANCED_REPXY); + /* Set the Z-repetitions number for High Enhanced mode */ + comres |= bmm050_set_repetitions_Z(BMM050_ENHANCED_REPZ); + break; + default: + comres = E_BMM050_OUT_OF_RANGE; + break; + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_functional_state( + unsigned char functional_state) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + switch (functional_state) { + case BMM050_NORMAL_MODE: + comres = bmm050_get_powermode(&v_data1_u8r); + if (v_data1_u8r == BMM050_OFF) { + comres |= bmm050_set_powermode(BMM050_ON); + p_bmm050->delay_msec( + BMM050_DELAY_SUSPEND_SLEEP); + } + { + comres |= p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_CNTL_OPMODE, + BMM050_NORMAL_MODE); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data1_u8r, 1); + } + break; + case BMM050_SUSPEND_MODE: + comres = bmm050_set_powermode(BMM050_OFF); + break; + case BMM050_FORCED_MODE: + comres = bmm050_get_powermode(&v_data1_u8r); + if (v_data1_u8r == BMM050_OFF) { + comres = bmm050_set_powermode(BMM050_ON); + p_bmm050->delay_msec( + BMM050_DELAY_SUSPEND_SLEEP); + } + comres |= p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_CNTL_OPMODE, BMM050_ON); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data1_u8r, 1); + break; + case BMM050_SLEEP_MODE: + bmm050_get_powermode(&v_data1_u8r); + if (v_data1_u8r == BMM050_OFF) { + comres = bmm050_set_powermode(BMM050_ON); + p_bmm050->delay_msec( + BMM050_DELAY_SUSPEND_SLEEP); + } + comres |= p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_CNTL_OPMODE, + BMM050_SLEEP_MODE); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data1_u8r, 1); + break; + default: + comres = E_BMM050_OUT_OF_RANGE; + break; + } + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_functional_state( + unsigned char *functional_state) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_OPMODE__REG, + &v_data_u8r, 1); + *functional_state = BMM050_GET_BITSLICE( + v_data_u8r, BMM050_CNTL_OPMODE); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ(struct bmm050_mdata *mdata) +{ + BMM050_RETURN_FUNCTION_TYPE comres; + + unsigned char a_data_u8r[8]; + + struct { + BMM050_S16 raw_dataX; + BMM050_S16 raw_dataY; + BMM050_S16 raw_dataZ; + BMM050_U16 raw_dataR; + } raw_dataXYZ; + + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DATAX_LSB, a_data_u8r, 8); + + /* Reading data for X axis */ + a_data_u8r[0] = BMM050_GET_BITSLICE(a_data_u8r[0], + BMM050_DATAX_LSB_VALUEX); + raw_dataXYZ.raw_dataX = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[1])) << + SHIFT_LEFT_5_POSITION) | a_data_u8r[0]); + + /* Reading data for Y axis */ + a_data_u8r[2] = BMM050_GET_BITSLICE(a_data_u8r[2], + BMM050_DATAY_LSB_VALUEY); + raw_dataXYZ.raw_dataY = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[3])) << + SHIFT_LEFT_5_POSITION) | a_data_u8r[2]); + + /* Reading data for Z axis */ + a_data_u8r[4] = BMM050_GET_BITSLICE(a_data_u8r[4], + BMM050_DATAZ_LSB_VALUEZ); + raw_dataXYZ.raw_dataZ = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[5])) << + SHIFT_LEFT_7_POSITION) | a_data_u8r[4]); + + /* Reading data for Resistance*/ + a_data_u8r[6] = BMM050_GET_BITSLICE(a_data_u8r[6], + BMM050_R_LSB_VALUE); + raw_dataXYZ.raw_dataR = (BMM050_U16)((((BMM050_U16) + a_data_u8r[7]) << + SHIFT_LEFT_6_POSITION) | a_data_u8r[6]); + + /* Compensation for X axis */ + mdata->datax = bmm050_compensate_X(raw_dataXYZ.raw_dataX, + raw_dataXYZ.raw_dataR); + + /* Compensation for Y axis */ + mdata->datay = bmm050_compensate_Y(raw_dataXYZ.raw_dataY, + raw_dataXYZ.raw_dataR); + + /* Compensation for Z axis */ + mdata->dataz = bmm050_compensate_Z(raw_dataXYZ.raw_dataZ, + raw_dataXYZ.raw_dataR); + + /* Output raw resistance value */ + mdata->resistance = raw_dataXYZ.raw_dataR; + + } + + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ_s32( + struct bmm050_mdata_s32 *mdata) +{ + BMM050_RETURN_FUNCTION_TYPE comres; + + unsigned char a_data_u8r[8] = ""; + + struct { + BMM050_S16 raw_dataX; + BMM050_S16 raw_dataY; + BMM050_S16 raw_dataZ; + BMM050_U16 raw_dataR; + } raw_dataXYZ; + + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DATAX_LSB, a_data_u8r, 8); + + /* Reading data for X axis */ + a_data_u8r[0] = BMM050_GET_BITSLICE(a_data_u8r[0], + BMM050_DATAX_LSB_VALUEX); + raw_dataXYZ.raw_dataX = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[1])) << + SHIFT_LEFT_5_POSITION) | a_data_u8r[0]); + + /* Reading data for Y axis */ + a_data_u8r[2] = BMM050_GET_BITSLICE(a_data_u8r[2], + BMM050_DATAY_LSB_VALUEY); + raw_dataXYZ.raw_dataY = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[3])) << + SHIFT_LEFT_5_POSITION) | a_data_u8r[2]); + + /* Reading data for Z axis */ + a_data_u8r[4] = BMM050_GET_BITSLICE(a_data_u8r[4], + BMM050_DATAZ_LSB_VALUEZ); + raw_dataXYZ.raw_dataZ = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[5])) << + SHIFT_LEFT_7_POSITION) | a_data_u8r[4]); + + /* Reading data for Resistance*/ + if (!comres) + mdata->drdy = BMM050_GET_BITSLICE(a_data_u8r[6], + BMM050_DATA_RDYSTAT); + + a_data_u8r[6] = BMM050_GET_BITSLICE(a_data_u8r[6], + BMM050_R_LSB_VALUE); + raw_dataXYZ.raw_dataR = (BMM050_U16)((((BMM050_U16) + a_data_u8r[7]) << + SHIFT_LEFT_6_POSITION) | a_data_u8r[6]); + + /* Compensation for X axis */ + mdata->datax = bmm050_compensate_X_s32(raw_dataXYZ.raw_dataX, + raw_dataXYZ.raw_dataR); + + /* Compensation for Y axis */ + mdata->datay = bmm050_compensate_Y_s32(raw_dataXYZ.raw_dataY, + raw_dataXYZ.raw_dataR); + + /* Compensation for Z axis */ + mdata->dataz = bmm050_compensate_Z_s32(raw_dataXYZ.raw_dataZ, + raw_dataXYZ.raw_dataR); + + /* Output raw resistance value */ + mdata->resistance = raw_dataXYZ.raw_dataR; + } + return comres; +} + +#ifdef ENABLE_FLOAT +BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ_float( + struct bmm050_mdata_float *mdata) +{ + BMM050_RETURN_FUNCTION_TYPE comres; + + unsigned char a_data_u8r[8]; + + struct { + BMM050_S16 raw_dataX; + BMM050_S16 raw_dataY; + BMM050_S16 raw_dataZ; + BMM050_U16 raw_dataR; + } raw_dataXYZ; + + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DATAX_LSB, a_data_u8r, 8); + + /* Reading data for X axis */ + a_data_u8r[0] = BMM050_GET_BITSLICE(a_data_u8r[0], + BMM050_DATAX_LSB_VALUEX); + raw_dataXYZ.raw_dataX = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[1])) << + SHIFT_LEFT_5_POSITION) | a_data_u8r[0]); + + /* Reading data for Y axis */ + a_data_u8r[2] = BMM050_GET_BITSLICE(a_data_u8r[2], + BMM050_DATAY_LSB_VALUEY); + raw_dataXYZ.raw_dataY = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[3])) << + SHIFT_LEFT_5_POSITION) | a_data_u8r[2]); + + /* Reading data for Z axis */ + a_data_u8r[4] = BMM050_GET_BITSLICE(a_data_u8r[4], + BMM050_DATAZ_LSB_VALUEZ); + raw_dataXYZ.raw_dataZ = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[5])) << + SHIFT_LEFT_7_POSITION) | a_data_u8r[4]); + + /* Reading data for Resistance*/ + a_data_u8r[6] = BMM050_GET_BITSLICE(a_data_u8r[6], + BMM050_R_LSB_VALUE); + raw_dataXYZ.raw_dataR = (BMM050_U16)((((BMM050_U16) + a_data_u8r[7]) << + SHIFT_LEFT_6_POSITION) | a_data_u8r[6]); + + /* Compensation for X axis */ + mdata->datax = bmm050_compensate_X_float(raw_dataXYZ.raw_dataX, + raw_dataXYZ.raw_dataR); + + /* Compensation for Y axis */ + mdata->datay = bmm050_compensate_Y_float(raw_dataXYZ.raw_dataY, + raw_dataXYZ.raw_dataR); + + /* Compensation for Z axis */ + mdata->dataz = bmm050_compensate_Z_float(raw_dataXYZ.raw_dataZ, + raw_dataXYZ.raw_dataR); + + /* Output raw resistance value */ + mdata->resistance = raw_dataXYZ.raw_dataR; + } + return comres; +} +#endif + +BMM050_RETURN_FUNCTION_TYPE bmm050_read_register(unsigned char addr, + unsigned char *data, unsigned char len) +{ + BMM050_RETURN_FUNCTION_TYPE comres; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + addr, data, len); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_write_register(unsigned char addr, + unsigned char *data, unsigned char len) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_WRITE_FUNC(p_bmm050->dev_addr, + addr, data, len); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_selftest(unsigned char selftest) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, BMM050_CNTL_S_TEST__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, BMM050_CNTL_S_TEST, selftest); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, BMM050_CNTL_S_TEST__REG, + &v_data1_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_self_test_XYZ( + unsigned char *self_testxyz) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char a_data_u8r[5], v_result_u8r = 0x00; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, BMM050_DATAX_LSB_TESTX__REG, + a_data_u8r, 5); + + v_result_u8r = BMM050_GET_BITSLICE(a_data_u8r[4], + BMM050_DATAZ_LSB_TESTZ); + + v_result_u8r = (v_result_u8r << 1); + v_result_u8r = (v_result_u8r | BMM050_GET_BITSLICE( + a_data_u8r[2], BMM050_DATAY_LSB_TESTY)); + + v_result_u8r = (v_result_u8r << 1); + v_result_u8r = (v_result_u8r | BMM050_GET_BITSLICE( + a_data_u8r[0], BMM050_DATAX_LSB_TESTX)); + + *self_testxyz = v_result_u8r; + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_spi3(unsigned char value) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_POWER_CNTL_SPI3_EN__REG, &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE(v_data1_u8r, + BMM050_POWER_CNTL_SPI3_EN, value); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC(p_bmm050->dev_addr, + BMM050_POWER_CNTL_SPI3_EN__REG, &v_data1_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_datarate(unsigned char data_rate) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_DR__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE(v_data1_u8r, + BMM050_CNTL_DR, data_rate); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_DR__REG, + &v_data1_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_datarate(unsigned char *data_rate) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_DR__REG, + &v_data_u8r, 1); + *data_rate = BMM050_GET_BITSLICE(v_data_u8r, + BMM050_CNTL_DR); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_perform_advanced_selftest( + BMM050_S16 *diff_z) +{ + BMM050_RETURN_FUNCTION_TYPE comres; + BMM050_S16 result_positive, result_negative; + struct bmm050_mdata mdata; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + /* set sleep mode to prepare for forced measurement. + * If sensor is off, this will turn it on + * and respect needed delays. */ + comres = bmm050_set_functional_state(BMM050_SLEEP_MODE); + + /* set normal accuracy mode */ + comres |= bmm050_set_repetitions_Z(BMM050_LOWPOWER_REPZ); + /* 14 repetitions Z in normal accuracy mode */ + + /* disable X, Y channel */ + comres |= bmm050_set_control_measurement_x( + BMM050_CHANNEL_DISABLE); + comres |= bmm050_set_control_measurement_y( + BMM050_CHANNEL_DISABLE); + + /* enable positive current and force a + * measurement with positive field */ + comres |= bmm050_set_adv_selftest( + BMM050_ADVANCED_SELFTEST_POSITIVE); + comres |= bmm050_set_functional_state(BMM050_FORCED_MODE); + /* wait for measurement to complete */ + p_bmm050->delay_msec(4); + + /* read result from positive field measurement */ + comres |= bmm050_read_mdataXYZ(&mdata); + result_positive = mdata.dataz; + + /* enable negative current and force a + * measurement with negative field */ + comres |= bmm050_set_adv_selftest( + BMM050_ADVANCED_SELFTEST_NEGATIVE); + comres |= bmm050_set_functional_state(BMM050_FORCED_MODE); + p_bmm050->delay_msec(4); /* wait for measurement to complete */ + + /* read result from negative field measurement */ + comres |= bmm050_read_mdataXYZ(&mdata); + result_negative = mdata.dataz; + + /* turn off self test current */ + comres |= bmm050_set_adv_selftest( + BMM050_ADVANCED_SELFTEST_OFF); + + /* enable X, Y channel */ + comres |= bmm050_set_control_measurement_x( + BMM050_CHANNEL_ENABLE); + comres |= bmm050_set_control_measurement_y( + BMM050_CHANNEL_ENABLE); + + /* write out difference in positive and negative field. + * This should be ~ 200 mT = 3200 LSB */ + *diff_z = (result_positive - result_negative); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_init_trim_registers(void) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char a_data_u8r[2]; + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_X1, (unsigned char *)&p_bmm050->dig_x1, 1); + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_Y1, (unsigned char *)&p_bmm050->dig_y1, 1); + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_X2, (unsigned char *)&p_bmm050->dig_x2, 1); + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_Y2, (unsigned char *)&p_bmm050->dig_y2, 1); + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_XY1, (unsigned char *)&p_bmm050->dig_xy1, 1); + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_XY2, (unsigned char *)&p_bmm050->dig_xy2, 1); + + /* shorts can not be recasted into (unsigned char*) + * due to possible mixup between trim data + * arrangement and memory arrangement */ + + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_Z1_LSB, a_data_u8r, 2); + p_bmm050->dig_z1 = (BMM050_U16)((((BMM050_U16)((unsigned char) + a_data_u8r[1])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[0]); + + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_Z2_LSB, a_data_u8r, 2); + p_bmm050->dig_z2 = (BMM050_S16)((((BMM050_S16)( + (signed char)a_data_u8r[1])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[0]); + + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_Z3_LSB, a_data_u8r, 2); + p_bmm050->dig_z3 = (BMM050_S16)((((BMM050_S16)( + (signed char)a_data_u8r[1])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[0]); + + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_Z4_LSB, a_data_u8r, 2); + p_bmm050->dig_z4 = (BMM050_S16)((((BMM050_S16)( + (signed char)a_data_u8r[1])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[0]); + + comres |= p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DIG_XYZ1_LSB, a_data_u8r, 2); + a_data_u8r[1] = BMM050_GET_BITSLICE(a_data_u8r[1], BMM050_DIG_XYZ1_MSB); + p_bmm050->dig_xyz1 = (BMM050_U16)((((BMM050_U16) + ((unsigned char)a_data_u8r[1])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[0]); + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_adv_selftest(unsigned char adv_selftest) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + switch (adv_selftest) { + case BMM050_ADVANCED_SELFTEST_OFF: + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_CNTL_ADV_ST, + BMM050_ADVANCED_SELFTEST_OFF); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, + &v_data1_u8r, 1); + break; + case BMM050_ADVANCED_SELFTEST_POSITIVE: + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_CNTL_ADV_ST, + BMM050_ADVANCED_SELFTEST_POSITIVE); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, + &v_data1_u8r, 1); + break; + case BMM050_ADVANCED_SELFTEST_NEGATIVE: + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_CNTL_ADV_ST, + BMM050_ADVANCED_SELFTEST_NEGATIVE); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, + &v_data1_u8r, 1); + break; + default: + break; + } + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_adv_selftest(unsigned char *adv_selftest) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_CNTL_ADV_ST__REG, &v_data_u8r, 1); + *adv_selftest = BMM050_GET_BITSLICE(v_data_u8r, + BMM050_CNTL_ADV_ST); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_presetmode( + unsigned char *mode) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char data_rate = 0; + unsigned char repetitionsxy = 0; + unsigned char repetitionsz = 0; + + /* Get the current data rate */ + comres = bmm050_get_datarate(&data_rate); + /* Get the preset number of XY Repetitions */ + comres |= bmm050_get_repetitions_XY(&repetitionsxy); + /* Get the preset number of Z Repetitions */ + comres |= bmm050_get_repetitions_Z(&repetitionsz); + if ((data_rate == BMM050_LOWPOWER_DR) && ( + repetitionsxy == BMM050_LOWPOWER_REPXY) && ( + repetitionsz == BMM050_LOWPOWER_REPZ)) { + *mode = BMM050_PRESETMODE_LOWPOWER; + } else { + if ((data_rate == BMM050_REGULAR_DR) && ( + repetitionsxy == BMM050_REGULAR_REPXY) && ( + repetitionsz == BMM050_REGULAR_REPZ)) { + *mode = BMM050_PRESETMODE_REGULAR; + } else { + if ((data_rate == BMM050_HIGHACCURACY_DR) && ( + repetitionsxy == BMM050_HIGHACCURACY_REPXY) && ( + repetitionsz == BMM050_HIGHACCURACY_REPZ)) { + *mode = BMM050_PRESETMODE_HIGHACCURACY; + } else { + if ((data_rate == BMM050_ENHANCED_DR) && ( + repetitionsxy == BMM050_ENHANCED_REPXY) && ( + repetitionsz == BMM050_ENHANCED_REPZ)) { + *mode = BMM050_PRESETMODE_ENHANCED; + } else { + *mode = E_BMM050_UNDEFINED_MODE; + } + } + } + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_powermode(unsigned char *mode) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_PCB__REG, + &v_data_u8r, 1); + *mode = BMM050_GET_BITSLICE(v_data_u8r, + BMM050_POWER_CNTL_PCB); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_powermode(unsigned char mode) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_PCB__REG, + &v_data_u8r, 1); + v_data_u8r = BMM050_SET_BITSLICE(v_data_u8r, + BMM050_POWER_CNTL_PCB, mode); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_PCB__REG, + &v_data_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_repetitions_XY( + unsigned char *no_repetitions_xy) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_NO_REPETITIONS_XY, + &v_data_u8r, 1); + *no_repetitions_xy = v_data_u8r; + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_repetitions_XY( + unsigned char no_repetitions_xy) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + v_data_u8r = no_repetitions_xy; + comres = p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_NO_REPETITIONS_XY, + &v_data_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_repetitions_Z( + unsigned char *no_repetitions_z) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_NO_REPETITIONS_Z, + &v_data_u8r, 1); + *no_repetitions_z = v_data_u8r; + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_repetitions_Z( + unsigned char no_repetitions_z) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + v_data_u8r = no_repetitions_z; + comres = p_bmm050->BMM050_BUS_WRITE_FUNC(p_bmm050->dev_addr, + BMM050_NO_REPETITIONS_Z, &v_data_u8r, 1); + } + return comres; +} + +BMM050_S16 bmm050_compensate_X(BMM050_S16 mdata_x, BMM050_U16 data_R) +{ + BMM050_S16 inter_retval; + if (mdata_x != BMM050_FLIP_OVERFLOW_ADCVAL /* no overflow */ + ) { + inter_retval = ((BMM050_S16)(((BMM050_U16) + ((((BMM050_S32)p_bmm050->dig_xyz1) << 14) / + (data_R != 0 ? data_R : p_bmm050->dig_xyz1))) - + ((BMM050_U16)0x4000))); + inter_retval = ((BMM050_S16)((((BMM050_S32)mdata_x) * + ((((((((BMM050_S32)p_bmm050->dig_xy2) * + ((((BMM050_S32)inter_retval) * + ((BMM050_S32)inter_retval)) >> 7)) + + (((BMM050_S32)inter_retval) * + ((BMM050_S32)(((BMM050_S16)p_bmm050->dig_xy1) + << 7)))) >> 9) + + ((BMM050_S32)0x100000)) * + ((BMM050_S32)(((BMM050_S16)p_bmm050->dig_x2) + + ((BMM050_S16)0xA0)))) >> 12)) >> 13)) + + (((BMM050_S16)p_bmm050->dig_x1) << 3); + } else { + /* overflow */ + inter_retval = BMM050_OVERFLOW_OUTPUT; + } + return inter_retval; +} + +BMM050_S32 bmm050_compensate_X_s32 (BMM050_S16 mdata_x, BMM050_U16 data_R) +{ + BMM050_S32 retval; + + retval = bmm050_compensate_X(mdata_x, data_R); + if (retval == (BMM050_S32)BMM050_OVERFLOW_OUTPUT) + retval = BMM050_OVERFLOW_OUTPUT_S32; + return retval; +} + +#ifdef ENABLE_FLOAT +float bmm050_compensate_X_float (BMM050_S16 mdata_x, BMM050_U16 data_R) +{ + float inter_retval; + if (mdata_x != BMM050_FLIP_OVERFLOW_ADCVAL /* no overflow */ + ) { + if (data_R != 0) { + inter_retval = ((((float)p_bmm050->dig_xyz1)*16384.0f + /data_R)-16384.0f); + } else { + inter_retval = 0; + } + inter_retval = (((mdata_x * ((((((float)p_bmm050->dig_xy2) * + (inter_retval*inter_retval / 268435456.0f) + + inter_retval*((float)p_bmm050->dig_xy1)/16384.0f)) + + 256.0f) * (((float)p_bmm050->dig_x2) + 160.0f))) + / 8192.0f) + (((float)p_bmm050->dig_x1) * 8.0f))/16.0f; + } else { + inter_retval = BMM050_OVERFLOW_OUTPUT_FLOAT; + } + return inter_retval; +} +#endif + +BMM050_S16 bmm050_compensate_Y(BMM050_S16 mdata_y, BMM050_U16 data_R) +{ + BMM050_S16 inter_retval; + if (mdata_y != BMM050_FLIP_OVERFLOW_ADCVAL /* no overflow */ + ) { + inter_retval = ((BMM050_S16)(((BMM050_U16)((( + (BMM050_S32)p_bmm050->dig_xyz1) << 14) / + (data_R != 0 ? + data_R : p_bmm050->dig_xyz1))) - + ((BMM050_U16)0x4000))); + inter_retval = ((BMM050_S16)((((BMM050_S32)mdata_y) * + ((((((((BMM050_S32) + p_bmm050->dig_xy2) * + ((((BMM050_S32) inter_retval) * + ((BMM050_S32)inter_retval)) >> 7)) + + (((BMM050_S32)inter_retval) * + ((BMM050_S32)(((BMM050_S16) + p_bmm050->dig_xy1) << 7)))) >> 9) + + ((BMM050_S32)0x100000)) * + ((BMM050_S32)(((BMM050_S16)p_bmm050->dig_y2) + + ((BMM050_S16)0xA0)))) + >> 12)) >> 13)) + + (((BMM050_S16)p_bmm050->dig_y1) << 3); + } else { + /* overflow */ + inter_retval = BMM050_OVERFLOW_OUTPUT; + } + return inter_retval; +} + +BMM050_S32 bmm050_compensate_Y_s32 (BMM050_S16 mdata_y, BMM050_U16 data_R) +{ + BMM050_S32 retval; + + retval = bmm050_compensate_Y(mdata_y, data_R); + if (retval == BMM050_OVERFLOW_OUTPUT) + retval = BMM050_OVERFLOW_OUTPUT_S32; + return retval; +} + +#ifdef ENABLE_FLOAT +float bmm050_compensate_Y_float(BMM050_S16 mdata_y, BMM050_U16 data_R) +{ + float inter_retval; + if (mdata_y != BMM050_FLIP_OVERFLOW_ADCVAL /* no overflow */ + ) { + if (data_R != 0) { + inter_retval = ((((float)p_bmm050->dig_xyz1)*16384.0f + /data_R)-16384.0f); + } else { + inter_retval = 0; + } + inter_retval = (((mdata_y * ((((((float)p_bmm050->dig_xy2) * + (inter_retval*inter_retval / 268435456.0f) + + inter_retval * ((float)p_bmm050->dig_xy1)/16384.0f)) + + 256.0f) * (((float)p_bmm050->dig_y2) + 160.0f))) + / 8192.0f) + (((float)p_bmm050->dig_y1) * 8.0f))/16.0f; + } else { + /* overflow, set output to 0.0f */ + inter_retval = BMM050_OVERFLOW_OUTPUT_FLOAT; + } + return inter_retval; +} +#endif + +BMM050_S16 bmm050_compensate_Z(BMM050_S16 mdata_z, BMM050_U16 data_R) +{ + BMM050_S32 retval; + if ((mdata_z != BMM050_HALL_OVERFLOW_ADCVAL) /* no overflow */ + ) { + retval = (((((BMM050_S32)(mdata_z - p_bmm050->dig_z4)) << 15) - + ((((BMM050_S32)p_bmm050->dig_z3) * + ((BMM050_S32)(((BMM050_S16)data_R) - + ((BMM050_S16) + p_bmm050->dig_xyz1))))>>2)) / + (p_bmm050->dig_z2 + + ((BMM050_S16)(((((BMM050_S32) + p_bmm050->dig_z1) * + ((((BMM050_S16)data_R) << 1)))+ + (1<<15))>>16)))); + /* saturate result to +/- 2 mT */ + if (retval > BMM050_POSITIVE_SATURATION_Z) { + retval = BMM050_POSITIVE_SATURATION_Z; + } else { + if (retval < BMM050_NEGATIVE_SATURATION_Z) + retval = BMM050_NEGATIVE_SATURATION_Z; + } + } else { + /* overflow */ + retval = BMM050_OVERFLOW_OUTPUT; + } + return (BMM050_S16)retval; +} + +BMM050_S32 bmm050_compensate_Z_s32(BMM050_S16 mdata_z, BMM050_U16 data_R) +{ + BMM050_S32 retval; + if (mdata_z != BMM050_HALL_OVERFLOW_ADCVAL) { + retval = (((((BMM050_S32)(mdata_z - p_bmm050->dig_z4)) << 15) - + ((((BMM050_S32)p_bmm050->dig_z3) * + ((BMM050_S32)(((BMM050_S16)data_R) - + ((BMM050_S16)p_bmm050->dig_xyz1))))>>2)) / + (p_bmm050->dig_z2 + + ((BMM050_S16)(((((BMM050_S32)p_bmm050->dig_z1) * + ((((BMM050_S16)data_R) << 1)))+(1<<15))>>16)))); + } else { + retval = BMM050_OVERFLOW_OUTPUT_S32; + } + return retval; +} + +#ifdef ENABLE_FLOAT +float bmm050_compensate_Z_float (BMM050_S16 mdata_z, BMM050_U16 data_R) +{ + float inter_retval; + if (mdata_z != BMM050_HALL_OVERFLOW_ADCVAL /* no overflow */ + ) { + inter_retval = ((((((float)mdata_z)-((float)p_bmm050->dig_z4))* + 131072.0f)-(((float)p_bmm050->dig_z3)*(((float)data_R)- + ((float)p_bmm050->dig_xyz1))))/((((float)p_bmm050->dig_z2)+ + ((float)p_bmm050->dig_z1)*((float)data_R)/32768.0)*4.0))/16.0; + } else { + /* overflow, set output to 0.0f */ + inter_retval = BMM050_OVERFLOW_OUTPUT_FLOAT; + } + return inter_retval; +} +#endif + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_control_measurement_x( + unsigned char enable_disable) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_SENS_CNTL_CHANNELX__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE(v_data1_u8r, + BMM050_SENS_CNTL_CHANNELX, + enable_disable); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_SENS_CNTL_CHANNELX__REG, + &v_data1_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_set_control_measurement_y( + unsigned char enable_disable) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data1_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_SENS_CNTL_CHANNELY__REG, + &v_data1_u8r, 1); + v_data1_u8r = BMM050_SET_BITSLICE( + v_data1_u8r, + BMM050_SENS_CNTL_CHANNELY, + enable_disable); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_SENS_CNTL_CHANNELY__REG, + &v_data1_u8r, 1); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_soft_reset(void) +{ + BMM050_RETURN_FUNCTION_TYPE comres = 0; + unsigned char v_data_u8r; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + v_data_u8r = BMM050_ON; + + comres = p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_SRST7__REG, + &v_data_u8r, 1); + v_data_u8r = BMM050_SET_BITSLICE(v_data_u8r, + BMM050_POWER_CNTL_SRST7, + BMM050_SOFT_RESET7_ON); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_SRST7__REG, &v_data_u8r, 1); + + comres |= p_bmm050->BMM050_BUS_READ_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_SRST1__REG, + &v_data_u8r, 1); + v_data_u8r = BMM050_SET_BITSLICE(v_data_u8r, + BMM050_POWER_CNTL_SRST1, + BMM050_SOFT_RESET1_ON); + comres |= p_bmm050->BMM050_BUS_WRITE_FUNC( + p_bmm050->dev_addr, + BMM050_POWER_CNTL_SRST1__REG, + &v_data_u8r, 1); + + p_bmm050->delay_msec(BMM050_DELAY_SOFTRESET); + } + return comres; +} + +BMM050_RETURN_FUNCTION_TYPE bmm050_get_raw_xyz(struct bmm050_mdata *mdata) +{ + BMM050_RETURN_FUNCTION_TYPE comres; + unsigned char a_data_u8r[6]; + if (p_bmm050 == BMM050_NULL) { + comres = E_BMM050_NULL_PTR; + } else { + comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr, + BMM050_DATAX_LSB, a_data_u8r, 6); + + a_data_u8r[0] = BMM050_GET_BITSLICE(a_data_u8r[0], + BMM050_DATAX_LSB_VALUEX); + mdata->datax = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[1])) + << SHIFT_LEFT_5_POSITION) + | a_data_u8r[0]); + + a_data_u8r[2] = BMM050_GET_BITSLICE(a_data_u8r[2], + BMM050_DATAY_LSB_VALUEY); + mdata->datay = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[3])) + << SHIFT_LEFT_5_POSITION) + | a_data_u8r[2]); + + a_data_u8r[4] = BMM050_GET_BITSLICE(a_data_u8r[4], + BMM050_DATAZ_LSB_VALUEZ); + mdata->dataz = (BMM050_S16)((((BMM050_S16) + ((signed char)a_data_u8r[5])) + << SHIFT_LEFT_7_POSITION) + | a_data_u8r[4]); + } + return comres; +} diff --git a/drivers/sensor/bmm050.h b/drivers/sensor/bmm050.h new file mode 100644 index 00000000..e6ecaf00 --- /dev/null +++ b/drivers/sensor/bmm050.h @@ -0,0 +1,580 @@ +/* + * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * @date Apr 28th, 2011 + * @version v1.0 + * @brief BMM050 Linux Driver API + */ + + +#ifndef __BMM050_H__ +#define __BMM050_H__ + + +#define BMM050_U16 unsigned short +#define BMM050_S16 signed short +#define BMM050_S32 signed int + + +#define BMM050_BUS_WR_RETURN_TYPE char +#define BMM050_BUS_WR_PARAM_TYPES\ + unsigned char, unsigned char, unsigned char *, unsigned char +#define BMM050_BUS_WR_PARAM_ORDER\ + (device_addr, register_addr, register_data, wr_len) +#define BMM050_BUS_WRITE_FUNC(\ + device_addr, register_addr, register_data, wr_len)\ + bus_write(device_addr, register_addr, register_data, wr_len) + +#define BMM050_BUS_RD_RETURN_TYPE char + +#define BMM050_BUS_RD_PARAM_TYPES\ + unsigned char, unsigned char, unsigned char *, unsigned char + +#define BMM050_BUS_RD_PARAM_ORDER (device_addr, register_addr, register_data) + +#define BMM050_BUS_READ_FUNC(device_addr, register_addr, register_data, rd_len)\ + bus_read(device_addr, register_addr, register_data, rd_len) + + +#define BMM050_DELAY_RETURN_TYPE void + +#define BMM050_DELAY_PARAM_TYPES unsigned int + +#define BMM050_DELAY_FUNC(delay_in_msec)\ + delay_func(delay_in_msec) + +#define BMM050_DELAY_POWEROFF_SUSPEND 1 +#define BMM050_DELAY_SUSPEND_SLEEP 2 +#define BMM050_DELAY_SLEEP_ACTIVE 1 +#define BMM050_DELAY_ACTIVE_SLEEP 1 +#define BMM050_DELAY_SLEEP_SUSPEND 1 +#define BMM050_DELAY_ACTIVE_SUSPEND 1 +#define BMM050_DELAY_SLEEP_POWEROFF 1 +#define BMM050_DELAY_ACTIVE_POWEROFF 1 +#define BMM050_DELAY_SETTLING_TIME 2 + + +#define BMM050_RETURN_FUNCTION_TYPE char +#define BMM050_I2C_ADDRESS 0x12 + +/*General Info datas*/ +#define BMM050_SOFT_RESET7_ON 1 +#define BMM050_SOFT_RESET1_ON 1 +#define BMM050_SOFT_RESET7_OFF 0 +#define BMM050_SOFT_RESET1_OFF 0 +#define BMM050_DELAY_SOFTRESET 1 + +/* Fixed Data Registers */ +#define BMM050_CHIP_ID 0x40 + +/* Data Registers */ +#define BMM050_DATAX_LSB 0x42 +#define BMM050_DATAX_MSB 0x43 +#define BMM050_DATAY_LSB 0x44 +#define BMM050_DATAY_MSB 0x45 +#define BMM050_DATAZ_LSB 0x46 +#define BMM050_DATAZ_MSB 0x47 +#define BMM050_R_LSB 0x48 +#define BMM050_R_MSB 0x49 + +/* Status Registers */ +#define BMM050_INT_STAT 0x4A + +/* Control Registers */ +#define BMM050_POWER_CNTL 0x4B +#define BMM050_CONTROL 0x4C +#define BMM050_INT_CNTL 0x4D +#define BMM050_SENS_CNTL 0x4E +#define BMM050_LOW_THRES 0x4F +#define BMM050_HIGH_THRES 0x50 +#define BMM050_NO_REPETITIONS_XY 0x51 +#define BMM050_NO_REPETITIONS_Z 0x52 + +/* Trim Extended Registers */ +#define BMM050_DIG_X1 0x5D +#define BMM050_DIG_Y1 0x5E +#define BMM050_DIG_Z4_LSB 0x62 +#define BMM050_DIG_Z4_MSB 0x63 +#define BMM050_DIG_X2 0x64 +#define BMM050_DIG_Y2 0x65 +#define BMM050_DIG_Z2_LSB 0x68 +#define BMM050_DIG_Z2_MSB 0x69 +#define BMM050_DIG_Z1_LSB 0x6A +#define BMM050_DIG_Z1_MSB 0x6B +#define BMM050_DIG_XYZ1_LSB 0x6C +#define BMM050_DIG_XYZ1_MSB 0x6D +#define BMM050_DIG_Z3_LSB 0x6E +#define BMM050_DIG_Z3_MSB 0x6F +#define BMM050_DIG_XY2 0x70 +#define BMM050_DIG_XY1 0x71 + + +/* Data X LSB Regsiter */ +#define BMM050_DATAX_LSB_VALUEX__POS 3 +#define BMM050_DATAX_LSB_VALUEX__LEN 5 +#define BMM050_DATAX_LSB_VALUEX__MSK 0xF8 +#define BMM050_DATAX_LSB_VALUEX__REG BMM050_DATAX_LSB + +#define BMM050_DATAX_LSB_TESTX__POS 0 +#define BMM050_DATAX_LSB_TESTX__LEN 1 +#define BMM050_DATAX_LSB_TESTX__MSK 0x01 +#define BMM050_DATAX_LSB_TESTX__REG BMM050_DATAX_LSB + +/* Data Y LSB Regsiter */ +#define BMM050_DATAY_LSB_VALUEY__POS 3 +#define BMM050_DATAY_LSB_VALUEY__LEN 5 +#define BMM050_DATAY_LSB_VALUEY__MSK 0xF8 +#define BMM050_DATAY_LSB_VALUEY__REG BMM050_DATAY_LSB + +#define BMM050_DATAY_LSB_TESTY__POS 0 +#define BMM050_DATAY_LSB_TESTY__LEN 1 +#define BMM050_DATAY_LSB_TESTY__MSK 0x01 +#define BMM050_DATAY_LSB_TESTY__REG BMM050_DATAY_LSB + +/* Data Z LSB Regsiter */ +#define BMM050_DATAZ_LSB_VALUEZ__POS 1 +#define BMM050_DATAZ_LSB_VALUEZ__LEN 7 +#define BMM050_DATAZ_LSB_VALUEZ__MSK 0xFE +#define BMM050_DATAZ_LSB_VALUEZ__REG BMM050_DATAZ_LSB + +#define BMM050_DATAZ_LSB_TESTZ__POS 0 +#define BMM050_DATAZ_LSB_TESTZ__LEN 1 +#define BMM050_DATAZ_LSB_TESTZ__MSK 0x01 +#define BMM050_DATAZ_LSB_TESTZ__REG BMM050_DATAZ_LSB + +/* Hall Resistance LSB Regsiter */ +#define BMM050_R_LSB_VALUE__POS 2 +#define BMM050_R_LSB_VALUE__LEN 6 +#define BMM050_R_LSB_VALUE__MSK 0xFC +#define BMM050_R_LSB_VALUE__REG BMM050_R_LSB + +#define BMM050_DATA_RDYSTAT__POS 0 +#define BMM050_DATA_RDYSTAT__LEN 1 +#define BMM050_DATA_RDYSTAT__MSK 0x01 +#define BMM050_DATA_RDYSTAT__REG BMM050_R_LSB + +/* Interupt Status Register */ +#define BMM050_INT_STAT_DOR__POS 7 +#define BMM050_INT_STAT_DOR__LEN 1 +#define BMM050_INT_STAT_DOR__MSK 0x80 +#define BMM050_INT_STAT_DOR__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_OVRFLOW__POS 6 +#define BMM050_INT_STAT_OVRFLOW__LEN 1 +#define BMM050_INT_STAT_OVRFLOW__MSK 0x40 +#define BMM050_INT_STAT_OVRFLOW__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_HIGH_THZ__POS 5 +#define BMM050_INT_STAT_HIGH_THZ__LEN 1 +#define BMM050_INT_STAT_HIGH_THZ__MSK 0x20 +#define BMM050_INT_STAT_HIGH_THZ__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_HIGH_THY__POS 4 +#define BMM050_INT_STAT_HIGH_THY__LEN 1 +#define BMM050_INT_STAT_HIGH_THY__MSK 0x10 +#define BMM050_INT_STAT_HIGH_THY__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_HIGH_THX__POS 3 +#define BMM050_INT_STAT_HIGH_THX__LEN 1 +#define BMM050_INT_STAT_HIGH_THX__MSK 0x08 +#define BMM050_INT_STAT_HIGH_THX__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_LOW_THZ__POS 2 +#define BMM050_INT_STAT_LOW_THZ__LEN 1 +#define BMM050_INT_STAT_LOW_THZ__MSK 0x04 +#define BMM050_INT_STAT_LOW_THZ__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_LOW_THY__POS 1 +#define BMM050_INT_STAT_LOW_THY__LEN 1 +#define BMM050_INT_STAT_LOW_THY__MSK 0x02 +#define BMM050_INT_STAT_LOW_THY__REG BMM050_INT_STAT + +#define BMM050_INT_STAT_LOW_THX__POS 0 +#define BMM050_INT_STAT_LOW_THX__LEN 1 +#define BMM050_INT_STAT_LOW_THX__MSK 0x01 +#define BMM050_INT_STAT_LOW_THX__REG BMM050_INT_STAT + +/* Power Control Register */ +#define BMM050_POWER_CNTL_SRST7__POS 7 +#define BMM050_POWER_CNTL_SRST7__LEN 1 +#define BMM050_POWER_CNTL_SRST7__MSK 0x80 +#define BMM050_POWER_CNTL_SRST7__REG BMM050_POWER_CNTL + +#define BMM050_POWER_CNTL_SPI3_EN__POS 2 +#define BMM050_POWER_CNTL_SPI3_EN__LEN 1 +#define BMM050_POWER_CNTL_SPI3_EN__MSK 0x04 +#define BMM050_POWER_CNTL_SPI3_EN__REG BMM050_POWER_CNTL + +#define BMM050_POWER_CNTL_SRST1__POS 1 +#define BMM050_POWER_CNTL_SRST1__LEN 1 +#define BMM050_POWER_CNTL_SRST1__MSK 0x02 +#define BMM050_POWER_CNTL_SRST1__REG BMM050_POWER_CNTL + +#define BMM050_POWER_CNTL_PCB__POS 0 +#define BMM050_POWER_CNTL_PCB__LEN 1 +#define BMM050_POWER_CNTL_PCB__MSK 0x01 +#define BMM050_POWER_CNTL_PCB__REG BMM050_POWER_CNTL + +/* Control Register */ +#define BMM050_CNTL_ADV_ST__POS 6 +#define BMM050_CNTL_ADV_ST__LEN 2 +#define BMM050_CNTL_ADV_ST__MSK 0xC0 +#define BMM050_CNTL_ADV_ST__REG BMM050_CONTROL + +#define BMM050_CNTL_DR__POS 3 +#define BMM050_CNTL_DR__LEN 3 +#define BMM050_CNTL_DR__MSK 0x38 +#define BMM050_CNTL_DR__REG BMM050_CONTROL + +#define BMM050_CNTL_OPMODE__POS 1 +#define BMM050_CNTL_OPMODE__LEN 2 +#define BMM050_CNTL_OPMODE__MSK 0x06 +#define BMM050_CNTL_OPMODE__REG BMM050_CONTROL + +#define BMM050_CNTL_S_TEST__POS 0 +#define BMM050_CNTL_S_TEST__LEN 1 +#define BMM050_CNTL_S_TEST__MSK 0x01 +#define BMM050_CNTL_S_TEST__REG BMM050_CONTROL + +/* Interupt Control Register */ +#define BMM050_INT_CNTL_DOR_EN__POS 7 +#define BMM050_INT_CNTL_DOR_EN__LEN 1 +#define BMM050_INT_CNTL_DOR_EN__MSK 0x80 +#define BMM050_INT_CNTL_DOR_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_OVRFLOW_EN__POS 6 +#define BMM050_INT_CNTL_OVRFLOW_EN__LEN 1 +#define BMM050_INT_CNTL_OVRFLOW_EN__MSK 0x40 +#define BMM050_INT_CNTL_OVRFLOW_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_HIGH_THZ_EN__POS 5 +#define BMM050_INT_CNTL_HIGH_THZ_EN__LEN 1 +#define BMM050_INT_CNTL_HIGH_THZ_EN__MSK 0x20 +#define BMM050_INT_CNTL_HIGH_THZ_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_HIGH_THY_EN__POS 4 +#define BMM050_INT_CNTL_HIGH_THY_EN__LEN 1 +#define BMM050_INT_CNTL_HIGH_THY_EN__MSK 0x10 +#define BMM050_INT_CNTL_HIGH_THY_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_HIGH_THX_EN__POS 3 +#define BMM050_INT_CNTL_HIGH_THX_EN__LEN 1 +#define BMM050_INT_CNTL_HIGH_THX_EN__MSK 0x08 +#define BMM050_INT_CNTL_HIGH_THX_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_LOW_THZ_EN__POS 2 +#define BMM050_INT_CNTL_LOW_THZ_EN__LEN 1 +#define BMM050_INT_CNTL_LOW_THZ_EN__MSK 0x04 +#define BMM050_INT_CNTL_LOW_THZ_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_LOW_THY_EN__POS 1 +#define BMM050_INT_CNTL_LOW_THY_EN__LEN 1 +#define BMM050_INT_CNTL_LOW_THY_EN__MSK 0x02 +#define BMM050_INT_CNTL_LOW_THY_EN__REG BMM050_INT_CNTL + +#define BMM050_INT_CNTL_LOW_THX_EN__POS 0 +#define BMM050_INT_CNTL_LOW_THX_EN__LEN 1 +#define BMM050_INT_CNTL_LOW_THX_EN__MSK 0x01 +#define BMM050_INT_CNTL_LOW_THX_EN__REG BMM050_INT_CNTL + +/* Sensor Control Register */ +#define BMM050_SENS_CNTL_DRDY_EN__POS 7 +#define BMM050_SENS_CNTL_DRDY_EN__LEN 1 +#define BMM050_SENS_CNTL_DRDY_EN__MSK 0x80 +#define BMM050_SENS_CNTL_DRDY_EN__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_IE__POS 6 +#define BMM050_SENS_CNTL_IE__LEN 1 +#define BMM050_SENS_CNTL_IE__MSK 0x40 +#define BMM050_SENS_CNTL_IE__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_CHANNELZ__POS 5 +#define BMM050_SENS_CNTL_CHANNELZ__LEN 1 +#define BMM050_SENS_CNTL_CHANNELZ__MSK 0x20 +#define BMM050_SENS_CNTL_CHANNELZ__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_CHANNELY__POS 4 +#define BMM050_SENS_CNTL_CHANNELY__LEN 1 +#define BMM050_SENS_CNTL_CHANNELY__MSK 0x10 +#define BMM050_SENS_CNTL_CHANNELY__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_CHANNELX__POS 3 +#define BMM050_SENS_CNTL_CHANNELX__LEN 1 +#define BMM050_SENS_CNTL_CHANNELX__MSK 0x08 +#define BMM050_SENS_CNTL_CHANNELX__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_DR_POLARITY__POS 2 +#define BMM050_SENS_CNTL_DR_POLARITY__LEN 1 +#define BMM050_SENS_CNTL_DR_POLARITY__MSK 0x04 +#define BMM050_SENS_CNTL_DR_POLARITY__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_INTERRUPT_LATCH__POS 1 +#define BMM050_SENS_CNTL_INTERRUPT_LATCH__LEN 1 +#define BMM050_SENS_CNTL_INTERRUPT_LATCH__MSK 0x02 +#define BMM050_SENS_CNTL_INTERRUPT_LATCH__REG BMM050_SENS_CNTL + +#define BMM050_SENS_CNTL_INTERRUPT_POLARITY__POS 0 +#define BMM050_SENS_CNTL_INTERRUPT_POLARITY__LEN 1 +#define BMM050_SENS_CNTL_INTERRUPT_POLARITY__MSK 0x01 +#define BMM050_SENS_CNTL_INTERRUPT_POLARITY__REG BMM050_SENS_CNTL + +/* Register 6D */ +#define BMM050_DIG_XYZ1_MSB__POS 0 +#define BMM050_DIG_XYZ1_MSB__LEN 7 +#define BMM050_DIG_XYZ1_MSB__MSK 0x7F +#define BMM050_DIG_XYZ1_MSB__REG BMM050_DIG_XYZ1_MSB + + +#define BMM050_X_AXIS 0 +#define BMM050_Y_AXIS 1 +#define BMM050_Z_AXIS 2 +#define BMM050_RESISTANCE 3 +#define BMM050_X 1 +#define BMM050_Y 2 +#define BMM050_Z 4 +#define BMM050_XYZ 7 + +/* Constants */ +#define BMM050_NULL 0 +#define BMM050_DISABLE 0 +#define BMM050_ENABLE 1 +#define BMM050_CHANNEL_DISABLE 1 +#define BMM050_CHANNEL_ENABLE 0 +#define BMM050_INTPIN_LATCH_ENABLE 1 +#define BMM050_INTPIN_LATCH_DISABLE 0 +#define BMM050_OFF 0 +#define BMM050_ON 1 + +#define BMM050_NORMAL_MODE 0x00 +#define BMM050_FORCED_MODE 0x01 +#define BMM050_SUSPEND_MODE 0x02 +#define BMM050_SLEEP_MODE 0x03 + +#define BMM050_ADVANCED_SELFTEST_OFF 0 +#define BMM050_ADVANCED_SELFTEST_NEGATIVE 2 +#define BMM050_ADVANCED_SELFTEST_POSITIVE 3 + +#define BMM050_NEGATIVE_SATURATION_Z -32767 +#define BMM050_POSITIVE_SATURATION_Z 32767 + +#define BMM050_SPI_RD_MASK 0x80 +#define BMM050_READ_SET 0x01 + +#define E_BMM050_NULL_PTR ((char)-127) +#define E_BMM050_COMM_RES ((char)-1) +#define E_BMM050_OUT_OF_RANGE ((char)-2) +#define E_BMM050_UNDEFINED_MODE 0 + +#define BMM050_WR_FUNC_PTR\ + char (*bus_write)(unsigned char, unsigned char,\ + unsigned char *, unsigned char) + +#define BMM050_RD_FUNC_PTR\ + char (*bus_read)(unsigned char, unsigned char,\ + unsigned char *, unsigned char) +#define BMM050_MDELAY_DATA_TYPE unsigned int + +/*Shifting Constants*/ +#define SHIFT_RIGHT_1_POSITION 1 +#define SHIFT_RIGHT_2_POSITION 2 +#define SHIFT_RIGHT_3_POSITION 3 +#define SHIFT_RIGHT_4_POSITION 4 +#define SHIFT_RIGHT_5_POSITION 5 +#define SHIFT_RIGHT_6_POSITION 6 +#define SHIFT_RIGHT_7_POSITION 7 +#define SHIFT_RIGHT_8_POSITION 8 + +#define SHIFT_LEFT_1_POSITION 1 +#define SHIFT_LEFT_2_POSITION 2 +#define SHIFT_LEFT_3_POSITION 3 +#define SHIFT_LEFT_4_POSITION 4 +#define SHIFT_LEFT_5_POSITION 5 +#define SHIFT_LEFT_6_POSITION 6 +#define SHIFT_LEFT_7_POSITION 7 +#define SHIFT_LEFT_8_POSITION 8 + +/* Conversion factors*/ +#define BMM050_CONVFACTOR_LSB_UT 6 + +/* get bit slice */ +#define BMM050_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + +/* Set bit slice */ +#define BMM050_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK)) + +/* compensated output value returned if sensor had overflow */ +#define BMM050_OVERFLOW_OUTPUT -32768 +#define BMM050_OVERFLOW_OUTPUT_S32 ((BMM050_S32)(-2147483647-1)) +#define BMM050_OVERFLOW_OUTPUT_FLOAT 0.0f +#define BMM050_FLIP_OVERFLOW_ADCVAL -4096 +#define BMM050_HALL_OVERFLOW_ADCVAL -16384 + + +#define BMM050_PRESETMODE_LOWPOWER 1 +#define BMM050_PRESETMODE_REGULAR 2 +#define BMM050_PRESETMODE_HIGHACCURACY 3 +#define BMM050_PRESETMODE_ENHANCED 4 + +/* PRESET MODES - DATA RATES */ +#define BMM050_LOWPOWER_DR BMM050_DR_10HZ +#define BMM050_REGULAR_DR BMM050_DR_10HZ +#define BMM050_HIGHACCURACY_DR BMM050_DR_20HZ +#define BMM050_ENHANCED_DR BMM050_DR_10HZ + +/* PRESET MODES - REPETITIONS-XY RATES */ +#define BMM050_LOWPOWER_REPXY 1 +#define BMM050_REGULAR_REPXY 4 +#define BMM050_HIGHACCURACY_REPXY 23 +#define BMM050_ENHANCED_REPXY 7 + +/* PRESET MODES - REPETITIONS-Z RATES */ +#define BMM050_LOWPOWER_REPZ 2 +#define BMM050_REGULAR_REPZ 15 +#define BMM050_HIGHACCURACY_REPZ 82 +#define BMM050_ENHANCED_REPZ 26 + +/* Data Rates */ + +#define BMM050_DR_10HZ 0 +#define BMM050_DR_02HZ 1 +#define BMM050_DR_06HZ 2 +#define BMM050_DR_08HZ 3 +#define BMM050_DR_15HZ 4 +#define BMM050_DR_20HZ 5 +#define BMM050_DR_25HZ 6 +#define BMM050_DR_30HZ 7 + +/*user defined Structures*/ +struct bmm050_mdata { + BMM050_S16 datax; + BMM050_S16 datay; + BMM050_S16 dataz; + BMM050_U16 resistance; +}; +struct bmm050_mdata_s32 { + BMM050_S32 datax; + BMM050_S32 datay; + BMM050_S32 dataz; + BMM050_U16 resistance; + BMM050_U16 drdy; +}; +struct bmm050_mdata_float { + float datax; + float datay; + float dataz; + BMM050_U16 resistance; +}; + +struct bmm050 { + unsigned char company_id; + unsigned char dev_addr; + + BMM050_WR_FUNC_PTR; + BMM050_RD_FUNC_PTR; + void(*delay_msec)(BMM050_MDELAY_DATA_TYPE); + + signed char dig_x1; + signed char dig_y1; + + signed char dig_x2; + signed char dig_y2; + + BMM050_U16 dig_z1; + BMM050_S16 dig_z2; + BMM050_S16 dig_z3; + BMM050_S16 dig_z4; + + unsigned char dig_xy1; + signed char dig_xy2; + + BMM050_U16 dig_xyz1; +}; + + +BMM050_RETURN_FUNCTION_TYPE bmm050_init(struct bmm050 *p_bmm050); +BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ( + struct bmm050_mdata *mdata); +BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ_s32( + struct bmm050_mdata_s32 *mdata); +#ifdef ENABLE_FLOAT +BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ_float( + struct bmm050_mdata_float *mdata); +#endif +BMM050_RETURN_FUNCTION_TYPE bmm050_read_register( + unsigned char addr, unsigned char *data, unsigned char len); +BMM050_RETURN_FUNCTION_TYPE bmm050_write_register( + unsigned char addr, unsigned char *data, unsigned char len); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_self_test_XYZ( + unsigned char *self_testxyz); +BMM050_S16 bmm050_compensate_X( + BMM050_S16 mdata_x, BMM050_U16 data_R); +BMM050_S32 bmm050_compensate_X_s32( + BMM050_S16 mdata_x, BMM050_U16 data_R); +#ifdef ENABLE_FLOAT +float bmm050_compensate_X_float( + BMM050_S16 mdata_x, BMM050_U16 data_R); +#endif +BMM050_S16 bmm050_compensate_Y( + BMM050_S16 mdata_y, BMM050_U16 data_R); +BMM050_S32 bmm050_compensate_Y_s32( + BMM050_S16 mdata_y, BMM050_U16 data_R); +#ifdef ENABLE_FLOAT +float bmm050_compensate_Y_float( + BMM050_S16 mdata_y, BMM050_U16 data_R); +#endif +BMM050_S16 bmm050_compensate_Z( + BMM050_S16 mdata_z, BMM050_U16 data_R); +BMM050_S32 bmm050_compensate_Z_s32( + BMM050_S16 mdata_z, BMM050_U16 data_R); +#ifdef ENABLE_FLOAT +float bmm050_compensate_Z_float( + BMM050_S16 mdata_z, BMM050_U16 data_R); +#endif +BMM050_RETURN_FUNCTION_TYPE bmm050_get_raw_xyz( + struct bmm050_mdata *mdata); +BMM050_RETURN_FUNCTION_TYPE bmm050_init_trim_registers(void); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_spi3( + unsigned char value); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_powermode( + unsigned char *mode); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_powermode( + unsigned char mode); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_adv_selftest( + unsigned char adv_selftest); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_adv_selftest( + unsigned char *adv_selftest); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_datarate( + unsigned char data_rate); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_datarate( + unsigned char *data_rate); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_functional_state( + unsigned char functional_state); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_functional_state( + unsigned char *functional_state); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_selftest( + unsigned char selftest); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_selftest( + unsigned char *selftest); +BMM050_RETURN_FUNCTION_TYPE bmm050_perform_advanced_selftest( + BMM050_S16 *diff_z); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_repetitions_XY( + unsigned char *no_repetitions_xy); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_repetitions_XY( + unsigned char no_repetitions_xy); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_repetitions_Z( + unsigned char *no_repetitions_z); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_repetitions_Z( + unsigned char no_repetitions_z); +BMM050_RETURN_FUNCTION_TYPE bmm050_get_presetmode(unsigned char *mode); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_presetmode(unsigned char mode); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_control_measurement_x( + unsigned char enable_disable); +BMM050_RETURN_FUNCTION_TYPE bmm050_set_control_measurement_y( + unsigned char enable_disable); +BMM050_RETURN_FUNCTION_TYPE bmm050_soft_reset(void); +#endif diff --git a/drivers/sensor/bmm050_driver.c b/drivers/sensor/bmm050_driver.c new file mode 100644 index 00000000..662f8ca1 --- /dev/null +++ b/drivers/sensor/bmm050_driver.c @@ -0,0 +1,1593 @@ +/* + * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * @date Jun 12th, 2013 + * @version v2.5.5 + * @brief BMM050 Linux Driver + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/sensors_core.h> + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif + +#define DEBUG 1 + +#include <linux/bst_sensor_common.h> + +#include "bmm050.h" +#include "bs_log.h" + +/* sensor specific */ +#define SENSOR_NAME "bmm050" + +#define SENSOR_CHIP_ID_BMM (0x32) + +#define BMM_REG_NAME(name) BMM050_##name +#define BMM_VAL_NAME(name) BMM050_##name +#define BMM_CALL_API(name) bmm050_##name + +#define BMM_I2C_WRITE_DELAY_TIME 1 + +#define BMM_DEFAULT_REPETITION_XY BMM_VAL_NAME(REGULAR_REPXY) +#define BMM_DEFAULT_REPETITION_Z BMM_VAL_NAME(REGULAR_REPZ) +#define BMM_DEFAULT_ODR BMM_VAL_NAME(REGULAR_DR) +/* generic */ +#define BMM_MAX_RETRY_I2C_XFER (100) +#define BMM_MAX_RETRY_WAKEUP (5) +#define BMM_MAX_RETRY_WAIT_DRDY (100) + +#define BMM_DELAY_MIN (1) +#define BMM_DELAY_DEFAULT (200) + +#define MAG_VALUE_MAX (32767) +#define MAG_VALUE_MIN (-32768) + +#define BYTES_PER_LINE (16) + +#define BMM_SELF_TEST 1 +#define BMM_ADV_TEST 2 + +#define BMM_OP_MODE_UNKNOWN (-1) + +static struct device *bmm_device = NULL; +struct op_mode_map { + char *op_mode_name; + long op_mode; +}; + +static const u8 odr_map[] = {10, 2, 6, 8, 15, 20, 25, 30}; +static const struct op_mode_map op_mode_maps[] = { + {"normal", BMM_VAL_NAME(NORMAL_MODE)}, + {"forced", BMM_VAL_NAME(FORCED_MODE)}, + {"suspend", BMM_VAL_NAME(SUSPEND_MODE)}, + {"sleep", BMM_VAL_NAME(SLEEP_MODE)}, +}; + + +struct bmm_client_data { + struct bmm050 device; + struct i2c_client *client; + struct input_dev *input; + struct delayed_work work; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend_handler; +#endif + + atomic_t delay; + /* whether the system in suspend state */ + atomic_t in_suspend; + + struct bmm050_mdata_s32 value; + u8 enable:1; + s8 op_mode:4; + u8 odr; + u8 rept_xy; + u8 rept_z; + + s16 result_test; + + struct mutex mutex_power_mode; + + /* controls not only reg, but also workqueue */ + struct mutex mutex_op_mode; + struct mutex mutex_enable; + struct mutex mutex_odr; + struct mutex mutex_rept_xy; + struct mutex mutex_rept_z; + + struct mutex mutex_value; +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + struct bosch_sensor_specific *bst_pd; +#endif +}; + +static struct i2c_client *bmm_client; +/* i2c operation for API */ +static void bmm_delay(u32 msec); +static char bmm_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len); +static char bmm_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len); + +static void bmm_dump_reg(struct i2c_client *client); +static int bmm_wakeup(struct i2c_client *client); +static int bmm_check_chip_id(struct i2c_client *client); + +static int bmm_pre_suspend(struct i2c_client *client); +static int bmm_post_resume(struct i2c_client *client); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bmm_early_suspend(struct early_suspend *handler); +static void bmm_late_resume(struct early_suspend *handler); +#endif + +static int bmm_restore_hw_cfg(struct i2c_client *client); + +static void bmm_remap_sensor_data(struct bmm050_mdata_s32 *val, + struct bmm_client_data *client_data) +{ +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + struct bosch_sensor_data bsd; + + if (NULL == client_data->bst_pd) + return; + + bsd.x = val->datax; + bsd.y = val->datay; + bsd.z = val->dataz; + + bst_remap_sensor_data_dft_tab(&bsd, + client_data->bst_pd->place); + + val->datax = bsd.x; + val->datay = bsd.y; + val->dataz = bsd.z; +#else + (void)val; + (void)client_data; +#endif +} + +static int bmm_check_chip_id(struct i2c_client *client) +{ + int err = 0; + u8 chip_id = 0; + + bmm_i2c_read(client, BMM_REG_NAME(CHIP_ID), &chip_id, 1); + PINFO("read chip id result: %#x", chip_id); + + if ((chip_id & 0xff) != SENSOR_CHIP_ID_BMM) + err = -1; + + return err; +} + +static void bmm_delay(u32 msec) +{ + mdelay(msec); +} + +static inline int bmm_get_forced_drdy_time(int rept_xy, int rept_z) +{ + return (145 * rept_xy + 500 * rept_z + 980 + (1000 - 1)) / 1000; +} + + +static void bmm_dump_reg(struct i2c_client *client) +{ +#ifdef DEBUG + int i; + u8 dbg_buf[64]; + u8 dbg_buf_str[64 * 3 + 1] = ""; + + for (i = 0; i < BYTES_PER_LINE; i++) { + dbg_buf[i] = i; + sprintf(dbg_buf_str + i * 3, "%02x%c", + dbg_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + printk(KERN_DEBUG "%s\n", dbg_buf_str); + + bmm_i2c_read(client, BMM_REG_NAME(CHIP_ID), dbg_buf, 64); + for (i = 0; i < 64; i++) { + sprintf(dbg_buf_str + i * 3, "%02x%c", + dbg_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + printk(KERN_DEBUG "%s\n", dbg_buf_str); +#endif +} + +static int bmm_wakeup(struct i2c_client *client) +{ + int err = 0; + int try_times = BMM_MAX_RETRY_WAKEUP; + const u8 value = 0x01; + u8 dummy; + + PINFO("waking up the chip..."); + + while (try_times) { + err = bmm_i2c_write(client, + BMM_REG_NAME(POWER_CNTL), (u8 *)&value, 1); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + dummy = 0; + + err = bmm_i2c_read(client, BMM_REG_NAME(POWER_CNTL), &dummy, 1); + if (value == dummy) + break; + + try_times--; + } + + PINFO("wake up result: %s, tried times: %d", + (try_times > 0) ? "succeed" : "fail", + BMM_MAX_RETRY_WAKEUP - try_times + 1); + + err = (try_times > 0) ? 0 : -1; + + return err; +} + +/* i2c read routine for API*/ +static char bmm_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ +#if !defined BMM_USE_BASIC_I2C_FUNC + s32 dummy; + if (NULL == client) + return -1; + + while (0 != len--) { +#ifdef BMM_SMBUS + dummy = i2c_smbus_read_byte_data(client, reg_addr); + if (dummy < 0) { + PERR("i2c bus read error"); + return -1; + } + *data = (u8)(dummy & 0xff); +#else + dummy = i2c_master_send(client, (char *)®_addr, 1); + if (dummy < 0) + return -1; + + dummy = i2c_master_recv(client, (char *)data, 1); + if (dummy < 0) + return -1; +#endif + reg_addr++; + data++; + } + return 0; +#else + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < BMM_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + mdelay(BMM_I2C_WRITE_DELAY_TIME); + } + + if (BMM_MAX_RETRY_I2C_XFER <= retry) { + PERR("I2C xfer error"); + return -EIO; + } + + return 0; +#endif +} + +/* i2c write routine for */ +static char bmm_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ +#if !defined BMM_USE_BASIC_I2C_FUNC + s32 dummy; + +#ifndef BMM_SMBUS + u8 buffer[2]; +#endif + + if (NULL == client) + return -1; + + while (0 != len--) { +#ifdef BMM_SMBUS + dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); +#else + buffer[0] = reg_addr; + buffer[1] = *data; + dummy = i2c_master_send(client, (char *)buffer, 2); +#endif + reg_addr++; + data++; + if (dummy < 0) { + PERR("error writing i2c bus"); + return -1; + } + + } + return 0; +#else + u8 buffer[2]; + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buffer, + }, + }; + + while (0 != len--) { + buffer[0] = reg_addr; + buffer[1] = *data; + for (retry = 0; retry < BMM_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) { + break; + } else { + mdelay(BMM_I2C_WRITE_DELAY_TIME); + } + } + if (BMM_MAX_RETRY_I2C_XFER <= retry) { + PERR("I2C xfer error"); + return -EIO; + } + reg_addr++; + data++; + } + + return 0; +#endif +} + +static char bmm_i2c_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + char err = 0; + err = bmm_i2c_read(bmm_client, reg_addr, data, len); + + return err; +} + +static char bmm_i2c_write_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + char err = 0; + err = bmm_i2c_write(bmm_client, reg_addr, data, len); + return err; +} + +/* this function exists for optimization of speed, + * because it is frequently called */ +static inline int bmm_set_forced_mode(struct i2c_client *client) +{ + int err = 0; + + /* FORCED_MODE */ + const u8 value = 0x02; + err = bmm_i2c_write(client, BMM_REG_NAME(CONTROL), (u8 *)&value, 1); + + return err; +} + +static void bmm_work_func(struct work_struct *work) +{ + struct bmm_client_data *client_data = + container_of((struct delayed_work *)work, + struct bmm_client_data, work); + struct i2c_client *client = client_data->client; + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + + mutex_lock(&client_data->mutex_value); + + mutex_lock(&client_data->mutex_op_mode); + if (BMM_VAL_NAME(NORMAL_MODE) != client_data->op_mode) + bmm_set_forced_mode(client); + + mutex_unlock(&client_data->mutex_op_mode); + + BMM_CALL_API(read_mdataXYZ_s32)(&client_data->value); + bmm_remap_sensor_data(&client_data->value, client_data); + + input_report_abs(client_data->input, ABS_X, client_data->value.datax); + input_report_abs(client_data->input, ABS_Y, client_data->value.datay); + input_report_abs(client_data->input, ABS_Z, client_data->value.dataz); + mutex_unlock(&client_data->mutex_value); + + input_sync(client_data->input); + + schedule_delayed_work(&client_data->work, delay); +} + + +static int bmm_set_odr(struct i2c_client *client, u8 odr) +{ + int err = 0; + + err = BMM_CALL_API(set_datarate)(odr); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + + return err; +} + +static int bmm_get_odr(struct i2c_client *client, u8 *podr) +{ + int err = 0; + u8 value; + + err = BMM_CALL_API(get_datarate)(&value); + if (!err) + *podr = value; + + return err; +} + +static ssize_t bmm_show_chip_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", SENSOR_CHIP_ID_BMM); +} + +static ssize_t bmm_show_op_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + u8 op_mode = 0xff; + u8 power_mode; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + if (power_mode) { + mutex_lock(&client_data->mutex_op_mode); + BMM_CALL_API(get_functional_state)(&op_mode); + mutex_unlock(&client_data->mutex_op_mode); + } else { + op_mode = BMM_VAL_NAME(SUSPEND_MODE); + } + + mutex_unlock(&client_data->mutex_power_mode); + + PDEBUG("op_mode: %d", op_mode); + + ret = sprintf(buf, "%d\n", op_mode); + + return ret; +} + + +static inline int bmm_get_op_mode_idx(u8 op_mode) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(op_mode_maps); i++) { + if (op_mode_maps[i].op_mode == op_mode) + break; + } + + if (i < ARRAY_SIZE(op_mode_maps)) + return i; + else + return -1; +} + + +static int bmm_set_op_mode(struct bmm_client_data *client_data, int op_mode) +{ + int err = 0; + + err = BMM_CALL_API(set_functional_state)( + op_mode); + + if (BMM_VAL_NAME(SUSPEND_MODE) == op_mode) + atomic_set(&client_data->in_suspend, 1); + else + atomic_set(&client_data->in_suspend, 0); + + return err; +} + +static ssize_t bmm_store_op_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err = 0; + int i; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + struct i2c_client *client = client_data->client; + long op_mode; + + err = strict_strtoul(buf, 10, &op_mode); + if (err) + return err; + + mutex_lock(&client_data->mutex_power_mode); + + i = bmm_get_op_mode_idx(op_mode); + + if (i != -1) { + mutex_lock(&client_data->mutex_op_mode); + if (op_mode != client_data->op_mode) { + if (BMM_VAL_NAME(FORCED_MODE) == op_mode) { + /* special treat of forced mode + * for optimization */ + err = bmm_set_forced_mode(client); + } else { + err = bmm_set_op_mode(client_data, op_mode); + } + + if (!err) { + if (BMM_VAL_NAME(FORCED_MODE) == op_mode) + client_data->op_mode = + BMM_OP_MODE_UNKNOWN; + else + client_data->op_mode = op_mode; + } + } + mutex_unlock(&client_data->mutex_op_mode); + } else { + err = -EINVAL; + } + + mutex_unlock(&client_data->mutex_power_mode); + + if (err) + return err; + else + return count; +} + +static ssize_t bmm_show_odr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + struct i2c_client *client = client_data->client; + int err; + u8 power_mode; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + if (power_mode) { + mutex_lock(&client_data->mutex_odr); + err = bmm_get_odr(client, &data); + mutex_unlock(&client_data->mutex_odr); + } else { + err = -EIO; + } + mutex_unlock(&client_data->mutex_power_mode); + + if (!err) { + if (data < ARRAY_SIZE(odr_map)) + err = sprintf(buf, "%d\n", odr_map[data]); + else + err = -EINVAL; + } + + return err; +} + +static ssize_t bmm_store_odr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long tmp; + unsigned char data; + int err; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + struct i2c_client *client = client_data->client; + u8 power_mode; + int i; + + err = strict_strtoul(buf, 10, &tmp); + if (err) + return err; + + if (tmp > 255) + return -EINVAL; + + data = (unsigned char)tmp; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + if (power_mode) { + for (i = 0; i < ARRAY_SIZE(odr_map); i++) { + if (odr_map[i] == data) + break; + } + + if (i < ARRAY_SIZE(odr_map)) { + mutex_lock(&client_data->mutex_odr); + err = bmm_set_odr(client, i); + if (!err) + client_data->odr = i; + + mutex_unlock(&client_data->mutex_odr); + } else { + err = -EINVAL; + } + } else { + err = -EIO; + } + + mutex_unlock(&client_data->mutex_power_mode); + if (err) + return err; + + return count; +} + +static ssize_t bmm_show_rept_xy(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int err; + u8 power_mode; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + printk(KERN_ALERT"%s : value of power_mode after get_powermode %u \n",__func__, power_mode); + + if (power_mode) { + mutex_lock(&client_data->mutex_rept_xy); + err = BMM_CALL_API(get_repetitions_XY)(&data); + printk(KERN_ALERT"%s : value of power_mode after get_repretitions_XY %u \n",__func__, data); + mutex_unlock(&client_data->mutex_rept_xy); + } else { + err = -EIO; + } + + mutex_unlock(&client_data->mutex_power_mode); + + if (err) + return err; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmm_store_rept_xy(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long tmp = 0; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int err; + u8 data; + u8 power_mode; + + err = strict_strtoul(buf, 10, &tmp); + if (err) + return err; + + if (tmp > 255) + return -EINVAL; + + data = (unsigned char)tmp; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + printk(KERN_ALERT"%s : value of power_mode after get_powermode %u\n",__func__, power_mode); + + if (power_mode) { + mutex_lock(&client_data->mutex_rept_xy); + err = BMM_CALL_API(set_repetitions_XY)(data); + printk(KERN_ALERT "%s : value of power_mode after set_repretitions_XY %u \n",__func__,data); + + if (!err) { + mdelay(BMM_I2C_WRITE_DELAY_TIME); + client_data->rept_xy = data; + } + mutex_unlock(&client_data->mutex_rept_xy); + } else { + err = -EIO; + } + mutex_unlock(&client_data->mutex_power_mode); + + if (err) + return err; + + return count; +} + +static ssize_t bmm_show_rept_z(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data = 0; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int err; + u8 power_mode; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + printk(KERN_ALERT"%s : value of power_mode after get_powermode %u\n",__func__, power_mode); + if (power_mode) { + mutex_lock(&client_data->mutex_rept_z); + err = BMM_CALL_API(get_repetitions_Z)(&data); + printk(KERN_ALERT"%s : value of power_mode after get_repretitions_XY %u \n",__func__, data); + mutex_unlock(&client_data->mutex_rept_z); + } else { + err = -EIO; + } + + mutex_unlock(&client_data->mutex_power_mode); + + if (err) + return err; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmm_store_rept_z(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long tmp = 0; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int err; + u8 data; + u8 power_mode; + + err = strict_strtoul(buf, 10, &tmp); + if (err) + return err; + + if (tmp > 255) + return -EINVAL; + + data = (unsigned char)tmp; + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + printk(KERN_ALERT" %s : value of power_mode after get_powermode %u\n",__func__, power_mode); + if (power_mode) { + mutex_lock(&client_data->mutex_rept_z); + err = BMM_CALL_API(set_repetitions_Z)(data); + printk(KERN_ALERT"%s : value of power_mode after set_repretitions_XY %u \n",__func__, data); + if (!err) { + mdelay(BMM_I2C_WRITE_DELAY_TIME); + client_data->rept_z = data; + } + mutex_unlock(&client_data->mutex_rept_z); + } else { + err = -EIO; + } + mutex_unlock(&client_data->mutex_power_mode); + + if (err) + return err; + + return count; +} + + +static ssize_t bmm_show_value(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int count; + struct bmm050_mdata_s32 value = {0, 0, 0, 0, 0}; + + BMM_CALL_API(read_mdataXYZ_s32)(&value); + if (value.drdy) { + bmm_remap_sensor_data(&value, client_data); + client_data->value = value; + } else + PERR("data not ready"); + + count = sprintf(buf, "%d %d %d\n", + client_data->value.datax, + client_data->value.datay, + client_data->value.dataz); + PDEBUG("%d %d %d", + client_data->value.datax, + client_data->value.datay, + client_data->value.dataz); + + return count; +} + + +static ssize_t bmm_show_value_raw(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmm050_mdata value; + int count; + + BMM_CALL_API(get_raw_xyz)(&value); + + count = sprintf(buf, "%hd %hd %hd\n", + value.datax, + value.datay, + value.dataz); + + return count; +} + + +static ssize_t bmm_show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int err; + + mutex_lock(&client_data->mutex_enable); + err = sprintf(buf, "%d\n", client_data->enable); + mutex_unlock(&client_data->mutex_enable); + return err; +} + +static void bmm_input_destroy(struct bmm_client_data *client_data) +{ + struct input_dev *dev = client_data->input; + + input_unregister_device(dev); + input_free_device(dev); +} + +static ssize_t bmm_store_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + + err = strict_strtoul(buf, 10, &data); + if (err) + return err; + + data = data ? 1 : 0; + mutex_lock(&client_data->mutex_enable); + + if (data != client_data->enable) { + if (data) { + + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(NORMAL_MODE)); + if (err) + { + PERR(" %s : fail to init h/w of %s",__func__, SENSOR_NAME); + err = -EIO; + goto exit_err_sysfs; + } + schedule_delayed_work( + &client_data->work, + msecs_to_jiffies(atomic_read( + &client_data->delay))); + } else { + + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SUSPEND_MODE)); + if (err) + { + PERR(" %s : fail to init h/w of %s",__func__, SENSOR_NAME); + err = -EIO; + goto exit_err_sysfs; + } + cancel_delayed_work_sync(&client_data->work); + } + + client_data->enable = data; + } + mutex_unlock(&client_data->mutex_enable); + +exit_err_sysfs: + if (err) + bmm_input_destroy(client_data); + + return count; +} + +static ssize_t bmm_show_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + + return sprintf(buf, "%d\n", atomic_read(&client_data->delay)); + +} + +static ssize_t bmm_store_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + + err = strict_strtoul(buf, 10, &data); + if (err) + return err; + + if (data <= 0) { + err = -EINVAL; + return err; + } + + if (data < BMM_DELAY_MIN) + data = BMM_DELAY_MIN; + + atomic_set(&client_data->delay, data); + + return count; +} + +static ssize_t bmm_show_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + int err; + + err = sprintf(buf, "%d\n", client_data->result_test); + return err; +} + +static ssize_t bmm_store_test(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + struct i2c_client *client = client_data->client; + u8 dummy; + + err = strict_strtoul(buf, 10, &data); + if (err) + return err; + + /* the following code assumes the work thread is not running */ + if (BMM_SELF_TEST == data) { + /* self test */ + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SLEEP_MODE)); + mdelay(3); + err = BMM_CALL_API(set_selftest)(1); + mdelay(3); + err = BMM_CALL_API(get_self_test_XYZ)(&dummy); + client_data->result_test = dummy; + } else if (BMM_ADV_TEST == data) { + /* advanced self test */ + err = BMM_CALL_API(perform_advanced_selftest)( + &client_data->result_test); + } else { + err = -EINVAL; + } + + if (!err) { + BMM_CALL_API(soft_reset)(); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + bmm_restore_hw_cfg(client); + } + + if (err) + count = -1; + + return count; +} + + +static ssize_t bmm_show_reg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + int i; + u8 dbg_buf[64]; + u8 dbg_buf_str[64 * 3 + 1] = ""; + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); + struct i2c_client *client = client_data->client; + + for (i = 0; i < BYTES_PER_LINE; i++) { + dbg_buf[i] = i; + sprintf(dbg_buf_str + i * 3, "%02x%c", + dbg_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + memcpy(buf, dbg_buf_str, BYTES_PER_LINE * 3); + + for (i = 0; i < BYTES_PER_LINE * 3 - 1; i++) + dbg_buf_str[i] = '-'; + + dbg_buf_str[i] = '\n'; + memcpy(buf + BYTES_PER_LINE * 3, dbg_buf_str, BYTES_PER_LINE * 3); + + + bmm_i2c_read(client, BMM_REG_NAME(CHIP_ID), dbg_buf, 64); + for (i = 0; i < 64; i++) { + sprintf(dbg_buf_str + i * 3, "%02x%c", + dbg_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + memcpy(buf + BYTES_PER_LINE * 3 + BYTES_PER_LINE * 3, + dbg_buf_str, 64 * 3); + + err = BYTES_PER_LINE * 3 + BYTES_PER_LINE * 3 + 64 * 3; + return err; +} + + +static ssize_t bmm_show_place(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + struct input_dev *input = to_input_dev(dev); + struct bmm_client_data *client_data = input_get_drvdata(input); +#endif + int place = BOSCH_SENSOR_PLACE_UNKNOWN; + +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + if (NULL != client_data->bst_pd) + place = client_data->bst_pd->place; +#endif + return sprintf(buf, "%d\n", place); +} + + +static DEVICE_ATTR(chip_id, S_IRUGO, + bmm_show_chip_id, NULL); +static DEVICE_ATTR(op_mode, S_IRUGO|S_IWUSR, + bmm_show_op_mode, bmm_store_op_mode); +static DEVICE_ATTR(odr, S_IRUGO|S_IWUSR, + bmm_show_odr, bmm_store_odr); +static DEVICE_ATTR(rept_xy, S_IRUGO|S_IWUSR, + bmm_show_rept_xy, bmm_store_rept_xy); +static DEVICE_ATTR(rept_z, S_IRUGO|S_IWUSR, + bmm_show_rept_z, bmm_store_rept_z); +static DEVICE_ATTR(value, S_IRUGO, + bmm_show_value, NULL); +static DEVICE_ATTR(value_raw, S_IRUGO, + bmm_show_value_raw, NULL); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, + bmm_show_enable, bmm_store_enable); +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, + bmm_show_delay, bmm_store_delay); +static DEVICE_ATTR(test, S_IRUGO|S_IWUSR, + bmm_show_test, bmm_store_test); +static DEVICE_ATTR(reg, S_IRUGO, + bmm_show_reg, NULL); +static DEVICE_ATTR(place, S_IRUGO, + bmm_show_place, NULL); + +static struct attribute *bmm_attributes[] = { + &dev_attr_chip_id.attr, + &dev_attr_op_mode.attr, + &dev_attr_odr.attr, + &dev_attr_rept_xy.attr, + &dev_attr_rept_z.attr, + &dev_attr_value.attr, + &dev_attr_value_raw.attr, + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_test.attr, + &dev_attr_reg.attr, + &dev_attr_place.attr, + NULL +}; + + +static struct attribute_group bmm_attribute_group = { + .attrs = bmm_attributes +}; + + +static struct device_attribute *bmm050_attr[] = { + &dev_attr_value, + &dev_attr_value_raw, + &dev_attr_enable, + NULL, + }; + +static int bmm_input_init(struct bmm_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = input_allocate_device(); + if (NULL == dev) + return -ENOMEM; + + dev->name = SENSOR_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0); + input_set_abs_params(dev, ABS_Y, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0); + input_set_abs_params(dev, ABS_Z, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0); + input_set_drvdata(dev, client_data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + client_data->input = dev; + + return 0; +} + +static int bmm_restore_hw_cfg(struct i2c_client *client) +{ + int err = 0; + u8 value; + struct bmm_client_data *client_data = + (struct bmm_client_data *)i2c_get_clientdata(client); + int op_mode; + + mutex_lock(&client_data->mutex_op_mode); + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SLEEP_MODE)); + + if (bmm_get_op_mode_idx(client_data->op_mode) != -1) + err = bmm_set_op_mode(client_data, client_data->op_mode); + + op_mode = client_data->op_mode; + mutex_unlock(&client_data->mutex_op_mode); + + if (BMM_VAL_NAME(SUSPEND_MODE) == op_mode) + return err; + + PINFO("app did not close this sensor before suspend"); + + mutex_lock(&client_data->mutex_odr); + BMM_CALL_API(set_datarate)(client_data->odr); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + mutex_unlock(&client_data->mutex_odr); + + mutex_lock(&client_data->mutex_rept_xy); + err = bmm_i2c_write(client, BMM_REG_NAME(NO_REPETITIONS_XY), + &client_data->rept_xy, 1); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + err = bmm_i2c_read(client, BMM_REG_NAME(NO_REPETITIONS_XY), &value, 1); + PINFO("BMM_NO_REPETITIONS_XY: %02x", value); + mutex_unlock(&client_data->mutex_rept_xy); + + mutex_lock(&client_data->mutex_rept_z); + err = bmm_i2c_write(client, BMM_REG_NAME(NO_REPETITIONS_Z), + &client_data->rept_z, 1); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + err = bmm_i2c_read(client, BMM_REG_NAME(NO_REPETITIONS_Z), &value, 1); + PINFO("BMM_NO_REPETITIONS_Z: %02x", value); + mutex_unlock(&client_data->mutex_rept_z); + + mutex_lock(&client_data->mutex_op_mode); + if (BMM_OP_MODE_UNKNOWN == (int)client_data->op_mode) { + bmm_set_forced_mode(client); + PINFO("set forced mode after hw_restore"); + mdelay(bmm_get_forced_drdy_time(client_data->rept_xy, + client_data->rept_z)); + } + mutex_unlock(&client_data->mutex_op_mode); + + + PINFO("register dump after init"); + bmm_dump_reg(client); + + return err; +} + +static int bmm_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + struct bmm_client_data *client_data = NULL; + int dummy; + + printk(KERN_ALERT"%s : function entrance\n",__func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + PERR("%s : i2c_check_functionality error!\n",__func__); + err = -EIO; + goto exit_err_clean; + } + + if (NULL == bmm_client) { + bmm_client = client; + } else { + PERR("this driver does not support multiple clients"); + err = -EBUSY; + return err; + } + + /* wake up the chip */ + dummy = bmm_wakeup(client); + if (dummy < 0) { + PERR("Cannot wake up %s, I2C xfer error", SENSOR_NAME); + err = -EIO; + goto exit_err_clean; + } + + PINFO("register dump after waking up"); + bmm_dump_reg(client); + /* check chip id */ + err = bmm_check_chip_id(client); + if (!err) { + PNOTICE("Bosch Sensortec Device %s detected: %#x", + SENSOR_NAME, client->addr); + } else { + PERR("Bosch Sensortec Device not found, chip id mismatch"); + err = -1; + goto exit_err_clean; + } + + client_data = kzalloc(sizeof(struct bmm_client_data), GFP_KERNEL); + if (NULL == client_data) { + PERR("no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + i2c_set_clientdata(client, client_data); + client_data->client = client; + + mutex_init(&client_data->mutex_power_mode); + mutex_init(&client_data->mutex_op_mode); + mutex_init(&client_data->mutex_enable); + mutex_init(&client_data->mutex_odr); + mutex_init(&client_data->mutex_rept_xy); + mutex_init(&client_data->mutex_rept_z); + mutex_init(&client_data->mutex_value); + + /* input device init */ + err = bmm_input_init(client_data); + if (err < 0) + goto exit_err_clean; + + /* sysfs node creation */ + err = sysfs_create_group(&client_data->input->dev.kobj, + &bmm_attribute_group); + printk(KERN_ALERT"%s : sysfs for magnetic created \n",__func__); + + if (err < 0) + goto exit_err_sysfs; + +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + + printk(KERN_ALERT"%s Entering Plat Data bmm \n",__func__); + if (NULL != client->dev.platform_data) { + client_data->bst_pd = kzalloc(sizeof(*client_data->bst_pd), + GFP_KERNEL); + + if (NULL != client_data->bst_pd) { + memcpy(client_data->bst_pd, client->dev.platform_data, + sizeof(*client_data->bst_pd)); + + printk(KERN_ALERT" %s : platform data of bmm %s: place: %d, irq: %d",__func__, + client_data->bst_pd->name, + client_data->bst_pd->place, + client_data->bst_pd->irq); + } + } +#endif + + + /* workqueue init */ + INIT_DELAYED_WORK(&client_data->work, bmm_work_func); + atomic_set(&client_data->delay, BMM_DELAY_DEFAULT); + + /* h/w init */ + client_data->device.bus_read = bmm_i2c_read_wrapper; + client_data->device.bus_write = bmm_i2c_write_wrapper; + client_data->device.delay_msec = bmm_delay; + + BMM_CALL_API(init)(&client_data->device); + + bmm_dump_reg(client); + + PDEBUG(" %s : trimming_reg x1: %d y1: %d x2: %d y2: %d xy1: %d xy2: %d\n",__func__, + client_data->device.dig_x1, + client_data->device.dig_y1, + client_data->device.dig_x2, + client_data->device.dig_y2, + client_data->device.dig_xy1, + client_data->device.dig_xy2); + + PDEBUG(" %s : trimming_reg z1: %d z2: %d z3: %d z4: %d xyz1: %d\n",__func__, + client_data->device.dig_z1, + client_data->device.dig_z2, + client_data->device.dig_z3, + client_data->device.dig_z4, + client_data->device.dig_xyz1); + + client_data->enable = 0; + /* now it's power on which is considered as resuming from suspend */ + client_data->op_mode = BMM_VAL_NAME(SUSPEND_MODE); + client_data->odr = BMM_DEFAULT_ODR; + client_data->rept_xy = BMM_DEFAULT_REPETITION_XY; + client_data->rept_z = BMM_DEFAULT_REPETITION_Z; + + +#if 0 + err = bmm_restore_hw_cfg(client); +#else + + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SUSPEND_MODE)); + if (err) { + PERR(" %s : fail to init h/w of %s",__func__, SENSOR_NAME); + err = -EIO; + goto exit_err_sysfs; + } +#endif + printk(KERN_ALERT"%s ... Removed SUSPEND_MODE \n",__func__); +#ifdef CONFIG_HAS_EARLYSUSPEND + client_data->early_suspend_handler.level = + EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + client_data->early_suspend_handler.suspend = bmm_early_suspend; + client_data->early_suspend_handler.resume = bmm_late_resume; + register_early_suspend(&client_data->early_suspend_handler); +#endif + + err = sensors_register(&bmm_device,client_data,bmm050_attr, "magnetic_sensor"); + if (err < 0 ) + { + pr_err("%s: could not register" "magnetic_sensor device(%d).\n", __func__, err); + goto exit_err_sysfs; + } + + PNOTICE(" %s : sensor %s probed successfully \n",__func__, SENSOR_NAME); + + PDEBUG(" %s : i2c_client: %p client_data: %p i2c_device: %p input: %p\n",__func__, + client, client_data, &client->dev, client_data->input); + + return 0; + +exit_err_sysfs: + if (err) + bmm_input_destroy(client_data); + +exit_err_clean: + if (err) { + if (client_data != NULL) { +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + if (NULL != client_data->bst_pd) { + kfree(client_data->bst_pd); + client_data->bst_pd = NULL; + } +#endif + kfree(client_data); + client_data = NULL; + } + + bmm_client = NULL; + } + + return err; +} + +static int bmm_pre_suspend(struct i2c_client *client) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)i2c_get_clientdata(client); + PDEBUG("function entrance"); + + mutex_lock(&client_data->mutex_enable); + if (client_data->enable) { + cancel_delayed_work_sync(&client_data->work); + PDEBUG("cancel work"); + } + mutex_unlock(&client_data->mutex_enable); + + return err; +} + +static int bmm_post_resume(struct i2c_client *client) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)i2c_get_clientdata(client); + + mutex_lock(&client_data->mutex_enable); + if (client_data->enable) { + schedule_delayed_work(&client_data->work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } + mutex_unlock(&client_data->mutex_enable); + + return err; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bmm_early_suspend(struct early_suspend *handler) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)container_of(handler, + struct bmm_client_data, early_suspend_handler); + struct i2c_client *client = client_data->client; + u8 power_mode; + PDEBUG("function entrance"); + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + if (power_mode) { + err = bmm_pre_suspend(client); + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SUSPEND_MODE)); + } + mutex_unlock(&client_data->mutex_power_mode); + +} + +static void bmm_late_resume(struct early_suspend *handler) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)container_of(handler, + struct bmm_client_data, early_suspend_handler); + struct i2c_client *client = client_data->client; + PDEBUG("function entrance"); + + mutex_lock(&client_data->mutex_power_mode); + + err = bmm_restore_hw_cfg(client); + /* post resume operation */ + bmm_post_resume(client); + + mutex_unlock(&client_data->mutex_power_mode); +} +#else +static int bmm_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)i2c_get_clientdata(client); + u8 power_mode; + + PDEBUG("function entrance"); + + mutex_lock(&client_data->mutex_power_mode); + BMM_CALL_API(get_powermode)(&power_mode); + if (power_mode) { + err = bmm_pre_suspend(client); + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SUSPEND_MODE)); + } + mutex_unlock(&client_data->mutex_power_mode); + + return err; +} + +static int bmm_resume(struct i2c_client *client) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)i2c_get_clientdata(client); + + PDEBUG("function entrance"); + + mutex_lock(&client_data->mutex_power_mode); + err = bmm_restore_hw_cfg(client); + /* post resume operation */ + bmm_post_resume(client); + + mutex_unlock(&client_data->mutex_power_mode); + + return err; +} +#endif + +static int bmm_remove(struct i2c_client *client) +{ + int err = 0; + struct bmm_client_data *client_data = + (struct bmm_client_data *)i2c_get_clientdata(client); + + if (NULL != client_data) { +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&client_data->early_suspend_handler); +#endif + + mutex_lock(&client_data->mutex_op_mode); + if (BMM_VAL_NAME(NORMAL_MODE) == client_data->op_mode) { + cancel_delayed_work_sync(&client_data->work); + PDEBUG("cancel work"); + } + mutex_unlock(&client_data->mutex_op_mode); + + err = bmm_set_op_mode(client_data, BMM_VAL_NAME(SUSPEND_MODE)); + mdelay(BMM_I2C_WRITE_DELAY_TIME); + + sensors_unregister(bmm_device, bmm050_attr); + + sysfs_remove_group(&client_data->input->dev.kobj, + &bmm_attribute_group); + bmm_input_destroy(client_data); + +#ifdef CONFIG_BMM_USE_PLATFORM_DATA + if (NULL != client_data->bst_pd) { + kfree(client_data->bst_pd); + client_data->bst_pd = NULL; + } +#endif + kfree(client_data); + + bmm_client = NULL; + } + + return err; +} + +static const struct i2c_device_id bmm_id[] = { + {SENSOR_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmm_id); + +static struct i2c_driver bmm_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = bmm_id, + .probe = bmm_probe, + .remove = bmm_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = bmm_suspend, + .resume = bmm_resume, +#endif +}; + +static int __init BMM_init(void) +{ + return i2c_add_driver(&bmm_driver); +} + +static void __exit BMM_exit(void) +{ + i2c_del_driver(&bmm_driver); +} + +MODULE_AUTHOR("Zhengguang.Guo <Zhengguang.Guo@bosch-sensortec.com>"); +MODULE_DESCRIPTION("driver for " SENSOR_NAME); +MODULE_LICENSE("GPL"); + +module_init(BMM_init); +module_exit(BMM_exit); diff --git a/drivers/sensor/bs_log.h b/drivers/sensor/bs_log.h new file mode 100644 index 00000000..ec3286aa --- /dev/null +++ b/drivers/sensor/bs_log.h @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * @date Apr 28th, 2011 + * @version v1.0 + * @brief Log API for Bosch MEMS Sensor drivers + */ + +#ifndef __BS_LOG_H +#define __BS_LOG_H + +#include <linux/kernel.h> + +#define LOG_LEVEL_E 3 +#define LOG_LEVEL_N 5 +#define LOG_LEVEL_I 6 +#define LOG_LEVEL_D 7 + +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_I +#endif + +#ifndef MODULE_TAG +#define MODULE_TAG "<>" +#endif + +#if (LOG_LEVEL >= LOG_LEVEL_E) +#define PERR(fmt, args...) printk(KERN_ERR\ + "\n" "[E]" KERN_ERR MODULE_TAG "<%s><%d>" fmt "\n",\ + __func__, __LINE__, ##args) +#else +#define PERR(fmt, args...) +#endif + +#if (LOG_LEVEL >= LOG_LEVEL_N) +#define PNOTICE(fmt, args...) printk(KERN_NOTICE\ + "\n" "[N]" KERN_NOTICE MODULE_TAG "<%s><%d>" fmt "\n",\ + __func__, __LINE__, ##args) +#else +#define PNOTICE(fmt, args...) +#endif + +#if (LOG_LEVEL >= LOG_LEVEL_I) +#define PINFO(fmt, args...) printk(KERN_INFO\ + "\n" "[I]" KERN_INFO MODULE_TAG "<%s><%d>" fmt "\n",\ + __func__, __LINE__, ##args) +#else +#define PINFO(fmt, args...) +#endif + +#if (LOG_LEVEL >= LOG_LEVEL_D) +#define PDEBUG(fmt, args...) printk(KERN_DEBUG\ + "\n" "[D]" KERN_DEBUG MODULE_TAG "<%s><%d>" fmt "\n",\ + __func__, __LINE__, ##args) +#else +#define PDEBUG(fmt, args...) +#endif + +#endif diff --git a/drivers/sensor/bst_sensor_common.c b/drivers/sensor/bst_sensor_common.c new file mode 100644 index 00000000..503b6239 --- /dev/null +++ b/drivers/sensor/bst_sensor_common.c @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2013 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * @date Sep 19th, 2012 + * @version v1.0 + * @brief Common APIs for Bosch MEMS sensor drivers + */ + +#include <linux/bst_sensor_common.h> + +#define MAX_AXIS_REMAP_TAB_SZ 8 /*P0~P7*/ +static const struct bosch_sensor_axis_remap +bst_axis_remap_tab_dft[MAX_AXIS_REMAP_TAB_SZ] = { + /* src_x src_y src_z sign_x sign_y sign_z */ + { 0, 1, 2, 1, 1, 1 }, /* P0 */ + { 1, 0, 2, 1, -1, 1 }, /* P1 */ + { 0, 1, 2, -1, -1, 1 }, /* P2 */ + { 1, 0, 2, -1, 1, 1 }, /* P3 */ + + { 0, 1, 2, -1, 1, -1 }, /* P4 */ + { 1, 0, 2, -1, -1, -1 }, /* P5 */ + { 0, 1, 2, 1, -1, -1 }, /* P6 */ + { 1, 0, 2, 1, 1, -1 }, /* P7 */ +}; + + +void bst_remap_sensor_data(struct bosch_sensor_data *data, + const struct bosch_sensor_axis_remap *remap) +{ + struct bosch_sensor_data tmp; + + tmp.x = data->v[remap->src_x] * remap->sign_x; + tmp.y = data->v[remap->src_y] * remap->sign_y; + tmp.z = data->v[remap->src_z] * remap->sign_z; + + memcpy(data, &tmp, sizeof(*data)); +} +EXPORT_SYMBOL(bst_remap_sensor_data); + + +void bst_remap_sensor_data_dft_tab(struct bosch_sensor_data *data, + int place) +{ + /* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ)) + return; + + bst_remap_sensor_data(data, &bst_axis_remap_tab_dft[place]); +} +EXPORT_SYMBOL(bst_remap_sensor_data_dft_tab); + + +MODULE_LICENSE("GPL"); diff --git a/drivers/sensor/gp2ap002a00f.c b/drivers/sensor/gp2ap002a00f.c new file mode 100644 index 00000000..397a3451 --- /dev/null +++ b/drivers/sensor/gp2ap002a00f.c @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2011 Sony Ericsson Mobile Communications Inc. + * + * Author: Courtney Cavin <courtney.cavin@sonyericsson.com> + * Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com> + * + * 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. + */ + +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/gp2ap002a00f.h> +#include <linux/sensors_core.h> + +static struct device *proximity_sensor_device = NULL; + +#define OFFSET_FILE_PATH "/efs/prox_cal" + + +#define PROX_NONDETECT 0x2F +#define PROX_DETECT 0x0C + +#define PROX_NONDETECT_MODE1 0x43 +#define PROX_DETECT_MODE1 0x28 + +#define PROX_NONDETECT_MODE2 0x48 +#define PROX_DETECT_MODE2 0x42 + +struct gp2a_data { + struct input_dev *input; + const struct gp2a_platform_data *pdata; + struct i2c_client *i2c_client; + int proximity_enabled; + int irq; + int value; + + char cal_mode; + +}; + +static int nondetect; +static int detect; + + +enum gp2a_addr { + GP2A_ADDR_PROX = 0x0, + GP2A_ADDR_GAIN = 0x1, + GP2A_ADDR_HYS = 0x2, + GP2A_ADDR_CYCLE = 0x3, + GP2A_ADDR_OPMOD = 0x4, + GP2A_ADDR_CON = 0x6 +}; + +enum gp2a_controls { + /* Software Shutdown control: 0 = shutdown, 1 = normal operation */ + GP2A_CTRL_SSD = 0x01 +}; + +static int gp2a_report(struct gp2a_data *dt) +{ + int vo = gpio_get_value(dt->pdata->vout_gpio); + + dt->value = vo; + + input_report_switch(dt->input, SW_FRONT_PROXIMITY, vo); + input_sync(dt->input); + + return 0; +} + +static irqreturn_t gp2a_irq(int irq, void *handle) +{ + struct gp2a_data *dt = handle; + + printk(KERN_EMERG"Proximity Interrupts ::%d\n",irq); + + gp2a_report(dt); + + return IRQ_HANDLED; +} + +static int gp2a_enable(struct gp2a_data *dt) +{ + return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD, + GP2A_CTRL_SSD); +} + +static int gp2a_disable(struct gp2a_data *dt) +{ + return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD, + 0x00); +} + + +/*Only One Read Only register, so word address need not be specified (from Data Sheet)*/ +static int gp2a_i2c_read(u8 reg, u8 *value,struct gp2a_data *gp2a_cal_data) +{ + int ret =0; + int count=0; + u8 buf[3]; + struct i2c_msg msg[1]; + + buf[0] = reg; + + /*first byte read(buf[0]) is dummy read*/ + msg[0].addr = gp2a_cal_data->i2c_client->addr; + msg[0].flags = I2C_M_RD; + msg[0].len = 2; + msg[0].buf = buf; + count = i2c_transfer(gp2a_cal_data->i2c_client->adapter, msg, 1); + + if(count < 0) + { + ret =-1; + } + else + { + *value = buf[0] << 8 | buf[1]; + } + + return ret; +} + +static int gp2a_i2c_write( u8 reg, u8 *value,struct gp2a_data *gp2a_cal_data) +{ + int ret =0; + int count=0; + struct i2c_msg msg[1]; + u8 data[2]; + + printk(KERN_INFO "[GP2A] %s : start \n", __func__); + + if( (gp2a_cal_data->i2c_client == NULL) || (!gp2a_cal_data->i2c_client->adapter) ){ + return -ENODEV; + } + + data[0] = reg; + data[1] = *value; + + msg[0].addr = gp2a_cal_data->i2c_client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = data; + count = i2c_transfer(gp2a_cal_data->i2c_client->adapter,msg,1); + + if(count < 0) + ret =-1; + + + printk(KERN_INFO "[GP2A] %s : stop \n", __func__); + + return ret; +} + +static ssize_t proximity_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gp2a_data *dt = dev_get_drvdata(dev); + + pr_info("%s, %d \n", __func__, __LINE__); + return snprintf(buf, PAGE_SIZE, "%d\n", dt->proximity_enabled); +} + +static ssize_t proximity_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gp2a_data *dt = dev_get_drvdata(dev); + + pr_info("%s, %d \n", __func__, __LINE__); + + return snprintf(buf, PAGE_SIZE, "%d\n", dt->value); +} + +static ssize_t proximity_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct gp2a_data *dt = dev_get_drvdata(dev); + + unsigned long value = 0; + int err = 0; + + err = strict_strtoul(buf, 10, &value); + if (err) + pr_err("%s, kstrtoint failed.", __func__); + + if (value != 0 && value != 1) + return count; + + printk(KERN_ALERT"%s :: Request for State(%d->%d)\n",__func__,dt->proximity_enabled,value); + + //check for multiple times disable and enable sensor + if (dt->proximity_enabled && !value) { /* Prox power off */ + + disable_irq(dt->irq); + + gp2a_disable(dt); + + if (dt->pdata->hw_pwr) + dt->pdata->hw_pwr(false); + + dt->proximity_enabled = 0; + } + if (!dt->proximity_enabled && value) { /* prox power on */ + + if (dt->pdata->hw_pwr) + dt->pdata->hw_pwr(true); + + msleep(20); + + gp2a_enable(dt); + + enable_irq(dt->irq); + dt->proximity_enabled = 1; + + gp2a_report(dt); + } + + return count; +} + +static int __init gp2a_initialize(struct gp2a_data *dt) +{ + int error; + + error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_GAIN, + 0x08); + if (error < 0) + return error; + + error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_HYS, + 0xc2); + if (error < 0) + return error; + + error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_CYCLE, + 0x04); + if (error < 0) + return error; + + error = gp2a_disable(dt); + + return error; +} + +static int gp2a_prox_offset(unsigned char vout,struct gp2a_data *gp2a_cal_data) +{ + u8 reg_value; + int ret=0; + + printk(KERN_INFO "[GP2A] %s called\n", __func__); + + /* Write HYS Register */ + if(!vout) + reg_value = nondetect; + else + reg_value = detect; + + if((ret=gp2a_i2c_write(GP2A_ADDR_HYS/*0x02*/,®_value,gp2a_cal_data))<0) + printk(KERN_INFO "[GP2A]gp2a_i2c_write 2 failed\n", __func__); + + return ret; +} + +static int gp2a_prox_cal_mode(char mode,struct gp2a_data *gp2a_cal_data) +{ + int ret=0; + u8 reg_value; + + printk(KERN_INFO "[GP2A] %s : start \n", __func__); + + if (mode == 1) + { + nondetect = PROX_NONDETECT_MODE1; + detect = PROX_DETECT_MODE1; + } + else if (mode == 2) + { + nondetect = PROX_NONDETECT_MODE2; + detect = PROX_DETECT_MODE2; + } + else + { + nondetect = PROX_NONDETECT; + detect = PROX_DETECT; + } + + + reg_value = 0x08; + if((ret=gp2a_i2c_write(GP2A_ADDR_GAIN/*0x01*/,®_value,gp2a_cal_data))<0) + printk(KERN_INFO "[GP2A]gp2a_i2c_write 1 failed\n", __func__); + + gp2a_prox_offset(0,gp2a_cal_data); + + reg_value = 0x04; + if((ret=gp2a_i2c_write(GP2A_ADDR_CYCLE/*0x03*/,®_value,gp2a_cal_data))<0) + printk(KERN_INFO "[GP2A]gp2a_i2c_write 2 failed\n", __func__); + + reg_value = 0x03; + if((ret=gp2a_i2c_write(GP2A_ADDR_OPMOD,®_value,gp2a_cal_data))<0) + printk(KERN_INFO "[GP2A]gp2a_i2c_write 3 failed\n", __func__); + + reg_value = 0x00; + if((ret=gp2a_i2c_write(GP2A_ADDR_CON,®_value,gp2a_cal_data))<0) + printk(KERN_INFO "[GP2A]gp2a_i2c_write 4 failed\n", __func__); + + printk(KERN_INFO "[GP2A] %s : stop \n", __func__); + + return ret; + +} + +static int gp2a_cal_mode_read_file(char *mode,struct gp2a_data *gp2a_cal_data) +{ + int err = 0; + mm_segment_t old_fs; + struct file *cal_mode_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_mode_filp = filp_open(OFFSET_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_mode_filp)) { + printk(KERN_INFO "[GP2A] %s: no cal_mode file\n", __func__); + err = PTR_ERR(cal_mode_filp); + if (err != -ENOENT) + pr_err("[GP2A] %s: Can't open cal_mode file\n", __func__); + set_fs(old_fs); + return err; + } + err = cal_mode_filp->f_op->read(cal_mode_filp, mode, sizeof(u8), &cal_mode_filp->f_pos); + + if (err != sizeof(u8)) { + pr_err("%s: Can't read the cal_mode from file\n", __func__); + filp_close(cal_mode_filp, current->files); + set_fs(old_fs); + return -EIO; + } + + filp_close(cal_mode_filp, current->files); + set_fs(old_fs); + + return err; +} + +static int gp2a_cal_mode_save_file(char mode,struct gp2a_data *gp2a_cal_data) +{ + struct file *cal_mode_filp = NULL; + int err = 0; + mm_segment_t old_fs; + + printk(KERN_INFO "[GP2A] %s : start \n", __func__); + + gp2a_prox_cal_mode(mode,gp2a_cal_data); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_mode_filp = filp_open(OFFSET_FILE_PATH, O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + if (IS_ERR(cal_mode_filp)) + { + pr_err("%s: Can't open cal_mode file\n", __func__); + set_fs(old_fs); + err = PTR_ERR(cal_mode_filp); + pr_err("%s: err = %d\n", __func__, err); + return err; + } + + err = cal_mode_filp->f_op->write(cal_mode_filp, (char *)&mode, sizeof(u8), &cal_mode_filp->f_pos); + if (err != sizeof(u8)) { + pr_err("%s: Can't read the cal_mode from file\n", __func__); + err = -EIO; + } + printk(KERN_INFO "[GP2A] %s : stop \n", __func__); + + filp_close(cal_mode_filp, current->files); + set_fs(old_fs); + + return err; +} +static ssize_t proximity_cal_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int result = 0; + + struct gp2a_data *gp2a_cal_data=dev_get_drvdata(dev); + + + result = gp2a_cal_data->cal_mode; + printk(KERN_INFO "[GP2A] prox_cal_read = %d\n", result); + + return sprintf(buf, "%d\n", result); +} + +static ssize_t proximity_cal_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct gp2a_data *gp2a_cal_data=dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) + gp2a_cal_data->cal_mode = 1; + else if (sysfs_streq(buf, "2")) + gp2a_cal_data->cal_mode = 2; + else if (sysfs_streq(buf, "0")) + gp2a_cal_data->cal_mode = 0; + else { + pr_err("[GP2A] %s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + printk(KERN_INFO "[GP2A] prox_cal_write =%d\n", gp2a_cal_data->cal_mode); + + gp2a_cal_mode_save_file(gp2a_cal_data->cal_mode,gp2a_cal_data); + + return size; +} + + +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, + proximity_enable_show, proximity_enable_store); + +static DEVICE_ATTR(value, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_value_show, NULL); + +static DEVICE_ATTR(prox_cal, S_IRUGO | S_IWUSR |S_IWGRP|S_IWOTH, proximity_cal_show, proximity_cal_store); + +static struct attribute *gp2a_attrs[] = { + &dev_attr_enable.attr, + NULL, +}; + +static struct attribute_group gp2a_attribute_group = { + .attrs = gp2a_attrs, +}; + +static struct device_attribute *proximity_sensor_attr[] = { + &dev_attr_value, + &dev_attr_enable, + + &dev_attr_prox_cal, + + NULL, + }; + +static int __init gp2a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct gp2a_platform_data *pdata = client->dev.platform_data; + struct gp2a_data *dt; + int error; + + if (!pdata) + return -EINVAL; + + if (pdata->hw_setup) { + error = pdata->hw_setup(client); + if (error < 0) + return error; + } + + error = gpio_request_one(pdata->vout_gpio, GPIOF_IN, GP2A_I2C_NAME); + if (error) + goto err_hw_shutdown; + + dt = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL); + if (!dt) { + error = -ENOMEM; + goto err_free_gpio; + } + + dt->pdata = pdata; + dt->i2c_client = client; + + error = gp2a_initialize(dt); + if (error < 0) + goto err_free_mem; + + dt->input = input_allocate_device(); + if (!dt->input) { + error = -ENOMEM; + goto err_free_mem; + } + + input_set_drvdata(dt->input, dt); + +// dt->input->open = gp2a_device_open; +// dt->input->close = gp2a_device_close; + dt->input->name = GP2A_I2C_NAME; + dt->input->id.bustype = BUS_I2C; + dt->input->dev.parent = &client->dev; + dt->proximity_enabled = 0; + dt->irq = client->irq; + dt->value = 0; + + input_set_capability(dt->input, EV_SW, SW_FRONT_PROXIMITY); + + error = request_threaded_irq(client->irq, NULL, gp2a_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT | IRQF_NO_SUSPEND , + GP2A_I2C_NAME, dt); + if (error) { + dev_err(&client->dev, "irq request failed\n"); + goto err_free_input_dev; + } + + error = input_register_device(dt->input); + if (error) { + dev_err(&client->dev, "device registration failed\n"); + goto err_free_irq; + } + + error = sysfs_create_group(&dt->input->dev.kobj, &gp2a_attribute_group); + if (error) { + dev_err(&client->dev, "sysfs create failed\n"); + goto err_unregister_input; + } + + device_init_wakeup(&client->dev, pdata->wakeup); + i2c_set_clientdata(client, dt); + dev_set_drvdata(&client->dev, dt); + + error = sensors_register(&proximity_sensor_device, dt,proximity_sensor_attr, "proximity_sensor"); + + if (error < 0) + { + pr_err("%s: could not register""proximity sensor device(%d).\n",__func__, error); + goto err_unregister_input; + } + disable_irq(client->irq); + + if (dt->pdata->hw_pwr) + { + dt->pdata->hw_pwr(false); + printk(KERN_ALERT"%s :: chip power down\n",__func__); + } + return 0; + +err_unregister_input: + input_unregister_device(dt->input); +err_free_irq: + free_irq(client->irq, dt); +err_free_input_dev: + input_free_device(dt->input); +err_free_mem: + kfree(dt); +err_free_gpio: + gpio_free(pdata->vout_gpio); +err_hw_shutdown: + if (pdata->hw_shutdown) + pdata->hw_shutdown(client); + if (pdata->hw_pwr) + pdata->hw_pwr(false); + return error; +} + +static int __exit gp2a_remove(struct i2c_client *client) +{ + struct gp2a_data *dt = i2c_get_clientdata(client); + const struct gp2a_platform_data *pdata = dt->pdata; + + device_init_wakeup(&client->dev, false); + + free_irq(client->irq, dt); + + sensors_unregister(proximity_sensor_device, proximity_sensor_attr); + input_unregister_device(dt->input); + kfree(dt); + + gpio_free(pdata->vout_gpio); + + if (pdata->hw_shutdown) + pdata->hw_shutdown(client); + + if (pdata->hw_pwr) + pdata->hw_pwr(false); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int gp2a_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gp2a_data *dt = i2c_get_clientdata(client); + int retval = 0; + printk(KERN_ALERT"%s\n",__func__); + if (device_may_wakeup(&client->dev)) { + enable_irq_wake(client->irq); + } else { + mutex_lock(&dt->input->mutex); + if (dt->input->users) + retval = gp2a_disable(dt); + mutex_unlock(&dt->input->mutex); + } + + return retval; +} + +static int gp2a_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gp2a_data *dt = i2c_get_clientdata(client); + int retval = 0; + printk(KERN_ALERT"%s\n",__func__); + if (device_may_wakeup(&client->dev)) { + disable_irq_wake(client->irq); + } else { + mutex_lock(&dt->input->mutex); + if (dt->input->users) + retval = gp2a_enable(dt); + mutex_unlock(&dt->input->mutex); + } + + return retval; +} +#endif + +static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume); + +static const struct i2c_device_id gp2a_i2c_id[] = { + { GP2A_I2C_NAME, 0 }, + { } +}; + +static struct i2c_driver gp2a_i2c_driver = { + .driver = { + .name = GP2A_I2C_NAME, + .owner = THIS_MODULE, + .pm = &gp2a_pm, + }, + .probe = gp2a_probe, + .remove = gp2a_remove, + .id_table = gp2a_i2c_id, +}; + +module_i2c_driver(gp2a_i2c_driver); + +MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>"); +MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/sensor/k2hh.c b/drivers/sensor/k2hh.c new file mode 100644 index 00000000..aa0831cc --- /dev/null +++ b/drivers/sensor/k2hh.c @@ -0,0 +1,1523 @@ +/* + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/errno.h> +#include <linux/input.h> +#include <linux/workqueue.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/of_gpio.h> +#include <linux/wakelock.h> +#include <linux/regulator/consumer.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/sensors_core.h> + + +#define I2C_M_WR 0 /* for i2c Write */ +#define I2c_M_RD 1 /* for i2c Read */ +#define READ_DATA_LENTH 6 + +#define VENDOR_NAME "STM" +#define MODEL_NAME "K2HH" +#define MODULE_NAME "accelerometer_sensor" + +#define CALIBRATION_FILE_PATH "/efs/accel_calibration_data" +#define CALIBRATION_DATA_AMOUNT 20 +#define MAX_ACCEL_1G 16384 + +#define K2HH_DEFAULT_DELAY 200000000LL + +#define CHIP_ID_RETRIES 3 +#define ACCEL_LOG_TIME 15 /* 15 sec */ + +#define K2HH_MODE_SUSPEND 0 +#define K2HH_MODE_NORMAL 1 + +#define SENSITIVITY_2G 61 +#define SENSITIVITY_4G 122 +#define SENSITIVITY_8G 244 + +#define K2HH_RANGE_2G 0 +#define K2HH_RANGE_4G 1 +#define K2HH_RANGE_8G 2 + +#define WHOAMI_REG 0x0F +#define AXISDATA_REG 0x28 + +#define CTRL1_REG 0x20 +#define CTRL2_REG 0x21 +#define CTRL3_REG 0x22 +#define CTRL4_REG 0x23 +#define CTRL5_REG 0x24 +#define CTRL6_REG 0x25 +#define CTRL7_REG 0x26 +#define STATUS_REG 0x27 + +/* CTRL1 */ +#define CTRL1_HR_DISABLE 0x00 +#define CTRL1_HR_ENABLE 0x80 +#define CTRL1_HR_MASK 0x80 +#define CTRL1_BDU_ENABLE 0x08 +#define CTRL1_BDU_MASK 0x08 + +/* CTRL2 */ +#define CTRL2_IG1_INT1 0x08 + +/* CTRL3 */ +#define CTRL3_IG1_INT1 0x08 + +/* CTRL7 */ +#define CTRL7_LIR2 0x08 +#define CTRL7_LIR1 0x04 + +#define ACC_PM_OFF 0x00 +#define ACC_ENABLE_ALL_AXES 0x07 + +#define INT_CFG1_REG 0x30 +#define INT_SRC1_REG 0x31 +#define K2HH_CHIP_ID 0x41 + +#define K2HH_ACC_FS_MASK 0x30 +#define K2HH_ACC_ODR_MASK 0x70 +#define K2HH_ACC_AXES_MASK 0x07 + +#define SELF_TEST_2G_MAX_LSB 24576 +#define SELF_TEST_2G_MIN_LSB 1146 + +#define K2HH_ACC_FS_2G 0x00 +#define K2HH_ACC_FS_4G 0x20 +#define K2HH_ACC_FS_8G 0x30 + +#define INT_THSX1_REG 0x32 +#define INT_THSY1_REG 0x33 +#define INT_THSZ1_REG 0x34 + +#define DYNAMIC_THRESHOLD 5000 + +enum { + OFF = 0, + ON = 1 +}; + +struct k2hh_v { + union { + s16 v[3]; + struct { + s16 x; + s16 y; + s16 z; + }; + }; +}; + +struct k2hh_p { + struct wake_lock reactive_wake_lock; + struct i2c_client *client; + struct input_dev *input; + struct delayed_work irq_work; + struct device *factory_device; + struct k2hh_v accdata; + struct k2hh_v caldata; + struct mutex mode_mutex; + struct hrtimer accel_timer; + struct workqueue_struct *accel_wq; + struct work_struct work; + struct regulator *vdd; + //struct regulator *vio; + ktime_t poll_delay; + atomic_t enable; + + int recog_flag; + int irq1; + int irq_state; + int acc_int1; + int sda_gpio; + int scl_gpio; + int time_count; + + u8 axis_map_x; + u8 axis_map_y; + u8 axis_map_z; + + u8 negate_x; + u8 negate_y; + u8 negate_z; +}; + +#define ACC_ODR10 0x10 /* 10Hz output data rate */ +#define ACC_ODR50 0x20 /* 50Hz output data rate */ +#define ACC_ODR100 0x30 /* 100Hz output data rate */ +#define ACC_ODR200 0x40 /* 200Hz output data rate */ +#define ACC_ODR400 0x50 /* 400Hz output data rate */ +#define ACC_ODR800 0x60 /* 800Hz output data rate */ +#define ACC_ODR_MASK 0X70 + +struct k2hh_acc_odr { + unsigned int cutoff_ms; + unsigned int mask; +}; + +#define OUTPUT_ALWAYS_ANTI_ALIASED + +const struct k2hh_acc_odr k2hh_acc_odr_table[] = { + { 2, ACC_ODR800}, + { 3, ACC_ODR400}, + { 5, ACC_ODR200}, + { 10, ACC_ODR100}, +#ifndef OUTPUT_ALWAYS_ANTI_ALIASED + { 20, ACC_ODR50}, + {100, ACC_ODR10}, +#endif +}; + +static int k2hh_open_calibration(struct k2hh_p *); +static int k2hh_regulator_onoff(struct k2hh_p *data, bool onoff); +#if 0 +static int k2hh_i2c_recovery(struct k2hh_p *data) +{ + int ret = 0; + struct gpiomux_setting old_config[2]; + struct gpiomux_setting recovery_config = { + .func = GPIOMUX_FUNC_3, + .drv = GPIOMUX_DRV_2MA, + .pull = GPIOMUX_PULL_NONE, + .dir = GPIOMUX_IN, + }; + + if (data->sda_gpio < 0 || data->scl_gpio < 0) { + pr_err("[SENSOR]: %s - no sda, scl gpio\n", __func__); + return -EINVAL; + } + + pr_err("[SENSOR] ################# %s #################\n", __func__); + + /*If LDO's are disabled then enable, Fallback LDO off scenario*/ + do { + if( 0 == regulator_is_enabled(data->vdd) ) { + ret = regulator_enable(data->vdd); + if (ret){ + pr_err(KERN_ERR "%s: vdd enable failed (%d)\n",__func__, ret); + break; + } + ret++; + } + if( 0 == regulator_is_enabled(data->vio) ) { + ret = regulator_enable(data->vio); + if (ret){ + pr_err(KERN_ERR "%s: vio enable failed (%d)\n",__func__, ret); + break; + } + ret++; + } + if(ret) + msleep(30); + }while(0); + + if(ret){ + pr_err("RECOVERY called as one of regulator was off:****\n Regulator \ + on/recovery complete****\n "); + } + + + ret = msm_gpiomux_write(data->sda_gpio, GPIOMUX_ACTIVE, + &recovery_config, &old_config[0]); + if (ret < 0) { + pr_err("[SENSOR]: %s sda_gpio have no active setting %d\n", + __func__, ret); + goto exit; + } + + ret = msm_gpiomux_write(data->scl_gpio, GPIOMUX_ACTIVE, + &recovery_config, &old_config[1]); + if (ret < 0) { + pr_err("[SENSOR]: %s scl_gpio have no active setting %d\n", + __func__, ret); + goto exit; + } + + ret = gpio_request(data->sda_gpio, "SENSOR_SDA"); + if (ret < 0) { + pr_err("[SENSOR]: %s - gpio %d request failed (%d)\n", + __func__, data->sda_gpio, ret); + goto exit; + } + + ret = gpio_request(data->scl_gpio, "SENSOR_SCL"); + if (ret < 0) { + pr_err("[SENSOR]: %s - gpio %d request failed (%d)\n", + __func__, data->scl_gpio, ret); + gpio_free(data->scl_gpio); + goto exit; + } + + ret = gpio_direction_input(data->sda_gpio); + if (ret < 0) { + pr_err("[SENSOR]: %s - failed to set gpio %d as output (%d)\n", + __func__, data->sda_gpio, ret); + goto exit_to_free; + } + + ret = gpio_direction_input(data->scl_gpio); + if (ret < 0) { + pr_err("[SENSOR]: %s - failed to set gpio %d as output (%d)\n", + __func__, data->scl_gpio, ret); + goto exit_to_free; + } + + /*Setting initial value after recovery*/ + udelay(100); + gpio_set_value_cansleep(data->sda_gpio, 0); + gpio_set_value_cansleep(data->scl_gpio, 0); + udelay(100); + gpio_set_value_cansleep(data->sda_gpio, 1); + gpio_set_value_cansleep(data->scl_gpio, 1); + + +exit_to_free: + gpio_free(data->sda_gpio); + gpio_free(data->scl_gpio); +exit: + msm_gpiomux_write(data->sda_gpio, GPIOMUX_ACTIVE, &old_config[0], NULL); + msm_gpiomux_write(data->scl_gpio, GPIOMUX_ACTIVE, &old_config[1], NULL); + + return ret; +} +#endif + +static int k2hh_i2c_read(struct k2hh_p *data, + unsigned char reg_addr, unsigned char *buf, unsigned int len) +{ + int ret, retries = 0; + struct i2c_msg msg[2]; + + msg[0].addr = data->client->addr; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = ®_addr; + + msg[1].addr = data->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = len; + msg[1].buf = buf; + + do { + ret = i2c_transfer(data->client->adapter, msg, 2); + if (ret >= 0) + break; + //else + // k2hh_i2c_recovery(data); + } while (retries++ < 2); + + if (ret < 0) { + pr_err("[SENSOR]: %s - i2c read error %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static int k2hh_i2c_write(struct k2hh_p *data, + unsigned char reg_addr, unsigned char buf) +{ + int ret, retries = 0; + struct i2c_msg msg; + unsigned char w_buf[2]; + + w_buf[0] = reg_addr; + w_buf[1] = buf; + + msg.addr = data->client->addr; + msg.flags = I2C_M_WR; + msg.len = 2; + msg.buf = (char *)w_buf; + + do { + ret = i2c_transfer(data->client->adapter, &msg, 1); + if (ret >= 0) + break; + //else + // k2hh_i2c_recovery(data); + } while (retries++ < 2); + + if (ret < 0) { + pr_err("[SENSOR]: %s - i2c write error %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static int k2hh_set_range(struct k2hh_p *data, unsigned char range) +{ + int ret = 0; + unsigned char temp, new_range, buf, mask; + + switch (range) { + case K2HH_RANGE_2G: + new_range = K2HH_ACC_FS_2G; + break; + case K2HH_RANGE_4G: + new_range = K2HH_ACC_FS_4G; + break; + case K2HH_RANGE_8G: + new_range = K2HH_ACC_FS_8G; + break; + default: + new_range = K2HH_ACC_FS_2G; + break; + } + + mask = K2HH_ACC_FS_MASK; + ret = k2hh_i2c_read(data, CTRL4_REG, &temp, 1); +#ifndef OUTPUT_ALWAYS_ANTI_ALIASED + buf = (mask & new_range) | ((~mask) & temp); +#else + buf = 0xCC; +#endif + ret += k2hh_i2c_write(data, CTRL4_REG, buf); + + return ret; +} + +static int k2hh_set_odr(struct k2hh_p *data) +{ + int ret = 0, i; + unsigned char buf, new_odr, mask, temp; + + /* 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(k2hh_acc_odr_table) - 1; i >= 0; i--) { + if ((k2hh_acc_odr_table[i].cutoff_ms <= \ + ktime_to_ms(data->poll_delay)) || (i == 0)) + break; + } + + if (data->recog_flag == ON) + i = ARRAY_SIZE(k2hh_acc_odr_table) - 1; + + new_odr = k2hh_acc_odr_table[i].mask; + + mask = K2HH_ACC_ODR_MASK; + ret = k2hh_i2c_read(data, CTRL1_REG, &temp, 1); + buf = ((mask & new_odr) | ((~mask) & temp)); + ret += k2hh_i2c_write(data, CTRL1_REG, buf); + + pr_info("[SENSOR]: %s - change odr %d\n", __func__, i); + return ret; +} + +static int k2hh_set_mode(struct k2hh_p *data, unsigned char mode) +{ + int ret = 0; + unsigned char buf, mask, temp; + + mutex_lock(&data->mode_mutex); + + switch (mode) { + case K2HH_MODE_NORMAL: + mask = K2HH_ACC_AXES_MASK; + ret = k2hh_i2c_read(data, CTRL1_REG, &temp, 1); + buf = ((mask & ACC_ENABLE_ALL_AXES) | ((~mask) & temp)); + ret += k2hh_i2c_write(data, CTRL1_REG, buf); + k2hh_set_odr(data); + pr_info("[SENSOR]: %s - normal mode\n", __func__); + break; + + case K2HH_MODE_SUSPEND: + if (data->recog_flag == ON) + break; + + mask = K2HH_ACC_AXES_MASK | K2HH_ACC_ODR_MASK; + ret = k2hh_i2c_read(data, CTRL1_REG, &temp, 1); + buf = ((mask & ACC_PM_OFF) | ((~mask) & temp)); + ret += k2hh_i2c_write(data, CTRL1_REG, buf); + pr_info("[SENSOR]: %s - suspend mode\n", __func__); + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&data->mode_mutex); + return ret; +} + +static int k2hh_read_accel_xyz(struct k2hh_p *data, struct k2hh_v *acc) +{ + int ret = 0; + struct k2hh_v rawdata; + unsigned char buf[READ_DATA_LENTH]; + + ret += k2hh_i2c_read(data, AXISDATA_REG, buf, READ_DATA_LENTH); + + if (ret < 0) + goto exit; + + rawdata.v[0] = ((s16) ((buf[1] << 8) | buf[0])); + rawdata.v[1] = ((s16) ((buf[3] << 8) | buf[2])); + rawdata.v[2] = ((s16) ((buf[5] << 8) | buf[4])); + + acc->v[0] = ((data->negate_x) ? (-rawdata.v[data->axis_map_x]) + : (rawdata.v[data->axis_map_x])); + acc->v[1] = ((data->negate_y) ? (-rawdata.v[data->axis_map_y]) + : (rawdata.v[data->axis_map_y])); + acc->v[2] = ((data->negate_z) ? (-rawdata.v[data->axis_map_z]) + : (rawdata.v[data->axis_map_z])); + +exit: + return ret; +} + +static enum hrtimer_restart k2hh_timer_func(struct hrtimer *timer) +{ + struct k2hh_p *data = container_of(timer, + struct k2hh_p, accel_timer); + + if (!work_pending(&data->work)) + queue_work(data->accel_wq, &data->work); + + hrtimer_forward_now(&data->accel_timer, data->poll_delay); + + return HRTIMER_RESTART; +} + +static void k2hh_work_func(struct work_struct *work) +{ + int ret; + struct k2hh_v acc; + struct k2hh_p *data = container_of(work, struct k2hh_p, work); + + ret = k2hh_read_accel_xyz(data, &acc); + if (ret < 0) + goto exit; + + data->accdata.x = acc.x - data->caldata.x; + data->accdata.y = acc.y - data->caldata.y; + data->accdata.z = acc.z - data->caldata.z; + + input_report_rel(data->input, REL_X, data->accdata.x); + input_report_rel(data->input, REL_Y, data->accdata.y); + input_report_rel(data->input, REL_Z, data->accdata.z); + input_sync(data->input); + +exit: + if ((ktime_to_ns(data->poll_delay) * (int64_t)data->time_count) + >= ((int64_t)ACCEL_LOG_TIME * NSEC_PER_SEC)) { + pr_info("[SENSOR]: %s - x = %d, y = %d, z = %d (ra:%d)\n", + __func__, data->accdata.x, data->accdata.y, + data->accdata.z, data->recog_flag); + data->time_count = 0; + } else + data->time_count++; +} + +static void k2hh_set_enable(struct k2hh_p *data, int enable) +{ + if (enable == ON) { + hrtimer_start(&data->accel_timer, data->poll_delay, + HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&data->accel_timer); + cancel_work_sync(&data->work); + } +} + +static ssize_t k2hh_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k2hh_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&data->enable)); +} + +static ssize_t k2hh_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 enable; + int ret, pre_enable; + struct k2hh_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &enable); + if (ret) { + pr_err("[SENSOR]: %s - Invalid Argument\n", __func__); + return ret; + } + + pr_info("[SENSOR]: %s - new_value = %u\n", __func__, enable); + pre_enable = atomic_read(&data->enable); + + if (enable) { + if (pre_enable == OFF) { + k2hh_regulator_onoff(data, true); + k2hh_open_calibration(data); + k2hh_set_range(data, K2HH_RANGE_2G); + + k2hh_set_mode(data, K2HH_MODE_NORMAL); + atomic_set(&data->enable, ON); + k2hh_set_enable(data, ON); + } + } else { + if (pre_enable == ON) { + atomic_set(&data->enable, OFF); + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + k2hh_set_enable(data, OFF); + k2hh_regulator_onoff(data, false); + } + } + + return size; +} + +static ssize_t k2hh_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k2hh_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%lld\n", + ktime_to_ns(data->poll_delay)); +} + +static ssize_t k2hh_delay_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int64_t delay; + struct k2hh_p *data = dev_get_drvdata(dev); + + ret = kstrtoll(buf, 10, &delay); + if (ret) { + pr_err("[SENSOR]: %s - Invalid Argument\n", __func__); + return ret; + } + + data->poll_delay = ns_to_ktime(delay); + k2hh_set_odr(data); + + if (atomic_read(&data->enable) == ON) { + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + k2hh_set_mode(data, K2HH_MODE_NORMAL); + } + + pr_info("[SENSOR]: %s - poll_delay = %lld\n", __func__, delay); + return size; +} + +static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + k2hh_delay_show, k2hh_delay_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + k2hh_enable_show, k2hh_enable_store); + +static struct attribute *k2hh_attributes[] = { + &dev_attr_poll_delay.attr, + &dev_attr_enable.attr, + NULL +}; + +static struct attribute_group k2hh_attribute_group = { + .attrs = k2hh_attributes +}; + + +static ssize_t k2hh_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR_NAME); +} + +static ssize_t k2hh_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", MODEL_NAME); +} + +static int k2hh_open_calibration(struct k2hh_p *data) +{ + int ret = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + ret = PTR_ERR(cal_filp); + + data->caldata.x = 0; + data->caldata.y = 0; + data->caldata.z = 0; + + pr_info("[SENSOR]: %s - No Calibration\n", __func__); + + return ret; + } + + ret = cal_filp->f_op->read(cal_filp, (char *)&data->caldata.v, + 3 * sizeof(s16), &cal_filp->f_pos); + if (ret != 3 * sizeof(s16)) { + pr_err("[SENSOR] %s: - Can't read the cal data\n", __func__); + ret = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + pr_info("[SENSOR]: open accel calibration %d, %d, %d\n", + data->caldata.x, data->caldata.y, data->caldata.z); + + if ((data->caldata.x == 0) && (data->caldata.y == 0) + && (data->caldata.z == 0)) + return -EIO; + + return ret; +} + +static int k2hh_do_calibrate(struct k2hh_p *data, int enable) +{ + int sum[3] = { 0, }; + int ret = 0, cnt; + struct file *cal_filp = NULL; + struct k2hh_v acc; + mm_segment_t old_fs; + + if (enable) { + data->caldata.x = 0; + data->caldata.y = 0; + data->caldata.z = 0; + + if (atomic_read(&data->enable) == ON) + k2hh_set_enable(data, OFF); + else + k2hh_set_mode(data, K2HH_MODE_NORMAL); + + msleep(300); + + for (cnt = 0; cnt < CALIBRATION_DATA_AMOUNT; cnt++) { + k2hh_read_accel_xyz(data, &acc); + sum[0] += acc.x; + sum[1] += acc.y; + sum[2] += acc.z; + mdelay(10); + } + + if (atomic_read(&data->enable) == ON) + k2hh_set_enable(data, ON); + else + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + + data->caldata.x = (sum[0] / CALIBRATION_DATA_AMOUNT); + data->caldata.y = (sum[1] / CALIBRATION_DATA_AMOUNT); + data->caldata.z = (sum[2] / CALIBRATION_DATA_AMOUNT); + + if (data->caldata.z > 0) + data->caldata.z -= MAX_ACCEL_1G; + else if (data->caldata.z < 0) + data->caldata.z += MAX_ACCEL_1G; + } else { + data->caldata.x = 0; + data->caldata.y = 0; + data->caldata.z = 0; + } + + pr_info("[SENSOR]: %s - do accel calibrate %d, %d, %d\n", __func__, + data->caldata.x, data->caldata.y, data->caldata.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SENSOR]: %s - Can't open calibration file\n", + __func__); + set_fs(old_fs); + ret = PTR_ERR(cal_filp); + return ret; + } + + ret = cal_filp->f_op->write(cal_filp, (char *)&data->caldata.v, + 3 * sizeof(s16), &cal_filp->f_pos); + if (ret != 3 * sizeof(s16)) { + pr_err("[SENSOR]: %s - Can't write the caldata to file\n", + __func__); + ret = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return ret; +} + +static ssize_t k2hh_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct k2hh_p *data = dev_get_drvdata(dev); + + ret = k2hh_open_calibration(data); + if (ret < 0) + pr_err("[SENSOR]: %s - calibration open failed(%d)\n", + __func__, ret); + + pr_info("[SENSOR]: %s - cal data %d %d %d - ret : %d\n", __func__, + data->caldata.x, data->caldata.y, data->caldata.z, ret); + + return snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", ret, data->caldata.x, + data->caldata.y, data->caldata.z); +} + +static ssize_t k2hh_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + int64_t dEnable; + struct k2hh_p *data = dev_get_drvdata(dev); + + ret = kstrtoll(buf, 10, &dEnable); + if (ret < 0) + return ret; + + ret = k2hh_do_calibrate(data, (int)dEnable); + if (ret < 0) + pr_err("[SENSOR]: %s - accel calibrate failed\n", __func__); + + return size; +} + +static ssize_t k2hh_raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k2hh_v acc; + struct k2hh_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == OFF) { + k2hh_set_mode(data, K2HH_MODE_NORMAL); + msleep(20); + k2hh_read_accel_xyz(data, &acc); + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + + acc.x = acc.x - data->caldata.x; + acc.y = acc.y - data->caldata.y; + acc.z = acc.z - data->caldata.z; + } else { + acc = data->accdata; + } + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + acc.x, acc.y, acc.z); +} + +static ssize_t k2hh_reactive_alert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned char threshx, threshy, threshz; + int enable = OFF, factory_mode = OFF; + struct k2hh_v acc; + struct k2hh_p *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "0")) { + enable = OFF; + factory_mode = OFF; + pr_info("[SENSOR]: %s - disable\n", __func__); + } else if (sysfs_streq(buf, "1")) { + enable = ON; + factory_mode = OFF; + pr_info("[SENSOR]: %s - enable\n", __func__); + } else if (sysfs_streq(buf, "2")) { + enable = ON; + factory_mode = ON; + pr_info("[SENSOR]: %s - factory mode\n", __func__); + } else { + pr_err("[SENSOR]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + if ((enable == ON) && (data->recog_flag == OFF)) { + data->irq_state = 0; + data->recog_flag = ON; + + if (factory_mode == ON) { + k2hh_i2c_write(data, INT_THSX1_REG, 0x00); + k2hh_i2c_write(data, INT_THSY1_REG, 0x00); + k2hh_i2c_write(data, INT_THSZ1_REG, 0x00); + k2hh_i2c_write(data, INT_CFG1_REG, 0x3f); + } else { + k2hh_set_odr(data); + if (atomic_read(&data->enable) == OFF) { + k2hh_set_mode(data, K2HH_MODE_NORMAL); + msleep(20); + k2hh_read_accel_xyz(data, &acc); + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + } else { + acc.x = data->accdata.x; + acc.y = data->accdata.y; + acc.z = data->accdata.z; + } + + threshx = (abs(acc.v[data->axis_map_x]) \ + + DYNAMIC_THRESHOLD) >> 8; + threshy = (abs(acc.v[data->axis_map_y]) \ + + DYNAMIC_THRESHOLD) >> 8; + threshz = (abs(acc.v[data->axis_map_z]) \ + + DYNAMIC_THRESHOLD) >> 8; + + k2hh_i2c_write(data, INT_THSX1_REG, threshx); + k2hh_i2c_write(data, INT_THSY1_REG, threshy); + k2hh_i2c_write(data, INT_THSZ1_REG, threshz); + k2hh_i2c_write(data, INT_CFG1_REG, 0x0a); + } + + k2hh_i2c_write(data, CTRL7_REG, CTRL7_LIR1); + k2hh_i2c_write(data, CTRL3_REG, CTRL3_IG1_INT1); + + enable_irq(data->irq1); + enable_irq_wake(data->irq1); + + pr_info("[SENSOR]: %s - reactive alert is on!\n", __func__); + } else if ((enable == OFF) && (data->recog_flag == ON)) { + k2hh_i2c_write(data, CTRL3_REG, 0x00); + + disable_irq_wake(data->irq1); + disable_irq_nosync(data->irq1); + data->recog_flag = OFF; + pr_info("[SENSOR]: %s - reactive alert is off! irq = %d\n", + __func__, data->irq_state); + } + + return size; +} + +static ssize_t k2hh_reactive_alert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k2hh_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->irq_state); +} + +static ssize_t k2hh_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k2hh_p *data = dev_get_drvdata(dev); + struct k2hh_v acc; + unsigned char temp; + int result = 1, i; + ssize_t ret; + s32 NO_ST[3] = {0, 0, 0}; + s32 ST[3] = {0, 0, 0}; + + if (atomic_read(&data->enable) == OFF) + k2hh_set_mode(data, K2HH_MODE_NORMAL); + else + k2hh_set_enable(data, OFF); + + k2hh_i2c_write(data, CTRL1_REG, 0x3f); + k2hh_i2c_write(data, CTRL4_REG, 0x04); + k2hh_i2c_write(data, CTRL5_REG, 0x00); + k2hh_i2c_write(data, CTRL6_REG, 0x00); + + mdelay(80); + + k2hh_read_accel_xyz(data, &acc); + + for (i = 0; i < 5; i++) { + while (1) { + if (k2hh_i2c_read(data, STATUS_REG, &temp, 1) < 0) { + pr_err("[SENSOR] %s: i2c error", __func__); + goto exit_status_err; + } + + if (temp & 0x08) + break; + } + + k2hh_read_accel_xyz(data, &acc); + NO_ST[0] += acc.x; + NO_ST[1] += acc.y; + NO_ST[2] += acc.z; + } + NO_ST[0] /= 5; + NO_ST[1] /= 5; + NO_ST[2] /= 5; + + k2hh_i2c_write(data, CTRL5_REG, 0x04); + + mdelay(80); + + k2hh_read_accel_xyz(data, &acc); + + for (i = 0; i < 5; i++) { + while (1) { + if (k2hh_i2c_read(data, STATUS_REG, &temp, 1) < 0) { + pr_err("[SENSOR] %s: i2c error", __func__); + goto exit_status_err; + } + + if (temp & 0x08) + break; + } + + k2hh_read_accel_xyz(data, &acc); + ST[0] += acc.x; + ST[1] += acc.y; + ST[2] += acc.z; + } + + ST[0] /= 5; + ST[1] /= 5; + ST[2] /= 5; + + for (i = 0; i < 3; i++) { + ST[i] -= NO_ST[i]; + ST[i] = abs(ST[i]); + + if ((SELF_TEST_2G_MIN_LSB > ST[i]) \ + || (ST[i] > SELF_TEST_2G_MAX_LSB)) { + pr_info("[SENSOR] %s: %d Out of range!! (%d)\n", + __func__, i, ST[i]); + result = 0; + } + } + + if (result) + ret = sprintf(buf, "1,%d,%d,%d\n", ST[0], ST[1], ST[2]); + else + ret = sprintf(buf, "0,%d,%d,%d\n", ST[0], ST[1], ST[2]); + + goto exit; + +exit_status_err: + ret = sprintf(buf, "-1,0,0,0\n"); +exit: + k2hh_i2c_write(data, CTRL1_REG, 0x00); + k2hh_i2c_write(data, CTRL5_REG, 0x00); + + if (atomic_read(&data->enable) == OFF) { + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + } else { + k2hh_set_mode(data, K2HH_MODE_NORMAL); + k2hh_set_enable(data, ON); + } + + return ret; +} + +static DEVICE_ATTR(selftest, S_IRUGO, k2hh_selftest_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, k2hh_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, k2hh_vendor_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + k2hh_calibration_show, k2hh_calibration_store); +static DEVICE_ATTR(raw_data, S_IRUGO, k2hh_raw_data_read, NULL); +static DEVICE_ATTR(reactive_alert, S_IRUGO | S_IWUSR | S_IWGRP, + k2hh_reactive_alert_show, k2hh_reactive_alert_store); + +static struct device_attribute *sensor_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_calibration, + &dev_attr_raw_data, + &dev_attr_reactive_alert, + &dev_attr_selftest, + NULL, +}; + +static void k2hh_irq_work_func(struct work_struct *work) +{ + struct k2hh_p *data = container_of((struct delayed_work *)work, + struct k2hh_p, irq_work); + unsigned char buf; + + k2hh_i2c_write(data, INT_CFG1_REG, 0x00); + k2hh_i2c_read(data, INT_SRC1_REG, &buf, 1); +} + +static irqreturn_t k2hh_irq_thread(int irq, void *k2hh_data_p) +{ + struct k2hh_p *data = k2hh_data_p; + + data->irq_state = 1; + wake_lock_timeout(&data->reactive_wake_lock, + msecs_to_jiffies(2000)); + schedule_delayed_work(&data->irq_work, msecs_to_jiffies(100)); + pr_info("###### [SENSOR]: %s reactive irq ######\n", __func__); + + return IRQ_HANDLED; +} + +static int k2hh_setup_pin(struct k2hh_p *data) +{ + int ret; + + ret = gpio_request(data->acc_int1, "ACC_INT1"); + if (ret < 0) { + pr_err("[SENSOR] %s - gpio %d request failed (%d)\n", + __func__, data->acc_int1, ret); + goto exit; + } + + ret = gpio_direction_input(data->acc_int1); + if (ret < 0) { + pr_err("[SENSOR]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->acc_int1, ret); + goto exit_acc_int1; + } + + wake_lock_init(&data->reactive_wake_lock, WAKE_LOCK_SUSPEND, + "reactive_wake_lock"); + + data->irq1 = gpio_to_irq(data->acc_int1); + ret = request_threaded_irq(data->irq1, NULL, k2hh_irq_thread, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "k2hh_accel", data); + if (ret < 0) { + pr_err("[SENSOR]: %s - can't allocate irq.\n", __func__); + goto exit_reactive_irq; + } + + disable_irq(data->irq1); + goto exit; + +exit_reactive_irq: + wake_lock_destroy(&data->reactive_wake_lock); +exit_acc_int1: + gpio_free(data->acc_int1); +exit: + return ret; +} + +static int k2hh_input_init(struct k2hh_p *data) +{ + int ret = 0; + struct input_dev *dev; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->name = MODULE_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_REL, REL_X); + input_set_capability(dev, EV_REL, REL_Y); + input_set_capability(dev, EV_REL, REL_Z); + input_set_drvdata(dev, data); + + ret = input_register_device(dev); + if (ret < 0) { + input_free_device(dev); + return ret; + } + /* sysfs node creation */ + ret = sysfs_create_group(&dev->dev.kobj, &k2hh_attribute_group); + if (ret < 0) { + input_unregister_device(dev); + return ret; + } + + data->input = dev; + return 0; +} + +static int k2hh_parse_dt(struct k2hh_p *data, struct device *dev) +{ + struct device_node *dNode = dev->of_node; + enum of_gpio_flags flags; + int ret; + u32 temp; + + if (dNode == NULL) + return -ENODEV; + + data->acc_int1 = of_get_named_gpio_flags(dNode, + "stm,irq_gpio", 0, &flags); + if (data->acc_int1 < 0) { + pr_err("[SENSOR]: %s - get acc_int1 error\n", __func__); + return -ENODEV; + } + + data->sda_gpio = of_get_named_gpio_flags(dNode, + "stm,sda", 0, &flags); + if (data->sda_gpio < 0) + pr_info("[SENSOR]: %s - no sda_gpio\n", __func__); + + data->scl_gpio = of_get_named_gpio_flags(dNode, + "stm,scl", 0, &flags); + if (data->scl_gpio < 0) + pr_info("[SENSOR]: %s - no scl_gpio\n", __func__); + + ret = of_property_read_u32(dNode,"stm,axis_map_x", &temp); + if ((data->axis_map_x > 2) || (ret < 0)) { + pr_err("%s: invalid x axis_map value %u\n", + __func__, data->axis_map_x); + data->axis_map_x = 0; + } else { + data->axis_map_x= (u8)temp; + } + + ret = of_property_read_u32(dNode,"stm,axis_map_y", &temp); + if ((data->axis_map_y > 2) || (ret < 0)) { + pr_err("%s: invalid y axis_map value %u\n", + __func__, data->axis_map_y); + data->axis_map_y = 1; + } else { + data->axis_map_y= (u8)temp; + } + + ret = of_property_read_u32(dNode,"stm,axis_map_z", &temp); + if ((data->axis_map_z > 2) || (ret < 0)) { + pr_err("%s: invalid z axis_map value %u\n", + __func__, data->axis_map_z); + data->axis_map_z = 2; + } else { + data->axis_map_z= (u8)temp; + } + + ret = of_property_read_u32(dNode,"stm,negate_x", &temp); + if ((data->negate_x > 1) || (ret < 0)) { + pr_err("%s: invalid x axis_map value %u\n", + __func__, data->negate_x); + data->negate_x = 0; + } else { + data->negate_x= (u8)temp; + } + + ret = of_property_read_u32(dNode,"stm,negate_y", &temp); + if ((data->negate_y > 1) || (ret < 0)) { + pr_err("%s: invalid y axis_map value %u\n", + __func__, data->negate_y); + data->negate_y = 0; + } else { + data->negate_y= (u8)temp; + } + + ret = of_property_read_u32(dNode,"stm,negate_z", &temp); + if ((data->negate_z > 1) || (ret < 0)) { + pr_err("%s: invalid z axis_map value %u\n", + __func__, data->negate_z); + data->negate_z = 0; + } else { + data->negate_z= (u8)temp; + } + + return 0; +} + +static int k2hh_regulator_onoff(struct k2hh_p *data, bool onoff) +{ +#if 0 + int ret = -1; + + if (!data->vdd) { + data->vdd = regulator_get(&data->client->dev, "stm,reg_vdd"); + if (!data->vdd) { + pr_err("%s: regulator pointer null vdd, rc=%d\n", + __func__, ret); + return ret; + } + ret = regulator_set_voltage(data->vdd, 3000000, 3000000); + if (ret) { + pr_err("%s: set voltage failed on vdd, rc=%d\n", + __func__, ret); + return ret; + } + } + /*if (!data->vio) { + data->vio = regulator_get(&data->client->dev, "stm,reg_vio"); + if(!data->vio){ + pr_err("%s: regulator_get for vio failed\n", + __func__); + return 0; + } + }*/ + if(onoff){ + ret = regulator_enable(data->vdd); + if (ret) { + pr_err("%s: Failed to enable regulator vdd.\n", + __func__); + return ret; + } + /*ret = regulator_enable(data->vio); + if (ret) { + pr_err("%s: Failed to enable regulator vio.\n", + __func__); + return ret; + } + msleep(30);*/ + } + else { + ret = regulator_disable(data->vdd); + if (ret) { + pr_err("%s: Failed to disable regulator vdd.\n", + __func__); + return ret; + } + /*ret = regulator_disable(data->vio); + if (ret) { + pr_err("%s: Failed to disable regulator vio.\n", + __func__); + return ret; + }*/ + } +#endif + return 0; +} + + +static int k2hh_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + u8 temp; + int ret = -ENODEV, i; + struct k2hh_p *data = NULL; + + pr_err("[SENSOR]: %s - Probe Start!\n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("[SENSOR]: %s - i2c_check_functionality error\n", + __func__); + goto exit; + } + + data = kzalloc(sizeof(struct k2hh_p), GFP_KERNEL); + if (data == NULL) { + pr_err("[SENSOR]: %s - kzalloc error\n", __func__); + ret = -ENOMEM; + goto exit_kzalloc; + } + + i2c_set_clientdata(client, data); + data->client = client; + + ret = k2hh_parse_dt(data, &client->dev); + if (ret < 0) { + pr_err("[SENSOR]: %s - of_node error\n", __func__); + ret = -ENODEV; + goto exit_of_node; + } + + ret = k2hh_regulator_onoff(data, true); + if (ret < 0) + pr_err("[SENSOR]: %s - No regulator\n", __func__); + + ret = k2hh_setup_pin(data); + if (ret < 0) { + pr_err("[SENSOR]: %s - could not setup pin\n", __func__); + goto exit_setup_pin; + } + + mutex_init(&data->mode_mutex); + + /* read chip id */ + k2hh_set_mode(data, K2HH_MODE_NORMAL); + for (i = 0; i < CHIP_ID_RETRIES; i++) { + ret = k2hh_i2c_read(data, WHOAMI_REG, &temp, 1); + if (temp != K2HH_CHIP_ID) { + pr_err("[SENSOR]: %s - chip id failed 0x%x : %d\n", + __func__, temp, ret); + } else { + pr_info("[SENSOR]: %s - chip id success 0x%x\n", + __func__, temp); + break; + } + msleep(20); + } + + if (i >= CHIP_ID_RETRIES) { + ret = -ENODEV; + goto exit_read_chipid; + } + + /* input device init */ + ret = k2hh_input_init(data); + if (ret < 0) + goto exit_input_init; + + sensors_register(data->factory_device, data, sensor_attrs, MODULE_NAME); + + /* accel_timer settings. we poll for light values using a timer. */ + hrtimer_init(&data->accel_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->poll_delay = ns_to_ktime(K2HH_DEFAULT_DELAY); + data->accel_timer.function = k2hh_timer_func; + + /* the timer just fires off a work queue request. we need a thread + to read the i2c (can be slow and blocking). */ + data->accel_wq = create_singlethread_workqueue("accel_wq"); + if (!data->accel_wq) { + ret = -ENOMEM; + pr_err("[SENSOR]: %s - could not create workqueue\n", __func__); + goto exit_create_workqueue; + } + + /* this is the thread function we run on the work queue */ + INIT_WORK(&data->work, k2hh_work_func); + INIT_DELAYED_WORK(&data->irq_work, k2hh_irq_work_func); + + atomic_set(&data->enable, OFF); + data->time_count = 0; + data->irq_state = 0; + data->recog_flag = OFF; + + k2hh_set_range(data, K2HH_RANGE_2G); + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + + /*power off the regulators, for next enable power will be on*/ + ret = k2hh_regulator_onoff(data, false); + + pr_err("[SENSOR]: %s - Probe done!\n", __func__); + + return 0; + +exit_create_workqueue: + sensors_unregister(data->factory_device, sensor_attrs); + sysfs_remove_group(&data->input->dev.kobj, &k2hh_attribute_group); + input_unregister_device(data->input); +exit_input_init: +exit_read_chipid: + mutex_destroy(&data->mode_mutex); + free_irq(data->irq1, data); + wake_lock_destroy(&data->reactive_wake_lock); + gpio_free(data->acc_int1); +exit_setup_pin: +exit_of_node: + kfree(data); +exit_kzalloc: +exit: + pr_err("[SENSOR]: %s - Probe fail!\n", __func__); + return ret; +} + +static void k2hh_shutdown(struct i2c_client *client) +{ + struct k2hh_p *data = (struct k2hh_p *)i2c_get_clientdata(client); + + pr_info("[SENSOR]: %s\n", __func__); + + if (atomic_read(&data->enable) == ON) + k2hh_set_enable(data, OFF); + + atomic_set(&data->enable, OFF); + k2hh_set_mode(data, K2HH_MODE_SUSPEND); +} + +/* +static int k2hh_remove(struct i2c_client *client) +{ + struct k2hh_p *data = (struct k2hh_p *)i2c_get_clientdata(client); + + if (atomic_read(&data->enable) == ON) + k2hh_set_enable(data, OFF); + + atomic_set(&data->enable, OFF); + cancel_delayed_work_sync(&data->irq_work); + + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + sensors_unregister(data->factory_device, sensor_attrs); + + sysfs_remove_group(&data->input->dev.kobj, &k2hh_attribute_group); + input_unregister_device(data->input); + + free_irq(data->irq1, data); + wake_lock_destroy(&data->reactive_wake_lock); + mutex_destroy(&data->mode_mutex); + gpio_free(data->acc_int1); + kfree(data); + + return 0; +} +*/ + +static int k2hh_suspend(struct device *dev) +{ + struct k2hh_p *data = dev_get_drvdata(dev); + + pr_info("[SENSOR]: %s\n", __func__); + + if (atomic_read(&data->enable) == ON) { + k2hh_set_mode(data, K2HH_MODE_SUSPEND); + k2hh_set_enable(data, OFF); + } + + return 0; +} + +static int k2hh_resume(struct device *dev) +{ + struct k2hh_p *data = dev_get_drvdata(dev); + + pr_info("[SENSOR]: %s\n", __func__); + + if (atomic_read(&data->enable) == ON) { + k2hh_set_mode(data, K2HH_MODE_NORMAL); + k2hh_set_enable(data, ON); + } + + return 0; +} + +static struct of_device_id k2hh_match_table[] = { + { .compatible = "stm,k2hh",}, + {}, +}; + +static const struct i2c_device_id k2hh_id[] = { + { "k2hh_match_table", 0 }, + { } +}; + +static const struct dev_pm_ops k2hh_pm_ops = { + .suspend = k2hh_suspend, + .resume = k2hh_resume +}; + +static struct i2c_driver k2hh_driver = { + .driver = { + .name = MODEL_NAME, + .owner = THIS_MODULE, + .of_match_table = k2hh_match_table, + .pm = &k2hh_pm_ops + }, + .probe = k2hh_probe, + .shutdown = k2hh_shutdown, +/* .remove = k2hh_remove, */ + .id_table = k2hh_id, +}; + +static int __init k2hh_init(void) +{ + return i2c_add_driver(&k2hh_driver); +} + +static void __exit k2hh_exit(void) +{ + i2c_del_driver(&k2hh_driver); +} + +module_init(k2hh_init); +module_exit(k2hh_exit); + +MODULE_DESCRIPTION("k2hh accelerometer sensor driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/sensor/sensors_core.c b/drivers/sensor/sensors_core.c new file mode 100644 index 00000000..5a192f95 --- /dev/null +++ b/drivers/sensor/sensors_core.c @@ -0,0 +1,110 @@ +/* /driver/sensors/core/sensors_core.c + * Copyright (C) 2011 Samsung Electronics. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/err.h> + + +struct class *sensors_class; +EXPORT_SYMBOL_GPL(sensors_class); + + +/** + * Create sysfs interface + */ +static void set_sensor_attr(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0 ; attributes[i] != NULL ; i++) { + if ((device_create_file(dev, attributes[i])) < 0) + pr_err("Create_dev_file fail(attributes[%d] )\n", i); + } +} + +int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name) +{ + int ret = 0; + + if (!sensors_class) { + sensors_class = class_create(THIS_MODULE, "sensors"); + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + } + + + dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); + + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + pr_err("[SENSORS CORE] device_create failed! [%d]\n", ret); + return ret; + } + + set_sensor_attr(dev, attributes); + + + return 0; +} +EXPORT_SYMBOL_GPL(sensors_register); + +void sensors_unregister(struct device *dev,struct device_attribute *attributes[]) +{ + int i; + + if (sensors_class != NULL) { + for (i = 0 ; attributes[i] != NULL ; i++) + device_remove_file(dev, attributes[i]); + } +} +EXPORT_SYMBOL_GPL(sensors_unregister); + +static int __init sensors_class_init(void) +{ + pr_debug("[SENSORS CORE] sensors_class_init\n"); + sensors_class = class_create(THIS_MODULE, "sensors"); + + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + + sensors_class->dev_uevent = NULL; + + return 0; +} + +static void __exit sensors_class_exit(void) +{ + class_destroy(sensors_class); +} + + +/* exported for the APM Power driver, APM emulation */ + +subsys_initcall(sensors_class_init); +module_exit(sensors_class_exit); + +MODULE_DESCRIPTION("Universal sensors core class"); +MODULE_AUTHOR("Ryunkyun Park <ryun.park@samsung.com>"); +MODULE_LICENSE("GPL"); + |
