Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: accel: bmc150: Get mount-matrix from ACPI

bmc150 accelerometers with an ACPI hardware-id of BOSC0200 have an ACPI
method providing their mount-matrix, add support for retrieving this.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20201130141954.339805-3-hdegoede@redhat.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Hans de Goede and committed by
Jonathan Cameron
8a067200 5bfb3a4b

+104 -4
+104 -4
drivers/iio/accel/bmc150-accel-core.c
··· 413 413 } 414 414 #endif 415 415 416 + #ifdef CONFIG_ACPI 417 + /* 418 + * Support for getting accelerometer information from BOSC0200 ACPI nodes. 419 + * 420 + * There are 2 variants of the BOSC0200 ACPI node. Some 2-in-1s with 360 degree 421 + * hinges declare 2 I2C ACPI-resources for 2 accelerometers, 1 in the display 422 + * and 1 in the base of the 2-in-1. On these 2-in-1s the ROMS ACPI object 423 + * contains the mount-matrix for the sensor in the display and ROMK contains 424 + * the mount-matrix for the sensor in the base. On devices using a single 425 + * sensor there is a ROTM ACPI object which contains the mount-matrix. 426 + * 427 + * Here is an incomplete list of devices known to use 1 of these setups: 428 + * 429 + * Yoga devices with 2 accelerometers using ROMS + ROMK for the mount-matrices: 430 + * Lenovo Thinkpad Yoga 11e 3th gen 431 + * Lenovo Thinkpad Yoga 11e 4th gen 432 + * 433 + * Tablets using a single accelerometer using ROTM for the mount-matrix: 434 + * Chuwi Hi8 Pro (CWI513) 435 + * Chuwi Vi8 Plus (CWI519) 436 + * Chuwi Hi13 437 + * Irbis TW90 438 + * Jumper EZpad mini 3 439 + * Onda V80 plus 440 + * Predia Basic Tablet 441 + */ 442 + static bool bmc150_apply_acpi_orientation(struct device *dev, 443 + struct iio_mount_matrix *orientation) 444 + { 445 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 446 + struct acpi_device *adev = ACPI_COMPANION(dev); 447 + union acpi_object *obj, *elements; 448 + char *name, *alt_name, *str; 449 + acpi_status status; 450 + int i, j, val[3]; 451 + 452 + if (!adev || !acpi_dev_hid_uid_match(adev, "BOSC0200", NULL)) 453 + return false; 454 + 455 + if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) 456 + alt_name = "ROMK"; 457 + else 458 + alt_name = "ROMS"; 459 + 460 + if (acpi_has_method(adev->handle, "ROTM")) 461 + name = "ROTM"; 462 + else if (acpi_has_method(adev->handle, alt_name)) 463 + name = alt_name; 464 + else 465 + return false; 466 + 467 + status = acpi_evaluate_object(adev->handle, name, NULL, &buffer); 468 + if (ACPI_FAILURE(status)) { 469 + dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status); 470 + return false; 471 + } 472 + 473 + obj = buffer.pointer; 474 + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) 475 + goto unknown_format; 476 + 477 + elements = obj->package.elements; 478 + for (i = 0; i < 3; i++) { 479 + if (elements[i].type != ACPI_TYPE_STRING) 480 + goto unknown_format; 481 + 482 + str = elements[i].string.pointer; 483 + if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) 484 + goto unknown_format; 485 + 486 + for (j = 0; j < 3; j++) { 487 + switch (val[j]) { 488 + case -1: str = "-1"; break; 489 + case 0: str = "0"; break; 490 + case 1: str = "1"; break; 491 + default: goto unknown_format; 492 + } 493 + orientation->rotation[i * 3 + j] = str; 494 + } 495 + } 496 + 497 + kfree(buffer.pointer); 498 + return true; 499 + 500 + unknown_format: 501 + dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n"); 502 + kfree(buffer.pointer); 503 + return false; 504 + } 505 + #else 506 + static bool bmc150_apply_acpi_orientation(struct device *dev, 507 + struct iio_mount_matrix *orientation) 508 + { 509 + return false; 510 + } 511 + #endif 512 + 416 513 static const struct bmc150_accel_interrupt_info { 417 514 u8 map_reg; 418 515 u8 map_bitmask; ··· 1682 1585 1683 1586 data->regmap = regmap; 1684 1587 1685 - ret = iio_read_mount_matrix(dev, "mount-matrix", 1686 - &data->orientation); 1687 - if (ret) 1688 - return ret; 1588 + if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) { 1589 + ret = iio_read_mount_matrix(dev, "mount-matrix", 1590 + &data->orientation); 1591 + if (ret) 1592 + return ret; 1593 + } 1594 + 1689 1595 /* 1690 1596 * VDD is the analog and digital domain voltage supply 1691 1597 * VDDIO is the digital I/O voltage supply