Skip to content

Commit 4e682ea

Browse files
sunxinpengJiri Kosina
authored andcommitted
HID: intel-thc-hid: intel-thc: Add THC interrupt handler
Add common interrupt handler to clear interrupt status and return interrupt type to caller for future handling. Co-developed-by: Even Xu <[email protected]> Signed-off-by: Even Xu <[email protected]> Signed-off-by: Xinpeng Sun <[email protected]> Tested-by: Rui Zhang <[email protected]> Tested-by: Mark Pearson <[email protected]> Reviewed-by: Srinivas Pandruvada <[email protected]> Reviewed-by: Mark Pearson <[email protected]> Tested-by: Aaron Ma <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent e86df90 commit 4e682ea

File tree

2 files changed

+286
-0
lines changed

2 files changed

+286
-0
lines changed

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

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,265 @@ void thc_ltr_unconfig(struct thc_device *dev)
802802
}
803803
EXPORT_SYMBOL_NS_GPL(thc_ltr_unconfig, "INTEL_THC");
804804

805+
/**
806+
* thc_int_cause_read - Read interrupt cause register value
807+
*
808+
* @dev: The pointer of THC private device context
809+
*
810+
* Return: The interrupt cause register value
811+
*/
812+
u32 thc_int_cause_read(struct thc_device *dev)
813+
{
814+
u32 int_cause;
815+
816+
regmap_read(dev->thc_regmap,
817+
THC_M_PRT_DEV_INT_CAUSE_REG_VAL_OFFSET, &int_cause);
818+
819+
return int_cause;
820+
}
821+
EXPORT_SYMBOL_NS_GPL(thc_int_cause_read, "INTEL_THC");
822+
823+
static void thc_print_txn_error_cause(const struct thc_device *dev)
824+
{
825+
bool known_error = false;
826+
u32 cause = 0;
827+
828+
regmap_read(dev->thc_regmap, THC_M_PRT_ERR_CAUSE_OFFSET, &cause);
829+
830+
if (cause & THC_M_PRT_ERR_CAUSE_PRD_ENTRY_ERR) {
831+
dev_err(dev->dev, "TXN Error: Invalid PRD Entry\n");
832+
known_error = true;
833+
}
834+
if (cause & THC_M_PRT_ERR_CAUSE_BUF_OVRRUN_ERR) {
835+
dev_err(dev->dev, "TXN Error: THC Buffer Overrun\n");
836+
known_error = true;
837+
}
838+
if (cause & THC_M_PRT_ERR_CAUSE_FRAME_BABBLE_ERR) {
839+
dev_err(dev->dev, "TXN Error: Frame Babble\n");
840+
known_error = true;
841+
}
842+
if (cause & THC_M_PRT_ERR_CAUSE_INVLD_DEV_ENTRY) {
843+
dev_err(dev->dev, "TXN Error: Invalid Device Register Setting\n");
844+
known_error = true;
845+
}
846+
847+
/* Clear interrupt status bits */
848+
regmap_write(dev->thc_regmap, THC_M_PRT_ERR_CAUSE_OFFSET, cause);
849+
850+
if (!known_error)
851+
dev_err(dev->dev, "TXN Error does not match any known value: 0x%X\n",
852+
cause);
853+
}
854+
855+
/**
856+
* thc_interrupt_handler - Handle THC interrupts
857+
*
858+
* THC interrupts include several types: external touch device (TIC) non-DMA
859+
* interrupts, PIO completion interrupts, DMA interrtups, I2C subIP raw
860+
* interrupts and error interrupts.
861+
*
862+
* This is a help function for interrupt processing, it detects interrupt
863+
* type, clear the interrupt status bit and return the interrupt type to caller
864+
* for future processing.
865+
*
866+
* @dev: The pointer of THC private device context
867+
*
868+
* Return: The combined flag for interrupt type
869+
*/
870+
int thc_interrupt_handler(struct thc_device *dev)
871+
{
872+
u32 read_sts_1, read_sts_2, read_sts_sw, write_sts;
873+
u32 int_sts, err_cause, seq_cntrl, seq_sts;
874+
int interrupt_type = 0;
875+
876+
regmap_read(dev->thc_regmap,
877+
THC_M_PRT_READ_DMA_INT_STS_1_OFFSET, &read_sts_1);
878+
879+
if (read_sts_1 & THC_M_PRT_READ_DMA_INT_STS_NONDMA_INT_STS) {
880+
dev_dbg(dev->dev, "THC non-DMA device interrupt\n");
881+
882+
regmap_write(dev->thc_regmap, THC_M_PRT_READ_DMA_INT_STS_1_OFFSET,
883+
NONDMA_INT_STS_BIT);
884+
885+
interrupt_type |= BIT(THC_NONDMA_INT);
886+
887+
return interrupt_type;
888+
}
889+
890+
regmap_read(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET, &int_sts);
891+
892+
if (int_sts & THC_M_PRT_INT_STATUS_TXN_ERR_INT_STS) {
893+
dev_err(dev->dev, "THC transaction error, int_sts: 0x%08X\n", int_sts);
894+
thc_print_txn_error_cause(dev);
895+
896+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
897+
TXN_ERR_INT_STS_BIT);
898+
899+
interrupt_type |= BIT(THC_TXN_ERR_INT);
900+
901+
return interrupt_type;
902+
}
903+
904+
regmap_read(dev->thc_regmap, THC_M_PRT_ERR_CAUSE_OFFSET, &err_cause);
905+
regmap_read(dev->thc_regmap,
906+
THC_M_PRT_READ_DMA_INT_STS_2_OFFSET, &read_sts_2);
907+
908+
if (err_cause & THC_M_PRT_ERR_CAUSE_BUF_OVRRUN_ERR ||
909+
read_sts_1 & THC_M_PRT_READ_DMA_INT_STS_STALL_STS ||
910+
read_sts_2 & THC_M_PRT_READ_DMA_INT_STS_STALL_STS) {
911+
dev_err(dev->dev, "Buffer overrun or RxDMA engine stalled!\n");
912+
thc_print_txn_error_cause(dev);
913+
914+
regmap_write(dev->thc_regmap, THC_M_PRT_READ_DMA_INT_STS_2_OFFSET,
915+
THC_M_PRT_READ_DMA_INT_STS_STALL_STS);
916+
regmap_write(dev->thc_regmap, THC_M_PRT_READ_DMA_INT_STS_1_OFFSET,
917+
THC_M_PRT_READ_DMA_INT_STS_STALL_STS);
918+
regmap_write(dev->thc_regmap, THC_M_PRT_ERR_CAUSE_OFFSET,
919+
THC_M_PRT_ERR_CAUSE_BUF_OVRRUN_ERR);
920+
921+
interrupt_type |= BIT(THC_TXN_ERR_INT);
922+
923+
return interrupt_type;
924+
}
925+
926+
if (int_sts & THC_M_PRT_INT_STATUS_FATAL_ERR_INT_STS) {
927+
dev_err_once(dev->dev, "THC FATAL error, int_sts: 0x%08X\n", int_sts);
928+
929+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
930+
TXN_FATAL_INT_STS_BIT);
931+
932+
interrupt_type |= BIT(THC_FATAL_ERR_INT);
933+
934+
return interrupt_type;
935+
}
936+
937+
regmap_read(dev->thc_regmap,
938+
THC_M_PRT_SW_SEQ_CNTRL_OFFSET, &seq_cntrl);
939+
regmap_read(dev->thc_regmap,
940+
THC_M_PRT_SW_SEQ_STS_OFFSET, &seq_sts);
941+
942+
if (seq_cntrl & THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CD_IE &&
943+
seq_sts & THC_M_PRT_SW_SEQ_STS_TSSDONE) {
944+
dev_dbg(dev->dev, "THC_SS_CD_IE and TSSDONE are set\n");
945+
interrupt_type |= BIT(THC_PIO_DONE_INT);
946+
}
947+
948+
if (read_sts_1 & THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS) {
949+
dev_dbg(dev->dev, "Got RxDMA1 Read Interrupt\n");
950+
951+
regmap_write(dev->thc_regmap,
952+
THC_M_PRT_READ_DMA_INT_STS_1_OFFSET, read_sts_1);
953+
954+
interrupt_type |= BIT(THC_RXDMA1_INT);
955+
}
956+
957+
if (read_sts_2 & THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS) {
958+
dev_dbg(dev->dev, "Got RxDMA2 Read Interrupt\n");
959+
960+
regmap_write(dev->thc_regmap,
961+
THC_M_PRT_READ_DMA_INT_STS_2_OFFSET, read_sts_2);
962+
963+
interrupt_type |= BIT(THC_RXDMA2_INT);
964+
}
965+
966+
regmap_read(dev->thc_regmap,
967+
THC_M_PRT_READ_DMA_INT_STS_SW_OFFSET, &read_sts_sw);
968+
969+
if (read_sts_sw & THC_M_PRT_READ_DMA_INT_STS_DMACPL_STS) {
970+
dev_dbg(dev->dev, "Got SwDMA Read Interrupt\n");
971+
972+
regmap_write(dev->thc_regmap,
973+
THC_M_PRT_READ_DMA_INT_STS_SW_OFFSET, read_sts_sw);
974+
975+
dev->swdma_done = true;
976+
wake_up_interruptible(&dev->swdma_complete_wait);
977+
978+
interrupt_type |= BIT(THC_SWDMA_INT);
979+
}
980+
981+
regmap_read(dev->thc_regmap,
982+
THC_M_PRT_WRITE_INT_STS_OFFSET, &write_sts);
983+
984+
if (write_sts & THC_M_PRT_WRITE_INT_STS_THC_WRDMA_CMPL_STATUS) {
985+
dev_dbg(dev->dev, "Got TxDMA Write complete Interrupt\n");
986+
987+
regmap_write(dev->thc_regmap,
988+
THC_M_PRT_WRITE_INT_STS_OFFSET, write_sts);
989+
990+
dev->write_done = true;
991+
wake_up_interruptible(&dev->write_complete_wait);
992+
993+
interrupt_type |= BIT(THC_TXDMA_INT);
994+
}
995+
996+
if (int_sts & THC_M_PRT_INT_STATUS_DEV_RAW_INT_STS) {
997+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
998+
THC_M_PRT_INT_STATUS_DEV_RAW_INT_STS);
999+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1000+
}
1001+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_UNDER_INT_STS) {
1002+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1003+
THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_UNDER_INT_STS);
1004+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1005+
}
1006+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_OVER_INT_STS) {
1007+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1008+
THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_OVER_INT_STS);
1009+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1010+
}
1011+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_FULL_INT_STS) {
1012+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1013+
THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_FULL_INT_STS);
1014+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1015+
}
1016+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_OVER_INT_STS) {
1017+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1018+
THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_OVER_INT_STS);
1019+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1020+
}
1021+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_EMPTY_INT_STS) {
1022+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1023+
THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_EMPTY_INT_STS);
1024+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1025+
}
1026+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_ABRT_INT_STS) {
1027+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1028+
THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_ABRT_INT_STS);
1029+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1030+
}
1031+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_ACTIVITY_INT_STS) {
1032+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1033+
THC_M_PRT_INT_STATUS_THC_I2C_IC_ACTIVITY_INT_STS);
1034+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1035+
}
1036+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_SCL_STUCK_AT_LOW_INT_STS) {
1037+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1038+
THC_M_PRT_INT_STATUS_THC_I2C_IC_SCL_STUCK_AT_LOW_INT_STS);
1039+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1040+
}
1041+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_STOP_DET_INT_STS) {
1042+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1043+
THC_M_PRT_INT_STATUS_THC_I2C_IC_STOP_DET_INT_STS);
1044+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1045+
}
1046+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_START_DET_INT_STS) {
1047+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1048+
THC_M_PRT_INT_STATUS_THC_I2C_IC_START_DET_INT_STS);
1049+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1050+
}
1051+
if (int_sts & THC_M_PRT_INT_STATUS_THC_I2C_IC_MST_ON_HOLD_INT_STS) {
1052+
regmap_write(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
1053+
THC_M_PRT_INT_STATUS_THC_I2C_IC_MST_ON_HOLD_INT_STS);
1054+
interrupt_type |= BIT(THC_I2CSUBIP_INT);
1055+
}
1056+
1057+
if (!interrupt_type)
1058+
interrupt_type |= BIT(THC_UNKNOWN_INT);
1059+
1060+
return interrupt_type;
1061+
}
1062+
EXPORT_SYMBOL_NS_GPL(thc_interrupt_handler, "INTEL_THC");
1063+
8051064
MODULE_AUTHOR("Xinpeng Sun <[email protected]>");
8061065
MODULE_AUTHOR("Even Xu <[email protected]>");
8071066

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,31 @@ enum thc_port_type {
2323
THC_PORT_TYPE_I2C = 1,
2424
};
2525

