Skip to content

Commit 22da60f

Browse files
EvenxfJiri Kosina
authored andcommitted
HID: Intel-thc-hid: Intel-thc: Introduce interrupt delay control
This patch adds support for a new feature, named "Interrupt Delay", allowing driver to set a specific delay time for next interrupt detection. It gives driver a capability to control THC waiting time for the next interrupt, to reduce the likelihood of spurious readings. APIs added: - thc_i2c_set_rx_int_delay(): Set I2C Rx input interrupt delay value - thc_i2c_rx_int_delay_enable(): Enable or disable I2C Rx interrupt delay As this interrupt delay feature is only applicable to RxDMA and must remain disabled during SWDMA operations, it also involves a change in SWDMA code to record the max input size control feature state before SWDMA and restore the state after SWDMA. Signed-off-by: Even Xu <[email protected]> Tested-by: Chong Han <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 45e92a0 commit 22da60f

File tree

6 files changed

+113
-0
lines changed

6 files changed

+113
-0
lines changed

Documentation/hid/intel-thc-hid.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,19 @@ input packet size with the given max size:
202202
This feature is used to avoid data corruption which will cause RxDMA buffer overrun issue for
203203
I2C bus, and enhance whole system stability.
204204

205+
2.4 Interrupt delay
206+
-------------------
207+
208+
Because of MCU performance limitation, some touch devices cannot de-assert interrupt pin
209+
immediately after input data is transferred, which cause an interrupt toggle delay. But THC
210+
always detects next interrupt immediately after last input interrupt is handled. In this
211+
case, the delayed interrupt de-assertion will be recognized as a new interrupt signal by THC,
212+
and causes THC to start an input report reading spuriously.
213+
214+
In order to avoid this situation, THC introduced interrupt delay new feature in Panther Lake
215+
platform, where THC allows driver to set an interrupt delay. After this feature is enabled,
216+
THC will delay this given time for next interrupt detection.
217+
205218
3. High level concept
206219
=====================
207220

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Copyright (c) 2024 Intel Corporation */
33

44
#include <linux/bitfield.h>
5+
#include <linux/math.h>
56
#include <linux/regmap.h>
67

78
#include "intel-thc-dev.h"
@@ -1640,6 +1641,76 @@ int thc_i2c_rx_max_size_enable(struct thc_device *dev, bool enable)
16401641
}
16411642
EXPORT_SYMBOL_NS_GPL(thc_i2c_rx_max_size_enable, "INTEL_THC");
16421643

1644+
/**
1645+
* thc_i2c_set_rx_int_delay - Set I2C Rx input interrupt delay value
1646+
* @dev: The pointer of THC private device context
1647+
* @delay_us: Interrupt delay value, unit is us
1648+
*
1649+
* Set @delay_us for I2C RxDMA input interrupt delay feature.
1650+
*
1651+
* Return: 0 on success, other error codes on failure.
1652+
*/
1653+
int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us)
1654+
{
1655+
u32 val;
1656+
int ret;
1657+
1658+
if (!dev)
1659+
return -EINVAL;
1660+
1661+
if (!delay_us)
1662+
return -EOPNOTSUPP;
1663+
1664+
ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val);
1665+
if (ret)
1666+
return ret;
1667+
1668+
/* THC hardware counts at 10us unit */
1669+
val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL, DIV_ROUND_UP(delay_us, 10));
1670+
1671+
ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val);
1672+
if (ret)
1673+
return ret;
1674+
1675+
dev->i2c_int_delay_us = delay_us;
1676+
1677+
return 0;
1678+
}
1679+
EXPORT_SYMBOL_NS_GPL(thc_i2c_set_rx_int_delay, "INTEL_THC");
1680+
1681+
/**
1682+
* thc_i2c_rx_int_delay_enable - Enable I2C Rx interrupt delay
1683+
* @dev: The pointer of THC private device context
1684+
* @enable: Enable interrupt delay or not
1685+
*
1686+
* Enable or disable I2C RxDMA input interrupt delay feature.
1687+
* Input interrupt delay can only be enabled after interrupt delay value
1688+
* was set by thc_i2c_set_rx_int_delay().
1689+
*
1690+
* Return: 0 on success, other error codes on failure.
1691+
*/
1692+
int thc_i2c_rx_int_delay_enable(struct thc_device *dev, bool enable)
1693+
{
1694+
u32 mask = THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL_EN;
1695+
u32 val = enable ? mask : 0;
1696+
int ret;
1697+
1698+
if (!dev)
1699+
return -EINVAL;
1700+
1701+
if (!dev->i2c_int_delay_us)
1702+
return -EOPNOTSUPP;
1703+
1704+
ret = regmap_write_bits(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, mask, val);
1705+
if (ret)
1706+
return ret;
1707+
1708+
dev->i2c_int_delay_en = enable;
1709+
1710+
return 0;
1711+
}
1712+
EXPORT_SYMBOL_NS_GPL(thc_i2c_rx_int_delay_enable, "INTEL_THC");
1713+
16431714
MODULE_AUTHOR("Xinpeng Sun <[email protected]>");
16441715
MODULE_AUTHOR("Even Xu <[email protected]>");
16451716

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ enum thc_int_type {
6363
* @perf_limit: The delay between read operation and write operation
6464
* @i2c_subip_regs: The copy of THC I2C sub-system registers for resuming restore
6565
* @i2c_max_rx_size: I2C Rx transfer max input size
66+
* @i2c_int_delay_us: I2C input interrupt delay, unit is us
6667
* @i2c_max_rx_size_en: Bool value that indicates I2C max input size control enabled or not
68+
* @i2c_int_delay_en: Bool value that indicates I2C input interrupt delay enabled or not
6769
*/
6870
struct thc_device {
6971
struct device *dev;
@@ -85,7 +87,9 @@ struct thc_device {
8587
u32 *i2c_subip_regs;
8688

8789
u32 i2c_max_rx_size;
90+
u32 i2c_int_delay_us;
8891
bool i2c_max_rx_size_en;
92+
bool i2c_int_delay_en;
8993
};
9094

9195
struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr);
@@ -119,5 +123,7 @@ int thc_i2c_subip_regs_save(struct thc_device *dev);
119123
int thc_i2c_subip_regs_restore(struct thc_device *dev);
120124
int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size);
121125
int thc_i2c_rx_max_size_enable(struct thc_device *dev, bool enable);
126+
int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us);
127+
int thc_i2c_rx_int_delay_enable(struct thc_device *dev, bool enable);
122128

