HID: intel-thc-hid: Add basic THC driver skeleton

Create intel-thc-hid folder and add Kconfig and Makefile for THC drivers.
Add basic THC device context structure, definitions and related
initialization APIs for THC Hardware layer driver. Also initialize
regmap struct for future THC registers access.

Co-developed-by: Even Xu <even.xu@intel.com>
Signed-off-by: Even Xu <even.xu@intel.com>
Signed-off-by: Xinpeng Sun <xinpeng.sun@intel.com>
Tested-by: Rui Zhang <rui1.zhang@intel.com>
Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Tested-by: Aaron Ma <aaron.ma@canonical.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
This commit is contained in:
Xinpeng Sun 2025-01-06 10:31:31 +08:00 committed by Jiri Kosina
parent df3a78d8a8
commit 1b2d05384c
7 changed files with 285 additions and 0 deletions

View File

@ -11873,6 +11873,12 @@ S: Maintained
F: arch/x86/include/asm/intel_telemetry.h
F: drivers/platform/x86/intel/telemetry/
INTEL TOUCH HOST CONTROLLER (THC) DRIVER
M: Even Xu <even.xu@intel.com>
M: Xinpeng Sun <xinpeng.sun@intel.com>
S: Maintained
F: drivers/hid/intel-thc-hid/
INTEL TPMI DRIVER
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
L: platform-driver-x86@vger.kernel.org

View File

@ -1386,4 +1386,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig"
source "drivers/hid/surface-hid/Kconfig"
source "drivers/hid/intel-thc-hid/Kconfig"
endif # HID_SUPPORT

View File

@ -171,3 +171,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/
obj-$(CONFIG_INTEL_THC_HID) += intel-thc-hid/

View File

@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2024, Intel Corporation.
menu "Intel THC HID Support"
depends on X86_64 && PCI
config INTEL_THC_HID
tristate "Intel Touch Host Controller"
select HID
help
THC (Touch Host Controller) is the name of the IP block in PCH that
interfaces with Touch Devices (ex: touchscreen, touchpad etc.). It
is comprised of 3 key functional blocks: A natively half-duplex
Quad I/O capable SPI master; a low latency I2C interface to support
HIDI2C compliant devices; a hardware sequencer with Read/Write DMA
capability to system memory.
Say Y/M here if you want to support Intel THC. If unsure, say N.
endmenu

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile - Intel Touch Host Controller (THC) drivers
# Copyright (c) 2024, Intel Corporation.
#
#
obj-$(CONFIG_INTEL_THC_HID) += intel-thc.o
intel-thc-objs += intel-thc/intel-thc-dev.o
ccflags-y += -I $(src)/intel-thc

View File

