summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/silead.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-05-07 09:37:55 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2021-05-07 09:37:55 +0300
commitaef511fb91b6efb2d355c2704cf979f3202d310a (patch)
treed94df6d5c0c297ade8a45594602006b04e95ad59 /drivers/input/touchscreen/silead.c
parente48661230cc35b3d0f4367eddfc19f86463ab917 (diff)
parent05665cef4b745cb46b1d1b8e96deaa25464092d3 (diff)
downloadlinux-aef511fb91b6efb2d355c2704cf979f3202d310a.tar.xz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - three new touchscreen drivers: Hycon HY46XX, ILITEK Lego Series, and MStar MSG2638 - a new driver for Azoteq IQS626A proximity and touch controller - addition of Amazon Game Controller to the list of devices handled by the xpad driver - Elan touchscreen driver will avoid binding to devices described as I2CHID compatible in ACPI tables - various driver fixes * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (56 commits) Input: xpad - add support for Amazon Game Controller Input: ili210x - add missing negation for touch indication on ili210x MAINTAINERS: repair reference in HYCON HY46XX TOUCHSCREEN SUPPORT Input: add driver for the Hycon HY46XX touchpanel series dt-bindings: touchscreen: Add HY46XX bindings dt-bindings: Add Hycon Technology vendor prefix Input: cyttsp - flag the device properly Input: cyttsp - set abs params for ABS_MT_TOUCH_MAJOR Input: cyttsp - drop the phys path Input: cyttsp - reduce reset pulse timings Input: cyttsp - error message on boot mode exit error Input: apbps2 - remove useless variable Input: mms114 - support MMS136 Input: mms114 - convert bindings to YAML and extend Input: Add support for ILITEK Lego Series dt-bindings: input: touchscreen: ilitek_ts_i2c: Add bindings Input: add MStar MSG2638 touchscreen driver dt-bindings: input/touchscreen: add bindings for msg2638 Input: silead - add workaround for x86 BIOS-es which bring the chip up in a stuck state Input: elants_i2c - do not bind to i2c-hid compatible ACPI instantiated devices ...
Diffstat (limited to 'drivers/input/touchscreen/silead.c')
-rw-r--r--drivers/input/touchscreen/silead.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 8fa2f3b7cfd8..1ee760bac0cf 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -20,6 +20,7 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/irq.h>
#include <linux/regulator/consumer.h>
@@ -335,10 +336,8 @@ static int silead_ts_get_id(struct i2c_client *client)
error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID,
sizeof(chip_id), (u8 *)&chip_id);
- if (error < 0) {
- dev_err(&client->dev, "Chip ID read error %d\n", error);
+ if (error < 0)
return error;
- }
data->chip_id = le32_to_cpu(chip_id);
dev_info(&client->dev, "Silead chip ID: 0x%8X", data->chip_id);
@@ -351,12 +350,49 @@ static int silead_ts_setup(struct i2c_client *client)
int error;
u32 status;
+ /*
+ * Some buggy BIOS-es bring up the chip in a stuck state where it
+ * blocks the I2C bus. The following steps are necessary to
+ * unstuck the chip / bus:
+ * 1. Turn off the Silead chip.
+ * 2. Try to do an I2C transfer with the chip, this will fail in
+ * response to which the I2C-bus-driver will call:
+ * i2c_recover_bus() which will unstuck the I2C-bus. Note the
+ * unstuck-ing of the I2C bus only works if we first drop the
+ * chip off the bus by turning it off.
+ * 3. Turn the chip back on.
+ *
+ * On the x86/ACPI systems were this problem is seen, step 1. and
+ * 3. require making ACPI calls and dealing with ACPI Power
+ * Resources. The workaround below runtime-suspends the chip to
+ * turn it off, leaving it up to the ACPI subsystem to deal with
+ * this.
+ */
+
+ if (device_property_read_bool(&client->dev,
+ "silead,stuck-controller-bug")) {
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_allow(&client->dev);
+
+ pm_runtime_suspend(&client->dev);
+
+ dev_warn(&client->dev, FW_BUG "Stuck I2C bus: please ignore the next 'controller timed out' error\n");
+ silead_ts_get_id(client);
+
+ /* The forbid will also resume the device */
+ pm_runtime_forbid(&client->dev);
+ pm_runtime_disable(&client->dev);
+ }
+
silead_ts_set_power(client, SILEAD_POWER_OFF);
silead_ts_set_power(client, SILEAD_POWER_ON);
error = silead_ts_get_id(client);
- if (error)
+ if (error) {
+ dev_err(&client->dev, "Chip ID read error %d\n", error);
return error;
+ }
error = silead_ts_init(client);
if (error)
@@ -486,7 +522,7 @@ static int silead_ts_probe(struct i2c_client *client,
silead_ts_read_props(client);
- /* We must have the IRQ provided by DT or ACPI subsytem */
+ /* We must have the IRQ provided by DT or ACPI subsystem */
if (client->irq <= 0)
return -ENODEV;