Commit 62f46669 authored by Dirk Behme's avatar Dirk Behme Committed by Dmitry Torokhov

Input: zforce - make the interrupt GPIO optional

Add support for hardware which uses an I2C Serializer / Deserializer
(SerDes) to communicate with the zFroce touch driver. In this case the
SerDes will be configured as an interrupt controller and the zForce driver
will have no access to poll the GPIO line.

To support this, we add two dedicated new GPIOs in the device tree:
reset-gpios and irq-gpios, with the irq-gpios being optional.

To not break the existing device trees, the index based 'gpios' entries
are still supported, but marked as deprecated.

With this, if the interrupt GPIO is available, either via the old or new
device tree style, the while loop will read and handle the packets as long
as the GPIO indicates that the interrupt is asserted (existing, unchanged
driver behavior).

If the interrupt GPIO isn't available, i.e. not configured via the new
device tree style, we are falling back to one read per ISR invocation
(new behavior to support the SerDes).

Note that the gpiod functions help to handle the optional GPIO:
devm_gpiod_get_index_optional() will return NULL in case the interrupt
GPIO isn't available. And gpiod_get_value_cansleep() does cover this, too,
by returning 0 in this case.
Signed-off-by: default avatarDirk Behme <dirk.behme@de.bosch.com>
Reviewed-by: default avatarHeiko Stuebner <heiko.stuebner@bq.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 0642ffd6
...@@ -4,12 +4,12 @@ Required properties: ...@@ -4,12 +4,12 @@ Required properties:
- compatible: must be "neonode,zforce" - compatible: must be "neonode,zforce"
- reg: I2C address of the chip - reg: I2C address of the chip
- interrupts: interrupt to which the chip is connected - interrupts: interrupt to which the chip is connected
- gpios: gpios the chip is connected to - reset-gpios: reset gpio the chip is connected to
first one is the interrupt gpio and second one the reset gpio
- x-size: horizontal resolution of touchscreen - x-size: horizontal resolution of touchscreen
- y-size: vertical resolution of touchscreen - y-size: vertical resolution of touchscreen
Optional properties: Optional properties:
- irq-gpios : interrupt gpio the chip is connected to
- vdd-supply: Regulator controlling the controller supply - vdd-supply: Regulator controlling the controller supply
Example: Example:
...@@ -23,8 +23,8 @@ Example: ...@@ -23,8 +23,8 @@ Example:
interrupts = <2 0>; interrupts = <2 0>;
vdd-supply = <&reg_zforce_vdd>; vdd-supply = <&reg_zforce_vdd>;
gpios = <&gpio5 6 0>, /* INT */ reset-gpios = <&gpio5 9 0>; /* RST */
<&gpio5 9 0>; /* RST */ irq-gpios = <&gpio5 6 0>; /* IRQ, optional */
x-size = <800>; x-size = <800>;
y-size = <600>; y-size = <600>;
......
...@@ -510,7 +510,16 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) ...@@ -510,7 +510,16 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
if (!ts->suspending && device_may_wakeup(&client->dev)) if (!ts->suspending && device_may_wakeup(&client->dev))
pm_stay_awake(&client->dev); pm_stay_awake(&client->dev);
while (gpiod_get_value_cansleep(ts->gpio_int)) { /*
* Run at least once and exit the loop if
* - the optional interrupt GPIO isn't specified
* (there is only one packet read per ISR invocation, then)
* or
* - the GPIO isn't active any more
* (packet read until the level GPIO indicates that there is
* no IRQ any more)
*/
do {
ret = zforce_read_packet(ts, payload_buffer); ret = zforce_read_packet(ts, payload_buffer);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, dev_err(&client->dev,
...@@ -577,7 +586,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) ...@@ -577,7 +586,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
payload[RESPONSE_ID]); payload[RESPONSE_ID]);
break; break;
} }
} } while (gpiod_get_value_cansleep(ts->gpio_int));
if (!ts->suspending && device_may_wakeup(&client->dev)) if (!ts->suspending && device_may_wakeup(&client->dev))
pm_relax(&client->dev); pm_relax(&client->dev);
...@@ -754,8 +763,33 @@ static int zforce_probe(struct i2c_client *client, ...@@ -754,8 +763,33 @@ static int zforce_probe(struct i2c_client *client,
if (!ts) if (!ts)
return -ENOMEM; return -ENOMEM;
ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(ts->gpio_rst)) {
ret = PTR_ERR(ts->gpio_rst);
dev_err(&client->dev,
"failed to request reset GPIO: %d\n", ret);
return ret;
}
if (ts->gpio_rst) {
ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq",
GPIOD_IN);
if (IS_ERR(ts->gpio_int)) {
ret = PTR_ERR(ts->gpio_int);
dev_err(&client->dev,
"failed to request interrupt GPIO: %d\n", ret);
return ret;
}
} else {
/*
* Deprecated GPIO handling for compatibility
* with legacy binding.
*/
/* INT GPIO */ /* INT GPIO */
ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN); ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0,
GPIOD_IN);
if (IS_ERR(ts->gpio_int)) { if (IS_ERR(ts->gpio_int)) {
ret = PTR_ERR(ts->gpio_int); ret = PTR_ERR(ts->gpio_int);
dev_err(&client->dev, dev_err(&client->dev,
...@@ -772,6 +806,7 @@ static int zforce_probe(struct i2c_client *client, ...@@ -772,6 +806,7 @@ static int zforce_probe(struct i2c_client *client,
"failed to request reset GPIO: %d\n", ret); "failed to request reset GPIO: %d\n", ret);
return ret; return ret;
} }
}
ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd"); ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
if (IS_ERR(ts->reg_vdd)) { if (IS_ERR(ts->reg_vdd)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment