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:
rst-gpio and int-gpio. With the int-gpio being optional, then.

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

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: Dirk Behme <dirk.be...@de.bosch.com>
---
 .../bindings/input/touchscreen/zforce_ts.txt       |  8 ++--
 drivers/input/touchscreen/zforce_ts.c              | 49 +++++++++++++++++++++-
 2 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt 
b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt
index 80c37df..c6be925 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt
@@ -4,12 +4,12 @@ Required properties:
 - compatible: must be "neonode,zforce"
 - reg: I2C address of the chip
 - interrupts: interrupt to which the chip is connected
-- gpios: gpios the chip is connected to
-  first one is the interrupt gpio and second one the reset gpio
+- rst-gpio: reset gpio the chip is connected to
 - x-size: horizontal resolution of touchscreen
 - y-size: vertical resolution of touchscreen
 
 Optional properties:
+- int-gpio : interrupt gpio the chip is connected to
 - vdd-supply: Regulator controlling the controller supply
 
 Example:
@@ -23,8 +23,8 @@ Example:
                        interrupts = <2 0>;
                        vdd-supply = <&reg_zforce_vdd>;
 
-                       gpios = <&gpio5 6 0>, /* INT */
-                               <&gpio5 9 0>; /* RST */
+                       rst-gpio = <&gpio5 9 0>; /* RST */
+                       int-gpio = <&gpio5 6 0>; /* INT, optional */
 
                        x-size = <800>;
                        y-size = <600>;
diff --git a/drivers/input/touchscreen/zforce_ts.c 
b/drivers/input/touchscreen/zforce_ts.c
index edf01c3..bf1e944 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -494,6 +494,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
        int ret;
        u8 payload_buffer[FRAME_MAXSIZE];
        u8 *payload;
+       int run = 1;
 
        /*
         * When still suspended, return.
@@ -510,7 +511,18 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
        if (!ts->suspending && device_may_wakeup(&client->dev))
                pm_stay_awake(&client->dev);
 
-       while (gpiod_get_value_cansleep(ts->gpio_int)) {
+       while (run) {
+               /*
+                * Exit the loop if either
+                * - 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)
+                */
+               run = gpiod_get_value_cansleep(ts->gpio_int);
+
                ret = zforce_read_packet(ts, payload_buffer);
                if (ret < 0) {
                        dev_err(&client->dev,
@@ -754,6 +766,40 @@ static int zforce_probe(struct i2c_client *client,
        if (!ts)
                return -ENOMEM;
 
+       /*
+        * The reset GPIO isn't optional, but we might get it
+        * via the old style DT entries below, too. So it's
+        * not an error if we don't get it here. Therefore use
+        * devm_gpiod_get_optional() here.
+        */
+       ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "rst",
+                                              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;
+       }
+
+       ts->gpio_int = devm_gpiod_get_optional(&client->dev, "int", 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;
+       }
+
+       /* Skip the old style GPIO if we have the new one */
+       if (ts->gpio_rst)
+               goto skip;
+
+       /*
+        * Depreciated GPIO device tree handling for compatibility
+        * with existing device trees. For new device trees, don't
+        * use it any more. Instead use rst-gpio and the optional
+        * int-gpio above.
+        */
+
        /* INT GPIO */
        ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN);
        if (IS_ERR(ts->gpio_int)) {
@@ -773,6 +819,7 @@ static int zforce_probe(struct i2c_client *client,
                return ret;
        }
 
+skip:
        ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
        if (IS_ERR(ts->reg_vdd)) {
                ret = PTR_ERR(ts->reg_vdd);
-- 
2.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to