From: Jeff LaBundy <jeff@labundy.com>
To: dmitry.torokhov@gmail.com
Cc: linux-input@vger.kernel.org, jeff@labundy.com
Subject: [PATCH v2 3/5] Input: iqs269a - configure device with a single block write
Date: Tue, 3 Jan 2023 11:59:12 -0600 [thread overview]
Message-ID: <Y7Rs8GyV7g0nF5Yy@nixie71> (raw)
In-Reply-To: <Y7RsTqhYJOZs11sK@nixie71>
Unless it is being done as part of servicing a soft reset interrupt,
configuring channels on-the-fly (as is the case when writing to the
ati_trigger attribute) may cause GPIO3 (which reflects the state of
touch for a selected channel) to be inadvertently asserted.
To solve this problem, follow the vendor's recommendation and write
all channel configuration as well as the REDO_ATI register field as
part of a single block write. This ensures the device has been told
to re-calibrate itself following an I2C stop condition, after which
sensing resumes and GPIO3 may be asserted.
Fixes: 04e49867fad1 ("Input: add support for Azoteq IQS269A")
Signed-off-by: Jeff LaBundy <jeff@labundy.com>
Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
---
Changes in v2:
- Added Reviewed-by
drivers/input/misc/iqs269a.c | 98 ++++++++++++++----------------------
1 file changed, 39 insertions(+), 59 deletions(-)
diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c
index ea3401a1000f..1530efd301c2 100644
--- a/drivers/input/misc/iqs269a.c
+++ b/drivers/input/misc/iqs269a.c
@@ -96,8 +96,6 @@
#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4)
#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0)
-#define IQS269_CHx_SETTINGS 0x8C
-
#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15)
#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13)
#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12)
@@ -245,6 +243,18 @@ struct iqs269_ver_info {
u8 padding;
} __packed;
+struct iqs269_ch_reg {
+ u8 rx_enable;
+ u8 tx_enable;
+ __be16 engine_a;
+ __be16 engine_b;
+ __be16 ati_comp;
+ u8 thresh[3];
+ u8 hyst;
+ u8 assoc_select;
+ u8 assoc_weight;
+} __packed;
+
struct iqs269_sys_reg {
__be16 general;
u8 active;
@@ -266,18 +276,7 @@ struct iqs269_sys_reg {
u8 timeout_swipe;
u8 thresh_swipe;
u8 redo_ati;
-} __packed;
-
-struct iqs269_ch_reg {
- u8 rx_enable;
- u8 tx_enable;
- __be16 engine_a;
- __be16 engine_b;
- __be16 ati_comp;
- u8 thresh[3];
- u8 hyst;
- u8 assoc_select;
- u8 assoc_weight;
+ struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
} __packed;
struct iqs269_flags {
@@ -292,7 +291,6 @@ struct iqs269_private {
struct regmap *regmap;
struct mutex lock;
struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
- struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
struct iqs269_sys_reg sys_reg;
struct input_dev *keypad;
struct input_dev *slider[IQS269_NUM_SL];
@@ -307,6 +305,7 @@ struct iqs269_private {
static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int mode)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_a;
if (ch_num >= IQS269_NUM_CH)
@@ -317,12 +316,12 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
mutex_lock(&iqs269->lock);
- engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
+ engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK;
engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
- iqs269->ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
+ ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -333,13 +332,14 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *mode)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_a;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
mutex_lock(&iqs269->lock);
- engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
+ engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
mutex_unlock(&iqs269->lock);
engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK;
@@ -351,6 +351,7 @@ static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
static int iqs269_ati_base_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int base)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
@@ -379,12 +380,12 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269,
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK;
engine_b |= base;
- iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
+ ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -395,13 +396,14 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269,
static int iqs269_ati_base_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *base)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
mutex_unlock(&iqs269->lock);
switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) {
@@ -429,6 +431,7 @@ static int iqs269_ati_base_get(struct iqs269_private *iqs269,
static int iqs269_ati_target_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int target)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
@@ -439,12 +442,12 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269,
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK;
engine_b |= target / 32;
- iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
+ ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -455,13 +458,14 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269,
static int iqs269_ati_target_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *target)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
mutex_unlock(&iqs269->lock);
*target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32;
@@ -531,13 +535,7 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
iqs269->sys_reg.slider_select[1] |= BIT(reg);
- ch_reg = &iqs269->ch_reg[reg];
-
- error = regmap_raw_read(iqs269->regmap,
- IQS269_CHx_SETTINGS + reg * sizeof(*ch_reg) / 2,
- ch_reg, sizeof(*ch_reg));
- if (error)
- return error;
+ ch_reg = &iqs269->sys_reg.ch_reg[reg];
error = iqs269_parse_mask(ch_node, "azoteq,rx-enable",
&ch_reg->rx_enable);
@@ -1042,10 +1040,8 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
static int iqs269_dev_init(struct iqs269_private *iqs269)
{
- struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
- struct iqs269_ch_reg *ch_reg;
unsigned int val;
- int error, i;
+ int error;
mutex_lock(&iqs269->lock);
@@ -1055,27 +1051,8 @@ static int iqs269_dev_init(struct iqs269_private *iqs269)
if (error)
goto err_mutex;
- for (i = 0; i < IQS269_NUM_CH; i++) {
- if (!(sys_reg->active & BIT(i)))
- continue;
-
- ch_reg = &iqs269->ch_reg[i];
-
- error = regmap_raw_write(iqs269->regmap,
- IQS269_CHx_SETTINGS + i *
- sizeof(*ch_reg) / 2, ch_reg,
- sizeof(*ch_reg));
- if (error)
- goto err_mutex;
- }
-
- /*
- * The REDO-ATI and ATI channel selection fields must be written in the
- * same block write, so every field between registers 0x80 through 0x8B
- * (inclusive) must be written as well.
- */
- error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
- sizeof(*sys_reg));
+ error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ &iqs269->sys_reg, sizeof(iqs269->sys_reg));
if (error)
goto err_mutex;
@@ -1349,6 +1326,7 @@ static ssize_t hall_bin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
struct i2c_client *client = iqs269->client;
unsigned int val;
int error;
@@ -1363,8 +1341,8 @@ static ssize_t hall_bin_show(struct device *dev,
if (error)
return error;
- switch (iqs269->ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
- iqs269->ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
+ switch (ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
+ ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
case IQS269_HALL_PAD_R:
val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK;
val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT;
@@ -1444,9 +1422,10 @@ static ssize_t rx_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
return scnprintf(buf, PAGE_SIZE, "%u\n",
- iqs269->ch_reg[iqs269->ch_num].rx_enable);
+ ch_reg[iqs269->ch_num].rx_enable);
}
static ssize_t rx_enable_store(struct device *dev,
@@ -1454,6 +1433,7 @@ static ssize_t rx_enable_store(struct device *dev,
size_t count)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
unsigned int val;
int error;
@@ -1466,7 +1446,7 @@ static ssize_t rx_enable_store(struct device *dev,
mutex_lock(&iqs269->lock);
- iqs269->ch_reg[iqs269->ch_num].rx_enable = val;
+ ch_reg[iqs269->ch_num].rx_enable = val;
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
--
2.34.1
next prev parent reply other threads:[~2023-01-03 17:59 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-03 17:56 [PATCH v2 0/5] Miscellaneous fixes for Azoteq IQS269A Jeff LaBundy
2023-01-03 17:58 ` [PATCH v2 1/5] Input: iqs269a - drop unused device node references Jeff LaBundy
2023-01-03 17:58 ` [PATCH v2 2/5] Input: iqs269a - increase interrupt handler return delay Jeff LaBundy
2023-01-03 17:59 ` Jeff LaBundy [this message]
2023-01-03 17:59 ` [PATCH v2 4/5] Input: iqs269a - do not poll during suspend or resume Jeff LaBundy
2023-01-03 17:59 ` [PATCH v2 5/5] Input: iqs269a - do not poll during ATI Jeff LaBundy
2023-01-11 1:18 ` [PATCH v2 0/5] Miscellaneous fixes for Azoteq IQS269A Dmitry Torokhov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Y7Rs8GyV7g0nF5Yy@nixie71 \
--to=jeff@labundy.com \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).