Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jean-Baptiste Maneyrol | 1125 | 95.83% | 3 | 75.00% |
Len Baker | 49 | 4.17% | 1 | 25.00% |
Total | 1174 | 4 |
// 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" /* * MPU9xxx magnetometer are AKM chips on I2C aux bus * MPU9150 is AK8975 * MPU9250 is AK8963 */ #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_MPU9250_MAGN_BIT_OUTPUT_BIT 0x10 #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 #define INV_MPU_MAGN_REG_ASAZ 0x12 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; default: return false; } } /* init magnetometer chip */ static int inv_magn_init(struct inv_mpu6050_state *st) { uint8_t val; uint8_t asa[3]; int32_t sensitivity; 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; /* 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_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, 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; /* * 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 * * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1) * Factor simplification: * Hadj = H * ((ASA + 128) / 256) * * raw_to_gauss = Hadj * sensitivity */ 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; } /** * 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) { uint8_t val; 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 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; 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) { struct device *dev = regmap_get_device(st->map); const char *orient; char *str; int i; /* fill magnetometer orientation */ switch (st->chip_type) { case INV_MPU9150: 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 = 6; i < 9; ++i) { orient = st->orientation.rotation[i]; /* * The value is negated according to one of the following * rules: * * 1) Drop leading minus. * 2) Leave 0 as is. * 3) Add leading minus. */ if (orient[0] == '-') str = devm_kstrdup(dev, orient + 1, GFP_KERNEL); else if (!strcmp(orient, "0")) str = devm_kstrdup(dev, orient, GFP_KERNEL); else str = devm_kasprintf(dev, GFP_KERNEL, "-%s", orient); if (!str) return -ENOMEM; st->magn_orient.rotation[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(struct inv_mpu6050_state *st, int axis, int *val) { unsigned int status; __be16 data; uint8_t addr; int ret; /* quit if chip is not supported */ if (!inv_magn_supported(st)) return -ENODEV; /* Mag data: XH,XL,YH,YL,ZH,ZL */ switch (axis) { case IIO_MOD_X: addr = 0; break; case IIO_MOD_Y: addr = 2; break; case IIO_MOD_Z: addr = 4; break; default: return -EINVAL; } addr += INV_MPU6050_REG_EXT_SENS_DATA; /* 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, addr, &data, sizeof(data)); if (ret) return ret; *val = (int16_t)be16_to_cpu(data); return IIO_VAL_INT; }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1