Takashi Iwai 2dc4c1
From 65299e8bfb24774e6340e93ae49f6626598917c8 Mon Sep 17 00:00:00 2001
Takashi Iwai 2dc4c1
From: Hans de Goede <hdegoede@redhat.com>
Takashi Iwai 2dc4c1
Date: Fri, 9 Apr 2021 22:29:07 -0700
Takashi Iwai 2dc4c1
Subject: [PATCH] Input: elants_i2c - do not bind to i2c-hid compatible ACPI instantiated devices
Takashi Iwai 2dc4c1
Git-commit: 65299e8bfb24774e6340e93ae49f6626598917c8
Takashi Iwai 2dc4c1
Patch-mainline: v5.13-rc1
Takashi Iwai 2dc4c1
References: git-fixes
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
Several users have been reporting that elants_i2c gives several errors
Takashi Iwai 2dc4c1
during probe and that their touchscreen does not work on their Lenovo AMD
Takashi Iwai 2dc4c1
based laptops with a touchscreen with a ELAN0001 ACPI hardware-id:
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
[    0.550596] elants_i2c i2c-ELAN0001:00: i2c-ELAN0001:00 supply vcc33 not found, using dummy regulator
Takashi Iwai 2dc4c1
[    0.551836] elants_i2c i2c-ELAN0001:00: i2c-ELAN0001:00 supply vccio not found, using dummy regulator
Takashi Iwai 2dc4c1
[    0.560932] elants_i2c i2c-ELAN0001:00: elants_i2c_send failed (77 77 77 77): -121
Takashi Iwai 2dc4c1
[    0.562427] elants_i2c i2c-ELAN0001:00: software reset failed: -121
Takashi Iwai 2dc4c1
[    0.595925] elants_i2c i2c-ELAN0001:00: elants_i2c_send failed (77 77 77 77): -121
Takashi Iwai 2dc4c1
[    0.597974] elants_i2c i2c-ELAN0001:00: software reset failed: -121
Takashi Iwai 2dc4c1
[    0.621893] elants_i2c i2c-ELAN0001:00: elants_i2c_send failed (77 77 77 77): -121
Takashi Iwai 2dc4c1
[    0.622504] elants_i2c i2c-ELAN0001:00: software reset failed: -121
Takashi Iwai 2dc4c1
[    0.632650] elants_i2c i2c-ELAN0001:00: elants_i2c_send failed (4d 61 69 6e): -121
Takashi Iwai 2dc4c1
[    0.634256] elants_i2c i2c-ELAN0001:00: boot failed: -121
Takashi Iwai 2dc4c1
[    0.699212] elants_i2c i2c-ELAN0001:00: invalid 'hello' packet: 00 00 ff ff
Takashi Iwai 2dc4c1
[    1.630506] elants_i2c i2c-ELAN0001:00: Failed to read fw id: -121
Takashi Iwai 2dc4c1
[    1.645508] elants_i2c i2c-ELAN0001:00: unknown packet 00 00 ff ff
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
Despite these errors, the elants_i2c driver stays bound to the device
Takashi Iwai 2dc4c1
(it returns 0 from its probe method despite the errors), blocking the
Takashi Iwai 2dc4c1
i2c-hid driver from binding.
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
Manually unbinding the elants_i2c driver and binding the i2c-hid driver
Takashi Iwai 2dc4c1
makes the touchscreen work.
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
Check if the ACPI-fwnode for the touchscreen contains one of the i2c-hid
Takashi Iwai 2dc4c1
compatiblity-id strings and if it has the I2C-HID spec's DSM to get the
Takashi Iwai 2dc4c1
HID descriptor address, If it has both then make elants_i2c not bind,
Takashi Iwai 2dc4c1
so that the i2c-hid driver can bind.
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
This assumes that non of the (older) elan touchscreens which actually
Takashi Iwai 2dc4c1
need the elants_i2c driver falsely advertise an i2c-hid compatiblity-id
Takashi Iwai 2dc4c1
+ DSM in their ACPI-fwnodes. If some of them actually do have this
Takashi Iwai 2dc4c1
false advertising, then this change may lead to regressions.
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
While at it also drop the unnecessary DEVICE_NAME prefixing of the
Takashi Iwai 2dc4c1
"I2C check functionality error", dev_err already outputs the driver-name.
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=207759
Takashi Iwai 2dc4c1
Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Takashi Iwai 2dc4c1
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Takashi Iwai 2dc4c1
Link: https://lore.kernel.org/r/20210405202756.16830-1-hdegoede@redhat.com
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Takashi Iwai 2dc4c1
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
---
Takashi Iwai 2dc4c1
 drivers/input/touchscreen/elants_i2c.c | 44 ++++++++++++++++++++++++--
Takashi Iwai 2dc4c1
 1 file changed, 42 insertions(+), 2 deletions(-)
