diff options
-rw-r--r-- | drivers/misc/Makefile | 2 | ||||
-rw-r--r-- | drivers/misc/mpu3050/Kconfig | 192 | ||||
-rw-r--r-- | drivers/misc/mpu3050/Makefile | 245 | ||||
-rw-r--r-- | drivers/misc/mpu3050/accel/kxtf9.c | 588 | ||||
-rw-r--r-- | drivers/misc/mpu3050/compass/ak8975.c | 95 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mldl_cfg.c | 1051 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mldl_cfg.h | 79 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mltypes.h | 22 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mpu-dev.c | 705 | ||||
-rw-r--r-- | drivers/misc/mpu3050/mpuirq.c | 27 | ||||
-rw-r--r-- | drivers/misc/mpu3050/slaveirq.c | 26 | ||||
-rw-r--r-- | drivers/misc/mpu3050/timerirq.c | 295 | ||||
-rw-r--r-- | drivers/misc/mpu3050/timerirq.h | 28 | ||||
-rw-r--r-- | include/linux/mpu.h | 117 | ||||
-rw-r--r-- | include/linux/mpu6000.h | 179 |
15 files changed, 2470 insertions, 1181 deletions
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4329de81abf4..2ea924ceb9d3 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -42,7 +42,7 @@ obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o obj-$(CONFIG_APANIC) += apanic.o obj-$(CONFIG_SENSORS_AK8975) += akm8975.o obj-$(CONFIG_BCM4329_RFKILL) += bcm4329_rfkill.o -obj-$(CONFIG_SENSORS_MPU3050) += mpu3050/ +obj-$(CONFIG_MPU_SENSORS_MPU3050) += mpu3050/ obj-$(CONFIG_SENSORS_NCT1008) += nct1008.o obj-$(CONFIG_TEGRA_CRYPTO_DEV) += tegra-cryptodev.o obj-$(CONFIG_MAX1749_VIBRATOR) += max1749.o diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig index 579ffd2665fb..e43857268ea7 100644 --- a/drivers/misc/mpu3050/Kconfig +++ b/drivers/misc/mpu3050/Kconfig @@ -1,92 +1,100 @@ -
-menu "Motion Sensors Support"
-
-choice
- tristate "Motion Processing Unit"
- depends on I2C
- default MPU_NONE
-
-config MPU_NONE
- bool "None"
- help
- This disables support for motion processing using the MPU family of
- motion processing units.
-
-config SENSORS_MPU3050
- tristate "MPU3050"
- depends on I2C
- help
- If you say yes here you get support for the MPU3050 Gyroscope driver
- This driver can also be built as a module. If so, the module
- will be called mpu3050.
-
-config SENSORS_MPU6000
- tristate "MPU6000"
- depends on I2C
- help
- If you say yes here you get support for the MPU6000 Gyroscope driver
- This driver can also be built as a module. If so, the module
- will be called mpu6000.
-
-endchoice
-
-choice
- prompt "Accelerometer Type"
- depends on SENSORS_MPU3050
- default SENSORS_KXTF9_MPU
-
-config SENSORS_ACCELEROMETER_NONE
- bool "NONE"
- depends on SENSORS_MPU3050 || SENSORS_MPU6000
- help
- This disables accelerometer support for the MPU3050
-
-config SENSORS_KXTF9_MPU
- bool "Kionix KXTF9"
- depends on SENSORS_MPU3050
- help
- This enables support for the Kionix KXFT9 accelerometer
-
-endchoice
-
-choice
- prompt "Compass Type"
- depends on SENSORS_MPU6000 || SENSORS_MPU3050
- default SENSORS_AK8975_MPU
-
-config SENSORS_COMPASS_NONE
- bool "NONE"
- depends on SENSORS_MPU6000 || SENSORS_MPU3050
- help
- This disables compass support for the MPU6000
-
-config SENSORS_AK8975_MPU
- bool "AKM ak8975"
- depends on SENSORS_MPU6000 || SENSORS_MPU3050
- help
- This enables support for the AKM ak8975 compass
-
-endchoice
-
-choice
- prompt "Pressure Type"
- depends on SENSORS_MPU6000 || SENSORS_MPU3050
- default SENSORS_NONE
-
-config SENSORS_PRESSURE_NONE
- bool "NONE"
- depends on SENSORS_MPU6000 || SENSORS_MPU3050
- help
- This disables pressure sensor support for the MPU6000
-
-endchoice
-
-config SENSORS_MPU_DEBUG
- bool "MPU debug"
- depends on SENSORS_MPU3050 || SENSORS_MPU6000
- help
- If you say yes here you get extra debug messages from the MPU3050
- and other slave sensors.
-
-endmenu
-
+ +menu "Motion Sensors Support" + +choice + tristate "Motion Processing Unit" + depends on I2C + default MPU_NONE + +config MPU_NONE + bool "None" + help + This disables support for motion processing using the MPU family of + motion processing units. + +config MPU_SENSORS_MPU3050 + tristate "MPU3050" + depends on I2C + help + If you say yes here you get support for the MPU3050 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu3050. + +config MPU_SENSORS_MPU6000 + tristate "MPU6000" + depends on I2C + help + If you say yes here you get support for the MPU6000 Gyroscope driver + This driver can also be built as a module. If so, the module + will be called mpu6000. + +endchoice + +choice + prompt "Accelerometer Type" + depends on MPU_SENSORS_MPU3050 + default MPU_SENSORS_KXTF9 + +config MPU_SENSORS_ACCELEROMETER_NONE + bool "NONE" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000 + help + This disables accelerometer support for the MPU3050 + +config MPU_SENSORS_KXTF9 + bool "Kionix KXTF9" + depends on MPU_SENSORS_MPU3050 + help + This enables support for the Kionix KXFT9 accelerometer + +endchoice + +choice + prompt "Compass Type" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + default MPU_SENSORS_AK8975 + +config MPU_SENSORS_COMPASS_NONE + bool "NONE" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This disables compass support for the MPU6000 + +config MPU_SENSORS_AK8975 + bool "AKM ak8975" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This enables support for the AKM ak8975 compass + +endchoice + +choice + prompt "Pressure Type" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + default MPU_SENSORS_BMA085 + +config MPU_SENSORS_PRESSURE_NONE + bool "NONE" + depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050 + help + This disables pressure sensor support for the MPU6000 + +endchoice + +config MPU_SENSORS_TIMERIRQ + tristate "Timer IRQ" + help + If you say yes here you get access to the timerirq device handle which + can be used to select on. This can be used instead of IRQ's, sleeping, + or timer threads. Reading from this device returns the same type of + information as reading from the MPU and slave IRQ's. + +config MPU_SENSORS_DEBUG + bool "MPU debug" + depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000 || MPU_SENSORS_TIMERIRQ + help + If you say yes here you get extra debug messages from the MPU3050 + and other slave sensors. + +endmenu + diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile index c03e473e375b..c7e1b863e588 100644 --- a/drivers/misc/mpu3050/Makefile +++ b/drivers/misc/mpu3050/Makefile @@ -1,117 +1,128 @@ -
-# Kernel makefile for motions sensors
-#
-#
-
-# MPU
-obj-$(CONFIG_SENSORS_MPU3050) += mpu3050.o
-mpu3050-objs += mpuirq.o \
- slaveirq.o \
- mpu-dev.o \
- mpu-i2c.o \
- mlsl-kernel.o \
- mlos-kernel.o \
- $(MLLITE_DIR)mldl_cfg.o
-
-#
-# Accel options
-#
-ifdef CONFIG_SENSORS_ADXL346
-mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o
-endif
-
-ifdef CONFIG_SENSORS_BMA150
-mpu3050-objs += $(MLLITE_DIR)accel/bma150.o
-endif
-
-ifdef CONFIG_SENSORS_BMA222
-mpu3050-objs += $(MLLITE_DIR)accel/bma222.o
-endif
-
-ifdef CONFIG_SENSORS_KXSD9
-mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o
-endif
-
-ifdef CONFIG_SENSORS_KXTF9_MPU
-mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o
-endif
-
-ifdef CONFIG_SENSORS_LIS331DLH
-mpu3050-objs += $(MLLITE_DIR)accel/lis331.o
-endif
-
-ifdef CONFIG_SENSORS_LSM303DLHA
-mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o
-endif
-
-ifdef CONFIG_SENSORS_MMA8450
-mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o
-endif
-
-ifdef CONFIG_SENSORS_MMA8451
-mpu3050-objs += $(MLLITE_DIR)accel/mma8451.o
-endif
-
-#
-# Compass options
-#
-ifdef CONFIG_SENSORS_AK8975_MPU
-mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o
-endif
-
-ifdef CONFIG_SENSORS_AMI30X
-mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o
-endif
-
-ifdef CONFIG_SENSORS_HMC5883
-mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o
-endif
-
-ifdef CONFIG_SENSORS_LSM303DLHM
-mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o
-endif
-
-ifdef CONFIG_SENSORS_MMC314X
-mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o
-endif
-
-ifdef CONFIG_SENSORS_YAS529
-mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o
-endif
-
-ifdef CONFIG_SENSORS_HSCDTD002B
-mpu3050-objs += $(MLLITE_DIR)compass/hscdtd002b.o
-endif
-
-#
-# Pressure options
-#
-ifdef CONFIG_SENSORS_BMA085
-mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o
-endif
-
-EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \
- -I$(M)/../../include \
- -Idrivers/misc/mpu3050 \
- -Iinclude/linux
-
-ifdef CONFIG_SENSORS_MPU_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
-
-obj-$(CONFIG_SENSORS_MPU6000)= mpu6000.o
-mpu6000-objs += mpuirq.o \
- mpu-dev.o \
- mpu-i2c.o \
- mlsl-kernel.o \
- mlos-kernel.o \
- $(MLLITE_DIR)mldl_cfg.o \
- $(MLLITE_DIR)accel/mantis.o
-
-ifdef CONFIG_SENSORS_AK8975_MPU
-mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o
-endif
-
-ifdef CONFIG_SENSORS_MPU6000
-EXTRA_CFLAGS += -DM_HW
-endif
+ +# Kernel makefile for motions sensors +# +# + +# MPU +obj-$(CONFIG_MPU_SENSORS_MPU3050) += mpu3050.o +mpu3050-objs += mpuirq.o \ + slaveirq.o \ + mpu-dev.o \ + mpu-i2c.o \ + mlsl-kernel.o \ + mlos-kernel.o \ + $(MLLITE_DIR)mldl_cfg.o + +# +# Accel options +# +ifdef CONFIG_MPU_SENSORS_ADXL346 +mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o +endif + +ifdef CONFIG_MPU_SENSORS_BMA150 +mpu3050-objs += $(MLLITE_DIR)accel/bma150.o +endif + +ifdef CONFIG_MPU_SENSORS_BMA222 +mpu3050-objs += $(MLLITE_DIR)accel/bma222.o +endif + +ifdef CONFIG_MPU_SENSORS_KXSD9 +mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o +endif + +ifdef CONFIG_MPU_SENSORS_KXTF9 +mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o +endif + +ifdef CONFIG_MPU_SENSORS_LIS331DLH +mpu3050-objs += $(MLLITE_DIR)accel/lis331.o +endif + +ifdef CONFIG_MPU_SENSORS_LIS3DH +mpu3050-objs += $(MLLITE_DIR)accel/lis3dh.o +endif + +ifdef CONFIG_MPU_SENSORS_LSM303DLHA +mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o +endif + +ifdef CONFIG_MPU_SENSORS_MMA8450 +mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o +endif + +ifdef CONFIG_MPU_SENSORS_MMA845X +mpu3050-objs += $(MLLITE_DIR)accel/mma845x.o +endif + +# +# Compass options +# +ifdef CONFIG_MPU_SENSORS_AK8975 +mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o +endif + +ifdef CONFIG_MPU_SENSORS_AMI30X +mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o +endif + +ifdef CONFIG_MPU_SENSORS_HMC5883 +mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o +endif + +ifdef CONFIG_MPU_SENSORS_LSM303DLHM +mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o +endif + +ifdef CONFIG_MPU_SENSORS_MMC314X +mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o +endif + +ifdef CONFIG_MPU_SENSORS_YAS529 +mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o +endif + +ifdef CONFIG_MPU_SENSORS_HSCDTD002B +mpu3050-objs += $(MLLITE_DIR)compass/hscdtd002b.o +endif + +ifdef CONFIG_MPU_SENSORS_HSCDTD004A +mpu3050-objs += $(MLLITE_DIR)compass/hscdtd004a.o +endif +# +# Pressure options +# +ifdef CONFIG_MPU_SENSORS_BMA085 +mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o +endif + +EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \ + -I$(M)/../../include \ + -Idrivers/misc/mpu3050 \ + -Iinclude/linux + +obj-$(CONFIG_MPU_SENSORS_MPU6000)+= mpu6000.o +mpu6000-objs += mpuirq.o \ + slaveirq.o \ + mpu-dev.o \ + mpu-i2c.o \ + mlsl-kernel.o \ + mlos-kernel.o \ + $(MLLITE_DIR)mldl_cfg.o \ + $(MLLITE_DIR)accel/mantis.o + +ifdef CONFIG_MPU_SENSORS_AK8975 +mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o +endif + +ifdef CONFIG_MPU_SENSORS_MPU6000 +EXTRA_CFLAGS += -DM_HW +endif + +obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o + +ifdef CONFIG_MPU_SENSORS_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif + diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c index 11a9491dd7f1..e2490af1ca77 100644 --- a/drivers/misc/mpu3050/accel/kxtf9.c +++ b/drivers/misc/mpu3050/accel/kxtf9.c @@ -31,6 +31,9 @@ /* - Include Files. - */ /* ------------------ */ +#undef MPL_LOG_NDEBUG +#define MPL_LOG_NDEBUG 1 + #ifdef __KERNEL__ #include <linux/module.h> #endif @@ -43,22 +46,322 @@ #undef MPL_LOG_TAG #define MPL_LOG_TAG "MPL-acc" +#define KXTF9_XOUT_HPF_L (0x00) /* 0000 0000 */ +#define KXTF9_XOUT_HPF_H (0x01) /* 0000 0001 */ +#define KXTF9_YOUT_HPF_L (0x02) /* 0000 0010 */ +#define KXTF9_YOUT_HPF_H (0x03) /* 0000 0011 */ +#define KXTF9_ZOUT_HPF_L (0x04) /* 0001 0100 */ +#define KXTF9_ZOUT_HPF_H (0x05) /* 0001 0101 */ +#define KXTF9_XOUT_L (0x06) /* 0000 0110 */ +#define KXTF9_XOUT_H (0x07) /* 0000 0111 */ +#define KXTF9_YOUT_L (0x08) /* 0000 1000 */ +#define KXTF9_YOUT_H (0x09) /* 0000 1001 */ +#define KXTF9_ZOUT_L (0x0A) /* 0001 1010 */ +#define KXTF9_ZOUT_H (0x0B) /* 0001 1011 */ +#define KXTF9_ST_RESP (0x0C) /* 0000 1100 */ +#define KXTF9_WHO_AM_I (0x0F) /* 0000 1111 */ +#define KXTF9_TILT_POS_CUR (0x10) /* 0001 0000 */ +#define KXTF9_TILT_POS_PRE (0x11) /* 0001 0001 */ +#define KXTF9_INT_SRC_REG1 (0x15) /* 0001 0101 */ +#define KXTF9_INT_SRC_REG2 (0x16) /* 0001 0110 */ +#define KXTF9_STATUS_REG (0x18) /* 0001 1000 */ +#define KXTF9_INT_REL (0x1A) /* 0001 1010 */ +#define KXTF9_CTRL_REG1 (0x1B) /* 0001 1011 */ +#define KXTF9_CTRL_REG2 (0x1C) /* 0001 1100 */ +#define KXTF9_CTRL_REG3 (0x1D) /* 0001 1101 */ +#define KXTF9_INT_CTRL_REG1 (0x1E) /* 0001 1110 */ +#define KXTF9_INT_CTRL_REG2 (0x1F) /* 0001 1111 */ +#define KXTF9_INT_CTRL_REG3 (0x20) /* 0010 0000 */ +#define KXTF9_DATA_CTRL_REG (0x21) /* 0010 0001 */ +#define KXTF9_TILT_TIMER (0x28) /* 0010 1000 */ +#define KXTF9_WUF_TIMER (0x29) /* 0010 1001 */ +#define KXTF9_TDT_TIMER (0x2B) /* 0010 1011 */ +#define KXTF9_TDT_H_THRESH (0x2C) /* 0010 1100 */ +#define KXTF9_TDT_L_THRESH (0x2D) /* 0010 1101 */ +#define KXTF9_TDT_TAP_TIMER (0x2E) /* 0010 1110 */ +#define KXTF9_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */ +#define KXTF9_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */ +#define KXTF9_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */ +#define KXTF9_WUF_THRESH (0x5A) /* 0101 1010 */ +#define KXTF9_TILT_ANGLE (0x5C) /* 0101 1100 */ +#define KXTF9_HYST_SET (0x5F) /* 0101 1111 */ + +#define KXTF9_MAX_DUR (0xFF) +#define KXTF9_MAX_THS (0xFF) +#define KXTF9_THS_COUNTS_P_G (32) + /* --------------------- */ /* - Variables. - */ /* --------------------- */ +struct kxtf9_config { + unsigned int odr; /* Output data rate mHz */ + unsigned int fsr; /* full scale range mg */ + unsigned int ths; /* Motion no-motion thseshold mg */ + unsigned int dur; /* Motion no-motion duration ms */ + unsigned int irq_type; + unsigned char reg_ths; + unsigned char reg_dur; + unsigned char reg_odr; + unsigned char reg_int_cfg1; + unsigned char reg_int_cfg2; + unsigned char ctrl_reg1; +}; + +struct kxtf9_private_data { + struct kxtf9_config suspend; + struct kxtf9_config resume; +}; + /***************************************** Accelerometer Initialization Functions *****************************************/ +static int kxtf9_set_ths(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long ths) +{ + int result = ML_SUCCESS; + if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS) + ths = (KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G; + + if (ths < 0) + ths = 0; + + config->ths = ths; + config->reg_ths = (unsigned char) + ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000); + MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + config->reg_ths); + return result; +} + +static int kxtf9_set_dur(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long dur) +{ + int result = ML_SUCCESS; + long reg_dur = (dur * config->odr) / 1000000; + config->dur = dur; + + if (reg_dur > KXTF9_MAX_DUR) + reg_dur = KXTF9_MAX_DUR; + + config->reg_dur = (unsigned char) reg_dur; + MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur); + if (apply) + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, + (unsigned char)reg_dur); + return result; +} + +/** + * Sets the IRQ to fire when one of the IRQ events occur. Threshold and + * duration will not be used uless the type is MOT or NMOT. + * + * @param config configuration to apply to, suspend or resume + * @param irq_type The type of IRQ. Valid values are + * - MPU_SLAVE_IRQ_TYPE_NONE + * - MPU_SLAVE_IRQ_TYPE_MOTION + * - MPU_SLAVE_IRQ_TYPE_DATA_READY + */ +static int kxtf9_set_irq(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long irq_type) +{ + int result = ML_SUCCESS; + struct kxtf9_private_data *private_data = pdata->private_data; + + config->irq_type = (unsigned char)irq_type; + config->ctrl_reg1 &= ~0x22; + if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) { + config->ctrl_reg1 |= 0x20; + config->reg_int_cfg1 = 0x38; + config->reg_int_cfg2 = 0x00; + } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) { + config->ctrl_reg1 |= 0x02; + if ((unsigned long) config == + (unsigned long) &private_data->suspend) + config->reg_int_cfg1 = 0x34; + else + config->reg_int_cfg1 = 0x24; + config->reg_int_cfg2 = 0xE0; + } else { + config->reg_int_cfg1 = 0x00; + config->reg_int_cfg2 = 0x00; + } + + if (apply) { + /* Must clear bit 7 before writing new configuration */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + config->reg_int_cfg1); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG2, + config->reg_int_cfg2); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n", + (unsigned long)config->ctrl_reg1, + (unsigned long)config->reg_int_cfg1, + (unsigned long)config->reg_int_cfg2); + + return result; +} + +/** + * Set the Output data rate for the particular configuration + * + * @param config Config to modify with new ODR + * @param odr Output data rate in units of 1/1000Hz + */ +static int kxtf9_set_odr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long odr) +{ + unsigned char bits; + int result = ML_SUCCESS; + + /* Data sheet says there is 12.5 hz, but that seems to produce a single + * correct data value, thus we remove it from the table */ + if (odr > 400000) { + config->odr = 800000; + bits = 0x06; + } else if (odr > 200000) { + config->odr = 400000; + bits = 0x05; + } else if (odr > 100000) { + config->odr = 200000; + bits = 0x04; + } else if (odr > 50000) { + config->odr = 100000; + bits = 0x03; + } else if (odr > 25000) { + config->odr = 50000; + bits = 0x02; + } else if (odr != 0) { + config->odr = 25000; + bits = 0x01; + } else { + config->odr = 0; + bits = 0; + } + + if (odr != 0) + config->ctrl_reg1 |= 0x80; + + config->reg_odr = bits; + kxtf9_set_dur(mlsl_handle, pdata, + config, apply, config->dur); + MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1); + if (apply) { + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + config->reg_odr); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + 0x40); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + config->ctrl_reg1); + } + return result; +} + +/** + * Set the full scale range of the accels + * + * @param config pointer to configuration + * @param fsr requested full scale range + */ +static int kxtf9_set_fsr(void *mlsl_handle, + struct ext_slave_platform_data *pdata, + struct kxtf9_config *config, + int apply, + long fsr) +{ + int result = ML_SUCCESS; + + config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7); + if (fsr <= 2000) { + config->fsr = 2000; + config->ctrl_reg1 |= 0x00; + } else if (fsr <= 4000) { + config->fsr = 4000; + config->ctrl_reg1 |= 0x08; + } else { + config->fsr = 8000; + config->ctrl_reg1 |= 0x10; + } + + MPL_LOGV("FSR: %d\n", config->fsr); + if (apply) { + /* Must clear bit 7 before writing new configuration */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, config->ctrl_reg1); + } + return result; +} + static int kxtf9_suspend(void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata) { int result; - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0); + unsigned char data; + struct kxtf9_private_data *private_data = pdata->private_data; + + /* Wake up */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); + ERROR_CHECK(result); + /* INT_CTRL_REG1: */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + private_data->suspend.reg_int_cfg1); + ERROR_CHECK(result); + /* WUF_THRESH: */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, + private_data->suspend.reg_ths); + ERROR_CHECK(result); + /* DATA_CTRL_REG */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + private_data->suspend.reg_odr); + ERROR_CHECK(result); + /* WUF_TIMER */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, private_data->suspend.reg_dur); ERROR_CHECK(result); + + /* Normal operation */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + private_data->suspend.ctrl_reg1); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, pdata->address, + KXTF9_INT_REL, 1, &data); + ERROR_CHECK(result); + return result; } @@ -71,53 +374,245 @@ static int kxtf9_resume(void *mlsl_handle, struct ext_slave_platform_data *pdata) { int result = ML_SUCCESS; - unsigned char reg; + unsigned char data; + struct kxtf9_private_data *private_data = pdata->private_data; - /* RAM reset */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1d, 0xcd); - ERROR_CHECK(result); - MLOSSleep(10); /* Wake up */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0x42); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, 0x40); ERROR_CHECK(result); /* INT_CTRL_REG1: */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1e, 0x14); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_INT_CTRL_REG1, + private_data->resume.reg_int_cfg1); ERROR_CHECK(result); /* WUF_THRESH: */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x5a, 0x00); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_THRESH, private_data->resume.reg_ths); ERROR_CHECK(result); /* DATA_CTRL_REG */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x04); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + private_data->resume.reg_odr); ERROR_CHECK(result); /* WUF_TIMER */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x29, 0x02); - ERROR_CHECK(result); - - /* Full Scale */ - reg = 0xc2; - reg &= ~ACCEL_KIONIX_CTRL_MASK; - reg |= 0x00; - if (slave->range.mantissa == 4) - reg |= 0x08; - else if (slave->range.mantissa == 8) - reg |= 0x10; - else { - slave->range.mantissa = 2; - reg |= 0x00; - } - slave->range.fraction = 0; + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_WUF_TIMER, private_data->resume.reg_dur); + ERROR_CHECK(result); /* Normal operation */ - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, reg); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + private_data->resume.ctrl_reg1); + ERROR_CHECK(result); + result = MLSLSerialRead(mlsl_handle, pdata->address, + KXTF9_INT_REL, 1, &data); + ERROR_CHECK(result); + + return ML_SUCCESS; +} + +static int kxtf9_init(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + + struct kxtf9_private_data *private_data; + int result = ML_SUCCESS; + + private_data = (struct kxtf9_private_data *) + MLOSMalloc(sizeof(struct kxtf9_private_data)); + + if (!private_data) + return ML_ERROR_MEMORY_EXAUSTED; + + /* RAM reset */ + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG1, + 0x40); /* Fastest Reset */ + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_DATA_CTRL_REG, + 0x36); /* Fastest Reset */ + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, + KXTF9_CTRL_REG3, 0xcd); /* Reset */ + ERROR_CHECK(result); + MLOSSleep(2); + + pdata->private_data = private_data; + + private_data->resume.ctrl_reg1 = 0xC0; + private_data->suspend.ctrl_reg1 = 0x40; + + result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend, + FALSE, 1000); + ERROR_CHECK(result); + result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume, + FALSE, 2540); ERROR_CHECK(result); - MLOSSleep(50); + + result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 50000); + ERROR_CHECK(result); + result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume, + FALSE, 200000); + + result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend, + FALSE, 2000); + ERROR_CHECK(result); + result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume, + FALSE, 2000); + ERROR_CHECK(result); + + result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend, + FALSE, 80); + ERROR_CHECK(result); + result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume, + FALSE, 40); + ERROR_CHECK(result); + + result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + ERROR_CHECK(result); + result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume, + FALSE, + MPU_SLAVE_IRQ_TYPE_NONE); + ERROR_CHECK(result); + return result; +} + +static int kxtf9_exit(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata) +{ + if (pdata->private_data) + return MLOSFree(pdata->private_data); + else + return ML_SUCCESS; +} + +static int kxtf9_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct kxtf9_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + return kxtf9_set_odr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_ODR_RESUME: + return kxtf9_set_odr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + return kxtf9_set_fsr(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_FSR_RESUME: + return kxtf9_set_fsr(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_THS: + return kxtf9_set_ths(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_THS: + return kxtf9_set_ths(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_MOT_DUR: + return kxtf9_set_dur(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_NMOT_DUR: + return kxtf9_set_dur(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + return kxtf9_set_irq(mlsl_handle, pdata, + &private_data->suspend, + data->apply, + *((long *)data->data)); + case MPU_SLAVE_CONFIG_IRQ_RESUME: + return kxtf9_set_irq(mlsl_handle, pdata, + &private_data->resume, + data->apply, + *((long *)data->data)); + default: + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; + + return ML_SUCCESS; +} + +static int kxtf9_get_config(void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *data) +{ + struct kxtf9_private_data *private_data = pdata->private_data; + if (!data->data) + return ML_ERROR_INVALID_PARAMETER; + + switch (data->key) { + case MPU_SLAVE_CONFIG_ODR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.odr; + break; + case MPU_SLAVE_CONFIG_ODR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.odr; + break; + case MPU_SLAVE_CONFIG_FSR_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.fsr; + break; + case MPU_SLAVE_CONFIG_FSR_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.fsr; + break; + case MPU_SLAVE_CONFIG_MOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.ths; + break; + case MPU_SLAVE_CONFIG_NMOT_THS: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.ths; + break; + case MPU_SLAVE_CONFIG_MOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.dur; + break; + case MPU_SLAVE_CONFIG_NMOT_DUR: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.dur; + break; + case MPU_SLAVE_CONFIG_IRQ_SUSPEND: + (*(unsigned long *)data->data) = + (unsigned long) private_data->suspend.irq_type; + break; + case MPU_SLAVE_CONFIG_IRQ_RESUME: + (*(unsigned long *)data->data) = + (unsigned long) private_data->resume.irq_type; + break; + default: + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + }; return ML_SUCCESS; } @@ -127,16 +622,29 @@ static int kxtf9_read(void *mlsl_handle, struct ext_slave_platform_data *pdata, unsigned char *data) { - return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + int result; + unsigned char reg; + result = MLSLSerialRead(mlsl_handle, pdata->address, + KXTF9_INT_SRC_REG2, 1, ®); + ERROR_CHECK(result); + + if (!(reg & 0x10)) + return ML_ERROR_ACCEL_DATA_NOT_READY; + + result = MLSLSerialRead(mlsl_handle, pdata->address, + slave->reg, slave->len, data); + ERROR_CHECK(result); + return result; } static struct ext_slave_descr kxtf9_descr = { - /*.init = */ NULL, - /*.exit = */ NULL, + /*.init = */ kxtf9_init, + /*.exit = */ kxtf9_exit, /*.suspend = */ kxtf9_suspend, /*.resume = */ kxtf9_resume, /*.read = */ kxtf9_read, - /*.config = */ NULL, + /*.config = */ kxtf9_config, + /*.get_config = */ kxtf9_get_config, /*.name = */ "kxtf9", /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER, /*.id = */ ACCEL_ID_KXTF9, diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c index 18606e240f1c..991de77dbd01 100644 --- a/drivers/misc/mpu3050/compass/ak8975.c +++ b/drivers/misc/mpu3050/compass/ak8975.c @@ -25,12 +25,14 @@ * @{ * @file AK8975.c * @brief Magnetometer setup and handling methods for AKM 8975 compass. -**/ + */ /* ------------------ */ /* - Include Files. - */ /* ------------------ */ +#include <string.h> + #ifdef __KERNEL__ #include <linux/module.h> #endif @@ -84,44 +86,78 @@ int ak8975_read(void *mlsl_handle, struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata, unsigned char *data) { - unsigned char stat; - unsigned char stat2; + unsigned char regs[8]; + unsigned char *stat = ®s[0]; + unsigned char *stat2 = ®s[7]; int result = ML_SUCCESS; + int status = ML_SUCCESS; result = - MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1, 1, - &stat); + MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1, + 8, regs); ERROR_CHECK(result); - if (stat & 0x01) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - AK8975_REG_HXL, 6, - (unsigned char *) data); - ERROR_CHECK(result); - result = - MLSLSerialRead(mlsl_handle, pdata->address, - AK8975_REG_ST2, 1, &stat2); - ERROR_CHECK(result); - if (stat2 & 0x04) /* data error */ - return ML_ERROR_COMPASS_DATA_NOT_READY; - if (stat2 & 0x08) - return ML_ERROR_COMPASS_DATA_OVERFLOW; + /* + * ST : data ready - + * Measurement has been completed and data is ready to be read. + */ + if (*stat & 0x01) { + memcpy(data, ®s[1], 6); + status = ML_SUCCESS; + } + + /* + * ST2 : data error - + * occurs when data read is started outside of a readable period; + * data read would not be correct. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour but we + * stil account for it and return an error, since the data would be + * corrupted. + * DERR bit is self-clearing when ST2 register is read. + */ + if (*stat2 & 0x04) + status = ML_ERROR_COMPASS_DATA_ERROR; + /* + * ST2 : overflow - + * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT. + * This is likely to happen in presence of an external magnetic + * disturbance; it indicates, the sensor data is incorrect and should + * be ignored. + * An error is returned. + * HOFL bit clears when a new measurement starts. + */ + if (*stat2 & 0x08) + status = ML_ERROR_COMPASS_DATA_OVERFLOW; + /* + * ST : overrun - + * the previous sample was not fetched and lost. + * Valid in continuous measurement mode only. + * In single measurement mode this error should not occour and we + * don't consider this condition an error. + * DOR bit is self-clearing when ST2 or any meas. data register is + * read. + */ + if (*stat & 0x02) { + /* status = ML_ERROR_COMPASS_DATA_UNDERFLOW; */ + status = ML_SUCCESS; + } + + /* + * trigger next measurement if: + * - stat is non zero; + * - if stat is zero and stat2 is non zero. + * Won't trigger if data is not ready and there was no error. + */ + if (*stat != 0x00 || *stat2 != 0x00) { result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, AK8975_REG_CNTL, AK8975_CNTL_MODE_SINGLE_MEASUREMENT); ERROR_CHECK(result); - return ML_SUCCESS; - } else if (stat & 0x02) { - result = - MLSLSerialRead(mlsl_handle, pdata->address, - AK8975_REG_ST2, 1, &stat2); - ERROR_CHECK(result); - return ML_ERROR_COMPASS_DATA_OVERFLOW; - } else { - return ML_ERROR_COMPASS_DATA_NOT_READY; } + + return status; } struct ext_slave_descr ak8975_descr = { @@ -131,6 +167,7 @@ struct ext_slave_descr ak8975_descr = { /*.resume = */ ak8975_resume, /*.read = */ ak8975_read, /*.config = */ NULL, + /*.get_config = */ NULL, /*.name = */ "ak8975", /*.type = */ EXT_SLAVE_TYPE_COMPASS, /*.id = */ COMPASS_ID_AKM, @@ -148,4 +185,4 @@ EXPORT_SYMBOL(ak8975_get_slave_descr); /** * @} -**/ + */ diff --git a/drivers/misc/mpu3050/mldl_cfg.c b/drivers/misc/mpu3050/mldl_cfg.c index 668a4cf03ccc..66f447e7ba85 100644 --- a/drivers/misc/mpu3050/mldl_cfg.c +++ b/drivers/misc/mpu3050/mldl_cfg.c @@ -57,99 +57,85 @@ #define STANDBY 1 #endif -/* --------------------- */ -/* - Prototypes. - */ -/* --------------------- */ -#ifdef M_HW -static tMLError MLDLPowerMgmtMantis(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char reset, - unsigned char powerselection); -static tMLError MLDLStandByGyros(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char disable_gx, - unsigned char disable_gy, - unsigned char disable_gz); -#else -static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char reset, - unsigned char sleep, - unsigned char disable_gx, - unsigned char disable_gy, - unsigned char disable_gz); -#endif +/*---------------------*/ +/*- Prototypes. -*/ +/*---------------------*/ -/* ---------------------- */ -/* - Static Functions. - */ -/* ---------------------- */ +/*----------------------*/ +/*- Static Functions. -*/ +/*----------------------*/ -/** - * @internal - * @brief MLDLCfgDMP configures the Digital Motion Processor internal to - * the MPU. The DMP can be enabled or disabled and the start address - * can be set. - * - * @param enableRun Enables the DMP processing if set to TRUE. - * @param enableFIFO Enables DMP output to the FIFO if set to TRUE. - * - * @return Zero if the command is successful, an error code otherwise. - */ -static int MLDLCtrlDmp(struct mldl_cfg *pdata, void *mlsl_handle, - bool enableRun, bool enableFIFO) +static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle) { - unsigned char b; + unsigned char userCtrlReg; + int result; - MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, 1, &b); - if (enableRun) - b |= BIT_DMP_EN; - else - b &= ~BIT_DMP_EN; + if (!mldl_cfg->dmp_is_running) + return ML_SUCCESS; - if (enableFIFO) - b |= BIT_FIFO_EN; + result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, 1, &userCtrlReg); + ERROR_CHECK(result); + userCtrlReg = (userCtrlReg & (~BIT_FIFO_EN)) | BIT_FIFO_RST; + userCtrlReg = (userCtrlReg & (~BIT_DMP_EN)) | BIT_DMP_RST; - b |= BIT_DMP_RST; + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, userCtrlReg); + ERROR_CHECK(result); + mldl_cfg->dmp_is_running = 0; - MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, - b); + return result; - return ML_SUCCESS; } - /** * @brief Starts the DMP running * * @return ML_SUCCESS or non-zero error code */ -static int MLDLDmpStart(struct mldl_cfg *pdata, void *mlsl_handle) +static int dmp_start(struct mldl_cfg *pdata, void *mlsl_handle) { - unsigned char fifoBuf[2]; - unsigned char tries = 0; unsigned char userCtrlReg; int result; - unsigned short len = !0; + + if (pdata->dmp_is_running == pdata->dmp_enable) + return ML_SUCCESS; result = MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, 1, &userCtrlReg); + ERROR_CHECK(result); - while (len != 0 && tries < 6) { - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, - ((userCtrlReg & (~BIT_FIFO_EN)) - | BIT_FIFO_RST)); - MLSLSerialRead(mlsl_handle, pdata->addr, - MPUREG_FIFO_COUNTH, 2, fifoBuf); - len = (((unsigned short) fifoBuf[0] << 8) - | (unsigned short) fifoBuf[1]); - tries++; - } + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, + ((userCtrlReg & (~BIT_FIFO_EN)) + | BIT_FIFO_RST)); + ERROR_CHECK(result); + + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, userCtrlReg); + ERROR_CHECK(result); + + result = MLSLSerialRead(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, 1, &userCtrlReg); + ERROR_CHECK(result); + + if (pdata->dmp_enable) + userCtrlReg |= BIT_DMP_EN; + else + userCtrlReg &= ~BIT_DMP_EN; + + if (pdata->fifo_enable) + userCtrlReg |= BIT_FIFO_EN; + else + userCtrlReg &= ~BIT_FIFO_EN; - MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_USER_CTRL, userCtrlReg); + userCtrlReg |= BIT_DMP_RST; - return MLDLCtrlDmp(pdata, mlsl_handle, - pdata->dmp_enable, pdata->fifo_enable); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_USER_CTRL, userCtrlReg); + ERROR_CHECK(result); + pdata->dmp_is_running = pdata->dmp_enable; + + return result; } /** @@ -166,22 +152,15 @@ static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg, unsigned char b; int result; -#ifdef ML_USE_DMP_SIM - /* done this way so that pc demo */ - /* w/arm board works with universal api */ - if (!MLGetGyroPresent()) + if ((mldl_cfg->gyro_is_bypassed && enable) || + (!mldl_cfg->gyro_is_bypassed && !enable)) return ML_SUCCESS; -#endif /*---- get current 'USER_CTRL' into b ----*/ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, MPUREG_USER_CTRL, 1, &b); ERROR_CHECK(result); - /* No change */ - if ((b & BIT_AUX_IF_EN) != (enable * BIT_AUX_IF_EN)) - return ML_SUCCESS; - b &= ~BIT_AUX_IF_EN; if (!enable) { @@ -215,7 +194,7 @@ static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg, * 3) wait for up to one MPU cycle then restore the slave * address */ - MLOSSleep(5); + MLOSSleep(SAMPLING_PERIOD_US(mldl_cfg) / 1000); result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, MPUREG_AUX_SLV_ADDR, mldl_cfg->pdata-> @@ -238,6 +217,7 @@ static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg, ERROR_CHECK(result); MLOSSleep(2); } + mldl_cfg->gyro_is_bypassed = enable; return result; } @@ -254,11 +234,14 @@ struct tsProdRevMap { #define OLDEST_PROD_REV_SUPPORTED 1 static struct tsProdRevMap prodRevsMap[] = { {0, 0}, - {MPU_SILICON_REV_A1, 131}, /* 1 A1 */ - {MPU_SILICON_REV_A1, 131}, /* 2 A1 */ - {MPU_SILICON_REV_A1, 131}, /* 3 A1 */ - {MPU_SILICON_REV_A1, 131}, /* 4 A1 */ - {MPU_SILICON_REV_A1, 131}, /* 5 A1 */ + {MPU_SILICON_REV_A1, 131}, /* 1 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 2 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 3 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 4 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 5 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 6 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 7 A1 (npp) */ + {MPU_SILICON_REV_A1, 131}, /* 8 A1 (npp) */ }; #else /* !M_HW */ @@ -411,11 +394,11 @@ static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata, /** * @internal * @param reset 1 to reset hardware -**/ -static tMLError MLDLPowerMgmtMantis(struct mldl_cfg *pdata, - void *mlsl_handle, - unsigned char reset, - unsigned char powerselection) + */ +static tMLError mpu60xx_pwr_mgmt(struct mldl_cfg *pdata, + void *mlsl_handle, + unsigned char reset, + unsigned char powerselection) { unsigned char b; tMLError result; @@ -434,7 +417,7 @@ static tMLError MLDLPowerMgmtMantis(struct mldl_cfg *pdata, /* Current sillicon has an errata where the reset will get * nacked. Ignore the error code for now. */ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b | 0x80); + MPUREG_PWR_MGM, b | BIT_H_RESET); #define M_HW_RESET_ERRATTA #ifndef M_HW_RESET_ERRATTA ERROR_CHECK(result); @@ -446,9 +429,9 @@ static tMLError MLDLPowerMgmtMantis(struct mldl_cfg *pdata, b |= (powerselection << 4); if (b & BITS_PWRSEL) - pdata->is_suspended = FALSE; + pdata->gyro_is_suspended = FALSE; else - pdata->is_suspended = TRUE; + pdata->gyro_is_suspended = TRUE; result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, b); @@ -570,29 +553,34 @@ static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, if ((!(b & BIT_SLEEP)) && reset) result = MLDLSetI2CBypass(pdata, mlsl_handle, 1); + /* If we are awake, we need stop the dmp sleeping */ + if ((!(b & BIT_SLEEP)) && sleep) + dmp_stop(pdata, mlsl_handle); + /* Reset if requested */ if (reset) { - result = - MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b | BIT_H_RESET); + MPL_LOGV("Reset MPU3050\n"); + result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, b | BIT_H_RESET); + ERROR_CHECK(result); MLOSSleep(5); + pdata->gyro_needs_reset = FALSE; + /* Some chips are awake after reset and some are asleep, + * check the status */ + result = MLSLSerialRead(mlsl_handle, pdata->addr, + MPUREG_PWR_MGM, 1, &b); + ERROR_CHECK(result); } - /* Some chips are awake after reset and some are asleep, check the - * status */ - result = - MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1, - &b); - ERROR_CHECK(result); - /* Update the suspended state just in case we return early */ if (b & BIT_SLEEP) - pdata->is_suspended = TRUE; + pdata->gyro_is_suspended = TRUE; else - pdata->is_suspended = FALSE; + pdata->gyro_is_suspended = FALSE; - if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) - == (((sleep != 0) * BIT_SLEEP) | + /* if power status match requested, nothing else's left to do */ + if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == + (((sleep != 0) * BIT_SLEEP) | ((disable_gx != 0) * BIT_STBY_XG) | ((disable_gy != 0) * BIT_STBY_YG) | ((disable_gz != 0) * BIT_STBY_ZG))) { @@ -608,7 +596,7 @@ static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, */ if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG) - && ((!sleep) && disable_gx && disable_gy && disable_gz)) { + && ((!sleep) && disable_gx && disable_gy && disable_gz)) { result = MLDLPowerMgmtMPU(pdata, mlsl_handle, 0, 1, 0, 0, 0); if (result) return result; @@ -616,7 +604,6 @@ static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG); } - if ((b & BIT_SLEEP) != ((sleep != 0) * BIT_SLEEP)) { if (sleep) { result = MLDLSetI2CBypass(pdata, mlsl_handle, 1); @@ -626,26 +613,25 @@ static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata, MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, b); ERROR_CHECK(result); - pdata->is_suspended = TRUE; + pdata->gyro_is_suspended = TRUE; } else { b &= ~BIT_SLEEP; - result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, b); ERROR_CHECK(result); - pdata->is_suspended = FALSE; + pdata->gyro_is_suspended = FALSE; MLOSSleep(5); } } - /*--- - WORKAROUND FOR PUTTING GYRO AXIS in STAND-BY MODE - 1) put one axis at a time in stand-by - ---*/ + /*--- + WORKAROUND FOR PUTTING GYRO AXIS in STAND-BY MODE + 1) put one axis at a time in stand-by + ---*/ if ((b & BIT_STBY_XG) != ((disable_gx != 0) * BIT_STBY_XG)) { b ^= BIT_STBY_XG; result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, - MPUREG_PWR_MGM, b); + MPUREG_PWR_MGM, b); ERROR_CHECK(result); } if ((b & BIT_STBY_YG) != ((disable_gy != 0) * BIT_STBY_YG)) { @@ -701,6 +687,8 @@ void mpu_print_cfg(struct mldl_cfg *mldl_cfg) MPL_LOGD("mldl_cfg.product_id = %02x\n", mldl_cfg->product_id); MPL_LOGD("mldl_cfg.trim = %02x\n", mldl_cfg->trim); + MPL_LOGD("mldl_cfg.requested_sensors= %04lx\n", + mldl_cfg->requested_sensors); if (mldl_cfg->accel) { MPL_LOGD("slave_accel->suspend = %02x\n", @@ -839,6 +827,275 @@ void mpu_print_cfg(struct mldl_cfg *mldl_cfg) offsetof(struct mldl_cfg, ram)); } +int mpu_set_slave(struct mldl_cfg *mldl_cfg, + void *gyro_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *slave_pdata) +{ + int result; + unsigned char reg; + unsigned char slave_reg; + unsigned char slave_len; + unsigned char slave_endian; + unsigned char slave_address; + + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); + + if (NULL == slave || NULL == slave_pdata) { + slave_reg = 0; + slave_len = 0; + slave_endian = 0; + slave_address = 0; + } else { + slave_reg = slave->reg; + slave_len = slave->len; + slave_endian = slave->endian; + slave_address = slave_pdata->address; + } + + /* Address */ + result = MLSLSerialWriteSingle(gyro_handle, + mldl_cfg->addr, + MPUREG_AUX_SLV_ADDR, + slave_address); + ERROR_CHECK(result); + /* Register */ + result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, + MPUREG_ACCEL_BURST_ADDR, 1, + ®); + ERROR_CHECK(result); + reg = ((reg & 0x80) | slave_reg); + result = MLSLSerialWriteSingle(gyro_handle, + mldl_cfg->addr, + MPUREG_ACCEL_BURST_ADDR, + reg); + ERROR_CHECK(result); + +#ifdef M_HW + /* Length, byte swapping, grouping & enable */ + if (slave_len > BITS_SLV_LENG) { + MPL_LOGW("Limiting slave burst read length to " + "the allowed maximum (15B, req. %d)\n", + slave_len); + slave_len = BITS_SLV_LENG; + } + reg = slave_len; + if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN) + reg |= BIT_SLV_BYTE_SW; + reg |= BIT_SLV_GRP; + reg |= BIT_SLV_ENABLE; + + result = MLSLSerialWriteSingle(gyro_handle, + mldl_cfg->addr, + MPUREG_I2C_SLV0_CTRL, + reg); +#else + /* Length */ + result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, + MPUREG_USER_CTRL, 1, ®); + ERROR_CHECK(result); + reg = (reg & ~BIT_AUX_RD_LENG); + result = MLSLSerialWriteSingle(gyro_handle, + mldl_cfg->addr, + MPUREG_USER_CTRL, reg); + ERROR_CHECK(result); +#endif + + if (slave_address) { + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, FALSE); + ERROR_CHECK(result); + } + return result; +} + +/** + * Check to see if the gyro was reset by testing a couple of registers known + * to change on reset. + * + * @param mldl_cfg mldl configuration structure + * @param gyro_handle handle used to communicate with the gyro + * + * @return ML_SUCCESS or non-zero error code + */ +static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + int result = ML_SUCCESS; + unsigned char reg; + + result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, + MPUREG_DMP_CFG_2, 1, ®); + ERROR_CHECK(result); + + if (mldl_cfg->dmp_cfg2 != reg) + return TRUE; + + if (0 != mldl_cfg->dmp_cfg1) + return FALSE; + + result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, + MPUREG_SMPLRT_DIV, 1, ®); + ERROR_CHECK(result); + if (reg != mldl_cfg->divider) + return TRUE; + + if (0 != mldl_cfg->divider) + return FALSE; + + /* Inconclusive assume it was reset */ + return TRUE; +} + +static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle) +{ + int result; + int ii; + int jj; + unsigned char reg; + unsigned char regs[7]; + + /* Wake up the part */ +#ifdef M_HW + result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, RESET, + WAKE_UP); + ERROR_CHECK(result); + + /* Configure the MPU */ + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1); + ERROR_CHECK(result); + /* setting int_config with the propert flag BIT_BYPASS_EN + should be done by the setup functions */ + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_INT_PIN_CFG, + (mldl_cfg->pdata->int_config | + BIT_BYPASS_EN)); + ERROR_CHECK(result); + /* temporary: masking out higher bits to avoid switching + intelligence */ + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_INT_ENABLE, + (mldl_cfg->int_config)); + ERROR_CHECK(result); +#else + result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 0, 0, + mldl_cfg->gyro_power & BIT_STBY_XG, + mldl_cfg->gyro_power & BIT_STBY_YG, + mldl_cfg->gyro_power & BIT_STBY_ZG); + + if (!mldl_cfg->gyro_needs_reset && + !mpu_was_reset(mldl_cfg, gyro_handle)) { + return ML_SUCCESS; + } + + result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 1, 0, + mldl_cfg->gyro_power & BIT_STBY_XG, + mldl_cfg->gyro_power & BIT_STBY_YG, + mldl_cfg->gyro_power & BIT_STBY_ZG); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_INT_CFG, + (mldl_cfg->int_config | + mldl_cfg->pdata->int_config)); + ERROR_CHECK(result); +#endif + + result = MLSLSerialRead(gyro_handle, mldl_cfg->addr, + MPUREG_PWR_MGM, 1, ®); + ERROR_CHECK(result); + reg &= ~BITS_CLKSEL; + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_PWR_MGM, + mldl_cfg->clk_src | reg); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_SMPLRT_DIV, + mldl_cfg->divider); + ERROR_CHECK(result); + +#ifdef M_HW + reg = DLPF_FS_SYNC_VALUE(0, mldl_cfg->full_scale, 0); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_GYRO_CONFIG, reg); + reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, 0, mldl_cfg->lpf); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_CONFIG, reg); +#else + reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, + mldl_cfg->full_scale, mldl_cfg->lpf); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_DLPF_FS_SYNC, reg); +#endif + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_DMP_CFG_1, + mldl_cfg->dmp_cfg1); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_DMP_CFG_2, + mldl_cfg->dmp_cfg2); + ERROR_CHECK(result); + + /* Write and verify memory */ + for (ii = 0; ii < MPU_MEM_NUM_RAM_BANKS; ii++) { + unsigned char read[MPU_MEM_BANK_SIZE]; + + result = MLSLSerialWriteMem(gyro_handle, + mldl_cfg->addr, + ((ii << 8) | 0x00), + MPU_MEM_BANK_SIZE, + mldl_cfg->ram[ii]); + ERROR_CHECK(result); + result = MLSLSerialReadMem(gyro_handle, mldl_cfg->addr, + ((ii << 8) | 0x00), + MPU_MEM_BANK_SIZE, read); + ERROR_CHECK(result); + +#ifdef M_HW +#define ML_SKIP_CHECK 38 +#else +#define ML_SKIP_CHECK 20 +#endif + for (jj = 0; jj < MPU_MEM_BANK_SIZE; jj++) { + /* skip the register memory locations */ + if (ii == 0 && jj < ML_SKIP_CHECK) + continue; + if (mldl_cfg->ram[ii][jj] != read[jj]) { + result = ML_ERROR_SERIAL_WRITE; + break; + } + } + ERROR_CHECK(result); + } + + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_XG_OFFS_TC, + mldl_cfg->offset_tc[0]); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_YG_OFFS_TC, + mldl_cfg->offset_tc[1]); + ERROR_CHECK(result); + result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr, + MPUREG_ZG_OFFS_TC, + mldl_cfg->offset_tc[2]); + ERROR_CHECK(result); + + regs[0] = MPUREG_X_OFFS_USRH; + for (ii = 0; ii < DIM(mldl_cfg->offset); ii++) { + regs[1 + ii * 2] = + (unsigned char)(mldl_cfg->offset[ii] >> 8) + & 0xff; + regs[1 + ii * 2 + 1] = + (unsigned char)(mldl_cfg->offset[ii] & 0xff); + } + result = MLSLSerialWrite(gyro_handle, mldl_cfg->addr, 7, regs); + ERROR_CHECK(result); + + /* Configure slaves */ + result = MLDLSetLevelShifterBit(mldl_cfg, gyro_handle, + mldl_cfg->pdata->level_shifter); + ERROR_CHECK(result); + return result; +} /******************************************************************************* ******************************************************************************* * Exported functions @@ -877,6 +1134,13 @@ int mpu3050_open(struct mldl_cfg *mldl_cfg, mldl_cfg->dmp_cfg1 = 0; mldl_cfg->dmp_cfg2 = 0; mldl_cfg->gyro_power = 0; + mldl_cfg->gyro_is_bypassed = TRUE; + mldl_cfg->dmp_is_running = FALSE; + mldl_cfg->gyro_is_suspended = TRUE; + mldl_cfg->accel_is_suspended = TRUE; + mldl_cfg->compass_is_suspended = TRUE; + mldl_cfg->pressure_is_suspended = TRUE; + mldl_cfg->gyro_needs_reset = FALSE; if (mldl_cfg->addr == 0) { #ifdef __KERNEL__ return ML_ERROR_INVALID_PARAMETER; @@ -891,20 +1155,21 @@ int mpu3050_open(struct mldl_cfg *mldl_cfg, * read the product_id, sillicon rev and whoami */ #ifdef M_HW - result = - MLDLPowerMgmtMantis(mldl_cfg, mlsl_handle, RESET, WAKE_UP); + result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle, + RESET, WAKE_UP); #else - result = - MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, RESET, 0, 0, 0, 0); + result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, RESET, 0, 0, 0, 0); #endif ERROR_CHECK(result); result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle); ERROR_CHECK(result); +#ifndef M_HW result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, MPUREG_PRODUCT_ID, 1, &mldl_cfg->product_id); ERROR_CHECK(result); +#endif /* Get the factory temperature compensation offsets */ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, @@ -922,7 +1187,8 @@ int mpu3050_open(struct mldl_cfg *mldl_cfg, /* Configure the MPU */ #ifdef M_HW - result = MLDLPowerMgmtMantis(mldl_cfg, mlsl_handle, 0, SLEEP); + result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle, + FALSE, SLEEP); #else result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, SLEEP, 0, 0, 0); @@ -931,26 +1197,25 @@ int mpu3050_open(struct mldl_cfg *mldl_cfg, if (mldl_cfg->accel && mldl_cfg->accel->init) { result = mldl_cfg->accel->init(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel); + mldl_cfg->accel, + &mldl_cfg->pdata->accel); ERROR_CHECK(result); } if (mldl_cfg->compass && mldl_cfg->compass->init) { result = mldl_cfg->compass->init(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); + mldl_cfg->compass, + &mldl_cfg->pdata->compass); if (ML_SUCCESS != result) { MPL_LOGE("mldl_cfg->compass->init returned %d\n", result); goto out_accel; } } - if (mldl_cfg->pressure && mldl_cfg->pressure->init) { result = mldl_cfg->pressure->init(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure); + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure); if (ML_SUCCESS != result) { MPL_LOGE("mldl_cfg->pressure->init returned %d\n", result); @@ -958,6 +1223,16 @@ int mpu3050_open(struct mldl_cfg *mldl_cfg, } } + mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO; + if (mldl_cfg->accel && mldl_cfg->accel->resume) + mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL; + + if (mldl_cfg->compass && mldl_cfg->compass->resume) + mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS; + + if (mldl_cfg->pressure && mldl_cfg->pressure->resume) + mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE; + return result; out_compass: @@ -1028,7 +1303,10 @@ int mpu3050_close(struct mldl_cfg *mldl_cfg, /** * @brief resume the MPU3050 device and all the other sensor * devices from their low power state. - * @param mlsl_handle + * + * @param mldl_cfg + * pointer to the configuration structure + * @param gyro_handle * the main file handle to the MPU3050 device. * @param accel_handle * an handle to the accelerometer device, if sitting @@ -1045,6 +1323,10 @@ int mpu3050_close(struct mldl_cfg *mldl_cfg, * onto a separate bus. Can match mlsl_handle if * the pressure sensor device operates on the same * primary bus of MPU. + * @param resume_gyro + * whether resuming the gyroscope device is + * actually needed (if the device supports low power + * mode of some sort). * @param resume_accel * whether resuming the accelerometer device is * actually needed (if the device supports low power @@ -1060,318 +1342,131 @@ int mpu3050_close(struct mldl_cfg *mldl_cfg, * @return ML_SUCCESS or a non-zero error code. */ int mpu3050_resume(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, + void *gyro_handle, void *accel_handle, void *compass_handle, void *pressure_handle, - bool resume_accel, bool resume_compass, bool resume_pressure) + bool resume_gyro, + bool resume_accel, + bool resume_compass, + bool resume_pressure) { - int result; - int ii; - int jj; - unsigned char reg; - unsigned char regs[7]; - + int result = ML_SUCCESS; -#ifdef CONFIG_SENSORS_MPU_DEBUG +#ifdef CONFIG_MPU_SENSORS_DEBUG mpu_print_cfg(mldl_cfg); #endif - /* Wake up the part */ -#ifdef M_HW - result = MLDLPowerMgmtMantis(mldl_cfg, mlsl_handle, 0, WAKE_UP); -#else - result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 1, 0, - mldl_cfg->gyro_power & BIT_STBY_XG, - mldl_cfg->gyro_power & BIT_STBY_YG, - mldl_cfg->gyro_power & BIT_STBY_ZG); -#endif - ERROR_CHECK(result); - - /* Configure the MPU */ -#ifdef M_HW - result = MLDLSetI2CBypass(mldl_cfg, mlsl_handle, 1); - ERROR_CHECK(result); - result = MLDLPowerMgmtMantis(mldl_cfg, mlsl_handle, RESET, SLEEP); - ERROR_CHECK(result); - result = MLDLPowerMgmtMantis(mldl_cfg, mlsl_handle, 0, WAKE_UP); - ERROR_CHECK(result); - /* setting int_config with the propert flag BIT_BYPASS_EN should be - done by the setup functions */ - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_INT_PIN_CFG, - (mldl_cfg->pdata->int_config | - BIT_BYPASS_EN)); - ERROR_CHECK(result); - /* temporary: masking out higher bits to avoid switching intelligence */ - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_INT_ENABLE, - (mldl_cfg->int_config & 0x0f)); - ERROR_CHECK(result); -#else - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_INT_CFG, - (mldl_cfg-> - int_config | mldl_cfg->pdata-> - int_config)); - ERROR_CHECK(result); -#endif - - result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr, - MPUREG_PWR_MGM, 1, ®); - ERROR_CHECK(result); - reg &= ~BITS_CLKSEL; - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_PWR_MGM, - mldl_cfg->clk_src | reg); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_SMPLRT_DIV, - mldl_cfg->divider); - ERROR_CHECK(result); - -#ifdef M_HW - reg = DLPF_FS_SYNC_VALUE(0, mldl_cfg->full_scale, 0); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_GYRO_CONFIG, reg); - reg = DLPF_FS_SYNC_VALUE(0, 0, mldl_cfg->lpf); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_CONFIG, reg); -#else - reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, - mldl_cfg->full_scale, mldl_cfg->lpf); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_DLPF_FS_SYNC, reg); -#endif - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_DMP_CFG_1, - mldl_cfg->dmp_cfg1); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_DMP_CFG_2, - mldl_cfg->dmp_cfg2); - ERROR_CHECK(result); - - /* Write and verify memory */ - for (ii = 0; ii < MPU_MEM_NUM_RAM_BANKS; ii++) { - unsigned char read[MPU_MEM_BANK_SIZE]; + if (resume_accel && + ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume))) + return ML_ERROR_INVALID_PARAMETER; + if (resume_compass && + ((!mldl_cfg->compass) || (!mldl_cfg->compass->resume))) + return ML_ERROR_INVALID_PARAMETER; + if (resume_pressure && + ((!mldl_cfg->pressure) || (!mldl_cfg->pressure->resume))) + return ML_ERROR_INVALID_PARAMETER; - result = MLSLSerialWriteMem(mlsl_handle, mldl_cfg->addr, - ((ii << 8) | 0x00), - MPU_MEM_BANK_SIZE, - mldl_cfg->ram[ii]); - ERROR_CHECK(result); - result = MLSLSerialReadMem(mlsl_handle, mldl_cfg->addr, - ((ii << 8) | 0x00), - MPU_MEM_BANK_SIZE, read); + if (resume_gyro && mldl_cfg->gyro_is_suspended) { + result = gyro_resume(mldl_cfg, gyro_handle); ERROR_CHECK(result); - -#ifdef M_HW -#define ML_SKIP_CHECK 38 -#else -#define ML_SKIP_CHECK 20 -#endif - for (jj = 0; jj < MPU_MEM_BANK_SIZE; jj++) { - /* skip the register memory locations */ - if (ii == 0 && jj < ML_SKIP_CHECK) - continue; - if (mldl_cfg->ram[ii][jj] != read[jj]) { - result = ML_ERROR_SERIAL_WRITE; - break; - } - } - ERROR_CHECK(result); - } - - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_XG_OFFS_TC, - mldl_cfg->offset_tc[0]); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_YG_OFFS_TC, - mldl_cfg->offset_tc[1]); - ERROR_CHECK(result); - result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr, - MPUREG_ZG_OFFS_TC, - mldl_cfg->offset_tc[2]); - ERROR_CHECK(result); - - regs[0] = MPUREG_X_OFFS_USRH; - for (ii = 0; ii < DIM(mldl_cfg->offset); ii++) { - regs[1 + ii * 2] = - (unsigned char)(mldl_cfg->offset[ii] >> 8) & 0xff; - regs[1 + ii * 2 + 1] = - (unsigned char)(mldl_cfg->offset[ii] & 0xff); } - result = MLSLSerialWrite(mlsl_handle, mldl_cfg->addr, 7, regs); - ERROR_CHECK(result); - - /* Configure slaves */ - result = MLDLSetLevelShifterBit(mldl_cfg, mlsl_handle, - mldl_cfg->pdata->level_shifter); - ERROR_CHECK(result); - - if (resume_accel) { - if ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume)) - return ML_ERROR_INVALID_PARAMETER; + if (resume_accel && mldl_cfg->accel_is_suspended) { + if (!mldl_cfg->gyro_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); + ERROR_CHECK(result); + } result = mldl_cfg->accel->resume(accel_handle, mldl_cfg->accel, &mldl_cfg->pdata->accel); ERROR_CHECK(result); - if (EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { - /* Address */ - result = - MLSLSerialWriteSingle(accel_handle, - mldl_cfg->addr, - MPUREG_AUX_SLV_ADDR, - mldl_cfg->pdata-> - accel.address); - ERROR_CHECK(result); - /* Register */ - result = - MLSLSerialRead(accel_handle, mldl_cfg->addr, - MPUREG_ACCEL_BURST_ADDR, 1, - ®); - ERROR_CHECK(result); - reg = ((reg & 0x80) | mldl_cfg->accel->reg); - /* Set VDDIO bit for ST accel */ - if ((ACCEL_ID_LIS331 == mldl_cfg->accel->id) - || (ACCEL_ID_LSM303 == mldl_cfg->accel->id)) { - reg |= 0x80; - } - result = - MLSLSerialWriteSingle(accel_handle, - mldl_cfg->addr, - MPUREG_ACCEL_BURST_ADDR, - reg); - ERROR_CHECK(result); - /* Length */ - result = - MLSLSerialRead(accel_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, 1, ®); - ERROR_CHECK(result); - reg = (reg & ~BIT_AUX_RD_LENG); - result = - MLSLSerialWriteSingle(accel_handle, - mldl_cfg->addr, - MPUREG_USER_CTRL, reg); - ERROR_CHECK(result); - result = - MLDLSetI2CBypass(mldl_cfg, accel_handle, 0); - ERROR_CHECK(result); - } + mldl_cfg->accel_is_suspended = FALSE; } - if (resume_compass) { - if ((mldl_cfg->compass) && (mldl_cfg->compass->resume)) { - result = mldl_cfg->compass->resume(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata-> - compass); + if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->accel_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel); + ERROR_CHECK(result); + } + + if (resume_compass && mldl_cfg->compass_is_suspended) { + if (!mldl_cfg->gyro_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); ERROR_CHECK(result); } + result = mldl_cfg->compass->resume(compass_handle, + mldl_cfg->compass, + &mldl_cfg->pdata-> + compass); ERROR_CHECK(result); - if (EXT_SLAVE_BUS_SECONDARY == - mldl_cfg->pdata->compass.bus) { - /* Address */ - result = - MLSLSerialWriteSingle(mlsl_handle, - mldl_cfg->addr, - MPUREG_AUX_SLV_ADDR, - mldl_cfg->pdata-> - compass.address); - ERROR_CHECK(result); - /* Register */ - result = - MLSLSerialRead(mlsl_handle, mldl_cfg->addr, - MPUREG_ACCEL_BURST_ADDR, 1, - ®); - ERROR_CHECK(result); - reg = ((reg & 0x80) | mldl_cfg->compass->reg); - result = - MLSLSerialWriteSingle(mlsl_handle, - mldl_cfg->addr, - MPUREG_ACCEL_BURST_ADDR, - reg); - ERROR_CHECK(result); + mldl_cfg->compass_is_suspended = FALSE; + } -#ifdef M_HW - /* Length, byte swapping, grouping & enable */ - if (mldl_cfg->compass->len > BITS_SLV_LENG) { - MPL_LOGW("Limiting slave burst read length to " - "the allowed maximum (15B, req. %d)\n", - mldl_cfg->compass->len); - mldl_cfg->compass->len = BITS_SLV_LENG; - } - reg = mldl_cfg->compass->len; - if (mldl_cfg->compass->endian == - EXT_SLAVE_LITTLE_ENDIAN) - reg |= BIT_SLV_BYTE_SW; - reg |= BIT_SLV_GRP; - reg |= BIT_SLV_ENABLE; + if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->compass_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass); + ERROR_CHECK(result); + } - result = - MLSLSerialWriteSingle(mlsl_handle, - mldl_cfg->addr, - MPUREG_I2C_SLV0_CTRL, - reg); -#else - /* Length */ - result = - MLSLSerialRead(mlsl_handle, mldl_cfg->addr, - MPUREG_USER_CTRL, 1, ®); - ERROR_CHECK(result); - reg = (reg & ~BIT_AUX_RD_LENG); - result = - MLSLSerialWriteSingle(mlsl_handle, - mldl_cfg->addr, - MPUREG_USER_CTRL, reg); - ERROR_CHECK(result); -#endif - result = - MLDLSetI2CBypass(mldl_cfg, mlsl_handle, 0); + if (resume_pressure && mldl_cfg->pressure_is_suspended) { + if (!mldl_cfg->gyro_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE); ERROR_CHECK(result); } + result = mldl_cfg->pressure->resume(pressure_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata-> + pressure); + ERROR_CHECK(result); + mldl_cfg->pressure_is_suspended = FALSE; } - if (resume_pressure) { - if ((mldl_cfg->pressure) && (mldl_cfg->pressure->resume)) { - result = mldl_cfg->pressure->resume(pressure_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata-> - pressure); - ERROR_CHECK(result); - } + if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->pressure_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { + result = mpu_set_slave(mldl_cfg, + gyro_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure); ERROR_CHECK(result); } /* Now start */ - result = MLDLDmpStart(mldl_cfg, mlsl_handle); - ERROR_CHECK(result); + if (resume_gyro) { + result = dmp_start(mldl_cfg, gyro_handle); + ERROR_CHECK(result); + } + return result; } - /** * @brief suspend the MPU3050 device and all the other sensor * devices into their low power state. - * @param mlsl_handle + * @param gyro_handle * the main file handle to the MPU3050 device. * @param accel_handle * an handle to the accelerometer device, if sitting - * onto a separate bus. Can match mlsl_handle if + * onto a separate bus. Can match gyro_handle if * the accelerometer device operates on the same * primary bus of MPU. * @param compass_handle * an handle to the compass device, if sitting - * onto a separate bus. Can match mlsl_handle if + * onto a separate bus. Can match gyro_handle if * the compass device operates on the same * primary bus of MPU. * @param pressure_handle * an handle to the pressure sensor device, if sitting - * onto a separate bus. Can match mlsl_handle if + * onto a separate bus. Can match gyro_handle if * the pressure sensor device operates on the same * primary bus of MPU. * @param accel @@ -1388,44 +1483,77 @@ int mpu3050_resume(struct mldl_cfg *mldl_cfg, * mode of some sort). * @return ML_SUCCESS or a non-zero error code. */ -int mpu3050_suspend(struct mldl_cfg *mldl_cfg, void *mlsl_handle, +int mpu3050_suspend(struct mldl_cfg *mldl_cfg, + void *gyro_handle, void *accel_handle, void *compass_handle, void *pressure_handle, - bool accel, bool compass, bool pressure) + bool suspend_gyro, + bool suspend_accel, + bool suspend_compass, + bool suspend_pressure) { - int result; - /* This puts the bus into bypass mode */ + int result = ML_SUCCESS; + if (suspend_gyro && !mldl_cfg->gyro_is_suspended) { #ifdef M_HW - result = MLDLSetI2CBypass(mldl_cfg, mlsl_handle, 1); - ERROR_CHECK(result); - result = MLDLPowerMgmtMantis(mldl_cfg, mlsl_handle, 0, SLEEP); + return ML_SUCCESS; + /* This puts the bus into bypass mode */ + result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1); + ERROR_CHECK(result); + result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP); #else - result = - MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, SLEEP, 0, 0, 0); + result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, + 0, SLEEP, 0, 0, 0); #endif - if (ML_SUCCESS == result && - accel && mldl_cfg->accel && mldl_cfg->accel->suspend) { + ERROR_CHECK(result); + } + + if (!mldl_cfg->accel_is_suspended && suspend_accel && + mldl_cfg->accel && mldl_cfg->accel->suspend) { + if (!mldl_cfg->gyro_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) { + result = mpu_set_slave(mldl_cfg, gyro_handle, + NULL, NULL); + ERROR_CHECK(result); + } result = mldl_cfg->accel->suspend(accel_handle, mldl_cfg->accel, &mldl_cfg->pdata->accel); + ERROR_CHECK(result); + mldl_cfg->accel_is_suspended = TRUE; } - if (ML_SUCCESS == result && compass && + if (!mldl_cfg->compass_is_suspended && suspend_compass && mldl_cfg->compass && mldl_cfg->compass->suspend) { + if (!mldl_cfg->gyro_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) { + result = mpu_set_slave(mldl_cfg, gyro_handle, + NULL, NULL); + ERROR_CHECK(result); + } result = mldl_cfg->compass->suspend(compass_handle, mldl_cfg->compass, &mldl_cfg-> pdata->compass); + ERROR_CHECK(result); + mldl_cfg->compass_is_suspended = TRUE; } - if (ML_SUCCESS == result && pressure && + if (!mldl_cfg->pressure_is_suspended && suspend_pressure && mldl_cfg->pressure && mldl_cfg->pressure->suspend) { + if (!mldl_cfg->gyro_is_suspended && + EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) { + result = mpu_set_slave(mldl_cfg, gyro_handle, + NULL, NULL); + ERROR_CHECK(result); + } result = mldl_cfg->pressure->suspend(pressure_handle, mldl_cfg->pressure, &mldl_cfg-> pdata->pressure); + ERROR_CHECK(result); + mldl_cfg->pressure_is_suspended = TRUE; } return result; } @@ -1434,18 +1562,26 @@ int mpu3050_suspend(struct mldl_cfg *mldl_cfg, void *mlsl_handle, /** * @brief read raw sensor data from the accelerometer device * in use. + * @param mldl_cfg + * A pointer to the struct mldl_cfg data structure. + * @param accel_handle + * The handle to the device the accelerometer is connected to. * @param data * a buffer to store the raw sensor data. * @return ML_SUCCESS if successful, a non-zero error code otherwise. */ int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, unsigned char *data) + void *accel_handle, unsigned char *data) { if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read) - return mldl_cfg->accel->read(mlsl_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - data); + if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) + && (!mldl_cfg->gyro_is_bypassed)) + return ML_ERROR_FEATURE_NOT_ENABLED; + else + return mldl_cfg->accel->read(accel_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -1453,18 +1589,26 @@ int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, /** * @brief read raw sensor data from the compass device * in use. + * @param mldl_cfg + * A pointer to the struct mldl_cfg data structure. + * @param compass_handle + * The handle to the device the compass is connected to. * @param data * a buffer to store the raw sensor data. * @return ML_SUCCESS if successful, a non-zero error code otherwise. */ int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, unsigned char *data) + void *compass_handle, unsigned char *data) { if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read) - return mldl_cfg->compass->read(mlsl_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - data); + if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) + && (!mldl_cfg->gyro_is_bypassed)) + return ML_ERROR_FEATURE_NOT_ENABLED; + else + return mldl_cfg->compass->read(compass_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -1472,18 +1616,27 @@ int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, /** * @brief read raw sensor data from the pressure device * in use. + * @param mldl_cfg + * A pointer to the struct mldl_cfg data structure. + * @param pressure_handle + * The handle to the device the pressure sensor is connected to. * @param data * a buffer to store the raw sensor data. * @return ML_SUCCESS if successful, a non-zero error code otherwise. */ int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, unsigned char *data) + void *pressure_handle, unsigned char *data) { if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->read) - return mldl_cfg->pressure->read(mlsl_handle, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - data); + if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) + && (!mldl_cfg->gyro_is_bypassed)) + return ML_ERROR_FEATURE_NOT_ENABLED; + else + return mldl_cfg->pressure->read( + pressure_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; } @@ -1494,9 +1647,9 @@ int mpu3050_config_accel(struct mldl_cfg *mldl_cfg, { if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->config) return mldl_cfg->accel->config(accel_handle, - mldl_cfg->accel, - &mldl_cfg->pdata->accel, - data); + mldl_cfg->accel, + &mldl_cfg->pdata->accel, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; @@ -1508,9 +1661,9 @@ int mpu3050_config_compass(struct mldl_cfg *mldl_cfg, { if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->config) return mldl_cfg->compass->config(compass_handle, - mldl_cfg->compass, - &mldl_cfg->pdata->compass, - data); + mldl_cfg->compass, + &mldl_cfg->pdata->compass, + data); else return ML_ERROR_FEATURE_NOT_IMPLEMENTED; @@ -1522,6 +1675,48 @@ int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg, { if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->config) return mldl_cfg->pressure->config(pressure_handle, + mldl_cfg->pressure, + &mldl_cfg->pdata->pressure, + data); + else + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; +} + +int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg, + void *accel_handle, + struct ext_slave_config *data) +{ + if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->get_config) + return mldl_cfg->accel->get_config(accel_handle, + mldl_cfg->accel, + &mldl_cfg->pdata->accel, + data); + else + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + +} + +int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg, + void *compass_handle, + struct ext_slave_config *data) +{ + if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->get_config) + return mldl_cfg->compass->get_config(compass_handle, + mldl_cfg->compass, + &mldl_cfg->pdata->compass, + data); + else + return ML_ERROR_FEATURE_NOT_IMPLEMENTED; + +} + +int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg, + void *pressure_handle, + struct ext_slave_config *data) +{ + if (NULL != mldl_cfg->pressure && + NULL != mldl_cfg->pressure->get_config) + return mldl_cfg->pressure->get_config(pressure_handle, mldl_cfg->pressure, &mldl_cfg->pdata->pressure, data); diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h index d714a0ee3ed8..ee3a1e3dd05f 100644 --- a/drivers/misc/mpu3050/mldl_cfg.h +++ b/drivers/misc/mpu3050/mldl_cfg.h @@ -39,12 +39,52 @@ /* - Defines. - */ /* --------------------- */ -#define SAMPLING_PERIOD(mldl_cfg) \ - (((((mldl_cfg->lpf) == 0) || ((mldl_cfg->lpf) == 7)) \ + /*************************************************************************/ + /* Sensors */ + /*************************************************************************/ + +#define ML_X_GYRO (0x0001) +#define ML_Y_GYRO (0x0002) +#define ML_Z_GYRO (0x0004) +#define ML_DMP_PROCESSOR (0x0008) + +#define ML_X_ACCEL (0x0010) +#define ML_Y_ACCEL (0x0020) +#define ML_Z_ACCEL (0x0040) + +#define ML_X_COMPASS (0x0080) +#define ML_Y_COMPASS (0x0100) +#define ML_Z_COMPASS (0x0200) + +#define ML_X_PRESSURE (0x0300) +#define ML_Y_PRESSURE (0x0800) +#define ML_Z_PRESSURE (0x1000) + +#define ML_TEMPERATURE (0x2000) +#define ML_TIME (0x4000) + +#define ML_THREE_AXIS_GYRO (0x000F) +#define ML_THREE_AXIS_ACCEL (0x0070) +#define ML_THREE_AXIS_COMPASS (0x0380) +#define ML_THREE_AXIS_PRESSURE (0x1C00) + +#define ML_FIVE_AXIS (0x007B) +#define ML_SIX_AXIS_GYRO_ACCEL (0x007F) +#define ML_SIX_AXIS_ACCEL_COMPASS (0x03F0) +#define ML_NINE_AXIS (0x03FF) +#define ML_ALL_SENSORS (0x7FFF) + +#define SAMPLING_RATE_HZ(mldl_cfg) \ + ((((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \ ? (8000) \ : (1000)) \ - / (mldl_cfg->divider + 1)) + / ((mldl_cfg)->divider + 1)) +#define SAMPLING_PERIOD_US(mldl_cfg) \ + ((1000000L * ((mldl_cfg)->divider + 1)) / \ + (((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \ + ? (8000) \ + : (1000))) /* --------------------- */ /* - Variables. - */ /* --------------------- */ @@ -52,6 +92,7 @@ /* Platform data for the MPU */ struct mldl_cfg { /* MPU related configuration */ + unsigned long requested_sensors; unsigned char addr; unsigned char int_config; unsigned char ext_sync; @@ -74,13 +115,20 @@ struct mldl_cfg { unsigned short trim; /* Driver/Kernel related state information */ - int is_suspended; + int gyro_is_bypassed; + int dmp_is_running; + int gyro_is_suspended; + int accel_is_suspended; + int compass_is_suspended; + int pressure_is_suspended; + int gyro_needs_reset; /* Slave related information */ struct ext_slave_descr *accel; struct ext_slave_descr *compass; struct ext_slave_descr *pressure; + /* Platform Data */ struct mpu3050_platform_data *pdata; }; @@ -96,20 +144,23 @@ int mpu3050_close(struct mldl_cfg *mldl_cfg, void *compass_handle, void *pressure_handle); int mpu3050_resume(struct mldl_cfg *mldl_cfg, - void *mlsl_handle, + void *gyro_handle, void *accel_handle, void *compass_handle, void *pressure_handle, + bool resume_gyro, bool resume_accel, bool resume_compass, bool resume_pressure); -int mpu3050_suspend(struct mldl_cfg *mldl_cfg, void *mlsl_handle, +int mpu3050_suspend(struct mldl_cfg *mldl_cfg, + void *gyro_handle, void *accel_handle, void *compass_handle, void *pressure_handle, - bool resume_accel, - bool resume_compass, - bool resume_pressure); + bool suspend_gyro, + bool suspend_accel, + bool suspend_compass, + bool suspend_pressure); int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, void *accel_handle, unsigned char *data); @@ -129,6 +180,16 @@ int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg, void *pressure_handle, struct ext_slave_config *data); +int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg, + void *accel_handle, + struct ext_slave_config *data); +int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg, + void *compass_handle, + struct ext_slave_config *data); +int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg, + void *pressure_handle, + struct ext_slave_config *data); + #endif /* __MLDL_CFG_H__ */ diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h index 447e208ee0a5..5c1b684e5b50 100644 --- a/drivers/misc/mpu3050/mltypes.h +++ b/drivers/misc/mpu3050/mltypes.h @@ -16,11 +16,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. $ */ -/****************************************************************************** - * - * $Id: mltypes.h 4436 2011-01-13 05:07:53Z mcaramello $ - * - *****************************************************************************/ /** * @defgroup MLERROR @@ -68,6 +63,7 @@ * - (70) ML_ERROR_COMPASS_DATA_OVERFLOW * - (71) ML_ERROR_COMPASS_DATA_UNDERFLOW * - (72) ML_ERROR_COMPASS_DATA_NOT_READY + * - (73) ML_ERROR_COMPASS_DATA_ERROR * - (75) ML_ERROR_CALIBRATION_LOAD * - (76) ML_ERROR_CALIBRATION_STORE * - (77) ML_ERROR_CALIBRATION_LEN @@ -93,11 +89,12 @@ ---------------------------*/ /** - * @struct tMLError The MPL Error Code return type. + * @struct tMLError mltypes.h "mltypes" + * @brief The MPL Error Code return type. * - * @code + * @code * typedef unsigned char tMLError; - * @endcode + * @endcode */ typedef unsigned char tMLError; @@ -204,6 +201,7 @@ typedef int_fast8_t bool; #define ML_ERROR_COMPASS_DATA_OVERFLOW (70) #define ML_ERROR_COMPASS_DATA_UNDERFLOW (71) #define ML_ERROR_COMPASS_DATA_NOT_READY (72) +#define ML_ERROR_COMPASS_DATA_ERROR (73) /* Load/Store calibration */ #define ML_ERROR_CALIBRATION_LOAD (75) @@ -211,9 +209,15 @@ typedef int_fast8_t bool; #define ML_ERROR_CALIBRATION_LEN (77) #define ML_ERROR_CALIBRATION_CHECKSUM (78) +/* Accel errors */ +#define ML_ERROR_ACCEL_DATA_OVERFLOW (79) +#define ML_ERROR_ACCEL_DATA_UNDERFLOW (80) +#define ML_ERROR_ACCEL_DATA_NOT_READY (81) +#define ML_ERROR_ACCEL_DATA_ERROR (82) + /* For Linux coding compliance */ #ifndef __KERNEL__ -#define EXPORT_SYMBOL(x) +#define EXPORT_SYMBOL(x) #endif /*--------------------------- diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c index 6cde9eeccced..115639f84704 100644 --- a/drivers/misc/mpu3050/mpu-dev.c +++ b/drivers/misc/mpu3050/mpu-dev.c @@ -73,6 +73,10 @@ static struct i2c_client *this_client; static int mpu_open(struct inode *inode, struct file *file) { + struct mpu_private_data *mpu = + (struct mpu_private_data *) i2c_get_clientdata(this_client); + struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + dev_dbg(&this_client->adapter->dev, "mpu_open\n"); dev_dbg(&this_client->adapter->dev, "current->pid %d\n", current->pid); @@ -81,6 +85,18 @@ static int mpu_open(struct inode *inode, struct file *file) /* we could do some checking on the flags supplied by "open" */ /* i.e. O_NONBLOCK */ /* -> set some flag to disable interruptible_sleep_on in mpu_read */ + + /* Reset the sensors to the default */ + mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO; + if (mldl_cfg->accel && mldl_cfg->accel->resume) + mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL; + + if (mldl_cfg->compass && mldl_cfg->compass->resume) + mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS; + + if (mldl_cfg->pressure && mldl_cfg->pressure->resume) + mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE; + return 0; } @@ -92,26 +108,20 @@ static int mpu_release(struct inode *inode, struct file *file) struct mpu_private_data *mpu = (struct mpu_private_data *) i2c_get_clientdata(client); struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct i2c_adapter *accel_adapter; + struct i2c_adapter *compass_adapter; + struct i2c_adapter *pressure_adapter; int result = 0; pid = 0; - if (!mldl_cfg->is_suspended) { - struct i2c_adapter *accel_adapter; - struct i2c_adapter *compass_adapter; - struct i2c_adapter *pressure_adapter; - accel_adapter = - i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); - compass_adapter = - i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); - pressure_adapter = - i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - result = - mpu3050_suspend(mldl_cfg, client->adapter, - accel_adapter, compass_adapter, - pressure_adapter, - TRUE, TRUE, TRUE); - } + accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num); + compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num); + pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); + result = mpu3050_suspend(mldl_cfg, client->adapter, + accel_adapter, compass_adapter, + pressure_adapter, + TRUE, TRUE, TRUE, TRUE); dev_dbg(&this_client->adapter->dev, "mpu_release\n"); return result; @@ -220,8 +230,11 @@ static ssize_t mpu_read(struct file *file, /* @todo fix this to do a i2c trasnfer from the FIFO */ ret = i2c_master_recv(client, tmp, count); - if (ret >= 0) + if (ret >= 0) { ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret; + if (ret) + ret = -EFAULT; + } kfree(tmp); return ret; } @@ -230,15 +243,14 @@ static int mpu_ioctl_set_mpu_pdata(struct i2c_client *client, unsigned long arg) { int ii; - int result; struct mpu_private_data *mpu = (struct mpu_private_data *) i2c_get_clientdata(client); struct mpu3050_platform_data *pdata = mpu->mldl_cfg.pdata; struct mpu3050_platform_data local_pdata; - result = copy_from_user(&local_pdata, - (unsigned char *) arg, - sizeof(local_pdata)); + if (copy_from_user(&local_pdata, (unsigned char __user *) arg, + sizeof(local_pdata))) + return -EFAULT; pdata->int_config = local_pdata.int_config; for (ii = 0; ii < DIM(pdata->orientation); ii++) @@ -262,27 +274,93 @@ mpu_ioctl_set_mpu_pdata(struct i2c_client *client, unsigned long arg) dev_dbg(&client->adapter->dev, "%s\n", __func__); - return result; + return ML_SUCCESS; } static int mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg) { + int ii; + int result = ML_SUCCESS; struct mpu_private_data *mpu = - (struct mpu_private_data *) i2c_get_clientdata(client); + (struct mpu_private_data *) i2c_get_clientdata(client); struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg; + struct mldl_cfg *temp_mldl_cfg; dev_dbg(&this_client->adapter->dev, "%s\n", __func__); + temp_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL); + if (NULL == temp_mldl_cfg) + return -ENOMEM; + /* * User space is not allowed to modify accel compass pressure or * pdata structs, as well as silicon_revision product_id or trim */ - if (copy_from_user(mldl_cfg, (struct mldl_cfg *) arg, - offsetof(struct mldl_cfg, silicon_revision))) - return -EFAULT; + if (copy_from_user(temp_mldl_cfg, (struct mldl_cfg __user *) arg, + offsetof(struct mldl_cfg, silicon_revision))) { + result = -EFAULT; + goto out; + } - return 0; + if (mldl_cfg->gyro_is_suspended) { + if (mldl_cfg->addr != temp_mldl_cfg->addr) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->int_config != temp_mldl_cfg->int_config) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->ext_sync != temp_mldl_cfg->ext_sync) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->full_scale != temp_mldl_cfg->full_scale) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->lpf != temp_mldl_cfg->lpf) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->clk_src != temp_mldl_cfg->clk_src) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->divider != temp_mldl_cfg->divider) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->dmp_enable != temp_mldl_cfg->dmp_enable) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->fifo_enable != temp_mldl_cfg->fifo_enable) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->dmp_cfg1 != temp_mldl_cfg->dmp_cfg1) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->dmp_cfg2 != temp_mldl_cfg->dmp_cfg2) + mldl_cfg->gyro_needs_reset = TRUE; + + if (mldl_cfg->gyro_power != temp_mldl_cfg->gyro_power) + mldl_cfg->gyro_needs_reset = TRUE; + + for (ii = 0; ii < MPU_NUM_AXES; ii++) + if (mldl_cfg->offset_tc[ii] != + temp_mldl_cfg->offset_tc[ii]) + mldl_cfg->gyro_needs_reset = TRUE; + + for (ii = 0; ii < MPU_NUM_AXES; ii++) + if (mldl_cfg->offset[ii] != temp_mldl_cfg->offset[ii]) + mldl_cfg->gyro_needs_reset = TRUE; + + if (memcmp(mldl_cfg->ram, temp_mldl_cfg->ram, + MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE * + sizeof(unsigned char))) + mldl_cfg->gyro_needs_reset = TRUE; + } + + memcpy(mldl_cfg, temp_mldl_cfg, + offsetof(struct mldl_cfg, silicon_revision)); + +out: + kfree(temp_mldl_cfg); + return result; } static int @@ -301,53 +379,189 @@ mpu_ioctl_get_mpu_config(struct i2c_client *client, unsigned long arg) return -ENOMEM; retval = - copy_from_user(local_mldl_cfg, (void *) arg, + copy_from_user(local_mldl_cfg, (struct mldl_cfg __user *) arg, sizeof(struct mldl_cfg)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on arg\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } /* Fill in the accel, compass, pressure and pdata pointers */ if (mldl_cfg->accel) { - retval = copy_to_user(local_mldl_cfg->accel, + retval = copy_to_user((void __user *)local_mldl_cfg->accel, mldl_cfg->accel, sizeof(*mldl_cfg->accel)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on accel\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } if (mldl_cfg->compass) { - retval = copy_to_user(local_mldl_cfg->compass, + retval = copy_to_user((void __user *)local_mldl_cfg->compass, mldl_cfg->compass, sizeof(*mldl_cfg->compass)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on compass\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } if (mldl_cfg->pressure) { - retval = copy_to_user(local_mldl_cfg->pressure, + retval = copy_to_user((void __user *)local_mldl_cfg->pressure, mldl_cfg->pressure, sizeof(*mldl_cfg->pressure)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on pressure\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } if (mldl_cfg->pdata) { - retval = copy_to_user(local_mldl_cfg->pdata, + retval = copy_to_user((void __user *)local_mldl_cfg->pdata, mldl_cfg->pdata, sizeof(*mldl_cfg->pdata)); - if (retval) + if (retval) { + dev_err(&this_client->adapter->dev, + "%s|%s:%d: EFAULT on pdata\n", + __FILE__, __func__, __LINE__); + retval = -EFAULT; goto out; + } } /* Do not modify the accel, compass, pressure and pdata pointers */ - retval = copy_to_user((struct mldl_cfg *) arg, + retval = copy_to_user((struct mldl_cfg __user *) arg, mldl_cfg, offsetof(struct mldl_cfg, accel)); + if (retval) + retval = -EFAULT; out: kfree(local_mldl_cfg); return retval; } +/** + * Pass a requested slave configuration to the slave sensor + * + * @param adapter the adaptor to use to communicate with the slave + * @param mldl_cfg the mldl configuration structuer + * @param slave pointer to the slave descriptor + * @param usr_config The configuration to pass to the slave sensor + * + * @return 0 or non-zero error code + */ +static int slave_config(void *adapter, + struct mldl_cfg *mldl_cfg, + struct ext_slave_descr *slave, + struct ext_slave_config __user *usr_config) +{ + int retval = ML_SUCCESS; + if ((slave) && (slave->config)) { + struct ext_slave_config config; + retval = copy_from_user( + &config, + usr_config, + sizeof(config)); + if (retval) + return -EFAULT; + + if (config.len && config.data) { + int *data; + data = kzalloc(config.len, GFP_KERNEL); + if (!data) + return ML_ERROR_MEMORY_EXAUSTED; + + retval = copy_from_user(data, + (void __user *)config.data, + config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = slave->config(adapter, + slave, + &mldl_cfg->pdata->accel, + &config); + kfree(config.data); + } + return retval; +} + +/** + * Get a requested slave configuration from the slave sensor + * + * @param adapter the adaptor to use to communicate with the slave + * @param mldl_cfg the mldl configuration structuer + * @param slave pointer to the slave descriptor + * @param usr_config The configuration for the slave to fill out + * + * @return 0 or non-zero error code + */ +static int slave_get_config(void *adapter, + struct mldl_cfg *mldl_cfg, + struct ext_slave_descr *slave, + struct ext_slave_config __user *usr_config) +{ + int retval = ML_SUCCESS; + if ((slave) && (slave->get_config)) { + struct ext_slave_config config; + void *user_data; + retval = copy_from_user( + &config, + usr_config, + sizeof(config)); + if (retval) + return -EFAULT; + + user_data = config.data; + if (config.len && config.data) { + int *data; + data = kzalloc(config.len, GFP_KERNEL); + if (!data) + return ML_ERROR_MEMORY_EXAUSTED; + + retval = copy_from_user(data, + (void __user *)config.data, + config.len); + if (retval) { + retval = -EFAULT; + kfree(data); + return retval; + } + config.data = data; + } + retval = slave->get_config(adapter, + slave, + &mldl_cfg->pdata->accel, + &config); + if (retval) { + kfree(config.data); + return retval; + } + retval = copy_to_user((unsigned char __user *) user_data, + config.data, + config.len); + kfree(config.data); + } + return retval; +} + /* ioctl - I/O control */ static long mpu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -417,13 +631,18 @@ static long mpu_ioctl(struct file *file, break; case MPU_SET_OFFSET_TC: retval = copy_from_user(mldl_cfg->offset_tc, - (unsigned char *) arg, + (unsigned char __user *) arg, sizeof(mldl_cfg->offset_tc)); + if (retval) + retval = -EFAULT; + break; case MPU_SET_RAM: retval = copy_from_user(mldl_cfg->ram, - (unsigned char *) arg, + (unsigned char __user *) arg, sizeof(mldl_cfg->ram)); + if (retval) + retval = -EFAULT; break; case MPU_SET_PLATFORM_DATA: retval = mpu_ioctl_set_mpu_pdata(client, arg); @@ -432,282 +651,169 @@ static long mpu_ioctl(struct file *file, retval = mpu_ioctl_get_mpu_config(client, arg); break; case MPU_GET_INT_CONFIG: - mldl_cfg->int_config = (unsigned char) arg; + retval = put_user(mldl_cfg->int_config, + (unsigned char __user *) arg); break; case MPU_GET_EXT_SYNC: - mldl_cfg->ext_sync = (enum mpu_ext_sync) arg; + retval = put_user(mldl_cfg->ext_sync, + (unsigned char __user *) arg); break; case MPU_GET_FULL_SCALE: - mldl_cfg->full_scale = (enum mpu_fullscale) arg; + retval = put_user(mldl_cfg->full_scale, + (unsigned char __user *) arg); break; case MPU_GET_LPF: - mldl_cfg->lpf = (enum mpu_filter) arg; + retval = put_user(mldl_cfg->lpf, + (unsigned char __user *) arg); break; case MPU_GET_CLK_SRC: - mldl_cfg->clk_src = (enum mpu_clock_sel) arg; + retval = put_user(mldl_cfg->clk_src, + (unsigned char __user *) arg); break; case MPU_GET_DIVIDER: - mldl_cfg->divider = (unsigned char) arg; + retval = put_user(mldl_cfg->divider, + (unsigned char __user *) arg); break; case MPU_GET_LEVEL_SHIFTER: - mldl_cfg->pdata->level_shifter = (unsigned char) arg; + retval = put_user(mldl_cfg->pdata->level_shifter, + (unsigned char __user *) arg); break; case MPU_GET_DMP_ENABLE: - mldl_cfg->dmp_enable = (unsigned char) arg; + retval = put_user(mldl_cfg->dmp_enable, + (unsigned char __user *) arg); break; case MPU_GET_FIFO_ENABLE: - mldl_cfg->fifo_enable = (unsigned char) arg; + retval = put_user(mldl_cfg->fifo_enable, + (unsigned char __user *) arg); break; case MPU_GET_DMP_CFG1: - mldl_cfg->dmp_cfg1 = (unsigned char) arg; + retval = put_user(mldl_cfg->dmp_cfg1, + (unsigned char __user *) arg); break; case MPU_GET_DMP_CFG2: - mldl_cfg->dmp_cfg2 = (unsigned char) arg; + retval = put_user(mldl_cfg->dmp_cfg2, + (unsigned char __user *) arg); break; case MPU_GET_OFFSET_TC: - retval = copy_to_user((unsigned char *) arg, + retval = copy_to_user((unsigned char __user *) arg, mldl_cfg->offset_tc, sizeof(mldl_cfg->offset_tc)); + if (retval) + retval = -EFAULT; break; case MPU_GET_RAM: - retval = copy_to_user((unsigned char *) arg, + retval = copy_to_user((unsigned char __user *) arg, mldl_cfg->ram, sizeof(mldl_cfg->ram)); + if (retval) + retval = -EFAULT; break; case MPU_CONFIG_ACCEL: - { - if ((mldl_cfg->accel) && (mldl_cfg->accel->config)) { - struct ext_slave_config config; - retval = copy_from_user( - &config, - (struct ext_slave_config *)arg, - sizeof(config)); - if (retval) - break; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) { - retval = ML_ERROR_MEMORY_EXAUSTED; - break; - } - retval = copy_from_user(data, - (void *)config.data, - config.len); - if (retval) { - kfree(data); - break; - } - config.data = data; - } - retval = mldl_cfg->accel->config( - accel_adapter, + retval = slave_config(accel_adapter, mldl_cfg, mldl_cfg->accel, - &mldl_cfg->pdata->accel, - &config); - kfree(config.data); - } + (struct ext_slave_config __user *) arg); break; - } case MPU_CONFIG_COMPASS: - { - if ((mldl_cfg->compass) && (mldl_cfg->compass->config)) { - struct ext_slave_config config; - retval = copy_from_user( - &config, - (struct ext_slave_config *)arg, - sizeof(config)); - if (retval) - break; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) { - retval = ML_ERROR_MEMORY_EXAUSTED; - break; - } - retval = copy_from_user(data, - (void *)config.data, - config.len); - if (retval) { - kfree(data); - break; - } - config.data = data; - } - retval = mldl_cfg->compass->config( - compass_adapter, + retval = slave_config(compass_adapter, mldl_cfg, mldl_cfg->compass, - &mldl_cfg->pdata->compass, - &config); - kfree(config.data); - } + (struct ext_slave_config __user *) arg); break; - } case MPU_CONFIG_PRESSURE: - { - if ((mldl_cfg->pressure) && (mldl_cfg->pressure->config)) { - struct ext_slave_config config; - retval = copy_from_user( - &config, - (struct ext_slave_config *)arg, - sizeof(config)); - if (retval) - break; - - if (config.len && config.data) { - int *data; - data = kzalloc(config.len, GFP_KERNEL); - if (!data) { - retval = ML_ERROR_MEMORY_EXAUSTED; - break; - } - retval = copy_from_user(data, - (void *)config.data, - config.len); - if (retval) { - kfree(data); - break; - } - config.data = data; - } - retval = mldl_cfg->pressure->config( - pressure_adapter, + retval = slave_config(pressure_adapter, mldl_cfg, mldl_cfg->pressure, - &mldl_cfg->pdata->pressure, - &config); - kfree(config.data); - } + (struct ext_slave_config __user *) arg); break; - } - case MPU_READ_MEMORY: - case MPU_WRITE_MEMORY: - case MPU_SUSPEND: - { - struct mpu_suspend_resume suspend; - retval = - copy_from_user(&suspend, - (struct mpu_suspend_resume *) - arg, sizeof(suspend)); - if (retval) - break; - if (suspend.gyro) { - retval = - mpu3050_suspend(mldl_cfg, - client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - suspend.accel, - suspend.compass, - suspend.pressure); - } else { - /* Cannot suspend the pressure compass or - * accel while the MPU is running */ - retval = ML_ERROR_FEATURE_NOT_IMPLEMENTED; - } - } + case MPU_GET_CONFIG_ACCEL: + retval = slave_get_config(accel_adapter, mldl_cfg, + mldl_cfg->accel, + (struct ext_slave_config __user *) arg); break; - case MPU_RESUME: - { - struct mpu_suspend_resume resume; - retval = - copy_from_user(&resume, - (struct mpu_suspend_resume *) - arg, sizeof(resume)); - if (retval) - break; - if (resume.gyro) { - retval = - mpu3050_resume(mldl_cfg, - client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - resume.accel, - resume.compass, - resume.pressure); - } else if (mldl_cfg->is_suspended) { - if (resume.accel) { - retval = - mldl_cfg-> - accel->resume(accel_adapter, - mldl_cfg->accel, - &mldl_cfg-> - pdata->accel); - if (retval) - break; - } - - if (resume.compass) { - retval = - mldl_cfg-> - compass->resume - (compass_adapter, - mldl_cfg->compass, - &mldl_cfg->pdata->compass); - if (retval) - break; - } - - if (resume.pressure) - retval = - mldl_cfg-> - pressure->resume - (pressure_adapter, - mldl_cfg->pressure, - &mldl_cfg->pdata->pressure); - } else { - /* Cannot resume the pressure compass or - * accel while the MPU is running */ - retval = ML_ERROR_FEATURE_NOT_IMPLEMENTED; - } - } + case MPU_GET_CONFIG_COMPASS: + retval = slave_get_config(compass_adapter, mldl_cfg, + mldl_cfg->compass, + (struct ext_slave_config __user *) arg); break; - case MPU_READ_ACCEL: - { - unsigned char data[6]; - retval = - mpu3050_read_accel(mldl_cfg, client->adapter, - data); - if (ML_SUCCESS == retval) - retval = - copy_to_user((unsigned char *) arg, - data, sizeof(data)); - } + case MPU_GET_CONFIG_PRESSURE: + retval = slave_get_config(pressure_adapter, mldl_cfg, + mldl_cfg->pressure, + (struct ext_slave_config __user *) arg); break; + case MPU_SUSPEND: + { + unsigned long sensors; + sensors = ~(mldl_cfg->requested_sensors); + retval = mpu3050_suspend(mldl_cfg, + client->adapter, + accel_adapter, + compass_adapter, + pressure_adapter, + ((sensors & ML_THREE_AXIS_GYRO) + == ML_THREE_AXIS_GYRO), + ((sensors & ML_THREE_AXIS_ACCEL) + == ML_THREE_AXIS_ACCEL), + ((sensors & ML_THREE_AXIS_COMPASS) + == ML_THREE_AXIS_COMPASS), + ((sensors & ML_THREE_AXIS_PRESSURE) + == ML_THREE_AXIS_PRESSURE)); + } + break; + case MPU_RESUME: + { + unsigned long sensors; + sensors = mldl_cfg->requested_sensors; + retval = mpu3050_resume(mldl_cfg, + client->adapter, + accel_adapter, + compass_adapter, + pressure_adapter, + sensors & ML_THREE_AXIS_GYRO, + sensors & ML_THREE_AXIS_ACCEL, + sensors & ML_THREE_AXIS_COMPASS, + sensors & ML_THREE_AXIS_PRESSURE); + } + break; + case MPU_READ_ACCEL: + { + unsigned char data[6]; + retval = mpu3050_read_accel(mldl_cfg, client->adapter, + data); + if ((ML_SUCCESS == retval) && + (copy_to_user((unsigned char __user *) arg, + data, sizeof(data)))) + retval = -EFAULT; + } + break; case MPU_READ_COMPASS: - { - unsigned char data[6]; - struct i2c_adapter *compass_adapt = - i2c_get_adapter(mldl_cfg->pdata->compass. - adapt_num); - retval = - mpu3050_read_compass(mldl_cfg, compass_adapt, + { + unsigned char data[6]; + struct i2c_adapter *compass_adapt = + i2c_get_adapter(mldl_cfg->pdata->compass. + adapt_num); + retval = mpu3050_read_compass(mldl_cfg, compass_adapt, data); - if (ML_SUCCESS == retval) - retval = - copy_to_user((unsigned char *) arg, - data, sizeof(data)); - } - break; + if ((ML_SUCCESS == retval) && + (copy_to_user((unsigned char *) arg, + data, sizeof(data)))) + retval = -EFAULT; + } + break; case MPU_READ_PRESSURE: - { - unsigned char data[3]; - struct i2c_adapter *pressure_adapt = - i2c_get_adapter(mldl_cfg->pdata->pressure. - adapt_num); - retval = - mpu3050_read_pressure(mldl_cfg, pressure_adapt, - data); - if (ML_SUCCESS == retval) - retval = - copy_to_user((unsigned char *) arg, - data, sizeof(data)); - } - break; + { + unsigned char data[3]; + struct i2c_adapter *pressure_adapt = + i2c_get_adapter(mldl_cfg->pdata->pressure. + adapt_num); + retval = + mpu3050_read_pressure(mldl_cfg, pressure_adapt, + data); + if ((ML_SUCCESS == retval) && + (copy_to_user((unsigned char __user *) arg, + data, sizeof(data)))) + retval = -EFAULT; + } + break; + case MPU_READ_MEMORY: + case MPU_WRITE_MEMORY: default: dev_err(&this_client->adapter->dev, "%s: Unknown cmd %d, arg %lu\n", __func__, cmd, @@ -737,11 +843,11 @@ void mpu3050_early_suspend(struct early_suspend *h) i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); dev_dbg(&this_client->adapter->dev, "%s: %d, %d\n", __func__, - h->level, mpu->mldl_cfg.is_suspended); + h->level, mpu->mldl_cfg.gyro_is_suspended); if (MPU3050_EARLY_SUSPEND_IN_DRIVER) (void) mpu3050_suspend(mldl_cfg, this_client->adapter, - accel_adapter, compass_adapter, - pressure_adapter, TRUE, TRUE, TRUE); + accel_adapter, compass_adapter, + pressure_adapter, TRUE, TRUE, TRUE, TRUE); } void mpu3050_early_resume(struct early_suspend *h) @@ -763,12 +869,16 @@ void mpu3050_early_resume(struct early_suspend *h) if (MPU3050_EARLY_SUSPEND_IN_DRIVER) { if (pid) { + unsigned long sensors = mldl_cfg->requested_sensors; (void) mpu3050_resume(mldl_cfg, - this_client->adapter, - accel_adapter, - compass_adapter, - pressure_adapter, - TRUE, TRUE, TRUE); + this_client->adapter, + accel_adapter, + compass_adapter, + pressure_adapter, + sensors & ML_THREE_AXIS_GYRO, + sensors & ML_THREE_AXIS_ACCEL, + sensors & ML_THREE_AXIS_COMPASS, + sensors & ML_THREE_AXIS_PRESSURE); dev_dbg(&this_client->adapter->dev, "%s for pid %d\n", __func__, pid); } @@ -794,7 +904,7 @@ void mpu_shutdown(struct i2c_client *client) (void) mpu3050_suspend(mldl_cfg, this_client->adapter, accel_adapter, compass_adapter, pressure_adapter, - TRUE, TRUE, TRUE); + TRUE, TRUE, TRUE, TRUE); dev_dbg(&this_client->adapter->dev, "%s\n", __func__); } @@ -813,14 +923,14 @@ int mpu_suspend(struct i2c_client *client, pm_message_t mesg) pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); - if (!mpu->mldl_cfg.is_suspended) { + if (!mpu->mldl_cfg.gyro_is_suspended) { dev_dbg(&this_client->adapter->dev, "%s: suspending on event %d\n", __func__, mesg.event); (void) mpu3050_suspend(mldl_cfg, this_client->adapter, accel_adapter, compass_adapter, pressure_adapter, - TRUE, TRUE, TRUE); + TRUE, TRUE, TRUE, TRUE); } else { dev_dbg(&this_client->adapter->dev, "%s: Already suspended %d\n", __func__, @@ -845,11 +955,15 @@ int mpu_resume(struct i2c_client *client) i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num); if (pid) { + unsigned long sensors = mldl_cfg->requested_sensors; (void) mpu3050_resume(mldl_cfg, this_client->adapter, accel_adapter, compass_adapter, pressure_adapter, - TRUE, TRUE, TRUE); + sensors & ML_THREE_AXIS_GYRO, + sensors & ML_THREE_AXIS_ACCEL, + sensors & ML_THREE_AXIS_COMPASS, + sensors & ML_THREE_AXIS_PRESSURE); dev_dbg(&this_client->adapter->dev, "%s for pid %d\n", __func__, pid); } @@ -888,6 +1002,7 @@ int mpu3050_probe(struct i2c_client *client, { struct mpu3050_platform_data *pdata; struct mpu_private_data *mpu; + struct mldl_cfg *mldl_cfg; int res = 0; struct i2c_adapter *accel_adapter = NULL; struct i2c_adapter *compass_adapter = NULL; @@ -908,27 +1023,27 @@ int mpu3050_probe(struct i2c_client *client, i2c_set_clientdata(client, mpu); this_client = client; - + mldl_cfg = &mpu->mldl_cfg; pdata = (struct mpu3050_platform_data *) client->dev.platform_data; if (!pdata) { dev_warn(&this_client->adapter->dev, "Warning no platform data for mpu3050\n"); } else { - mpu->mldl_cfg.pdata = pdata; + mldl_cfg->pdata = pdata; -#if defined(CONFIG_SENSORS_MPU3050_MODULE) || \ - defined(CONFIG_SENSORS_MPU6000_MODULE) +#if defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) || \ + defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) pdata->accel.get_slave_descr = get_accel_slave_descr; pdata->compass.get_slave_descr = get_compass_slave_descr; pdata->pressure.get_slave_descr = get_pressure_slave_descr; #endif if (pdata->accel.get_slave_descr) { - mpu->mldl_cfg.accel = + mldl_cfg->accel = pdata->accel.get_slave_descr(); dev_info(&this_client->adapter->dev, "%s: +%s\n", MPU_NAME, - mpu->mldl_cfg.accel->name); + mldl_cfg->accel->name); accel_adapter = i2c_get_adapter(pdata->accel.adapt_num); if (pdata->accel.irq > 0) { @@ -950,11 +1065,11 @@ int mpu3050_probe(struct i2c_client *client, } if (pdata->compass.get_slave_descr) { - mpu->mldl_cfg.compass = + mldl_cfg->compass = pdata->compass.get_slave_descr(); dev_info(&this_client->adapter->dev, "%s: +%s\n", MPU_NAME, - mpu->mldl_cfg.compass->name); + mldl_cfg->compass->name); compass_adapter = i2c_get_adapter(pdata->compass.adapt_num); if (pdata->compass.irq > 0) { @@ -976,11 +1091,11 @@ int mpu3050_probe(struct i2c_client *client, } if (pdata->pressure.get_slave_descr) { - mpu->mldl_cfg.pressure = + mldl_cfg->pressure = pdata->pressure.get_slave_descr(); dev_info(&this_client->adapter->dev, "%s: +%s\n", MPU_NAME, - mpu->mldl_cfg.pressure->name); + mldl_cfg->pressure->name); pressure_adapter = i2c_get_adapter(pdata->pressure.adapt_num); @@ -1003,7 +1118,7 @@ int mpu3050_probe(struct i2c_client *client, } } - mpu->mldl_cfg.addr = client->addr; + mldl_cfg->addr = client->addr; res = mpu3050_open(&mpu->mldl_cfg, client->adapter, accel_adapter, compass_adapter, pressure_adapter); diff --git a/drivers/misc/mpu3050/mpuirq.c b/drivers/misc/mpu3050/mpuirq.c index b6f21856cf32..691e5bc5b052 100644 --- a/drivers/misc/mpu3050/mpuirq.c +++ b/drivers/misc/mpu3050/mpuirq.c @@ -61,7 +61,7 @@ struct mpuirq_dev_data { }; static struct mpuirq_dev_data mpuirq_dev_data; -static struct irq_data mpuirq_data; +static struct mpuirq_data mpuirq_data; static char *interface = MPUIRQ_NAME; static void mpu_accel_data_work_fcn(struct work_struct *work); @@ -206,23 +206,20 @@ static irqreturn_t mpuirq_handler(int irq, void *dev_id) /* wake up (unblock) for reading data from userspace */ /* and ignore first interrupt generated in module init */ - if (mpuirq_data.interruptcount > 1) { - mpuirq_dev_data.data_ready = 1; - - do_gettimeofday(&irqtime); - mpuirq_data.irqtime = (((long long) irqtime.tv_sec) << 32); - mpuirq_data.irqtime += irqtime.tv_usec; - - if ((mpuirq_dev_data.accel_divider >= 0) && - (0 == - (mycount % (mpuirq_dev_data.accel_divider + 1)))) { - schedule_work((struct work_struct - *) (&mpuirq_dev_data)); - } + mpuirq_dev_data.data_ready = 1; + + do_gettimeofday(&irqtime); + mpuirq_data.irqtime = (((long long) irqtime.tv_sec) << 32); + mpuirq_data.irqtime += irqtime.tv_usec; - wake_up_interruptible(&mpuirq_wait); + if ((mpuirq_dev_data.accel_divider >= 0) && + (0 == (mycount % (mpuirq_dev_data.accel_divider + 1)))) { + schedule_work((struct work_struct + *) (&mpuirq_dev_data)); } + wake_up_interruptible(&mpuirq_wait); + return IRQ_HANDLED; } diff --git a/drivers/misc/mpu3050/slaveirq.c b/drivers/misc/mpu3050/slaveirq.c index 3791868505ee..2ee53851e125 100644 --- a/drivers/misc/mpu3050/slaveirq.c +++ b/drivers/misc/mpu3050/slaveirq.c @@ -34,22 +34,22 @@ #include <linux/mm.h> #include <linux/sched.h> #include <linux/wait.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/slab.h> #include "mpu.h" #include "slaveirq.h" #include "mldl_cfg.h" #include "mpu-i2c.h" -#include <linux/wait.h> -#include <linux/slab.h> /* function which gets slave data and sends it to SLAVE */ struct slaveirq_dev_data { struct miscdevice dev; struct i2c_client *slave_client; - struct irq_data data; + struct mpuirq_data data; wait_queue_head_t slaveirq_wait; int irq; int pid; @@ -83,7 +83,7 @@ static int slaveirq_release(struct inode *inode, struct file *file) /* read function called when from /dev/slaveirq is read */ static ssize_t slaveirq_read(struct file *file, - char *buf, size_t count, loff_t * ppos) + char *buf, size_t count, loff_t *ppos) { int len, err; struct slaveirq_dev_data *data = @@ -169,16 +169,14 @@ static irqreturn_t slaveirq_handler(int irq, void *dev_id) /* wake up (unblock) for reading data from userspace */ /* and ignore first interrupt generated in module init */ - if (data->data.interruptcount > 1) { - data->data_ready = 1; + data->data_ready = 1; - do_gettimeofday(&irqtime); - data->data.irqtime = (((long long) irqtime.tv_sec) << 32); - data->data.irqtime += irqtime.tv_usec; - data->data.data_type |= 1; + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long) irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; - wake_up_interruptible(&data->slaveirq_wait); - } + wake_up_interruptible(&data->slaveirq_wait); return IRQ_HANDLED; diff --git a/drivers/misc/mpu3050/timerirq.c b/drivers/misc/mpu3050/timerirq.c new file mode 100644 index 000000000000..94dd095306a5 --- /dev/null +++ b/drivers/misc/mpu3050/timerirq.c @@ -0,0 +1,295 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, 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 as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/stat.h> +#include <linux/signal.h> +#include <linux/miscdevice.h> +#include <linux/i2c.h> +#include <linux/i2c-dev.h> +#include <linux/poll.h> + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/timer.h> +#include <linux/slab.h> + +#include "mpu.h" +#include "mltypes.h" +#include "timerirq.h" + +/* function which gets timer data and sends it to TIMER */ +struct timerirq_data { + int pid; + int data_ready; + int run; + int timeout; + unsigned long period; + struct mpuirq_data data; + struct completion timer_done; + wait_queue_head_t timerirq_wait; + struct timer_list timer; + struct miscdevice *dev; +}; + +static struct miscdevice *timerirq_dev_data; + +static void timerirq_handler(unsigned long arg) +{ + struct timerirq_data *data = (struct timerirq_data *)arg; + struct timeval irqtime; + + /* dev_info(data->dev->this_device, + "%s, %ld\n", __func__, (unsigned long)data); */ + + data->data.interruptcount++; + + data->data_ready = 1; + + do_gettimeofday(&irqtime); + data->data.irqtime = (((long long) irqtime.tv_sec) << 32); + data->data.irqtime += irqtime.tv_usec; + data->data.data_type |= 1; + + wake_up_interruptible(&data->timerirq_wait); + + if (data->run) + mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); + else + complete(&data->timer_done); +} + +static int start_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + + /* Timer already running... success */ + if (data->run) + return 0; + + /* Don't allow a period of 0 since this would fire constantly */ + if (!data->period) + return -EINVAL; + + data->run = TRUE; + data->data_ready = FALSE; + + init_completion(&data->timer_done); + setup_timer(&data->timer, timerirq_handler, (unsigned long)data); + + return mod_timer(&data->timer, + jiffies + msecs_to_jiffies(data->period)); +} + +static int stop_timerirq(struct timerirq_data *data) +{ + dev_dbg(data->dev->this_device, + "%s current->pid %lx\n", __func__, (unsigned long)data); + + if (data->run) { + data->run = FALSE; + mod_timer(&data->timer, jiffies + 1); + wait_for_completion(&data->timer_done); + } + return 0; +} + +/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28 + * drivers: misc: pass miscdevice pointer via file private data + */ +static int timerirq_open(struct inode *inode, struct file *file) +{ + /* Device node is availabe in the file->private_data, this is + * exactly what we want so we leave it there */ + struct miscdevice *dev_data = file->private_data; + struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev_data; + file->private_data = data; + data->pid = current->pid; + init_waitqueue_head(&data->timerirq_wait); + + dev_dbg(data->dev->this_device, + "%s current->pid %d\n", __func__, current->pid); + return 0; +} + +static int timerirq_release(struct inode *inode, struct file *file) +{ + struct timerirq_data *data = file->private_data; + dev_dbg(data->dev->this_device, "timerirq_release\n"); + if (data->run) + stop_timerirq(data); + kfree(data); + return 0; +} + +/* read function called when from /dev/timerirq is read */ +static ssize_t timerirq_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int len, err; + struct timerirq_data *data = file->private_data; + + if (!data->data_ready) { + wait_event_interruptible_timeout(data->timerirq_wait, + data->data_ready, + data->timeout); + } + + if (data->data_ready && NULL != buf + && count >= sizeof(data->data)) { + err = copy_to_user(buf, &data->data, sizeof(data->data)); + data->data.data_type = 0; + } else { + return 0; + } + if (err != 0) { + dev_err(data->dev->this_device, + "Copy to user returned %d\n", err); + return -EFAULT; + } + data->data_ready = 0; + len = sizeof(data->data); + return len; +} + +unsigned int timerirq_poll(struct file *file, struct poll_table_struct *poll) +{ + int mask = 0; + struct timerirq_data *data = file->private_data; + + poll_wait(file, &data->timerirq_wait, poll); + if (data->data_ready) + mask |= POLLIN | POLLRDNORM; + return mask; +} + +/* ioctl - I/O control */ +static long timerirq_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int tmp; + struct timerirq_data *data = file->private_data; + + dev_dbg(data->dev->this_device, + "%s current->pid %d, %d, %ld\n", + __func__, current->pid, cmd, arg); + + if (!data) + return -EFAULT; + + switch (cmd) { + case TIMERIRQ_SET_TIMEOUT: + data->timeout = arg; + break; + case TIMERIRQ_GET_INTERRUPT_CNT: + tmp = data->data.interruptcount - 1; + if (data->data.interruptcount > 1) + data->data.interruptcount = 1; + + if (copy_to_user((int *) arg, &tmp, sizeof(int))) + return -EFAULT; + break; + case TIMERIRQ_START: + data->period = arg; + retval = start_timerirq(data); + break; + case TIMERIRQ_STOP: + retval = stop_timerirq(data); + break; + default: + retval = -EINVAL; + } + return retval; +} + +/* define which file operations are supported */ +static const struct file_operations timerirq_fops = { + .owner = THIS_MODULE, + .read = timerirq_read, + .poll = timerirq_poll, + +#if HAVE_COMPAT_IOCTL + .compat_ioctl = timerirq_ioctl, +#endif +#if HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = timerirq_ioctl, +#endif + .open = timerirq_open, + .release = timerirq_release, +}; + +static int __init timerirq_init(void) +{ + + int res; + static struct miscdevice *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + timerirq_dev_data = data; + data->minor = MISC_DYNAMIC_MINOR; + data->name = "timerirq"; + data->fops = &timerirq_fops; + + res = misc_register(data); + if (res < 0) { + dev_err(data->this_device, + "misc_register returned %d\n", + res); + return res; + } + + return res; +} +module_init(timerirq_init); + +static void __exit timerirq_exit(void) +{ + struct miscdevice *data = timerirq_dev_data; + + dev_info(data->this_device, "Unregistering %s\n", + data->name); + + misc_deregister(data); + kfree(data); + + timerirq_dev_data = NULL; +} +module_exit(timerirq_exit); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Timer IRQ device driver."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("timerirq"); diff --git a/drivers/misc/mpu3050/timerirq.h b/drivers/misc/mpu3050/timerirq.h new file mode 100644 index 000000000000..a38b4907a4d4 --- /dev/null +++ b/drivers/misc/mpu3050/timerirq.h @@ -0,0 +1,28 @@ +/* + $License: + Copyright (C) 2010 InvenSense Corporation, 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 as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. + $ + */ + +#ifndef __TIMERIRQ__ +#define __TIMERIRQ__ + +#define TIMERIRQ_SET_TIMEOUT (5) +#define TIMERIRQ_GET_INTERRUPT_CNT (7) +#define TIMERIRQ_START (8) +#define TIMERIRQ_STOP (9) + +#endif diff --git a/include/linux/mpu.h b/include/linux/mpu.h index 5756f5709a75..15b5fef07c9a 100644 --- a/include/linux/mpu.h +++ b/include/linux/mpu.h @@ -31,9 +31,9 @@ #endif /* Number of axes on each sensor */ -#define GYRO_NUM_AXES (3) -#define ACCEL_NUM_AXES (3) -#define COMPASS_NUM_AXES (3) +#define GYRO_NUM_AXES (3) +#define ACCEL_NUM_AXES (3) +#define COMPASS_NUM_AXES (3) /* IOCTL commands for /dev/mpu */ #define MPU_SET_MPU_CONFIG (0x00) @@ -83,6 +83,10 @@ #define MPU_CONFIG_COMPASS (0x21) #define MPU_CONFIG_PRESSURE (0x22) +#define MPU_GET_CONFIG_ACCEL (0x28) +#define MPU_GET_CONFIG_COMPASS (0x29) +#define MPU_GET_CONFIG_PRESSURE (0x2a) + /* Structure for the following IOCTL's: MPU_SET_RAM MPU_GET_RAM @@ -97,18 +101,7 @@ struct mpu_read_write { unsigned char *data; }; -/* Structure for the following IOCTL's - MPU_SUSPEND - MPU_RESUME -*/ -struct mpu_suspend_resume { - int gyro; - int accel; - int compass; - int pressure; -}; - -struct irq_data { +struct mpuirq_data { int interruptcount; unsigned long long irqtime; int data_type; @@ -116,24 +109,38 @@ struct irq_data { void *data; }; enum ext_slave_config_key { - MPU_SLAVE_CONFIG_ODR_SUSPEND, - MPU_SLAVE_CONFIG_ODR_RESUME, - MPU_SLAVE_CONFIG_FSR_SUSPEND, - MPU_SLAVE_CONFIG_FSR_RESUME, - MPU_SLAVE_CONFIG_MOT_THS, - MPU_SLAVE_CONFIG_NMOT_THS, - MPU_SLAVE_CONFIG_MOT_DUR, - MPU_SLAVE_CONFIG_NMOT_DUR, - MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS, + MPU_SLAVE_CONFIG_ODR_SUSPEND, + MPU_SLAVE_CONFIG_ODR_RESUME, + MPU_SLAVE_CONFIG_FSR_SUSPEND, + MPU_SLAVE_CONFIG_FSR_RESUME, + MPU_SLAVE_CONFIG_MOT_THS, + MPU_SLAVE_CONFIG_NMOT_THS, + MPU_SLAVE_CONFIG_MOT_DUR, + MPU_SLAVE_CONFIG_NMOT_DUR, + MPU_SLAVE_CONFIG_IRQ_SUSPEND, + MPU_SLAVE_CONFIG_IRQ_RESUME, + MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS, }; + +/* For the MPU_SLAVE_CONFIG_IRQ_SUSPEND and MPU_SLAVE_CONFIG_IRQ_RESUME */ +enum ext_slave_config_irq_type { + MPU_SLAVE_IRQ_TYPE_NONE, + MPU_SLAVE_IRQ_TYPE_MOTION, + MPU_SLAVE_IRQ_TYPE_DATA_READY, +}; + /* Structure for the following IOCTS's * MPU_CONFIG_ACCEL * MPU_CONFIG_COMPASS * MPU_CONFIG_PRESSURE + * MPU_GET_CONFIG_ACCEL + * MPU_GET_CONFIG_COMPASS + * MPU_GET_CONFIG_PRESSURE */ struct ext_slave_config { int key; int len; + int apply; void *data; }; @@ -156,8 +163,9 @@ enum ext_slave_id { ACCEL_ID_BMA222, ACCEL_ID_ADI346, ACCEL_ID_MMA8450, - ACCEL_ID_MMA8451, + ACCEL_ID_MMA845X, ACCEL_ID_MPU6000, + ACCEL_ID_LIS3DH, COMPASS_ID_AKM, COMPASS_ID_AMI30X, @@ -166,6 +174,7 @@ enum ext_slave_id { COMPASS_ID_LSM303, COMPASS_ID_MMC314X, COMPASS_ID_HSCDTD002B, + COMPASS_ID_HSCDTD004A, PRESSURE_ID_BMA085, }; @@ -229,6 +238,7 @@ struct tFixPntRange { * @init: function used to preallocate memory used by the driver * @exit: function used to free memory allocated for the driver * @config: function used to configure the device + * @get_config:function used to get the device's configuration * * @name: text name of the device * @type: device type. enum ext_slave_type @@ -262,6 +272,10 @@ struct ext_slave_descr { struct ext_slave_descr *slave, struct ext_slave_platform_data *pdata, struct ext_slave_config *config); + int (*get_config) (void *mlsl_handle, + struct ext_slave_descr *slave, + struct ext_slave_platform_data *pdata, + struct ext_slave_config *config); char *name; unsigned char type; @@ -302,65 +316,73 @@ struct mpu3050_platform_data { */ #define get_accel_slave_descr NULL -#ifdef CONFIG_SENSORS_ADXL346 /* ADI accelerometer */ +#ifdef CONFIG_MPU_SENSORS_ADXL346 /* ADI accelerometer */ struct ext_slave_descr *adxl346_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr adxl346_get_slave_descr #endif -#ifdef CONFIG_SENSORS_BMA150 /* Bosch accelerometer */ +#ifdef CONFIG_MPU_SENSORS_BMA150 /* Bosch accelerometer */ struct ext_slave_descr *bma150_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr bma150_get_slave_descr #endif -#ifdef CONFIG_SENSORS_BMA222 /* Bosch 222 accelerometer */ +#ifdef CONFIG_MPU_SENSORS_BMA222 /* Bosch 222 accelerometer */ struct ext_slave_descr *bma222_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr bma222_get_slave_descr #endif -#ifdef CONFIG_SENSORS_KXSD9 /* Kionix accelerometer */ +#ifdef CONFIG_MPU_SENSORS_KXSD9 /* Kionix accelerometer */ struct ext_slave_descr *kxsd9_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr kxsd9_get_slave_descr #endif -#ifdef CONFIG_SENSORS_KXTF9_MPU /* Kionix accelerometer */ +#ifdef CONFIG_MPU_SENSORS_KXTF9 /* Kionix accelerometer */ struct ext_slave_descr *kxtf9_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr kxtf9_get_slave_descr #endif -#ifdef CONFIG_SENSORS_LIS331DLH /* ST accelerometer */ +#ifdef CONFIG_MPU_SENSORS_LIS331DLH /* ST accelerometer */ struct ext_slave_descr *lis331dlh_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr lis331dlh_get_slave_descr #endif -#ifdef CONFIG_SENSORS_LSM303DLHA /* ST accelerometer */ + +#ifdef CONFIG_MPU_SENSORS_LIS3DH /* ST accelerometer */ +struct ext_slave_descr *lis3dh_get_slave_descr(void); +#undef get_accel_slave_descr +#define get_accel_slave_descr lis3dh_get_slave_descr +#endif + +#ifdef CONFIG_MPU_SENSORS_LSM303DLHA /* ST accelerometer */ struct ext_slave_descr *lsm303dlha_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr lsm303dlha_get_slave_descr #endif /* MPU6000 Accel */ -#if defined(CONFIG_SENSORS_MPU6000) || defined(CONFIG_SENSORS_MPU6000_MODULE) +#if defined(CONFIG_MPU_SENSORS_MPU6000) || \ + defined(CONFIG_MPU_SENSORS_MPU6000_MODULE) struct ext_slave_descr *mantis_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr mantis_get_slave_descr #endif -#ifdef CONFIG_SENSORS_MMA8450 /* Freescale accelerometer */ +#ifdef CONFIG_MPU_SENSORS_MMA8450 /* Freescale accelerometer */ struct ext_slave_descr *mma8450_get_slave_descr(void); #undef get_accel_slave_descr #define get_accel_slave_descr mma8450_get_slave_descr #endif -#ifdef CONFIG_SENSORS_MMA8451 /* Freescale accelerometer */ -struct ext_slave_descr *mma8451_get_slave_descr(void); +#ifdef CONFIG_MPU_SENSORS_MMA845X /* Freescale accelerometer */ +struct ext_slave_descr *mma845x_get_slave_descr(void); #undef get_accel_slave_descr -#define get_accel_slave_descr mma8451_get_slave_descr +#define get_accel_slave_descr mma845x_get_slave_descr #endif @@ -369,54 +391,59 @@ struct ext_slave_descr *mma8451_get_slave_descr(void); */ #define get_compass_slave_descr NULL -#ifdef CONFIG_SENSORS_AK8975_MPU /* AKM compass */ +#ifdef CONFIG_MPU_SENSORS_AK8975 /* AKM compass */ struct ext_slave_descr *ak8975_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr ak8975_get_slave_descr #endif -#ifdef CONFIG_SENSORS_AMI30X /* AICHI Steel compass */ +#ifdef CONFIG_MPU_SENSORS_AMI30X /* AICHI Steel compass */ struct ext_slave_descr *ami30x_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr ami30x_get_slave_descr #endif -#ifdef CONFIG_SENSORS_HMC5883 /* Honeywell compass */ +#ifdef CONFIG_MPU_SENSORS_HMC5883 /* Honeywell compass */ struct ext_slave_descr *hmc5883_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr hmc5883_get_slave_descr #endif -#ifdef CONFIG_SENSORS_MMC314X /* MEMSIC compass */ +#ifdef CONFIG_MPU_SENSORS_MMC314X /* MEMSIC compass */ struct ext_slave_descr *mmc314x_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr mmc314x_get_slave_descr #endif -#ifdef CONFIG_SENSORS_LSM303DLHM /* ST compass */ +#ifdef CONFIG_MPU_SENSORS_LSM303DLHM /* ST compass */ struct ext_slave_descr *lsm303dlhm_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr lsm303dlhm_get_slave_descr #endif -#ifdef CONFIG_SENSORS_YAS529 /* Yamaha compass */ +#ifdef CONFIG_MPU_SENSORS_YAS529 /* Yamaha compass */ struct ext_slave_descr *yas529_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr yas529_get_slave_descr #endif -#ifdef CONFIG_SENSORS_HSCDTD002B /* Alps compass */ +#ifdef CONFIG_MPU_SENSORS_HSCDTD002B /* Alps HSCDTD002B compass */ struct ext_slave_descr *hscdtd002b_get_slave_descr(void); #undef get_compass_slave_descr #define get_compass_slave_descr hscdtd002b_get_slave_descr #endif +#ifdef CONFIG_MPU_SENSORS_HSCDTD004A /* Alps HSCDTD004A compass */ +struct ext_slave_descr *hscdtd004a_get_slave_descr(void); +#undef get_compass_slave_descr +#define get_compass_slave_descr hscdtd004a_get_slave_descr +#endif /* Pressure */ #define get_pressure_slave_descr NULL -#ifdef CONFIG_SENSORS_BMA085 /* BMA pressure */ +#ifdef CONFIG_MPU_SENSORS_BMA085 /* BMA pressure */ struct ext_slave_descr *bma085_get_slave_descr(void); #undef get_pressure_slave_descr #define get_pressure_slave_descr bma085_get_slave_descr diff --git a/include/linux/mpu6000.h b/include/linux/mpu6000.h index 89c4cbb90b69..5a63c8f07b70 100644 --- a/include/linux/mpu6000.h +++ b/include/linux/mpu6000.h @@ -34,122 +34,122 @@ /*==== M_HW REGISTER SET ====*/ enum { - MPUREG_XG_OFFS_TC = 0, - MPUREG_YG_OFFS_TC, - MPUREG_ZG_OFFS_TC, - MPUREG_X_FINE_GAIN, - MPUREG_Y_FINE_GAIN, - MPUREG_Z_FINE_GAIN, - MPUREG_XA_OFFS_H, - MPUREG_XA_OFFS_L_TC, - MPUREG_YA_OFFS_H, - MPUREG_YA_OFFS_L_TC, - MPUREG_ZA_OFFS_H, + MPUREG_XG_OFFS_TC = 0, /* 0x00 */ + MPUREG_YG_OFFS_TC, /* 0x00 */ + MPUREG_ZG_OFFS_TC, /* 0x00 */ + MPUREG_X_FINE_GAIN, /* 0x00 */ + MPUREG_Y_FINE_GAIN, /* 0x00 */ + MPUREG_Z_FINE_GAIN, /* 0x00 */ + MPUREG_XA_OFFS_H, /* 0x00 */ + MPUREG_XA_OFFS_L_TC, /* 0x00 */ + MPUREG_YA_OFFS_H, /* 0x00 */ + MPUREG_YA_OFFS_L_TC, /* 0x00 */ + MPUREG_ZA_OFFS_H, /* 0x00 */ MPUREG_ZA_OFFS_L_TC, /* 0xB */ - MPUREG_0C_RSVD, - MPUREG_0D_RSVD, - MPUREG_0E_RSVD, - MPUREG_0F_RSVD, - MPUREG_10_RSVD, - MPUREG_11_RSVD, - MPUREG_12_RSVD, - MPUREG_XG_OFFS_USRH, - MPUREG_XG_OFFS_USRL, - MPUREG_YG_OFFS_USRH, - MPUREG_YG_OFFS_USRL, - MPUREG_ZG_OFFS_USRH, - MPUREG_ZG_OFFS_USRL, + MPUREG_0C_RSVD, /* 0x00 */ + MPUREG_0D_RSVD, /* 0x00 */ + MPUREG_0E_RSVD, /* 0x00 */ + MPUREG_0F_RSVD, /* 0x00 */ + MPUREG_10_RSVD, /* 0x00 */ + MPUREG_11_RSVD, /* 0x00 */ + MPUREG_12_RSVD, /* 0x00 */ + MPUREG_XG_OFFS_USRH, /* 0x00 */ + MPUREG_XG_OFFS_USRL, /* 0x00 */ + MPUREG_YG_OFFS_USRH, /* 0x00 */ + MPUREG_YG_OFFS_USRL, /* 0x00 */ + MPUREG_ZG_OFFS_USRH, /* 0x00 */ + MPUREG_ZG_OFFS_USRL, /* 0x00 */ MPUREG_SMPLRT_DIV, /* 0x19 */ MPUREG_CONFIG, /* 0x1A ==> DLPF_FS_SYNC */ - MPUREG_GYRO_CONFIG, - MPUREG_ACCEL_CONFIG, - MPUREG_ACCEL_FF_THR, - MPUREG_ACCEL_FF_DUR, - MPUREG_ACCEL_MOT_THR, - MPUREG_ACCEL_MOT_DUR, - MPUREG_ACCEL_ZRMOT_THR, - MPUREG_ACCEL_ZRMOT_DUR, + MPUREG_GYRO_CONFIG, /* 0x00 */ + MPUREG_ACCEL_CONFIG, /* 0x00 */ + MPUREG_ACCEL_FF_THR, /* 0x00 */ + MPUREG_ACCEL_FF_DUR, /* 0x00 */ + MPUREG_ACCEL_MOT_THR, /* 0x00 */ + MPUREG_ACCEL_MOT_DUR, /* 0x00 */ + MPUREG_ACCEL_ZRMOT_THR, /* 0x00 */ + MPUREG_ACCEL_ZRMOT_DUR, /* 0x00 */ MPUREG_FIFO_EN, /* 0x23 */ - MPUREG_I2C_MST_CTRL, + MPUREG_I2C_MST_CTRL, /* 0x00 */ MPUREG_I2C_SLV0_ADDR, /* 0x25 */ - MPUREG_I2C_SLV0_REG, - MPUREG_I2C_SLV0_CTRL, + MPUREG_I2C_SLV0_REG, /* 0x00 */ + MPUREG_I2C_SLV0_CTRL, /* 0x00 */ MPUREG_I2C_SLV1_ADDR, /* 0x28 */ - MPUREG_I2C_SLV1_REG_PASSWORD, - MPUREG_I2C_SLV1_CTRL, + MPUREG_I2C_SLV1_REG_PASSWORD, /* 0x00 */ + MPUREG_I2C_SLV1_CTRL, /* 0x00 */ MPUREG_I2C_SLV2_ADDR, /* 0x2B */ - MPUREG_I2C_SLV2_REG, - MPUREG_I2C_SLV2_CTRL, + MPUREG_I2C_SLV2_REG, /* 0x00 */ + MPUREG_I2C_SLV2_CTRL, /* 0x00 */ MPUREG_I2C_SLV3_ADDR, /* 0x2E */ - MPUREG_I2C_SLV3_REG, - MPUREG_I2C_SLV3_CTRL, + MPUREG_I2C_SLV3_REG, /* 0x00 */ + MPUREG_I2C_SLV3_CTRL, /* 0x00 */ MPUREG_I2C_SLV4_ADDR, /* 0x31 */ - MPUREG_I2C_SLV4_REG, - MPUREG_I2C_SLV4_DO, - MPUREG_I2C_SLV4_CTRL, - MPUREG_I2C_SLV4_DI, + MPUREG_I2C_SLV4_REG, /* 0x00 */ + MPUREG_I2C_SLV4_DO, /* 0x00 */ + MPUREG_I2C_SLV4_CTRL, /* 0x00 */ + MPUREG_I2C_SLV4_DI, /* 0x00 */ MPUREG_I2C_MST_STATUS, /* 0x36 */ MPUREG_INT_PIN_CFG, /* 0x37 ==> -* INT_CFG */ MPUREG_INT_ENABLE, /* 0x38 ==> / */ MPUREG_DMP_INT_STATUS, /* 0x39 */ MPUREG_INT_STATUS, /* 0x3A */ MPUREG_ACCEL_XOUT_H, /* 0x3B */ - MPUREG_ACCEL_XOUT_L, - MPUREG_ACCEL_YOUT_H, - MPUREG_ACCEL_YOUT_L, - MPUREG_ACCEL_ZOUT_H, - MPUREG_ACCEL_ZOUT_L, + MPUREG_ACCEL_XOUT_L, /* 0x00 */ + MPUREG_ACCEL_YOUT_H, /* 0x00 */ + MPUREG_ACCEL_YOUT_L, /* 0x00 */ + MPUREG_ACCEL_ZOUT_H, /* 0x00 */ + MPUREG_ACCEL_ZOUT_L, /* 0x00 */ MPUREG_TEMP_OUT_H, /* 0x41 */ - MPUREG_TEMP_OUT_L, + MPUREG_TEMP_OUT_L, /* 0x00 */ MPUREG_GYRO_XOUT_H, /* 0x43 */ - MPUREG_GYRO_XOUT_L, - MPUREG_GYRO_YOUT_H, - MPUREG_GYRO_YOUT_L, - MPUREG_GYRO_ZOUT_H, - MPUREG_GYRO_ZOUT_L, + MPUREG_GYRO_XOUT_L, /* 0x00 */ + MPUREG_GYRO_YOUT_H, /* 0x00 */ + MPUREG_GYRO_YOUT_L, /* 0x00 */ + MPUREG_GYRO_ZOUT_H, /* 0x00 */ + MPUREG_GYRO_ZOUT_L, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_00, /* 0x49 */ - MPUREG_EXT_SLV_SENS_DATA_01, - MPUREG_EXT_SLV_SENS_DATA_02, - MPUREG_EXT_SLV_SENS_DATA_03, - MPUREG_EXT_SLV_SENS_DATA_04, - MPUREG_EXT_SLV_SENS_DATA_05, + MPUREG_EXT_SLV_SENS_DATA_01, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_02, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_03, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_04, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_05, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_06, /* 0x4F */ - MPUREG_EXT_SLV_SENS_DATA_07, - MPUREG_EXT_SLV_SENS_DATA_08, - MPUREG_EXT_SLV_SENS_DATA_09, - MPUREG_EXT_SLV_SENS_DATA_10, - MPUREG_EXT_SLV_SENS_DATA_11, + MPUREG_EXT_SLV_SENS_DATA_07, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_08, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_09, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_10, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_11, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_12, /* 0x55 */ - MPUREG_EXT_SLV_SENS_DATA_13, - MPUREG_EXT_SLV_SENS_DATA_14, - MPUREG_EXT_SLV_SENS_DATA_15, - MPUREG_EXT_SLV_SENS_DATA_16, - MPUREG_EXT_SLV_SENS_DATA_17, + MPUREG_EXT_SLV_SENS_DATA_13, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_14, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_15, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_16, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_17, /* 0x00 */ MPUREG_EXT_SLV_SENS_DATA_18, /* 0x5B */ - MPUREG_EXT_SLV_SENS_DATA_19, - MPUREG_EXT_SLV_SENS_DATA_20, - MPUREG_EXT_SLV_SENS_DATA_21, - MPUREG_EXT_SLV_SENS_DATA_22, - MPUREG_EXT_SLV_SENS_DATA_23, + MPUREG_EXT_SLV_SENS_DATA_19, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_20, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_21, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_22, /* 0x00 */ + MPUREG_EXT_SLV_SENS_DATA_23, /* 0x00 */ ACCEL_INTEL_STATUS, /* 0x61 */ - MPUREG_62_RSVD, - MPUREG_63_RSVD, - MPUREG_64_RSVD, - MPUREG_65_RSVD, - MPUREG_66_RSVD, - MPUREG_67_RSVD, + MPUREG_62_RSVD, /* 0x00 */ + MPUREG_63_RSVD, /* 0x00 */ + MPUREG_64_RSVD, /* 0x00 */ + MPUREG_65_RSVD, /* 0x00 */ + MPUREG_66_RSVD, /* 0x00 */ + MPUREG_67_RSVD, /* 0x00 */ SIGNAL_PATH_RESET, /* 0x68 */ ACCEL_INTEL_CTRL, /* 0x69 */ MPUREG_USER_CTRL, /* 0x6A */ MPUREG_PWR_MGMT_1, /* 0x6B */ - MPUREG_PWR_MGMT_2, + MPUREG_PWR_MGMT_2, /* 0x00 */ MPUREG_BANK_SEL, /* 0x6D */ MPUREG_MEM_START_ADDR, /* 0x6E */ MPUREG_MEM_R_W, /* 0x6F */ - MPUREG_PRGM_STRT_ADDRH, - MPUREG_PRGM_STRT_ADDRL, + MPUREG_PRGM_STRT_ADDRH, /* 0x00 */ + MPUREG_PRGM_STRT_ADDRL, /* 0x00 */ MPUREG_FIFO_COUNTH, /* 0x72 */ - MPUREG_FIFO_COUNTL, + MPUREG_FIFO_COUNTL, /* 0x00 */ MPUREG_FIFO_R_W, /* 0x74 */ MPUREG_WHOAMI, /* 0x75,117 */ @@ -309,7 +309,12 @@ enum MPU_MEMORY_BANKS { #define BIT_STBY_ZG 0x01 /* although it has 6, this refers to the gyros */ -#define MPU_NUM_AXES (3) +#define MPU_NUM_AXES (3) + +#define ACCEL_MOT_THR_LSB (32) /* mg */ +#define ACCEL_MOT_DUR_LSB (1) +#define ACCEL_ZRMOT_THR_LSB_CONVERSION(mg) ((mg *1000)/255) +#define ACCEL_ZRMOT_DUR_LSB (64) /*----------------------------------------------------------------------------*/ /*---- Alternative names to take care of conflicts with current mpu3050.h ----*/ |