1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * IIO driver for Bosch BNO055 IMU |
4 | * |
5 | * Copyright (C) 2021-2022 Istituto Italiano di Tecnologia |
6 | * Electronic Design Laboratory |
7 | * Written by Andrea Merello <andrea.merello@iit.it> |
8 | * |
9 | * Portions of this driver are taken from the BNO055 driver patch |
10 | * from Vlad Dogaru which is Copyright (c) 2016, Intel Corporation. |
11 | * |
12 | * This driver is also based on BMI160 driver, which is: |
13 | * Copyright (c) 2016, Intel Corporation. |
14 | * Copyright (c) 2019, Martin Kelly. |
15 | */ |
16 | |
17 | #include <linux/bitfield.h> |
18 | #include <linux/bitmap.h> |
19 | #include <linux/clk.h> |
20 | #include <linux/debugfs.h> |
21 | #include <linux/device.h> |
22 | #include <linux/firmware.h> |
23 | #include <linux/gpio/consumer.h> |
24 | #include <linux/module.h> |
25 | #include <linux/mutex.h> |
26 | #include <linux/regmap.h> |
27 | #include <linux/util_macros.h> |
28 | |
29 | #include <linux/iio/buffer.h> |
30 | #include <linux/iio/iio.h> |
31 | #include <linux/iio/sysfs.h> |
32 | #include <linux/iio/trigger_consumer.h> |
33 | #include <linux/iio/triggered_buffer.h> |
34 | |
35 | #include "bno055.h" |
36 | |
37 | #define BNO055_FW_UID_FMT "bno055-caldata-%*phN.dat" |
38 | #define BNO055_FW_GENERIC_NAME "bno055-caldata.dat" |
39 | |
40 | /* common registers */ |
41 | #define BNO055_PAGESEL_REG 0x7 |
42 | |
43 | /* page 0 registers */ |
44 | #define BNO055_CHIP_ID_REG 0x0 |
45 | #define BNO055_CHIP_ID_MAGIC 0xA0 |
46 | #define BNO055_SW_REV_LSB_REG 0x4 |
47 | #define BNO055_SW_REV_MSB_REG 0x5 |
48 | #define BNO055_ACC_DATA_X_LSB_REG 0x8 |
49 | #define BNO055_ACC_DATA_Y_LSB_REG 0xA |
50 | #define BNO055_ACC_DATA_Z_LSB_REG 0xC |
51 | #define BNO055_MAG_DATA_X_LSB_REG 0xE |
52 | #define BNO055_MAG_DATA_Y_LSB_REG 0x10 |
53 | #define BNO055_MAG_DATA_Z_LSB_REG 0x12 |
54 | #define BNO055_GYR_DATA_X_LSB_REG 0x14 |
55 | #define BNO055_GYR_DATA_Y_LSB_REG 0x16 |
56 | #define BNO055_GYR_DATA_Z_LSB_REG 0x18 |
57 | #define BNO055_EUL_DATA_X_LSB_REG 0x1A |
58 | #define BNO055_EUL_DATA_Y_LSB_REG 0x1C |
59 | #define BNO055_EUL_DATA_Z_LSB_REG 0x1E |
60 | #define BNO055_QUAT_DATA_W_LSB_REG 0x20 |
61 | #define BNO055_LIA_DATA_X_LSB_REG 0x28 |
62 | #define BNO055_LIA_DATA_Y_LSB_REG 0x2A |
63 | #define BNO055_LIA_DATA_Z_LSB_REG 0x2C |
64 | #define BNO055_GRAVITY_DATA_X_LSB_REG 0x2E |
65 | #define BNO055_GRAVITY_DATA_Y_LSB_REG 0x30 |
66 | #define BNO055_GRAVITY_DATA_Z_LSB_REG 0x32 |
67 | #define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2) |
68 | #define BNO055_TEMP_REG 0x34 |
69 | #define BNO055_CALIB_STAT_REG 0x35 |
70 | #define BNO055_CALIB_STAT_MAGN_SHIFT 0 |
71 | #define BNO055_CALIB_STAT_ACCEL_SHIFT 2 |
72 | #define BNO055_CALIB_STAT_GYRO_SHIFT 4 |
73 | #define BNO055_CALIB_STAT_SYS_SHIFT 6 |
74 | #define BNO055_SYS_ERR_REG 0x3A |
75 | #define BNO055_POWER_MODE_REG 0x3E |
76 | #define BNO055_POWER_MODE_NORMAL 0 |
77 | #define BNO055_SYS_TRIGGER_REG 0x3F |
78 | #define BNO055_SYS_TRIGGER_RST_SYS BIT(5) |
79 | #define BNO055_SYS_TRIGGER_CLK_SEL BIT(7) |
80 | #define BNO055_OPR_MODE_REG 0x3D |
81 | #define BNO055_OPR_MODE_CONFIG 0x0 |
82 | #define BNO055_OPR_MODE_AMG 0x7 |
83 | #define BNO055_OPR_MODE_FUSION_FMC_OFF 0xB |
84 | #define BNO055_OPR_MODE_FUSION 0xC |
85 | #define BNO055_UNIT_SEL_REG 0x3B |
86 | /* Android orientation mode means: pitch value decreases turning clockwise */ |
87 | #define BNO055_UNIT_SEL_ANDROID BIT(7) |
88 | #define BNO055_UNIT_SEL_GYR_RPS BIT(1) |
89 | #define BNO055_CALDATA_START 0x55 |
90 | #define BNO055_CALDATA_END 0x6A |
91 | #define BNO055_CALDATA_LEN 22 |
92 | |
93 | /* |
94 | * The difference in address between the register that contains the |
95 | * value and the register that contains the offset. This applies for |
96 | * accel, gyro and magn channels. |
97 | */ |
98 | #define BNO055_REG_OFFSET_ADDR 0x4D |
99 | |
100 | /* page 1 registers */ |
101 | #define BNO055_PG1(x) ((x) | 0x80) |
102 | #define BNO055_ACC_CONFIG_REG BNO055_PG1(0x8) |
103 | #define BNO055_ACC_CONFIG_LPF_MASK GENMASK(4, 2) |
104 | #define BNO055_ACC_CONFIG_RANGE_MASK GENMASK(1, 0) |
105 | #define BNO055_MAG_CONFIG_REG BNO055_PG1(0x9) |
106 | #define BNO055_MAG_CONFIG_HIGHACCURACY 0x18 |
107 | #define BNO055_MAG_CONFIG_ODR_MASK GENMASK(2, 0) |
108 | #define BNO055_GYR_CONFIG_REG BNO055_PG1(0xA) |
109 | #define BNO055_GYR_CONFIG_RANGE_MASK GENMASK(2, 0) |
110 | #define BNO055_GYR_CONFIG_LPF_MASK GENMASK(5, 3) |
111 | #define BNO055_GYR_AM_SET_REG BNO055_PG1(0x1F) |
112 | #define BNO055_UID_LOWER_REG BNO055_PG1(0x50) |
113 | #define BNO055_UID_HIGHER_REG BNO055_PG1(0x5F) |
114 | #define BNO055_UID_LEN 16 |
115 | |
116 | struct bno055_sysfs_attr { |
117 | int *vals; |
118 | int len; |
119 | int *fusion_vals; |
120 | int *hw_xlate; |
121 | int type; |
122 | }; |
123 | |
124 | static int bno055_acc_lpf_vals[] = { |
125 | 7, 810000, 15, 630000, 31, 250000, 62, 500000, |
126 | 125, 0, 250, 0, 500, 0, 1000, 0, |
127 | }; |
128 | |
129 | static struct bno055_sysfs_attr bno055_acc_lpf = { |
130 | .vals = bno055_acc_lpf_vals, |
131 | .len = ARRAY_SIZE(bno055_acc_lpf_vals), |
132 | .fusion_vals = (int[]){62, 500000}, |
133 | .type = IIO_VAL_INT_PLUS_MICRO, |
134 | }; |
135 | |
136 | static int bno055_acc_range_vals[] = { |
137 | /* G: 2, 4, 8, 16 */ |
138 | 1962, 3924, 7848, 15696 |
139 | }; |
140 | |
141 | static struct bno055_sysfs_attr bno055_acc_range = { |
142 | .vals = bno055_acc_range_vals, |
143 | .len = ARRAY_SIZE(bno055_acc_range_vals), |
144 | .fusion_vals = (int[]){3924}, /* 4G */ |
145 | .type = IIO_VAL_INT, |
146 | }; |
147 | |
148 | /* |
149 | * Theoretically the IMU should return data in a given (i.e. fixed) unit |
150 | * regardless of the range setting. This happens for the accelerometer, but not |
151 | * for the gyroscope; the gyroscope range setting affects the scale. |
152 | * This is probably due to this[0] bug. |
153 | * For this reason we map the internal range setting onto the standard IIO scale |
154 | * attribute for gyro. |
155 | * Since the bug[0] may be fixed in future, we check for the IMU FW version and |
156 | * eventually warn the user. |
157 | * Currently we just don't care about "range" attributes for gyro. |
158 | * |
159 | * [0] https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BNO055-Wrong-sensitivity-resolution-in-datasheet/td-p/10266 |
160 | */ |
161 | |
162 | /* |
163 | * dps = hwval * (dps_range/2^15) |
164 | * rps = hwval * (rps_range/2^15) |
165 | * = hwval * (dps_range/(2^15 * k)) |
166 | * where k is rad-to-deg factor |
167 | */ |
168 | static int bno055_gyr_scale_vals[] = { |
169 | 125, 1877467, 250, 1877467, 500, 1877467, |
170 | 1000, 1877467, 2000, 1877467, |
171 | }; |
172 | |
173 | static struct bno055_sysfs_attr bno055_gyr_scale = { |
174 | .vals = bno055_gyr_scale_vals, |
175 | .len = ARRAY_SIZE(bno055_gyr_scale_vals), |
176 | .fusion_vals = (int[]){1, 900}, |
177 | .hw_xlate = (int[]){4, 3, 2, 1, 0}, |
178 | .type = IIO_VAL_FRACTIONAL, |
179 | }; |
180 | |
181 | static int bno055_gyr_lpf_vals[] = {12, 23, 32, 47, 64, 116, 230, 523}; |
182 | static struct bno055_sysfs_attr bno055_gyr_lpf = { |
183 | .vals = bno055_gyr_lpf_vals, |
184 | .len = ARRAY_SIZE(bno055_gyr_lpf_vals), |
185 | .fusion_vals = (int[]){32}, |
186 | .hw_xlate = (int[]){5, 4, 7, 3, 6, 2, 1, 0}, |
187 | .type = IIO_VAL_INT, |
188 | }; |
189 | |
190 | static int bno055_mag_odr_vals[] = {2, 6, 8, 10, 15, 20, 25, 30}; |
191 | static struct bno055_sysfs_attr bno055_mag_odr = { |
192 | .vals = bno055_mag_odr_vals, |
193 | .len = ARRAY_SIZE(bno055_mag_odr_vals), |
194 | .fusion_vals = (int[]){20}, |
195 | .type = IIO_VAL_INT, |
196 | }; |
197 | |
198 | struct bno055_priv { |
199 | struct regmap *regmap; |
200 | struct device *dev; |
201 | struct clk *clk; |
202 | int operation_mode; |
203 | int xfer_burst_break_thr; |
204 | struct mutex lock; |
205 | u8 uid[BNO055_UID_LEN]; |
206 | struct gpio_desc *reset_gpio; |
207 | bool sw_reset; |
208 | struct { |
209 | __le16 chans[BNO055_SCAN_CH_COUNT]; |
210 | s64 timestamp __aligned(8); |
211 | } buf; |
212 | struct dentry *debugfs; |
213 | }; |
214 | |
215 | static bool bno055_regmap_volatile(struct device *dev, unsigned int reg) |
216 | { |
217 | /* data and status registers */ |
218 | if (reg >= BNO055_ACC_DATA_X_LSB_REG && reg <= BNO055_SYS_ERR_REG) |
219 | return true; |
220 | |
221 | /* when in fusion mode, config is updated by chip */ |
222 | if (reg == BNO055_MAG_CONFIG_REG || |
223 | reg == BNO055_ACC_CONFIG_REG || |
224 | reg == BNO055_GYR_CONFIG_REG) |
225 | return true; |
226 | |
227 | /* calibration data may be updated by the IMU */ |
228 | if (reg >= BNO055_CALDATA_START && reg <= BNO055_CALDATA_END) |
229 | return true; |
230 | |
231 | return false; |
232 | } |
233 | |
234 | static bool bno055_regmap_readable(struct device *dev, unsigned int reg) |
235 | { |
236 | /* unnamed PG0 reserved areas */ |
237 | if ((reg < BNO055_PG1(0) && reg > BNO055_CALDATA_END) || |
238 | reg == 0x3C) |
239 | return false; |
240 | |
241 | /* unnamed PG1 reserved areas */ |
242 | if (reg > BNO055_PG1(BNO055_UID_HIGHER_REG) || |
243 | (reg < BNO055_PG1(BNO055_UID_LOWER_REG) && reg > BNO055_PG1(BNO055_GYR_AM_SET_REG)) || |
244 | reg == BNO055_PG1(0xE) || |
245 | (reg < BNO055_PG1(BNO055_PAGESEL_REG) && reg >= BNO055_PG1(0x0))) |
246 | return false; |
247 | return true; |
248 | } |
249 | |
250 | static bool bno055_regmap_writeable(struct device *dev, unsigned int reg) |
251 | { |
252 | /* |
253 | * Unreadable registers are indeed reserved; there are no WO regs |
254 | * (except for a single bit in SYS_TRIGGER register) |
255 | */ |
256 | if (!bno055_regmap_readable(dev, reg)) |
257 | return false; |
258 | |
259 | /* data and status registers */ |
260 | if (reg >= BNO055_ACC_DATA_X_LSB_REG && reg <= BNO055_SYS_ERR_REG) |
261 | return false; |
262 | |
263 | /* ID areas */ |
264 | if (reg < BNO055_PAGESEL_REG || |
265 | (reg <= BNO055_UID_HIGHER_REG && reg >= BNO055_UID_LOWER_REG)) |
266 | return false; |
267 | |
268 | return true; |
269 | } |
270 | |
271 | static const struct regmap_range_cfg bno055_regmap_ranges[] = { |
272 | { |
273 | .range_min = 0, |
274 | .range_max = 0x7f * 2, |
275 | .selector_reg = BNO055_PAGESEL_REG, |
276 | .selector_mask = GENMASK(7, 0), |
277 | .selector_shift = 0, |
278 | .window_start = 0, |
279 | .window_len = 0x80, |
280 | }, |
281 | }; |
282 | |
283 | const struct regmap_config bno055_regmap_config = { |
284 | .name = "bno055" , |
285 | .reg_bits = 8, |
286 | .val_bits = 8, |
287 | .ranges = bno055_regmap_ranges, |
288 | .num_ranges = 1, |
289 | .volatile_reg = bno055_regmap_volatile, |
290 | .max_register = 0x80 * 2, |
291 | .writeable_reg = bno055_regmap_writeable, |
292 | .readable_reg = bno055_regmap_readable, |
293 | .cache_type = REGCACHE_RBTREE, |
294 | }; |
295 | EXPORT_SYMBOL_NS_GPL(bno055_regmap_config, IIO_BNO055); |
296 | |
297 | /* must be called in configuration mode */ |
298 | static int bno055_calibration_load(struct bno055_priv *priv, const u8 *data, int len) |
299 | { |
300 | if (len != BNO055_CALDATA_LEN) { |
301 | dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)" , |
302 | len, BNO055_CALDATA_LEN); |
303 | return -EINVAL; |
304 | } |
305 | |
306 | dev_dbg(priv->dev, "loading cal data: %*ph" , BNO055_CALDATA_LEN, data); |
307 | return regmap_bulk_write(map: priv->regmap, BNO055_CALDATA_START, |
308 | val: data, BNO055_CALDATA_LEN); |
309 | } |
310 | |
311 | static int bno055_operation_mode_do_set(struct bno055_priv *priv, |
312 | int operation_mode) |
313 | { |
314 | int ret; |
315 | |
316 | ret = regmap_write(map: priv->regmap, BNO055_OPR_MODE_REG, |
317 | val: operation_mode); |
318 | if (ret) |
319 | return ret; |
320 | |
321 | /* Following datasheet specifications: sensor takes 7mS up to 19 mS to switch mode */ |
322 | msleep(msecs: 20); |
323 | |
324 | return 0; |
325 | } |
326 | |
327 | static int bno055_system_reset(struct bno055_priv *priv) |
328 | { |
329 | int ret; |
330 | |
331 | if (priv->reset_gpio) { |
332 | gpiod_set_value_cansleep(desc: priv->reset_gpio, value: 0); |
333 | usleep_range(min: 5000, max: 10000); |
334 | gpiod_set_value_cansleep(desc: priv->reset_gpio, value: 1); |
335 | } else if (priv->sw_reset) { |
336 | ret = regmap_write(map: priv->regmap, BNO055_SYS_TRIGGER_REG, |
337 | BNO055_SYS_TRIGGER_RST_SYS); |
338 | if (ret) |
339 | return ret; |
340 | } else { |
341 | return 0; |
342 | } |
343 | |
344 | regcache_drop_region(map: priv->regmap, min: 0x0, max: 0xff); |
345 | usleep_range(min: 650000, max: 700000); |
346 | |
347 | return 0; |
348 | } |
349 | |
350 | static int bno055_init(struct bno055_priv *priv, const u8 *caldata, int len) |
351 | { |
352 | int ret; |
353 | |
354 | ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG); |
355 | if (ret) |
356 | return ret; |
357 | |
358 | ret = regmap_write(map: priv->regmap, BNO055_POWER_MODE_REG, |
359 | BNO055_POWER_MODE_NORMAL); |
360 | if (ret) |
361 | return ret; |
362 | |
363 | ret = regmap_write(map: priv->regmap, BNO055_SYS_TRIGGER_REG, |
364 | val: priv->clk ? BNO055_SYS_TRIGGER_CLK_SEL : 0); |
365 | if (ret) |
366 | return ret; |
367 | |
368 | /* use standard SI units */ |
369 | ret = regmap_write(map: priv->regmap, BNO055_UNIT_SEL_REG, |
370 | BNO055_UNIT_SEL_ANDROID | BNO055_UNIT_SEL_GYR_RPS); |
371 | if (ret) |
372 | return ret; |
373 | |
374 | if (caldata) { |
375 | ret = bno055_calibration_load(priv, data: caldata, len); |
376 | if (ret) |
377 | dev_warn(priv->dev, "failed to load calibration data with error %d\n" , |
378 | ret); |
379 | } |
380 | |
381 | return 0; |
382 | } |
383 | |
384 | static ssize_t bno055_operation_mode_set(struct bno055_priv *priv, |
385 | int operation_mode) |
386 | { |
387 | u8 caldata[BNO055_CALDATA_LEN]; |
388 | int ret; |
389 | |
390 | mutex_lock(&priv->lock); |
391 | |
392 | ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG); |
393 | if (ret) |
394 | goto exit_unlock; |
395 | |
396 | if (operation_mode == BNO055_OPR_MODE_FUSION || |
397 | operation_mode == BNO055_OPR_MODE_FUSION_FMC_OFF) { |
398 | /* for entering fusion mode, reset the chip to clear the algo state */ |
399 | ret = regmap_bulk_read(map: priv->regmap, BNO055_CALDATA_START, val: caldata, |
400 | BNO055_CALDATA_LEN); |
401 | if (ret) |
402 | goto exit_unlock; |
403 | |
404 | ret = bno055_system_reset(priv); |
405 | if (ret) |
406 | goto exit_unlock; |
407 | |
408 | ret = bno055_init(priv, caldata, BNO055_CALDATA_LEN); |
409 | if (ret) |
410 | goto exit_unlock; |
411 | } |
412 | |
413 | ret = bno055_operation_mode_do_set(priv, operation_mode); |
414 | if (ret) |
415 | goto exit_unlock; |
416 | |
417 | priv->operation_mode = operation_mode; |
418 | |
419 | exit_unlock: |
420 | mutex_unlock(lock: &priv->lock); |
421 | return ret; |
422 | } |
423 | |
424 | static void bno055_uninit(void *arg) |
425 | { |
426 | struct bno055_priv *priv = arg; |
427 | |
428 | /* stop the IMU */ |
429 | bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG); |
430 | } |
431 | |
432 | #define BNO055_CHANNEL(_type, _axis, _index, _address, _sep, _sh, _avail) { \ |
433 | .address = _address, \ |
434 | .type = _type, \ |
435 | .modified = 1, \ |
436 | .channel2 = IIO_MOD_##_axis, \ |
437 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | (_sep), \ |
438 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | (_sh), \ |
439 | .info_mask_shared_by_type_available = _avail, \ |
440 | .scan_index = _index, \ |
441 | .scan_type = { \ |
442 | .sign = 's', \ |
443 | .realbits = 16, \ |
444 | .storagebits = 16, \ |
445 | .endianness = IIO_LE, \ |
446 | .repeat = IIO_MOD_##_axis == IIO_MOD_QUATERNION ? 4 : 0, \ |
447 | }, \ |
448 | } |
449 | |
450 | /* scan indexes follow DATA register order */ |
451 | enum bno055_scan_axis { |
452 | BNO055_SCAN_ACCEL_X, |
453 | BNO055_SCAN_ACCEL_Y, |
454 | BNO055_SCAN_ACCEL_Z, |
455 | BNO055_SCAN_MAGN_X, |
456 | BNO055_SCAN_MAGN_Y, |
457 | BNO055_SCAN_MAGN_Z, |
458 | BNO055_SCAN_GYRO_X, |
459 | BNO055_SCAN_GYRO_Y, |
460 | BNO055_SCAN_GYRO_Z, |
461 | BNO055_SCAN_YAW, |
462 | BNO055_SCAN_ROLL, |
463 | BNO055_SCAN_PITCH, |
464 | BNO055_SCAN_QUATERNION, |
465 | BNO055_SCAN_LIA_X, |
466 | BNO055_SCAN_LIA_Y, |
467 | BNO055_SCAN_LIA_Z, |
468 | BNO055_SCAN_GRAVITY_X, |
469 | BNO055_SCAN_GRAVITY_Y, |
470 | BNO055_SCAN_GRAVITY_Z, |
471 | BNO055_SCAN_TIMESTAMP, |
472 | _BNO055_SCAN_MAX |
473 | }; |
474 | |
475 | static const struct iio_chan_spec bno055_channels[] = { |
476 | /* accelerometer */ |
477 | BNO055_CHANNEL(IIO_ACCEL, X, BNO055_SCAN_ACCEL_X, |
478 | BNO055_ACC_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
479 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
480 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), |
481 | BNO055_CHANNEL(IIO_ACCEL, Y, BNO055_SCAN_ACCEL_Y, |
482 | BNO055_ACC_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
483 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
484 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), |
485 | BNO055_CHANNEL(IIO_ACCEL, Z, BNO055_SCAN_ACCEL_Z, |
486 | BNO055_ACC_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
487 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
488 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), |
489 | /* gyroscope */ |
490 | BNO055_CHANNEL(IIO_ANGL_VEL, X, BNO055_SCAN_GYRO_X, |
491 | BNO055_GYR_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
492 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
493 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | |
494 | BIT(IIO_CHAN_INFO_SCALE)), |
495 | BNO055_CHANNEL(IIO_ANGL_VEL, Y, BNO055_SCAN_GYRO_Y, |
496 | BNO055_GYR_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
497 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
498 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | |
499 | BIT(IIO_CHAN_INFO_SCALE)), |
500 | BNO055_CHANNEL(IIO_ANGL_VEL, Z, BNO055_SCAN_GYRO_Z, |
501 | BNO055_GYR_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
502 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
503 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | |
504 | BIT(IIO_CHAN_INFO_SCALE)), |
505 | /* magnetometer */ |
506 | BNO055_CHANNEL(IIO_MAGN, X, BNO055_SCAN_MAGN_X, |
507 | BNO055_MAG_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
508 | BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)), |
509 | BNO055_CHANNEL(IIO_MAGN, Y, BNO055_SCAN_MAGN_Y, |
510 | BNO055_MAG_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
511 | BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)), |
512 | BNO055_CHANNEL(IIO_MAGN, Z, BNO055_SCAN_MAGN_Z, |
513 | BNO055_MAG_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), |
514 | BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)), |
515 | /* euler angle */ |
516 | BNO055_CHANNEL(IIO_ROT, YAW, BNO055_SCAN_YAW, |
517 | BNO055_EUL_DATA_X_LSB_REG, 0, 0, 0), |
518 | BNO055_CHANNEL(IIO_ROT, ROLL, BNO055_SCAN_ROLL, |
519 | BNO055_EUL_DATA_Y_LSB_REG, 0, 0, 0), |
520 | BNO055_CHANNEL(IIO_ROT, PITCH, BNO055_SCAN_PITCH, |
521 | BNO055_EUL_DATA_Z_LSB_REG, 0, 0, 0), |
522 | /* quaternion */ |
523 | BNO055_CHANNEL(IIO_ROT, QUATERNION, BNO055_SCAN_QUATERNION, |
524 | BNO055_QUAT_DATA_W_LSB_REG, 0, 0, 0), |
525 | |
526 | /* linear acceleration */ |
527 | BNO055_CHANNEL(IIO_ACCEL, LINEAR_X, BNO055_SCAN_LIA_X, |
528 | BNO055_LIA_DATA_X_LSB_REG, 0, 0, 0), |
529 | BNO055_CHANNEL(IIO_ACCEL, LINEAR_Y, BNO055_SCAN_LIA_Y, |
530 | BNO055_LIA_DATA_Y_LSB_REG, 0, 0, 0), |
531 | BNO055_CHANNEL(IIO_ACCEL, LINEAR_Z, BNO055_SCAN_LIA_Z, |
532 | BNO055_LIA_DATA_Z_LSB_REG, 0, 0, 0), |
533 | |
534 | /* gravity vector */ |
535 | BNO055_CHANNEL(IIO_GRAVITY, X, BNO055_SCAN_GRAVITY_X, |
536 | BNO055_GRAVITY_DATA_X_LSB_REG, 0, 0, 0), |
537 | BNO055_CHANNEL(IIO_GRAVITY, Y, BNO055_SCAN_GRAVITY_Y, |
538 | BNO055_GRAVITY_DATA_Y_LSB_REG, 0, 0, 0), |
539 | BNO055_CHANNEL(IIO_GRAVITY, Z, BNO055_SCAN_GRAVITY_Z, |
540 | BNO055_GRAVITY_DATA_Z_LSB_REG, 0, 0, 0), |
541 | |
542 | { |
543 | .type = IIO_TEMP, |
544 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), |
545 | .scan_index = -1, |
546 | }, |
547 | IIO_CHAN_SOFT_TIMESTAMP(BNO055_SCAN_TIMESTAMP), |
548 | }; |
549 | |
550 | static int bno055_get_regmask(struct bno055_priv *priv, int *val, int *val2, |
551 | int reg, int mask, struct bno055_sysfs_attr *attr) |
552 | { |
553 | const int shift = __ffs(mask); |
554 | int hwval, idx; |
555 | int ret; |
556 | int i; |
557 | |
558 | ret = regmap_read(map: priv->regmap, reg, val: &hwval); |
559 | if (ret) |
560 | return ret; |
561 | |
562 | idx = (hwval & mask) >> shift; |
563 | if (attr->hw_xlate) |
564 | for (i = 0; i < attr->len; i++) |
565 | if (attr->hw_xlate[i] == idx) { |
566 | idx = i; |
567 | break; |
568 | } |
569 | if (attr->type == IIO_VAL_INT) { |
570 | *val = attr->vals[idx]; |
571 | } else { /* IIO_VAL_INT_PLUS_MICRO or IIO_VAL_FRACTIONAL */ |
572 | *val = attr->vals[idx * 2]; |
573 | *val2 = attr->vals[idx * 2 + 1]; |
574 | } |
575 | |
576 | return attr->type; |
577 | } |
578 | |
579 | static int bno055_set_regmask(struct bno055_priv *priv, int val, int val2, |
580 | int reg, int mask, struct bno055_sysfs_attr *attr) |
581 | { |
582 | const int shift = __ffs(mask); |
583 | int best_delta; |
584 | int req_val; |
585 | int tbl_val; |
586 | bool first; |
587 | int delta; |
588 | int hwval; |
589 | int ret; |
590 | int len; |
591 | int i; |
592 | |
593 | /* |
594 | * The closest value the HW supports is only one in fusion mode, |
595 | * and it is autoselected, so don't do anything, just return OK, |
596 | * as the closest possible value has been (virtually) selected |
597 | */ |
598 | if (priv->operation_mode != BNO055_OPR_MODE_AMG) |
599 | return 0; |
600 | |
601 | len = attr->len; |
602 | |
603 | /* |
604 | * We always get a request in INT_PLUS_MICRO, but we |
605 | * take care of the micro part only when we really have |
606 | * non-integer tables. This prevents 32-bit overflow with |
607 | * larger integers contained in integer tables. |
608 | */ |
609 | req_val = val; |
610 | if (attr->type != IIO_VAL_INT) { |
611 | len /= 2; |
612 | req_val = min(val, 2147) * 1000000 + val2; |
613 | } |
614 | |
615 | first = true; |
616 | for (i = 0; i < len; i++) { |
617 | switch (attr->type) { |
618 | case IIO_VAL_INT: |
619 | tbl_val = attr->vals[i]; |
620 | break; |
621 | case IIO_VAL_INT_PLUS_MICRO: |
622 | WARN_ON(attr->vals[i * 2] > 2147); |
623 | tbl_val = attr->vals[i * 2] * 1000000 + |
624 | attr->vals[i * 2 + 1]; |
625 | break; |
626 | case IIO_VAL_FRACTIONAL: |
627 | WARN_ON(attr->vals[i * 2] > 4294); |
628 | tbl_val = attr->vals[i * 2] * 1000000 / |
629 | attr->vals[i * 2 + 1]; |
630 | break; |
631 | default: |
632 | return -EINVAL; |
633 | } |
634 | delta = abs(tbl_val - req_val); |
635 | if (first || delta < best_delta) { |
636 | best_delta = delta; |
637 | hwval = i; |
638 | first = false; |
639 | } |
640 | } |
641 | |
642 | if (attr->hw_xlate) |
643 | hwval = attr->hw_xlate[hwval]; |
644 | |
645 | ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG); |
646 | if (ret) |
647 | return ret; |
648 | |
649 | ret = regmap_update_bits(map: priv->regmap, reg, mask, val: hwval << shift); |
650 | if (ret) |
651 | return ret; |
652 | |
653 | return bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_AMG); |
654 | } |
655 | |
656 | static int bno055_read_simple_chan(struct iio_dev *indio_dev, |
657 | struct iio_chan_spec const *chan, |
658 | int *val, int *val2, long mask) |
659 | { |
660 | struct bno055_priv *priv = iio_priv(indio_dev); |
661 | __le16 raw_val; |
662 | int ret; |
663 | |
664 | switch (mask) { |
665 | case IIO_CHAN_INFO_RAW: |
666 | ret = regmap_bulk_read(map: priv->regmap, reg: chan->address, |
667 | val: &raw_val, val_count: sizeof(raw_val)); |
668 | if (ret < 0) |
669 | return ret; |
670 | *val = sign_extend32(le16_to_cpu(raw_val), index: 15); |
671 | return IIO_VAL_INT; |
672 | case IIO_CHAN_INFO_OFFSET: |
673 | if (priv->operation_mode != BNO055_OPR_MODE_AMG) { |
674 | *val = 0; |
675 | } else { |
676 | ret = regmap_bulk_read(map: priv->regmap, |
677 | reg: chan->address + |
678 | BNO055_REG_OFFSET_ADDR, |
679 | val: &raw_val, val_count: sizeof(raw_val)); |
680 | if (ret < 0) |
681 | return ret; |
682 | /* |
683 | * IMU reports sensor offsets; IIO wants correction |
684 | * offsets, thus we need the 'minus' here. |
685 | */ |
686 | *val = -sign_extend32(le16_to_cpu(raw_val), index: 15); |
687 | } |
688 | return IIO_VAL_INT; |
689 | case IIO_CHAN_INFO_SCALE: |
690 | *val = 1; |
691 | switch (chan->type) { |
692 | case IIO_GRAVITY: |
693 | /* Table 3-35: 1 m/s^2 = 100 LSB */ |
694 | case IIO_ACCEL: |
695 | /* Table 3-17: 1 m/s^2 = 100 LSB */ |
696 | *val2 = 100; |
697 | break; |
698 | case IIO_MAGN: |
699 | /* |
700 | * Table 3-19: 1 uT = 16 LSB. But we need |
701 | * Gauss: 1G = 0.1 uT. |
702 | */ |
703 | *val2 = 160; |
704 | break; |
705 | case IIO_ANGL_VEL: |
706 | /* |
707 | * Table 3-22: 1 Rps = 900 LSB |
708 | * .. but this is not exactly true. See comment at the |
709 | * beginning of this file. |
710 | */ |
711 | if (priv->operation_mode != BNO055_OPR_MODE_AMG) { |
712 | *val = bno055_gyr_scale.fusion_vals[0]; |
713 | *val2 = bno055_gyr_scale.fusion_vals[1]; |
714 | return IIO_VAL_FRACTIONAL; |
715 | } |
716 | |
717 | return bno055_get_regmask(priv, val, val2, |
718 | BNO055_GYR_CONFIG_REG, |
719 | BNO055_GYR_CONFIG_RANGE_MASK, |
720 | attr: &bno055_gyr_scale); |
721 | break; |
722 | case IIO_ROT: |
723 | /* Table 3-28: 1 degree = 16 LSB */ |
724 | *val2 = 16; |
725 | break; |
726 | default: |
727 | return -EINVAL; |
728 | } |
729 | return IIO_VAL_FRACTIONAL; |
730 | |
731 | case IIO_CHAN_INFO_SAMP_FREQ: |
732 | if (chan->type != IIO_MAGN) |
733 | return -EINVAL; |
734 | |
735 | return bno055_get_regmask(priv, val, val2, |
736 | BNO055_MAG_CONFIG_REG, |
737 | BNO055_MAG_CONFIG_ODR_MASK, |
738 | attr: &bno055_mag_odr); |
739 | |
740 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
741 | switch (chan->type) { |
742 | case IIO_ANGL_VEL: |
743 | return bno055_get_regmask(priv, val, val2, |
744 | BNO055_GYR_CONFIG_REG, |
745 | BNO055_GYR_CONFIG_LPF_MASK, |
746 | attr: &bno055_gyr_lpf); |
747 | case IIO_ACCEL: |
748 | return bno055_get_regmask(priv, val, val2, |
749 | BNO055_ACC_CONFIG_REG, |
750 | BNO055_ACC_CONFIG_LPF_MASK, |
751 | attr: &bno055_acc_lpf); |
752 | default: |
753 | return -EINVAL; |
754 | } |
755 | |
756 | default: |
757 | return -EINVAL; |
758 | } |
759 | } |
760 | |
761 | static int bno055_sysfs_attr_avail(struct bno055_priv *priv, struct bno055_sysfs_attr *attr, |
762 | const int **vals, int *length) |
763 | { |
764 | if (priv->operation_mode != BNO055_OPR_MODE_AMG) { |
765 | /* locked when fusion enabled */ |
766 | *vals = attr->fusion_vals; |
767 | if (attr->type == IIO_VAL_INT) |
768 | *length = 1; |
769 | else |
770 | *length = 2; /* IIO_VAL_INT_PLUS_MICRO or IIO_VAL_FRACTIONAL*/ |
771 | } else { |
772 | *vals = attr->vals; |
773 | *length = attr->len; |
774 | } |
775 | |
776 | return attr->type; |
777 | } |
778 | |
779 | static int bno055_read_avail(struct iio_dev *indio_dev, |
780 | struct iio_chan_spec const *chan, |
781 | const int **vals, int *type, int *length, |
782 | long mask) |
783 | { |
784 | struct bno055_priv *priv = iio_priv(indio_dev); |
785 | |
786 | switch (mask) { |
787 | case IIO_CHAN_INFO_SCALE: |
788 | switch (chan->type) { |
789 | case IIO_ANGL_VEL: |
790 | *type = bno055_sysfs_attr_avail(priv, attr: &bno055_gyr_scale, |
791 | vals, length); |
792 | return IIO_AVAIL_LIST; |
793 | default: |
794 | return -EINVAL; |
795 | } |
796 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
797 | switch (chan->type) { |
798 | case IIO_ANGL_VEL: |
799 | *type = bno055_sysfs_attr_avail(priv, attr: &bno055_gyr_lpf, |
800 | vals, length); |
801 | return IIO_AVAIL_LIST; |
802 | case IIO_ACCEL: |
803 | *type = bno055_sysfs_attr_avail(priv, attr: &bno055_acc_lpf, |
804 | vals, length); |
805 | return IIO_AVAIL_LIST; |
806 | default: |
807 | return -EINVAL; |
808 | } |
809 | |
810 | break; |
811 | case IIO_CHAN_INFO_SAMP_FREQ: |
812 | switch (chan->type) { |
813 | case IIO_MAGN: |
814 | *type = bno055_sysfs_attr_avail(priv, attr: &bno055_mag_odr, |
815 | vals, length); |
816 | return IIO_AVAIL_LIST; |
817 | default: |
818 | return -EINVAL; |
819 | } |
820 | default: |
821 | return -EINVAL; |
822 | } |
823 | } |
824 | |
825 | static int bno055_read_temp_chan(struct iio_dev *indio_dev, int *val) |
826 | { |
827 | struct bno055_priv *priv = iio_priv(indio_dev); |
828 | unsigned int raw_val; |
829 | int ret; |
830 | |
831 | ret = regmap_read(map: priv->regmap, BNO055_TEMP_REG, val: &raw_val); |
832 | if (ret < 0) |
833 | return ret; |
834 | |
835 | /* |
836 | * Tables 3-36 and 3-37: one byte of priv, signed, 1 LSB = 1C. |
837 | * ABI wants milliC. |
838 | */ |
839 | *val = raw_val * 1000; |
840 | |
841 | return IIO_VAL_INT; |
842 | } |
843 | |
844 | static int bno055_read_quaternion(struct iio_dev *indio_dev, |
845 | struct iio_chan_spec const *chan, |
846 | int size, int *vals, int *val_len, |
847 | long mask) |
848 | { |
849 | struct bno055_priv *priv = iio_priv(indio_dev); |
850 | __le16 raw_vals[4]; |
851 | int i, ret; |
852 | |
853 | switch (mask) { |
854 | case IIO_CHAN_INFO_RAW: |
855 | if (size < 4) |
856 | return -EINVAL; |
857 | ret = regmap_bulk_read(map: priv->regmap, |
858 | BNO055_QUAT_DATA_W_LSB_REG, |
859 | val: raw_vals, val_count: sizeof(raw_vals)); |
860 | if (ret < 0) |
861 | return ret; |
862 | for (i = 0; i < 4; i++) |
863 | vals[i] = sign_extend32(le16_to_cpu(raw_vals[i]), index: 15); |
864 | *val_len = 4; |
865 | return IIO_VAL_INT_MULTIPLE; |
866 | case IIO_CHAN_INFO_SCALE: |
867 | /* Table 3-31: 1 quaternion = 2^14 LSB */ |
868 | if (size < 2) |
869 | return -EINVAL; |
870 | vals[0] = 1; |
871 | vals[1] = 14; |
872 | return IIO_VAL_FRACTIONAL_LOG2; |
873 | default: |
874 | return -EINVAL; |
875 | } |
876 | } |
877 | |
878 | static bool bno055_is_chan_readable(struct iio_dev *indio_dev, |
879 | struct iio_chan_spec const *chan) |
880 | { |
881 | struct bno055_priv *priv = iio_priv(indio_dev); |
882 | |
883 | if (priv->operation_mode != BNO055_OPR_MODE_AMG) |
884 | return true; |
885 | |
886 | switch (chan->type) { |
887 | case IIO_GRAVITY: |
888 | case IIO_ROT: |
889 | return false; |
890 | case IIO_ACCEL: |
891 | if (chan->channel2 == IIO_MOD_LINEAR_X || |
892 | chan->channel2 == IIO_MOD_LINEAR_Y || |
893 | chan->channel2 == IIO_MOD_LINEAR_Z) |
894 | return false; |
895 | return true; |
896 | default: |
897 | return true; |
898 | } |
899 | } |
900 | |
901 | static int _bno055_read_raw_multi(struct iio_dev *indio_dev, |
902 | struct iio_chan_spec const *chan, |
903 | int size, int *vals, int *val_len, |
904 | long mask) |
905 | { |
906 | if (!bno055_is_chan_readable(indio_dev, chan)) |
907 | return -EBUSY; |
908 | |
909 | switch (chan->type) { |
910 | case IIO_MAGN: |
911 | case IIO_ACCEL: |
912 | case IIO_ANGL_VEL: |
913 | case IIO_GRAVITY: |
914 | if (size < 2) |
915 | return -EINVAL; |
916 | *val_len = 2; |
917 | return bno055_read_simple_chan(indio_dev, chan, |
918 | val: &vals[0], val2: &vals[1], |
919 | mask); |
920 | case IIO_TEMP: |
921 | *val_len = 1; |
922 | return bno055_read_temp_chan(indio_dev, val: &vals[0]); |
923 | case IIO_ROT: |
924 | /* |
925 | * Rotation is exposed as either a quaternion or three |
926 | * Euler angles. |
927 | */ |
928 | if (chan->channel2 == IIO_MOD_QUATERNION) |
929 | return bno055_read_quaternion(indio_dev, chan, |
930 | size, vals, |
931 | val_len, mask); |
932 | if (size < 2) |
933 | return -EINVAL; |
934 | *val_len = 2; |
935 | return bno055_read_simple_chan(indio_dev, chan, |
936 | val: &vals[0], val2: &vals[1], |
937 | mask); |
938 | default: |
939 | return -EINVAL; |
940 | } |
941 | } |
942 | |
943 | static int bno055_read_raw_multi(struct iio_dev *indio_dev, |
944 | struct iio_chan_spec const *chan, |
945 | int size, int *vals, int *val_len, |
946 | long mask) |
947 | { |
948 | struct bno055_priv *priv = iio_priv(indio_dev); |
949 | int ret; |
950 | |
951 | mutex_lock(&priv->lock); |
952 | ret = _bno055_read_raw_multi(indio_dev, chan, size, |
953 | vals, val_len, mask); |
954 | mutex_unlock(lock: &priv->lock); |
955 | return ret; |
956 | } |
957 | |
958 | static int _bno055_write_raw(struct iio_dev *iio_dev, |
959 | struct iio_chan_spec const *chan, |
960 | int val, int val2, long mask) |
961 | { |
962 | struct bno055_priv *priv = iio_priv(indio_dev: iio_dev); |
963 | |
964 | switch (chan->type) { |
965 | case IIO_MAGN: |
966 | switch (mask) { |
967 | case IIO_CHAN_INFO_SAMP_FREQ: |
968 | return bno055_set_regmask(priv, val, val2, |
969 | BNO055_MAG_CONFIG_REG, |
970 | BNO055_MAG_CONFIG_ODR_MASK, |
971 | attr: &bno055_mag_odr); |
972 | default: |
973 | return -EINVAL; |
974 | } |
975 | case IIO_ACCEL: |
976 | switch (mask) { |
977 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
978 | return bno055_set_regmask(priv, val, val2, |
979 | BNO055_ACC_CONFIG_REG, |
980 | BNO055_ACC_CONFIG_LPF_MASK, |
981 | attr: &bno055_acc_lpf); |
982 | |
983 | default: |
984 | return -EINVAL; |
985 | } |
986 | case IIO_ANGL_VEL: |
987 | switch (mask) { |
988 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
989 | return bno055_set_regmask(priv, val, val2, |
990 | BNO055_GYR_CONFIG_REG, |
991 | BNO055_GYR_CONFIG_LPF_MASK, |
992 | attr: &bno055_gyr_lpf); |
993 | case IIO_CHAN_INFO_SCALE: |
994 | return bno055_set_regmask(priv, val, val2, |
995 | BNO055_GYR_CONFIG_REG, |
996 | BNO055_GYR_CONFIG_RANGE_MASK, |
997 | attr: &bno055_gyr_scale); |
998 | default: |
999 | return -EINVAL; |
1000 | } |
1001 | default: |
1002 | return -EINVAL; |
1003 | } |
1004 | } |
1005 | |
1006 | static int bno055_write_raw(struct iio_dev *iio_dev, |
1007 | struct iio_chan_spec const *chan, |
1008 | int val, int val2, long mask) |
1009 | { |
1010 | struct bno055_priv *priv = iio_priv(indio_dev: iio_dev); |
1011 | int ret; |
1012 | |
1013 | mutex_lock(&priv->lock); |
1014 | ret = _bno055_write_raw(iio_dev, chan, val, val2, mask); |
1015 | mutex_unlock(lock: &priv->lock); |
1016 | |
1017 | return ret; |
1018 | } |
1019 | |
1020 | static ssize_t in_accel_range_raw_available_show(struct device *dev, |
1021 | struct device_attribute *attr, |
1022 | char *buf) |
1023 | { |
1024 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1025 | int len = 0; |
1026 | int i; |
1027 | |
1028 | if (priv->operation_mode != BNO055_OPR_MODE_AMG) |
1029 | return sysfs_emit(buf, fmt: "%d\n" , bno055_acc_range.fusion_vals[0]); |
1030 | |
1031 | for (i = 0; i < bno055_acc_range.len; i++) |
1032 | len += sysfs_emit_at(buf, at: len, fmt: "%d " , bno055_acc_range.vals[i]); |
1033 | buf[len - 1] = '\n'; |
1034 | |
1035 | return len; |
1036 | } |
1037 | |
1038 | static ssize_t fusion_enable_show(struct device *dev, |
1039 | struct device_attribute *attr, |
1040 | char *buf) |
1041 | { |
1042 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1043 | |
1044 | return sysfs_emit(buf, fmt: "%d\n" , |
1045 | priv->operation_mode != BNO055_OPR_MODE_AMG); |
1046 | } |
1047 | |
1048 | static ssize_t fusion_enable_store(struct device *dev, |
1049 | struct device_attribute *attr, |
1050 | const char *buf, size_t len) |
1051 | { |
1052 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
1053 | struct bno055_priv *priv = iio_priv(indio_dev); |
1054 | bool en; |
1055 | int ret; |
1056 | |
1057 | if (indio_dev->active_scan_mask && |
1058 | !bitmap_empty(src: indio_dev->active_scan_mask, nbits: _BNO055_SCAN_MAX)) |
1059 | return -EBUSY; |
1060 | |
1061 | ret = kstrtobool(s: buf, res: &en); |
1062 | if (ret) |
1063 | return -EINVAL; |
1064 | |
1065 | if (!en) |
1066 | return bno055_operation_mode_set(priv, BNO055_OPR_MODE_AMG) ?: len; |
1067 | |
1068 | /* |
1069 | * Coming from AMG means the FMC was off, just switch to fusion but |
1070 | * don't change anything that doesn't belong to us (i.e let FMC stay off). |
1071 | * Coming from any other fusion mode means we don't need to do anything. |
1072 | */ |
1073 | if (priv->operation_mode == BNO055_OPR_MODE_AMG) |
1074 | return bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF) ?: len; |
1075 | |
1076 | return len; |
1077 | } |
1078 | |
1079 | static ssize_t in_magn_calibration_fast_enable_show(struct device *dev, |
1080 | struct device_attribute *attr, |
1081 | char *buf) |
1082 | { |
1083 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1084 | |
1085 | return sysfs_emit(buf, fmt: "%d\n" , |
1086 | priv->operation_mode == BNO055_OPR_MODE_FUSION); |
1087 | } |
1088 | |
1089 | static ssize_t in_magn_calibration_fast_enable_store(struct device *dev, |
1090 | struct device_attribute *attr, |
1091 | const char *buf, size_t len) |
1092 | { |
1093 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
1094 | struct bno055_priv *priv = iio_priv(indio_dev); |
1095 | int ret; |
1096 | |
1097 | if (indio_dev->active_scan_mask && |
1098 | !bitmap_empty(src: indio_dev->active_scan_mask, nbits: _BNO055_SCAN_MAX)) |
1099 | return -EBUSY; |
1100 | |
1101 | if (sysfs_streq(s1: buf, s2: "0" )) { |
1102 | if (priv->operation_mode == BNO055_OPR_MODE_FUSION) { |
1103 | ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); |
1104 | if (ret) |
1105 | return ret; |
1106 | } |
1107 | } else { |
1108 | if (priv->operation_mode == BNO055_OPR_MODE_AMG) |
1109 | return -EINVAL; |
1110 | |
1111 | if (priv->operation_mode != BNO055_OPR_MODE_FUSION) { |
1112 | ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION); |
1113 | if (ret) |
1114 | return ret; |
1115 | } |
1116 | } |
1117 | |
1118 | return len; |
1119 | } |
1120 | |
1121 | static ssize_t in_accel_range_raw_show(struct device *dev, |
1122 | struct device_attribute *attr, |
1123 | char *buf) |
1124 | { |
1125 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1126 | int val; |
1127 | int ret; |
1128 | |
1129 | ret = bno055_get_regmask(priv, val: &val, NULL, |
1130 | BNO055_ACC_CONFIG_REG, |
1131 | BNO055_ACC_CONFIG_RANGE_MASK, |
1132 | attr: &bno055_acc_range); |
1133 | if (ret < 0) |
1134 | return ret; |
1135 | |
1136 | return sysfs_emit(buf, fmt: "%d\n" , val); |
1137 | } |
1138 | |
1139 | static ssize_t in_accel_range_raw_store(struct device *dev, |
1140 | struct device_attribute *attr, |
1141 | const char *buf, size_t len) |
1142 | { |
1143 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1144 | unsigned long val; |
1145 | int ret; |
1146 | |
1147 | ret = kstrtoul(s: buf, base: 10, res: &val); |
1148 | if (ret) |
1149 | return ret; |
1150 | |
1151 | mutex_lock(&priv->lock); |
1152 | ret = bno055_set_regmask(priv, val, val2: 0, |
1153 | BNO055_ACC_CONFIG_REG, |
1154 | BNO055_ACC_CONFIG_RANGE_MASK, |
1155 | attr: &bno055_acc_range); |
1156 | mutex_unlock(lock: &priv->lock); |
1157 | |
1158 | return ret ?: len; |
1159 | } |
1160 | |
1161 | static ssize_t bno055_get_calib_status(struct device *dev, char *buf, int which) |
1162 | { |
1163 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1164 | int calib; |
1165 | int ret; |
1166 | int val; |
1167 | |
1168 | if (priv->operation_mode == BNO055_OPR_MODE_AMG || |
1169 | (priv->operation_mode == BNO055_OPR_MODE_FUSION_FMC_OFF && |
1170 | which == BNO055_CALIB_STAT_MAGN_SHIFT)) { |
1171 | calib = 0; |
1172 | } else { |
1173 | mutex_lock(&priv->lock); |
1174 | ret = regmap_read(map: priv->regmap, BNO055_CALIB_STAT_REG, val: &val); |
1175 | mutex_unlock(lock: &priv->lock); |
1176 | |
1177 | if (ret) |
1178 | return -EIO; |
1179 | |
1180 | calib = ((val >> which) & GENMASK(1, 0)) + 1; |
1181 | } |
1182 | |
1183 | return sysfs_emit(buf, fmt: "%d\n" , calib); |
1184 | } |
1185 | |
1186 | static ssize_t serialnumber_show(struct device *dev, |
1187 | struct device_attribute *attr, |
1188 | char *buf) |
1189 | { |
1190 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
1191 | |
1192 | return sysfs_emit(buf, fmt: "%*ph\n" , BNO055_UID_LEN, priv->uid); |
1193 | } |
1194 | |
1195 | static ssize_t calibration_data_read(struct file *filp, struct kobject *kobj, |
1196 | struct bin_attribute *bin_attr, char *buf, |
1197 | loff_t pos, size_t count) |
1198 | { |
1199 | struct bno055_priv *priv = iio_priv(indio_dev: dev_to_iio_dev(kobj_to_dev(kobj))); |
1200 | u8 data[BNO055_CALDATA_LEN]; |
1201 | int ret; |
1202 | |
1203 | /* |
1204 | * Calibration data is volatile; reading it in chunks will possibly |
1205 | * results in inconsistent data. We require the user to read the whole |
1206 | * blob in a single chunk |
1207 | */ |
1208 | if (count < BNO055_CALDATA_LEN || pos) |
1209 | return -EINVAL; |
1210 | |
1211 | mutex_lock(&priv->lock); |
1212 | ret = bno055_operation_mode_do_set(priv, BNO055_OPR_MODE_CONFIG); |
1213 | if (ret) |
1214 | goto exit_unlock; |
1215 | |
1216 | ret = regmap_bulk_read(map: priv->regmap, BNO055_CALDATA_START, val: data, |
1217 | BNO055_CALDATA_LEN); |
1218 | if (ret) |
1219 | goto exit_unlock; |
1220 | |
1221 | ret = bno055_operation_mode_do_set(priv, operation_mode: priv->operation_mode); |
1222 | if (ret) |
1223 | goto exit_unlock; |
1224 | |
1225 | memcpy(buf, data, BNO055_CALDATA_LEN); |
1226 | |
1227 | ret = BNO055_CALDATA_LEN; |
1228 | exit_unlock: |
1229 | mutex_unlock(lock: &priv->lock); |
1230 | return ret; |
1231 | } |
1232 | |
1233 | static ssize_t sys_calibration_auto_status_show(struct device *dev, |
1234 | struct device_attribute *a, |
1235 | char *buf) |
1236 | { |
1237 | return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_SYS_SHIFT); |
1238 | } |
1239 | |
1240 | static ssize_t in_accel_calibration_auto_status_show(struct device *dev, |
1241 | struct device_attribute *a, |
1242 | char *buf) |
1243 | { |
1244 | return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_ACCEL_SHIFT); |
1245 | } |
1246 | |
1247 | static ssize_t in_gyro_calibration_auto_status_show(struct device *dev, |
1248 | struct device_attribute *a, |
1249 | char *buf) |
1250 | { |
1251 | return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_GYRO_SHIFT); |
1252 | } |
1253 | |
1254 | static ssize_t in_magn_calibration_auto_status_show(struct device *dev, |
1255 | struct device_attribute *a, |
1256 | char *buf) |
1257 | { |
1258 | return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_MAGN_SHIFT); |
1259 | } |
1260 | |
1261 | static int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg, |
1262 | unsigned int writeval, unsigned int *readval) |
1263 | { |
1264 | struct bno055_priv *priv = iio_priv(indio_dev: iio_dev); |
1265 | |
1266 | if (readval) |
1267 | return regmap_read(map: priv->regmap, reg, val: readval); |
1268 | else |
1269 | return regmap_write(map: priv->regmap, reg, val: writeval); |
1270 | } |
1271 | |
1272 | static ssize_t bno055_show_fw_version(struct file *file, char __user *userbuf, |
1273 | size_t count, loff_t *ppos) |
1274 | { |
1275 | struct bno055_priv *priv = file->private_data; |
1276 | int rev, ver; |
1277 | char *buf; |
1278 | int ret; |
1279 | |
1280 | ret = regmap_read(map: priv->regmap, BNO055_SW_REV_LSB_REG, val: &rev); |
1281 | if (ret) |
1282 | return ret; |
1283 | |
1284 | ret = regmap_read(map: priv->regmap, BNO055_SW_REV_MSB_REG, val: &ver); |
1285 | if (ret) |
1286 | return ret; |
1287 | |
1288 | buf = kasprintf(GFP_KERNEL, fmt: "ver: 0x%x, rev: 0x%x\n" , ver, rev); |
1289 | if (!buf) |
1290 | return -ENOMEM; |
1291 | |
1292 | ret = simple_read_from_buffer(to: userbuf, count, ppos, from: buf, strlen(buf)); |
1293 | kfree(objp: buf); |
1294 | |
1295 | return ret; |
1296 | } |
1297 | |
1298 | static const struct file_operations bno055_fw_version_ops = { |
1299 | .open = simple_open, |
1300 | .read = bno055_show_fw_version, |
1301 | .llseek = default_llseek, |
1302 | .owner = THIS_MODULE, |
1303 | }; |
1304 | |
1305 | static void bno055_debugfs_remove(void *_priv) |
1306 | { |
1307 | struct bno055_priv *priv = _priv; |
1308 | |
1309 | debugfs_remove(dentry: priv->debugfs); |
1310 | priv->debugfs = NULL; |
1311 | } |
1312 | |
1313 | static void bno055_debugfs_init(struct iio_dev *iio_dev) |
1314 | { |
1315 | struct bno055_priv *priv = iio_priv(indio_dev: iio_dev); |
1316 | |
1317 | priv->debugfs = debugfs_create_file(name: "firmware_version" , mode: 0400, |
1318 | parent: iio_get_debugfs_dentry(indio_dev: iio_dev), |
1319 | data: priv, fops: &bno055_fw_version_ops); |
1320 | if (!IS_ERR(ptr: priv->debugfs)) |
1321 | devm_add_action_or_reset(priv->dev, bno055_debugfs_remove, |
1322 | priv); |
1323 | if (IS_ERR_OR_NULL(ptr: priv->debugfs)) |
1324 | dev_warn(priv->dev, "failed to setup debugfs" ); |
1325 | } |
1326 | |
1327 | static IIO_DEVICE_ATTR_RW(fusion_enable, 0); |
1328 | static IIO_DEVICE_ATTR_RW(in_magn_calibration_fast_enable, 0); |
1329 | static IIO_DEVICE_ATTR_RW(in_accel_range_raw, 0); |
1330 | |
1331 | static IIO_DEVICE_ATTR_RO(in_accel_range_raw_available, 0); |
1332 | static IIO_DEVICE_ATTR_RO(sys_calibration_auto_status, 0); |
1333 | static IIO_DEVICE_ATTR_RO(in_accel_calibration_auto_status, 0); |
1334 | static IIO_DEVICE_ATTR_RO(in_gyro_calibration_auto_status, 0); |
1335 | static IIO_DEVICE_ATTR_RO(in_magn_calibration_auto_status, 0); |
1336 | static IIO_DEVICE_ATTR_RO(serialnumber, 0); |
1337 | |
1338 | static struct attribute *bno055_attrs[] = { |
1339 | &iio_dev_attr_in_accel_range_raw_available.dev_attr.attr, |
1340 | &iio_dev_attr_in_accel_range_raw.dev_attr.attr, |
1341 | &iio_dev_attr_fusion_enable.dev_attr.attr, |
1342 | &iio_dev_attr_in_magn_calibration_fast_enable.dev_attr.attr, |
1343 | &iio_dev_attr_sys_calibration_auto_status.dev_attr.attr, |
1344 | &iio_dev_attr_in_accel_calibration_auto_status.dev_attr.attr, |
1345 | &iio_dev_attr_in_gyro_calibration_auto_status.dev_attr.attr, |
1346 | &iio_dev_attr_in_magn_calibration_auto_status.dev_attr.attr, |
1347 | &iio_dev_attr_serialnumber.dev_attr.attr, |
1348 | NULL |
1349 | }; |
1350 | |
1351 | static BIN_ATTR_RO(calibration_data, BNO055_CALDATA_LEN); |
1352 | |
1353 | static struct bin_attribute *bno055_bin_attrs[] = { |
1354 | &bin_attr_calibration_data, |
1355 | NULL |
1356 | }; |
1357 | |
1358 | static const struct attribute_group bno055_attrs_group = { |
1359 | .attrs = bno055_attrs, |
1360 | .bin_attrs = bno055_bin_attrs, |
1361 | }; |
1362 | |
1363 | static const struct iio_info bno055_info = { |
1364 | .read_raw_multi = bno055_read_raw_multi, |
1365 | .read_avail = bno055_read_avail, |
1366 | .write_raw = bno055_write_raw, |
1367 | .attrs = &bno055_attrs_group, |
1368 | .debugfs_reg_access = bno055_debugfs_reg_access, |
1369 | }; |
1370 | |
1371 | /* |
1372 | * Reads len samples from the HW, stores them in buf starting from buf_idx, |
1373 | * and applies mask to cull (skip) unneeded samples. |
1374 | * Updates buf_idx incrementing with the number of stored samples. |
1375 | * Samples from HW are transferred into buf, then in-place copy on buf is |
1376 | * performed in order to cull samples that need to be skipped. |
1377 | * This avoids copies of the first samples until we hit the 1st sample to skip, |
1378 | * and also avoids having an extra bounce buffer. |
1379 | * buf must be able to contain len elements in spite of how many samples we are |
1380 | * going to cull. |
1381 | */ |
1382 | static int bno055_scan_xfer(struct bno055_priv *priv, |
1383 | int start_ch, int len, unsigned long mask, |
1384 | __le16 *buf, int *buf_idx) |
1385 | { |
1386 | const int base = BNO055_ACC_DATA_X_LSB_REG; |
1387 | bool quat_in_read = false; |
1388 | int buf_base = *buf_idx; |
1389 | __le16 *dst, *src; |
1390 | int offs_fixup = 0; |
1391 | int xfer_len = len; |
1392 | int ret; |
1393 | int i, n; |
1394 | |
1395 | if (!mask) |
1396 | return 0; |
1397 | |
1398 | /* |
1399 | * All channels are made up 1 16-bit sample, except for quaternion that |
1400 | * is made up 4 16-bit values. |
1401 | * For us the quaternion CH is just like 4 regular CHs. |
1402 | * If our read starts past the quaternion make sure to adjust the |
1403 | * starting offset; if the quaternion is contained in our scan then make |
1404 | * sure to adjust the read len. |
1405 | */ |
1406 | if (start_ch > BNO055_SCAN_QUATERNION) { |
1407 | start_ch += 3; |
1408 | } else if ((start_ch <= BNO055_SCAN_QUATERNION) && |
1409 | ((start_ch + len) > BNO055_SCAN_QUATERNION)) { |
1410 | quat_in_read = true; |
1411 | xfer_len += 3; |
1412 | } |
1413 | |
1414 | ret = regmap_bulk_read(map: priv->regmap, |
1415 | reg: base + start_ch * sizeof(__le16), |
1416 | val: buf + buf_base, |
1417 | val_count: xfer_len * sizeof(__le16)); |
1418 | if (ret) |
1419 | return ret; |
1420 | |
1421 | for_each_set_bit(i, &mask, len) { |
1422 | if (quat_in_read && ((start_ch + i) > BNO055_SCAN_QUATERNION)) |
1423 | offs_fixup = 3; |
1424 | |
1425 | dst = buf + *buf_idx; |
1426 | src = buf + buf_base + offs_fixup + i; |
1427 | |
1428 | n = (start_ch + i == BNO055_SCAN_QUATERNION) ? 4 : 1; |
1429 | |
1430 | if (dst != src) |
1431 | memcpy(dst, src, n * sizeof(__le16)); |
1432 | |
1433 | *buf_idx += n; |
1434 | } |
1435 | return 0; |
1436 | } |
1437 | |
1438 | static irqreturn_t bno055_trigger_handler(int irq, void *p) |
1439 | { |
1440 | struct iio_poll_func *pf = p; |
1441 | struct iio_dev *iio_dev = pf->indio_dev; |
1442 | struct bno055_priv *priv = iio_priv(indio_dev: iio_dev); |
1443 | int xfer_start, start, end, prev_end; |
1444 | unsigned long mask; |
1445 | int ; |
1446 | bool first = true; |
1447 | int buf_idx = 0; |
1448 | bool thr_hit; |
1449 | int ret; |
1450 | |
1451 | mutex_lock(&priv->lock); |
1452 | |
1453 | /* |
1454 | * Walk the bitmap and eventually perform several transfers. |
1455 | * Bitmap ones-fields that are separated by gaps <= xfer_burst_break_thr |
1456 | * will be included in same transfer. |
1457 | * Every time the bitmap contains a gap wider than xfer_burst_break_thr |
1458 | * then we split the transfer, skipping the gap. |
1459 | */ |
1460 | for_each_set_bitrange(start, end, iio_dev->active_scan_mask, |
1461 | iio_dev->masklength) { |
1462 | /* |
1463 | * First transfer will start from the beginning of the first |
1464 | * ones-field in the bitmap |
1465 | */ |
1466 | if (first) { |
1467 | xfer_start = start; |
1468 | } else { |
1469 | /* |
1470 | * We found the next ones-field; check whether to |
1471 | * include it in * the current transfer or not (i.e. |
1472 | * let's perform the current * transfer and prepare for |
1473 | * another one). |
1474 | */ |
1475 | |
1476 | /* |
1477 | * In case the zeros-gap contains the quaternion bit, |
1478 | * then its length is actually 4 words instead of 1 |
1479 | * (i.e. +3 wrt other channels). |
1480 | */ |
1481 | quat_extra_len = ((start > BNO055_SCAN_QUATERNION) && |
1482 | (prev_end <= BNO055_SCAN_QUATERNION)) ? 3 : 0; |
1483 | |
1484 | /* If the gap is wider than xfer_burst_break_thr then.. */ |
1485 | thr_hit = (start - prev_end + quat_extra_len) > |
1486 | priv->xfer_burst_break_thr; |
1487 | |
1488 | /* |
1489 | * .. transfer all the data up to the gap. Then set the |
1490 | * next transfer start index at right after the gap |
1491 | * (i.e. at the start of this ones-field). |
1492 | */ |
1493 | if (thr_hit) { |
1494 | mask = *iio_dev->active_scan_mask >> xfer_start; |
1495 | ret = bno055_scan_xfer(priv, start_ch: xfer_start, |
1496 | len: prev_end - xfer_start, |
1497 | mask, buf: priv->buf.chans, buf_idx: &buf_idx); |
1498 | if (ret) |
1499 | goto done; |
1500 | xfer_start = start; |
1501 | } |
1502 | } |
1503 | first = false; |
1504 | prev_end = end; |
1505 | } |
1506 | |
1507 | /* |
1508 | * We finished walking the bitmap; no more gaps to check for. Just |
1509 | * perform the current transfer. |
1510 | */ |
1511 | mask = *iio_dev->active_scan_mask >> xfer_start; |
1512 | ret = bno055_scan_xfer(priv, start_ch: xfer_start, |
1513 | len: prev_end - xfer_start, |
1514 | mask, buf: priv->buf.chans, buf_idx: &buf_idx); |
1515 | |
1516 | if (!ret) |
1517 | iio_push_to_buffers_with_timestamp(indio_dev: iio_dev, |
1518 | data: &priv->buf, timestamp: pf->timestamp); |
1519 | done: |
1520 | mutex_unlock(lock: &priv->lock); |
1521 | iio_trigger_notify_done(trig: iio_dev->trig); |
1522 | return IRQ_HANDLED; |
1523 | } |
1524 | |
1525 | static int bno055_buffer_preenable(struct iio_dev *indio_dev) |
1526 | { |
1527 | struct bno055_priv *priv = iio_priv(indio_dev); |
1528 | const unsigned long fusion_mask = |
1529 | BIT(BNO055_SCAN_YAW) | |
1530 | BIT(BNO055_SCAN_ROLL) | |
1531 | BIT(BNO055_SCAN_PITCH) | |
1532 | BIT(BNO055_SCAN_QUATERNION) | |
1533 | BIT(BNO055_SCAN_LIA_X) | |
1534 | BIT(BNO055_SCAN_LIA_Y) | |
1535 | BIT(BNO055_SCAN_LIA_Z) | |
1536 | BIT(BNO055_SCAN_GRAVITY_X) | |
1537 | BIT(BNO055_SCAN_GRAVITY_Y) | |
1538 | BIT(BNO055_SCAN_GRAVITY_Z); |
1539 | |
1540 | if (priv->operation_mode == BNO055_OPR_MODE_AMG && |
1541 | bitmap_intersects(src1: indio_dev->active_scan_mask, src2: &fusion_mask, |
1542 | nbits: _BNO055_SCAN_MAX)) |
1543 | return -EBUSY; |
1544 | return 0; |
1545 | } |
1546 | |
1547 | static const struct iio_buffer_setup_ops bno055_buffer_setup_ops = { |
1548 | .preenable = bno055_buffer_preenable, |
1549 | }; |
1550 | |
1551 | int bno055_probe(struct device *dev, struct regmap *regmap, |
1552 | int xfer_burst_break_thr, bool sw_reset) |
1553 | { |
1554 | const struct firmware *caldata = NULL; |
1555 | struct bno055_priv *priv; |
1556 | struct iio_dev *iio_dev; |
1557 | char *fw_name_buf; |
1558 | unsigned int val; |
1559 | int rev, ver; |
1560 | int ret; |
1561 | |
1562 | iio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*priv)); |
1563 | if (!iio_dev) |
1564 | return -ENOMEM; |
1565 | |
1566 | iio_dev->name = "bno055" ; |
1567 | priv = iio_priv(indio_dev: iio_dev); |
1568 | mutex_init(&priv->lock); |
1569 | priv->regmap = regmap; |
1570 | priv->dev = dev; |
1571 | priv->xfer_burst_break_thr = xfer_burst_break_thr; |
1572 | priv->sw_reset = sw_reset; |
1573 | |
1574 | priv->reset_gpio = devm_gpiod_get_optional(dev, con_id: "reset" , flags: GPIOD_OUT_LOW); |
1575 | if (IS_ERR(ptr: priv->reset_gpio)) |
1576 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->reset_gpio), fmt: "Failed to get reset GPIO\n" ); |
1577 | |
1578 | priv->clk = devm_clk_get_optional_enabled(dev, id: "clk" ); |
1579 | if (IS_ERR(ptr: priv->clk)) |
1580 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->clk), fmt: "Failed to get CLK\n" ); |
1581 | |
1582 | if (priv->reset_gpio) { |
1583 | usleep_range(min: 5000, max: 10000); |
1584 | gpiod_set_value_cansleep(desc: priv->reset_gpio, value: 1); |
1585 | usleep_range(min: 650000, max: 750000); |
1586 | } else if (!sw_reset) { |
1587 | dev_warn(dev, "No usable reset method; IMU may be unreliable\n" ); |
1588 | } |
1589 | |
1590 | ret = regmap_read(map: priv->regmap, BNO055_CHIP_ID_REG, val: &val); |
1591 | if (ret) |
1592 | return ret; |
1593 | |
1594 | if (val != BNO055_CHIP_ID_MAGIC) |
1595 | dev_warn(dev, "Unrecognized chip ID 0x%x\n" , val); |
1596 | |
1597 | /* |
1598 | * In case we haven't a HW reset pin, we can still reset the chip via |
1599 | * register write. This is probably nonsense in case we can't even |
1600 | * communicate with the chip or the chip isn't the one we expect (i.e. |
1601 | * we don't write to unknown chips), so we perform SW reset only after |
1602 | * chip magic ID check |
1603 | */ |
1604 | if (!priv->reset_gpio) { |
1605 | ret = bno055_system_reset(priv); |
1606 | if (ret) |
1607 | return ret; |
1608 | } |
1609 | |
1610 | ret = regmap_read(map: priv->regmap, BNO055_SW_REV_LSB_REG, val: &rev); |
1611 | if (ret) |
1612 | return ret; |
1613 | |
1614 | ret = regmap_read(map: priv->regmap, BNO055_SW_REV_MSB_REG, val: &ver); |
1615 | if (ret) |
1616 | return ret; |
1617 | |
1618 | /* |
1619 | * The stock FW version contains a bug (see comment at the beginning of |
1620 | * this file) that causes the anglvel scale to be changed depending on |
1621 | * the chip range setting. We workaround this, but we don't know what |
1622 | * other FW versions might do. |
1623 | */ |
1624 | if (ver != 0x3 || rev != 0x11) |
1625 | dev_warn(dev, "Untested firmware version. Anglvel scale may not work as expected\n" ); |
1626 | |
1627 | ret = regmap_bulk_read(map: priv->regmap, BNO055_UID_LOWER_REG, |
1628 | val: priv->uid, BNO055_UID_LEN); |
1629 | if (ret) |
1630 | return ret; |
1631 | |
1632 | /* Sensor calibration data */ |
1633 | fw_name_buf = kasprintf(GFP_KERNEL, BNO055_FW_UID_FMT, |
1634 | BNO055_UID_LEN, priv->uid); |
1635 | if (!fw_name_buf) |
1636 | return -ENOMEM; |
1637 | |
1638 | ret = request_firmware(fw: &caldata, name: fw_name_buf, device: dev); |
1639 | kfree(objp: fw_name_buf); |
1640 | if (ret) |
1641 | ret = request_firmware(fw: &caldata, BNO055_FW_GENERIC_NAME, device: dev); |
1642 | if (ret) { |
1643 | dev_notice(dev, "Calibration file load failed. See instruction in kernel Documentation/iio/bno055.rst\n" ); |
1644 | ret = bno055_init(priv, NULL, len: 0); |
1645 | } else { |
1646 | ret = bno055_init(priv, caldata: caldata->data, len: caldata->size); |
1647 | release_firmware(fw: caldata); |
1648 | } |
1649 | if (ret) |
1650 | return ret; |
1651 | |
1652 | priv->operation_mode = BNO055_OPR_MODE_FUSION; |
1653 | ret = bno055_operation_mode_do_set(priv, operation_mode: priv->operation_mode); |
1654 | if (ret) |
1655 | return ret; |
1656 | |
1657 | ret = devm_add_action_or_reset(dev, bno055_uninit, priv); |
1658 | if (ret) |
1659 | return ret; |
1660 | |
1661 | iio_dev->channels = bno055_channels; |
1662 | iio_dev->num_channels = ARRAY_SIZE(bno055_channels); |
1663 | iio_dev->info = &bno055_info; |
1664 | iio_dev->modes = INDIO_DIRECT_MODE; |
1665 | |
1666 | ret = devm_iio_triggered_buffer_setup(dev, iio_dev, |
1667 | iio_pollfunc_store_time, |
1668 | bno055_trigger_handler, |
1669 | &bno055_buffer_setup_ops); |
1670 | if (ret) |
1671 | return ret; |
1672 | |
1673 | ret = devm_iio_device_register(dev, iio_dev); |
1674 | if (ret) |
1675 | return ret; |
1676 | |
1677 | bno055_debugfs_init(iio_dev); |
1678 | |
1679 | return 0; |
1680 | } |
1681 | EXPORT_SYMBOL_NS_GPL(bno055_probe, IIO_BNO055); |
1682 | |
1683 | MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>" ); |
1684 | MODULE_DESCRIPTION("Bosch BNO055 driver" ); |
1685 | MODULE_LICENSE("GPL" ); |
1686 | |