1
1
// SPDX-License-Identifier: GPL-2.0-only
2
- #include <linux/module.h>
2
+ #include <linux/delay.h>
3
+ #include <linux/gpio/consumer.h>
3
4
#include <linux/i2c.h>
4
- #include <linux/interrupt.h>
5
- #include <linux/slab.h>
6
5
#include <linux/input.h>
7
6
#include <linux/input/mt.h>
8
7
#include <linux/input/touchscreen.h>
9
- #include <linux/delay.h>
10
- #include <linux/workqueue.h>
11
- #include <linux/gpio/consumer.h>
8
+ #include <linux/interrupt.h>
9
+ #include <linux/module.h>
12
10
#include <linux/of_device.h>
11
+ #include <linux/slab.h>
13
12
#include <asm/unaligned.h>
14
13
15
14
#define ILI210X_TOUCHES 2
16
15
#define ILI211X_TOUCHES 10
17
16
#define ILI251X_TOUCHES 10
18
- #define DEFAULT_POLL_PERIOD 20
17
+
18
+ #define ILI2XXX_POLL_PERIOD 20
19
19
20
20
/* Touchscreen commands */
21
21
#define REG_TOUCHDATA 0x10
@@ -38,12 +38,11 @@ enum ili2xxx_model {
38
38
struct ili210x {
39
39
struct i2c_client * client ;
40
40
struct input_dev * input ;
41
- unsigned int poll_period ;
42
- struct delayed_work dwork ;
43
41
struct gpio_desc * reset_gpio ;
44
42
struct touchscreen_properties prop ;
45
43
enum ili2xxx_model model ;
46
44
unsigned int max_touches ;
45
+ bool stop ;
47
46
};
48
47
49
48
static int ili210x_read_reg (struct i2c_client * client , u8 reg , void * buf ,
@@ -196,57 +195,54 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata)
196
195
return contact ;
197
196
}
198
197
199
- static void ili210x_work ( struct work_struct * work )
198
+ static irqreturn_t ili210x_irq ( int irq , void * irq_data )
200
199
{
201
- struct ili210x * priv = container_of (work , struct ili210x ,
202
- dwork .work );
200
+ struct ili210x * priv = irq_data ;
203
201
struct i2c_client * client = priv -> client ;
204
202
u8 touchdata [64 ] = { 0 };
205
203
s16 sum = 0 ;
206
204
bool touch ;
207
- int i , error = - EINVAL ;
208
-
209
- if (priv -> model == MODEL_ILI210X ) {
210
- error = ili210x_read_reg (client , REG_TOUCHDATA ,
211
- touchdata , sizeof (touchdata ));
212
- } else if (priv -> model == MODEL_ILI211X ) {
213
- error = ili210x_read (client , touchdata , 43 );
214
- if (!error ) {
215
- /* This chip uses custom checksum at the end of data */
216
- for (i = 0 ; i <= 41 ; i ++ )
217
- sum = (sum + touchdata [i ]) & 0xff ;
218
- if ((- sum & 0xff ) != touchdata [42 ]) {
219
- dev_err (& client -> dev ,
220
- "CRC error (crc=0x%02x expected=0x%02x)\n" ,
221
- sum , touchdata [42 ]);
222
- return ;
205
+ int i ;
206
+ int error ;
207
+
208
+ do {
209
+ if (priv -> model == MODEL_ILI210X ) {
210
+ error = ili210x_read_reg (client , REG_TOUCHDATA ,
211
+ touchdata , sizeof (touchdata ));
212
+ } else if (priv -> model == MODEL_ILI211X ) {
213
+ error = ili210x_read (client , touchdata , 43 );
214
+ if (!error ) {
215
+ /*
216
+ * This chip uses custom checksum at the end
217
+ * of data.
218
+ */
219
+ for (i = 0 ; i <= 41 ; i ++ )
220
+ sum = (sum + touchdata [i ]) & 0xff ;
221
+ if ((- sum & 0xff ) != touchdata [42 ]) {
222
+ dev_err (& client -> dev ,
223
+ "CRC error (crc=0x%02x expected=0x%02x)\n" ,
224
+ sum , touchdata [42 ]);
225
+ break ;
226
+ }
223
227
}
228
+ } else if (priv -> model == MODEL_ILI251X ) {
229
+ error = ili210x_read_reg (client , REG_TOUCHDATA ,
230
+ touchdata , 31 );
231
+ if (!error && touchdata [0 ] == 2 )
232
+ error = ili210x_read (client ,
233
+ & touchdata [31 ], 20 );
224
234
}
225
- } else if (priv -> model == MODEL_ILI251X ) {
226
- error = ili210x_read_reg (client , REG_TOUCHDATA ,
227
- touchdata , 31 );
228
- if (!error && touchdata [0 ] == 2 )
229
- error = ili210x_read (client , & touchdata [31 ], 20 );
230
- }
231
-
232
- if (error ) {
233
- dev_err (& client -> dev ,
234
- "Unable to get touchdata, err = %d\n" , error );
235
- return ;
236
- }
237
235
238
- touch = ili210x_report_events (priv , touchdata );
239
-
240
- if (touch )
241
- schedule_delayed_work (& priv -> dwork ,
242
- msecs_to_jiffies (priv -> poll_period ));
243
- }
244
-
245
- static irqreturn_t ili210x_irq (int irq , void * irq_data )
246
- {
247
- struct ili210x * priv = irq_data ;
236
+ if (error ) {
237
+ dev_err (& client -> dev ,
238
+ "Unable to get touchdata, err = %d\n" , error );
239
+ break ;
240
+ }
248
241
249
- schedule_delayed_work (& priv -> dwork , 0 );
242
+ touch = ili210x_report_events (priv , touchdata );
243
+ if (touch )
244
+ msleep (ILI2XXX_POLL_PERIOD );
245
+ } while (!priv -> stop && touch );
250
246
251
247
return IRQ_HANDLED ;
252
248
}
@@ -293,11 +289,12 @@ static void ili210x_power_down(void *data)
293
289
gpiod_set_value_cansleep (reset_gpio , 1 );
294
290
}
295
291
296
- static void ili210x_cancel_work (void * data )
292
+ static void ili210x_stop (void * data )
297
293
{
298
294
struct ili210x * priv = data ;
299
295
300
- cancel_delayed_work_sync (& priv -> dwork );
296
+ /* Tell ISR to quit even if there is a contact. */
297
+ priv -> stop = true;
301
298
}
302
299
303
300
static int ili210x_i2c_probe (struct i2c_client * client ,
@@ -345,8 +342,6 @@ static int ili210x_i2c_probe(struct i2c_client *client,
345
342
346
343
priv -> client = client ;
347
344
priv -> input = input ;
348
- priv -> poll_period = DEFAULT_POLL_PERIOD ;
349
- INIT_DELAYED_WORK (& priv -> dwork , ili210x_work );
350
345
priv -> reset_gpio = reset_gpio ;
351
346
priv -> model = model ;
352
347
if (model == MODEL_ILI210X )
@@ -378,18 +373,18 @@ static int ili210x_i2c_probe(struct i2c_client *client,
378
373
touchscreen_parse_properties (input , true, & priv -> prop );
379
374
input_mt_init_slots (input , priv -> max_touches , INPUT_MT_DIRECT );
380
375
381
- error = devm_add_action (dev , ili210x_cancel_work , priv );
382
- if (error )
383
- return error ;
384
-
385
- error = devm_request_irq (dev , client -> irq , ili210x_irq , 0 ,
386
- client -> name , priv );
376
+ error = devm_request_threaded_irq (dev , client -> irq , NULL , ili210x_irq ,
377
+ IRQF_ONESHOT , client -> name , priv );
387
378
if (error ) {
388
379
dev_err (dev , "Unable to request touchscreen IRQ, err: %d\n" ,
389
380
error );
390
381
return error ;
391
382
}
392
383
384
+ error = devm_add_action_or_reset (dev , ili210x_stop , priv );
385
+ if (error )
386
+ return error ;
387
+
393
388
error = devm_device_add_group (dev , & ili210x_attr_group );
394
389
if (error ) {
395
390
dev_err (dev , "Unable to create sysfs attributes, err: %d\n" ,
0 commit comments