.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Touch Screen driver for EETI's I2C connected touch screen panels |
---|
3 | 4 | * Copyright (c) 2009,2018 Daniel Mack <daniel@zonque.org> |
---|
.. | .. |
---|
8 | 9 | * Based on migor_ts.c |
---|
9 | 10 | * Copyright (c) 2008 Magnus Damm |
---|
10 | 11 | * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com> |
---|
11 | | - * |
---|
12 | | - * This file is free software; you can redistribute it and/or |
---|
13 | | - * modify it under the terms of the GNU General Public |
---|
14 | | - * License as published by the Free Software Foundation; either |
---|
15 | | - * version 2 of the License, or (at your option) any later version. |
---|
16 | | - * |
---|
17 | | - * This file is distributed in the hope that it will be useful, |
---|
18 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
19 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
20 | | - * General Public License for more details. |
---|
21 | | - * |
---|
22 | | - * You should have received a copy of the GNU General Public |
---|
23 | | - * License along with this library; if not, write to the Free Software |
---|
24 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
25 | 12 | */ |
---|
26 | 13 | |
---|
27 | 14 | #include <linux/module.h> |
---|
.. | .. |
---|
41 | 28 | struct input_dev *input; |
---|
42 | 29 | struct gpio_desc *attn_gpio; |
---|
43 | 30 | struct touchscreen_properties props; |
---|
| 31 | + struct mutex mutex; |
---|
44 | 32 | bool running; |
---|
45 | 33 | }; |
---|
46 | 34 | |
---|
.. | .. |
---|
75 | 63 | input_sync(eeti->input); |
---|
76 | 64 | } |
---|
77 | 65 | |
---|
| 66 | +static int eeti_ts_read(struct eeti_ts *eeti) |
---|
| 67 | +{ |
---|
| 68 | + int len, error; |
---|
| 69 | + char buf[6]; |
---|
| 70 | + |
---|
| 71 | + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); |
---|
| 72 | + if (len != sizeof(buf)) { |
---|
| 73 | + error = len < 0 ? len : -EIO; |
---|
| 74 | + dev_err(&eeti->client->dev, |
---|
| 75 | + "failed to read touchscreen data: %d\n", |
---|
| 76 | + error); |
---|
| 77 | + return error; |
---|
| 78 | + } |
---|
| 79 | + |
---|
| 80 | + /* Motion packet */ |
---|
| 81 | + if (buf[0] & 0x80) |
---|
| 82 | + eeti_ts_report_event(eeti, buf); |
---|
| 83 | + |
---|
| 84 | + return 0; |
---|
| 85 | +} |
---|
| 86 | + |
---|
78 | 87 | static irqreturn_t eeti_ts_isr(int irq, void *dev_id) |
---|
79 | 88 | { |
---|
80 | 89 | struct eeti_ts *eeti = dev_id; |
---|
81 | | - int len; |
---|
82 | 90 | int error; |
---|
83 | | - char buf[6]; |
---|
| 91 | + |
---|
| 92 | + mutex_lock(&eeti->mutex); |
---|
84 | 93 | |
---|
85 | 94 | do { |
---|
86 | | - len = i2c_master_recv(eeti->client, buf, sizeof(buf)); |
---|
87 | | - if (len != sizeof(buf)) { |
---|
88 | | - error = len < 0 ? len : -EIO; |
---|
89 | | - dev_err(&eeti->client->dev, |
---|
90 | | - "failed to read touchscreen data: %d\n", |
---|
91 | | - error); |
---|
| 95 | + /* |
---|
| 96 | + * If we have attention GPIO, trust it. Otherwise we'll read |
---|
| 97 | + * once and exit. We assume that in this case we are using |
---|
| 98 | + * level triggered interrupt and it will get raised again |
---|
| 99 | + * if/when there is more data. |
---|
| 100 | + */ |
---|
| 101 | + if (eeti->attn_gpio && |
---|
| 102 | + !gpiod_get_value_cansleep(eeti->attn_gpio)) { |
---|
92 | 103 | break; |
---|
93 | 104 | } |
---|
94 | 105 | |
---|
95 | | - if (buf[0] & 0x80) { |
---|
96 | | - /* Motion packet */ |
---|
97 | | - eeti_ts_report_event(eeti, buf); |
---|
98 | | - } |
---|
99 | | - } while (eeti->running && |
---|
100 | | - eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)); |
---|
| 106 | + error = eeti_ts_read(eeti); |
---|
| 107 | + if (error) |
---|
| 108 | + break; |
---|
101 | 109 | |
---|
| 110 | + } while (eeti->running && eeti->attn_gpio); |
---|
| 111 | + |
---|
| 112 | + mutex_unlock(&eeti->mutex); |
---|
102 | 113 | return IRQ_HANDLED; |
---|
103 | 114 | } |
---|
104 | 115 | |
---|
105 | 116 | static void eeti_ts_start(struct eeti_ts *eeti) |
---|
106 | 117 | { |
---|
| 118 | + mutex_lock(&eeti->mutex); |
---|
| 119 | + |
---|
107 | 120 | eeti->running = true; |
---|
108 | | - wmb(); |
---|
109 | 121 | enable_irq(eeti->client->irq); |
---|
| 122 | + |
---|
| 123 | + /* |
---|
| 124 | + * Kick the controller in case we are using edge interrupt and |
---|
| 125 | + * we missed our edge while interrupt was disabled. We expect |
---|
| 126 | + * the attention GPIO to be wired in this case. |
---|
| 127 | + */ |
---|
| 128 | + if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)) |
---|
| 129 | + eeti_ts_read(eeti); |
---|
| 130 | + |
---|
| 131 | + mutex_unlock(&eeti->mutex); |
---|
110 | 132 | } |
---|
111 | 133 | |
---|
112 | 134 | static void eeti_ts_stop(struct eeti_ts *eeti) |
---|
113 | 135 | { |
---|
| 136 | + /* |
---|
| 137 | + * Not locking here, just setting a flag and expect that the |
---|
| 138 | + * interrupt thread will notice the flag eventually. |
---|
| 139 | + */ |
---|
114 | 140 | eeti->running = false; |
---|
115 | 141 | wmb(); |
---|
116 | 142 | disable_irq(eeti->client->irq); |
---|
.. | .. |
---|
153 | 179 | return -ENOMEM; |
---|
154 | 180 | } |
---|
155 | 181 | |
---|
| 182 | + mutex_init(&eeti->mutex); |
---|
| 183 | + |
---|
156 | 184 | input = devm_input_allocate_device(dev); |
---|
157 | 185 | if (!input) { |
---|
158 | 186 | dev_err(dev, "Failed to allocate input device.\n"); |
---|