mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
iio: imu: inv_mpu6050: add MPU925x magnetometer support
Add support of driving MPU9250 magnetometer connected on i2c auxiliary bus using the MPU i2c master. Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
16ef433769
commit
b1392de061
@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
|
||||
inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o \
|
||||
inv_mpu_aux.o
|
||||
inv_mpu_aux.o inv_mpu_magn.o
|
||||
|
||||
obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
|
||||
inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include "inv_mpu_iio.h"
|
||||
#include "inv_mpu_magn.h"
|
||||
|
||||
/*
|
||||
* this is the gyro scale translated from dynamic range plus/minus
|
||||
@ -332,6 +333,11 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
|
||||
*/
|
||||
st->chip_period = NSEC_PER_MSEC;
|
||||
|
||||
/* magn chip init, noop if not present in the chip */
|
||||
result = inv_mpu_magn_probe(st);
|
||||
if (result)
|
||||
goto error_power_off;
|
||||
|
||||
return inv_mpu6050_set_power_itg(st, false);
|
||||
|
||||
error_power_off:
|
||||
@ -411,6 +417,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||
ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
|
||||
IIO_MOD_X, val);
|
||||
break;
|
||||
case IIO_MAGN:
|
||||
ret = inv_mpu_magn_read(st, chan->channel2, val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
@ -469,6 +478,8 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
|
||||
*val2 = INV_MPU6050_TEMP_SCALE;
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_MAGN:
|
||||
return inv_mpu_magn_get_scale(st, chan, val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -710,6 +721,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
|
||||
if (result)
|
||||
goto fifo_rate_fail_power_off;
|
||||
|
||||
/* update rate for magn, noop if not present in chip */
|
||||
result = inv_mpu_magn_set_rate(st, fifo_rate);
|
||||
if (result)
|
||||
goto fifo_rate_fail_power_off;
|
||||
|
||||
fifo_rate_fail_power_off:
|
||||
result |= inv_mpu6050_set_power_itg(st, false);
|
||||
fifo_rate_fail_unlock:
|
||||
@ -795,8 +811,14 @@ inv_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct inv_mpu6050_state *data = iio_priv(indio_dev);
|
||||
const struct iio_mount_matrix *matrix;
|
||||
|
||||
return &data->orientation;
|
||||
if (chan->type == IIO_MAGN)
|
||||
matrix = &data->magn_orient;
|
||||
else
|
||||
matrix = &data->orientation;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info inv_ext_info[] = {
|
||||
@ -864,6 +886,98 @@ static const unsigned long inv_mpu_scan_masks[] = {
|
||||
0,
|
||||
};
|
||||
|
||||
#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index) \
|
||||
{ \
|
||||
.type = IIO_MAGN, \
|
||||
.modified = 1, \
|
||||
.channel2 = _chan2, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_RAW), \
|
||||
.scan_index = _index, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = _bits, \
|
||||
.storagebits = 16, \
|
||||
.shift = 0, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
.ext_info = inv_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec inv_mpu9250_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 16 bits */
|
||||
INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X),
|
||||
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y),
|
||||
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z),
|
||||
};
|
||||
|
||||
static const unsigned long inv_mpu9x50_scan_masks[] = {
|
||||
/* 3-axis accel */
|
||||
BIT(INV_MPU6050_SCAN_ACCL_X)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Y)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Z),
|
||||
/* 3-axis gyro */
|
||||
BIT(INV_MPU6050_SCAN_GYRO_X)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Y)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Z),
|
||||
/* 3-axis magn */
|
||||
BIT(INV_MPU9X50_SCAN_MAGN_X)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
|
||||
/* 6-axis accel + gyro */
|
||||
BIT(INV_MPU6050_SCAN_ACCL_X)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Y)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Z)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_X)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Y)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Z),
|
||||
/* 6-axis accel + magn */
|
||||
BIT(INV_MPU6050_SCAN_ACCL_X)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Y)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Z)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_X)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
|
||||
/* 6-axis gyro + magn */
|
||||
BIT(INV_MPU6050_SCAN_GYRO_X)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Y)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Z)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_X)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
|
||||
/* 9-axis accel + gyro + magn */
|
||||
BIT(INV_MPU6050_SCAN_ACCL_X)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Y)
|
||||
| BIT(INV_MPU6050_SCAN_ACCL_Z)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_X)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Y)
|
||||
| BIT(INV_MPU6050_SCAN_GYRO_Z)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_X)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
|
||||
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
|
||||
0,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec inv_icm20602_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
|
||||
{
|
||||
@ -1145,6 +1259,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* fill magnetometer orientation */
|
||||
result = inv_mpu_magn_set_orient(st);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* power is turned on inside check chip type*/
|
||||
result = inv_check_and_setup_chip(st);
|
||||
if (result)
|
||||
@ -1168,14 +1287,33 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||
if (inv_mpu_bus_setup)
|
||||
inv_mpu_bus_setup(indio_dev);
|
||||
|
||||
if (chip_type == INV_ICM20602) {
|
||||
switch (chip_type) {
|
||||
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;
|
||||
indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
|
||||
indio_dev->available_scan_masks = inv_icm20602_scan_masks;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
indio_dev->info = &mpu_info;
|
||||
|
@ -130,6 +130,8 @@ struct inv_mpu6050_hw {
|
||||
* @data_timestamp: timestamp for next data sample.
|
||||
* @vddio_supply voltage regulator for the chip.
|
||||
* @magn_disabled: magnetometer disabled for backward compatibility reason.
|
||||
* @magn_raw_to_gauss: coefficient to convert mag raw value to Gauss.
|
||||
* @magn_orient: magnetometer sensor chip orientation if available.
|
||||
*/
|
||||
struct inv_mpu6050_state {
|
||||
struct mutex lock;
|
||||
@ -152,6 +154,8 @@ struct inv_mpu6050_state {
|
||||
s64 data_timestamp;
|
||||
struct regulator *vddio_supply;
|
||||
bool magn_disabled;
|
||||
s32 magn_raw_to_gauss[3];
|
||||
struct iio_mount_matrix magn_orient;
|
||||
};
|
||||
|
||||
/*register and associated bit definition*/
|
||||
|
356
drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
Normal file
356
drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
Normal file
@ -0,0 +1,356 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 TDK-InvenSense, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "inv_mpu_aux.h"
|
||||
#include "inv_mpu_iio.h"
|
||||
#include "inv_mpu_magn.h"
|
||||
|
||||
/*
|
||||
* MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus
|
||||
*/
|
||||
#define INV_MPU_MAGN_I2C_ADDR 0x0C
|
||||
|
||||
#define INV_MPU_MAGN_REG_WIA 0x00
|
||||
#define INV_MPU_MAGN_BITS_WIA 0x48
|
||||
|
||||
#define INV_MPU_MAGN_REG_ST1 0x02
|
||||
#define INV_MPU_MAGN_BIT_DRDY 0x01
|
||||
#define INV_MPU_MAGN_BIT_DOR 0x02
|
||||
|
||||
#define INV_MPU_MAGN_REG_DATA 0x03
|
||||
|
||||
#define INV_MPU_MAGN_REG_ST2 0x09
|
||||
#define INV_MPU_MAGN_BIT_HOFL 0x08
|
||||
#define INV_MPU_MAGN_BIT_BITM 0x10
|
||||
|
||||
#define INV_MPU_MAGN_REG_CNTL1 0x0A
|
||||
#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_MPU_MAGN_REG_CNTL2 0x0B
|
||||
#define INV_MPU_MAGN_BIT_SRST 0x01
|
||||
|
||||
#define INV_MPU_MAGN_REG_ASAX 0x10
|
||||
#define INV_MPU_MAGN_REG_ASAY 0x11
|
||||
#define INV_MPU_MAGN_REG_ASAZ 0x12
|
||||
|
||||
/* Magnetometer maximum frequency */
|
||||
#define INV_MPU_MAGN_FREQ_HZ_MAX 50
|
||||
|
||||
static bool inv_magn_supported(const struct inv_mpu6050_state *st)
|
||||
{
|
||||
switch (st->chip_type) {
|
||||
case INV_MPU9250:
|
||||
case INV_MPU9255:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* init magnetometer chip */
|
||||
static int inv_magn_init(struct inv_mpu6050_state *st)
|
||||
{
|
||||
uint8_t val;
|
||||
uint8_t asa[3];
|
||||
int ret;
|
||||
|
||||
/* check whoami */
|
||||
ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_WIA,
|
||||
&val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val != INV_MPU_MAGN_BITS_WIA)
|
||||
return -ENODEV;
|
||||
|
||||
/* reset chip */
|
||||
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
|
||||
INV_MPU_MAGN_REG_CNTL2,
|
||||
INV_MPU_MAGN_BIT_SRST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* read fuse ROM data */
|
||||
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
|
||||
INV_MPU_MAGN_REG_CNTL1,
|
||||
INV_MPU_MAGN_BITS_MODE_FUSE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_ASAX,
|
||||
asa, sizeof(asa));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* switch back to power-down */
|
||||
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
|
||||
INV_MPU_MAGN_REG_CNTL1,
|
||||
INV_MPU_MAGN_BITS_MODE_PWDN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Sensitivity adjustement and scale to Gauss
|
||||
*
|
||||
* Hadj = H * (((ASA - 128) * 0.5 / 128) + 1)
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* inv_mpu_magn_probe() - probe and setup magnetometer chip
|
||||
* @st: driver internal state
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise
|
||||
*
|
||||
* It is probing the chip and setting up all needed i2c transfers.
|
||||
* Noop if there is no magnetometer in the chip.
|
||||
*/
|
||||
int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* quit if chip is not supported */
|
||||
if (!inv_magn_supported(st))
|
||||
return 0;
|
||||
|
||||
/* configure i2c master aux port */
|
||||
ret = inv_mpu_aux_init(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* check and init mag chip */
|
||||
ret = inv_magn_init(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* configure mpu i2c master accesses
|
||||
* i2c SLV0: read sensor data, 7 bytes data(6)-ST2
|
||||
* Byte swap data to store them in big-endian in impair address groups
|
||||
*/
|
||||
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
|
||||
INV_MPU6050_BIT_I2C_SLV_RNW | INV_MPU_MAGN_I2C_ADDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0),
|
||||
INV_MPU_MAGN_REG_DATA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
|
||||
INV_MPU6050_BIT_SLV_EN |
|
||||
INV_MPU6050_BIT_SLV_BYTE_SW |
|
||||
INV_MPU6050_BIT_SLV_GRP |
|
||||
INV_MPU9X50_BYTES_MAGN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* i2c SLV1: launch single measurement */
|
||||
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(1),
|
||||
INV_MPU_MAGN_I2C_ADDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(1),
|
||||
INV_MPU_MAGN_REG_CNTL1);
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(1),
|
||||
INV_MPU6050_BIT_SLV_EN | 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* inv_mpu_magn_set_rate() - set magnetometer sampling rate
|
||||
* @st: driver internal state
|
||||
* @fifo_rate: mpu set fifo rate
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise
|
||||
*
|
||||
* Limit sampling frequency to the maximum value supported by the
|
||||
* magnetometer chip. Resulting in duplicated data for higher frequencies.
|
||||
* Noop if there is no magnetometer in the chip.
|
||||
*/
|
||||
int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)
|
||||
{
|
||||
uint8_t d;
|
||||
|
||||
/* quit if chip is not supported */
|
||||
if (!inv_magn_supported(st))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* update i2c master delay to limit mag sampling to max frequency
|
||||
* compute fifo_rate divider d: rate = fifo_rate / (d + 1)
|
||||
*/
|
||||
if (fifo_rate > INV_MPU_MAGN_FREQ_HZ_MAX)
|
||||
d = fifo_rate / INV_MPU_MAGN_FREQ_HZ_MAX - 1;
|
||||
else
|
||||
d = 0;
|
||||
|
||||
return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* inv_mpu_magn_set_orient() - fill magnetometer mounting matrix
|
||||
* @st: driver internal state
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise
|
||||
*
|
||||
* Fill magnetometer mounting matrix using the provided chip matrix.
|
||||
*/
|
||||
int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
|
||||
{
|
||||
const char *orient;
|
||||
char *str;
|
||||
int i;
|
||||
|
||||
/* fill magnetometer orientation */
|
||||
switch (st->chip_type) {
|
||||
case INV_MPU9250:
|
||||
case INV_MPU9255:
|
||||
/* x <- y */
|
||||
st->magn_orient.rotation[0] = st->orientation.rotation[3];
|
||||
st->magn_orient.rotation[1] = st->orientation.rotation[4];
|
||||
st->magn_orient.rotation[2] = st->orientation.rotation[5];
|
||||
/* y <- x */
|
||||
st->magn_orient.rotation[3] = st->orientation.rotation[0];
|
||||
st->magn_orient.rotation[4] = st->orientation.rotation[1];
|
||||
st->magn_orient.rotation[5] = st->orientation.rotation[2];
|
||||
/* z <- -z */
|
||||
for (i = 0; i < 3; ++i) {
|
||||
orient = st->orientation.rotation[6 + i];
|
||||
/* use length + 2 for adding minus sign if needed */
|
||||
str = devm_kzalloc(regmap_get_device(st->map),
|
||||
strlen(orient) + 2, GFP_KERNEL);
|
||||
if (str == NULL)
|
||||
return -ENOMEM;
|
||||
if (strcmp(orient, "0") == 0) {
|
||||
strcpy(str, orient);
|
||||
} else if (orient[0] == '-') {
|
||||
strcpy(str, &orient[1]);
|
||||
} else {
|
||||
str[0] = '-';
|
||||
strcpy(&str[1], orient);
|
||||
}
|
||||
st->magn_orient.rotation[6 + i] = str;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
st->magn_orient = st->orientation;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* inv_mpu_magn_read() - read magnetometer data
|
||||
* @st: driver internal state
|
||||
* @axis: IIO modifier axis value
|
||||
* @val: store corresponding axis value
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise
|
||||
*/
|
||||
int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val)
|
||||
{
|
||||
unsigned int user_ctrl, status;
|
||||
__be16 data[3];
|
||||
uint8_t addr;
|
||||
uint8_t d;
|
||||
unsigned int period_ms;
|
||||
int ret;
|
||||
|
||||
/* quit if chip is not supported */
|
||||
if (!inv_magn_supported(st))
|
||||
return -ENODEV;
|
||||
|
||||
/* Mag data: X - Y - Z */
|
||||
switch (axis) {
|
||||
case IIO_MOD_X:
|
||||
addr = 0;
|
||||
break;
|
||||
case IIO_MOD_Y:
|
||||
addr = 1;
|
||||
break;
|
||||
case IIO_MOD_Z:
|
||||
addr = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set sample rate to max mag freq */
|
||||
d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU_MAGN_FREQ_HZ_MAX);
|
||||
ret = regmap_write(st->map, st->reg->sample_rate_div, d);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* start i2c master, wait for xfer, stop */
|
||||
user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
|
||||
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* need to wait 2 periods + half-period margin */
|
||||
period_ms = 1000 / INV_MPU_MAGN_FREQ_HZ_MAX;
|
||||
msleep(period_ms * 2 + period_ms / 2);
|
||||
user_ctrl = st->chip_config.user_ctrl;
|
||||
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* restore sample rate */
|
||||
d = st->chip_config.divider;
|
||||
ret = regmap_write(st->map, st->reg->sample_rate_div, d);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* check i2c status and read raw data */
|
||||
ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (status & INV_MPU6050_BIT_I2C_SLV0_NACK ||
|
||||
status & INV_MPU6050_BIT_I2C_SLV1_NACK)
|
||||
return -EIO;
|
||||
|
||||
ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
|
||||
data, sizeof(data));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = (int16_t)be16_to_cpu(data[addr]);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
36
drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
Normal file
36
drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2019 TDK-InvenSense, Inc.
|
||||
*/
|
||||
|
||||
#ifndef INV_MPU_MAGN_H_
|
||||
#define INV_MPU_MAGN_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "inv_mpu_iio.h"
|
||||
|
||||
int inv_mpu_magn_probe(struct inv_mpu6050_state *st);
|
||||
|
||||
/**
|
||||
* inv_mpu_magn_get_scale() - get magnetometer scale value
|
||||
* @st: driver internal state
|
||||
*
|
||||
* Returns IIO data format.
|
||||
*/
|
||||
static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,
|
||||
const struct iio_chan_spec *chan,
|
||||
int *val, int *val2)
|
||||
{
|
||||
*val = 0;
|
||||
*val2 = st->magn_raw_to_gauss[chan->address];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate);
|
||||
|
||||
int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st);
|
||||
|
||||
int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val);
|
||||
|
||||
#endif /* INV_MPU_MAGN_H_ */
|
Loading…
Reference in New Issue
Block a user