@ -0,0 +1,219 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */
#include <linux/regmap.h>
#include "intel-thc-dev.h"
static int thc_regmap_read(void *context, unsigned int reg,
unsigned int *val)
{
struct thc_device *thc_ctx = context;
void __iomem *base = thc_ctx->mmio_addr;
*val = ioread32(base + reg);
return 0;
}
static int thc_regmap_write(void *context, unsigned int reg,
unsigned int val)
{
struct thc_device *thc_ctx = context;
void __iomem *base = thc_ctx->mmio_addr;
iowrite32(val, base + reg);
return 0;
}
static const struct regmap_range thc_rw_ranges[] = {
regmap_reg_range(0x10, 0x14),
regmap_reg_range(0x1000, 0x1320),
};
static const struct regmap_access_table thc_rw_table = {
.yes_ranges = thc_rw_ranges,
.n_yes_ranges = ARRAY_SIZE(thc_rw_ranges),
};
static const struct regmap_config thc_regmap_cfg = {
.name = "thc_regmap_common",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x1320,
.reg_read = thc_regmap_read,
.reg_write = thc_regmap_write,
.cache_type = REGCACHE_NONE,
.fast_io = true,
.rd_table = &thc_rw_table,
.wr_table = &thc_rw_table,
.volatile_table = &thc_rw_table,
};
/**
* thc_clear_state - Clear THC hardware state
*
* @dev: The pointer of THC device structure
*/
static void thc_clear_state(const struct thc_device *dev)
{
u32 val;
/* Clear interrupt cause register */
val = THC_M_PRT_ERR_CAUSE_INVLD_DEV_ENTRY |
THC_M_PRT_ERR_CAUSE_FRAME_BABBLE_ERR |
THC_M_PRT_ERR_CAUSE_BUF_OVRRUN_ERR |
THC_M_PRT_ERR_CAUSE_PRD_ENTRY_ERR;
regmap_write_bits(dev->thc_regmap, THC_M_PRT_ERR_CAUSE_OFFSET, val, val);
/* Clear interrupt error state */
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_CNTRL_1_OFFSET,
THC_M_PRT_READ_DMA_CNTRL_IE_STALL,
THC_M_PRT_READ_DMA_CNTRL_IE_STALL);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_CNTRL_2_OFFSET,
THC_M_PRT_READ_DMA_CNTRL_IE_STALL,
THC_M_PRT_READ_DMA_CNTRL_IE_STALL);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
THC_M_PRT_INT_STATUS_TXN_ERR_INT_STS,
THC_M_PRT_INT_STATUS_TXN_ERR_INT_STS);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_INT_STATUS_OFFSET,
THC_M_PRT_INT_STATUS_FATAL_ERR_INT_STS,
THC_M_PRT_INT_STATUS_FATAL_ERR_INT_STS);
val = THC_M_PRT_INT_EN_TXN_ERR_INT_EN |
THC_M_PRT_INT_EN_FATAL_ERR_INT_EN |
THC_M_PRT_INT_EN_BUF_OVRRUN_ERR_INT_EN;
regmap_write_bits(dev->thc_regmap, THC_M_PRT_INT_EN_OFFSET, val, val);
val = THC_M_PRT_SW_SEQ_STS_THC_SS_ERR |
THC_M_PRT_SW_SEQ_STS_TSSDONE;
regmap_write_bits(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, val, val);
/* Clear RxDMA state */
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_CNTRL_1_OFFSET,
THC_M_PRT_READ_DMA_CNTRL_IE_EOF, 0);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_CNTRL_2_OFFSET,
THC_M_PRT_READ_DMA_CNTRL_IE_EOF, 0);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_INT_STS_1_OFFSET,
THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS,
THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_INT_STS_2_OFFSET,
THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS,
THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_INT_STS_1_OFFSET,
THC_M_PRT_READ_DMA_INT_STS_NONDMA_INT_STS,
THC_M_PRT_READ_DMA_INT_STS_NONDMA_INT_STS);
/* Clear TxDMA state */
regmap_write_bits(dev->thc_regmap, THC_M_PRT_WRITE_DMA_CNTRL_OFFSET,
THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_IE_IOC_DMACPL,
THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_IE_IOC_DMACPL);
val = THC_M_PRT_WRITE_INT_STS_THC_WRDMA_ERROR_STS |
THC_M_PRT_WRITE_INT_STS_THC_WRDMA_IOC_STS |
THC_M_PRT_WRITE_INT_STS_THC_WRDMA_CMPL_STATUS;
regmap_write_bits(dev->thc_regmap, THC_M_PRT_WRITE_INT_STS_OFFSET, val, val);
/* Reset all DMAs count */
regmap_write_bits(dev->thc_regmap, THC_M_PRT_DB_CNT_1_OFFSET,
THC_M_PRT_DB_CNT_1_THC_M_PRT_DB_CNT_RST,
THC_M_PRT_DB_CNT_1_THC_M_PRT_DB_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_DEVINT_CNT_OFFSET,
THC_M_PRT_DEVINT_CNT_THC_M_PRT_DEVINT_CNT_RST,
THC_M_PRT_DEVINT_CNT_THC_M_PRT_DEVINT_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_READ_DMA_CNTRL_1_OFFSET,
THC_M_PRT_READ_DMA_CNTRL_TPCPR,
THC_M_PRT_READ_DMA_CNTRL_TPCPR);
/* Reset THC hardware sequence state */
regmap_write_bits(dev->thc_regmap, THC_M_PRT_FRAME_DROP_CNT_1_OFFSET,
THC_M_PRT_FRAME_DROP_CNT_1_RFDC,
THC_M_PRT_FRAME_DROP_CNT_1_RFDC);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_FRAME_DROP_CNT_2_OFFSET,
THC_M_PRT_FRAME_DROP_CNT_2_RFDC,
THC_M_PRT_FRAME_DROP_CNT_2_RFDC);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_FRM_CNT_1_OFFSET,
THC_M_PRT_FRM_CNT_1_THC_M_PRT_FRM_CNT_RST,
THC_M_PRT_FRM_CNT_1_THC_M_PRT_FRM_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_FRM_CNT_2_OFFSET,
THC_M_PRT_FRM_CNT_2_THC_M_PRT_FRM_CNT_RST,
THC_M_PRT_FRM_CNT_2_THC_M_PRT_FRM_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_RXDMA_PKT_CNT_1_OFFSET,
THC_M_PRT_RXDMA_PKT_CNT_1_THC_M_PRT_RXDMA_PKT_CNT_RST,
THC_M_PRT_RXDMA_PKT_CNT_1_THC_M_PRT_RXDMA_PKT_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_RXDMA_PKT_CNT_2_OFFSET,
THC_M_PRT_RXDMA_PKT_CNT_2_THC_M_PRT_RXDMA_PKT_CNT_RST,
THC_M_PRT_RXDMA_PKT_CNT_2_THC_M_PRT_RXDMA_PKT_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_SWINT_CNT_1_OFFSET,
THC_M_PRT_SWINT_CNT_1_THC_M_PRT_SWINT_CNT_RST,
THC_M_PRT_SWINT_CNT_1_THC_M_PRT_SWINT_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_SWINT_CNT_1_OFFSET,
THC_M_PRT_SWINT_CNT_1_THC_M_PRT_SWINT_CNT_RST,
THC_M_PRT_SWINT_CNT_1_THC_M_PRT_SWINT_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_TX_FRM_CNT_OFFSET,
THC_M_PRT_TX_FRM_CNT_THC_M_PRT_TX_FRM_CNT_RST,
THC_M_PRT_TX_FRM_CNT_THC_M_PRT_TX_FRM_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_TXDMA_PKT_CNT_OFFSET,
THC_M_PRT_TXDMA_PKT_CNT_THC_M_PRT_TXDMA_PKT_CNT_RST,
THC_M_PRT_TXDMA_PKT_CNT_THC_M_PRT_TXDMA_PKT_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_UFRM_CNT_1_OFFSET,
THC_M_PRT_UFRM_CNT_1_THC_M_PRT_UFRM_CNT_RST,
THC_M_PRT_UFRM_CNT_1_THC_M_PRT_UFRM_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_UFRM_CNT_2_OFFSET,
THC_M_PRT_UFRM_CNT_2_THC_M_PRT_UFRM_CNT_RST,
THC_M_PRT_UFRM_CNT_2_THC_M_PRT_UFRM_CNT_RST);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_PRD_EMPTY_CNT_1_OFFSET,
THC_M_PRT_PRD_EMPTY_CNT_1_RPTEC,
THC_M_PRT_PRD_EMPTY_CNT_1_RPTEC);
regmap_write_bits(dev->thc_regmap, THC_M_PRT_PRD_EMPTY_CNT_2_OFFSET,
THC_M_PRT_PRD_EMPTY_CNT_2_RPTEC,
THC_M_PRT_PRD_EMPTY_CNT_2_RPTEC);
}
/**
* thc_dev_init - Allocate and initialize the THC device structure
*
* @device: The pointer of device structure
* @mem_addr: The pointer of MMIO memory address
*
* Return: The thc_device pointer on success, NULL on failed.
*/
struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr)
{
struct thc_device *thc_dev;
int ret;
thc_dev = devm_kzalloc(device, sizeof(*thc_dev), GFP_KERNEL);
if (!thc_dev)
return ERR_PTR(-ENOMEM);
thc_dev->dev = device;
thc_dev->mmio_addr = mem_addr;
thc_dev->thc_regmap = devm_regmap_init(device, NULL, thc_dev, &thc_regmap_cfg);
if (IS_ERR(thc_dev->thc_regmap)) {
ret = PTR_ERR(thc_dev->thc_regmap);
dev_err_once(device, "Failed to init thc_regmap: %d\n", ret);
return ERR_PTR(ret);
}
thc_clear_state(thc_dev);
return thc_dev;
}
EXPORT_SYMBOL_NS_GPL(thc_dev_init, "INTEL_THC");
MODULE_AUTHOR("Xinpeng Sun <xinpeng.sun@intel.com>");
MODULE_AUTHOR("Even Xu <even.xu@intel.com>");
MODULE_DESCRIPTION("Intel(R) Intel THC Hardware Driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */
#ifndef _INTEL_THC_DEV_H_
#define _INTEL_THC_DEV_H_
#include <linux/cdev.h>
#define THC_REGMAP_COMMON_OFFSET 0x10
#define THC_REGMAP_MMIO_OFFSET 0x1000
/**
* struct thc_device - THC private device struct
* @thc_regmap: MMIO regmap structure for accessing THC registers
* @mmio_addr: MMIO registers address
*/
struct thc_device {
struct device *dev;
struct regmap *thc_regmap;
void __iomem *mmio_addr;
};
struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr);
#endif /* _INTEL_THC_DEV_H_ */