Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: qt2160 - switch to using threaded interrupt handler

Instead of using combination of normal IRQ and work item which required
careful handling on device teardown, use standard threaded interrupt that
allows communication wityh the chip over slow (I2C) bus directly in the
interrupt handler.

To support polling mode switch to standard polling support implemented by
the input core.

Link: https://lore.kernel.org/r/20230724051345.335219-2-dmitry.torokhov@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+19 -34
+19 -34
drivers/input/keyboard/qt2160.c
··· 32 32 33 33 #define QT2160_NUM_LEDS_X 8 34 34 35 - #define QT2160_CYCLE_INTERVAL (2*HZ) 35 + #define QT2160_CYCLE_INTERVAL 2000 /* msec - 2 sec */ 36 36 37 37 static unsigned char qt2160_key2code[] = { 38 38 KEY_0, KEY_1, KEY_2, KEY_3, ··· 54 54 struct qt2160_data { 55 55 struct i2c_client *client; 56 56 struct input_dev *input; 57 - struct delayed_work dwork; 58 57 unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)]; 59 58 u16 key_matrix; 60 59 #ifdef CONFIG_LEDS_CLASS ··· 154 155 return 0; 155 156 } 156 157 157 - static int qt2160_get_key_matrix(struct qt2160_data *qt2160) 158 + static void qt2160_get_key_matrix(struct input_dev *input) 158 159 { 160 + struct qt2160_data *qt2160 = input_get_drvdata(input); 159 161 struct i2c_client *client = qt2160->client; 160 - struct input_dev *input = qt2160->input; 161 162 u8 regs[6]; 162 163 u16 old_matrix, new_matrix; 163 164 int ret, i, mask; ··· 172 173 if (ret) { 173 174 dev_err(&client->dev, 174 175 "could not perform chip read.\n"); 175 - return ret; 176 + return; 176 177 } 177 178 178 179 old_matrix = qt2160->key_matrix; ··· 190 191 } 191 192 192 193 input_sync(input); 193 - 194 - return 0; 195 194 } 196 195 197 - static irqreturn_t qt2160_irq(int irq, void *_qt2160) 196 + static irqreturn_t qt2160_irq(int irq, void *data) 198 197 { 199 - struct qt2160_data *qt2160 = _qt2160; 198 + struct input_dev *input = data; 200 199 201 - mod_delayed_work(system_wq, &qt2160->dwork, 0); 200 + qt2160_get_key_matrix(input); 202 201 203 202 return IRQ_HANDLED; 204 - } 205 - 206 - static void qt2160_schedule_read(struct qt2160_data *qt2160) 207 - { 208 - schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL); 209 - } 210 - 211 - static void qt2160_worker(struct work_struct *work) 212 - { 213 - struct qt2160_data *qt2160 = 214 - container_of(work, struct qt2160_data, dwork.work); 215 - 216 - dev_dbg(&qt2160->client->dev, "worker\n"); 217 - 218 - qt2160_get_key_matrix(qt2160); 219 - 220 - /* Avoid device lock up by checking every so often */ 221 - qt2160_schedule_read(qt2160); 222 203 } 223 204 224 205 static int qt2160_read(struct i2c_client *client, u8 reg) ··· 344 365 345 366 qt2160->client = client; 346 367 qt2160->input = input; 347 - INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker); 348 368 349 369 input->name = "AT42QT2160 Touch Sense Keyboard"; 350 370 input->id.bustype = BUS_I2C; ··· 360 382 } 361 383 __clear_bit(KEY_RESERVED, input->keybit); 362 384 385 + input_set_drvdata(input, qt2160); 386 + 363 387 /* Calibrate device */ 364 388 error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1); 365 389 if (error) { ··· 370 390 } 371 391 372 392 if (client->irq) { 373 - error = request_irq(client->irq, qt2160_irq, 374 - IRQF_TRIGGER_FALLING, "qt2160", qt2160); 393 + error = request_threaded_irq(client->irq, NULL, qt2160_irq, 394 + IRQF_TRIGGER_LOW | IRQF_ONESHOT, 395 + "qt2160", input); 375 396 if (error) { 376 397 dev_err(&client->dev, 377 398 "failed to allocate irq %d\n", client->irq); 378 399 goto err_free_mem; 379 400 } 401 + } else { 402 + error = input_setup_polling(input, qt2160_get_key_matrix); 403 + if (error) { 404 + dev_err(&client->dev, "Failed to setup polling\n"); 405 + goto err_free_mem; 406 + } 407 + input_set_poll_interval(input, QT2160_CYCLE_INTERVAL); 380 408 } 381 409 382 410 error = qt2160_register_leds(qt2160); ··· 401 413 } 402 414 403 415 i2c_set_clientdata(client, qt2160); 404 - qt2160_schedule_read(qt2160); 405 416 406 417 return 0; 407 418 ··· 424 437 /* Release IRQ so no queue will be scheduled */ 425 438 if (client->irq) 426 439 free_irq(client->irq, qt2160); 427 - 428 - cancel_delayed_work_sync(&qt2160->dwork); 429 440 430 441 input_unregister_device(qt2160->input); 431 442 kfree(qt2160);