Commit a2587eb0 authored by Jean-Baptiste Maneyrol's avatar Jean-Baptiste Maneyrol Committed by Jonathan Cameron
Browse files

iio: imu: inv_mpu6050: add support of MPU9150 magnetometer



Add support for driving MPU9150 magnetometer (AK8975) from mpu.

Signed-off-by: default avatarJean-Baptiste Maneyrol <jmaneyrol@invensense.com>
Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent b95ed406
Loading
Loading
Loading
Loading
+44 −13
Original line number Diff line number Diff line
@@ -914,6 +914,33 @@ static const unsigned long inv_mpu_scan_masks[] = {
		.ext_info = inv_ext_info,				\
	}

static const struct iio_chan_spec inv_mpu9150_channels[] = {
	IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
	/*
	 * Note that temperature should only be via polled reading only,
	 * not the final scan elements output.
	 */
	{
		.type = IIO_TEMP,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
				| BIT(IIO_CHAN_INFO_OFFSET)
				| BIT(IIO_CHAN_INFO_SCALE),
		.scan_index = -1,
	},
	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),

	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),

	/* Magnetometer resolution is 13 bits */
	INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 13, INV_MPU9X50_SCAN_MAGN_X),
	INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 13, INV_MPU9X50_SCAN_MAGN_Y),
	INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 13, INV_MPU9X50_SCAN_MAGN_Z),
};

static const struct iio_chan_spec inv_mpu9250_channels[] = {
	IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
	/*
@@ -1323,21 +1350,16 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
		inv_mpu_bus_setup(indio_dev);

	switch (chip_type) {
	case INV_MPU9150:
		indio_dev->channels = inv_mpu9150_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels);
		indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
		break;
	case INV_MPU9250:
	case INV_MPU9255:
		/*
		 * Use magnetometer inside the chip only if there is no i2c
		 * auxiliary device in use.
		 */
		if (!st->magn_disabled) {
		indio_dev->channels = inv_mpu9250_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
		indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
		} else {
			indio_dev->channels = inv_mpu_channels;
			indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
			indio_dev->available_scan_masks = inv_mpu_scan_masks;
		}
		break;
	case INV_ICM20602:
		indio_dev->channels = inv_icm20602_channels;
@@ -1350,6 +1372,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
		indio_dev->available_scan_masks = inv_mpu_scan_masks;
		break;
	}
	/*
	 * Use magnetometer inside the chip only if there is no i2c
	 * auxiliary device in use. Otherwise Going back to 6-axis only.
	 */
	if (st->magn_disabled) {
		indio_dev->channels = inv_mpu_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
		indio_dev->available_scan_masks = inv_mpu_scan_masks;
	}

	indio_dev->info = &mpu_info;
	indio_dev->modes = INDIO_BUFFER_TRIGGERED;
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev)
	case INV_ICM20602:
		/* no i2c auxiliary bus on the chip */
		return false;
	case INV_MPU9150:
	case INV_MPU9250:
	case INV_MPU9255:
		if (st->magn_disabled)
