From patchwork Mon Dec 16 01:41:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851908 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D1B6017C8D; Mon, 16 Dec 2024 01:41:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313312; cv=none; b=I2/cCfsF8TeS6ZyTViWByQpkKfyUwP6JRLs8nToD0heYsqO6wxeBwFd2A6RxvU2pAq71mEODC3RauRk4vY2Mg/nX6PwgZsAeNgAWuqkTxx44l7FR2snm07QYsd8SW86mmIzRESFxwYDP7mHEgrvEN1CBkH3JG1CDmWJNwzGQ+zI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313312; c=relaxed/simple; bh=W6S0CE9R+juo3kVYYxcwk0CVdSjNL5d2C6DgEaF99rA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=Rn1BHPfPXIj0nxLAQ87ffB+R6vPU49od09mFMQpZ80iByPxVqqF7iLqvChAn4UnFrfBovyY4GG//XKCTN5FHyCMjlkX5CHzlJEAs6U51XIKs3hwg4QKu433X8UUPq0xNOVl7KEoZhrxBSXvxH0dEobd/evpzK4rWOCYJeSjLJ4M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=CY23ZPPL; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="CY23ZPPL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313310; x=1765849310; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=W6S0CE9R+juo3kVYYxcwk0CVdSjNL5d2C6DgEaF99rA=; b=CY23ZPPLdzfgKX8RS+7RrUtN5/+pJTGKWAqfP0uF+M/K5JFy6Mmg605/ +3KXaXFKFM+HS/tHnNKHI6bXmk3sAbasFqAXbgrRmdSkbvOQzCKQW1QL3 k+jdFjUgxK1DuUvOZ9tN/JmmH+rFstYgSz4fLPDxcM52UovnxJ8Yv9+Ss FEjVEbiNm+Kctn7Yq0JS1JUSEF8V9ni80TQNwGVL8yxzMx5Uvlp7csQYy 2xxEsR7b4yFh1XxTmt7LR+JHN8l6Txjd6RARtx+rW3bI4VC9/MbLLPfCD Dyto5wfWmT5tMFSHPNtp/8cizHzB4YyphPjbaYWP3RKLDjtMdgUPBu0O0 Q==; X-CSE-ConnectionGUID: Dx8UVu6QS/6Sx59Y/rQp6A== X-CSE-MsgGUID: +0CVdgyVTfeaT9f1oY10jA== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34012941" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34012941" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:41:49 -0800 X-CSE-ConnectionGUID: YS1C4jK4QcaNpOaVN1NHDg== X-CSE-MsgGUID: LS1lrGDaQjailPyPW3bdUw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084149" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:41:46 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Even Xu , Sun Xinpeng , Srinivas Pandruvada Subject: [PATCH v3 01/22] HID: THC: Add documentation Date: Mon, 16 Dec 2024 09:41:06 +0800 Message-Id: <20241216014127.3722172-2-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add Documentation/hid/intel-thc-hid.rst file to provide hardware and software detail for intel THC drivers. Co-developed-by: Sun Xinpeng Signed-off-by: Sun Xinpeng Signed-off-by: Even Xu Reviewed-by: Srinivas Pandruvada --- Documentation/hid/index.rst | 1 + Documentation/hid/intel-thc-hid.rst | 568 ++++++++++++++++++++++++++++ 2 files changed, 569 insertions(+) create mode 100644 Documentation/hid/intel-thc-hid.rst diff --git a/Documentation/hid/index.rst b/Documentation/hid/index.rst index af02cf7cfa82..baf156b44b58 100644 --- a/Documentation/hid/index.rst +++ b/Documentation/hid/index.rst @@ -18,4 +18,5 @@ Human Interface Devices (HID) hid-alps intel-ish-hid + intel-thc-hid amd-sfh-hid diff --git a/Documentation/hid/intel-thc-hid.rst b/Documentation/hid/intel-thc-hid.rst new file mode 100644 index 000000000000..e9452c11d8de --- /dev/null +++ b/Documentation/hid/intel-thc-hid.rst @@ -0,0 +1,568 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================= +Intel Touch Host Controller (THC) +================================= + +Touch Host Controller is the name of the IP block in PCH that interface 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 +- Low latency I2C interface to support HIDI2C compliant devices +- A HW sequencer with RW DMA capability to system memory + +It has a single root space IOSF Primary interface that supports transactions to/from touch devices. +Host driver configures and controls the touch devices over THC interface. THC provides high +bandwidth DMA services to the touch driver and transfers the HID report to host system main memory. + +Hardware sequencer within the THC is responsible for transferring (via DMA) data from touch devices +into system memory. A ring buffer is used to avoid data loss due to asynchronous nature of data +consumption (by host) in relation to data production (by touch device via DMA). + +Unlike other common SPI/I2C controllers, THC handles the HID device data interrupt and reset +signals directly. + +1. Overview +=========== + +1.1 THC software/hardware stack +------------------------------- + +Below diagram illustrates the high-level architecture of THC software/hardware stack, which is fully +capable of supporting HIDSPI/HIDI2C protocol in Linux OS. + +:: + + ---------------------------------------------- + | +-----------------------------------+ | + | | Input Device | | + | +-----------------------------------+ | + | +-----------------------------------+ | + | | HID Multi-touch Driver | | + | +-----------------------------------+ | + | +-----------------------------------+ | + | | HID Core | | + | +-----------------------------------+ | + | +-----------------------------------+ | + | | THC QuickSPI/QuickI2C Driver | | + | +-----------------------------------+ | + | +-----------------------------------+ | + | | THC Hardware Driver | | + | +-----------------------------------+ | + | +----------------+ +----------------+ | + | SW | PCI Bus Driver | | ACPI Resource | | + | +----------------+ +----------------+ | + ---------------------------------------------- + ---------------------------------------------- + | +-----------------------------------+ | + | HW | PCI Bus | | + | +-----------------------------------+ | + | +-----------------------------------+ | + | | THC Controller | | + | +-----------------------------------+ | + | +-----------------------------------+ | + | | Touch IC | | + | +-----------------------------------+ | + ---------------------------------------------- + +Touch IC (TIC), also as known as the Touch devices (touchscreen or touchpad). The discrete analog +components that sense and transfer either discrete touch data or heatmap data in the form of HID +reports over the SPI/I2C bus to the THC Controller on the host. + +THC Host Controller, which is a PCI device HBA (host bus adapter), integrated into the PCH, that +serves as a bridge between the Touch ICs and the host. + +THC Hardware Driver, provides THC hardware operation APIs for above QuickSPI/QuickI2C driver, it +accesses THC MMIO registers to configure and control THC hardware. + +THC QuickSPI/QuickI2C driver, also as known as HIDSPI/HIDI2C driver, is registered as a HID +low-level driver that manages the THC Controller and implements HIDSPI/HIDI2C protocol. + + +1.2 THC hardware diagram +------------------------ +Below diagram shows THC hardware components:: + + --------------------------------- + | THC Controller | + | +---------------------------+ | + | | PCI Config Space | | + | +---------------------------+ | + | +---------------------------+ | + | + MMIO Registers | | + | +---------------------------+ | + +---------------+ | +------------+ +------------+ | + | System Memory +---+--+ DMA | | PIO | | + +---------------+ | +------------+ +------------+ | + | +---------------------------+ | + | | HW Sequencer | | + | +---------------------------+ | + | +------------+ +------------+ | + | | SPI/I2C | | GPIO | | + | | Controller | | Controller | | + | +------------+ +------------+ | + --------------------------------- + +As THC is exposed as a PCI devices, so it has standard PCI config space registers for PCI +enumeration and configuration. + +MMIO Registers, which provide registers access for driver to configure and control THC hardware, +the registers include several categories: Interrupt status and control, DMA configure, +PIO (Programmed I/O, defined in section 3.2) status and control, SPI bus configure, I2C subIP +status and control, reset status and control... + +THC provides two ways for driver to communicate with external Touch ICs: PIO and DMA. +PIO can let driver manually write/read data to/from Touch ICs, instead, THC DMA can +automatically write/read data without driver involved. + +HW Sequencer includes THC major logic, it gets instruction from MMIO registers to control +SPI bus and I2C bus to finish a bus data transaction, it also can automatically handle +Touch ICs interrupt and start DMA receive/send data from/to Touch ICs according to interrupt +type. That means THC HW Sequencer understands HIDSPI/HIDI2C transfer protocol, and handle +the communication without driver involved, what driver needs to do is just configure the THC +properly, and prepare the formatted data packet or handle received data packet. + +As THC supports HIDSPI/HIDI2C protocols, it has SPI controller and I2C subIP in it to expose +SPI bus and I2C bus. THC also integrates a GPIO controller to provide interrupt line support +and reset line support. + +2. THC Hardware Interface +========================= + +2.1 Host Interface +------------------ + +THC is exposed as "PCI Digitizer device" to the host. The PCI product and device IDs are +changed from different generations of processors. So the source code which enumerates drivers +needs to update from generation to generation. + + +2.2 Device Interface +-------------------- + +THC supports two types of bus for Touch IC connection: Enhanced SPI bus and I2C bus. + +2.2.1 SPI Port +~~~~~~~~~~~~~~ + +When PORT_TYPE = 00b in MMIO registers, THC uses SPI interfaces to communicate with external +Touch IC. THC enhanced SPI Bus supports different SPI modes: standard Single IO mode, +Dual IO mode and Quad IO mode. + +In Single IO mode, THC drives MOSI line to send data to Touch ICs, and receives data from Touch +ICs data from MISO line. In Dual IO mode, THC drivers MOSI and MISO both for data sending, and +also receives the data on both line. In Quad IO mode, there are other two lines (IO2 and IO3) +are added, THC drives MOSI (IO0), MISO (IO1), IO2 and IO3 at the same time for data sending, and +also receives the data on those 4 lines. Driver needs to configure THC in different mode by +setting different opcode. + +Beside IO mode, driver also needs to configure SPI bus speed. THC supports up to 42MHz SPI clock +on Intel Lunar Lake platform. + +For THC sending data to Touch IC, the data flow on SPI bus:: + + | --------------------THC sends---------------------------------| + <8Bits OPCode><24Bits Slave Address>........... + +For THC receiving data from Touch IC, the data flow on SPI bus:: + + | ---------THC Sends---------------||-----Touch IC sends--------| + <8Bits OPCode><24Bits Slave Address>........... + +2.2.2 I2C Port +~~~~~~~~~~~~~~ + +THC also integrates I2C controller in it, it's called I2C SubSystem. When PORT_TYPE = 01, THC +is configured to I2C mode. Comparing to SPI mode which can be configured through MMIO registers +directly, THC needs to use PIO read (by setting SubIP read opcode) to I2C subIP APB registers' +value and use PIO write (by setting SubIP write opcode) to do a write operation. + +2.2.3 GPIO interface +~~~~~~~~~~~~~~~~~~~~ + +THC also includes two GPIO pins, one for interrupt and the other for device reset control. + +Interrupt line can be configured to either level triggerred or edge triggerred by setting MMIO +Control register. + +Reset line is controlled by BIOS (or EFI) through ACPI _RST method, driver needs to call this +device ACPI _RST method to reset touch IC during initialization. + +3. High level concept +===================== + +3.1 Opcode +---------- + +Opcode (operation code) is used to tell THC or Touch IC what the operation will be, such as PIO +read or PIO write. + +When THC is configured to SPI mode, opcodes are used for determining the read/write IO mode. +There are some OPCode examples for SPI IO mode: + +======= ============================== +opcode Corresponding SPI command +======= ============================== +0x0B Read Single I/O +0x02 Write Single I/O +0xBB Read Dual I/O +0xB2 Write Dual I/O +0xEB Read Quad I/O +0xE2 Write Quad I/O +======= ============================== + +In general, different touch IC has different OPCode definition. According to HIDSPI +protocol whitepaper, those OPCodes are defined in device ACPI table, and driver needs to +query those information through OS ACPI APIs during driver initialization, then configures +THC MMIO OPCode registers with correct setting. + +When THC is working in I2C mode, opcodes are used to tell THC what's the next PIO type: +I2C SubIP APB register read, I2C SubIP APB register write, I2C touch IC device read, +I2C touch IC device write, I2C touch IC device write followed by read. + +Here are the THC pre-defined opcodes for I2C mode: + +======= =================================================== =========== +opcode Corresponding I2C command Address +======= =================================================== =========== +0x12 Read I2C SubIP APB internal registers 0h - FFh +0x13 Write I2C SubIP APB internal registers 0h - FFh +0x14 Read external Touch IC through I2C bus N/A +0x18 Write external Touch IC through I2C bus N/A +0x1C Write then read external Touch IC through I2C bus N/A +======= =================================================== =========== + +3.2 PIO +------- + +THC provides a programmed I/O (PIO) access interface for the driver to access the touch IC's +configuration registers, or access I2C subIP's configuration registers. To use PIO to perform +I/O operations, driver should pre-program PIO control registers and PIO data registers and kick +off the sequencing cycle. THC uses different PIO opcodes to distinguish different PIO +operations (PIO read/write/write followed by read). + +If there is a Sequencing Cycle In Progress and an attempt is made to program any of the control, +address, or data register the cycle is blocked and a sequence error will be encountered. + +A status bit indicates when the cycle has completed allowing the driver to know when read results +can be checked and/or when to initiate a new command. If enabled, the cycle done assertion can +interrupt driver with an interrupt. + +Because THC only has 16 FIFO registers for PIO, so all the data transfer through PIO shouldn't +exceed 64 bytes. + +As DMA needs max packet size for transferring configuration, and the max packet size information +always in HID device descriptor which needs THC driver to read it out from HID Device (Touch IC). +So PIO typical use case is, before DMA initialization, write RESET command (PIO write), read +RESET response (PIO read or PIO write followed by read), write Power ON command (PIO write), read +device descriptor (PIO read). + +For how to issue a PIO operation, here is the steps which driver needs follow: + +- Program read/write data size in THC_SS_BC. +- Program I/O target address in THC_SW_SEQ_DATA0_ADDR. +- If write, program the write data in THC_SW_SEQ_DATA0..THC_SW_SEQ_DATAn. +- Program the PIO opcode in THC_SS_CMD. +- Set TSSGO = 1 to start the PIO write sequence. +- If THC_SS_CD_IE = 1, SW will receives a MSI when the PIO is completed. +- If read, read out the data in THC_SW_SEQ_DATA0..THC_SW_SEQ_DATAn. + +3.3 DMA +------- + +THC has 4 DMA channels: Read DMA1, Read DMA2, Write DMA and Software DMA. + +3.3.1 Read DMA Channel +~~~~~~~~~~~~~~~~~~~~~~ + +THC has two Read DMA engines: 1st RxDMA (RxDMA1) and 2nd RxDMA (RxDMA2). RxDMA1 is reserved for +raw data mode. RxDMA2 is used for HID data mode and it is the RxDMA engine currently driver uses +for HID input report data retrieval. + +RxDMA's typical use case is auto receiving the data from Touch IC. Once RxDMA is enabled by +software, THC will start auto-handling receiving logic. + +For SPI mode, THC RxDMA sequence is: when Touch IC triggers a interrupt to THC, THC reads out +report header to identify what's the report type, and what's the report length, according to +above information, THC reads out report body to internal FIFO and start RxDMA coping the data +to system memory. After that, THC update interrupt cause register with report type, and update +RxDMA PRD table read pointer, then trigger a MSI interrupt to notify driver RxDMA finishing +data receiving. + +For I2C mode, THC RxDMA's behavior is little difference, because of HIDI2C protocol difference with +HIDSPI protocol, RxDMA only be used to receive input report. The sequence is, when Touch IC +triggers a interrupt to THC, THC first reads out 2 bytes from input report address to determine the +packet length, then use this packet length to start a DMA reading from input report address for +input report data. After that, THC update RxDMA PRD table read pointer, then trigger a MSI interrupt +to notify driver input report data is ready in system memory. + +All above sequence is hardware automatically handled, all driver needs to do is configure RxDMA and +waiting for interrupt ready then read out the data from system memory. + +3.3.2 Software DMA channel +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +THC supports a software triggerred RxDMA mode to read the touch data from touch IC. This SW RxDMA +is the 3rd THC RxDMA engine with the similar functionalities as the existing two RxDMAs, the only +difference is this SW RxDMA is triggerred by software, and RxDMA2 is triggerred by external Touch IC +interrupt. It gives a flexiblity to software driver to use RxDMA read Touch IC data in any time. + +Before software starts a SW RxDMA, it shall stop the 1st and 2nd RxDMA, clear PRD read/write pointer +and quiesce the device interrupt (THC_DEVINT_QUIESCE_HW_STS = 1), other operations are the same with +RxDMA. + +3.3.3 Write DMA Channel +~~~~~~~~~~~~~~~~~~~~~~~ + +THC has one write DMA engine, which can be used for sending data to Touch IC automatically. +According to HIDSPI and HIDI2C protocol, every time only one command can be sent to touch IC, and +before last command is completely handled, next command cannot be sent, THC write DMA engine only +supports single PRD table. + +What driver needs to do is, preparing PRD table and DMA buffer, then copy data to DMA buffer and +update PRD table with buffer address and buffer length, then start write DMA. THC will +automatically send the data to touch IC, and trigger a DMA completion interrupt once transferring +is done. + +3.4 PRD +------- + +Physical Region Descriptor (PRD) provides the memory mapping description for THC DMAs. + +3.4.1 PRD table and entry +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to improve physical DMA memory usage, modern drivers trend to allocate a virtually +contiguous, but physically fragmented buffer of memory for each data buffer. Linux OS also +provide SGL (scatter gather list) APIs to support this usage. + +THC uses PRD table (physical region descriptor) to support the corresponding OS kernel +SGL that describes the virtual to physical buffer mapping. + +:: + + ------------------------ -------------- -------------- + | PRD table base address +----+ PRD table #1 +-----+ PRD Entry #1 | + ------------------------ -------------- -------------- + -------------- + | PRD Entry #2 | + -------------- + -------------- + | PRD Entry #n | + -------------- + +The read DMA engine supports multiple PRD tables held within a circular buffer that allow the THC +to support multiple data buffers from the Touch IC. This allows host SW to arm the Read DMA engine +with multiple buffers, allowing the Touch IC to send multiple data frames to the THC without SW +interaction. This capability is required when the CPU processes touch frames slower than the +Touch IC can send them. + +To simplify the design, SW assumes worst-case memory fragmentation. Therefore,each PRD table shall +contain the same number of PRD entries, allowing for a global register (per Touch IC) to hold the +number of PRD-entries per PRD table. + +SW allocates up to 128 PRD tables per Read DMA engine as specified in the THC_M_PRT_RPRD_CNTRL.PCD +register field. The number of PRD tables should equal the number of data buffers. + +Max OS memory fragmentation will be at a 4KB boundary, thus to address 1MB of virtually contiguous +memory 256 PRD entries are required for a single PRD Table. SW writes the number of PRD entries +for each PRD table in the THC_M_PRT_RPRD_CNTRL.PTEC register field. The PRD entry's length must be +multiple of 4KB except for the last entry in a PRD table. + +SW allocates all the data buffers and PRD tables only once at host initialization. + +3.4.2 PRD Write pointer and read pointer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As PRD tables are organized as a Circular Buffer (CB), a read pointer and a write pointer for a CB +are needed. + +DMA HW consumes the PRD tables in the CB, one PRD entry at a time until the EOP bit is found set +in a PRD entry. At this point HW increments the PRD read pointer. Thus, the read pointer points +to the PRD which the DMA engine is currently processing. This pointer rolls over once the circular +buffer's depth has been traversed with bit[7] the Rollover bit. E.g. if the DMA CB depth is equal +to 4 entries (0011b), then the read pointers will follow this pattern (HW is required to honor +this behavior): 00h 01h 02h 03h 80h 81h 82h 83h 00h 01h ... + +The write pointer is updated by SW. The write pointer points to location in the DMA CB, where the +next PRD table is going to be stored. SW needs to ensure that this pointer rolls over once the +circular buffer's depth has been traversed with Bit[7] as the rollover bit. E.g. if the DMA CB +depth is equal to 5 entries (0100b), then the write pointers will follow this pattern (SW is +required to honor this behavior): 00h 01h 02h 03h 04h 80h 81h 82h 83h 84h 00h 01h .. + +3.4.3 PRD descriptor structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Intel THC uses PRD entry descriptor for every PRD entry. Every PRD entry descriptor occupies +128 bits memories: + +=================== ======== =============================================== +struct field bit(s) description +=================== ======== =============================================== +dest_addr 53..0 destination memory address, as every entry + is 4KB, ignore lowest 10 bits of address. +reserved1 54..62 reserved +int_on_completion 63 completion interrupt enable bit, if this bit + set it means THC will trigger a completion + interrupt. This bit is set by SW driver. +len 87..64 how many bytes of data in this entry. +end_of_prd 88 end of PRD table bit, if this bit is set, + it means this entry is last entry in this PRD + table. This bit is set by SW driver. +hw_status 90..89 HW status bits +reserved2 127..91 reserved +=================== ======== =============================================== + +And one PRD table can include up to 256 PRD entries, as every entries is 4K bytes, so every +PRD table can describe 1M bytes memory. + +.. code-block:: c + + struct thc_prd_table { + struct thc_prd_entry entries[PRD_ENTRIES_NUM]; + }; + +In general, every PRD table means one HID touch data packet. Every DMA engine can support +up to 128 PRD tables (except write DMA, write DMA only has one PRD table). SW driver is responsible +to get max packet length from touch IC, and use this max packet length to create PRD entries for +each PRD table. + +4. HIDSPI support (QuickSPI) +============================ + +Intel THC is total compatible with HIDSPI protocol, THC HW sequenser can accelerate HIDSPI +protocol transferring. + +4.1 Reset Flow +-------------- + +- Call ACPI _RST method to reset Touch IC device. +- Read the reset response from TIC through PIO read. +- Issue a command to retrieve device descriptor from Touch IC through PIO write. +- Read the device descriptor from Touch IC through PIO read. +- If the device descriptor is valid, allocate DMA buffers and configure all DMA channels. +- Issue a command to retrieve report descriptor from Touch IC through DMA. + +4.2 Input Report Data Flow +-------------------------- + +Basic Flow: + +- Touch IC interrupts the THC Controller using an in-band THC interrupt. +- THC Sequencer reads the input report header by transmitting read approval as a signal + to the Touch IC to prepare for host to read from the device. +- THC Sequencer executes a Input Report Body Read operation corresponding to the value + reflected in “Input Report Length” field of the Input Report Header. +- THC DMA engine begins fetching data from the THC Sequencer and writes to host memory + at PRD entry 0 for the current CB PRD table entry. This process continues until the + THC Sequencer signals all data has been read or the THC DMA Read Engine reaches the + end of it's last PRD entry (or both). +- The THC Sequencer checks for the “Last Fragment Flag” bit in the Input Report Header. + If it is clear, the THC Sequencer enters an idle state. +- If the “Last Fragment Flag” bit is enabled the THC Sequencer enters End-of-Frame Processing. + +THC Sequencer End of Frame Processing: + +- THC DMA engine increments the read pointer of the Read PRD CB, sets EOF interrupt status + in RxDMA2 register (THC_M_PRT_READ_DMA_INT_STS_2). +- If THC EOF interrupt is enabled by the driver in the control register (THC_M_PRT_READ_DMA_CNTRL_2), + generates interrupt to software. + +Sequence of steps to read data from RX DMA buffer: + +- THC QuickSPI driver checks CB write Ptr and CB read Ptr to identify if any data frame in DMA + circular buffers. +- THC QuickSPI driver gets first unprocessed PRD table. +- THC QuickSPI driver scans all PRD entries in this PRD table to calculate the total frame size. +- THC QuickSPI driver copies all frame data out. +- THC QuickSPI driver checks the data type according to input report body, and calls related + callbacks to process the data. +- THC QuickSPI driver updates write Ptr. + +4.3 Output Report Data Flow +--------------------------- + +Generic Output Report Flow: + +- HID core calls raw_request callback with a request to THC QuickSPI driver. +- THC QuickSPI Driver converts request provided data into the output report packet and copies it + to THC's write DMA buffer. +- Start TxDMA to complete the write operation. + +5. HIDI2C support (QuickI2C) +============================ + +5.1 Reset Flow +-------------- + +- Read device descriptor from Touch IC device through PIO write followed by read. +- If the device descriptor is valid, allocate DMA buffers and configure all DMA channels. +- Use PIO or TxDMA to write a SET_POWER request to TIC's command register, and check if the + write operation is successfully completed. +- Use PIO or TxDMA to write a RESET request to TIC's command register. If the write operation + is successfully completed, wait for reset response from TIC. +- Use SWDMA to read report descriptor through TIC's report descriptor register. + +5.2 Input Report Data Flow +-------------------------- + +Basic Flow: + +- Touch IC asserts the interrupt indicating that it has an interrupt to send to HOST. + THC Sequencer issues a READ request over the I2C bus. The HIDI2C device returns the + first 2 bytes from the HIDI2C device which contains the length of the received data. +- THC Sequencer continues the Read operation as per the size of data indicated in the + length field. +- THC DMA engine begins fetching data from the THC Sequencer and writes to host memory + at PRD entry 0 for the current CB PRD table entry. THC writes 2Bytes for length field + plus the remaining data to RxDMA buffer. This process continues until the THC Sequencer + signals all data has been read or the THC DMA Read Engine reaches the end of it's last + PRD entry (or both). +- THC Sequencer enters End-of-Input Report Processing. +- If the device has no more input reports to send to the host, it de-asserts the interrupt + line. For any additional input reports, device keeps the interrupt line asserted and + steps 1 through 4 in the flow are repeated. + +THC Sequencer End of Input Report Processing: + +- THC DMA engine increments the read pointer of the Read PRD CB, sets EOF interrupt status + in RxDMA 2 register (THC_M_PRT_READ_DMA_INT_STS_2). +- If THC EOF interrupt is enabled by the driver in the control register + (THC_M_PRT_READ_DMA_CNTRL_2), generates interrupt to software. + +Sequence of steps to read data from RX DMA buffer: + +- THC QuickI2C driver checks CB write Ptr and CB read Ptr to identify if any data frame in DMA + circular buffers. +- THC QuickI2C driver gets first unprocessed PRD table. +- THC QuickI2C driver scans all PRD entries in this PRD table to calculate the total frame size. +- THC QuickI2C driver copies all frame data out. +- THC QuickI2C driver call hid_input_report to send the input report content to HID core, which + includes Report ID + Report Data Content (remove the length field from the original report + data). +- THC QuickI2C driver updates write Ptr. + +5.3 Output Report Data Flow +--------------------------- + +Generic Output Report Flow: + +- HID core call THC QuickI2C raw_request callback. +- THC QuickI2C uses PIO or TXDMA to write a SET_REPORT request to TIC's command register. Report + type in SET_REPORT should be set to Output. +- THC QuickI2C programs TxDMA buffer with TX Data to be written to TIC's data register. The first + 2 bytes should indicate the length of the report followed by the report contents including + Report ID. + +6. THC Debugging +================ + +To debug THC, event tracing mechanism is used. To enable debug logs:: + + echo 1 > /sys/kernel/debug/tracing/events/intel_thc/enable + cat /sys/kernel/debug/tracing/trace + +7. Reference +============ +- HIDSPI: https://download.microsoft.com/download/c/a/0/ca07aef3-3e10-4022-b1e9-c98cea99465d/HidSpiProtocolSpec.pdf +- HIDI2C: https://download.microsoft.com/download/7/d/d/7dd44bb7-2a7a-4505-ac1c-7227d3d96d5b/hid-over-i2c-protocol-spec-v1-0.docx From patchwork Mon Dec 16 01:41:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851907 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C49AF3BBF2; Mon, 16 Dec 2024 01:41:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313320; cv=none; b=Ep30eN1J4TArd3w3gDIIDW/kTI2M5ic0wZstCCF8SQG21XV7KBbuSum9ZEv9rvkdLTQy49sCqKOJIaMUPrqjJIKf+ofeiaEpwat9w9Ks2YoGnJSUalCrQQ98yRmFi6WD8tarzuib8Oj64GdORgtgMbQcZpRQss7+by1b8R772Qw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313320; c=relaxed/simple; bh=wSLx/hVjhFBPyiR2r0qHi6tjKq3RUgdfZv/yKffH6q8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HEqyucq+Lj5HxWqvyKmuPNaUnKyQmDN521qpe+NKobpQYiBTeiyxPjFHVdh5SOtVYArRIrjgScpvMK1fP9vZCuHVY/DysAI6510c2bPVDaczWuH/ypVYTw68ls7f5WLLnH/tjf0N1gcI7sXsxrAwli8qvjFrHw2SwKnQpSE0Bfo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=HG0KYfNC; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="HG0KYfNC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313318; x=1765849318; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wSLx/hVjhFBPyiR2r0qHi6tjKq3RUgdfZv/yKffH6q8=; b=HG0KYfNCuCRHl6Ex/FnS86vk1TNwbhh6W05Wb/d7v5UVxk7v1Oa/eyn7 WZ+LyeATIxtrVuatGUkPXXTlwHV+zuEenX7aHKKQJzOncfMyr/Wd2HUsr NDX7Z2bOb41BZ+I1eYg5N73NHXhsGpwymZg0NK8ljJv/xDGR7Aner9F8j 5ZW7AhADKfMfS9abS4diMnJiniLEqEOBtMylLrZBCEG5BAHNcNM9R15i3 IHsxxQiU5FHs6ozjJ5lw9FX69m7LEYaX6xavINfCWAqkEmmGSdTC00Ldu Ui/nAysEiwtJBAMU7e6YaHeTGrm1dUiDeBsb2ecpS/SirL7zP8BkVcQU+ w==; X-CSE-ConnectionGUID: Ika5MXaLS4Cy7T6Ba+7q2A== X-CSE-MsgGUID: sOzinDIITyuSBViQiEePig== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34012957" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34012957" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:41:57 -0800 X-CSE-ConnectionGUID: Mz8RI44uRq2XKealGCBJig== X-CSE-MsgGUID: Zzu6RRKtSOugUkaP3CY/4w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084173" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:41:53 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Xinpeng Sun , Even Xu , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 03/22] HID: intel-thc-hid: intel-thc: Add THC registers definition Date: Mon, 16 Dec 2024 09:41:08 +0800 Message-Id: <20241216014127.3722172-4-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Xinpeng Sun Add THC Hardware register definitions and descriptions. Co-developed-by: Even Xu Signed-off-by: Even Xu Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-thc-hid/intel-thc/intel-thc-hw.h | 639 ++++++++++++++++++ 1 file changed, 639 insertions(+) create mode 100644 drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h new file mode 100644 index 000000000000..8b3a962e7e64 --- /dev/null +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h @@ -0,0 +1,639 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2024 Intel Corporation */ + +#ifndef _INTEL_THC_HW_H_ +#define _INTEL_THC_HW_H_ + +#include + +/* THC registers offset */ +/* Touch Host Controller Control Register */ +#define THC_M_PRT_CONTROL_OFFSET 0x1008 +/* THC SPI Bus Configuration Register */ +#define THC_M_PRT_SPI_CFG_OFFSET 0x1010 +/* THC SPI Bus Read Opcode Register */ +#define THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET 0x1014 +/* THC SPI Bus Read Opcode Register */ +#define THC_M_PRT_SPI_DMARD_OPCODE_OFFSET 0x1018 +/* THC SPI Bus Write Opcode Register */ +#define THC_M_PRT_SPI_WR_OPCODE_OFFSET 0x101C +/* THC Interrupt Enable Register */ +#define THC_M_PRT_INT_EN_OFFSET 0x1020 +/* THC Interrupt Status Register */ +#define THC_M_PRT_INT_STATUS_OFFSET 0x1024 +/* THC Error Cause Register */ +#define THC_M_PRT_ERR_CAUSE_OFFSET 0x1028 +/* THC SW sequencing Control */ +#define THC_M_PRT_SW_SEQ_CNTRL_OFFSET 0x1040 +/* THC SW sequencing Status */ +#define THC_M_PRT_SW_SEQ_STS_OFFSET 0x1044 +/* THC SW Sequencing Data DW0 or SPI Address Register */ +#define THC_M_PRT_SW_SEQ_DATA0_ADDR_OFFSET 0x1048 +/* THC SW sequencing Data DW1 */ +#define THC_M_PRT_SW_SEQ_DATA1_OFFSET 0x104C +/* THC SW sequencing Data DW2 */ +#define THC_M_PRT_SW_SEQ_DATA2_OFFSET 0x1050 +/* THC SW sequencing Data DW3 */ +#define THC_M_PRT_SW_SEQ_DATA3_OFFSET 0x1054 +/* THC SW sequencing Data DW4 */ +#define THC_M_PRT_SW_SEQ_DATA4_OFFSET 0x1058 +/* THC SW sequencing Data DW5 */ +#define THC_M_PRT_SW_SEQ_DATA5_OFFSET 0x105C +/* THC SW sequencing Data DW6 */ +#define THC_M_PRT_SW_SEQ_DATA6_OFFSET 0x1060 +/* THC SW sequencing Data DW7 */ +#define THC_M_PRT_SW_SEQ_DATA7_OFFSET 0x1064 +/* THC SW sequencing Data DW8 */ +#define THC_M_PRT_SW_SEQ_DATA8_OFFSET 0x1068 +/* THC SW sequencing Data DW9 */ +#define THC_M_PRT_SW_SEQ_DATA9_OFFSET 0x106C +/* THC SW sequencing Data DW10 */ +#define THC_M_PRT_SW_SEQ_DATA10_OFFSET 0x1070 +/* THC SW sequencing Data DW11 */ +#define THC_M_PRT_SW_SEQ_DATA11_OFFSET 0x1074 +/* THC SW sequencing Data DW12 */ +#define THC_M_PRT_SW_SEQ_DATA12_OFFSET 0x1078 +/* THC SW sequencing Data DW13 */ +#define THC_M_PRT_SW_SEQ_DATA13_OFFSET 0x107C +/* THC SW sequencing Data DW14 */ +#define THC_M_PRT_SW_SEQ_DATA14_OFFSET 0x1080 +/* THC SW sequencing Data DW15 */ +#define THC_M_PRT_SW_SEQ_DATA15_OFFSET 0x1084 +/* THC SW sequencing Data DW16 */ +#define THC_M_PRT_SW_SEQ_DATA16_OFFSET 0x1088 +/* THC Write PRD Base Address Register Low */ +#define THC_M_PRT_WPRD_BA_LOW_OFFSET 0x1090 +/* THC Write PRD Base Address Register High */ +#define THC_M_PRT_WPRD_BA_HI_OFFSET 0x1094 +/* THC Write DMA Control */ +#define THC_M_PRT_WRITE_DMA_CNTRL_OFFSET 0x1098 +/* THC Write Interrupt Status */ +#define THC_M_PRT_WRITE_INT_STS_OFFSET 0x109C +/* THC Write DMA Error Register */ +#define THC_M_PRT_WRITE_DMA_ERR_OFFSET 0x10A0 +/* THC device address for the bulk write */ +#define THC_M_PRT_WR_BULK_ADDR_OFFSET 0x10B4 +/* THC Device Interrupt Cause Register Address */ +#define THC_M_PRT_DEV_INT_CAUSE_ADDR_OFFSET 0x10B8 +/* THC Device Interrupt Cause Register Value */ +#define THC_M_PRT_DEV_INT_CAUSE_REG_VAL_OFFSET 0x10BC +/* THC TXDMA Frame Count */ +#define THC_M_PRT_TX_FRM_CNT_OFFSET 0x10E0 +/* THC TXDMA Packet Count */ +#define THC_M_PRT_TXDMA_PKT_CNT_OFFSET 0x10E4 +/* THC Device Interrupt Count on this port */ +#define THC_M_PRT_DEVINT_CNT_OFFSET 0x10E8 +/* Touch Device Interrupt Cause register Format Configuration Register 1 */ +#define THC_M_PRT_DEVINT_CFG_1_OFFSET 0x10EC +/* Touch Device Interrupt Cause register Format Configuration Register 2 */ +#define THC_M_PRT_DEVINT_CFG_2_OFFSET 0x10F0 +/* THC Read PRD Base Address Low for the 1st RXDMA */ +#define THC_M_PRT_RPRD_BA_LOW_1_OFFSET 0x1100 +/* THC Read PRD Base Address High for the 1st RXDMA */ +#define THC_M_PRT_RPRD_BA_HI_1_OFFSET 0x1104 +/* THC Read PRD Control for the 1st RXDMA */ +#define THC_M_PRT_RPRD_CNTRL_1_OFFSET 0x1108 +/* THC Read DMA Control for the 1st RXDMA */ +#define THC_M_PRT_READ_DMA_CNTRL_1_OFFSET 0x110C +/* THC Read Interrupt Status for the 1st RXDMA */ +#define THC_M_PRT_READ_DMA_INT_STS_1_OFFSET 0x1110 +/* THC Read DMA Error Register for the 1st RXDMA */ +#define THC_M_PRT_READ_DMA_ERR_1_OFFSET 0x1114 +/* Touch Sequencer GuC Tail Offset Address Low for the 1st RXDMA */ +#define THC_M_PRT_GUC_OFFSET_LOW_1_OFFSET 0x1118 +/* Touch Sequencer GuC Tail Offset Address High for the 1st RXDMA */ +#define THC_M_PRT_GUC_OFFSET_HI_1_OFFSET 0x111C +/* Touch Host Controller GuC Work Queue Item Size for the 1st RXDMA */ +#define THC_M_PRT_GUC_WORKQ_ITEM_SZ_1_OFFSET 0x1120 +/* Touch Host Controller GuC Control register for the 1st RXDMA */ +#define THC_M_PRT_GUC_WORKQ_SZ_1_OFFSET 0x1124 +/* Touch Sequencer Control for the 1st DMA */ +#define THC_M_PRT_TSEQ_CNTRL_1_OFFSET 0x1128 +/* Touch Sequencer GuC Doorbell Address Low for the 1st RXDMA */ +#define THC_M_PRT_GUC_DB_ADDR_LOW_1_OFFSET 0x1130 +/* Touch Sequencer GuC Doorbell Address High for the 1st RXDMA */ +#define THC_M_PRT_GUC_DB_ADDR_HI_1_OFFSET 0x1134 +/* Touch Sequencer GuC Doorbell Data */ +#define THC_M_PRT_GUC_DB_DATA_1_OFFSET 0x1138 +/* Touch Sequencer GuC Tail Offset Initial Value for the 1st RXDMA */ +#define THC_M_PRT_GUC_OFFSET_INITVAL_1_OFFSET 0x1140 +/* THC Device Address for the bulk/touch data read for the 1st RXDMA */ +#define THC_M_PRT_RD_BULK_ADDR_1_OFFSET 0x1170 +/* THC Gfx/SW Doorbell Count from the 1st Stream RXDMA on this port */ +#define THC_M_PRT_DB_CNT_1_OFFSET 0x11A0 +/* THC Frame Count from the 1st Stream RXDMA on this port */ +#define THC_M_PRT_FRM_CNT_1_OFFSET 0x11A4 +/* THC Micro Frame Count from the 1st Stream RXDMA on this port */ +#define THC_M_PRT_UFRM_CNT_1_OFFSET 0x11A8 +/* THC Packet Count from the 1st Stream RXDMA on this port */ +#define THC_M_PRT_RXDMA_PKT_CNT_1_OFFSET 0x11AC +/* + * THC Software Interrupt Count from the 1st Stream RXDMA + * on this port + */ +#define THC_M_PRT_SWINT_CNT_1_OFFSET 0x11B0 +/* Touch Sequencer Frame Drop Counter for the 1st RXDMA */ +#define THC_M_PRT_FRAME_DROP_CNT_1_OFFSET 0x11B4 +/* THC Coaescing 1 */ +#define THC_M_PRT_COALESCE_1_OFFSET 0x11B8 +/* THC Read PRD Base Address Low for the 2nd RXDMA */ +#define THC_M_PRT_RPRD_BA_LOW_2_OFFSET 0x1200 +/* THC Read PRD Base Address High for the 2nd RXDMA */ +#define THC_M_PRT_RPRD_BA_HI_2_OFFSET 0x1204 +/* THC Read PRD Control for the 2nd RXDMA */ +#define THC_M_PRT_RPRD_CNTRL_2_OFFSET 0x1208 +/* THC Read DMA Control for the 2nd RXDMA */ +#define THC_M_PRT_READ_DMA_CNTRL_2_OFFSET 0x120C +/* THC Read Interrupt Status for the 2nd RXDMA */ +#define THC_M_PRT_READ_DMA_INT_STS_2_OFFSET 0x1210 +/* THC Read DMA Error Register for the 2nd RXDMA */ +#define THC_M_PRT_READ_DMA_ERR_2_OFFSET 0x1214 +/* Touch Sequencer GuC Tail Offset Address Low for the 2nd RXDMA */ +#define THC_M_PRT_GUC_OFFSET_LOW_2_OFFSET 0x1218 +/* Touch Sequencer GuC Tail Offset Address High for the 2nd RXDMA */ +#define THC_M_PRT_GUC_OFFSET_HI_2_OFFSET 0x121C +/* Touch Host Controller GuC Work Queue Item Size for the 2nd RXDMA */ +#define THC_M_PRT_GUC_WORKQ_ITEM_SZ_2_OFFSET 0x1220 +/* Touch Host Controller GuC Control register for the 2nd RXDMA */ +#define THC_M_PRT_GUC_WORKQ_SZ_2_OFFSET 0x1224 +/* Touch Sequencer Control for the 2nd DMA */ +#define THC_M_PRT_TSEQ_CNTRL_2_OFFSET 0x1228 +/* Touch Sequencer GuC Doorbell Address Low for the 2nd RXDMA */ +#define THC_M_PRT_GUC_DB_ADDR_LOW_2_OFFSET 0x1230 +/* Touch Sequencer GuC Doorbell Address High for the 2nd RXDMA */ +#define THC_M_PRT_GUC_DB_ADDR_HI_2_OFFSET 0x1234 +/* Touch Sequencer GuC Doorbell Data for PRD2 */ +#define THC_M_PRT_GUC_DB_DATA_2_OFFSET 0x1238 +/* Touch Sequencer GuC Tail Offset Initial Value for the 2nd RXDMA */ +#define THC_M_PRT_GUC_OFFSET_INITVAL_2_OFFSET 0x1240 +/* THC Device Address for the bulk/touch data read for the 2nd RXDMA */ +#define THC_M_PRT_RD_BULK_ADDR_2_OFFSET 0x1270 +/* THC Gfx/SW Doorbell Count from the 2nd Stream RXDMA on this port */ +#define THC_M_PRT_DB_CNT_2_OFFSET 0x12A0 +/* THC Frame Count from the 2nd Stream RXDMA on this port */ +#define THC_M_PRT_FRM_CNT_2_OFFSET 0x12A4 +/* THC Micro Frame Count from the 2nd Stream RXDMA on this port */ +#define THC_M_PRT_UFRM_CNT_2_OFFSET 0x12A8 +/* THC Packet Count from the 2nd Stream RXDMA on this port */ +#define THC_M_PRT_RXDMA_PKT_CNT_2_OFFSET 0x12AC +/* + * THC Software Interrupt Count from the 2nd Stream RXDMA + * on this port + */ +#define THC_M_PRT_SWINT_CNT_2_OFFSET 0x12B0 +/* Touch Sequencer Frame Drop Counter for the 2nd RXDMA */ +#define THC_M_PRT_FRAME_DROP_CNT_2_OFFSET 0x12B4 +/* THC Coaescing 2 */ +#define THC_M_PRT_COALESCE_2_OFFSET 0x12B8 +/* THC SPARE REGISTER */ +#define THC_M_PRT_SPARE_REG_OFFSET 0x12BC +/* THC Read PRD Base Address Low for the SW RXDMA */ +#define THC_M_PRT_RPRD_BA_LOW_SW_OFFSET 0x12C0 +/* THC Read PRD Base Address High for the SW RXDMA */ +#define THC_M_PRT_RPRD_BA_HI_SW_OFFSET 0x12C4 +/* THC Read PRD Control for the SW RXDMA */ +#define THC_M_PRT_RPRD_CNTRL_SW_OFFSET 0x12C8 +/* THC Read DMA Control for the SW RXDMA */ +#define THC_M_PRT_READ_DMA_CNTRL_SW_OFFSET 0x12CC +/* THC Read Interrupt Status for the SW RXDMA */ +#define THC_M_PRT_READ_DMA_INT_STS_SW_OFFSET 0x12D0 +/* Touch Sequencer Control for the SW DMA */ +#define THC_M_PRT_TSEQ_CNTRL_SW_OFFSET 0x12D4 +/* Address for the bulk read for SW DMA engine */ +#define THC_M_PRT_RD_BULK_ADDR_SW_OFFSET 0x12D8 +/* THC Frame Count from the SW RXDMA on this port */ +#define THC_M_PRT_FRM_CNT_SW_OFFSET 0x12DC +/* THC Packet Count from the SW RXDMA on this port */ +#define THC_M_PRT_RXDMA_PKT_CNT_SW_OFFSET 0x12E0 +/* SW DMA PRD Table Length */ +#define THC_M_PRT_SW_DMA_PRD_TABLE_LEN_OFFSET 0x12E4 +/* THC timing based Frame/Interrupt caolescing control register for 1st RXDMA */ +#define THC_M_PRT_COALESCE_CNTRL_1_OFFSET 0x12E8 +/* THC timing based Frame/Interrupt caolescing control register for 2nd RXDMA */ +#define THC_M_PRT_COALESCE_CNTRL_2_OFFSET 0x12EC +/* Touch Sequencer PRD Table Empty Counter for the 1st RXDMA */ +#define THC_M_PRT_PRD_EMPTY_CNT_1_OFFSET 0x12F0 +/* Touch Sequencer PRD Table Empty Counter for the 2nd RXDM */ +#define THC_M_PRT_PRD_EMPTY_CNT_2_OFFSET 0x12F4 +/* THC coalescing status to reflect the current coalescing FSM state for 1st RXDMA */ +#define THC_M_PRT_COALESCE_STS_1_OFFSET 0x12F8 +/* THC coalescing status to reflect the current coalescing FSM state for 2nd RXDMA */ +#define THC_M_PRT_COALESCE_STS_2_OFFSET 0x12FC +/* THC Register for the SPI Port Duty Cycle Configuration */ +#define THC_M_PRT_SPI_DUTYC_CFG_OFFSET 0x1300 +/* THC Register for SW I2C Wtite Sequecning control */ +#define THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_OFFSET 0x1304 +/* THC current Timestamp Register for RXDMA1 */ +#define THC_M_PRT_TIMESTAMP_1_OFFSET 0x1308 +/* THC current Timestamp Register for RXDMA2 */ +#define THC_M_PRT_TIMESTAMP_2_OFFSET 0x130C +/* Current SYNC Event Timestamp Register */ +#define THC_M_PRT_SYNC_TIMESTAMP_OFFSET 0x1310 +/* THC Display Sync Register */ +#define THC_M_PRT_DISP_SYNC_OFFSET 0x1314 +/* THC Display Sync Register */ +#define THC_M_PRT_DISP_SYNC_2_OFFSET 0x1318 +/* THC Register for SW I2C Wtite Sequecning control */ +#define THC_M_PRT_I2C_CFG_OFFSET 0x131C + +/* THC register bits definition */ +#define TXN_ERR_INT_STS_BIT BIT(28) +#define TXN_FATAL_INT_STS_BIT BIT(30) + +#define NONDMA_INT_STS_BIT BIT(4) +#define EOF_INT_STS_BIT BIT(5) + +#define THC_CFG_DID_VID_VID GENMASK(15, 0) +#define THC_CFG_DID_VID_DID GENMASK(31, 16) + +#define THC_CFG_STS_CMD_IOSE BIT(0) +#define THC_CFG_STS_CMD_MSE BIT(1) +#define THC_CFG_STS_CMD_BME BIT(2) +#define THC_CFG_STS_CMD_SPCYC BIT(3) +#define THC_CFG_STS_CMD_MWRIEN BIT(4) +#define THC_CFG_STS_CMD_VGAPS BIT(5) +#define THC_CFG_STS_CMD_PERRR BIT(6) +#define THC_CFG_STS_CMD_SERREN BIT(8) +#define THC_CFG_STS_CMD_FBTBEN BIT(9) +#define THC_CFG_STS_CMD_INTD BIT(10) +#define THC_CFG_STS_CMD_INTS BIT(19) +#define THC_CFG_STS_CMD_CAPL BIT(20) +#define THC_CFG_STS_CMD_MCAP BIT(21) +#define THC_CFG_STS_CMD_FBTBC BIT(23) +#define THC_CFG_STS_CMD_MDPE BIT(24) +#define THC_CFG_STS_CMD_DEVT GENMASK(26, 25) +#define THC_CFG_STS_CMD_STA BIT(27) +#define THC_CFG_STS_CMD_RTA BIT(28) +#define THC_CFG_STS_CMD_RMA BIT(29) +#define THC_CFG_STS_CMD_SSE BIT(30) +#define THC_CFG_STS_CMD_DPE BIT(31) + +#define THC_CFG_CC_RID_RID GENMASK(7, 0) +#define THC_CFG_CC_RID_PI GENMASK(15, 8) +#define THC_CFG_CC_RID_SCC GENMASK(23, 16) +#define THC_CFG_CC_RID_BCC GENMASK(31, 24) + +#define THC_CFG_BIST_HTYPE_LT_CLS_CLSZ GENMASK(7, 0) +#define THC_CFG_BIST_HTYPE_LT_CLS_LT GENMASK(15, 8) +#define THC_CFG_BIST_HTYPE_LT_CLS_HTYPE GENMASK(22, 16) +#define THC_CFG_BIST_HTYPE_LT_CLS_MFD BIT(23) + +#define THC_CFG_BAR0_LOW_MEMSPACE BIT(0) +#define THC_CFG_BAR0_LOW_TYP GENMASK(2, 1) +#define THC_CFG_BAR0_LOW_PREFETCH BIT(3) +#define THC_CFG_BAR0_LOW_MEMSIZE GENMASK(14, 4) +#define THC_CFG_BAR0_LOW_MEMBAR GENMASK(31, 15) +#define THC_CFG_BAR0_HI_MEMBAR GENMASK(31, 0) + +#define THC_CFG_SID_SVID_SSVID GENMASK(15, 0) +#define THC_CFG_SID_SVID_SSID GENMASK(31, 16) + +#define THC_CFG_CAPP_CP GENMASK(7, 0) + +#define THC_CFG_INT_ILINE GENMASK(7, 0) +#define THC_CFG_INT_IPIN GENMASK(15, 8) + +#define THC_CFG_UR_STS_CTL_URRE BIT(0) +#define THC_CFG_UR_STS_CTL_URD BIT(1) +#define THC_CFG_UR_STS_CTL_FD BIT(2) + +#define THC_CFG_MSIMC_MSINP_MSICID_CAPID GENMASK(7, 0) +#define THC_CFG_MSIMC_MSINP_MSICID_NXTP GENMASK(15, 8) +#define THC_CFG_MSIMC_MSINP_MSICID_MSIE BIT(16) +#define THC_CFG_MSIMC_MSINP_MSICID_MMC GENMASK(19, 17) +#define THC_CFG_MSIMC_MSINP_MSICID_MMEN GENMASK(22, 20) +#define THC_CFG_MSIMC_MSINP_MSICID_XAC BIT(23) +#define THC_CFG_MSIMC_MSINP_MSICID_PVMC BIT(24) +#define THC_CFG_MSIMA_MADDR GENMASK(31, 2) +#define THC_CFG_MSIMUA_MAUDDR GENMASK(31, 0) +#define THC_CFG_MSIMD_MDAT GENMASK(15, 0) + +#define THC_CFG_PMCAP_PMNP_PMCID_CAPP GENMASK(7, 0) +#define THC_CFG_PMCAP_PMNP_PMCID_NXTP GENMASK(15, 8) +#define THC_CFG_PMCAP_PMNP_PMCID_VER GENMASK(18, 16) +#define THC_CFG_PMCAP_PMNP_PMCID_PMECLK BIT(19) +#define THC_CFG_PMCAP_PMNP_PMCID_DSI BIT(21) +#define THC_CFG_PMCAP_PMNP_PMCID_AUXC GENMASK(24, 22) +#define THC_CFG_PMCAP_PMNP_PMCID_D1S BIT(25) +#define THC_CFG_PMCAP_PMNP_PMCID_D2S BIT(26) +#define THC_CFG_PMCAP_PMNP_PMCID_PMES GENMASK(31, 27) + +#define THC_CFG_PMD_PMCSRBSE_PMCSR_PWRST GENMASK(1, 0) +#define THC_CFG_PMD_PMCSRBSE_PMCSR_NSR BIT(3) +#define THC_CFG_PMD_PMCSRBSE_PMCSR_PMEEN BIT(8) +#define THC_CFG_PMD_PMCSRBSE_PMCSR_DSEL GENMASK(12, 9) +#define THC_CFG_PMD_PMCSRBSE_PMCSR_DS GENMASK(14, 13) +#define THC_CFG_PMD_PMCSRBSE_PMCSR_PMESTS BIT(15) + +#define THC_CFG_DEVIDLE_CAPPID GENMASK(7, 0) +#define THC_CFG_DEVIDLE_NCAPPP GENMASK(15, 8) +#define THC_CFG_DEVIDLE_LENGTH GENMASK(23, 16) +#define THC_CFG_DEVIDLE_REV GENMASK(27, 24) +#define THC_CFG_DEVIDLE_VID GENMASK(31, 28) + +#define THC_CFG_VSHDR_VSECID GENMASK(15, 0) +#define THC_CFG_VSHDR_VSECR GENMASK(19, 16) +#define THC_CFG_VSHDR_VSECL GENMASK(31, 20) + +#define THC_CFG_SWLTRPTR_VALID BIT(0) +#define THC_CFG_SWLTRPTR_BARNUM GENMASK(3, 1) +#define THC_CFG_SWLTRPTR_SWLTRLOC GENMASK(31, 4) + +#define THC_CFG_DEVIDLEPTR_VALID BIT(0) +#define THC_CFG_DEVIDLEPTR_BARNUM GENMASK(3, 1) +#define THC_CFG_DEVIDLEPTR_DEVIDLELOC GENMASK(31, 4) +#define THC_CFG_DEVIDLEPOL_POLV GENMASK(9, 0) +#define THC_CFG_DEVIDLEPOL_POLS GENMASK(12, 10) + +#define THC_CFG_PCE_SPE BIT(0) +#define THC_CFG_PCE_I3E BIT(1) +#define THC_CFG_PCE_D3HE BIT(2) +#define THC_CFG_PCE_SE BIT(3) +#define THC_CFG_PCE_HAE BIT(5) + +#define THC_CFG_MANID_PROC GENMASK(7, 0) +#define THC_CFG_MANID_MID GENMASK(15, 8) +#define THC_CFG_MANID_MSID GENMASK(23, 16) +#define THC_CFG_MANID_DOT GENMASK(27, 24) + +#define THC_M_CMN_DEVIDLECTRL_CIP BIT(0) +#define THC_M_CMN_DEVIDLECTRL_IR BIT(1) +#define THC_M_CMN_DEVIDLECTRL_DEVIDLE BIT(2) +#define THC_M_CMN_DEVIDLECTRL_RR BIT(3) +#define THC_M_CMN_DEVIDLECTRL_IRC BIT(4) + +#define THC_M_CMN_LTR_CTRL_OFFSET 0x14 +#define THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ BIT(0) +#define THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN BIT(1) +#define THC_M_CMN_LTR_CTRL_LP_LTR_REQ BIT(2) +#define THC_M_CMN_LTR_CTRL_LP_LTR_EN BIT(3) +#define THC_M_CMN_LTR_CTRL_LP_LTR_SCALE GENMASK(6, 4) +#define THC_M_CMN_LTR_CTRL_LP_LTR_VAL GENMASK(16, 7) +#define THC_M_CMN_LTR_CTRL_ACT_LTR_SCALE GENMASK(19, 17) +#define THC_M_CMN_LTR_CTRL_ACT_LTR_VAL GENMASK(29, 20) +#define THC_M_CMN_LTR_CTRL_LAST_LTR_SENT GENMASK(31, 30) + +#define THC_M_PRT_CONTROL_TSFTRST BIT(0) +#define THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_EN BIT(1) +#define THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_HW_STS BIT(2) +#define THC_M_PRT_CONTROL_DEVRST BIT(3) +#define THC_M_PRT_CONTROL_THC_DRV_LOCK_EN BIT(13) +#define THC_M_PRT_CONTROL_THC_INSTANCE_INDEX GENMASK(18, 16) +#define THC_M_PRT_CONTROL_PORT_INDEX GENMASK(22, 20) +#define THC_M_PRT_CONTROL_THC_ARB_POLICY GENMASK(25, 24) +#define THC_M_PRT_CONTROL_THC_BIOS_LOCK_EN BIT(27) +#define THC_M_PRT_CONTROL_PORT_SUPPORTED BIT(28) +#define THC_M_PRT_CONTROL_SPI_IO_RDY BIT(29) +#define THC_M_PRT_CONTROL_PORT_TYPE GENMASK(31, 30) + +#define THC_M_PRT_SPI_CFG_SPI_TRDC GENMASK(1, 0) +#define THC_M_PRT_SPI_CFG_SPI_TRMODE GENMASK(3, 2) +#define THC_M_PRT_SPI_CFG_SPI_TCRF GENMASK(6, 4) +#define THC_M_PRT_SPI_CFG_SPI_RD_MPS GENMASK(15, 7) +#define THC_M_PRT_SPI_CFG_SPI_TWMODE GENMASK(19, 18) +#define THC_M_PRT_SPI_CFG_SPI_TCWF GENMASK(22, 20) +#define THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN BIT(23) +#define THC_M_PRT_SPI_CFG_SPI_WR_MPS GENMASK(31, 24) + +#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_SIO GENMASK(31, 24) +#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO GENMASK(23, 16) +#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO GENMASK(15, 8) + +#define THC_M_PRT_INT_EN_SIPE BIT(0) +#define THC_M_PRT_INT_EN_SBO BIT(1) +#define THC_M_PRT_INT_EN_SIDR BIT(2) +#define THC_M_PRT_INT_EN_SOFB BIT(3) +#define THC_M_PRT_INT_EN_INVLD_DEV_ENTRY_INT_EN BIT(9) +#define THC_M_PRT_INT_EN_FRAME_BABBLE_ERR_INT_EN BIT(10) +#define THC_M_PRT_INT_EN_BUF_OVRRUN_ERR_INT_EN BIT(12) +#define THC_M_PRT_INT_EN_PRD_ENTRY_ERR_INT_EN BIT(13) +#define THC_M_PRT_INT_EN_DISP_SYNC_EVT_INT_EN BIT(14) +#define THC_M_PRT_INT_EN_DEV_RAW_INT_EN BIT(15) +#define THC_M_PRT_INT_EN_FATAL_ERR_INT_EN BIT(16) +#define THC_M_PRT_INT_EN_THC_I2C_IC_RX_UNDER_INT_EN BIT(17) +#define THC_M_PRT_INT_EN_THC_I2C_IC_RX_OVER_INT_EN BIT(18) +#define THC_M_PRT_INT_EN_THC_I2C_IC_RX_FULL_INT_EN BIT(19) +#define THC_M_PRT_INT_EN_THC_I2C_IC_TX_OVER_INT_EN BIT(20) +#define THC_M_PRT_INT_EN_THC_I2C_IC_TX_EMPTY_INT_EN BIT(21) +#define THC_M_PRT_INT_EN_THC_I2C_IC_TX_ABRT_INT_EN BIT(22) +#define THC_M_PRT_INT_EN_THC_I2C_IC_SCL_STUCK_AT_LOW_DET_INT_EN BIT(24) +#define THC_M_PRT_INT_EN_THC_I2C_IC_STOP_DET_INT_EN BIT(25) +#define THC_M_PRT_INT_EN_THC_I2C_IC_START_DET_INT_EN BIT(26) +#define THC_M_PRT_INT_EN_THC_I2C_IC_MST_ON_HOLD_INT_EN BIT(27) +#define THC_M_PRT_INT_EN_TXN_ERR_INT_EN BIT(29) +#define THC_M_PRT_INT_EN_GBL_INT_EN BIT(31) + +#define THC_M_PRT_INT_STATUS_DISP_SYNC_EVT_INT_STS BIT(14) +#define THC_M_PRT_INT_STATUS_DEV_RAW_INT_STS BIT(15) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_UNDER_INT_STS BIT(17) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_OVER_INT_STS BIT(18) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_RX_FULL_INT_STS BIT(19) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_OVER_INT_STS BIT(20) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_EMPTY_INT_STS BIT(21) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_TX_ABRT_INT_STS BIT(22) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_ACTIVITY_INT_STS BIT(23) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_SCL_STUCK_AT_LOW_INT_STS BIT(24) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_STOP_DET_INT_STS BIT(25) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_START_DET_INT_STS BIT(26) +#define THC_M_PRT_INT_STATUS_THC_I2C_IC_MST_ON_HOLD_INT_STS BIT(27) +#define THC_M_PRT_INT_STATUS_TXN_ERR_INT_STS BIT(28) +#define THC_M_PRT_INT_STATUS_FATAL_ERR_INT_STS BIT(30) + +#define THC_M_PRT_ERR_CAUSE_INVLD_DEV_ENTRY BIT(9) +#define THC_M_PRT_ERR_CAUSE_FRAME_BABBLE_ERR BIT(10) +#define THC_M_PRT_ERR_CAUSE_BUF_OVRRUN_ERR BIT(12) +#define THC_M_PRT_ERR_CAUSE_PRD_ENTRY_ERR BIT(13) +#define THC_M_PRT_ERR_CAUSE_FATAL_ERR_CAUSE GENMASK(23, 16) + +#define THC_M_PRT_SW_SEQ_CNTRL_TSSGO BIT(0) +#define THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CD_IE BIT(1) +#define THC_M_PRT_SW_SEQ_CNTRL_THC_SS_CMD GENMASK(15, 8) +#define THC_M_PRT_SW_SEQ_CNTRL_THC_SS_BC GENMASK(31, 16) +#define THC_M_PRT_SW_SEQ_STS_TSSDONE BIT(0) +#define THC_M_PRT_SW_SEQ_STS_THC_SS_ERR BIT(1) +#define THC_M_PRT_SW_SEQ_STS_THC_SS_CIP BIT(3) +#define THC_M_PRT_SW_SEQ_DATA0_ADDR_THC_SW_SEQ_DATA0_ADDR GENMASK(31, 0) +#define THC_M_PRT_SW_SEQ_DATA1_THC_SW_SEQ_DATA1 GENMASK(31, 0) + +#define THC_M_PRT_WPRD_BA_LOW_THC_M_PRT_WPRD_BA_LOW GENMASK(31, 12) +#define THC_M_PRT_WPRD_BA_HI_THC_M_PRT_WPRD_BA_HI GENMASK(31, 0) + +#define THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_START BIT(0) +#define THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_IE_IOC_ERROR BIT(1) +#define THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_IE_IOC BIT(2) +#define THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_IE_IOC_DMACPL BIT(3) +#define THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_UHS BIT(23) +#define THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_PTEC GENMASK(31, 24) + +#define THC_M_PRT_WRITE_INT_STS_THC_WRDMA_CMPL_STATUS BIT(0) +#define THC_M_PRT_WRITE_INT_STS_THC_WRDMA_ERROR_STS BIT(1) +#define THC_M_PRT_WRITE_INT_STS_THC_WRDMA_IOC_STS BIT(2) +#define THC_M_PRT_WRITE_INT_STS_THC_WRDMA_ACTIVE BIT(3) + +#define THC_M_PRT_WR_BULK_ADDR_THC_M_PRT_WR_BULK_ADDR GENMASK(31, 0) + +#define THC_M_PRT_DEV_INT_CAUSE_ADDR_THC_M_PRT_DEV_INT_CAUSE_ADDR GENMASK(31, 0) +#define THC_M_PRT_DEV_INT_CAUSE_REG_VAL_INTERRUPT_TYPE GENMASK(3, 0) +#define THC_M_PRT_DEV_INT_CAUSE_REG_VAL_MICRO_FRAME_SIZE GENMASK(23, 4) +#define THC_M_PRT_DEV_INT_CAUSE_REG_VAL_BEGINNING_OF_FRAME BIT(29) +#define THC_M_PRT_DEV_INT_CAUSE_REG_VAL_END_OF_FRAME BIT(30) +#define THC_M_PRT_DEV_INT_CAUSE_REG_VAL_FRAME_TYPE BIT(31) + +#define THC_M_PRT_TX_FRM_CNT_THC_M_PRT_TX_FRM_CNT GENMASK(30, 0) +#define THC_M_PRT_TX_FRM_CNT_THC_M_PRT_TX_FRM_CNT_RST BIT(31) + +#define THC_M_PRT_TXDMA_PKT_CNT_THC_M_PRT_TXDMA_PKT_CNT GENMASK(30, 0) +#define THC_M_PRT_TXDMA_PKT_CNT_THC_M_PRT_TXDMA_PKT_CNT_RST BIT(31) + +#define THC_M_PRT_DEVINT_CNT_THC_M_PRT_DEVINT_CNT GENMASK(30, 0) +#define THC_M_PRT_DEVINT_CNT_THC_M_PRT_DEVINT_CNT_RST BIT(31) + +#define THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_OFFSET GENMASK(4, 0) +#define THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_LEN GENMASK(9, 5) +#define THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_EOF_OFFSET GENMASK(14, 10) +#define THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_SEND_ICR_US_EN BIT(15) +#define THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_DATA_VAL GENMASK(31, 16) + +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_OFFSET GENMASK(4, 0) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_LEN GENMASK(9, 5) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_UNIT GENMASK(15, 12) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_FTYPE_IGNORE BIT(16) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_FTYPE_VAL BIT(17) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_RXDMA_ADDRINC_DIS BIT(24) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_TXDMA_ADDRINC_DIS BIT(25) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_RXDMA_PKT_STRM_EN BIT(26) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_TXDMA_PKT_STRM_EN BIT(27) +#define THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_DEVINT_POL BIT(28) + +#define THC_M_PRT_RPRD_BA_LOW_1_THC_M_PRT_RPRD_BA_LOW GENMASK(31, 12) +#define THC_M_PRT_RPRD_BA_HI_1_THC_M_PRT_RPRD_BA_HI GENMASK(31, 0) + +#define THC_M_PRT_RPRD_CNTRL_PCD GENMASK(6, 0) +#define THC_M_PRT_RPRD_CNTRL_PTEC GENMASK(15, 8) +#define THC_M_PRT_RPRD_CNTRL_PREFETCH_WM GENMASK(19, 16) + +#define THC_M_PRT_READ_DMA_CNTRL_START BIT(0) +#define THC_M_PRT_READ_DMA_CNTRL_IE_ERROR BIT(1) +#define THC_M_PRT_READ_DMA_CNTRL_IE_IOC BIT(2) +#define THC_M_PRT_READ_DMA_CNTRL_IE_STALL BIT(3) +#define THC_M_PRT_READ_DMA_CNTRL_IE_NDDI BIT(4) +#define THC_M_PRT_READ_DMA_CNTRL_IE_EOF BIT(5) +#define THC_M_PRT_READ_DMA_CNTRL_IE_DMACPL BIT(7) +#define THC_M_PRT_READ_DMA_CNTRL_TPCRP GENMASK(15, 8) +#define THC_M_PRT_READ_DMA_CNTRL_TPCWP GENMASK(23, 16) +#define THC_M_PRT_READ_DMA_CNTRL_INT_SW_DMA_EN BIT(28) +#define THC_M_PRT_READ_DMA_CNTRL_SOO BIT(29) +#define THC_M_PRT_READ_DMA_CNTRL_UHS BIT(30) +#define THC_M_PRT_READ_DMA_CNTRL_TPCPR BIT(31) + +#define THC_M_PRT_READ_DMA_INT_STS_DMACPL_STS BIT(0) +#define THC_M_PRT_READ_DMA_INT_STS_ERROR_STS BIT(1) +#define THC_M_PRT_READ_DMA_INT_STS_IOC_STS BIT(2) +#define THC_M_PRT_READ_DMA_INT_STS_STALL_STS BIT(3) +#define THC_M_PRT_READ_DMA_INT_STS_NONDMA_INT_STS BIT(4) +#define THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS BIT(5) +#define THC_M_PRT_READ_DMA_INT_STS_ACTIVE BIT(8) + +#define THC_M_PRT_READ_DMA_ERR_1_DLERR BIT(0) + +#define THC_M_PRT_GUC_OFFSET_LOW_1_THC_M_PRT_GUC_OFFSET_LOW GENMASK(31, 3) +#define THC_M_PRT_GUC_OFFSET_HI_1_THC_M_PRT_GUC_OFFSET_HI GENMASK(31, 0) +#define THC_M_PRT_GUC_WORKQ_ITEM_SZ_1_WORKQ_ITEM_SZ GENMASK(23, 0) +#define THC_M_PRT_GUC_WORKQ_SZ_1_WORKQ_SZ GENMASK(23, 0) +#define THC_M_PRT_GUC_WORKQ_SZ_1_FCD GENMASK(27, 24) +#define THC_M_PRT_GUC_WORKQ_SZ_1_GIC GENMASK(31, 28) + +#define THC_M_PRT_TSEQ_CNTRL_1_RGD BIT(2) +#define THC_M_PRT_TSEQ_CNTRL_1_EGP BIT(3) +#define THC_M_PRT_TSEQ_CNTRL_1_RTO BIT(4) +#define THC_M_PRT_TSEQ_CNTRL_1_EWOG BIT(5) +#define THC_M_PRT_TSEQ_CNTRL_1_RWOGC BIT(6) +#define THC_M_PRT_TSEQ_CNTRL_1_RX_DATA_FIFO_WR_WM GENMASK(25, 16) +#define THC_M_PRT_TSEQ_CNTRL_1_RESET_PREP_CHICKEN BIT(30) +#define THC_M_PRT_TSEQ_CNTRL_1_INT_EDG_DET_EN BIT(31) + +#define THC_M_PRT_GUC_DB_ADDR_LOW_1_GUC_DB_ADDR_LOW GENMASK(31, 2) +#define THC_M_PRT_GUC_DB_ADDR_HI_1_GUC_DB_ADDR_HI GENMASK(31, 0) +#define THC_M_PRT_GUC_DB_DATA_1_GUC_DB_DATA GENMASK(31, 0) +#define THC_M_PRT_GUC_OFFSET_INITVAL_1_THC_M_PRT_GUC_OFFSET_INITVAL GENMASK(31, 0) + +#define THC_M_PRT_RD_BULK_ADDR_1_THC_M_PRT_RD_BULK_ADDR GENMASK(31, 0) + +#define THC_M_PRT_DB_CNT_1_THC_M_PRT_DB_CNT GENMASK(30, 0) +#define THC_M_PRT_DB_CNT_1_THC_M_PRT_DB_CNT_RST BIT(31) + +#define THC_M_PRT_FRM_CNT_1_THC_M_PRT_FRM_CNT GENMASK(30, 0) +#define THC_M_PRT_FRM_CNT_1_THC_M_PRT_FRM_CNT_RST BIT(31) + +#define THC_M_PRT_UFRM_CNT_1_THC_M_PRT_UFRM_CNT GENMASK(30, 0) +#define THC_M_PRT_UFRM_CNT_1_THC_M_PRT_UFRM_CNT_RST BIT(31) + +#define THC_M_PRT_RXDMA_PKT_CNT_1_THC_M_PRT_RXDMA_PKT_CNT GENMASK(30, 0) +#define THC_M_PRT_RXDMA_PKT_CNT_1_THC_M_PRT_RXDMA_PKT_CNT_RST BIT(31) + +#define THC_M_PRT_SWINT_CNT_1_THC_M_PRT_SWINT_CNT GENMASK(30, 0) +#define THC_M_PRT_SWINT_CNT_1_THC_M_PRT_SWINT_CNT_RST BIT(31) + +#define THC_M_PRT_FRAME_DROP_CNT_1_NOFD GENMASK(30, 0) +#define THC_M_PRT_FRAME_DROP_CNT_1_RFDC BIT(31) + +#define THC_M_PRT_COALESCE_1_COALESCE_TIMEOUT GENMASK(6, 0) + +#define THC_M_PRT_RPRD_BA_LOW_2_THC_M_PRT_RPRD_BA_LOW GENMASK(31, 12) +#define THC_M_PRT_RPRD_BA_HI_2_THC_M_PRT_RPRD_BA_HI GENMASK(31, 0) + +#define THC_M_PRT_READ_DMA_ERR_2_DLERR BIT(0) + +#define THC_M_PRT_GUC_OFFSET_LOW_2_THC_M_PRT_GUC_OFFSET_LOW GENMASK(31, 3) +#define THC_M_PRT_GUC_OFFSET_HI_2_THC_M_PRT_GUC_OFFSET_HI GENMASK(31, 0) + +#define THC_M_PRT_GUC_WORKQ_ITEM_SZ_2_WORKQ_ITEM_SZ GENMASK(23, 0) +#define THC_M_PRT_GUC_WORKQ_SZ_2_WORKQ_SZ GENMASK(23, 0) +#define THC_M_PRT_GUC_WORKQ_SZ_2_FCD GENMASK(27, 24) +#define THC_M_PRT_GUC_WORKQ_SZ_2_GIC GENMASK(31, 28) + +#define THC_M_PRT_TSEQ_CNTRL_2_RGD BIT(2) +#define THC_M_PRT_TSEQ_CNTRL_2_EGP BIT(3) +#define THC_M_PRT_TSEQ_CNTRL_2_RTO BIT(4) + +#define THC_M_PRT_GUC_DB_ADDR_LOW_2_GUC_DB_ADDR_LOW GENMASK(31, 2) +#define THC_M_PRT_GUC_DB_ADDR_HI_2_GUC_DB_ADDR_HI GENMASK(31, 0) + +#define THC_M_PRT_GUC_DB_DATA_2_GUC_DB_DATA GENMASK(31, 0) + +#define THC_M_PRT_GUC_OFFSET_INITVAL_2_THC_M_PRT_GUC_OFFSET_INITVAL GENMASK(31, 0) + +#define THC_M_PRT_RD_BULK_ADDR_2_THC_M_PRT_RD_BULK_ADDR GENMASK(31, 0) + +#define THC_M_PRT_DB_CNT_2_THC_M_PRT_DB_CNT GENMASK(30, 0) +#define THC_M_PRT_DB_CNT_2_THC_M_PRT_DB_CNT_RST BIT(31) + +#define THC_M_PRT_FRM_CNT_2_THC_M_PRT_FRM_CNT GENMASK(30, 0) +#define THC_M_PRT_FRM_CNT_2_THC_M_PRT_FRM_CNT_RST BIT(31) + +#define THC_M_PRT_UFRM_CNT_2_THC_M_PRT_UFRM_CNT GENMASK(30, 0) +#define THC_M_PRT_UFRM_CNT_2_THC_M_PRT_UFRM_CNT_RST BIT(31) + +#define THC_M_PRT_RXDMA_PKT_CNT_2_THC_M_PRT_RXDMA_PKT_CNT GENMASK(30, 0) +#define THC_M_PRT_RXDMA_PKT_CNT_2_THC_M_PRT_RXDMA_PKT_CNT_RST BIT(31) + +#define THC_M_PRT_SWINT_CNT_2_THC_M_PRT_SWINT_CNT GENMASK(30, 0) +#define THC_M_PRT_SWINT_CNT_2_THC_M_PRT_SWINT_CNT_RST BIT(31) + +#define THC_M_PRT_FRAME_DROP_CNT_2_NOFD GENMASK(30, 0) +#define THC_M_PRT_FRAME_DROP_CNT_2_RFDC BIT(31) + +#define THC_M_PRT_COALESCE_2_COALESCE_TIMEOUT GENMASK(6, 0) + +#define THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_THC_I2C_RW_PIO_EN BIT(23) +#define THC_M_PRT_SW_SEQ_I2C_WR_CNTRL_THC_PIO_I2C_WBC GENMASK(31, 26) + +#define THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_RX_DLEN_EN BIT(23) +#define THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC GENMASK(31, 26) + +#define THC_M_PRT_PRD_EMPTY_CNT_1_RPTEC BIT(31) +#define THC_M_PRT_PRD_EMPTY_CNT_2_RPTEC BIT(31) + +#define THC_M_PRT_SW_DMA_PRD_TABLE_LEN_THC_M_PRT_SW_DMA_PRD_TABLE_LEN GENMASK(23, 0) + +#endif /* _INTEL_THC_HW_H_ */ From patchwork Mon Dec 16 01:41:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851906 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2C43F1B808; Mon, 16 Dec 2024 01:42:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313327; cv=none; b=ubv5PddMtaU3nlo4RenXXgxR5IJ2ExXXqYC/YvApTMG6q3WbbSEgMU73IM7L606Ntcw494Vh6fIJGkocrgy/ajZbki0ts7XlbWQOHkrVsZJ18lLLcuKngbqoySFRirPGYKgKvnfbZdUffA9VJXokuNKDlHvqWoMNlhvCIKyJqjQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313327; c=relaxed/simple; bh=bkB5KfX4N3dVo/jfeZRhI61ZERWlhj8TMJWgfWYNi5I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rUjtrySI71okT9gMYZcl4PH2Ah26wbYr5Ndr2hf93fPXvv+C1wZ8Rj/LvHs9kUGBVNV6k5DMs7sbs60O61RfZsHNSnLa9PdXiiX6rFJEY6y973h+PfJZdZIvXMKVUM37bI0HXp86IpjegWC9Zvc65/d3TXMRdlT7/6+eZ3m+G4w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=cQOG3DO4; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="cQOG3DO4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313325; x=1765849325; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bkB5KfX4N3dVo/jfeZRhI61ZERWlhj8TMJWgfWYNi5I=; b=cQOG3DO4GjZvmLpVDXKEEfIneasn37Q9t7L876ywB8FkXhUB9vQyvp12 xYbLHoINB5FA6Hd0D7g1hEN1bNeDuToEmJayRt5FJNz2JRBE36RsWsAlr THdQ6PBAlGvaXLZFL1Tt1RGs4AWtN4A9im516suUO9iZLYoBvw965CAsw R5FvqaAp7Xm0Kb4nG/h2xsAtAhzi2Dsym6mA5/mK09/FfWF6wFnzqp0hp 8MBt+T+6PKwrsLaK9QwcSyjxYISSzKPx5wn/M80gQs/rdATAUnD8Jka+u W5ruFhD2qEm9hamF03VaXejJHJmMD8+351qAwvPDfuG43udTvl7qe85tH w==; X-CSE-ConnectionGUID: zUposm76SsKoTvXE9Vt9Ig== X-CSE-MsgGUID: 7MB9Oc0+TwS3Z0m7N9esAw== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34012971" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34012971" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:04 -0800 X-CSE-ConnectionGUID: NVurgoibRTuyB7r+h/V4Fg== X-CSE-MsgGUID: KmPoTjdCTYGDMyozeedEDg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084189" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:01 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Xinpeng Sun , Even Xu , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 05/22] HID: intel-thc-hid: intel-thc: Add APIs for interrupt Date: Mon, 16 Dec 2024 09:41:10 +0800 Message-Id: <20241216014127.3722172-6-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Xinpeng Sun Add THC interrupt operation interfaces, such as interrupt configure, global interrupt enable/disable, external touch device GPIO interrupt quiesce and unquiesce. Co-developed-by: Even Xu Signed-off-by: Even Xu Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-thc-hid/intel-thc/intel-thc-dev.c | 223 ++++++++++++++++++ .../intel-thc-hid/intel-thc/intel-thc-dev.h | 5 + .../intel-thc-hid/intel-thc/intel-thc-hw.h | 17 ++ 3 files changed, 245 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 397250c38ae7..e16810b2fb9d 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -457,6 +457,229 @@ int thc_tic_pio_write_and_read(struct thc_device *dev, const u32 address, } EXPORT_SYMBOL_NS_GPL(thc_tic_pio_write_and_read, "INTEL_THC"); +/** + * thc_interrupt_config - Configure THC interrupts + * + * @dev: The pointer of THC private device context + */ +void thc_interrupt_config(struct thc_device *dev) +{ + u32 mbits, mask, r_dma_ctrl_1; + + /* Clear Error reporting interrupt status bits */ + mbits = THC_M_PRT_INT_STATUS_TXN_ERR_INT_STS | + THC_M_PRT_INT_STATUS_FATAL_ERR_INT_STS; + regmap_write_bits(dev->thc_regmap, + THC_M_PRT_INT_STATUS_OFFSET, + mbits, mbits); + + /* Enable Error Reporting Interrupts */ + mbits = 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, + mbits, mbits); + + /* Clear PIO Interrupt status bits */ + mbits = 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, + mbits, mbits); + + /* Read Interrupts */ + regmap_read(dev->thc_regmap, + THC_M_PRT_READ_DMA_CNTRL_1_OFFSET, + &r_dma_ctrl_1); + /* Disable RxDMA1 */ + r_dma_ctrl_1 &= ~THC_M_PRT_READ_DMA_CNTRL_IE_EOF; + regmap_write(dev->thc_regmap, + THC_M_PRT_READ_DMA_CNTRL_1_OFFSET, + r_dma_ctrl_1); + + /* Ack EOF Interrupt RxDMA1 */ + mbits = THC_M_PRT_READ_DMA_INT_STS_EOF_INT_STS; + /* Ack NonDMA Interrupt */ + mbits |= THC_M_PRT_READ_DMA_INT_STS_NONDMA_INT_STS; + regmap_write_bits(dev->thc_regmap, + THC_M_PRT_READ_DMA_INT_STS_1_OFFSET, + mbits, mbits); + + /* Ack EOF Interrupt RxDMA2 */ + 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); + + /* Write Interrupts */ + /* Disable TxDMA */ + regmap_write_bits(dev->thc_regmap, + THC_M_PRT_WRITE_DMA_CNTRL_OFFSET, + THC_M_PRT_WRITE_DMA_CNTRL_THC_WRDMA_IE_IOC_DMACPL, + 0); + + /* Clear TxDMA interrupt status bits */ + mbits = THC_M_PRT_WRITE_INT_STS_THC_WRDMA_ERROR_STS; + mbits |= THC_M_PRT_WRITE_INT_STS_THC_WRDMA_IOC_STS; + regmap_write_bits(dev->thc_regmap, + THC_M_PRT_WRITE_INT_STS_OFFSET, + mbits, mbits); + + /* Enable Non-DMA device inband interrupt */ + r_dma_ctrl_1 |= THC_M_PRT_READ_DMA_CNTRL_IE_NDDI; + regmap_write(dev->thc_regmap, + THC_M_PRT_READ_DMA_CNTRL_1_OFFSET, + r_dma_ctrl_1); + + if (dev->port_type == THC_PORT_TYPE_SPI) { + /* Edge triggered interrupt */ + regmap_write_bits(dev->thc_regmap, THC_M_PRT_TSEQ_CNTRL_1_OFFSET, + THC_M_PRT_TSEQ_CNTRL_1_INT_EDG_DET_EN, + THC_M_PRT_TSEQ_CNTRL_1_INT_EDG_DET_EN); + } else { + /* Level triggered interrupt */ + regmap_write_bits(dev->thc_regmap, THC_M_PRT_TSEQ_CNTRL_1_OFFSET, + THC_M_PRT_TSEQ_CNTRL_1_INT_EDG_DET_EN, 0); + + mbits = THC_M_PRT_INT_EN_THC_I2C_IC_MST_ON_HOLD_INT_EN | + THC_M_PRT_INT_EN_THC_I2C_IC_SCL_STUCK_AT_LOW_DET_INT_EN | + THC_M_PRT_INT_EN_THC_I2C_IC_TX_ABRT_INT_EN | + THC_M_PRT_INT_EN_THC_I2C_IC_TX_OVER_INT_EN | + THC_M_PRT_INT_EN_THC_I2C_IC_RX_FULL_INT_EN | + THC_M_PRT_INT_EN_THC_I2C_IC_RX_OVER_INT_EN | + THC_M_PRT_INT_EN_THC_I2C_IC_RX_UNDER_INT_EN; + regmap_write_bits(dev->thc_regmap, THC_M_PRT_INT_EN_OFFSET, + mbits, mbits); + } + + thc_set_pio_interrupt_support(dev, false); + + /* HIDSPI specific settings */ + if (dev->port_type == THC_PORT_TYPE_SPI) { + mbits = FIELD_PREP(THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_OFFSET, + THC_BIT_OFFSET_INTERRUPT_TYPE) | + FIELD_PREP(THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_LEN, + THC_BIT_LENGTH_INTERRUPT_TYPE) | + FIELD_PREP(THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_EOF_OFFSET, + THC_BIT_OFFSET_LAST_FRAGMENT_FLAG) | + FIELD_PREP(THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_DATA_VAL, + THC_BITMASK_INVALID_TYPE_DATA); + mask = THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_OFFSET | + THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_LEN | + THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_EOF_OFFSET | + THC_M_PRT_DEVINT_CFG_1_THC_M_PRT_INTTYP_DATA_VAL; + regmap_write_bits(dev->thc_regmap, THC_M_PRT_DEVINT_CFG_1_OFFSET, + mask, mbits); + + mbits = FIELD_PREP(THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_OFFSET, + THC_BIT_OFFSET_MICROFRAME_SIZE) | + FIELD_PREP(THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_LEN, + THC_BIT_LENGTH_MICROFRAME_SIZE) | + FIELD_PREP(THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_UNIT, + THC_UNIT_MICROFRAME_SIZE) | + THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_FTYPE_IGNORE | + THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_FTYPE_VAL; + mask = THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_OFFSET | + THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_LEN | + THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_UFSIZE_UNIT | + THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_FTYPE_IGNORE | + THC_M_PRT_DEVINT_CFG_2_THC_M_PRT_FTYPE_VAL; + regmap_write_bits(dev->thc_regmap, THC_M_PRT_DEVINT_CFG_2_OFFSET, + mask, mbits); + } +} +EXPORT_SYMBOL_NS_GPL(thc_interrupt_config, "INTEL_THC"); + +/** + * thc_int_trigger_type_select - Select THC interrupt trigger type + * + * @dev: the pointer of THC private device context + * @edge_trigger: determine the interrupt is edge triggered or level triggered + */ +void thc_int_trigger_type_select(struct thc_device *dev, bool edge_trigger) +{ + regmap_write_bits(dev->thc_regmap, THC_M_PRT_TSEQ_CNTRL_1_OFFSET, + THC_M_PRT_TSEQ_CNTRL_1_INT_EDG_DET_EN, + edge_trigger ? THC_M_PRT_TSEQ_CNTRL_1_INT_EDG_DET_EN : 0); +} +EXPORT_SYMBOL_NS_GPL(thc_int_trigger_type_select, "INTEL_THC"); + +/** + * thc_interrupt_enable - Enable or disable THC interrupt + * + * @dev: the pointer of THC private device context + * @int_enable: the flag to control THC interrupt enable or disable + */ +void thc_interrupt_enable(struct thc_device *dev, bool int_enable) +{ + regmap_write_bits(dev->thc_regmap, THC_M_PRT_INT_EN_OFFSET, + THC_M_PRT_INT_EN_GBL_INT_EN, + int_enable ? THC_M_PRT_INT_EN_GBL_INT_EN : 0); +} +EXPORT_SYMBOL_NS_GPL(thc_interrupt_enable, "INTEL_THC"); + +/** + * thc_interrupt_quiesce - Quiesce or unquiesce external touch device interrupt + * + * @dev: the pointer of THC private device context + * @int_quiesce: the flag to determine quiesce or unquiesce device interrupt + * + * Return: 0 on success, other error codes on failed + */ +int thc_interrupt_quiesce(const struct thc_device *dev, bool int_quiesce) +{ + u32 ctrl; + int ret; + + regmap_read(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, &ctrl); + if (!(ctrl & THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_EN) && !int_quiesce) { + dev_warn(dev->dev, "THC interrupt already unquiesce\n"); + return 0; + } + + if ((ctrl & THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_EN) && int_quiesce) { + dev_warn(dev->dev, "THC interrupt already quiesce\n"); + return 0; + } + + /* Quiesce device interrupt - Set quiesce bit and waiting for THC HW to ACK */ + if (int_quiesce) + regmap_write_bits(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, + THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_EN, + THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_EN); + + ret = regmap_read_poll_timeout(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, ctrl, + ctrl & THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_HW_STS, + THC_REGMAP_POLLING_INTERVAL_US, THC_QUIESCE_EN_TIMEOUT_US); + if (ret) { + dev_err_once(dev->dev, + "Timeout while waiting THC idle, target quiesce state = %s\n", + int_quiesce ? "true" : "false"); + return ret; + } + + /* Unquiesce device interrupt - Clear the quiesce bit */ + if (!int_quiesce) + regmap_write_bits(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, + THC_M_PRT_CONTROL_THC_DEVINT_QUIESCE_EN, 0); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(thc_interrupt_quiesce, "INTEL_THC"); + +/** + * thc_set_pio_interrupt_support - Determine PIO interrupt is supported or not + * + * @dev: The pointer of THC private device context + * @supported: The flag to determine enabling PIO interrupt or not + */ +void thc_set_pio_interrupt_support(struct thc_device *dev, bool supported) +{ + dev->pio_int_supported = supported; +} +EXPORT_SYMBOL_NS_GPL(thc_set_pio_interrupt_support, "INTEL_THC"); + MODULE_AUTHOR("Xinpeng Sun "); MODULE_AUTHOR("Even Xu "); diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h index 88a9f606a6a9..bef48c25c195 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h @@ -45,5 +45,10 @@ int thc_tic_pio_write(struct thc_device *dev, const u32 address, int thc_tic_pio_write_and_read(struct thc_device *dev, const u32 address, const u32 write_size, const u32 *write_buffer, const u32 read_size, u32 *actual_size, u32 *read_buffer); +void thc_interrupt_config(struct thc_device *dev); +void thc_int_trigger_type_select(struct thc_device *dev, bool edge_trigger); +void thc_interrupt_enable(struct thc_device *dev, bool int_enable); +void thc_set_pio_interrupt_support(struct thc_device *dev, bool supported); +int thc_interrupt_quiesce(const struct thc_device *dev, bool int_quiesce); #endif /* _INTEL_THC_DEV_H_ */ diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h index 60f5f657be62..093c36fb5e1f 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h @@ -639,6 +639,23 @@ #define THC_REGMAP_POLLING_INTERVAL_US 10 /* 10us */ #define THC_PIO_DONE_TIMEOUT_US USEC_PER_SEC /* 1s */ +/* Default configures for HIDSPI */ +#define THC_BIT_OFFSET_INTERRUPT_TYPE 4 +/* input_report_type is 4 bits for HIDSPI */ +#define THC_BIT_LENGTH_INTERRUPT_TYPE 4 +/* Last fragment indicator is bit 15 for HIDSPI */ +#define THC_BIT_OFFSET_LAST_FRAGMENT_FLAG 22 +#define THC_BIT_OFFSET_MICROFRAME_SIZE 8 +/* input_report_length is 14 bits for HIDSPI */ +#define THC_BIT_LENGTH_MICROFRAME_SIZE 14 +/* MFS unit in power of 2 */ +#define THC_UNIT_MICROFRAME_SIZE 2 +#define THC_BITMASK_INTERRUPT_TYPE_DATA 1 +#define THC_BITMASK_INVALID_TYPE_DATA 2 + +/* Interrupt Quiesce default timeout value */ +#define THC_QUIESCE_EN_TIMEOUT_US USEC_PER_SEC /* 1s */ + /* * THC PIO opcode default value * @THC_PIO_OP_SPI_TIC_READ: THC opcode for SPI PIO read From patchwork Mon Dec 16 01:41:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851905 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6559513A24D; Mon, 16 Dec 2024 01:42:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313334; cv=none; b=koG7uUe2wAUsv3aNtlW8XEchr9xP4xC3uK9/k+qpuIn9029gR1w/v03WDLCxBy9bRqvDuDhL/cLc4Q7SiNHczwn9NSeW5m2i648w2MktvIhBsXR/dpWZxXJYJfucGTzfV03j581EIXeAMrW2AqYZ5nnNu7Pmh1ke9x74RvNwSIo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313334; c=relaxed/simple; bh=eWC65HK46t+PpgXGIHBAgkW5f8olh2v5dxR/WB3uSJk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=trh4xEGSY+Gzfb9CIKIQzc7TYcAu68OOEg7VPQIYmldmnwVVgB1GoG/ZeYvGFo8brjDex/jZgP+iMKC+55QuOwskPO87PjMfPPMZV487mBTVJwguHUUa4F8zxBBHV5Hv3EvvTl9gNS5rTcE9h6F+nbeoOoiud/JEdu8EZv7L6l4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=frheV0Cf; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="frheV0Cf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313332; x=1765849332; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eWC65HK46t+PpgXGIHBAgkW5f8olh2v5dxR/WB3uSJk=; b=frheV0Cf5Zt0bH9nh49JT27m+0V7vhon4IJzFmBUMHGOHRAlSRDH2PhZ yRsGzdeLpdeeIP3vZ7EBDccCusJQie9yv2T2Eh4j8PfGipfzlqJg00jzR lweoAVmW9tHyLg2YXPIpU2bDSVKn02WbgGFHaNossAw6uWEeW330/noKc 8grY/hi0jol4PYmx6FNnIxgcAZR/zrSkHCzqdBQYcTZkrk8Y67AOryTJh i6r038YG3LLT3AhlFEF1a4HcLP03Th7JyzbDwp/FvMitz81wP5+QAiOSA NGTgqU8rPuwyHc8KBlsHdVO6zStlcGJ0AztyKKpTLICaN/+uSjJar5wa9 w==; X-CSE-ConnectionGUID: 2RSKmQjMT7SKcu4x36dYQw== X-CSE-MsgGUID: TMqqPtGIRVK4HweATy1xVw== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34012987" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34012987" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:12 -0800 X-CSE-ConnectionGUID: CbiSibYiRxyT3JiUPPz+Iw== X-CSE-MsgGUID: K/ELDRBCSnq597UjPfklHg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084205" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:08 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Xinpeng Sun , Even Xu , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 07/22] HID: intel-thc-hid: intel-thc: Add THC LTR interfaces Date: Mon, 16 Dec 2024 09:41:12 +0800 Message-Id: <20241216014127.3722172-8-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Xinpeng Sun THC supports LTR configuration and runtimely mode switching. There are two LTR modes: Active LTR and Low Power LTR. THC hardware layer provides APIs for LTR configuration and mode switching. Co-developed-by: Even Xu Signed-off-by: Even Xu Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-thc-hid/intel-thc/intel-thc-dev.c | 114 ++++++++++++++++++ .../intel-thc-hid/intel-thc/intel-thc-dev.h | 3 + .../intel-thc-hid/intel-thc/intel-thc-hw.h | 21 ++++ 3 files changed, 138 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 4cb9ceaf395c..f09832016d9c 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -688,6 +688,120 @@ void thc_set_pio_interrupt_support(struct thc_device *dev, bool supported) } EXPORT_SYMBOL_NS_GPL(thc_set_pio_interrupt_support, "INTEL_THC"); +/** + * thc_ltr_config - Configure THC Latency Tolerance Reporting(LTR) settings + * + * @dev: The pointer of THC private device context + * @active_ltr_us: active LTR value, unit is us + * @lp_ltr_us: low power LTR value, unit is us + */ +void thc_ltr_config(struct thc_device *dev, u32 active_ltr_us, u32 lp_ltr_us) +{ + u32 active_ltr_scale, lp_ltr_scale, ltr_ctrl, ltr_mask, orig, tmp; + + if (active_ltr_us >= THC_LTR_MIN_VAL_SCALE_3 && + active_ltr_us < THC_LTR_MAX_VAL_SCALE_3) { + active_ltr_scale = THC_LTR_SCALE_3; + active_ltr_us = active_ltr_us >> 5; + } else if (active_ltr_us >= THC_LTR_MIN_VAL_SCALE_4 && + active_ltr_us < THC_LTR_MAX_VAL_SCALE_4) { + active_ltr_scale = THC_LTR_SCALE_4; + active_ltr_us = active_ltr_us >> 10; + } else if (active_ltr_us >= THC_LTR_MIN_VAL_SCALE_5 && + active_ltr_us < THC_LTR_MAX_VAL_SCALE_5) { + active_ltr_scale = THC_LTR_SCALE_5; + active_ltr_us = active_ltr_us >> 15; + } else { + active_ltr_scale = THC_LTR_SCALE_2; + } + + if (lp_ltr_us >= THC_LTR_MIN_VAL_SCALE_3 && + lp_ltr_us < THC_LTR_MAX_VAL_SCALE_3) { + lp_ltr_scale = THC_LTR_SCALE_3; + lp_ltr_us = lp_ltr_us >> 5; + } else if (lp_ltr_us >= THC_LTR_MIN_VAL_SCALE_4 && + lp_ltr_us < THC_LTR_MAX_VAL_SCALE_4) { + lp_ltr_scale = THC_LTR_SCALE_4; + lp_ltr_us = lp_ltr_us >> 10; + } else if (lp_ltr_us >= THC_LTR_MIN_VAL_SCALE_5 && + lp_ltr_us < THC_LTR_MAX_VAL_SCALE_5) { + lp_ltr_scale = THC_LTR_SCALE_5; + lp_ltr_us = lp_ltr_us >> 15; + } else { + lp_ltr_scale = THC_LTR_SCALE_2; + } + + regmap_read(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, &orig); + ltr_ctrl = FIELD_PREP(THC_M_CMN_LTR_CTRL_ACT_LTR_VAL, active_ltr_us) | + FIELD_PREP(THC_M_CMN_LTR_CTRL_ACT_LTR_SCALE, active_ltr_scale) | + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ | + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN | + FIELD_PREP(THC_M_CMN_LTR_CTRL_LP_LTR_VAL, lp_ltr_us) | + FIELD_PREP(THC_M_CMN_LTR_CTRL_LP_LTR_SCALE, lp_ltr_scale) | + THC_M_CMN_LTR_CTRL_LP_LTR_REQ; + + ltr_mask = THC_M_CMN_LTR_CTRL_ACT_LTR_VAL | + THC_M_CMN_LTR_CTRL_ACT_LTR_SCALE | + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ | + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN | + THC_M_CMN_LTR_CTRL_LP_LTR_VAL | + THC_M_CMN_LTR_CTRL_LP_LTR_SCALE | + THC_M_CMN_LTR_CTRL_LP_LTR_REQ | + THC_M_CMN_LTR_CTRL_LP_LTR_EN; + + tmp = orig & ~ltr_mask; + tmp |= ltr_ctrl & ltr_mask; + + regmap_write(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, tmp); +} +EXPORT_SYMBOL_NS_GPL(thc_ltr_config, "INTEL_THC"); + +/** + * thc_change_ltr_mode - Change THC LTR mode + * + * @dev: The pointer of THC private device context + * @ltr_mode: LTR mode(active or low power) + */ +void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode) +{ + if (ltr_mode == THC_LTR_MODE_ACTIVE) { + regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, + THC_M_CMN_LTR_CTRL_LP_LTR_EN, 0); + regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN, + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN); + return; + } + + regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN, 0); + regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, + THC_M_CMN_LTR_CTRL_LP_LTR_EN, + THC_M_CMN_LTR_CTRL_LP_LTR_EN); +} +EXPORT_SYMBOL_NS_GPL(thc_change_ltr_mode, "INTEL_THC"); + +/** + * thc_ltr_unconfig - Unconfigure THC Latency Tolerance Reporting(LTR) settings + * + * @dev: The pointer of THC private device context + */ +void thc_ltr_unconfig(struct thc_device *dev) +{ + u32 ltr_ctrl, bits_clear; + + regmap_read(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, <r_ctrl); + bits_clear = THC_M_CMN_LTR_CTRL_LP_LTR_EN | + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN | + THC_M_CMN_LTR_CTRL_LP_LTR_REQ | + THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ; + + ltr_ctrl &= ~bits_clear; + + regmap_write(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, ltr_ctrl); +} +EXPORT_SYMBOL_NS_GPL(thc_ltr_unconfig, "INTEL_THC"); + MODULE_AUTHOR("Xinpeng Sun "); MODULE_AUTHOR("Even Xu "); diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h index f775b972b4f5..c25f2fd57c76 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h @@ -68,5 +68,8 @@ void thc_int_trigger_type_select(struct thc_device *dev, bool edge_trigger); void thc_interrupt_enable(struct thc_device *dev, bool int_enable); void thc_set_pio_interrupt_support(struct thc_device *dev, bool supported); int thc_interrupt_quiesce(const struct thc_device *dev, bool int_quiesce); +void thc_ltr_config(struct thc_device *dev, u32 active_ltr_us, u32 lp_ltr_us); +void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode); +void thc_ltr_unconfig(struct thc_device *dev); #endif /* _INTEL_THC_DEV_H_ */ diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h index 093c36fb5e1f..b646bd3f36b2 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h @@ -656,6 +656,27 @@ /* Interrupt Quiesce default timeout value */ #define THC_QUIESCE_EN_TIMEOUT_US USEC_PER_SEC /* 1s */ +/* LTR definition */ +/* + * THC uses scale to calcualte final LTR value. + * Scale is geometric progression of 2^5 step, starting from 2^0. + * For example, THC_LTR_SCALE_2(2) means 2^(5 * 2) = 1024, unit is ns. + */ +#define THC_LTR_SCALE_0 0 +#define THC_LTR_SCALE_1 1 +#define THC_LTR_SCALE_2 2 +#define THC_LTR_SCALE_3 3 +#define THC_LTR_SCALE_4 4 +#define THC_LTR_SCALE_5 5 +#define THC_LTR_MODE_ACTIVE 0 +#define THC_LTR_MODE_LP 1 +#define THC_LTR_MIN_VAL_SCALE_3 BIT(10) +#define THC_LTR_MAX_VAL_SCALE_3 BIT(15) +#define THC_LTR_MIN_VAL_SCALE_4 BIT(15) +#define THC_LTR_MAX_VAL_SCALE_4 BIT(20) +#define THC_LTR_MIN_VAL_SCALE_5 BIT(20) +#define THC_LTR_MAX_VAL_SCALE_5 BIT(25) + /* * THC PIO opcode default value * @THC_PIO_OP_SPI_TIC_READ: THC opcode for SPI PIO read From patchwork Mon Dec 16 01:41:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851904 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A62A143C7E; Mon, 16 Dec 2024 01:42:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313341; cv=none; b=FBNk9cjiIekJFF5Oa/VF5RlW0kVVIPBgaZW3gqevzfZxPw4rzgtTlAGTzpvseWjFnhnHw3Eub+qdxva/KS7UAkF8MADmBqvmTjy/fQItg6QTaR/NaJErHAJckXxwqBZeOoXrhU4qgQd2hz1sFmp5lBaQ0AEQ4axWpd1sB/OPDpw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313341; c=relaxed/simple; bh=TnVsvJo8d7n1aOM7V/uzi8BrC/rYINH/ifokjnrAXdo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=S6E5iXtPID8gMCggAfFeu0NAimYTmiTMY/SW96akBIaRIaox1eR8F6nK6qDxdXkqUp4wAujJh1344EnR62VjC06aZcOoTF8Z5YSoc7jmhpY53dmhIKo916A0NrHNaiwDpf1oNiqs40OwXSFobfw5GDXd2KbmAczkDZu1tV7yH8s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=KPj6g/fI; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="KPj6g/fI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313339; x=1765849339; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TnVsvJo8d7n1aOM7V/uzi8BrC/rYINH/ifokjnrAXdo=; b=KPj6g/fIiomVmtjTZLxjYj1sLHwm8vB5W32GFvZWtyztFOxLdOA5Wmtt ToDghlsM63UcV0BNfvJsSzBgQvZDPJfyJEy5mlgXSkvypIi70VBKAuch6 0yAnwl5ijYFuCUcs3YvTd50HYsrIkyd9R4SRd9OCks+QqVQVIygbUaiFR Cc7yGfHGQ58Jny9FhSt6QsoLtbBDUS3n5f+E8hJLdocseOKJwmosNXOAA DT78c92uZYGboWcD2/QiicBywthOqsreBj/Ma9r0QZeQVF2rr7reD2wT9 ++cqWgwvEtHjUhb5JCX5cl5AR8+OwsXQyIMNf51F+G3vlaCBsbDzkdmrq Q==; X-CSE-ConnectionGUID: lbZKK4fTStSF5XrdIr8JZg== X-CSE-MsgGUID: zXJoj73uQjWXCQnrc9aFmA== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013001" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013001" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:19 -0800 X-CSE-ConnectionGUID: J2kewpmqTkWEe3d7hIAzTw== X-CSE-MsgGUID: gqNfPAgFRQOOjLPYCKBZxg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084215" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:15 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Xinpeng Sun , Even Xu , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 09/22] HID: intel-thc-hid: intel-thc: Add THC SPI config interfaces Date: Mon, 16 Dec 2024 09:41:14 +0800 Message-Id: <20241216014127.3722172-10-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Xinpeng Sun Add SPI bus related APIs to configure SPI operation parameters, such as port type, bus frequency, bus IO mode, read/write OPcode, and slave register addresses. Co-developed-by: Even Xu Signed-off-by: Even Xu Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-thc-hid/intel-thc/intel-thc-dev.c | 229 ++++++++++++++++++ .../intel-thc-hid/intel-thc/intel-thc-dev.h | 7 + .../intel-thc-hid/intel-thc/intel-thc-hw.h | 52 ++++ 3 files changed, 288 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 99dbaeef041c..8a439eb120b5 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -1061,6 +1061,235 @@ int thc_interrupt_handler(struct thc_device *dev) } EXPORT_SYMBOL_NS_GPL(thc_interrupt_handler, "INTEL_THC"); +/** + * thc_port_select - Set THC port type + * + * @dev: The pointer of THC private device context + * @port_type: THC port type to use for current device + * + * Return: 0 on success, other error codes on failed. + */ +int thc_port_select(struct thc_device *dev, enum thc_port_type port_type) +{ + u32 ctrl, mask; + + if (port_type == THC_PORT_TYPE_SPI) { + dev_dbg(dev->dev, "Set THC port type to SPI\n"); + dev->port_type = THC_PORT_TYPE_SPI; + + /* Enable delay of CS assertion and set to default value */ + ctrl = THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_EN | + FIELD_PREP(THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_VAL, + THC_CSA_CK_DELAY_VAL_DEFAULT); + mask = THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_EN | + THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_VAL; + regmap_write_bits(dev->thc_regmap, THC_M_PRT_SPI_DUTYC_CFG_OFFSET, + mask, ctrl); + } else if (port_type == THC_PORT_TYPE_I2C) { + dev_dbg(dev->dev, "Set THC port type to I2C\n"); + dev->port_type = THC_PORT_TYPE_I2C; + + /* Set THC transition arbitration policy to frame boundary for I2C */ + ctrl = FIELD_PREP(THC_M_PRT_CONTROL_THC_ARB_POLICY, + THC_ARB_POLICY_FRAME_BOUNDARY); + mask = THC_M_PRT_CONTROL_THC_ARB_POLICY; + + regmap_write_bits(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, mask, ctrl); + } else { + dev_err(dev->dev, "unsupported THC port type: %d\n", port_type); + return -EINVAL; + } + + ctrl = FIELD_PREP(THC_M_PRT_CONTROL_PORT_TYPE, port_type); + mask = THC_M_PRT_CONTROL_PORT_TYPE; + + regmap_write_bits(dev->thc_regmap, THC_M_PRT_CONTROL_OFFSET, mask, ctrl); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(thc_port_select, "INTEL_THC"); + +#define THC_SPI_FREQUENCY_7M 7812500 +#define THC_SPI_FREQUENCY_15M 15625000 +#define THC_SPI_FREQUENCY_17M 17857100 +#define THC_SPI_FREQUENCY_20M 20833000 +#define THC_SPI_FREQUENCY_25M 25000000 +#define THC_SPI_FREQUENCY_31M 31250000 +#define THC_SPI_FREQUENCY_41M 41666700 + +#define THC_SPI_LOW_FREQUENCY THC_SPI_FREQUENCY_17M + +static u8 thc_get_spi_freq_div_val(struct thc_device *dev, u32 spi_freq_val) +{ + int frequency[] = { + THC_SPI_FREQUENCY_7M, + THC_SPI_FREQUENCY_15M, + THC_SPI_FREQUENCY_17M, + THC_SPI_FREQUENCY_20M, + THC_SPI_FREQUENCY_25M, + THC_SPI_FREQUENCY_31M, + THC_SPI_FREQUENCY_41M, + }; + u8 frequency_div[] = { + THC_SPI_FRQ_DIV_2, + THC_SPI_FRQ_DIV_1, + THC_SPI_FRQ_DIV_7, + THC_SPI_FRQ_DIV_6, + THC_SPI_FRQ_DIV_5, + THC_SPI_FRQ_DIV_4, + THC_SPI_FRQ_DIV_3, + }; + int size = ARRAY_SIZE(frequency); + u32 closest_freq; + u8 freq_div; + int i; + + for (i = size - 1; i >= 0; i--) + if ((int)spi_freq_val - frequency[i] >= 0) + break; + + if (i < 0) { + dev_err_once(dev->dev, "Not supported SPI frequency %d\n", spi_freq_val); + return THC_SPI_FRQ_RESERVED; + } + + closest_freq = frequency[i]; + freq_div = frequency_div[i]; + + dev_dbg(dev->dev, + "Setting SPI frequency: spi_freq_val = %u, Closest freq = %u\n", + spi_freq_val, closest_freq); + + return freq_div; +} + +/** + * thc_spi_read_config - Configure SPI bus read attributes + * + * @dev: The pointer of THC private device context + * @spi_freq_val: SPI read frequecy value + * @io_mode: SPI read IO mode + * @opcode: Read opcode + * @spi_rd_mps: SPI read max packet size + * + * Return: 0 on success, other error codes on failed. + */ +int thc_spi_read_config(struct thc_device *dev, u32 spi_freq_val, + u32 io_mode, u32 opcode, u32 spi_rd_mps) +{ + bool is_low_freq = false; + u32 cfg, mask; + u8 freq_div; + + freq_div = thc_get_spi_freq_div_val(dev, spi_freq_val); + if (freq_div == THC_SPI_FRQ_RESERVED) + return -EINVAL; + + if (spi_freq_val < THC_SPI_LOW_FREQUENCY) + is_low_freq = true; + + cfg = FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TCRF, freq_div) | + FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TRMODE, io_mode) | + (is_low_freq ? THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN : 0) | + FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_RD_MPS, spi_rd_mps); + mask = THC_M_PRT_SPI_CFG_SPI_TCRF | + THC_M_PRT_SPI_CFG_SPI_TRMODE | + THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN | + THC_M_PRT_SPI_CFG_SPI_RD_MPS; + + regmap_write_bits(dev->thc_regmap, + THC_M_PRT_SPI_CFG_OFFSET, mask, cfg); + + if (io_mode == THC_QUAD_IO) + opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO, opcode); + else if (io_mode == THC_DUAL_IO) + opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO, opcode); + else + opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_SIO, opcode); + + regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, opcode); + regmap_write(dev->thc_regmap, THC_M_PRT_SPI_DMARD_OPCODE_OFFSET, opcode); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(thc_spi_read_config, "INTEL_THC"); + +/** + * thc_spi_write_config - Configure SPI bus write attributes + * + * @dev: The pointer of THC private device context + * @spi_freq_val: SPI write frequecy value + * @io_mode: SPI write IO mode + * @opcode: Write opcode + * @spi_wr_mps: SPI write max packet size + * @perf_limit: Performance limitation in unit of 10us + * + * Return: 0 on success, other error codes on failed. + */ +int thc_spi_write_config(struct thc_device *dev, u32 spi_freq_val, + u32 io_mode, u32 opcode, u32 spi_wr_mps, + u32 perf_limit) +{ + bool is_low_freq = false; + u32 cfg, mask; + u8 freq_div; + + freq_div = thc_get_spi_freq_div_val(dev, spi_freq_val); + if (freq_div == THC_SPI_FRQ_RESERVED) + return -EINVAL; + + if (spi_freq_val < THC_SPI_LOW_FREQUENCY) + is_low_freq = true; + + cfg = FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TCWF, freq_div) | + FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_TWMODE, io_mode) | + (is_low_freq ? THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN : 0) | + FIELD_PREP(THC_M_PRT_SPI_CFG_SPI_WR_MPS, spi_wr_mps); + mask = THC_M_PRT_SPI_CFG_SPI_TCWF | + THC_M_PRT_SPI_CFG_SPI_TWMODE | + THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN | + THC_M_PRT_SPI_CFG_SPI_WR_MPS; + + regmap_write_bits(dev->thc_regmap, + THC_M_PRT_SPI_CFG_OFFSET, mask, cfg); + + if (io_mode == THC_QUAD_IO) + opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO, opcode); + else if (io_mode == THC_DUAL_IO) + opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO, opcode); + else + opcode = FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_SPI_SIO, opcode); + + regmap_write(dev->thc_regmap, THC_M_PRT_SPI_WR_OPCODE_OFFSET, opcode); + + dev->perf_limit = perf_limit; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(thc_spi_write_config, "INTEL_THC"); + +/** + * thc_spi_input_output_address_config - Configure SPI input and output addresses + * + * @dev: the pointer of THC private device context + * @input_hdr_addr: input report header address + * @input_bdy_addr: input report body address + * @output_addr: output report address + */ +void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_addr, + u32 input_bdy_addr, u32 output_addr) +{ + regmap_write(dev->thc_regmap, + THC_M_PRT_DEV_INT_CAUSE_ADDR_OFFSET, input_hdr_addr); + regmap_write(dev->thc_regmap, + THC_M_PRT_RD_BULK_ADDR_1_OFFSET, input_bdy_addr); + regmap_write(dev->thc_regmap, + THC_M_PRT_RD_BULK_ADDR_2_OFFSET, input_bdy_addr); + regmap_write(dev->thc_regmap, + THC_M_PRT_WR_BULK_ADDR_OFFSET, output_addr); +} +EXPORT_SYMBOL_NS_GPL(thc_spi_input_output_address_config, "INTEL_THC"); + MODULE_AUTHOR("Xinpeng Sun "); MODULE_AUTHOR("Even Xu "); diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h index d34fab243fdc..925355f19bae 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h @@ -98,5 +98,12 @@ void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode); void thc_ltr_unconfig(struct thc_device *dev); u32 thc_int_cause_read(struct thc_device *dev); int thc_interrupt_handler(struct thc_device *dev); +int thc_port_select(struct thc_device *dev, enum thc_port_type port_type); +int thc_spi_read_config(struct thc_device *dev, u32 spi_freq_val, + u32 io_mode, u32 opcode, u32 spi_rd_mps); +int thc_spi_write_config(struct thc_device *dev, u32 spi_freq_val, + u32 io_mode, u32 opcode, u32 spi_wr_mps, u32 perf_limit); +void thc_spi_input_output_address_config(struct thc_device *dev, u32 input_hdr_addr, + u32 input_bdy_addr, u32 output_addr); #endif /* _INTEL_THC_DEV_H_ */ diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h index b646bd3f36b2..efa028560d2a 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h @@ -636,6 +636,20 @@ #define THC_M_PRT_SW_DMA_PRD_TABLE_LEN_THC_M_PRT_SW_DMA_PRD_TABLE_LEN GENMASK(23, 0) +#define THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_VAL GENMASK(3, 0) +#define THC_M_PRT_SPI_DUTYC_CFG_SPI_CSA_CK_DELAY_EN BIT(25) + +/* CS Assertion delay default value */ +#define THC_CSA_CK_DELAY_VAL_DEFAULT 4 + +/* ARB policy definition */ +/* Arbiter switches on packet boundary */ +#define THC_ARB_POLICY_PACKET_BOUNDARY 0 +/* Arbiter switches on Micro Frame boundary */ +#define THC_ARB_POLICY_UFRAME_BOUNDARY 1 +/* Arbiter switches on Frame boundary */ +#define THC_ARB_POLICY_FRAME_BOUNDARY 2 + #define THC_REGMAP_POLLING_INTERVAL_US 10 /* 10us */ #define THC_PIO_DONE_TIMEOUT_US USEC_PER_SEC /* 1s */ @@ -697,4 +711,42 @@ enum thc_pio_opcode { THC_PIO_OP_I2C_TIC_WRITE_AND_READ = 0x1C, }; +/** + * THC SPI IO mode + * @THC_SINGLE_IO: single IO mode, 1(opcode) - 1(address) - 1(data) + * @THC_DUAL_IO: dual IO mode, 1(opcode) - 2(address) - 2(data) + * @THC_QUAD_IO: quad IO mode, 1(opcode) - 4(address) - 4(data) + * @THC_QUAD_PARALLEL_IO: parallel quad IO mode, 4(opcode) - 4(address) - 4(data) + */ +enum thc_spi_iomode { + THC_SINGLE_IO = 0, + THC_DUAL_IO = 1, + THC_QUAD_IO = 2, + THC_QUAD_PARALLEL_IO = 3, +}; + +/** + * THC SPI frequency divider + * + * This DIV final value is determined by THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN bit. + * If THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN isn't be set, THC takes the DIV value directly; + * If THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN is set, THC takes the DIV value multiply by 8. + * + * For example, if THC input clock is 125MHz: + * When THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN isn't set, THC_SPI_FRQ_DIV_3 means DIV is 3, + * THC final clock is 125 / 3 = 41.667MHz; + * When THC_M_PRT_SPI_CFG_SPI_LOW_FREQ_EN is set, THC_SPI_FRQ_DIV_3 means DIV is 3 * 8, + * THC final clock is 125 / (3 * 8) = 5.208MHz; + */ +enum thc_spi_frq_div { + THC_SPI_FRQ_RESERVED = 0, + THC_SPI_FRQ_DIV_1 = 1, + THC_SPI_FRQ_DIV_2 = 2, + THC_SPI_FRQ_DIV_3 = 3, + THC_SPI_FRQ_DIV_4 = 4, + THC_SPI_FRQ_DIV_5 = 5, + THC_SPI_FRQ_DIV_6 = 6, + THC_SPI_FRQ_DIV_7 = 7, +}; + #endif /* _INTEL_THC_HW_H_ */ From patchwork Mon Dec 16 01:41:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851903 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E11981494A3; Mon, 16 Dec 2024 01:42:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313348; cv=none; b=kftB7PV4Yu4Ld6eUhqze+eydRt4KfTr+9oVTO89AlLeMqrYLrnpU62mXuzN8F1b2ISaLT4lwuVDhXegeboW0eXD8qMZsowAPEu/teE7DEsuXDJGB2iZHHu2jaVw2n0VGxCqj0s9VRbDH5lgU5Lt5DUr2nkxAu8K3ZJffcruIuEc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313348; c=relaxed/simple; bh=iHJdamAnrpQ+H7wwOnYxSgdjMoZ1XJyQc7bG4fkrrHI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=s16BL1x44psj1gyvxDfqJ2tGMABak30uw2I9CIzu1eLmfaXLD+Zn4lm9r7fMpx9BNTaIc2oXHK0OFNu6HoFCXVlKMffPyTsLSUuCtSrVCU8uTDVzzVMX4wfFE/VtwTiTc0GIciduDYOVLbUzvYQ3mlF01+VE/NJIP5F4WUxCV28= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=GX4BQEhI; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="GX4BQEhI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313347; x=1765849347; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iHJdamAnrpQ+H7wwOnYxSgdjMoZ1XJyQc7bG4fkrrHI=; b=GX4BQEhILQC5zXsUFRjwfpAWY6RwWdf1fQffOSNgItf5VVduXA0wnX4V 61oHv4NGUIimVYWWsc7kBhsKBw4vMHXwyKl65JcJGiAj85jyNBbJbwRTq 8KEj0wMqEGDZHY9/IH+irUBz1ca3oT9VkpaDJdG4LuPUZWg1ONDmj/6l7 IVNNMpszH8jqdN++Y1XWXAu9uSI6pwIH+cokTX6DhwKIk4HRb7QeUGosT At3PcULr2rcbe35YZRINor8QXI5EhbQFs4tVoobM3P+oRFi5zFM9s0/ZL ChiaxpBtVDohZTvwicVwIkkyxU0DaxRaEjwUyo+Gx43VTM5fFzPLQBo55 w==; X-CSE-ConnectionGUID: IsT5Yj1NRtigmzyUGpU58w== X-CSE-MsgGUID: xfihLOuRR8S4D8Njkb5Rog== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013018" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013018" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:26 -0800 X-CSE-ConnectionGUID: nNxn33lcRwm4/S2RNNCFig== X-CSE-MsgGUID: oRF9a0hlQdSTZAVzPQH7/g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084223" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:23 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Xinpeng Sun , Even Xu , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 11/22] HID: intel-thc-hid: intel-quickspi: Add THC QuickSPI driver skeleton Date: Mon, 16 Dec 2024 09:41:16 +0800 Message-Id: <20241216014127.3722172-12-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Xinpeng Sun Create intel-quickspi folder and add Kconfig and Makefile for THC QuickSPI driver. Add basic device structure, definitions and probe/remove functions for QuickSPI driver. Co-developed-by: Even Xu Signed-off-by: Even Xu Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- drivers/hid/intel-thc-hid/Kconfig | 11 + drivers/hid/intel-thc-hid/Makefile | 3 + .../intel-quickspi/pci-quickspi.c | 287 ++++++++++++++++++ .../intel-quickspi/quickspi-dev.h | 61 ++++ 4 files changed, 362 insertions(+) create mode 100644 drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c create mode 100644 drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h diff --git a/drivers/hid/intel-thc-hid/Kconfig b/drivers/hid/intel-thc-hid/Kconfig index dc7c5a23f0ad..25a3729df92a 100644 --- a/drivers/hid/intel-thc-hid/Kconfig +++ b/drivers/hid/intel-thc-hid/Kconfig @@ -17,4 +17,15 @@ config INTEL_THC_HID Say Y/M here if you want to support Intel THC. If unsure, say N. +config INTEL_QUICKSPI + tristate "Intel QuickSPI driver based on Intel Touch Host Controller" + depends on INTEL_THC_HID + help + Intel QuickSPI, based on Touch Host Controller (THC), implements + HIDSPI (HID over SPI) protocol. It configures THC to work at SPI + mode, and controls THC hardware sequencer to accelerate HIDSPI + transaction flow. + + Say Y/M here if you want to support Intel QuickSPI. If unsure, say N. + endmenu diff --git a/drivers/hid/intel-thc-hid/Makefile b/drivers/hid/intel-thc-hid/Makefile index b9709cc5e9eb..7669739a39b7 100644 --- a/drivers/hid/intel-thc-hid/Makefile +++ b/drivers/hid/intel-thc-hid/Makefile @@ -9,4 +9,7 @@ obj-$(CONFIG_INTEL_THC_HID) += intel-thc.o intel-thc-objs += intel-thc/intel-thc-dev.o intel-thc-objs += intel-thc/intel-thc-dma.o +obj-$(CONFIG_INTEL_QUICKSPI) += intel-quickspi.o +intel-quickspi-objs += intel-quickspi/pci-quickspi.o + ccflags-y += -I $(src)/intel-thc diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c new file mode 100644 index 000000000000..a997c9a570d4 --- /dev/null +++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2024 Intel Corporation */ + +#include +#include +#include +#include +#include +#include + +#include "intel-thc-dev.h" + +#include "quickspi-dev.h" + +struct quickspi_driver_data mtl = { + .max_packet_size_value = MAX_PACKET_SIZE_VALUE_MTL, +}; + +struct quickspi_driver_data lnl = { + .max_packet_size_value = MAX_PACKET_SIZE_VALUE_LNL, +}; + +struct quickspi_driver_data ptl = { + .max_packet_size_value = MAX_PACKET_SIZE_VALUE_LNL, +}; + +/** + * quickspi_irq_quick_handler - The ISR of the quickspi driver + * + * @irq: The irq number + * @dev_id: pointer to the device structure + * + * Return: IRQ_WAKE_THREAD if further process needed. + */ +static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id) +{ + struct quickspi_device *qsdev = dev_id; + + if (qsdev->state == QUICKSPI_DISABLED) + return IRQ_HANDLED; + + /* Disable THC interrupt before current interrupt be handled */ + thc_interrupt_enable(qsdev->thc_hw, false); + + return IRQ_WAKE_THREAD; +} + +/** + * quickspi_irq_thread_handler - IRQ thread handler of quickspi driver + * + * @irq: The IRQ number + * @dev_id: pointer to the quickspi device structure + * + * Return: IRQ_HANDLED to finish this handler. + */ +static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id) +{ + struct quickspi_device *qsdev = dev_id; + int int_mask; + + if (qsdev->state == QUICKSPI_DISABLED) + return IRQ_HANDLED; + + int_mask = thc_interrupt_handler(qsdev->thc_hw); + + thc_interrupt_enable(qsdev->thc_hw, true); + + return IRQ_HANDLED; +} + +/** + * quickspi_dev_init - Initialize quickspi device + * + * @pdev: pointer to the thc pci device + * @mem_addr: The pointer of MMIO memory address + * @id: point to pci_device_id structure + * + * Alloc quickspi device structure and initialized THC device, + * then configure THC to HIDSPI mode. + * + * If success, enable THC hardware interrupt. + * + * Return: pointer to the quickspi device structure if success + * or NULL on failed. + */ +static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __iomem *mem_addr, + const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct quickspi_device *qsdev; + int ret; + + qsdev = devm_kzalloc(dev, sizeof(struct quickspi_device), GFP_KERNEL); + if (!qsdev) + return ERR_PTR(-ENOMEM); + + qsdev->pdev = pdev; + qsdev->dev = dev; + qsdev->mem_addr = mem_addr; + qsdev->driver_data = (struct quickspi_driver_data *)id->driver_data; + + /* thc hw init */ + qsdev->thc_hw = thc_dev_init(qsdev->dev, qsdev->mem_addr); + if (IS_ERR(qsdev->thc_hw)) { + ret = PTR_ERR(qsdev->thc_hw); + dev_err(dev, "Failed to initialize THC device context, ret = %d.\n", ret); + return ERR_PTR(ret); + } + + ret = thc_port_select(qsdev->thc_hw, THC_PORT_TYPE_SPI); + if (ret) { + dev_err(dev, "Failed to select THC port, ret = %d.\n", ret); + return ERR_PTR(ret); + } + + thc_interrupt_config(qsdev->thc_hw); + + thc_interrupt_enable(qsdev->thc_hw, true); + + return qsdev; +} + +/** + * quickspi_dev_deinit - De-initialize quickspi device + * + * @qsdev: pointer to the quickspi device structure + * + * Disable THC interrupt and deinitilize THC. + */ +static void quickspi_dev_deinit(struct quickspi_device *qsdev) +{ + thc_interrupt_enable(qsdev->thc_hw, false); +} + +/* + * quickspi_probe: Quickspi driver probe function + * + * @pdev: point to pci device + * @id: point to pci_device_id structure + * + * Return 0 if success or error code on failure. + */ +static int quickspi_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct quickspi_device *qsdev; + void __iomem *mem_addr; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to enable PCI device, ret = %d.\n", ret); + return ret; + } + + pci_set_master(pdev); + + ret = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); + if (ret) { + dev_err(&pdev->dev, "Failed to get PCI regions, ret = %d.\n", ret); + goto disable_pci_device; + } + + mem_addr = pcim_iomap_table(pdev)[0]; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration %d\n", ret); + goto unmap_io_region; + } + } + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) { + dev_err(&pdev->dev, + "Failed to allocate IRQ vectors. ret = %d\n", ret); + goto unmap_io_region; + } + + pdev->irq = pci_irq_vector(pdev, 0); + + qsdev = quickspi_dev_init(pdev, mem_addr, id); + if (IS_ERR(qsdev)) { + dev_err(&pdev->dev, "QuickSPI device init failed\n"); + ret = PTR_ERR(qsdev); + goto unmap_io_region; + } + + pci_set_drvdata(pdev, qsdev); + + ret = devm_request_threaded_irq(&pdev->dev, pdev->irq, + quickspi_irq_quick_handler, + quickspi_irq_thread_handler, + IRQF_ONESHOT, KBUILD_MODNAME, + qsdev); + if (ret) { + dev_err(&pdev->dev, + "Failed to request threaded IRQ, irq = %d.\n", pdev->irq); + goto dev_deinit; + } + + return 0; + +dev_deinit: + quickspi_dev_deinit(qsdev); +unmap_io_region: + pcim_iounmap_regions(pdev, BIT(0)); +disable_pci_device: + pci_clear_master(pdev); + + return ret; +} + +/** + * quickspi_remove - Device Removal Routine + * + * @pdev: PCI device structure + * + * This is called by the PCI subsystem to alert the driver + * that it should release a PCI device. + */ +static void quickspi_remove(struct pci_dev *pdev) +{ + struct quickspi_device *qsdev; + + qsdev = pci_get_drvdata(pdev); + if (!qsdev) + return; + + quickspi_dev_deinit(qsdev); + + pcim_iounmap_regions(pdev, BIT(0)); + pci_clear_master(pdev); +} + +/** + * quickspi_shutdown - Device Shutdown Routine + * + * @pdev: PCI device structure + * + * This is called from the reboot notifier + * it's a simplified version of remove so we go down + * faster. + */ +static void quickspi_shutdown(struct pci_dev *pdev) +{ + struct quickspi_device *qsdev; + + qsdev = pci_get_drvdata(pdev); + if (!qsdev) + return; + + quickspi_dev_deinit(qsdev); +} + +static const struct pci_device_id quickspi_pci_tbl[] = { + {PCI_DEVICE_DATA(INTEL, THC_MTL_DEVICE_ID_SPI_PORT1, &mtl), }, + {PCI_DEVICE_DATA(INTEL, THC_MTL_DEVICE_ID_SPI_PORT2, &mtl), }, + {PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_SPI_PORT1, &lnl), }, + {PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_SPI_PORT2, &lnl), }, + {PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_SPI_PORT1, &ptl), }, + {PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_SPI_PORT2, &ptl), }, + {PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_SPI_PORT1, &ptl), }, + {PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_SPI_PORT2, &ptl), }, + {} +}; +MODULE_DEVICE_TABLE(pci, quickspi_pci_tbl); + +static struct pci_driver quickspi_driver = { + .name = KBUILD_MODNAME, + .id_table = quickspi_pci_tbl, + .probe = quickspi_probe, + .remove = quickspi_remove, + .shutdown = quickspi_shutdown, + .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, +}; + +module_pci_driver(quickspi_driver); + +MODULE_AUTHOR("Xinpeng Sun "); +MODULE_AUTHOR("Even Xu "); + +MODULE_DESCRIPTION("Intel(R) QuickSPI Driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("INTEL_THC"); diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h new file mode 100644 index 000000000000..cffc859efa19 --- /dev/null +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2024 Intel Corporation */ + +#ifndef _QUICKSPI_DEV_H_ +#define _QUICKSPI_DEV_H_ + +#define PCI_DEVICE_ID_INTEL_THC_MTL_DEVICE_ID_SPI_PORT1 0x7E49 +#define PCI_DEVICE_ID_INTEL_THC_MTL_DEVICE_ID_SPI_PORT2 0x7E4B +#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_SPI_PORT1 0xA849 +#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_SPI_PORT2 0xA84B +#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT1 0xE349 +#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT2 0xE34B +#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT1 0xE449 +#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT2 0xE44B + +/* Packet size value, the unit is 16 bytes */ +#define DEFAULT_MIN_PACKET_SIZE_VALUE 4 +#define MAX_PACKET_SIZE_VALUE_MTL 128 +#define MAX_PACKET_SIZE_VALUE_LNL 256 + +enum quickspi_dev_state { + QUICKSPI_NONE, + QUICKSPI_RESETING, + QUICKSPI_RESETED, + QUICKSPI_INITED, + QUICKSPI_ENABLED, + QUICKSPI_DISABLED, +}; + +/** + * struct quickspi_driver_data - Driver specific data for quickspi device + * @max_packet_size_value: identify max packet size, unit is 16 bytes + */ +struct quickspi_driver_data { + u32 max_packet_size_value; +}; + +struct device; +struct pci_dev; +struct thc_device; + +/** + * struct quickspi_device - THC QuickSpi device struct + * @dev: point to kernel device + * @pdev: point to PCI device + * @thc_hw: point to THC device + * @driver_data: point to quickspi specific driver data + * @state: THC SPI device state + * @mem_addr: MMIO memory address + */ +struct quickspi_device { + struct device *dev; + struct pci_dev *pdev; + struct thc_device *thc_hw; + struct quickspi_driver_data *driver_data; + enum quickspi_dev_state state; + + void __iomem *mem_addr; +}; + +#endif /* _QUICKSPI_DEV_H_ */ From patchwork Mon Dec 16 01:41:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851902 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A6B974315D; Mon, 16 Dec 2024 01:42:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313355; cv=none; b=f6+YG4PSH84QASUChulog2J4ZIgni1xWgRLcMymKeMxbn/LsOcN6kMl8ocmv91V0z1Fcb+aZjb2cBq2ete3d8pce4yvgiVSip7VTdgVpdz/rB9l18odeu0WuiveEAbILOORxUkZTenqlUQpLbCVR30eAUFD3pIHv28GdLjyOAyM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313355; c=relaxed/simple; bh=NizAkAjCliMZjjKT2vdtFZZ7fpcmd9qrcq2URA+7tNA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=f+7L4EP0WqT/5HbbesGYaY0MdZUqlPXfrGGJV32grTWjJFKbJhGHKAJXqZV7NzR3Ecoo9R2XVmOk9YzE6zId5/pI+qbplxOBRLnnAxdRmJiRgrb8rbuFUlnBT77+nQjV8wCYDuSg1QjOghucjuRgLIeOn1QbN2CFAkS4RQzsomE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=G7BdH6uO; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="G7BdH6uO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313353; x=1765849353; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NizAkAjCliMZjjKT2vdtFZZ7fpcmd9qrcq2URA+7tNA=; b=G7BdH6uO+1Uij/4KbiR5MU841M0JKdp9OE9kCRY7L0N303xbebPWw3sq GtKcscmeliGB1BoVID+eGoOTZv1SQIqevlKhlGUfznDyrD1ckTPMuEMqg HYkmY6ClJs33TrqN26vjADmVjxtC641Gs4yWQLPENRIr2GwSRzKYBV+Ph UnDqCBY2ODZcP/SW+qiPg5BVCELdCvf9Gmj2RC++Fb4RP5izeBMEwEnjv DbPE/y/vhSyqG0r5y4J3NImPAlqHgVXSznJQ/OvmmgQaby3kbS6OFu8p8 RyViqxvu5YTFUpUNaVBtNOcu71GpDVz3GRNOhHB8N5Be1xOSTb97hZ6D1 g==; X-CSE-ConnectionGUID: DFv4MzmqTlq87NdkPsRtTA== X-CSE-MsgGUID: unuzshDlRGGyVE/tLc/rAg== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013038" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013038" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:33 -0800 X-CSE-ConnectionGUID: eiU59gPBRHyLIRglK9Y3xg== X-CSE-MsgGUID: 8ZhUFPHkSYi8qE7jgHmZQQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084233" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:30 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Even Xu , Xinpeng Sun , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 13/22] HID: intel-thc-hid: intel-quickspi: Add THC QuickSPI ACPI interfaces Date: Mon, 16 Dec 2024 09:41:18 +0800 Message-Id: <20241216014127.3722172-14-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add functions to query QuickSPI ACPI DSD parameters and provide APIs for DSM method accessing. Co-developed-by: Xinpeng Sun Signed-off-by: Xinpeng Sun Signed-off-by: Even Xu Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-quickspi/pci-quickspi.c | 189 ++++++++++++++++++ .../intel-quickspi/quickspi-dev.h | 54 +++++ 2 files changed, 243 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c index a997c9a570d4..7df2d00c3b22 100644 --- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c +++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2024 Intel Corporation */ +#include +#include #include #include #include @@ -9,6 +11,7 @@ #include #include "intel-thc-dev.h" +#include "intel-thc-hw.h" #include "quickspi-dev.h" @@ -24,6 +27,186 @@ struct quickspi_driver_data ptl = { .max_packet_size_value = MAX_PACKET_SIZE_VALUE_LNL, }; +/* THC QuickSPI ACPI method to get device properties */ +/* HIDSPI Method: {6e2ac436-0fcf-41af-a265-b32a220dcfab} */ +static guid_t hidspi_guid = + GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, + 0x22, 0x0d, 0xcf, 0xab); + +/* QuickSpi Method: {300D35b7-ac20-413e-8e9c-92e4dafd0afe} */ +static guid_t thc_quickspi_guid = + GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, + 0xda, 0xfd, 0x0a, 0xfe); + +/* Platform Method: {84005682-5b71-41a4-0x8d668130f787a138} */ +static guid_t thc_platform_guid = + GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, + 0xf7, 0x87, 0xa1, 0x38); + +/** + * thc_acpi_get_property - Query device ACPI parameter + * + * @adev: point to ACPI device + * @guid: ACPI method's guid + * @rev: ACPI method's revision + * @func: ACPI method's function number + * @type: ACPI parameter's data type + * @prop_buf: point to return buffer + * + * This is a helper function for device to query its ACPI parameters. + * + * Return: 0 if successful or ENODEV on failed. + */ +static int thc_acpi_get_property(struct acpi_device *adev, const guid_t *guid, + u64 rev, u64 func, acpi_object_type type, void *prop_buf) +{ + acpi_handle handle = acpi_device_handle(adev); + union acpi_object *obj; + + obj = acpi_evaluate_dsm_typed(handle, guid, rev, func, NULL, type); + if (!obj) { + acpi_handle_err(handle, + "Error _DSM call failed, rev: %llu, func: %llu, type: %u\n", + rev, func, type); + return -ENODEV; + } + + if (type == ACPI_TYPE_INTEGER) + *(u32 *)prop_buf = (u32)obj->integer.value; + else if (type == ACPI_TYPE_BUFFER) + memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length); + + ACPI_FREE(obj); + + return 0; +} + +/** + * quickspi_get_acpi_resources - Query all quickspi devices' ACPI parameters + * + * @qsdev: point to quickspi device + * + * This function gets all quickspi devices' ACPI resource. + * + * Return: 0 if successful or error code on failed. + */ +static int quickspi_get_acpi_resources(struct quickspi_device *qsdev) +{ + struct acpi_device *adev = ACPI_COMPANION(qsdev->dev); + int ret = -EINVAL; + + if (!adev) { + dev_err(qsdev->dev, "no valid ACPI companion\n"); + return ret; + } + + qsdev->acpi_dev = adev; + + ret = thc_acpi_get_property(adev, &hidspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_HDR_ADDR, + ACPI_TYPE_INTEGER, + &qsdev->input_report_hdr_addr); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &hidspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_BDY_ADDR, + ACPI_TYPE_INTEGER, + &qsdev->input_report_bdy_addr); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &hidspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_OUTPUT_REP_ADDR, + ACPI_TYPE_INTEGER, + &qsdev->output_report_addr); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &hidspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_READ_OPCODE, + ACPI_TYPE_BUFFER, + &qsdev->spi_read_opcode); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &hidspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_WRITE_OPCODE, + ACPI_TYPE_BUFFER, + &qsdev->spi_write_opcode); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &hidspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_IO_MODE, + ACPI_TYPE_INTEGER, + &qsdev->spi_read_io_mode); + if (ret) + return ret; + + if (qsdev->spi_read_io_mode & SPI_WRITE_IO_MODE) + qsdev->spi_write_io_mode = FIELD_GET(SPI_IO_MODE_OPCODE, qsdev->spi_read_io_mode); + else + qsdev->spi_write_io_mode = THC_SINGLE_IO; + + qsdev->spi_read_io_mode = FIELD_GET(SPI_IO_MODE_OPCODE, qsdev->spi_read_io_mode); + + ret = thc_acpi_get_property(adev, &thc_quickspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_CONNECTION_SPEED, + ACPI_TYPE_INTEGER, + &qsdev->spi_freq_val); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &thc_quickspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_LIMIT_PACKET_SIZE, + ACPI_TYPE_INTEGER, + &qsdev->limit_packet_size); + if (ret) + return ret; + + if (qsdev->limit_packet_size || !qsdev->driver_data) + qsdev->spi_packet_size = DEFAULT_MIN_PACKET_SIZE_VALUE; + else + qsdev->spi_packet_size = qsdev->driver_data->max_packet_size_value; + + ret = thc_acpi_get_property(adev, &thc_quickspi_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_PERFORMANCE_LIMIT, + ACPI_TYPE_INTEGER, + &qsdev->performance_limit); + if (ret) + return ret; + + qsdev->performance_limit = FIELD_GET(PERFORMANCE_LIMITATION, qsdev->performance_limit); + + ret = thc_acpi_get_property(adev, &thc_platform_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_ACTIVE_LTR, + ACPI_TYPE_INTEGER, + &qsdev->active_ltr_val); + if (ret) + return ret; + + ret = thc_acpi_get_property(adev, &thc_platform_guid, + ACPI_QUICKSPI_REVISION_NUM, + ACPI_QUICKSPI_FUNC_NUM_LP_LTR, + ACPI_TYPE_INTEGER, + &qsdev->low_power_ltr_val); + if (ret) + return ret; + + return 0; +} + /** * quickspi_irq_quick_handler - The ISR of the quickspi driver * @@ -113,6 +296,12 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io return ERR_PTR(ret); } + ret = quickspi_get_acpi_resources(qsdev); + if (ret) { + dev_err(dev, "Get ACPI resources failed, ret = %d\n", ret); + return ERR_PTR(ret); + } + thc_interrupt_config(qsdev->thc_hw); thc_interrupt_enable(qsdev->thc_hw, true); diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h index 335b32363d7f..deb24dd1a0fa 100644 --- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h @@ -15,6 +15,28 @@ #define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT1 0xE449 #define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT2 0xE44B +/* HIDSPI special ACPI parameters DSM methods */ +#define ACPI_QUICKSPI_REVISION_NUM 2 +#define ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_HDR_ADDR 1 +#define ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_BDY_ADDR 2 +#define ACPI_QUICKSPI_FUNC_NUM_OUTPUT_REP_ADDR 3 +#define ACPI_QUICKSPI_FUNC_NUM_READ_OPCODE 4 +#define ACPI_QUICKSPI_FUNC_NUM_WRITE_OPCODE 5 +#define ACPI_QUICKSPI_FUNC_NUM_IO_MODE 6 + +/* QickSPI device special ACPI parameters DSM methods */ +#define ACPI_QUICKSPI_FUNC_NUM_CONNECTION_SPEED 1 +#define ACPI_QUICKSPI_FUNC_NUM_LIMIT_PACKET_SIZE 2 +#define ACPI_QUICKSPI_FUNC_NUM_PERFORMANCE_LIMIT 3 + +/* Platform special ACPI parameters DSM methods */ +#define ACPI_QUICKSPI_FUNC_NUM_ACTIVE_LTR 1 +#define ACPI_QUICKSPI_FUNC_NUM_LP_LTR 2 + +#define SPI_WRITE_IO_MODE BIT(13) +#define SPI_IO_MODE_OPCODE GENMASK(15, 14) +#define PERFORMANCE_LIMITATION GENMASK(15, 0) + /* Packet size value, the unit is 16 bytes */ #define DEFAULT_MIN_PACKET_SIZE_VALUE 4 #define MAX_PACKET_SIZE_VALUE_MTL 128 @@ -41,6 +63,7 @@ struct device; struct pci_dev; struct thc_device; struct hid_device; +struct acpi_device; /** * struct quickspi_device - THC QuickSpi device struct @@ -48,10 +71,26 @@ struct hid_device; * @pdev: point to PCI device * @thc_hw: point to THC device * @hid_dev: point to hid device + * @acpi_dev: point to ACPI device * @driver_data: point to quickspi specific driver data * @state: THC SPI device state * @mem_addr: MMIO memory address * @dev_desc: device descriptor for HIDSPI protocol + * @input_report_hdr_addr: device input report header address + * @input_report_bdy_addr: device input report body address + * @output_report_bdy_addr: device output report address + * @spi_freq_val: device supported max SPI frequnecy, in Hz + * @spi_read_io_mode: device supported SPI read io mode + * @spi_write_io_mode: device supported SPI write io mode + * @spi_read_opcode: device read opcode + * @spi_write_opcode: device write opcode + * @limit_packet_size: 1 - limit read/write packet to 64Bytes + * 0 - device no packet size limiation for read/write + * @performance_limit: delay time, in ms. + * if device has performance limitation, must give a delay + * before write operation after a read operation. + * @active_ltr_val: THC active LTR value + * @low_power_ltr_val: THC low power LTR value * @report_descriptor: store a copy of device report descriptor */ struct quickspi_device { @@ -59,12 +98,27 @@ struct quickspi_device { struct pci_dev *pdev; struct thc_device *thc_hw; struct hid_device *hid_dev; + struct acpi_device *acpi_dev; struct quickspi_driver_data *driver_data; enum quickspi_dev_state state; void __iomem *mem_addr; struct hidspi_dev_descriptor dev_desc; + u32 input_report_hdr_addr; + u32 input_report_bdy_addr; + u32 output_report_addr; + u32 spi_freq_val; + u32 spi_read_io_mode; + u32 spi_write_io_mode; + u32 spi_read_opcode; + u32 spi_write_opcode; + u32 limit_packet_size; + u32 spi_packet_size; + u32 performance_limit; + + u32 active_ltr_val; + u32 low_power_ltr_val; u8 *report_descriptor; }; From patchwork Mon Dec 16 01:41:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851901 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F28C17993; Mon, 16 Dec 2024 01:42:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313363; cv=none; b=TWx8Pp/8QJfh3w6qCSxgWmvya+TWgzWq/NNG1wSgQTiTtrHQhnTX1iPd6Tj9VY7GHDWHtWIwCNxxAi0tQ/6LM7gSCMAxCXVSuL20usTqVJ9pY5XopghgkLza60EmuK3gayPLCTY8XbFAflCOX68/SpWYhnzIX45TJGX0xenHND8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313363; c=relaxed/simple; bh=buwyFcRe1RIIS/GIfTDyDJm1tk3mDSIeGXRUKau2De4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=eVHWmHHarpbkWEY0j/RJh/im/vwGdlh1uIGudWKp0QrDJqKBWSBCaj7nEqyjjpYwnDwOnEeuj5wQuhAyLEm2ZkRoB8VoG81gPX955XAA1Lhr4qdhSP0dJFwkerZ5d85kgR+hVqp1tn5dx03mvE43R3DLQPKxMapsTLCzJfDize4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=oDL3dQqF; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="oDL3dQqF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313361; x=1765849361; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=buwyFcRe1RIIS/GIfTDyDJm1tk3mDSIeGXRUKau2De4=; b=oDL3dQqFamypw25yFRu4eLQB+IF6KbXaFOWmLjZsZRbS27F1V3wtzAeQ Swun0R9cNYt/RlAdBIiECOBvj7318ZLMvVipYUn/sHr6fMSqNGTmeCyb9 XTomdbfQNsueXCSsqQZ2K8FYc7FhBXuprfwR7XSXHHqI+0RqYwwLr36mM 080W4lmLlj1lWr6h3ty5xDM9+1TMZsRcUVys45CA0jimfDi3tITWOJNfr eCljSiBSzTpsTc/c/38JV335bezg0xXAgCl4FD8tU6h8Ebwr58YqNUD/F 2QGOqvLGkd0UuIi+bzcUg6zxLI57aM7tsfE4inUUGg4rpz75RYl/Z7JZs Q==; X-CSE-ConnectionGUID: 6YQ13YMMSB2WdGzSDrZGsw== X-CSE-MsgGUID: yiNimbFHQIKrIrH6ThfMQA== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013068" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013068" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:41 -0800 X-CSE-ConnectionGUID: Ls0c5yDXRIqdMfxIcuEbUw== X-CSE-MsgGUID: Islsm5JDRcOSoRzQUlML9A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084244" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:37 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Xinpeng Sun , Even Xu , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 15/22] HID: intel-thc-hid: intel-quickspi: Complete THC QuickSPI driver Date: Mon, 16 Dec 2024 09:41:20 +0800 Message-Id: <20241216014127.3722172-16-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Xinpeng Sun Fully implement QuickSPI driver probe/remove callbacks, interrupt handler, integrate HIDSPI protocol, enumerate HID device and register HID device. Co-developed-by: Even Xu Signed-off-by: Even Xu Signed-off-by: Xinpeng Sun Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-quickspi/pci-quickspi.c | 265 ++++++++++++++++++ .../intel-quickspi/quickspi-protocol.c | 3 + 2 files changed, 268 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c index 7df2d00c3b22..cc92e1a30411 100644 --- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c +++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c @@ -14,6 +14,8 @@ #include "intel-thc-hw.h" #include "quickspi-dev.h" +#include "quickspi-hid.h" +#include "quickspi-protocol.h" struct quickspi_driver_data mtl = { .max_packet_size_value = MAX_PACKET_SIZE_VALUE_MTL, @@ -228,6 +230,37 @@ static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +/** + * try_recover - Try to recovery THC and Device + * @qsdev: pointer to quickspi device + * + * This function is a error handler, called when fatal error happens. + * It try to reset Touch Device and re-configure THC to recovery + * transferring between Device and THC. + * + * Return: 0 if successful or error code on failed. + */ +static int try_recover(struct quickspi_device *qsdev) +{ + int ret; + + ret = reset_tic(qsdev); + if (ret) { + dev_err(qsdev->dev, "Reset touch device failed, ret = %d\n", ret); + return ret; + } + + thc_dma_unconfigure(qsdev->thc_hw); + + ret = thc_dma_configure(qsdev->thc_hw); + if (ret) { + dev_err(qsdev->dev, "Re-configure THC DMA failed, ret = %d\n", ret); + return ret; + } + + return 0; +} + /** * quickspi_irq_thread_handler - IRQ thread handler of quickspi driver * @@ -239,15 +272,52 @@ static irqreturn_t quickspi_irq_quick_handler(int irq, void *dev_id) static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id) { struct quickspi_device *qsdev = dev_id; + size_t input_len; + int read_finished = 0; + int err_recover = 0; int int_mask; + int ret; if (qsdev->state == QUICKSPI_DISABLED) return IRQ_HANDLED; int_mask = thc_interrupt_handler(qsdev->thc_hw); + if (int_mask & BIT(THC_FATAL_ERR_INT) || int_mask & BIT(THC_TXN_ERR_INT)) { + err_recover = 1; + goto end; + } + + if (int_mask & BIT(THC_NONDMA_INT)) { + if (qsdev->state == QUICKSPI_RESETING) { + qsdev->reset_ack = true; + wake_up_interruptible(&qsdev->reset_ack_wq); + } else { + qsdev->nondma_int_received = true; + wake_up_interruptible(&qsdev->nondma_int_received_wq); + } + } + + if (int_mask & BIT(THC_RXDMA2_INT)) { + while (!read_finished) { + ret = thc_rxdma_read(qsdev->thc_hw, THC_RXDMA2, qsdev->input_buf, + &input_len, &read_finished); + if (ret) { + err_recover = 1; + goto end; + } + + quickspi_handle_input_data(qsdev, input_len); + } + } + +end: thc_interrupt_enable(qsdev->thc_hw, true); + if (err_recover) + if (try_recover(qsdev)) + qsdev->state = QUICKSPI_DISABLED; + return IRQ_HANDLED; } @@ -280,8 +350,15 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io qsdev->pdev = pdev; qsdev->dev = dev; qsdev->mem_addr = mem_addr; + qsdev->state = QUICKSPI_DISABLED; qsdev->driver_data = (struct quickspi_driver_data *)id->driver_data; + init_waitqueue_head(&qsdev->reset_ack_wq); + init_waitqueue_head(&qsdev->nondma_int_received_wq); + init_waitqueue_head(&qsdev->report_desc_got_wq); + init_waitqueue_head(&qsdev->get_report_cmpl_wq); + init_waitqueue_head(&qsdev->set_report_cmpl_wq); + /* thc hw init */ qsdev->thc_hw = thc_dev_init(qsdev->dev, qsdev->mem_addr); if (IS_ERR(qsdev->thc_hw)) { @@ -290,6 +367,10 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io return ERR_PTR(ret); } + ret = thc_interrupt_quiesce(qsdev->thc_hw, true); + if (ret) + return ERR_PTR(ret); + ret = thc_port_select(qsdev->thc_hw, THC_PORT_TYPE_SPI); if (ret) { dev_err(dev, "Failed to select THC port, ret = %d.\n", ret); @@ -302,10 +383,43 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io return ERR_PTR(ret); } + /* THC config for input/output address */ + thc_spi_input_output_address_config(qsdev->thc_hw, + qsdev->input_report_hdr_addr, + qsdev->input_report_bdy_addr, + qsdev->output_report_addr); + + /* THC config for spi read operation */ + ret = thc_spi_read_config(qsdev->thc_hw, qsdev->spi_freq_val, + qsdev->spi_read_io_mode, + qsdev->spi_read_opcode, + qsdev->spi_packet_size); + if (ret) { + dev_err(dev, "thc_spi_read_config failed, ret = %d\n", ret); + return ERR_PTR(ret); + } + + /* THC config for spi write operation */ + ret = thc_spi_write_config(qsdev->thc_hw, qsdev->spi_freq_val, + qsdev->spi_write_io_mode, + qsdev->spi_write_opcode, + qsdev->spi_packet_size, + qsdev->performance_limit); + if (ret) { + dev_err(dev, "thc_spi_write_config failed, ret = %d\n", ret); + return ERR_PTR(ret); + } + + thc_ltr_config(qsdev->thc_hw, + qsdev->active_ltr_val, + qsdev->low_power_ltr_val); + thc_interrupt_config(qsdev->thc_hw); thc_interrupt_enable(qsdev->thc_hw, true); + qsdev->state = QUICKSPI_INITED; + return qsdev; } @@ -319,6 +433,103 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io static void quickspi_dev_deinit(struct quickspi_device *qsdev) { thc_interrupt_enable(qsdev->thc_hw, false); + thc_ltr_unconfig(qsdev->thc_hw); + + qsdev->state = QUICKSPI_DISABLED; +} + +/** + * quickspi_dma_init - Configure THC DMA for quickspi device + * @qsdev: pointer to the quickspi device structure + * + * This function uses TIC's parameters(such as max input length, max output + * length) to allocate THC DMA buffers and configure THC DMA engines. + * + * Return: 0 if successful or error code on failed. + */ +static int quickspi_dma_init(struct quickspi_device *qsdev) +{ + int ret; + + ret = thc_dma_set_max_packet_sizes(qsdev->thc_hw, 0, + le16_to_cpu(qsdev->dev_desc.max_input_len), + le16_to_cpu(qsdev->dev_desc.max_output_len), + 0); + if (ret) + return ret; + + ret = thc_dma_allocate(qsdev->thc_hw); + if (ret) { + dev_err(qsdev->dev, "Allocate THC DMA buffer failed, ret = %d\n", ret); + return ret; + } + + /* Enable RxDMA */ + ret = thc_dma_configure(qsdev->thc_hw); + if (ret) { + dev_err(qsdev->dev, "Configure THC DMA failed, ret = %d\n", ret); + thc_dma_unconfigure(qsdev->thc_hw); + thc_dma_release(qsdev->thc_hw); + return ret; + } + + return ret; +} + +/** + * quickspi_dma_deinit - Release THC DMA for quickspi device + * @qsdev: pointer to the quickspi device structure + * + * Stop THC DMA engines and release all DMA buffers. + * + */ +static void quickspi_dma_deinit(struct quickspi_device *qsdev) +{ + thc_dma_unconfigure(qsdev->thc_hw); + thc_dma_release(qsdev->thc_hw); +} + +/** + * quickspi_alloc_report_buf - Alloc report buffers + * @qsdev: pointer to the quickspi device structure + * + * Allocate report descriptor buffer, it will be used for restore TIC HID + * report descriptor. + * + * Allocate input report buffer, it will be used for receive HID input report + * data from TIC. + * + * Allocate output report buffer, it will be used for store HID output report, + * such as set feature. + * + * Return: 0 if successful or error code on failed. + */ +static int quickspi_alloc_report_buf(struct quickspi_device *qsdev) +{ + size_t max_report_len; + size_t max_input_len; + + qsdev->report_descriptor = devm_kzalloc(qsdev->dev, + le16_to_cpu(qsdev->dev_desc.rep_desc_len), + GFP_KERNEL); + if (!qsdev->report_descriptor) + return -ENOMEM; + + max_input_len = max(le16_to_cpu(qsdev->dev_desc.rep_desc_len), + le16_to_cpu(qsdev->dev_desc.max_input_len)); + + qsdev->input_buf = devm_kzalloc(qsdev->dev, max_input_len, GFP_KERNEL); + if (!qsdev->input_buf) + return -ENOMEM; + + max_report_len = max(le16_to_cpu(qsdev->dev_desc.max_output_len), + le16_to_cpu(qsdev->dev_desc.max_input_len)); + + qsdev->report_buf = devm_kzalloc(qsdev->dev, max_report_len, GFP_KERNEL); + if (!qsdev->report_buf) + return -ENOMEM; + + return 0; } /* @@ -327,6 +538,18 @@ static void quickspi_dev_deinit(struct quickspi_device *qsdev) * @pdev: point to pci device * @id: point to pci_device_id structure * + * This function initializes THC and HIDSPI device, the flow is: + * - do THC pci device initialization + * - query HIDSPI ACPI parameters + * - configure THC to HIDSPI mode + * - go through HIDSPI enumeration flow + * |- reset HIDSPI device + * |- read device descriptor + * - enable THC interrupt and DMA + * - read report descriptor + * - register HID device + * - enable runtime power management + * * Return 0 if success or error code on failure. */ static int quickspi_probe(struct pci_dev *pdev, @@ -390,8 +613,44 @@ static int quickspi_probe(struct pci_dev *pdev, goto dev_deinit; } + ret = reset_tic(qsdev); + if (ret) { + dev_err(&pdev->dev, "Reset Touch Device failed, ret = %d\n", ret); + goto dev_deinit; + } + + ret = quickspi_alloc_report_buf(qsdev); + if (ret) { + dev_err(&pdev->dev, "Alloc report buffers failed, ret= %d\n", ret); + goto dev_deinit; + } + + ret = quickspi_dma_init(qsdev); + if (ret) { + dev_err(&pdev->dev, "Setup THC DMA failed, ret= %d\n", ret); + goto dev_deinit; + } + + ret = quickspi_get_report_descriptor(qsdev); + if (ret) { + dev_err(&pdev->dev, "Get report descriptor failed, ret = %d\n", ret); + goto dma_deinit; + } + + ret = quickspi_hid_probe(qsdev); + if (ret) { + dev_err(&pdev->dev, "Failed to register HID device, ret = %d\n", ret); + goto dma_deinit; + } + + qsdev->state = QUICKSPI_ENABLED; + + dev_dbg(&pdev->dev, "QuickSPI probe success\n"); + return 0; +dma_deinit: + quickspi_dma_deinit(qsdev); dev_deinit: quickspi_dev_deinit(qsdev); unmap_io_region: @@ -418,6 +677,9 @@ static void quickspi_remove(struct pci_dev *pdev) if (!qsdev) return; + quickspi_hid_remove(qsdev); + quickspi_dma_deinit(qsdev); + quickspi_dev_deinit(qsdev); pcim_iounmap_regions(pdev, BIT(0)); @@ -441,6 +703,9 @@ static void quickspi_shutdown(struct pci_dev *pdev) if (!qsdev) return; + /* Must stop DMA before reboot to avoid DMA entering into unknown state */ + quickspi_dma_deinit(qsdev); + quickspi_dev_deinit(qsdev); } diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c index b575d3311e61..f23461ac4787 100644 --- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-protocol.c @@ -220,6 +220,9 @@ void quickspi_handle_input_data(struct quickspi_device *qsdev, u32 buf_len) break; case DATA: + if (qsdev->state != QUICKSPI_ENABLED) + return; + if (input_len > le16_to_cpu(qsdev->dev_desc.max_input_len)) { dev_err_once(qsdev->dev, "Unexpected too large input report length: %u\n", input_len); From patchwork Mon Dec 16 01:41:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851900 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A437E1CEE8A; Mon, 16 Dec 2024 01:42:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313371; cv=none; b=QcJ3AL031d0oHr7GkfJ8e9bu4LjMk7vgMQRWbzxtGuzIt0AlsXYbqgLUs4KBZnOTHsw4STTCivwr5hL1Z4+PB7vLrOhnY5cZ1ZjGecqvpZIDtflTDyiNWldWGlwClc7hsnnTKX7Jv4rYMEj44B4lq95BDizZ+oTbS46N2M+srXE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313371; c=relaxed/simple; bh=bKp/0fwGGGoM8Omj5SQhW4rHR2g7TAuijByxCFAXtbs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=cTJ5oIcC6DCv8naD3p+0RRSx5EGughzJ3puXWjZkQxsvnn/ARkLVMAllFkB3Br0m5MgXJMc3kqYuZLohs6cZHxXGmqZMZOJWZ8njU4t1oxk2mSXw0AtLleNBS5F3b/crPE+rT4iczrnvQurdrPkaWgdcSRdgsFob3RYszYSHSuU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Jp+hZzmz; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Jp+hZzmz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313368; x=1765849368; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bKp/0fwGGGoM8Omj5SQhW4rHR2g7TAuijByxCFAXtbs=; b=Jp+hZzmzcsWzYAfREPi7SdE3xFhckHRrciXBhdoKKF0Awro6Eqb3iWMg qtLnhKSEiCRHFuEQ1jCZ/t2qBMalsRJARdWHgQjmgH5X8TnC6Kh3nq2SR O1F8xYS7za0Lvku/ypJTuJVbQPakzGPQBg+wS+eAG9nRo13wDCE9FHuzj ZykNFyE5Ibyov7nxHpsQKvgzx3YoqnuI5AKKyaIZAveg+g+CGacOKD6+V POzXkNGNU1KF33T8mcku4yatvO5+sb3HzwrMtlxnSksgycTAjN+oZwLc1 1BKo7qRBstZTengKv2EPra6NuqkhcCvEcIM3rk4AXpRDjRPkRQ7r6rr0J g==; X-CSE-ConnectionGUID: H4D99PamQq2lCfqrAOxC0g== X-CSE-MsgGUID: kIrF0LiiRrmHVtnqmEyiEg== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013106" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013106" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:48 -0800 X-CSE-ConnectionGUID: puOqPSPsRyS5CG3VKQHK5A== X-CSE-MsgGUID: 3Db/MuuiS/Kd24ADYWUFHA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084262" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:45 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Even Xu , Xinpeng Sun , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 17/22] HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C driver skeleton Date: Mon, 16 Dec 2024 09:41:22 +0800 Message-Id: <20241216014127.3722172-18-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Create intel-quicki2c folder and add Kconfig and Makefile for THC QuickI2C driver. Add basic device structure, definitions and probe/remove functions for QuickI2C driver. Co-developed-by: Xinpeng Sun Signed-off-by: Xinpeng Sun Signed-off-by: Even Xu Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- drivers/hid/intel-thc-hid/Kconfig | 11 + drivers/hid/intel-thc-hid/Makefile | 3 + .../intel-quicki2c/pci-quicki2c.c | 270 ++++++++++++++++++ .../intel-quicki2c/quicki2c-dev.h | 48 ++++ 4 files changed, 332 insertions(+) create mode 100644 drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c create mode 100644 drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h diff --git a/drivers/hid/intel-thc-hid/Kconfig b/drivers/hid/intel-thc-hid/Kconfig index 25a3729df92a..84c2db881bf4 100644 --- a/drivers/hid/intel-thc-hid/Kconfig +++ b/drivers/hid/intel-thc-hid/Kconfig @@ -28,4 +28,15 @@ config INTEL_QUICKSPI Say Y/M here if you want to support Intel QuickSPI. If unsure, say N. +config INTEL_QUICKI2C + tristate "Intel QuickI2C driver based on Intel Touch Host Controller" + depends on INTEL_THC_HID + help + Intel QuickI2C, uses Touch Host Controller (THC) hardware, implements + HIDI2C (HID over I2C) protocol. It configures THC to work in I2C + mode, and controls THC hardware sequencer to accelerate HIDI2C + transaction flow. + + Say Y/M here if you want to support Intel QuickI2C. If unsure, say N. + endmenu diff --git a/drivers/hid/intel-thc-hid/Makefile b/drivers/hid/intel-thc-hid/Makefile index 2dba4db70c33..4d4f02e1c415 100644 --- a/drivers/hid/intel-thc-hid/Makefile +++ b/drivers/hid/intel-thc-hid/Makefile @@ -14,4 +14,7 @@ intel-quickspi-objs += intel-quickspi/pci-quickspi.o intel-quickspi-objs += intel-quickspi/quickspi-hid.o intel-quickspi-objs += intel-quickspi/quickspi-protocol.o +obj-$(CONFIG_INTEL_QUICKI2C) += intel-quicki2c.o +intel-quicki2c-objs += intel-quicki2c/pci-quicki2c.o + ccflags-y += -I $(src)/intel-thc diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c new file mode 100644 index 000000000000..3919ae3e1400 --- /dev/null +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2024 Intel Corporation */ + +#include +#include +#include +#include +#include +#include + +#include "intel-thc-dev.h" + +#include "quicki2c-dev.h" + +/** + * quicki2c_irq_quick_handler - The ISR of the quicki2c driver + * + * @irq: The irq number + * @dev_id: pointer to the device structure + * + * Return: IRQ_WAKE_THREAD if further process needed. + */ +static irqreturn_t quicki2c_irq_quick_handler(int irq, void *dev_id) +{ + struct quicki2c_device *qcdev = dev_id; + + if (qcdev->state == QUICKI2C_DISABLED) + return IRQ_HANDLED; + + /* Disable THC interrupt before current interrupt be handled */ + thc_interrupt_enable(qcdev->thc_hw, false); + + return IRQ_WAKE_THREAD; +} + +/** + * quicki2c_irq_thread_handler - IRQ thread handler of quicki2c driver + * + * @irq: The IRQ number + * @dev_id: pointer to the quicki2c device structure + * + * Return: IRQ_HANDLED to finish this handler. + */ +static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id) +{ + struct quicki2c_device *qcdev = dev_id; + int int_mask; + + if (qcdev->state == QUICKI2C_DISABLED) + return IRQ_HANDLED; + + int_mask = thc_interrupt_handler(qcdev->thc_hw); + + thc_interrupt_enable(qcdev->thc_hw, true); + + return IRQ_HANDLED; +} + +/** + * quicki2c_dev_init - Initialize quicki2c device + * + * @pdev: pointer to the thc pci device + * @mem_addr: The pointer of MMIO memory address + * + * Alloc quicki2c device structure and initialized THC device, + * then configure THC to HIDI2C mode. + * + * If success, enable THC hardware interrupt. + * + * Return: pointer to the quicki2c device structure if success + * or NULL on failed. + */ +static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __iomem *mem_addr) +{ + struct device *dev = &pdev->dev; + struct quicki2c_device *qcdev; + int ret; + + qcdev = devm_kzalloc(dev, sizeof(struct quicki2c_device), GFP_KERNEL); + if (!qcdev) + return ERR_PTR(-ENOMEM); + + qcdev->pdev = pdev; + qcdev->dev = dev; + qcdev->mem_addr = mem_addr; + + /* thc hw init */ + qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr); + if (IS_ERR(qcdev->thc_hw)) { + ret = PTR_ERR(qcdev->thc_hw); + dev_err_once(dev, "Failed to initialize THC device context, ret = %d.\n", ret); + return ERR_PTR(ret); + } + + ret = thc_port_select(qcdev->thc_hw, THC_PORT_TYPE_I2C); + if (ret) { + dev_err_once(dev, "Failed to select THC port, ret = %d.\n", ret); + return ERR_PTR(ret); + } + + thc_interrupt_config(qcdev->thc_hw); + + thc_interrupt_enable(qcdev->thc_hw, true); + + return qcdev; +} + +/** + * quicki2c_dev_deinit - De-initialize quicki2c device + * + * @qcdev: pointer to the quicki2c device structure + * + * Disable THC interrupt and deinitilize THC. + */ +static void quicki2c_dev_deinit(struct quicki2c_device *qcdev) +{ + thc_interrupt_enable(qcdev->thc_hw, false); +} + +/* + * quicki2c_probe: Quicki2c driver probe function + * + * @pdev: point to pci device + * @id: point to pci_device_id structure + * + * Return 0 if success or error code on failed. + */ +static int quicki2c_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct quicki2c_device *qcdev; + void __iomem *mem_addr; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) { + dev_err_once(&pdev->dev, "Failed to enable PCI device, ret = %d.\n", ret); + return ret; + } + + pci_set_master(pdev); + + ret = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); + if (ret) { + dev_err_once(&pdev->dev, "Failed to get PCI regions, ret = %d.\n", ret); + goto disable_pci_device; + } + + mem_addr = pcim_iomap_table(pdev)[0]; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err_once(&pdev->dev, "No usable DMA configuration %d\n", ret); + goto unmap_io_region; + } + } + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) { + dev_err_once(&pdev->dev, + "Failed to allocate IRQ vectors. ret = %d\n", ret); + goto unmap_io_region; + } + + pdev->irq = pci_irq_vector(pdev, 0); + + qcdev = quicki2c_dev_init(pdev, mem_addr); + if (IS_ERR(qcdev)) { + dev_err_once(&pdev->dev, "QuickI2C device init failed\n"); + ret = PTR_ERR(qcdev); + goto unmap_io_region; + } + + pci_set_drvdata(pdev, qcdev); + + ret = devm_request_threaded_irq(&pdev->dev, pdev->irq, + quicki2c_irq_quick_handler, + quicki2c_irq_thread_handler, + IRQF_ONESHOT, KBUILD_MODNAME, + qcdev); + if (ret) { + dev_err_once(&pdev->dev, + "Failed to request threaded IRQ, irq = %d.\n", pdev->irq); + goto dev_deinit; + } + + return 0; + +dev_deinit: + quicki2c_dev_deinit(qcdev); +unmap_io_region: + pcim_iounmap_regions(pdev, BIT(0)); +disable_pci_device: + pci_clear_master(pdev); + + return ret; +} + +/** + * quicki2c_remove - Device Removal Routine + * + * @pdev: PCI device structure + * + * This is called by the PCI subsystem to alert the driver + * that it should release a PCI device. + */ +static void quicki2c_remove(struct pci_dev *pdev) +{ + struct quicki2c_device *qcdev; + + qcdev = pci_get_drvdata(pdev); + if (!qcdev) + return; + + quicki2c_dev_deinit(qcdev); + + pcim_iounmap_regions(pdev, BIT(0)); + pci_clear_master(pdev); +} + +/** + * quicki2c_shutdown - Device Shutdown Routine + * + * @pdev: PCI device structure + * + * This is called from the reboot notifier + * it's a simplified version of remove so we go down + * faster. + */ +static void quicki2c_shutdown(struct pci_dev *pdev) +{ + struct quicki2c_device *qcdev; + + qcdev = pci_get_drvdata(pdev); + if (!qcdev) + return; + + quicki2c_dev_deinit(qcdev); +} + +static const struct pci_device_id quicki2c_pci_tbl[] = { + {PCI_VDEVICE(INTEL, THC_LNL_DEVICE_ID_I2C_PORT1), }, + {PCI_VDEVICE(INTEL, THC_LNL_DEVICE_ID_I2C_PORT2), }, + {PCI_VDEVICE(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT1), }, + {PCI_VDEVICE(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2), }, + {PCI_VDEVICE(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1), }, + {PCI_VDEVICE(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2), }, + {} +}; +MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl); + +static struct pci_driver quicki2c_driver = { + .name = KBUILD_MODNAME, + .id_table = quicki2c_pci_tbl, + .probe = quicki2c_probe, + .remove = quicki2c_remove, + .shutdown = quicki2c_shutdown, + .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, +}; + +module_pci_driver(quicki2c_driver); + +MODULE_AUTHOR("Xinpeng Sun "); +MODULE_AUTHOR("Even Xu "); + +MODULE_DESCRIPTION("Intel(R) QuickI2C Driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("INTEL_THC"); diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h new file mode 100644 index 000000000000..90c4ffe5ccfa --- /dev/null +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2024 Intel Corporation */ + +#ifndef _QUICKI2C_DEV_H_ +#define _QUICKI2C_DEV_H_ + +#define THC_LNL_DEVICE_ID_I2C_PORT1 0xA848 +#define THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A +#define THC_PTL_H_DEVICE_ID_I2C_PORT1 0xE348 +#define THC_PTL_H_DEVICE_ID_I2C_PORT2 0xE34A +#define THC_PTL_U_DEVICE_ID_I2C_PORT1 0xE448 +#define THC_PTL_U_DEVICE_ID_I2C_PORT2 0xE44A + +/* Packet size value, the unit is 16 bytes */ +#define MAX_PACKET_SIZE_VALUE_LNL 256 + +enum quicki2c_dev_state { + QUICKI2C_NONE, + QUICKI2C_RESETING, + QUICKI2C_RESETED, + QUICKI2C_INITED, + QUICKI2C_ENABLED, + QUICKI2C_DISABLED, +}; + +struct device; +struct pci_dev; +struct thc_device; + +/** + * struct quicki2c_device - THC QuickI2C device struct + * @dev: point to kernel device + * @pdev: point to PCI device + * @thc_hw: point to THC device + * @driver_data: point to quicki2c specific driver data + * @state: THC I2C device state + * @mem_addr: MMIO memory address + */ +struct quicki2c_device { + struct device *dev; + struct pci_dev *pdev; + struct thc_device *thc_hw; + enum quicki2c_dev_state state; + + void __iomem *mem_addr; +}; + +#endif /* _QUICKI2C_DEV_H_ */ From patchwork Mon Dec 16 01:41:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851899 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B35903B2BB; Mon, 16 Dec 2024 01:42:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313377; cv=none; b=kdp2McJFztGn4L1eDRhlOOHIrF5tk8BGInS7Z4A6FZa05m7jMaNBZrqR3WiZlXbiyXfuNzxkCADKX/JQhyjoptNwX7pv8Div+6kI5+htXGIIgWELUtL7NlIha/lhb6mt0cWqBS66+lfVg91xslJJk006T6YDiThP1VHVHgu5mrc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313377; c=relaxed/simple; bh=Tt6tkx1ePydH8yvh1qqdlscRfAbz9O4gVGPd3WSIh8Y=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=s7fyxjl+hoS9EsdIkxtz8a4ZAnsDSGOqto6VQDYdf4n07bxBED2kVTq1KK8Q8pB4tQp+amtOk/oiLhNLMvXG5oBuNITW2HgY40xkzAPV85/Y87oC7vJzh01cDqpLxaL0O1SFqIRTrkgz55SHrd1BJ2lT+UfCJFWD46T0SNegrfs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=j7GAylTG; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="j7GAylTG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313375; x=1765849375; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Tt6tkx1ePydH8yvh1qqdlscRfAbz9O4gVGPd3WSIh8Y=; b=j7GAylTGmqDKOUbDMOJO6mrs2vsdFFpingl9otmSzfhFWyOQi1uF+CgT J0Wx/u1W8X/f5DdW3XVPpw2boUV1VbuROpIL9dmZK2NkyoipSEO/0bLeK yq1hQQ9SnaPIPZu5Rv4w20Us29sJPl7yJAFKN9KEJLEoDKGnrBLjofuc9 p0jisoi9FYhGSKsojdB1Lae5xzbx6O4AHAf08N0AUb9bQn0ddkb7xMZru KYD81MljL1BUFr6uEoBMJs494oxu6dOKTpKZVeAhVqj38XS7hNsGt3FDR OyU/eol6P3AKh/buvKBw6aqIsjIDwAkKS4XMsM5KpR7BtTDmyNyrkcMq+ A==; X-CSE-ConnectionGUID: XtgxSyHdThqOoTWFJ0h+Hw== X-CSE-MsgGUID: 7i9QR2y3TvKGtVKiaBeiTg== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013143" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013143" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:42:55 -0800 X-CSE-ConnectionGUID: xrRIgTXoSbuml+HSS9GlBQ== X-CSE-MsgGUID: rB5NkjYXS0GMXqS+wpOVdg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084275" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:52 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Even Xu , Xinpeng Sun , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 19/22] HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C ACPI interfaces Date: Mon, 16 Dec 2024 09:41:24 +0800 Message-Id: <20241216014127.3722172-20-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add functions to query QuickI2C ACPI DSM/DSD parameters and use these APIs to access all QuickI2C ACPI resources. Co-developed-by: Xinpeng Sun Signed-off-by: Xinpeng Sun Signed-off-by: Even Xu Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-quicki2c/pci-quicki2c.c | 190 ++++++++++++++++++ .../intel-quicki2c/quicki2c-dev.h | 107 ++++++++++ 2 files changed, 297 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c index 3919ae3e1400..a8b35d40f3b9 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2024 Intel Corporation */ +#include #include #include #include @@ -9,9 +10,185 @@ #include #include "intel-thc-dev.h" +#include "intel-thc-hw.h" #include "quicki2c-dev.h" +/* THC QuickI2C ACPI method to get device properties */ +/* HIDI2C device method */ +static guid_t i2c_hid_guid = + GUID_INIT(0x3cdff6f7, 0x4267, 0x4555, 0xad, 0x05, 0xb3, 0x0a, 0x3d, 0x89, 0x38, 0xde); + +/* platform method */ +static guid_t thc_platform_guid = + GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); + +/** + * quicki2c_acpi_get_dsm_property - Query device ACPI DSM parameter + * + * @adev: point to ACPI device + * @guid: ACPI method's guid + * @rev: ACPI method's revision + * @func: ACPI method's function number + * @type: ACPI parameter's data type + * @prop_buf: point to return buffer + * + * This is a helper function for device to query its ACPI DSM parameters. + * + * Return: 0 if success or ENODEV on failed. + */ +static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t *guid, + u64 rev, u64 func, acpi_object_type type, void *prop_buf) +{ + acpi_handle handle = acpi_device_handle(adev); + union acpi_object *obj; + + obj = acpi_evaluate_dsm_typed(handle, guid, rev, func, NULL, type); + if (!obj) { + acpi_handle_err(handle, + "Error _DSM call failed, rev: %d, func: %d, type: %d\n", + (int)rev, (int)func, (int)type); + return -ENODEV; + } + + if (type == ACPI_TYPE_INTEGER) + *(u32 *)prop_buf = (u32)obj->integer.value; + else if (type == ACPI_TYPE_BUFFER) + memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length); + + ACPI_FREE(obj); + + return 0; +} + +/** + * quicki2c_acpi_get_dsd_property - Query device ACPI DSD parameter + * + * @adev: point to ACPI device + * @dsd_method_name: ACPI method's property name + * @type: ACPI parameter's data type + * @prop_buf: point to return buffer + * + * This is a helper function for device to query its ACPI DSD parameters. + * + * Return: 0 if success or ENODEV on failed. + */ +static int quicki2c_acpi_get_dsd_property(struct acpi_device *adev, acpi_string dsd_method_name, + acpi_object_type type, void *prop_buf) +{ + acpi_handle handle = acpi_device_handle(adev); + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object obj = { .type = type }; + struct acpi_object_list arg_list = { + .count = 1, + .pointer = &obj, + }; + union acpi_object *ret_obj; + acpi_status status; + + status = acpi_evaluate_object(handle, dsd_method_name, &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + acpi_handle_err(handle, + "Can't evaluate %s method: %d\n", dsd_method_name, status); + return -ENODEV; + } + + ret_obj = buffer.pointer; + + memcpy(prop_buf, ret_obj->buffer.pointer, ret_obj->buffer.length); + + return 0; +} + +/** + * quicki2c_get_acpi_resources - Query all quicki2c devices' ACPI parameters + * + * @qcdev: point to quicki2c device + * + * This function gets all quicki2c devices' ACPI resource. + * + * Return: 0 if success or error code on failed. + */ +static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev) +{ + struct acpi_device *adev = ACPI_COMPANION(qcdev->dev); + struct quicki2c_subip_acpi_parameter i2c_param; + struct quicki2c_subip_acpi_config i2c_config; + int ret = -EINVAL; + + if (!adev) { + dev_err(qcdev->dev, "Invalid acpi device pointer\n"); + return ret; + } + + qcdev->acpi_dev = adev; + + ret = quicki2c_acpi_get_dsm_property(adev, &i2c_hid_guid, + QUICKI2C_ACPI_REVISION_NUM, + QUICKI2C_ACPI_FUNC_NUM_HID_DESC_ADDR, + ACPI_TYPE_INTEGER, + &qcdev->hid_desc_addr); + if (ret) + return ret; + + ret = quicki2c_acpi_get_dsm_property(adev, &thc_platform_guid, + QUICKI2C_ACPI_REVISION_NUM, + QUICKI2C_ACPI_FUNC_NUM_ACTIVE_LTR_VAL, + ACPI_TYPE_INTEGER, + &qcdev->active_ltr_val); + if (ret) + return ret; + + ret = quicki2c_acpi_get_dsm_property(adev, &thc_platform_guid, + QUICKI2C_ACPI_REVISION_NUM, + QUICKI2C_ACPI_FUNC_NUM_LP_LTR_VAL, + ACPI_TYPE_INTEGER, + &qcdev->low_power_ltr_val); + if (ret) + return ret; + + ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ICRS, + ACPI_TYPE_BUFFER, &i2c_param); + if (ret) + return ret; + + if (i2c_param.addressing_mode != HIDI2C_ADDRESSING_MODE_7BIT) + return -EOPNOTSUPP; + + qcdev->i2c_slave_addr = i2c_param.device_address; + + ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ISUB, + ACPI_TYPE_BUFFER, &i2c_config); + if (ret) + return ret; + + if (i2c_param.connection_speed > 0 && + i2c_param.connection_speed <= QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED) { + qcdev->i2c_speed_mode = THC_I2C_STANDARD; + qcdev->i2c_clock_hcnt = i2c_config.SMHX; + qcdev->i2c_clock_lcnt = i2c_config.SMLX; + } else if (i2c_param.connection_speed > QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED && + i2c_param.connection_speed <= QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED) { + qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS; + qcdev->i2c_clock_hcnt = i2c_config.FMHX; + qcdev->i2c_clock_lcnt = i2c_config.FMLX; + } else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED && + i2c_param.connection_speed <= QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED) { + qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS; + qcdev->i2c_clock_hcnt = i2c_config.FPHX; + qcdev->i2c_clock_lcnt = i2c_config.FPLX; + } else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED && + i2c_param.connection_speed <= QUICKI2C_SUBIP_HIGH_SPEED_MODE_MAX_SPEED) { + qcdev->i2c_speed_mode = THC_I2C_HIGH_SPEED; + qcdev->i2c_clock_hcnt = i2c_config.HMHX; + qcdev->i2c_clock_lcnt = i2c_config.HMLX; + } else { + return -EOPNOTSUPP; + } + + return 0; +} + /** * quicki2c_irq_quick_handler - The ISR of the quicki2c driver * @@ -92,12 +269,25 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io return ERR_PTR(ret); } + ret = quicki2c_get_acpi_resources(qcdev); + if (ret) { + dev_err_once(dev, "Get ACPI resources failed, ret = %d\n", ret); + return ERR_PTR(ret); + } + ret = thc_port_select(qcdev->thc_hw, THC_PORT_TYPE_I2C); if (ret) { dev_err_once(dev, "Failed to select THC port, ret = %d.\n", ret); return ERR_PTR(ret); } + ret = thc_i2c_subip_init(qcdev->thc_hw, qcdev->i2c_slave_addr, + qcdev->i2c_speed_mode, + qcdev->i2c_clock_hcnt, + qcdev->i2c_clock_lcnt); + if (ret) + return ERR_PTR(ret); + thc_interrupt_config(qcdev->thc_hw); thc_interrupt_enable(qcdev->thc_hw, true); diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h index 9e2a863d8135..60cb736bd5e5 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h @@ -16,6 +16,25 @@ /* Packet size value, the unit is 16 bytes */ #define MAX_PACKET_SIZE_VALUE_LNL 256 +/* HIDI2C special ACPI parameters DSD name */ +#define QUICKI2C_ACPI_METHOD_NAME_ICRS "ICRS" +#define QUICKI2C_ACPI_METHOD_NAME_ISUB "ISUB" + +/* HIDI2C special ACPI parameters DSM methods */ +#define QUICKI2C_ACPI_REVISION_NUM 1 +#define QUICKI2C_ACPI_FUNC_NUM_HID_DESC_ADDR 1 +#define QUICKI2C_ACPI_FUNC_NUM_ACTIVE_LTR_VAL 1 +#define QUICKI2C_ACPI_FUNC_NUM_LP_LTR_VAL 2 + +#define QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED 100000 +#define QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED 400000 +#define QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED 1000000 +#define QUICKI2C_SUBIP_HIGH_SPEED_MODE_MAX_SPEED 3400000 + +#define QUICKI2C_DEFAULT_ACTIVE_LTR_VALUE 5 +#define QUICKI2C_DEFAULT_LP_LTR_VALUE 500 +#define QUICKI2C_RPM_TIMEOUT_MS 500 + enum quicki2c_dev_state { QUICKI2C_NONE, QUICKI2C_RESETING, @@ -25,10 +44,80 @@ enum quicki2c_dev_state { QUICKI2C_DISABLED, }; +enum { + HIDI2C_ADDRESSING_MODE_7BIT, + HIDI2C_ADDRESSING_MODE_10BIT, +}; + +/** + * struct quicki2c_subip_acpi_parameter - QuickI2C ACPI DSD parameters + * @device_address: I2C device slave address + * @connection_speed: I2C device expected connection speed + * @addressing_mode: I2C device slave address mode, 7bit or 10bit + * + * Those properties get from QUICKI2C_ACPI_METHOD_NAME_ICRS method, used for + * Bus parameter. + */ +struct quicki2c_subip_acpi_parameter { + u16 device_address; + u64 connection_speed; + u8 addressing_mode; +} __packed; + +/** + * struct quicki2c_subip_acpi_config - QuickI2C ACPI DSD parameters + * @SMHX: Standard Mode (100 kbit/s) Serial Clock Line HIGH Period + * @SMLX: Standard Mode (100 kbit/s) Serial Clock Line LOW Period + * @SMTD: Standard Mode (100 kbit/s) Serial Data Line Transmit Hold Period + * @SMRD: Standard Mode (100 kbit/s) Serial Data Receive Hold Period + * @FMHX: Fast Mode (400 kbit/s) Serial Clock Line HIGH Period + * @FMLX: Fast Mode (400 kbit/s) Serial Clock Line LOW Period + * @FMTD: Fast Mode (400 kbit/s) Serial Data Line Transmit Hold Period + * @FMRD: Fast Mode (400 kbit/s) Serial Data Line Receive Hold Period + * @FMSL: Maximum length (in ic_clk_cycles) of suppressed spikes + * in Standard Mode, Fast Mode and Fast Mode Plus + * @FPHX: Fast Mode Plus (1Mbit/sec) Serial Clock Line HIGH Period + * @FPLX: Fast Mode Plus (1Mbit/sec) Serial Clock Line LOW Period + * @FPTD: Fast Mode Plus (1Mbit/sec) Serial Data Line Transmit HOLD Period + * @FPRD: Fast Mode Plus (1Mbit/sec) Serial Data Line Receive HOLD Period + * @HMHX: High Speed Mode Plus (3.4Mbits/sec) Serial Clock Line HIGH Period + * @HMLX: High Speed Mode Plus (3.4Mbits/sec) Serial Clock Line LOW Period + * @HMTD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Transmit HOLD Period + * @HMRD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Receive HOLD Period + * @HMSL: Maximum length (in ic_clk_cycles) of suppressed spikes in High Speed Mode + * + * Those properties get from QUICKI2C_ACPI_METHOD_NAME_ISUB method, used for + * I2C timing configure. + */ +struct quicki2c_subip_acpi_config { + u64 SMHX; + u64 SMLX; + u64 SMTD; + u64 SMRD; + + u64 FMHX; + u64 FMLX; + u64 FMTD; + u64 FMRD; + u64 FMSL; + + u64 FPHX; + u64 FPLX; + u64 FPTD; + u64 FPRD; + + u64 HMHX; + u64 HMLX; + u64 HMTD; + u64 HMRD; + u64 HMSL; +}; + struct device; struct pci_dev; struct thc_device; struct hid_device; +struct acpi_device; /** * struct quicki2c_device - THC QuickI2C device struct @@ -36,10 +125,18 @@ struct hid_device; * @pdev: point to PCI device * @thc_hw: point to THC device * @hid_dev: point to hid device + * @acpi_dev: point to ACPI device * @driver_data: point to quicki2c specific driver data * @state: THC I2C device state * @mem_addr: MMIO memory address * @dev_desc: device descriptor for HIDI2C protocol + * @i2c_slave_addr: HIDI2C device slave address + * @hid_desc_addr: Register address for retrieve HID device descriptor + * @active_ltr_val: THC active LTR value + * @low_power_ltr_val: THC low power LTR value + * @i2c_speed_mode: 0 - standard mode, 1 - fast mode, 2 - fast mode plus + * @i2c_clock_hcnt: I2C CLK high period time (unit in cycle count) + * @i2c_clock_lcnt: I2C CLK low period time (unit in cycle count) * @report_descriptor: store a copy of device report descriptor */ struct quicki2c_device { @@ -47,11 +144,21 @@ struct quicki2c_device { struct pci_dev *pdev; struct thc_device *thc_hw; struct hid_device *hid_dev; + struct acpi_device *acpi_dev; enum quicki2c_dev_state state; void __iomem *mem_addr; struct hidi2c_dev_descriptor dev_desc; + u8 i2c_slave_addr; + u16 hid_desc_addr; + + u32 active_ltr_val; + u32 low_power_ltr_val; + + u32 i2c_speed_mode; + u32 i2c_clock_hcnt; + u32 i2c_clock_lcnt; u8 *report_descriptor; }; From patchwork Mon Dec 16 01:41:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Even Xu X-Patchwork-Id: 851898 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0734A7404E; Mon, 16 Dec 2024 01:43:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313385; cv=none; b=arLApxWMe2uNuqiWM9Uoxs1AWH2Td7fpsaEBaDUpgUTz4LMldxEPyHNRrWWbXzHR/UU9dGRqSF79M6EJNK2/K/ZW+BL8CVlVEyiUZqmLVDipm06kGUaIJGqMpMGrvcDHlJcjKZImG+suuf8GtbLApb7sZUFxBsi70OLwiVlWsUY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734313385; c=relaxed/simple; bh=r8i8zSJTHikaOlhZH8b0JwIIJiZ7UjuOorDLBOk6C74=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iZcqdISS1V/kSI0pk8Y66NfxVN3CPSXLY+QeSJX3qypqbsS+js4UcG9d0ZhTOsjQAu/OFdzh1eTwl5OLD/sA0zvNdpQnExXTR/L7/DPA+hZUcgUXK7LtvkBKI2tsG+RmT3B57yN4TLA2A+fsuMhn+3c3zCoZfqJko1wF7xdrUwk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=eHi2iGIe; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="eHi2iGIe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1734313383; x=1765849383; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=r8i8zSJTHikaOlhZH8b0JwIIJiZ7UjuOorDLBOk6C74=; b=eHi2iGIeaWqr8mI5hzpZRukIabsNKYho3JbsWKLoZ6FlaG44WpqzAFKi latEl/nzWocIMNhgqcCj/ao+sq1EwW5ClZlW25b7EQTmVgMFhXQLxiQFI l+4Ra7Hrbbn27EMn5ECSE0VGbeLE8UsJMI4Ro3AnoMlVln4ZMGVOdDk6w MpOB6Yli5OQzVkW7/HTNADwr/WZHKQ7rB5dqM8QCfjHhO9YShFciGWKya fVsKwFe+oNaLRY+ewnIK4JzQeDPl5bJ2c2Tsj9gEBWFt9jU9sgc0eYLZd 57070qC1iIXJho8EI2o+4LvQzKgYJn2n+/8kpTPfcPDYmww6RdFahE3Xx w==; X-CSE-ConnectionGUID: J3orm8XkS7axucAIR71KgQ== X-CSE-MsgGUID: hMHIqy9OSgWDHMXQHTsv4g== X-IronPort-AV: E=McAfee;i="6700,10204,11287"; a="34013172" X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="34013172" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Dec 2024 17:43:02 -0800 X-CSE-ConnectionGUID: eABBspweSweMWw4zb3G2gQ== X-CSE-MsgGUID: oucbEFHNSM2i9FdWy0apfg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,237,1728975600"; d="scan'208";a="102084293" Received: from shsensorbuild.sh.intel.com ([10.239.133.18]) by orviesa004.jf.intel.com with ESMTP; 15 Dec 2024 17:42:59 -0800 From: Even Xu To: jikos@kernel.org, bentiss@kernel.org, corbet@lwn.net, bagasdotme@gmail.com, aaron.ma@canonical.com, rdunlap@infradead.org Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, Even Xu , Xinpeng Sun , Rui Zhang , Srinivas Pandruvada Subject: [PATCH v3 21/22] HID: intel-thc-hid: intel-quicki2c: Complete THC QuickI2C driver Date: Mon, 16 Dec 2024 09:41:26 +0800 Message-Id: <20241216014127.3722172-22-even.xu@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20241216014127.3722172-1-even.xu@intel.com> References: <20241216014127.3722172-1-even.xu@intel.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Fully implement QuickI2C driver probe/remove callbacks, interrupt handler, integrate HIDI2C protocol, enumerate HID device and register HID device. Co-developed-by: Xinpeng Sun Signed-off-by: Xinpeng Sun Signed-off-by: Even Xu Tested-by: Rui Zhang Reviewed-by: Srinivas Pandruvada --- .../intel-quicki2c/pci-quicki2c.c | 273 ++++++++++++++++++ .../intel-quicki2c/quicki2c-dev.h | 6 + .../intel-quicki2c/quicki2c-protocol.c | 27 ++ .../intel-quicki2c/quicki2c-protocol.h | 1 + 4 files changed, 307 insertions(+) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c index a8b35d40f3b9..d417972ae9b0 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c @@ -8,11 +8,14 @@ #include #include #include +#include #include "intel-thc-dev.h" #include "intel-thc-hw.h" #include "quicki2c-dev.h" +#include "quicki2c-hid.h" +#include "quicki2c-protocol.h" /* THC QuickI2C ACPI method to get device properties */ /* HIDI2C device method */ @@ -210,6 +213,69 @@ static irqreturn_t quicki2c_irq_quick_handler(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +/** + * try_recover - Try to recovery THC and Device + * @qcdev: pointer to quicki2c device + * + * This function is a error handler, called when fatal error happens. + * It try to reset Touch Device and re-configure THC to recovery + * transferring between Device and THC. + * + * Return: 0 if successful or error code on failed + */ +static int try_recover(struct quicki2c_device *qcdev) +{ + int ret; + + thc_dma_unconfigure(qcdev->thc_hw); + + ret = thc_dma_configure(qcdev->thc_hw); + if (ret) { + dev_err(qcdev->dev, "Reconfig DMA failed\n"); + return ret; + } + + return 0; +} + +static int handle_input_report(struct quicki2c_device *qcdev) +{ + struct hidi2c_report_packet *pkt = (struct hidi2c_report_packet *)qcdev->input_buf; + int rx_dma_finished = 0; + size_t report_len; + int ret; + + while (!rx_dma_finished) { + ret = thc_rxdma_read(qcdev->thc_hw, THC_RXDMA2, + (u8 *)pkt, &report_len, + &rx_dma_finished); + if (ret) + return ret; + + if (!pkt->len) { + if (qcdev->state == QUICKI2C_RESETING) { + qcdev->reset_ack = true; + wake_up(&qcdev->reset_ack_wq); + + qcdev->state = QUICKI2C_RESETED; + } else { + dev_warn(qcdev->dev, "unexpected DIR happen\n"); + } + + continue; + } + + /* discard samples before driver probe complete */ + if (qcdev->state != QUICKI2C_ENABLED) + continue; + + quicki2c_hid_send_report(qcdev, pkt->data, + HIDI2C_DATA_LEN(le16_to_cpu(pkt->len))); + } + + return 0; +} + /** * quicki2c_irq_thread_handler - IRQ thread handler of quicki2c driver * @@ -221,6 +287,7 @@ static irqreturn_t quicki2c_irq_quick_handler(int irq, void *dev_id) static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id) { struct quicki2c_device *qcdev = dev_id; + int err_recover = 0; int int_mask; if (qcdev->state == QUICKI2C_DISABLED) @@ -228,8 +295,25 @@ static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id) int_mask = thc_interrupt_handler(qcdev->thc_hw); + if (int_mask & BIT(THC_FATAL_ERR_INT) || int_mask & BIT(THC_TXN_ERR_INT) || + int_mask & BIT(THC_UNKNOWN_INT)) { + err_recover = 1; + goto exit; + } + + if (int_mask & BIT(THC_RXDMA2_INT)) { + err_recover = handle_input_report(qcdev); + if (err_recover) + goto exit; + } + +exit: thc_interrupt_enable(qcdev->thc_hw, true); + if (err_recover) + if (try_recover(qcdev)) + qcdev->state = QUICKI2C_DISABLED; + return IRQ_HANDLED; } @@ -260,6 +344,9 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io qcdev->pdev = pdev; qcdev->dev = dev; qcdev->mem_addr = mem_addr; + qcdev->state = QUICKI2C_DISABLED; + + init_waitqueue_head(&qcdev->reset_ack_wq); /* thc hw init */ qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr); @@ -275,6 +362,10 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io return ERR_PTR(ret); } + ret = thc_interrupt_quiesce(qcdev->thc_hw, true); + if (ret) + return ERR_PTR(ret); + ret = thc_port_select(qcdev->thc_hw, THC_PORT_TYPE_I2C); if (ret) { dev_err_once(dev, "Failed to select THC port, ret = %d.\n", ret); @@ -288,10 +379,14 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io if (ret) return ERR_PTR(ret); + thc_int_trigger_type_select(qcdev->thc_hw, false); + thc_interrupt_config(qcdev->thc_hw); thc_interrupt_enable(qcdev->thc_hw, true); + qcdev->state = QUICKI2C_INITED; + return qcdev; } @@ -305,6 +400,114 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io static void quicki2c_dev_deinit(struct quicki2c_device *qcdev) { thc_interrupt_enable(qcdev->thc_hw, false); + thc_ltr_unconfig(qcdev->thc_hw); + + qcdev->state = QUICKI2C_DISABLED; +} + +/** + * quicki2c_dma_init - Configure THC DMA for quicki2c device + * @qcdev: pointer to the quicki2c device structure + * + * This function uses TIC's parameters(such as max input length, max output + * length) to allocate THC DMA buffers and configure THC DMA engines. + * + * Return: 0 if success or error code on failed. + */ +static int quicki2c_dma_init(struct quicki2c_device *qcdev) +{ + size_t swdma_max_len; + int ret; + + swdma_max_len = max(le16_to_cpu(qcdev->dev_desc.max_input_len), + le16_to_cpu(qcdev->dev_desc.report_desc_len)); + + ret = thc_dma_set_max_packet_sizes(qcdev->thc_hw, 0, + le16_to_cpu(qcdev->dev_desc.max_input_len), + le16_to_cpu(qcdev->dev_desc.max_output_len), + swdma_max_len); + if (ret) + return ret; + + ret = thc_dma_allocate(qcdev->thc_hw); + if (ret) { + dev_err(qcdev->dev, "Allocate THC DMA buffer failed, ret = %d\n", ret); + return ret; + } + + /* Enable RxDMA */ + ret = thc_dma_configure(qcdev->thc_hw); + if (ret) { + dev_err(qcdev->dev, "Configure THC DMA failed, ret = %d\n", ret); + thc_dma_unconfigure(qcdev->thc_hw); + thc_dma_release(qcdev->thc_hw); + return ret; + } + + return ret; +} + +/** + * quicki2c_dma_deinit - Release THC DMA for quicki2c device + * @qcdev: pointer to the quicki2c device structure + * + * Stop THC DMA engines and release all DMA buffers. + * + */ +static void quicki2c_dma_deinit(struct quicki2c_device *qcdev) +{ + thc_dma_unconfigure(qcdev->thc_hw); + thc_dma_release(qcdev->thc_hw); +} + +/** + * quicki2c_alloc_report_buf - Alloc report buffers + * @qcdev: pointer to the quicki2c device structure + * + * Allocate report descriptor buffer, it will be used for restore TIC HID + * report descriptor. + * + * Allocate input report buffer, it will be used for receive HID input report + * data from TIC. + * + * Allocate output report buffer, it will be used for store HID output report, + * such as set feature. + * + * Return: 0 if success or error code on failed. + */ +static int quicki2c_alloc_report_buf(struct quicki2c_device *qcdev) +{ + size_t max_report_len; + + qcdev->report_descriptor = devm_kzalloc(qcdev->dev, + le16_to_cpu(qcdev->dev_desc.report_desc_len), + GFP_KERNEL); + if (!qcdev->report_descriptor) + return -ENOMEM; + + /* + * Some HIDI2C devices don't declare input/output max length correctly, + * give default 4K buffer to avoid DMA buffer overrun. + */ + max_report_len = max(le16_to_cpu(qcdev->dev_desc.max_input_len), SZ_4K); + + qcdev->input_buf = devm_kzalloc(qcdev->dev, max_report_len, GFP_KERNEL); + if (!qcdev->input_buf) + return -ENOMEM; + + if (!le16_to_cpu(qcdev->dev_desc.max_output_len)) + qcdev->dev_desc.max_output_len = cpu_to_le16(SZ_4K); + + max_report_len = max(le16_to_cpu(qcdev->dev_desc.max_output_len), + max_report_len); + + qcdev->report_buf = devm_kzalloc(qcdev->dev, max_report_len, GFP_KERNEL); + if (!qcdev->report_buf) + return -ENOMEM; + + qcdev->report_len = max_report_len; + + return 0; } /* @@ -313,6 +516,18 @@ static void quicki2c_dev_deinit(struct quicki2c_device *qcdev) * @pdev: point to pci device * @id: point to pci_device_id structure * + * This function initializes THC and HIDI2C device, the flow is: + * - do THC pci device initialization + * - query HIDI2C ACPI parameters + * - configure THC to HIDI2C mode + * - go through HIDI2C enumeration flow + * |- read device descriptor + * |- reset HIDI2C device + * - enable THC interrupt and DMA + * - read report descriptor + * - register HID device + * - enable runtime power management + * * Return 0 if success or error code on failed. */ static int quicki2c_probe(struct pci_dev *pdev, @@ -376,8 +591,60 @@ static int quicki2c_probe(struct pci_dev *pdev, goto dev_deinit; } + ret = quicki2c_get_device_descriptor(qcdev); + if (ret) { + dev_err(&pdev->dev, "Get device descriptor failed, ret = %d\n", ret); + goto dev_deinit; + } + + ret = quicki2c_alloc_report_buf(qcdev); + if (ret) { + dev_err(&pdev->dev, "Alloc report buffers failed, ret= %d\n", ret); + goto dev_deinit; + } + + ret = quicki2c_dma_init(qcdev); + if (ret) { + dev_err(&pdev->dev, "Setup THC DMA failed, ret= %d\n", ret); + goto dev_deinit; + } + + ret = thc_interrupt_quiesce(qcdev->thc_hw, false); + if (ret) + goto dev_deinit; + + ret = quicki2c_set_power(qcdev, HIDI2C_ON); + if (ret) { + dev_err(&pdev->dev, "Set Power On command failed, ret= %d\n", ret); + goto dev_deinit; + } + + ret = quicki2c_reset(qcdev); + if (ret) { + dev_err(&pdev->dev, "Reset HIDI2C device failed, ret= %d\n", ret); + goto dev_deinit; + } + + ret = quicki2c_get_report_descriptor(qcdev); + if (ret) { + dev_err(&pdev->dev, "Get report descriptor failed, ret = %d\n", ret); + goto dma_deinit; + } + + ret = quicki2c_hid_probe(qcdev); + if (ret) { + dev_err(&pdev->dev, "Failed to register HID device, ret = %d\n", ret); + goto dma_deinit; + } + + qcdev->state = QUICKI2C_ENABLED; + + dev_dbg(&pdev->dev, "QuickI2C probe success\n"); + return 0; +dma_deinit: + quicki2c_dma_deinit(qcdev); dev_deinit: quicki2c_dev_deinit(qcdev); unmap_io_region: @@ -404,6 +671,9 @@ static void quicki2c_remove(struct pci_dev *pdev) if (!qcdev) return; + quicki2c_hid_remove(qcdev); + quicki2c_dma_deinit(qcdev); + quicki2c_dev_deinit(qcdev); pcim_iounmap_regions(pdev, BIT(0)); @@ -427,6 +697,9 @@ static void quicki2c_shutdown(struct pci_dev *pdev) if (!qcdev) return; + /* Must stop DMA before reboot to avoid DMA entering into unknown state */ + quicki2c_dma_deinit(qcdev); + quicki2c_dev_deinit(qcdev); } diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h index d6ad731120ce..0fdac6ba1b04 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h @@ -5,6 +5,7 @@ #define _QUICKI2C_DEV_H_ #include +#include #define THC_LNL_DEVICE_ID_I2C_PORT1 0xA848 #define THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A @@ -141,6 +142,8 @@ struct acpi_device; * @input_buf: store a copy of latest input report data * @report_buf: store a copy of latest input/output report packet from set/get feature * @report_len: the length of input/output report packet + * @reset_ack_wq: workqueue for waiting reset response from device + * @reset_ack: indicate reset response received or not */ struct quicki2c_device { struct device *dev; @@ -167,6 +170,9 @@ struct quicki2c_device { u8 *input_buf; u8 *report_buf; u32 report_len; + + wait_queue_head_t reset_ack_wq; + bool reset_ack; }; #endif /* _QUICKI2C_DEV_H_ */ diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c index 0540003c221e..f493df0d5dc4 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c @@ -195,3 +195,30 @@ int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type, return buf_len; } + +#define HIDI2C_RESET_TIMEOUT 5 + +int quicki2c_reset(struct quicki2c_device *qcdev) +{ + int ret; + + qcdev->reset_ack = false; + qcdev->state = QUICKI2C_RESETING; + + ret = write_cmd_to_txdma(qcdev, HIDI2C_RESET, HIDI2C_RESERVED, 0, NULL, 0); + if (ret) { + dev_err_once(qcdev->dev, "Send reset command failed, ret %d\n", ret); + return ret; + } + + ret = wait_event_interruptible_timeout(qcdev->reset_ack_wq, qcdev->reset_ack, + HIDI2C_RESET_TIMEOUT * HZ); + if (ret <= 0 || !qcdev->reset_ack) { + dev_err_once(qcdev->dev, + "Wait reset response timed out ret:%d timeout:%ds\n", + ret, HIDI2C_RESET_TIMEOUT); + return -ETIMEDOUT; + } + + return 0; +} diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h index 3a0d66c7d9ef..bf4908cce59c 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h @@ -15,5 +15,6 @@ int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type, unsigned int reportnum, void *buf, u32 buf_len); int quicki2c_get_device_descriptor(struct quicki2c_device *qcdev); int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev); +int quicki2c_reset(struct quicki2c_device *qcdev); #endif /* _QUICKI2C_PROTOCOL_H_ */