diff options
Diffstat (limited to 'drivers/iio/imu-aosp/inv_mpu6515/inv_slave_pressure.c')
| -rwxr-xr-x | drivers/iio/imu-aosp/inv_mpu6515/inv_slave_pressure.c | 522 | 
1 files changed, 522 insertions, 0 deletions
diff --git a/drivers/iio/imu-aosp/inv_mpu6515/inv_slave_pressure.c b/drivers/iio/imu-aosp/inv_mpu6515/inv_slave_pressure.c new file mode 100755 index 00000000000..24d80810449 --- /dev/null +++ b/drivers/iio/imu-aosp/inv_mpu6515/inv_slave_pressure.c @@ -0,0 +1,522 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include "inv_mpu_iio.h" + +/* Constants */ +#define SHIFT_RIGHT_4_POSITION				 4 +#define SHIFT_LEFT_2_POSITION                2 +#define SHIFT_LEFT_4_POSITION                4 +#define SHIFT_LEFT_5_POSITION                5 +#define SHIFT_LEFT_8_POSITION                8 +#define SHIFT_LEFT_12_POSITION               12 +#define SHIFT_LEFT_16_POSITION               16 + +/* Sensor Specific constants */ +#define BMP280_SLEEP_MODE                    0x00 +#define BMP280_FORCED_MODE                   0x01 +#define BMP280_NORMAL_MODE                   0x03 +#define BMP280_SOFT_RESET                    0xB6 + +#define BMP280_DELAYTIME_MS_NONE             0 +#define BMP280_DELAYTIME_MS_5                5 +#define BMP280_DELAYTIME_MS_6                6 +#define BMP280_DELAYTIME_MS_8                8 +#define BMP280_DELAYTIME_MS_12               12 +#define BMP280_DELAYTIME_MS_22               22 +#define BMP280_DELAYTIME_MS_38               38 + +#define BMP280_OVERSAMPLING_SKIPPED          0x00 +#define BMP280_OVERSAMPLING_1X               0x01 +#define BMP280_OVERSAMPLING_2X               0x02 +#define BMP280_OVERSAMPLING_4X               0x03 +#define BMP280_OVERSAMPLING_8X               0x04 +#define BMP280_OVERSAMPLING_16X              0x05 + +#define BMP280_ULTRALOWPOWER_MODE            0x00 +#define BMP280_LOWPOWER_MODE	             0x01 +#define BMP280_STANDARDRESOLUTION_MODE       0x02 +#define BMP280_HIGHRESOLUTION_MODE           0x03 +#define BMP280_ULTRAHIGHRESOLUTION_MODE      0x04 + +#define BMP280_ULTRALOWPOWER_OSRS_P          BMP280_OVERSAMPLING_1X +#define BMP280_ULTRALOWPOWER_OSRS_T          BMP280_OVERSAMPLING_1X + +#define BMP280_LOWPOWER_OSRS_P	             BMP280_OVERSAMPLING_2X +#define BMP280_LOWPOWER_OSRS_T	             BMP280_OVERSAMPLING_1X + +#define BMP280_STANDARDRESOLUTION_OSRS_P     BMP280_OVERSAMPLING_4X +#define BMP280_STANDARDRESOLUTION_OSRS_T     BMP280_OVERSAMPLING_1X + +#define BMP280_HIGHRESOLUTION_OSRS_P         BMP280_OVERSAMPLING_8X +#define BMP280_HIGHRESOLUTION_OSRS_T         BMP280_OVERSAMPLING_1X + +#define BMP280_ULTRAHIGHRESOLUTION_OSRS_P    BMP280_OVERSAMPLING_16X +#define BMP280_ULTRAHIGHRESOLUTION_OSRS_T    BMP280_OVERSAMPLING_2X + +#define BMP280_FILTERCOEFF_OFF               0x00 +#define BMP280_FILTERCOEFF_2                 0x01 +#define BMP280_FILTERCOEFF_4                 0x02 +#define BMP280_FILTERCOEFF_8                 0x03 +#define BMP280_FILTERCOEFF_16                0x04 + +/*calibration parameters */ +#define BMP280_DIG_T1_LSB_REG                0x88 +#define BMP280_DIG_T1_MSB_REG                0x89 +#define BMP280_DIG_T2_LSB_REG                0x8A +#define BMP280_DIG_T2_MSB_REG                0x8B +#define BMP280_DIG_T3_LSB_REG                0x8C +#define BMP280_DIG_T3_MSB_REG                0x8D +#define BMP280_DIG_P1_LSB_REG                0x8E +#define BMP280_DIG_P1_MSB_REG                0x8F +#define BMP280_DIG_P2_LSB_REG                0x90 +#define BMP280_DIG_P2_MSB_REG                0x91 +#define BMP280_DIG_P3_LSB_REG                0x92 +#define BMP280_DIG_P3_MSB_REG                0x93 +#define BMP280_DIG_P4_LSB_REG                0x94 +#define BMP280_DIG_P4_MSB_REG                0x95 +#define BMP280_DIG_P5_LSB_REG                0x96 +#define BMP280_DIG_P5_MSB_REG                0x97 +#define BMP280_DIG_P6_LSB_REG                0x98 +#define BMP280_DIG_P6_MSB_REG                0x99 +#define BMP280_DIG_P7_LSB_REG                0x9A +#define BMP280_DIG_P7_MSB_REG                0x9B +#define BMP280_DIG_P8_LSB_REG                0x9C +#define BMP280_DIG_P8_MSB_REG                0x9D +#define BMP280_DIG_P9_LSB_REG                0x9E +#define BMP280_DIG_P9_MSB_REG                0x9F + +#define BMP280_CHIPID_REG                    0xD0  /*Chip ID Register */ +#define BMP280_RESET_REG                     0xE0  /*Softreset Register */ +#define BMP280_STATUS_REG                    0xF3  /*Status Register */ +#define BMP280_CTRLMEAS_REG                  0xF4  /*Ctrl Measure Register */ +#define BMP280_CONFIG_REG                    0xF5  /*Configuration Register */ +#define BMP280_PRESSURE_MSB_REG              0xF7  /*Pressure MSB Register */ +#define BMP280_PRESSURE_LSB_REG              0xF8  /*Pressure LSB Register */ +#define BMP280_PRESSURE_XLSB_REG             0xF9  /*Pressure XLSB Register */ +#define BMP280_TEMPERATURE_MSB_REG           0xFA  /*Temperature MSB Reg */ +#define BMP280_TEMPERATURE_LSB_REG           0xFB  /*Temperature LSB Reg */ +#define BMP280_TEMPERATURE_XLSB_REG          0xFC  /*Temperature XLSB Reg */ + +/* Status Register */ +#define BMP280_STATUS_REG_MEASURING__POS           3 +#define BMP280_STATUS_REG_MEASURING__MSK           0x08 +#define BMP280_STATUS_REG_MEASURING__LEN           1 +#define BMP280_STATUS_REG_MEASURING__REG           BMP280_STATUS_REG + +#define BMP280_STATUS_REG_IMUPDATE__POS            0 +#define BMP280_STATUS_REG_IMUPDATE__MSK            0x01 +#define BMP280_STATUS_REG_IMUPDATE__LEN            1 +#define BMP280_STATUS_REG_IMUPDATE__REG            BMP280_STATUS_REG + +/* Control Measurement Register */ +#define BMP280_CTRLMEAS_REG_OSRST__POS             5 +#define BMP280_CTRLMEAS_REG_OSRST__MSK             0xE0 +#define BMP280_CTRLMEAS_REG_OSRST__LEN             3 +#define BMP280_CTRLMEAS_REG_OSRST__REG             BMP280_CTRLMEAS_REG + +#define BMP280_CTRLMEAS_REG_OSRSP__POS             2 +#define BMP280_CTRLMEAS_REG_OSRSP__MSK             0x1C +#define BMP280_CTRLMEAS_REG_OSRSP__LEN             3 +#define BMP280_CTRLMEAS_REG_OSRSP__REG             BMP280_CTRLMEAS_REG + +#define BMP280_CTRLMEAS_REG_MODE__POS              0 +#define BMP280_CTRLMEAS_REG_MODE__MSK              0x03 +#define BMP280_CTRLMEAS_REG_MODE__LEN              2 +#define BMP280_CTRLMEAS_REG_MODE__REG              BMP280_CTRLMEAS_REG + +/* Configuation Register */ +#define BMP280_CONFIG_REG_TSB__POS                 5 +#define BMP280_CONFIG_REG_TSB__MSK                 0xE0 +#define BMP280_CONFIG_REG_TSB__LEN                 3 +#define BMP280_CONFIG_REG_TSB__REG                 BMP280_CONFIG_REG + +#define BMP280_CONFIG_REG_FILTER__POS              2 +#define BMP280_CONFIG_REG_FILTER__MSK              0x1C +#define BMP280_CONFIG_REG_FILTER__LEN              3 +#define BMP280_CONFIG_REG_FILTER__REG              BMP280_CONFIG_REG + +#define BMP280_CONFIG_REG_SPI3WEN__POS             0 +#define BMP280_CONFIG_REG_SPI3WEN__MSK             0x01 +#define BMP280_CONFIG_REG_SPI3WEN__LEN             1 +#define BMP280_CONFIG_REG_SPI3WEN__REG             BMP280_CONFIG_REG + +/* Data Register */ +#define BMP280_PRESSURE_XLSB_REG_DATA__POS         4 +#define BMP280_PRESSURE_XLSB_REG_DATA__MSK         0xF0 +#define BMP280_PRESSURE_XLSB_REG_DATA__LEN         4 +#define BMP280_PRESSURE_XLSB_REG_DATA__REG         BMP280_PRESSURE_XLSB_REG + +#define BMP280_TEMPERATURE_XLSB_REG_DATA__POS      4 +#define BMP280_TEMPERATURE_XLSB_REG_DATA__MSK      0xF0 +#define BMP280_TEMPERATURE_XLSB_REG_DATA__LEN      4 +#define BMP280_TEMPERATURE_XLSB_REG_DATA__REG      BMP280_TEMPERATURE_XLSB_REG + +#define BMP280_RATE_SCALE  35 +#define DATA_BMP280_MIN_READ_TIME            (32 * NSEC_PER_MSEC) +#define BMP280_DATA_BYTES_9911                6 +#define FAKE_DATA_NUM_BYTES 10 + +/** this structure holds all device specific calibration parameters */ +struct bmp280_calibration_param_t { +	u32 dig_T1; +	s32 dig_T2; +	s32 dig_T3; +	u32 dig_P1; +	s32 dig_P2; +	s32 dig_P3; +	s32 dig_P4; +	s32 dig_P5; +	s32 dig_P6; +	s32 dig_P7; +	s32 dig_P8; +	s32 dig_P9; + +	s32 t_fine; +}; +/** BMP280 image registers data structure */ +struct bmp280_t { +	struct bmp280_calibration_param_t cal_param; + +	u8 chip_id; +	u8 dev_addr; + +	u8 waittime; + +	u8 osrs_t; +	u8 osrs_p; +}; +static struct bmp280_t bmp280; + +static int bmp280_get_calib_param(struct inv_mpu_state *st) +{ +	u8 d[24]; +	int r; + +	r = inv_aux_read(BMP280_DIG_T1_LSB_REG, 24, d); +	if (r) +		return r; + +	bmp280.cal_param.dig_T1 = (u16)((((u16)((u8)d[1])) << +		SHIFT_LEFT_8_POSITION) | d[0]); +	bmp280.cal_param.dig_T2 = (s16)((((s16)((s8)d[3])) << +		SHIFT_LEFT_8_POSITION) | d[2]); +	bmp280.cal_param.dig_T3 = (s16)((((s16)((s8)d[5])) << +		SHIFT_LEFT_8_POSITION) | d[4]); +	bmp280.cal_param.dig_P1 = (u16)((((u16)((u8)d[7])) << +		SHIFT_LEFT_8_POSITION) | d[6]); +	bmp280.cal_param.dig_P2 = (s16)((((s16)((s8)d[9])) << +		SHIFT_LEFT_8_POSITION) | d[8]); +	bmp280.cal_param.dig_P3 = (s16)((((s16)((s8)d[11])) << +		SHIFT_LEFT_8_POSITION) | d[10]); +	bmp280.cal_param.dig_P4 = (s16)((((s16)((s8)d[13])) << +		SHIFT_LEFT_8_POSITION) | d[12]); +	bmp280.cal_param.dig_P5 = (s16)((((s16)((s8)d[15])) << +		SHIFT_LEFT_8_POSITION) | d[14]); +	bmp280.cal_param.dig_P6 = (s16)((((s16)((s8)d[17])) << +		SHIFT_LEFT_8_POSITION) | d[16]); +	bmp280.cal_param.dig_P7 = (s16)((((s16)((s8)d[19])) << +		SHIFT_LEFT_8_POSITION) | d[18]); +	bmp280.cal_param.dig_P8 = (s16)((((s16)((s8)d[21])) << +		SHIFT_LEFT_8_POSITION) | d[20]); +	bmp280.cal_param.dig_P9 = (s16)((((s16)((s8)d[23])) << +		SHIFT_LEFT_8_POSITION) | d[22]); + +	return 0; +} + +static int inv_setup_bmp280(struct inv_mpu_state *st) +{ +	int r; +	u8 d[10]; + +	/* set to bypass mode */ +	r = inv_i2c_single_write(st, REG_INT_PIN_CFG, +				st->plat_data.int_config | BIT_BYPASS_EN); +	if (r) +		return r; +	/* issue soft reset */ +	r = inv_aux_write(BMP280_RESET_REG, BMP280_SOFT_RESET); +	if (r) +		return r; +	msleep(100); +	r = inv_aux_read(BMP280_CHIPID_REG, 1, d); +	if (r) +		return r; +	/* set pressure as ultra high resolution */ +	bmp280.osrs_t = BMP280_ULTRAHIGHRESOLUTION_OSRS_T; +	bmp280.osrs_p = BMP280_ULTRAHIGHRESOLUTION_OSRS_P; + +	/* set IIR filter as 4 */ +	r = inv_aux_write(BMP280_CONFIG_REG_FILTER__REG, +			BMP280_FILTERCOEFF_16 << SHIFT_LEFT_2_POSITION); +	if (r) +		return r; +	r = bmp280_get_calib_param(st); +	if (r) +		return r; + +	/*restore to non-bypass mode */ +	r = inv_i2c_single_write(st, REG_INT_PIN_CFG, +			st->plat_data.int_config); +	if (r) +		return r; + +	/* setup master mode and master clock and ES bit */ +	r = inv_i2c_single_write(st, REG_I2C_MST_CTRL, BIT_WAIT_FOR_ES); +	if (r) +		return r; +	/*slave 3 is used for pressure mode change only*/ +	r = inv_i2c_single_write(st, REG_I2C_SLV3_ADDR, +						st->plat_data.aux_i2c_addr); +	if (r) +		return r; +	/* pressure sensor mode register address */ +	r = inv_i2c_single_write(st, REG_I2C_SLV3_REG, BMP280_CTRLMEAS_REG); +	if (r) +		return r; +	d[0] = (bmp280.osrs_t << SHIFT_LEFT_5_POSITION) + +			(bmp280.osrs_p << SHIFT_LEFT_2_POSITION) + +						BMP280_FORCED_MODE; +	r = inv_i2c_single_write(st, INV_MPU_REG_I2C_SLV3_DO, d[0]); + +	return r; +} + +static int inv_check_bmp280_self_test(struct inv_mpu_state *st) +{ +	return 0; +} +static int inv_write_bmp280_scale(struct inv_mpu_state *st, int data) +{ +	return 0; +} +static int inv_read_bmp280_scale(struct inv_mpu_state *st, int *scale) +{ +	return 0; +} + +static int inv_resume_bmp280(struct inv_mpu_state *st) +{ +	int r; +	u8 bytes, start; + +	bytes = BMP280_DATA_BYTES_9911; +	start = BMP280_PRESSURE_MSB_REG; +	if (st->chip_config.dmp_on) { +		if (st->sensor[SENSOR_COMPASS].on) { +			if (COMPASS_ID_AK09911 != st->plat_data.sec_slave_id) { +				bytes++; +				start -= 1; +			} +		} else { +			/* if compass is disabled, read fake data for DMP */ +			/*read mode */ +			r = inv_i2c_single_write(st, REG_I2C_SLV0_ADDR, +						INV_MPU_BIT_I2C_READ | +						st->plat_data.aux_i2c_addr); +			if (r) +				return r; +			/* read calibration data as the fake data */ +			r = inv_i2c_single_write(st, REG_I2C_SLV0_REG, +						BMP280_DIG_T1_LSB_REG); +			if (r) +				return r; +			/* slave 0 is enabled, read 10 bytes from here */ +			r = inv_i2c_single_write(st, REG_I2C_SLV0_CTRL, +						INV_MPU_BIT_SLV_EN | +						FAKE_DATA_NUM_BYTES); +		} +	} +	/* slave 2 is used to read data from pressure sensor */ +	/*read mode */ +	r = inv_i2c_single_write(st, REG_I2C_SLV2_ADDR, +					INV_MPU_BIT_I2C_READ | +					st->plat_data.aux_i2c_addr); +	if (r) +		return r; +	/* start from pressure sensor  */ +	r = inv_i2c_single_write(st, REG_I2C_SLV2_REG, start); +	if (r) +		return r; + +	/* slave 2 is enabled, read 6 or 7 bytes from here */ +	r = inv_i2c_single_write(st, REG_I2C_SLV2_CTRL, +					INV_MPU_BIT_SLV_EN | bytes); +	if (r) +		return r; +	/* slave 3 is enabled, write byte length is 1 */ +	r = inv_i2c_single_write(st, REG_I2C_SLV3_CTRL, +						INV_MPU_BIT_SLV_EN | 1); + +	return r; +} + +static int inv_suspend_bmp280(struct inv_mpu_state *st) +{ +	int r; + +	if ((!st->sensor[SENSOR_COMPASS].on) && st->chip_config.dmp_on) { +		/* slave 0 is disabled */ +		r = inv_i2c_single_write(st, REG_I2C_SLV0_CTRL, 0); +		if (r) +			return r; +	} + +	/* slave 2 is disabled */ +	r = inv_i2c_single_write(st, REG_I2C_SLV2_CTRL, 0); +	if (r) +		return r; +	/* slave 3 is disabled */ +	r = inv_i2c_single_write(st, REG_I2C_SLV3_CTRL, 0); + +	return r; +} + +static s32 bmp280_compensate_T_int32(s32 adc_t) +{ +	s32 v_x1_u32r = 0; +	s32 v_x2_u32r = 0; +	s32 temperature = 0; + +	v_x1_u32r  = ((((adc_t >> 3) - ((s32) +		bmp280.cal_param.dig_T1 << 1))) * +		((s32)bmp280.cal_param.dig_T2)) >> 11; +	v_x2_u32r  = (((((adc_t >> 4) - +		((s32)bmp280.cal_param.dig_T1)) * ((adc_t >> 4) - +		((s32)bmp280.cal_param.dig_T1))) >> 12) * +		((s32)bmp280.cal_param.dig_T3)) >> 14; +	bmp280.cal_param.t_fine = v_x1_u32r + v_x2_u32r; +	temperature  = (bmp280.cal_param.t_fine * 5 + 128) >> 8; + +	return temperature; +} + + +static u32 bmp280_compensate_P_int32(s32 adc_p) +{ +	s32 v_x1_u32r = 0; +	s32 v_x2_u32r = 0; +	u32 pressure = 0; + +	v_x1_u32r = (((s32)bmp280.cal_param.t_fine) >> 1) - +		(s32)64000; +	v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11) * +		((s32)bmp280.cal_param.dig_P6); +	v_x2_u32r = v_x2_u32r + ((v_x1_u32r * +		((s32)bmp280.cal_param.dig_P5)) << 1); +	v_x2_u32r = (v_x2_u32r >> 2) + +		(((s32)bmp280.cal_param.dig_P4) << 16); +	v_x1_u32r = (((bmp280.cal_param.dig_P3 * (((v_x1_u32r >> 2) * +		(v_x1_u32r >> 2)) >> 13)) >> 3) + +		((((s32)bmp280.cal_param.dig_P2) * +		v_x1_u32r) >> 1)) >> 18; +	v_x1_u32r = ((((32768+v_x1_u32r)) * +		((s32)bmp280.cal_param.dig_P1))	>> 15); +	/* Avoid exception caused by division by zero */ +	if (v_x1_u32r == 0) +		return 0; +	pressure = (((u32)(((s32)1048576) - adc_p) - +		(v_x2_u32r >> 12))) * 3125; +	if (pressure < 0x80000000) +		pressure = (pressure << 1) / ((u32)v_x1_u32r); +	else +		pressure = (pressure / (u32)v_x1_u32r) * 2; +	v_x1_u32r = (((s32)bmp280.cal_param.dig_P9) * +		((s32)(((pressure >> 3) * (pressure >> 3)) >> 13))) +		>> 12; +	v_x2_u32r = (((s32)(pressure >> 2)) * +		((s32)bmp280.cal_param.dig_P8)) >> 13; +	pressure = (u32)((s32)pressure + +		((v_x1_u32r + v_x2_u32r + bmp280.cal_param.dig_P7) >> 4)); + +	return pressure; +} + +static int inv_bmp280_read_data(struct inv_mpu_state *st, short *o) +{ +	int r, i; +	u8 d[BMP280_DATA_BYTES_9911], reg_addr; +	s32 upressure, utemperature; + +	if (st->chip_config.dmp_on) { +		for (i = 0; i < 6; i++) +			d[i] = st->fifo_data[i]; +	} else { +		if (st->sensor[SENSOR_COMPASS].on) { +			if (COMPASS_ID_AK09911 == st->plat_data.sec_slave_id) +				reg_addr = REG_EXT_SENS_DATA_09; +			else +				reg_addr = REG_EXT_SENS_DATA_08; +		} else { +			reg_addr = REG_EXT_SENS_DATA_00; +		} +		r = inv_i2c_read(st, reg_addr, BMP280_DATA_BYTES_9911, d); +		if (r) +			return r; +	} +	/* pressure */ +	upressure = (s32)((((s32)(d[0])) +		<< SHIFT_LEFT_12_POSITION) | (((u32)(d[1])) +		<< SHIFT_LEFT_4_POSITION) | ((u32)d[2] >> +		SHIFT_RIGHT_4_POSITION)); + +	/* Temperature */ +	utemperature = (s32)((( +		(s32) (d[3])) << SHIFT_LEFT_12_POSITION) | +		(((u32)(d[4])) << SHIFT_LEFT_4_POSITION) +		| ((u32)d[5] >> SHIFT_RIGHT_4_POSITION)); + +	bmp280_compensate_T_int32(utemperature); +	r = bmp280_compensate_P_int32(upressure); +	o[0] = 0; +	o[1] = (r >> 16); +	o[2] = (r & 0xffff); + +	return 0; +} + +static struct inv_mpu_slave slave_bmp280 = { +	.suspend   = inv_suspend_bmp280, +	.resume    = inv_resume_bmp280, +	.get_scale = inv_read_bmp280_scale, +	.set_scale = inv_write_bmp280_scale, +	.self_test = inv_check_bmp280_self_test, +	.setup     = inv_setup_bmp280, +	.read_data = inv_bmp280_read_data, +	.rate_scale = BMP280_RATE_SCALE, +	.min_read_time = DATA_BMP280_MIN_READ_TIME, +}; + +int inv_mpu_setup_pressure_slave(struct inv_mpu_state *st) +{ +	switch (st->plat_data.aux_slave_id) { +	case PRESSURE_ID_BMP280: +		st->slave_pressure = &slave_bmp280; +		break; +	default: +		return -EINVAL; +	} + +	return st->slave_pressure->setup(st); +} +  |