1
2
3
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
16
17
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
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
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
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
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
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
110
111
112
113 switch (st->chip_type) {
114 case INV_MPU9150:
115
116 sensitivity = 3000;
117 break;
118 case INV_MPU9250:
119 case INV_MPU9255:
120
121 sensitivity = 1500;
122 break;
123 default:
124 return -EINVAL;
125 }
126
127
128
129
130
131
132
133
134
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
145
146
147
148
149
150
151
152int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
153{
154 uint8_t val;
155 int ret;
156
157
158 if (!inv_magn_supported(st))
159 return 0;
160
161
162 ret = inv_mpu_aux_init(st);
163 if (ret)
164 return ret;
165
166
167 ret = inv_magn_init(st);
168 if (ret)
169 return ret;
170
171
172
173
174
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
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
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
225
226
227
228
229
230
231
232
233
234int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)
235{
236 uint8_t d;
237
238
239 if (!inv_magn_supported(st))
240 return 0;
241
242
243
244
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
256
257
258
259
260
261
262int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
263{
264 const char *orient;
265 char *str;
266 int i;
267
268
269 switch (st->chip_type) {
270 case INV_MPU9150:
271 case INV_MPU9250:
272 case INV_MPU9255:
273
274 st->magn_orient.rotation[0] = st->orientation.rotation[3];
275 st->magn_orient.rotation[1] = st->orientation.rotation[4];
276 st->magn_orient.rotation[2] = st->orientation.rotation[5];
277
278 st->magn_orient.rotation[3] = st->orientation.rotation[0];
279 st->magn_orient.rotation[4] = st->orientation.rotation[1];
280 st->magn_orient.rotation[5] = st->orientation.rotation[2];
281
282 for (i = 0; i < 3; ++i) {
283 orient = st->orientation.rotation[6 + i];
284
285 str = devm_kzalloc(regmap_get_device(st->map),
286 strlen(orient) + 2, GFP_KERNEL);
287 if (str == NULL)
288 return -ENOMEM;
289 if (strcmp(orient, "0") == 0) {
290 strcpy(str, orient);
291 } else if (orient[0] == '-') {
292 strcpy(str, &orient[1]);
293 } else {
294 str[0] = '-';
295 strcpy(&str[1], orient);
296 }
297 st->magn_orient.rotation[6 + i] = str;
298 }
299 break;
300 default:
301 st->magn_orient = st->orientation;
302 break;
303 }
304
305 return 0;
306}
307
308
309
310
311
312
313
314
315
316int inv_mpu_magn_read(struct inv_mpu6050_state *st, int axis, int *val)
317{
318 unsigned int status;
319 __be16 data;
320 uint8_t addr;
321 int ret;
322
323
324 if (!inv_magn_supported(st))
325 return -ENODEV;
326
327
328 switch (axis) {
329 case IIO_MOD_X:
330 addr = 0;
331 break;
332 case IIO_MOD_Y:
333 addr = 2;
334 break;
335 case IIO_MOD_Z:
336 addr = 4;
337 break;
338 default:
339 return -EINVAL;
340 }
341 addr += INV_MPU6050_REG_EXT_SENS_DATA;
342
343
344 ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
345 if (ret)
346 return ret;
347
348 if (status & INV_MPU6050_BIT_I2C_SLV0_NACK ||
349 status & INV_MPU6050_BIT_I2C_SLV1_NACK)
350 return -EIO;
351
352 ret = regmap_bulk_read(st->map, addr, &data, sizeof(data));
353 if (ret)
354 return ret;
355
356 *val = (int16_t)be16_to_cpu(data);
357
358 return IIO_VAL_INT;
359}
360