123129
#endif /* _INTEL_THC_DEV_H_ */

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,15 @@ static int thc_swdma_read_start(struct thc_device *dev, void *write_buff,
725725
dev->dma_ctx->rx_max_size_en = true;
726726
}
727727

728+
/*
729+
* Interrupt delay feature is in the same situation with max input size control feature,
730+
* needs record feature state before SWDMA.
731+
*/
732+
if (dev->i2c_int_delay_en) {
733+
thc_i2c_rx_int_delay_enable(dev, false);
734+
dev->dma_ctx->rx_int_delay_en = true;
735+
}
736+
728737
mask = THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC |
729738
THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_RX_DLEN_EN;
730739
val = FIELD_PREP(THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC, write_len) |
@@ -776,6 +785,15 @@ static int thc_swdma_read_completion(struct thc_device *dev)
776785
dev->dma_ctx->rx_max_size_en = false;
777786
}
778787

788+
/*
789+
* Restore input interrupt delay feature to previous state after SWDMA if it was
790+
* enabled before SWDMA, and reset temp rx_int_delay_en variable for next time.
791+
*/
792+
if (dev->dma_ctx->rx_int_delay_en) {
793+
thc_i2c_rx_int_delay_enable(dev, true);
794+
dev->dma_ctx->rx_int_delay_en = false;
795+
}
796+
779797
thc_reset_dma_settings(dev);
780798

781799
dma_set_start_bit(dev, &dev->dma_ctx->dma_config[THC_RXDMA2]);

drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,15 @@ struct thc_dma_configuration {
123123
* @use_write_interrupts: Indicate TxDMA using interrupt or polling
124124
* @rx_max_size_en: Temp flag to indicate THC I2C Rx max input size control feature
125125
* enabled or not, only be used during SWDMA operation.
126+
* @rx_int_delay_en: Temp flag to indicate THC I2C Rx interrupt delay feature
127+
* enabled or not, only be used during SWDMA operation.
126128
*/
127129
struct thc_dma_context {
128130
struct thc_dma_configuration dma_config[MAX_THC_DMA_CHANNEL];
129131
u8 use_write_interrupts;
130132

131133
bool rx_max_size_en;
134+
bool rx_int_delay_en;
132135
};
133136

134137
struct thc_device;

drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@
400400
#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO GENMASK(15, 8)
401401

402402
#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE GENMASK(15, 0)
403+
#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL GENMASK(23, 16)
404+
#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL_EN BIT(30)
403405
#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE_EN BIT(31)
404406

405407
#define THC_M_PRT_INT_EN_SIPE BIT(0)

0 commit comments

Comments
 (0)