Skip to content

Commit

Permalink
Input: iqs7222 - protect volatile registers
Browse files Browse the repository at this point in the history
Select variants of silicon silently mirror part of the event mask
register to the system setup register (0xD0), and vice versa. For
the following sequence:

1. Read registers 0xD0 onward and store their contents.
2. Modify the contents, including event mask fields.
3. Write registers 0xD0 onward with the modified contents.
4. Write register 0xD0 on its own again later, using the contents
   from step 1 to populate any reserved fields.

...the event mask register (e.g. address 0xDA) has been corrupted
by writing register 0xD0 with contents that were made stale after
step 3.

To solve this problem, read register 0xD0 once more between steps
3 and 4. When register 0xD0 is written during step 4, the portion
which is mirrored to the event mask register already matches what
was written in step 3.

Fixes: e505eda ("Input: add support for Azoteq IQS7222A/B/C")
Signed-off-by: Jeff LaBundy <jeff@labundy.com>
Link: https://lore.kernel.org/r/20220626072412.475211-4-jeff@labundy.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
jlabundy authored and dtor committed Jun 27, 2022
1 parent 95215d3 commit 1e4189d
Showing 1 changed file with 14 additions and 4 deletions.
18 changes: 14 additions & 4 deletions drivers/input/misc/iqs7222.c
Original file line number Diff line number Diff line change
Expand Up @@ -1274,9 +1274,22 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
struct i2c_client *client = iqs7222->client;
ktime_t ati_timeout;
u16 sys_status = 0;
u16 sys_setup = iqs7222->sys_setup[0] & ~IQS7222_SYS_SETUP_ACK_RESET;
u16 sys_setup;
int error, i;

/*
* The reserved fields of the system setup register may have changed
* as a result of other registers having been written. As such, read
* the register's latest value to avoid unexpected behavior when the
* register is written in the loop that follows.
*/
error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup);
if (error)
return error;

sys_setup &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
sys_setup &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;

for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
/*
* Trigger ATI from streaming and normal-power modes so that
Expand Down Expand Up @@ -2241,9 +2254,6 @@ static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
return error;
}

sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;

sys_setup[0] |= IQS7222_SYS_SETUP_ACK_RESET;

return iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_SYS,
Expand Down

0 comments on commit 1e4189d

Please sign in to comment.