| .. | .. |
|---|
| 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) |
|---|