diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-05-07 09:37:55 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-05-07 09:37:55 +0300 |
commit | aef511fb91b6efb2d355c2704cf979f3202d310a (patch) | |
tree | d94df6d5c0c297ade8a45594602006b04e95ad59 /drivers/input/touchscreen/silead.c | |
parent | e48661230cc35b3d0f4367eddfc19f86463ab917 (diff) | |
parent | 05665cef4b745cb46b1d1b8e96deaa25464092d3 (diff) | |
download | linux-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.c | 46 |
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; |