Takashi Iwai 2dc4c1
Takashi Iwai 2dc4c1
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
Takashi Iwai 2dc4c1
index 4c2b579f6c8b..36cf5694bfcc 100644
Takashi Iwai 2dc4c1
--- a/drivers/input/touchscreen/elants_i2c.c
Takashi Iwai 2dc4c1
+++ b/drivers/input/touchscreen/elants_i2c.c
Takashi Iwai 2dc4c1
@@ -38,6 +38,7 @@
Takashi Iwai 2dc4c1
 #include <linux/of.h>
Takashi Iwai 2dc4c1
 #include <linux/gpio/consumer.h>
Takashi Iwai 2dc4c1
 #include <linux/regulator/consumer.h>
Takashi Iwai 2dc4c1
+#include <linux/uuid.h>
Takashi Iwai 2dc4c1
 #include <asm/unaligned.h>
Takashi Iwai 2dc4c1
 
Takashi Iwai 2dc4c1
 /* Device, Driver information */
Takashi Iwai 2dc4c1
@@ -1334,6 +1335,40 @@ static void elants_i2c_power_off(void *_data)
Takashi Iwai 2dc4c1
 	}
Takashi Iwai 2dc4c1
 }
Takashi Iwai 2dc4c1
 
Takashi Iwai 2dc4c1
+#ifdef CONFIG_ACPI
Takashi Iwai 2dc4c1
+static const struct acpi_device_id i2c_hid_ids[] = {
Takashi Iwai 2dc4c1
+	{"ACPI0C50", 0 },
Takashi Iwai 2dc4c1
+	{"PNP0C50", 0 },
Takashi Iwai 2dc4c1
+	{ },
Takashi Iwai 2dc4c1
+};
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
+static const guid_t i2c_hid_guid =
Takashi Iwai 2dc4c1
+	GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555,
Takashi Iwai 2dc4c1
+		  0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
+static bool elants_acpi_is_hid_device(struct device *dev)
Takashi Iwai 2dc4c1
+{
Takashi Iwai 2dc4c1
+	acpi_handle handle = ACPI_HANDLE(dev);
Takashi Iwai 2dc4c1
+	union acpi_object *obj;
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
+	if (acpi_match_device_ids(ACPI_COMPANION(dev), i2c_hid_ids))
Takashi Iwai 2dc4c1
+		return false;
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
+	obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL, ACPI_TYPE_INTEGER);
Takashi Iwai 2dc4c1
+	if (obj) {
Takashi Iwai 2dc4c1
+		ACPI_FREE(obj);
Takashi Iwai 2dc4c1
+		return true;
Takashi Iwai 2dc4c1
+	}
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
+	return false;
Takashi Iwai 2dc4c1
+}
Takashi Iwai 2dc4c1
+#else
Takashi Iwai 2dc4c1
+static bool elants_acpi_is_hid_device(struct device *dev)
Takashi Iwai 2dc4c1
+{
Takashi Iwai 2dc4c1
+	return false;
Takashi Iwai 2dc4c1
+}
Takashi Iwai 2dc4c1
+#endif
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
 static int elants_i2c_probe(struct i2c_client *client,
Takashi Iwai 2dc4c1
 			    const struct i2c_device_id *id)
Takashi Iwai 2dc4c1
 {
Takashi Iwai 2dc4c1
@@ -1342,9 +1377,14 @@ static int elants_i2c_probe(struct i2c_client *client,
Takashi Iwai 2dc4c1
 	unsigned long irqflags;
Takashi Iwai 2dc4c1
 	int error;
Takashi Iwai 2dc4c1
 
Takashi Iwai 2dc4c1
+	/* Don't bind to i2c-hid compatible devices, these are handled by the i2c-hid drv. */
Takashi Iwai 2dc4c1
+	if (elants_acpi_is_hid_device(&client->dev)) {
Takashi Iwai 2dc4c1
+		dev_warn(&client->dev, "This device appears to be an I2C-HID device, not binding\n");
Takashi Iwai 2dc4c1
+		return -ENODEV;
Takashi Iwai 2dc4c1
+	}
Takashi Iwai 2dc4c1
+
Takashi Iwai 2dc4c1
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
Takashi Iwai 2dc4c1
-		dev_err(&client->dev,
Takashi Iwai 2dc4c1
-			"%s: i2c check functionality error\n", DEVICE_NAME);
Takashi Iwai 2dc4c1
+		dev_err(&client->dev, "I2C check functionality error\n");
Takashi Iwai 2dc4c1
 		return -ENXIO;
Takashi Iwai 2dc4c1
 	}
Takashi Iwai 2dc4c1
 
Takashi Iwai 2dc4c1
-- 
Takashi Iwai 2dc4c1
2.26.2
Takashi Iwai 2dc4c1