1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2019 TDK-InvenSense, Inc.
6 #include <linux/kernel.h>
7 #include <linux/device.h>
8 #include <linux/string.h>
10 #include "inv_mpu_aux.h"
11 #include "inv_mpu_iio.h"
12 #include "inv_mpu_magn.h"
15 * MPU9xxx magnetometer are AKM chips on I2C aux bus
19 #define INV_MPU_MAGN_I2C_ADDR 0x0C
21 #define INV_MPU_MAGN_REG_WIA 0x00
22 #define INV_MPU_MAGN_BITS_WIA 0x48
24 #define INV_MPU_MAGN_REG_ST1 0x02
25 #define INV_MPU_MAGN_BIT_DRDY 0x01
26 #define INV_MPU_MAGN_BIT_DOR 0x02
28 #define INV_MPU_MAGN_REG_DATA 0x03
30 #define INV_MPU_MAGN_REG_ST2 0x09
31 #define INV_MPU_MAGN_BIT_HOFL 0x08
32 #define INV_MPU_MAGN_BIT_BITM 0x10
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
40 #define INV_MPU9250_MAGN_REG_CNTL2 0x0B
41 #define INV_MPU9250_MAGN_BIT_SRST 0x01
43 #define INV_MPU_MAGN_REG_ASAX 0x10
44 #define INV_MPU_MAGN_REG_ASAY 0x11
45 #define INV_MPU_MAGN_REG_ASAZ 0x12
47 static bool inv_magn_supported(const struct inv_mpu6050_state *st)
49 switch (st->chip_type) {
59 /* init magnetometer chip */
60 static int inv_magn_init(struct inv_mpu6050_state *st)
68 ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_WIA,
72 if (val != INV_MPU_MAGN_BITS_WIA)
75 /* software reset for MPU925x only */
76 switch (st->chip_type) {
79 ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
80 INV_MPU9250_MAGN_REG_CNTL2,
81 INV_MPU9250_MAGN_BIT_SRST);
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);
96 ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_ASAX,
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);
110 * 1 uT = 0.01 G and value is in micron (1e6)
111 * sensitvity = x uT * 0.01 * 1e6
113 switch (st->chip_type) {
115 /* sensor sensitivity is 0.3 uT */
120 /* sensor sensitivity in 16 bits mode: 0.15 uT */
128 * Sensitivity adjustement and scale to Gauss
130 * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1)
131 * Factor simplification:
132 * Hadj = H * ((ASA + 128) / 256)
134 * raw_to_gauss = Hadj * sensitivity
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;
144 * inv_mpu_magn_probe() - probe and setup magnetometer chip
145 * @st: driver internal state
147 * Returns 0 on success, a negative error code otherwise
149 * It is probing the chip and setting up all needed i2c transfers.
150 * Noop if there is no magnetometer in the chip.
152 int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
157 /* quit if chip is not supported */
158 if (!inv_magn_supported(st))
161 /* configure i2c master aux port */
162 ret = inv_mpu_aux_init(st);
166 /* check and init mag chip */
167 ret = inv_magn_init(st);
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
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);
181 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0),
182 INV_MPU_MAGN_REG_DATA);
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);
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);
200 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(1),
201 INV_MPU_MAGN_REG_CNTL1);
205 /* add 16 bits mode for MPU925x */
206 val = INV_MPU_MAGN_BITS_MODE_SINGLE;
207 switch (st->chip_type) {
210 val |= INV_MPU9250_MAGN_BIT_OUTPUT_BIT;
215 ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), val);
219 return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(1),
220 INV_MPU6050_BIT_SLV_EN | 1);
224 * inv_mpu_magn_set_rate() - set magnetometer sampling rate
225 * @st: driver internal state
226 * @fifo_rate: mpu set fifo rate
228 * Returns 0 on success, a negative error code otherwise
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.
234 int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)
238 /* quit if chip is not supported */
239 if (!inv_magn_supported(st))
243 * update i2c master delay to limit mag sampling to max frequency
244 * compute fifo_rate divider d: rate = fifo_rate / (d + 1)
246 if (fifo_rate > INV_MPU_MAGN_FREQ_HZ_MAX)
247 d = fifo_rate / INV_MPU_MAGN_FREQ_HZ_MAX - 1;
251 return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d);
255 * inv_mpu_magn_set_orient() - fill magnetometer mounting matrix
256 * @st: driver internal state
258 * Returns 0 on success, a negative error code otherwise
260 * Fill magnetometer mounting matrix using the provided chip matrix.
262 int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
264 struct device *dev = regmap_get_device(st->map);
269 /* fill magnetometer orientation */
270 switch (st->chip_type) {
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];
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];
283 for (i = 6; i < 9; ++i) {
284 orient = st->orientation.rotation[i];
287 * The value is negated according to one of the following
290 * 1) Drop leading minus.
292 * 3) Add leading minus.
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);
299 str = devm_kasprintf(dev, GFP_KERNEL, "-%s", orient);
303 st->magn_orient.rotation[i] = str;
307 st->magn_orient = st->orientation;
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
320 * Returns 0 on success, a negative error code otherwise
322 int inv_mpu_magn_read(struct inv_mpu6050_state *st, int axis, int *val)
329 /* quit if chip is not supported */
330 if (!inv_magn_supported(st))
333 /* Mag data: XH,XL,YH,YL,ZH,ZL */
347 addr += INV_MPU6050_REG_EXT_SENS_DATA;
349 /* check i2c status and read raw data */
350 ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
354 if (status & INV_MPU6050_BIT_I2C_SLV0_NACK ||
355 status & INV_MPU6050_BIT_I2C_SLV1_NACK)
358 ret = regmap_bulk_read(st->map, addr, &data, sizeof(data));
362 *val = (int16_t)be16_to_cpu(data);