@@ -102,6 +103,7 @@ static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
	struct device_node *mux_node;

	switch (st->chip_type) {
	case INV_MPU9150:
	case INV_MPU9250:
	case INV_MPU9255:
		mux_node = of_get_child_by_name(dev->of_node, "i2c-gate");
+57 −23
Original line number Diff line number Diff line
@@ -12,7 +12,9 @@
#include "inv_mpu_magn.h"

/*
 * MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus
 * MPU9xxx magnetometer are AKM chips on I2C aux bus
 * MPU9150 is AK8975
 * MPU9250 is AK8963
 */
#define INV_MPU_MAGN_I2C_ADDR		0x0C

@@ -33,10 +35,10 @@
#define INV_MPU_MAGN_BITS_MODE_PWDN	0x00
#define INV_MPU_MAGN_BITS_MODE_SINGLE	0x01
#define INV_MPU_MAGN_BITS_MODE_FUSE	0x0F
#define INV_MPU_MAGN_BIT_OUTPUT_BIT	0x10
#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT	0x10

#define INV_MPU_MAGN_REG_CNTL2		0x0B
#define INV_MPU_MAGN_BIT_SRST		0x01
#define INV_MPU9250_MAGN_REG_CNTL2	0x0B
#define INV_MPU9250_MAGN_BIT_SRST	0x01

#define INV_MPU_MAGN_REG_ASAX		0x10
#define INV_MPU_MAGN_REG_ASAY		0x11
@@ -48,6 +50,7 @@
static bool inv_magn_supported(const struct inv_mpu6050_state *st)
{
	switch (st->chip_type) {
	case INV_MPU9150:
	case INV_MPU9250:
	case INV_MPU9255:
		return true;
@@ -61,6 +64,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
{
	uint8_t val;
	uint8_t asa[3];
	int32_t sensitivity;
	int ret;

	/* check whoami */
@@ -71,12 +75,19 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
	if (val != INV_MPU_MAGN_BITS_WIA)
		return -ENODEV;

	/* reset chip */
	/* software reset for MPU925x only */
	switch (st->chip_type) {
	case INV_MPU9250:
	case INV_MPU9255:
		ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
				INV_MPU_MAGN_REG_CNTL2,
				INV_MPU_MAGN_BIT_SRST);
					INV_MPU9250_MAGN_REG_CNTL2,
					INV_MPU9250_MAGN_BIT_SRST);
		if (ret)
			return ret;
		break;
	default:
		break;
	}

	/* read fuse ROM data */
	ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
@@ -97,6 +108,25 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
	if (ret)
		return ret;

	/*
	 * Sensor sentivity
	 * 1 uT = 0.01 G and value is in micron (1e6)
	 * sensitvity = x uT * 0.01 * 1e6
	 */
	switch (st->chip_type) {
	case INV_MPU9150:
		/* sensor sensitivity is 0.3 uT */
		sensitivity = 3000;
		break;
	case INV_MPU9250:
	case INV_MPU9255:
		/* sensor sensitivity in 16 bits mode: 0.15 uT */
		sensitivity = 1500;
		break;
	default:
		return -EINVAL;
	}

	/*
	 * Sensitivity adjustement and scale to Gauss
	 *
@@ -104,16 +134,11 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
	 * Factor simplification:
	 * Hadj = H * ((ASA + 128) / 256)
	 *
	 * Sensor sentivity
	 * 0.15 uT in 16 bits mode
	 * 1 uT = 0.01 G and value is in micron (1e6)
	 * sensitvity = 0.15 uT * 0.01 * 1e6
	 *
	 * raw_to_gauss = Hadj * 1500
	 * raw_to_gauss = Hadj * sensitivity
	 */
	st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256;
	st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256;
	st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256;
	st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * sensitivity) / 256;
	st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * sensitivity) / 256;
	st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * sensitivity) / 256;

	return 0;
}
@@ -129,6 +154,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
 */
int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
{
	uint8_t val;
	int ret;

	/* quit if chip is not supported */
@@ -179,10 +205,17 @@ int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
	if (ret)
		return ret;

	/* add 16 bits mode */
	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1),
			   INV_MPU_MAGN_BITS_MODE_SINGLE |
			   INV_MPU_MAGN_BIT_OUTPUT_BIT);
	/* add 16 bits mode for MPU925x */
	val = INV_MPU_MAGN_BITS_MODE_SINGLE;
	switch (st->chip_type) {
	case INV_MPU9250:
	case INV_MPU9255:
		val |= INV_MPU9250_MAGN_BIT_OUTPUT_BIT;
		break;
	default:
		break;
	}
	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), val);
	if (ret)
		return ret;

@@ -237,6 +270,7 @@ int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)

	/* fill magnetometer orientation */
	switch (st->chip_type) {
	case INV_MPU9150:
	case INV_MPU9250:
	case INV_MPU9255:
		/* x <- y */
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ static void inv_scan_query(struct iio_dev *indio_dev)
	struct inv_mpu6050_state *st = iio_priv(indio_dev);

	switch (st->chip_type) {
	case INV_MPU9150:
	case INV_MPU9250:
	case INV_MPU9255:
		return inv_scan_query_mpu9x50(indio_dev);