Some 360 degree hinges (yoga) style 2-in-1 devices use 2 KXCJ91008-s to allow the OS to determine the angle between the display and the base of the device, so that the OS can determine if the 2-in-1 is in laptop or in tablet-mode. On Windows both accelerometers are read by a special HingeAngleService process; and this process calls a DSM (Device Specific Method) on the ACPI KIOX010A device node for the sensor in the display, to let the embedded-controller (EC) know about the mode so that it can disable the kbd and touchpad to avoid spurious input while folded into tablet-mode. Currently the kxcjk1013 driver calls the DSM for this once at probe time to ensure that the builtin kbd and touchpad work. But some users have expressed interest in using this functionality to disable the kbd and touchpad when folded into tablet-mode as done under Windows. Add a tablet_mode sysfs file so that users can control the kbd/touchpad enable/disable functionality from user-space. Reported-by: russianneuromancer <russianneuromancer@xxxxx> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- drivers/iio/accel/kxcjk-1013.c | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 560a3373ff20..f15946d87c3c 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -150,6 +150,7 @@ struct kxcjk1013_data { int64_t timestamp; enum kx_chipset chipset; enum kx_acpi_type acpi_type; + bool tablet_mode; }; enum kxcjk1013_axis { @@ -300,6 +301,50 @@ static int kiox010a_dsm(struct device *dev, int fn_index) ACPI_FREE(obj); return 0; } + +static ssize_t tablet_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", data->tablet_mode); +} + +static ssize_t tablet_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct kxcjk1013_data *data = iio_priv(indio_dev); + unsigned long tablet_mode; + int err; + + err = kstrtoul(buf, 0, &tablet_mode); + if (err) + return err; + + err = kiox010a_dsm(&data->client->dev, + tablet_mode ? KIOX010A_SET_TABLET_MODE : + KIOX010A_SET_LAPTOP_MODE); + if (err) + return err; + + data->tablet_mode = tablet_mode; + return len; +} + +static DEVICE_ATTR_RW(tablet_mode); + +static struct attribute *tablet_mode_attrs[] = { + &dev_attr_tablet_mode.attr, + NULL +}; + +static const struct attribute_group tablet_mode_attrs_group = { + .attrs = tablet_mode_attrs, +}; #endif static int kxcjk1013_set_mode(struct kxcjk1013_data *data, @@ -383,6 +428,10 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (data->acpi_type == ACPI_KIOX010A) { /* Make sure the kbd and touchpad on 2-in-1s using 2 KXCJ91008-s work */ kiox010a_dsm(&data->client->dev, KIOX010A_SET_LAPTOP_MODE); + + ret = devm_device_add_group(&data->client->dev, &tablet_mode_attrs_group); + if (ret < 0) + dev_warn(&data->client->dev, "Error creating tablet_mode sysfs attribute\n"); } #endif -- 2.28.0