Skip to content

Commit ea4e174

Browse files
committed
input: atmel_ptc: add tracking support
The PTC sends too many IRQs, it causes to miss some of them. Most of the time, it's not an issue since it concerns position reporting. Unfortunately, we can miss IRQ about touch event. In this case, we can't report that the scroller is no longer touched. To avoid this situation, use a tasklet to perform a kind of tracking. While tracking the position, IRQs received are discarded. To perform the tracking, a tasklet is used to monitor the scroller position and status until the status is set to "not touch". Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
1 parent 5279055 commit ea4e174

1 file changed

Lines changed: 52 additions & 16 deletions

File tree

drivers/input/misc/atmel_ptc.c

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,14 @@ struct atmel_ptc {
186186
int irq;
187187
u8 imr;
188188
struct completion ppp_ack;
189+
struct tasklet_struct tasklet;
189190
unsigned int button_keycode[ATMEL_PTC_MAX_NODES];
190191
bool buttons_registered;
191192
bool scroller_registered[ATMEL_PTC_MAX_SCROLLERS];
192193
u32 button_event[ATMEL_PTC_MAX_NODES / 32];
193194
u32 button_state[ATMEL_PTC_MAX_NODES / 32];
194195
u32 scroller_event;
196+
bool scroller_tracking;
195197
char fw_version[ATMEL_PPP_FW_FOOTER_SIZE];
196198
};
197199

@@ -403,29 +405,29 @@ static u32 atmel_qtm_get_touch_events_scroller_event_id(struct atmel_ptc *ptc)
403405

404406
static void atmel_ptc_irq_scroller_event(struct atmel_ptc *ptc)
405407
{
406-
unsigned long i;
408+
unsigned int status, i;
407409

408-
if (!ptc->scroller_event)
410+
if (!ptc->scroller_event || ptc->scroller_tracking)
409411
return;
410412

411-
for_each_set_bit(i, (unsigned long *)&ptc->scroller_event, ATMEL_PTC_MAX_SCROLLERS) {
412-
unsigned int scroller_type =
413-
atmel_qtm_get_scroller_type(ptc, i);
414-
unsigned int position =
415-
atmel_qtm_get_scroller_position(ptc, i);
416-
unsigned int status =
417-
atmel_qtm_get_scroller_status(ptc, i);
418-
419-
if (scroller_type == ATMEL_QTM_SCROLLER_TYPE_WHEEL)
420-
input_report_abs(ptc->scroller_input[i],
421-
ABS_WHEEL, position);
422-
else
423-
input_report_abs(ptc->scroller_input[i],
424-
ABS_X, position);
413+
/*
414+
* Report the touch event and let the tasklet tracking the position
415+
* until the scrollers are no longer touched.
416+
*/
417+
for (i = 0 ; i < ATMEL_PTC_MAX_SCROLLERS; i++) {
418+
if (!ptc->scroller_input[i])
419+
break;
420+
421+
status = atmel_qtm_get_scroller_status(ptc, i);
425422

426423
input_report_key(ptc->scroller_input[i], BTN_TOUCH,
427424
status & 0x1);
428425
input_sync(ptc->scroller_input[i]);
426+
427+
if (status & 0x1) {
428+
ptc->scroller_tracking = true;
429+
tasklet_schedule(&ptc->tasklet);
430+
}
429431
}
430432
}
431433

@@ -724,6 +726,37 @@ static int atmel_ptc_cmd_send(struct atmel_ptc *ptc, struct atmel_qtm_cmd *cmd)
724726
return 0;
725727
}
726728

729+
static void atmel_ptc_tasklet(unsigned long priv)
730+
{
731+
struct atmel_ptc *ptc = (struct atmel_ptc *)priv;
732+
unsigned int scroller_type, position, status, i;
733+
734+
for (i = 0 ; i < ATMEL_PTC_MAX_SCROLLERS; i++) {
735+
if (!ptc->scroller_input[i])
736+
break;
737+
738+
scroller_type = atmel_qtm_get_scroller_type(ptc, i);
739+
position = atmel_qtm_get_scroller_position(ptc, i);
740+
status = atmel_qtm_get_scroller_status(ptc, i);
741+
742+
if (status & 0x1) {
743+
if (scroller_type == ATMEL_QTM_SCROLLER_TYPE_WHEEL)
744+
input_report_abs(ptc->scroller_input[i],
745+
ABS_WHEEL, position);
746+
else
747+
input_report_abs(ptc->scroller_input[i],
748+
ABS_X, position);
749+
input_sync(ptc->scroller_input[i]);
750+
tasklet_schedule(&ptc->tasklet);
751+
} else {
752+
input_report_key(ptc->scroller_input[i], BTN_TOUCH, 0);
753+
input_sync(ptc->scroller_input[i]);
754+
755+
ptc->scroller_tracking = false;
756+
}
757+
}
758+
}
759+
727760
static int atmel_ptc_conf_load(struct atmel_ptc *ptc)
728761
{
729762
const struct firmware *conf;
@@ -1024,13 +1057,16 @@ static int atmel_ptc_probe(struct platform_device *pdev)
10241057
if (debug_mode)
10251058
ret = sysfs_create_group(&ptc->dev->kobj, &atmel_ptc_qtm_mb_attr_group);
10261059

1060+
tasklet_init(&ptc->tasklet, atmel_ptc_tasklet, (unsigned long)ptc);
1061+
10271062
return ret;
10281063
}
10291064

10301065
static int atmel_ptc_remove(struct platform_device *pdev)
10311066
{
10321067
struct atmel_ptc *ptc = platform_get_drvdata(pdev);
10331068

1069+
tasklet_kill(&ptc->tasklet);
10341070
atmel_ptc_unregister_input_devices(ptc);
10351071
atmel_ptc_free_pins(ptc);
10361072

0 commit comments

Comments
 (0)