hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/iio/imu/fxos8700_core.c
....@@ -10,6 +10,7 @@
1010 #include <linux/regmap.h>
1111 #include <linux/acpi.h>
1212 #include <linux/bitops.h>
13
+#include <linux/bitfield.h>
1314
1415 #include <linux/iio/iio.h>
1516 #include <linux/iio/sysfs.h>
....@@ -144,9 +145,8 @@
144145 #define FXOS8700_NVM_DATA_BNK0 0xa7
145146
146147 /* Bit definitions for FXOS8700_CTRL_REG1 */
147
-#define FXOS8700_CTRL_ODR_MSK 0x38
148148 #define FXOS8700_CTRL_ODR_MAX 0x00
149
-#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3)
149
+#define FXOS8700_CTRL_ODR_MSK GENMASK(5, 3)
150150
151151 /* Bit definitions for FXOS8700_M_CTRL_REG1 */
152152 #define FXOS8700_HMS_MASK GENMASK(1, 0)
....@@ -320,7 +320,7 @@
320320 switch (iio_type) {
321321 case IIO_ACCEL:
322322 return FXOS8700_ACCEL;
323
- case IIO_ANGL_VEL:
323
+ case IIO_MAGN:
324324 return FXOS8700_MAGN;
325325 default:
326326 return -EINVAL;
....@@ -345,13 +345,33 @@
345345 static int fxos8700_set_scale(struct fxos8700_data *data,
346346 enum fxos8700_sensor t, int uscale)
347347 {
348
- int i;
348
+ int i, ret, val;
349
+ bool active_mode;
349350 static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
350351 struct device *dev = regmap_get_device(data->regmap);
351352
352353 if (t == FXOS8700_MAGN) {
353
- dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
354
+ dev_err(dev, "Magnetometer scale is locked at 0.001Gs\n");
354355 return -EINVAL;
356
+ }
357
+
358
+ /*
359
+ * When device is in active mode, it failed to set an ACCEL
360
+ * full-scale range(2g/4g/8g) in FXOS8700_XYZ_DATA_CFG.
361
+ * This is not align with the datasheet, but it is a fxos8700
362
+ * chip behavier. Set the device in standby mode before setting
363
+ * an ACCEL full-scale range.
364
+ */
365
+ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
366
+ if (ret)
367
+ return ret;
368
+
369
+ active_mode = val & FXOS8700_ACTIVE;
370
+ if (active_mode) {
371
+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
372
+ val & ~FXOS8700_ACTIVE);
373
+ if (ret)
374
+ return ret;
355375 }
356376
357377 for (i = 0; i < scale_num; i++)
....@@ -361,8 +381,12 @@
361381 if (i == scale_num)
362382 return -EINVAL;
363383
364
- return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
384
+ ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
365385 fxos8700_accel_scale[i].bits);
386
+ if (ret)
387
+ return ret;
388
+ return regmap_write(data->regmap, FXOS8700_CTRL_REG1,
389
+ active_mode);
366390 }
367391
368392 static int fxos8700_get_scale(struct fxos8700_data *data,
....@@ -372,7 +396,7 @@
372396 static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
373397
374398 if (t == FXOS8700_MAGN) {
375
- *uscale = 1200; /* Magnetometer is locked at 1200uT */
399
+ *uscale = 1000; /* Magnetometer is locked at 0.001Gs */
376400 return 0;
377401 }
378402
....@@ -394,22 +418,61 @@
394418 int axis, int *val)
395419 {
396420 u8 base, reg;
421
+ s16 tmp;
397422 int ret;
398
- enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
399423
400
- base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
424
+ /*
425
+ * Different register base addresses varies with channel types.
426
+ * This bug hasn't been noticed before because using an enum is
427
+ * really hard to read. Use an a switch statement to take over that.
428
+ */
429
+ switch (chan_type) {
430
+ case IIO_ACCEL:
431
+ base = FXOS8700_OUT_X_MSB;
432
+ break;
433
+ case IIO_MAGN:
434
+ base = FXOS8700_M_OUT_X_MSB;
435
+ break;
436
+ default:
437
+ return -EINVAL;
438
+ }
401439
402440 /* Block read 6 bytes of device output registers to avoid data loss */
403441 ret = regmap_bulk_read(data->regmap, base, data->buf,
404
- FXOS8700_DATA_BUF_SIZE);
442
+ sizeof(data->buf));
405443 if (ret)
406444 return ret;
407445
408446 /* Convert axis to buffer index */
409447 reg = axis - IIO_MOD_X;
410448
449
+ /*
450
+ * Convert to native endianness. The accel data and magn data
451
+ * are signed, so a forced type conversion is needed.
452
+ */
453
+ tmp = be16_to_cpu(data->buf[reg]);
454
+
455
+ /*
456
+ * ACCEL output data registers contain the X-axis, Y-axis, and Z-axis
457
+ * 14-bit left-justified sample data and MAGN output data registers
458
+ * contain the X-axis, Y-axis, and Z-axis 16-bit sample data. Apply
459
+ * a signed 2 bits right shift to the readback raw data from ACCEL
460
+ * output data register and keep that from MAGN sensor as the origin.
461
+ * Value should be extended to 32 bit.
462
+ */
463
+ switch (chan_type) {
464
+ case IIO_ACCEL:
465
+ tmp = tmp >> 2;
466
+ break;
467
+ case IIO_MAGN:
468
+ /* Nothing to do */
469
+ break;
470
+ default:
471
+ return -EINVAL;
472
+ }
473
+
411474 /* Convert to native endianness */
412
- *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
475
+ *val = sign_extend32(tmp, 15);
413476
414477 return 0;
415478 }
....@@ -445,10 +508,9 @@
445508 if (i >= odr_num)
446509 return -EINVAL;
447510
448
- return regmap_update_bits(data->regmap,
449
- FXOS8700_CTRL_REG1,
450
- FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
451
- fxos8700_odr[i].bits << 3 | active_mode);
511
+ val &= ~FXOS8700_CTRL_ODR_MSK;
512
+ val |= FIELD_PREP(FXOS8700_CTRL_ODR_MSK, fxos8700_odr[i].bits) | FXOS8700_ACTIVE;
513
+ return regmap_write(data->regmap, FXOS8700_CTRL_REG1, val);
452514 }
453515
454516 static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
....@@ -461,7 +523,7 @@
461523 if (ret)
462524 return ret;
463525
464
- val &= FXOS8700_CTRL_ODR_MSK;
526
+ val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val);
465527
466528 for (i = 0; i < odr_num; i++)
467529 if (val == fxos8700_odr[i].bits)
....@@ -526,7 +588,7 @@
526588 static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
527589 "1.5625 6.25 12.5 50 100 200 400 800");
528590 static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
529
-static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
591
+static IIO_CONST_ATTR(in_magn_scale_available, "0.001000");
530592
531593 static struct attribute *fxos8700_attrs[] = {
532594 &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
....@@ -592,14 +654,19 @@
592654 if (ret)
593655 return ret;
594656
595
- /* Max ODR (800Hz individual or 400Hz hybrid), active mode */
596
- ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
597
- FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
657
+ /*
658
+ * Set max full-scale range (+/-8G) for ACCEL sensor in chip
659
+ * initialization then activate the device.
660
+ */
661
+ ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
598662 if (ret)
599663 return ret;
600664
601
- /* Set for max full-scale range (+/-8G) */
602
- return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
665
+ /* Max ODR (800Hz individual or 400Hz hybrid), active mode */
666
+ return regmap_update_bits(data->regmap, FXOS8700_CTRL_REG1,
667
+ FXOS8700_CTRL_ODR_MSK | FXOS8700_ACTIVE,
668
+ FIELD_PREP(FXOS8700_CTRL_ODR_MSK, FXOS8700_CTRL_ODR_MAX) |
669
+ FXOS8700_ACTIVE);
603670 }
604671
605672 static void fxos8700_chip_uninit(void *data)