.. | .. |
---|
10 | 10 | #include <linux/regmap.h> |
---|
11 | 11 | #include <linux/acpi.h> |
---|
12 | 12 | #include <linux/bitops.h> |
---|
| 13 | +#include <linux/bitfield.h> |
---|
13 | 14 | |
---|
14 | 15 | #include <linux/iio/iio.h> |
---|
15 | 16 | #include <linux/iio/sysfs.h> |
---|
.. | .. |
---|
144 | 145 | #define FXOS8700_NVM_DATA_BNK0 0xa7 |
---|
145 | 146 | |
---|
146 | 147 | /* Bit definitions for FXOS8700_CTRL_REG1 */ |
---|
147 | | -#define FXOS8700_CTRL_ODR_MSK 0x38 |
---|
148 | 148 | #define FXOS8700_CTRL_ODR_MAX 0x00 |
---|
149 | | -#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3) |
---|
| 149 | +#define FXOS8700_CTRL_ODR_MSK GENMASK(5, 3) |
---|
150 | 150 | |
---|
151 | 151 | /* Bit definitions for FXOS8700_M_CTRL_REG1 */ |
---|
152 | 152 | #define FXOS8700_HMS_MASK GENMASK(1, 0) |
---|
.. | .. |
---|
320 | 320 | switch (iio_type) { |
---|
321 | 321 | case IIO_ACCEL: |
---|
322 | 322 | return FXOS8700_ACCEL; |
---|
323 | | - case IIO_ANGL_VEL: |
---|
| 323 | + case IIO_MAGN: |
---|
324 | 324 | return FXOS8700_MAGN; |
---|
325 | 325 | default: |
---|
326 | 326 | return -EINVAL; |
---|
.. | .. |
---|
345 | 345 | static int fxos8700_set_scale(struct fxos8700_data *data, |
---|
346 | 346 | enum fxos8700_sensor t, int uscale) |
---|
347 | 347 | { |
---|
348 | | - int i; |
---|
| 348 | + int i, ret, val; |
---|
| 349 | + bool active_mode; |
---|
349 | 350 | static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); |
---|
350 | 351 | struct device *dev = regmap_get_device(data->regmap); |
---|
351 | 352 | |
---|
352 | 353 | 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"); |
---|
354 | 355 | 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; |
---|
355 | 375 | } |
---|
356 | 376 | |
---|
357 | 377 | for (i = 0; i < scale_num; i++) |
---|
.. | .. |
---|
361 | 381 | if (i == scale_num) |
---|
362 | 382 | return -EINVAL; |
---|
363 | 383 | |
---|
364 | | - return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, |
---|
| 384 | + ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, |
---|
365 | 385 | fxos8700_accel_scale[i].bits); |
---|
| 386 | + if (ret) |
---|
| 387 | + return ret; |
---|
| 388 | + return regmap_write(data->regmap, FXOS8700_CTRL_REG1, |
---|
| 389 | + active_mode); |
---|
366 | 390 | } |
---|
367 | 391 | |
---|
368 | 392 | static int fxos8700_get_scale(struct fxos8700_data *data, |
---|
.. | .. |
---|
372 | 396 | static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); |
---|
373 | 397 | |
---|
374 | 398 | if (t == FXOS8700_MAGN) { |
---|
375 | | - *uscale = 1200; /* Magnetometer is locked at 1200uT */ |
---|
| 399 | + *uscale = 1000; /* Magnetometer is locked at 0.001Gs */ |
---|
376 | 400 | return 0; |
---|
377 | 401 | } |
---|
378 | 402 | |
---|
.. | .. |
---|
394 | 418 | int axis, int *val) |
---|
395 | 419 | { |
---|
396 | 420 | u8 base, reg; |
---|
| 421 | + s16 tmp; |
---|
397 | 422 | int ret; |
---|
398 | | - enum fxos8700_sensor type = fxos8700_to_sensor(chan_type); |
---|
399 | 423 | |
---|
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 | + } |
---|
401 | 439 | |
---|
402 | 440 | /* Block read 6 bytes of device output registers to avoid data loss */ |
---|
403 | 441 | ret = regmap_bulk_read(data->regmap, base, data->buf, |
---|
404 | | - FXOS8700_DATA_BUF_SIZE); |
---|
| 442 | + sizeof(data->buf)); |
---|
405 | 443 | if (ret) |
---|
406 | 444 | return ret; |
---|
407 | 445 | |
---|
408 | 446 | /* Convert axis to buffer index */ |
---|
409 | 447 | reg = axis - IIO_MOD_X; |
---|
410 | 448 | |
---|
| 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 | + |
---|
411 | 474 | /* Convert to native endianness */ |
---|
412 | | - *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15); |
---|
| 475 | + *val = sign_extend32(tmp, 15); |
---|
413 | 476 | |
---|
414 | 477 | return 0; |
---|
415 | 478 | } |
---|
.. | .. |
---|
445 | 508 | if (i >= odr_num) |
---|
446 | 509 | return -EINVAL; |
---|
447 | 510 | |
---|
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); |
---|
452 | 514 | } |
---|
453 | 515 | |
---|
454 | 516 | static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, |
---|
.. | .. |
---|
461 | 523 | if (ret) |
---|
462 | 524 | return ret; |
---|
463 | 525 | |
---|
464 | | - val &= FXOS8700_CTRL_ODR_MSK; |
---|
| 526 | + val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val); |
---|
465 | 527 | |
---|
466 | 528 | for (i = 0; i < odr_num; i++) |
---|
467 | 529 | if (val == fxos8700_odr[i].bits) |
---|
.. | .. |
---|
526 | 588 | static IIO_CONST_ATTR(in_magn_sampling_frequency_available, |
---|
527 | 589 | "1.5625 6.25 12.5 50 100 200 400 800"); |
---|
528 | 590 | 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"); |
---|
530 | 592 | |
---|
531 | 593 | static struct attribute *fxos8700_attrs[] = { |
---|
532 | 594 | &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, |
---|
.. | .. |
---|
592 | 654 | if (ret) |
---|
593 | 655 | return ret; |
---|
594 | 656 | |
---|
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); |
---|
598 | 662 | if (ret) |
---|
599 | 663 | return ret; |
---|
600 | 664 | |
---|
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); |
---|
603 | 670 | } |
---|
604 | 671 | |
---|
605 | 672 | static void fxos8700_chip_uninit(void *data) |
---|