cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

inv_mpu_magn.c (8654B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2019 TDK-InvenSense, Inc.
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/device.h>
      8#include <linux/string.h>
      9
     10#include "inv_mpu_aux.h"
     11#include "inv_mpu_iio.h"
     12#include "inv_mpu_magn.h"
     13
     14/*
     15 * MPU9xxx magnetometer are AKM chips on I2C aux bus
     16 * MPU9150 is AK8975
     17 * MPU9250 is AK8963
     18 */
     19#define INV_MPU_MAGN_I2C_ADDR		0x0C
     20
     21#define INV_MPU_MAGN_REG_WIA		0x00
     22#define INV_MPU_MAGN_BITS_WIA		0x48
     23
     24#define INV_MPU_MAGN_REG_ST1		0x02
     25#define INV_MPU_MAGN_BIT_DRDY		0x01
     26#define INV_MPU_MAGN_BIT_DOR		0x02
     27
     28#define INV_MPU_MAGN_REG_DATA		0x03
     29
     30#define INV_MPU_MAGN_REG_ST2		0x09
     31#define INV_MPU_MAGN_BIT_HOFL		0x08
     32#define INV_MPU_MAGN_BIT_BITM		0x10
     33
     34#define INV_MPU_MAGN_REG_CNTL1		0x0A
     35#define INV_MPU_MAGN_BITS_MODE_PWDN	0x00
     36#define INV_MPU_MAGN_BITS_MODE_SINGLE	0x01
     37#define INV_MPU_MAGN_BITS_MODE_FUSE	0x0F
     38#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT	0x10
     39
     40#define INV_MPU9250_MAGN_REG_CNTL2	0x0B
     41#define INV_MPU9250_MAGN_BIT_SRST	0x01
     42
     43#define INV_MPU_MAGN_REG_ASAX		0x10
     44#define INV_MPU_MAGN_REG_ASAY		0x11
     45#define INV_MPU_MAGN_REG_ASAZ		0x12
     46
     47static bool inv_magn_supported(const struct inv_mpu6050_state *st)
     48{
     49	switch (st->chip_type) {
     50	case INV_MPU9150:
     51	case INV_MPU9250:
     52	case INV_MPU9255:
     53		return true;
     54	default:
     55		return false;
     56	}
     57}
     58
     59/* init magnetometer chip */
     60static int inv_magn_init(struct inv_mpu6050_state *st)
     61{
     62	uint8_t val;
     63	uint8_t asa[3];
     64	int32_t sensitivity;
     65	int ret;
     66
     67	/* check whoami */
     68	ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_WIA,
     69			       &val, sizeof(val));
     70	if (ret)
     71		return ret;
     72	if (val != INV_MPU_MAGN_BITS_WIA)
     73		return -ENODEV;
     74
     75	/* software reset for MPU925x only */
     76	switch (st->chip_type) {
     77	case INV_MPU9250:
     78	case INV_MPU9255:
     79		ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
     80					INV_MPU9250_MAGN_REG_CNTL2,
     81					INV_MPU9250_MAGN_BIT_SRST);
     82		if (ret)
     83			return ret;
     84		break;
     85	default:
     86		break;
     87	}
     88
     89	/* read fuse ROM data */
     90	ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
     91				INV_MPU_MAGN_REG_CNTL1,
     92				INV_MPU_MAGN_BITS_MODE_FUSE);
     93	if (ret)
     94		return ret;
     95
     96	ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_ASAX,
     97			       asa, sizeof(asa));
     98	if (ret)
     99		return ret;
    100
    101	/* switch back to power-down */
    102	ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
    103				INV_MPU_MAGN_REG_CNTL1,
    104				INV_MPU_MAGN_BITS_MODE_PWDN);
    105	if (ret)
    106		return ret;
    107
    108	/*
    109	 * Sensor sentivity
    110	 * 1 uT = 0.01 G and value is in micron (1e6)
    111	 * sensitvity = x uT * 0.01 * 1e6
    112	 */
    113	switch (st->chip_type) {
    114	case INV_MPU9150:
    115		/* sensor sensitivity is 0.3 uT */
    116		sensitivity = 3000;
    117		break;
    118	case INV_MPU9250:
    119	case INV_MPU9255:
    120		/* sensor sensitivity in 16 bits mode: 0.15 uT */
    121		sensitivity = 1500;
    122		break;
    123	default:
    124		return -EINVAL;
    125	}
    126
    127	/*
    128	 * Sensitivity adjustement and scale to Gauss
    129	 *
    130	 * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1)
    131	 * Factor simplification:
    132	 * Hadj = H * ((ASA + 128) / 256)
    133	 *
    134	 * raw_to_gauss = Hadj * sensitivity
    135	 */
    136	st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * sensitivity) / 256;
    137	st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * sensitivity) / 256;
    138	st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * sensitivity) / 256;
    139
    140	return 0;
    141}
    142
    143/**
    144 * inv_mpu_magn_probe() - probe and setup magnetometer chip
    145 * @st: driver internal state
    146 *
    147 * Returns 0 on success, a negative error code otherwise
    148 *
    149 * It is probing the chip and setting up all needed i2c transfers.
    150 * Noop if there is no magnetometer in the chip.
    151 */
    152int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
    153{
    154	uint8_t val;
    155	int ret;
    156
    157	/* quit if chip is not supported */
    158	if (!inv_magn_supported(st))
    159		return 0;
    160
    161	/* configure i2c master aux port */
    162	ret = inv_mpu_aux_init(st);
    163	if (ret)
    164		return ret;
    165
    166	/* check and init mag chip */
    167	ret = inv_magn_init(st);
    168	if (ret)
    169		return ret;
    170
    171	/*
    172	 * configure mpu i2c master accesses
    173	 * i2c SLV0: read sensor data, 7 bytes data(6)-ST2
    174	 * Byte swap data to store them in big-endian in impair address groups
    175	 */
    176	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
    177			   INV_MPU6050_BIT_I2C_SLV_RNW | INV_MPU_MAGN_I2C_ADDR);
    178	if (ret)
    179		return ret;
    180
    181	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0),
    182			   INV_MPU_MAGN_REG_DATA);
    183	if (ret)
    184		return ret;
    185
    186	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
    187			   INV_MPU6050_BIT_SLV_EN |
    188			   INV_MPU6050_BIT_SLV_BYTE_SW |
    189			   INV_MPU6050_BIT_SLV_GRP |
    190			   INV_MPU9X50_BYTES_MAGN);
    191	if (ret)
    192		return ret;
    193
    194	/* i2c SLV1: launch single measurement */
    195	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(1),
    196			   INV_MPU_MAGN_I2C_ADDR);
    197	if (ret)
    198		return ret;
    199
    200	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(1),
    201			   INV_MPU_MAGN_REG_CNTL1);
    202	if (ret)
    203		return ret;
    204
    205	/* add 16 bits mode for MPU925x */
    206	val = INV_MPU_MAGN_BITS_MODE_SINGLE;
    207	switch (st->chip_type) {
    208	case INV_MPU9250:
    209	case INV_MPU9255:
    210		val |= INV_MPU9250_MAGN_BIT_OUTPUT_BIT;
    211		break;
    212	default:
    213		break;
    214	}
    215	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), val);
    216	if (ret)
    217		return ret;
    218
    219	return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(1),
    220			    INV_MPU6050_BIT_SLV_EN | 1);
    221}
    222
    223/**
    224 * inv_mpu_magn_set_rate() - set magnetometer sampling rate
    225 * @st: driver internal state
    226 * @fifo_rate: mpu set fifo rate
    227 *
    228 * Returns 0 on success, a negative error code otherwise
    229 *
    230 * Limit sampling frequency to the maximum value supported by the
    231 * magnetometer chip. Resulting in duplicated data for higher frequencies.
    232 * Noop if there is no magnetometer in the chip.
    233 */
    234int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)
    235{
    236	uint8_t d;
    237
    238	/* quit if chip is not supported */
    239	if (!inv_magn_supported(st))
    240		return 0;
    241
    242	/*
    243	 * update i2c master delay to limit mag sampling to max frequency
    244	 * compute fifo_rate divider d: rate = fifo_rate / (d + 1)
    245	 */
    246	if (fifo_rate > INV_MPU_MAGN_FREQ_HZ_MAX)
    247		d = fifo_rate / INV_MPU_MAGN_FREQ_HZ_MAX - 1;
    248	else
    249		d = 0;
    250
    251	return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d);
    252}
    253
    254/**
    255 * inv_mpu_magn_set_orient() - fill magnetometer mounting matrix
    256 * @st: driver internal state
    257 *
    258 * Returns 0 on success, a negative error code otherwise
    259 *
    260 * Fill magnetometer mounting matrix using the provided chip matrix.
    261 */
    262int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
    263{
    264	struct device *dev = regmap_get_device(st->map);
    265	const char *orient;
    266	char *str;
    267	int i;
    268
    269	/* fill magnetometer orientation */
    270	switch (st->chip_type) {
    271	case INV_MPU9150:
    272	case INV_MPU9250:
    273	case INV_MPU9255:
    274		/* x <- y */
    275		st->magn_orient.rotation[0] = st->orientation.rotation[3];
    276		st->magn_orient.rotation[1] = st->orientation.rotation[4];
    277		st->magn_orient.rotation[2] = st->orientation.rotation[5];
    278		/* y <- x */
    279		st->magn_orient.rotation[3] = st->orientation.rotation[0];
    280		st->magn_orient.rotation[4] = st->orientation.rotation[1];
    281		st->magn_orient.rotation[5] = st->orientation.rotation[2];
    282		/* z <- -z */
    283		for (i = 6; i < 9; ++i) {
    284			orient = st->orientation.rotation[i];
    285
    286			/*
    287			 * The value is negated according to one of the following
    288			 * rules:
    289			 *
    290			 * 1) Drop leading minus.
    291			 * 2) Leave 0 as is.
    292			 * 3) Add leading minus.
    293			 */
    294			if (orient[0] == '-')
    295				str = devm_kstrdup(dev, orient + 1, GFP_KERNEL);
    296			else if (!strcmp(orient, "0"))
    297				str = devm_kstrdup(dev, orient, GFP_KERNEL);
    298			else
    299				str = devm_kasprintf(dev, GFP_KERNEL, "-%s", orient);
    300			if (!str)
    301				return -ENOMEM;
    302
    303			st->magn_orient.rotation[i] = str;
    304		}
    305		break;
    306	default:
    307		st->magn_orient = st->orientation;
    308		break;
    309	}
    310
    311	return 0;
    312}
    313
    314/**
    315 * inv_mpu_magn_read() - read magnetometer data
    316 * @st: driver internal state
    317 * @axis: IIO modifier axis value
    318 * @val: store corresponding axis value
    319 *
    320 * Returns 0 on success, a negative error code otherwise
    321 */
    322int inv_mpu_magn_read(struct inv_mpu6050_state *st, int axis, int *val)
    323{
    324	unsigned int status;
    325	__be16 data;
    326	uint8_t addr;
    327	int ret;
    328
    329	/* quit if chip is not supported */
    330	if (!inv_magn_supported(st))
    331		return -ENODEV;
    332
    333	/* Mag data: XH,XL,YH,YL,ZH,ZL */
    334	switch (axis) {
    335	case IIO_MOD_X:
    336		addr = 0;
    337		break;
    338	case IIO_MOD_Y:
    339		addr = 2;
    340		break;
    341	case IIO_MOD_Z:
    342		addr = 4;
    343		break;
    344	default:
    345		return -EINVAL;
    346	}
    347	addr += INV_MPU6050_REG_EXT_SENS_DATA;
    348
    349	/* check i2c status and read raw data */
    350	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
    351	if (ret)
    352		return ret;
    353
    354	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK ||
    355			status & INV_MPU6050_BIT_I2C_SLV1_NACK)
    356		return -EIO;
    357
    358	ret = regmap_bulk_read(st->map, addr, &data, sizeof(data));
    359	if (ret)
    360		return ret;
    361
    362	*val = (int16_t)be16_to_cpu(data);
    363
    364	return IIO_VAL_INT;
    365}