Skip to content

Commit 9a98b33

Browse files
aduggan-synaJiri Kosina
authored andcommitted
HID: rmi: Set F01 interrupt enable register when not set
A firmware bug in some touchpads causes the F01 interrupt enable register to be cleared on reset. This register controls which RMI functions generate interrupts and when it is cleared, the touchpad stops reporting all data. This patch looks for the cleared F01 control register and writes the correct value based on interrupt mask computed while scanning the PDT. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=91102 Signed-off-by: Andrew Duggan <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 7035f3a commit 9a98b33

File tree

1 file changed

+52
-5
lines changed

1 file changed

+52
-5
lines changed

drivers/hid/hid-rmi.c

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ struct rmi_data {
141141
unsigned long firmware_id;
142142

143143
u8 f01_ctrl0;
144+
u8 interrupt_enable_mask;
145+
bool restore_interrupt_mask;
144146
};
145147

146148
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
@@ -361,13 +363,34 @@ static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
361363
}
362364
}
363365

366+
static int rmi_reset_attn_mode(struct hid_device *hdev)
367+
{
368+
struct rmi_data *data = hid_get_drvdata(hdev);
369+
int ret;
370+
371+
ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
372+
if (ret)
373+
return ret;
374+
375+
if (data->restore_interrupt_mask) {
376+
ret = rmi_write(hdev, data->f01.control_base_addr + 1,
377+
&data->interrupt_enable_mask);
378+
if (ret) {
379+
hid_err(hdev, "can not write F01 control register\n");
380+
return ret;
381+
}
382+
}
383+
384+
return 0;
385+
}
386+
364387
static void rmi_reset_work(struct work_struct *work)
365388
{
366389
struct rmi_data *hdata = container_of(work, struct rmi_data,
367390
reset_work);
368391

369392
/* switch the device to RMI if we receive a generic mouse report */
370-
rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS);
393+
rmi_reset_attn_mode(hdata->hdev);
371394
}
372395

373396
static inline int rmi_schedule_reset(struct hid_device *hdev)
@@ -590,7 +613,7 @@ static int rmi_post_reset(struct hid_device *hdev)
590613
struct rmi_data *data = hid_get_drvdata(hdev);
591614
int ret;
592615

593-
ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
616+
ret = rmi_reset_attn_mode(hdev);
594617
if (ret) {
595618
hid_err(hdev, "can not set rmi mode\n");
596619
return ret;
@@ -617,7 +640,7 @@ static int rmi_post_reset(struct hid_device *hdev)
617640

618641
static int rmi_post_resume(struct hid_device *hdev)
619642
{
620-
return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
643+
return rmi_reset_attn_mode(hdev);
621644
}
622645
#endif /* CONFIG_PM */
623646

@@ -673,6 +696,7 @@ static void rmi_register_function(struct rmi_data *data,
673696
f->interrupt_count = pdt_entry->interrupt_source_count;
674697
f->irq_mask = rmi_gen_mask(f->interrupt_base,
675698
f->interrupt_count);
699+
data->interrupt_enable_mask |= f->irq_mask;
676700
}
677701
}
678702

@@ -810,12 +834,35 @@ static int rmi_populate_f01(struct hid_device *hdev)
810834
data->firmware_id += info[2] * 65536;
811835
}
812836

813-
ret = rmi_read(hdev, data->f01.control_base_addr, &data->f01_ctrl0);
837+
ret = rmi_read_block(hdev, data->f01.control_base_addr, info,
838+
2);
814839

815840
if (ret) {
816-
hid_err(hdev, "can not read f01 ctrl0\n");
841+
hid_err(hdev, "can not read f01 ctrl registers\n");
817842
return ret;
818843
}
844+
845+
data->f01_ctrl0 = info[0];
846+
847+
if (!info[1]) {
848+
/*
849+
* Do to a firmware bug in some touchpads the F01 interrupt
850+
* enable control register will be cleared on reset.
851+
* This will stop the touchpad from reporting data, so
852+
* if F01 CTRL1 is 0 then we need to explicitly enable
853+
* interrupts for the functions we want data for.
854+
*/
855+
data->restore_interrupt_mask = true;
856+
857+
ret = rmi_write(hdev, data->f01.control_base_addr + 1,
858+
&data->interrupt_enable_mask);
859+
if (ret) {
860+
hid_err(hdev, "can not write to control reg 1: %d.\n",
861+
ret);
862+
return ret;
863+
}
864+
}
865+
819866
return 0;
820867
}
821868

0 commit comments

Comments
 (0)