Skip to content

Commit

Permalink
Input: iqs7222 - preserve system status register
Browse files Browse the repository at this point in the history
Some register groups reserve a byte at the end of their continuous
address space. Depending on the variant of silicon, this field may
share the same memory space as the lower byte of the system status
register (0x10).

In these cases, caching the reserved byte and writing it later may
effectively reset the device depending on what happened in between
the read and write operations.

Solve this problem by avoiding any access to this last byte within
offending register groups. This method replaces a workaround which
attempted to write the reserved byte with up-to-date contents, but
left a small window in which updates by the device could have been
clobbered.

Now that the driver does not touch these reserved bytes, the order
in which the device's registers are written no longer matters, and
they can be written in their natural order. The new method is also
much more generic, and can be more easily extended to new variants
of silicon with different register maps.

As part of this change, the register read and write functions must
be gently updated to support byte access instead of word access.

Fixes: 2e70ef5 ("Input: iqs7222 - acknowledge reset before writing registers")
Signed-off-by: Jeff LaBundy <jeff@labundy.com>
Link: https://lore.kernel.org/r/Z85Alw+d9EHKXx2e@nixie71
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Jeff LaBundy authored and Dmitry Torokhov committed Mar 10, 2025
1 parent d85862c commit a2add51
Showing 1 changed file with 22 additions and 28 deletions.
50 changes: 22 additions & 28 deletions drivers/input/misc/iqs7222.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ enum iqs7222_reg_key_id {

enum iqs7222_reg_grp_id {
IQS7222_REG_GRP_STAT,
IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_CYCLE,
IQS7222_REG_GRP_GLBL,
IQS7222_REG_GRP_BTN,
IQS7222_REG_GRP_CHAN,
IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_SLDR,
IQS7222_REG_GRP_TPAD,
IQS7222_REG_GRP_GPIO,
Expand Down Expand Up @@ -286,6 +286,7 @@ static const struct iqs7222_event_desc iqs7222_tp_events[] = {

struct iqs7222_reg_grp_desc {
u16 base;
u16 val_len;
int num_row;
int num_col;
};
Expand Down Expand Up @@ -342,6 +343,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAC00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -400,6 +402,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAC00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -454,6 +457,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xC400,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -496,6 +500,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xC400,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -543,6 +548,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAA00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -600,6 +606,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAA00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -656,6 +663,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -712,6 +720,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -768,6 +777,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
.val_len = 3,
.num_row = 1,
.num_col = 2,
},
Expand Down Expand Up @@ -1604,7 +1614,7 @@ static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
}

static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
u16 reg, void *val, u16 num_val)
u16 reg, void *val, u16 val_len)
{
u8 reg_buf[sizeof(__be16)];
int ret, i;
Expand All @@ -1619,7 +1629,7 @@ static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = num_val * sizeof(__le16),
.len = val_len,
.buf = (u8 *)val,
},
};
Expand Down Expand Up @@ -1675,7 +1685,7 @@ static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
__le16 val_buf;
int error;

error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
error = iqs7222_read_burst(iqs7222, reg, &val_buf, sizeof(val_buf));
if (error)
return error;

Expand All @@ -1685,10 +1695,9 @@ static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
}

static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
u16 reg, const void *val, u16 num_val)
u16 reg, const void *val, u16 val_len)
{
int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
int val_len = num_val * sizeof(__le16);
int msg_len = reg_len + val_len;
int ret, i;
struct i2c_client *client = iqs7222->client;
Expand Down Expand Up @@ -1747,7 +1756,7 @@ static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
{
__le16 val_buf = cpu_to_le16(val);

return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
return iqs7222_write_burst(iqs7222, reg, &val_buf, sizeof(val_buf));
}

static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
Expand Down Expand Up @@ -1831,30 +1840,14 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)

/*
* Acknowledge reset before writing any registers in case the device
* suffers a spurious reset during initialization. Because this step
* may change the reserved fields of the second filter beta register,
* its cache must be updated.
*
* Writing the second filter beta register, in turn, may clobber the
* system status register. As such, the filter beta register pair is
* written first to protect against this hazard.
* suffers a spurious reset during initialization.
*/
if (dir == WRITE) {
u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1;
u16 filt_setup;

error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
iqs7222->sys_setup[0] |
IQS7222_SYS_SETUP_ACK_RESET);
if (error)
return error;

error = iqs7222_read_word(iqs7222, reg, &filt_setup);
if (error)
return error;

iqs7222->filt_setup[1] &= GENMASK(7, 0);
iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0));
}

/*
Expand Down Expand Up @@ -1883,6 +1876,7 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
int num_col = dev_desc->reg_grps[i].num_col;
u16 reg = dev_desc->reg_grps[i].base;
__le16 *val_buf;
u16 val_len = dev_desc->reg_grps[i].val_len ? : num_col * sizeof(*val_buf);
u16 *val;

if (!num_col)
Expand All @@ -1900,7 +1894,7 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
switch (dir) {
case READ:
error = iqs7222_read_burst(iqs7222, reg,
val_buf, num_col);
val_buf, val_len);
for (k = 0; k < num_col; k++)
val[k] = le16_to_cpu(val_buf[k]);
break;
Expand All @@ -1909,7 +1903,7 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
for (k = 0; k < num_col; k++)
val_buf[k] = cpu_to_le16(val[k]);
error = iqs7222_write_burst(iqs7222, reg,
val_buf, num_col);
val_buf, val_len);
break;

default:
Expand Down Expand Up @@ -1962,7 +1956,7 @@ static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
int error, i;

error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
ARRAY_SIZE(dev_id));
sizeof(dev_id));
if (error)
return error;

Expand Down Expand Up @@ -2915,7 +2909,7 @@ static int iqs7222_report(struct iqs7222_private *iqs7222)
__le16 status[IQS7222_MAX_COLS_STAT];

error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
num_stat);
num_stat * sizeof(*status));
if (error)
return error;

Expand Down

0 comments on commit a2add51

Please sign in to comment.