26+
/**
27+
* THC interrupt flag
28+
* @THC_NONDMA_INT: THC non-DMA interrupt
29+
* @THC_RXDMA1_INT: THC RxDMA1 interrupt
30+
* @THC_RXDMA2_INT: THC RxDMA2 interrupt
31+
* @THC_SWDMA_INT: THC SWDMA interrupt
32+
* @THC_TXDMA_INT: THC TXDMA interrupt
33+
* @THC_PIO_DONE_INT: THC PIO complete interrupt
34+
* @THC_I2CSUBIP_INT: THC I2C subsystem interrupt
35+
* @THC_TXN_ERR_INT: THC transfer error interrupt
36+
* @THC_FATAL_ERR_INT: THC fatal error interrupt
37+
*/
38+
enum thc_int_type {
39+
THC_NONDMA_INT = 0,
40+
THC_RXDMA1_INT = 1,
41+
THC_RXDMA2_INT = 2,
42+
THC_SWDMA_INT = 3,
43+
THC_TXDMA_INT = 4,
44+
THC_PIO_DONE_INT = 5,
45+
THC_I2CSUBIP_INT = 6,
46+
THC_TXN_ERR_INT = 7,
47+
THC_FATAL_ERR_INT = 8,
48+
THC_UNKNOWN_INT
49+
};
50+
2651
/**
2752
* struct thc_device - THC private device struct
2853
* @thc_regmap: MMIO regmap structure for accessing THC registers
@@ -71,5 +96,7 @@ int thc_interrupt_quiesce(const struct thc_device *dev, bool int_quiesce);
7196
void thc_ltr_config(struct thc_device *dev, u32 active_ltr_us, u32 lp_ltr_us);
7297
void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode);
7398
void thc_ltr_unconfig(struct thc_device *dev);
99+
u32 thc_int_cause_read(struct thc_device *dev);
100+
int thc_interrupt_handler(struct thc_device *dev);
74101

75102
#endif /* _INTEL_THC_DEV_H_ */

0 commit comments

Comments
 (0)