diff options
author | Jonathan Cameron <Jonathan.Cameron@huawei.com> | 2023-01-30 20:10:18 +0000 |
---|---|---|
committer | Jonathan Cameron <jonathan.cameron@huawei.com> | 2023-04-13 11:37:20 +0100 |
commit | dc3d25f22b889a326abc8331075849ea11b4f2bb (patch) | |
tree | c92e49a0c00a4a730c5b0aac729b77577f2785de /drivers | |
parent | bd66b6acd20ba72d1779fa1abe55eb0fcc20f2c3 (diff) |
iio: imu: lsm6dsx: Add ACPI mount matrix retrieval
DSDT ROTM method seen in the wild with SMO8B30 _HID.
Making assumption it is similar to that used for bmc150 plus
information from Darrell that the rotation is out by 90 degrees at boot.
Method (ROTM, 0, NotSerialized)
{
Name (RBUF, Package (0x03)
{
"0 -1 0",
"1 0 0",
"0 0 1"
})
Return (RBUF) /* \_SB_.PCI0.I2C5.DEV_.ROTM.RBUF */
}
Reported-by: Darrell Kavanagh <darrell.kavanagh@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Tested-by: Darrell Kavanagh <darrell.kavanagh@gmail.org>
Link: https://lore.kernel.org/r/20230130201018.981024-3-jic23@kernel.org
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 455e5edd3a80..6a18b363cf73 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -56,6 +56,7 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/acpi.h> #include <linux/delay.h> #include <linux/iio/events.h> #include <linux/iio/iio.h> @@ -2624,6 +2625,73 @@ static int st_lsm6dsx_init_regulators(struct device *dev) return 0; } +#ifdef CONFIG_ACPI + +static int lsm6dsx_get_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_device *adev = ACPI_COMPANION(dev); + union acpi_object *obj, *elements; + acpi_status status; + int i, j, val[3]; + char *str; + + if (!has_acpi_companion(dev)) + return -EINVAL; + + if (!acpi_has_method(adev->handle, "ROTM")) + return -EINVAL; + + status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer); + if (ACPI_FAILURE(status)) { + dev_warn(dev, "Failed to get ACPI mount matrix: %d\n", status); + return -EINVAL; + } + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) + goto unknown_format; + + elements = obj->package.elements; + for (i = 0; i < 3; i++) { + if (elements[i].type != ACPI_TYPE_STRING) + goto unknown_format; + + str = elements[i].string.pointer; + if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) + goto unknown_format; + + for (j = 0; j < 3; j++) { + switch (val[j]) { + case -1: str = "-1"; break; + case 0: str = "0"; break; + case 1: str = "1"; break; + default: goto unknown_format; + } + orientation->rotation[i * 3 + j] = str; + } + } + + kfree(buffer.pointer); + return 0; + +unknown_format: + dev_warn(dev, "Unknown ACPI mount matrix format, ignoring\n"); + kfree(buffer.pointer); + return -EINVAL; +} + +#else + +static int lsm6dsx_get_acpi_mount_matrix(struct device *dev, + struct iio_mount_matrix *orientation) +{ + return false; +} + +#endif + int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { @@ -2698,9 +2766,12 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } - err = iio_read_mount_matrix(hw->dev, &hw->orientation); - if (err) - return err; + err = lsm6dsx_get_acpi_mount_matrix(hw->dev, &hw->orientation); + if (err) { + err = iio_read_mount_matrix(hw->dev, &hw->orientation); + if (err) + return err; + } for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { if (!hw->iio_devs[i]) |