summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDirk Behme <dirk.behme@de.bosch.com>2015-08-03 22:03:09 +0200
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-08-03 23:10:10 +0200
commit62f46669688bf13643b91bbc30f19da1095a5ed6 (patch)
tree8d08537c78f1567badb6437d74aeb4a986471750 /drivers
parentInput: cyapa - do not try to enable proximity reporting on older devices (diff)
downloadlinux-62f46669688bf13643b91bbc30f19da1095a5ed6.tar.xz
linux-62f46669688bf13643b91bbc30f19da1095a5ed6.zip
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: Dirk Behme <dirk.behme@de.bosch.com> Reviewed-by: Heiko Stuebner <heiko.stuebner@bq.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/touchscreen/zforce_ts.c63
1 files changed, 49 insertions, 14 deletions
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 0aa934c3540e..781d0f83050a 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -510,7 +510,16 @@ 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)) {
+ /*
+ * 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);
if (ret < 0) {
dev_err(&client->dev,
@@ -577,7 +586,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
payload[RESPONSE_ID]);
break;
}
- }
+ } while (gpiod_get_value_cansleep(ts->gpio_int));
if (!ts->suspending && device_may_wakeup(&client->dev))
pm_relax(&client->dev);
@@ -754,18 +763,8 @@ static int zforce_probe(struct i2c_client *client,
if (!ts)
return -ENOMEM;
- /* INT GPIO */
- ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, 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;
- }
-
- /* RST GPIO */
- ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1,
- GPIOD_OUT_HIGH);
+ 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,
@@ -773,6 +772,42 @@ static int zforce_probe(struct i2c_client *client,
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 */
+ ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0,
+ 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;
+ }
+
+ /* RST GPIO */
+ ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1,
+ 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->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
if (IS_ERR(ts->reg_vdd)) {
ret = PTR_ERR(ts->reg_vdd);