aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses
diff options
context:
space:
mode:
authorJarkko Nikula <jarkko.nikula@linux.intel.com>2024-02-13 14:48:43 +0200
committerAndi Shyti <andi.shyti@kernel.org>2024-02-27 01:51:32 +0100
commit64b6426a6e97a95c044fd2fff3f0adf7c1edb60c (patch)
treed193ac39b1bc39a55ad9ae10512c9245d3a1fd6a /drivers/i2c/busses
parent535677e44d57a31e1363529b5ecddb92653d7136 (diff)
downloadlinux-64b6426a6e97a95c044fd2fff3f0adf7c1edb60c.tar.gz
i2c: designware: Do not enable interrupts shortly in polling mode
I was testing the polling mode txgbe_i2c_dw_xfer_quirk() on a HW where the i2c-designware has interrupt connected and shared with other device. I noticed there is a bogus interrupt for each transfer. Reason for this that both polling mode functions call the i2c_dw_xfer_init() which enable interrupts then followed by immediate disable by the same polling mode functions. This is enough to trigger TX_EMPTY interrupt. Fix this by introducing a __i2c_dw_write_intr_mask() helper that unmasks interrupts conditionally and use it in i2c_dw_xfer_init(). Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Tested-by: Jiawen Wu <jiawenwu@trustnetic.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h8
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c4
2 files changed, 9 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 78c8062a8eb5f3..8ce6111cdda3e8 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -352,6 +352,14 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
dev->status &= ~STATUS_ACTIVE;
}
+static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev,
+ unsigned int intr_mask)
+{
+ unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask;
+
+ regmap_write(dev->map, DW_IC_INTR_MASK, val);
+}
+
void __i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index e879a0f5cc9771..835d82e2c5fecd 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -250,7 +250,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
/* Clear and enable interrupts */
regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
- regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
+ __i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK);
}
static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev)
@@ -300,7 +300,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
dev->msgs = msgs;
dev->msgs_num = num_msgs;
i2c_dw_xfer_init(dev);
- regmap_write(dev->map, DW_IC_INTR_MASK, 0);
/* Initiate messages read/write transaction */
for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) {
@@ -384,7 +383,6 @@ static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msg
dev->msgs = msgs;
dev->msgs_num = num_msgs;
i2c_dw_xfer_init(dev);
- regmap_write(dev->map, DW_IC_INTR_MASK, 0);
for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
buf = msgs[msg_idx].buf;