Cliff Huang has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/81331?usp=email )
Change subject: drivers/intel/touch: Add driver for Intel Touch Controller and Devices ......................................................................
drivers/intel/touch: Add driver for Intel Touch Controller and Devices
Support WACOM, ELAN, and generic touch sensor devices. This driver generates the following ACPI objects: _DSM _CRS Power resource with _STA, _ON, and _OFF _RST
BUG=b:307775082
Signed-off-by: Cliff Huang cliff.huang@intel.com Change-Id: I52dfcd187c92141cb8fc47f4143b90d243439d4e --- A src/drivers/intel/touch/Kconfig A src/drivers/intel/touch/Makefile.mk A src/drivers/intel/touch/chip.h A src/drivers/intel/touch/elan.h A src/drivers/intel/touch/touch.c A src/drivers/intel/touch/wacom.h 6 files changed, 979 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/31/81331/1
diff --git a/src/drivers/intel/touch/Kconfig b/src/drivers/intel/touch/Kconfig new file mode 100644 index 0000000..3175ec5 --- /dev/null +++ b/src/drivers/intel/touch/Kconfig @@ -0,0 +1,6 @@ +config DRIVERS_INTEL_TOUCH + bool + default n + help + When enabled, chip drivers/intel/touch will publish information + to the SSDT for the touch controller and the sensor device. diff --git a/src/drivers/intel/touch/Makefile.mk b/src/drivers/intel/touch/Makefile.mk new file mode 100644 index 0000000..7ac2c365 --- /dev/null +++ b/src/drivers/intel/touch/Makefile.mk @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_INTEL_TOUCH) += touch.c diff --git a/src/drivers/intel/touch/chip.h b/src/drivers/intel/touch/chip.h new file mode 100644 index 0000000..7d1c794 --- /dev/null +++ b/src/drivers/intel/touch/chip.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __DRIVERS_INTEL_TOUCH_CHIP_H__ +#define __DRIVERS_INTEL_TOUCH_CHIP_H__ + +#include <acpi/acpi_device.h> +#include "wacom.h" +#include "elan.h" + +/* maxinum number of port per controller */ +#define MAX_TOUCH_PORTS 2 + +#define INTEL_THC0_NAME "THC0" +#define INTEL_THC1_NAME "THC1" + +#define TOUCH_FLGS_SPI_WRITE_MODE_SINGLE 0x0000 +#define TOUCH_FLGS_SPI_WRITE_MODE_MULTI_SINGLE_SPI 0x2000 +#define TOUCH_FLGS_SPI_WRITE_MODE_MULTI_DUAL_SPI 0x6000 +#define TOUCH_FLGS_SPI_WRITE_MODE_MULTI_QUAD_SPI 0xa000 + +/* + * Intel Touch controller & sensor device + */ +struct drivers_intel_touch_config { + + const char *name; + const char *desc; + + /* Touch Host Controller Mode + Switch between Intel THC protocol and Industry standard HID Over SPI protocol. + 0x0:Thc IPTS (not supporded at this time) + 0x1:Thc HID SPI + 0x2 Thc HID I2C; (not supporded at this time) + */ + enum { + THC_IPTS_MODE, + THC_HID_SPI_MODE, + THC_HID_I2C_MODE, + } mode; + + /* GPIO used to enable device. */ + struct acpi_gpio enable_gpio; + /* Delay to be inserted after device is enabled. */ + unsigned int enable_delay_ms; + /* Delay to be inserted after device is disabled. */ + unsigned int enable_off_delay_ms; + + /* GPIO used to take device out of reset or to put it into reset. */ + struct acpi_gpio reset_gpio; + /* Delay to be inserted after device is taken out of reset. */ + unsigned int reset_delay_ms; + /* Delay to be inserted after device is put into reset. */ + unsigned int reset_off_delay_ms; + + /* GPIO used for report enabling */ + struct acpi_gpio rpt_gpio; + /* Delay to be inserted after device is taken out of reset. */ + unsigned int rpt_delay_ms; + /* Delay to be inserted after device is put into reset. */ + unsigned int rpt_off_delay_ms; + + /* Touch Host Controller Wake On Touch + Based on this setting vGPIO for given THC will be in native mode, and additional + _CRS for wake will be exposed in ACPI + */ + uint8_t wake_on_touch; + struct acpi_irq wake_irq; + + /* Touch Host Controller Hid Over Spi ResetPad */ + /* NOTE: this could be the same pad as reset_gpio */ + struct acpi_gpio hidspi_reset_gpio; + /* Delay to be inserted after device is taken out of reset. */ + unsigned int hidspi_reset_delay_ms; + /* Delay to be inserted after device is put into reset. */ + unsigned int hidspi_reset_off_delay_ms; + + + /* sensor-specific */ + const char *sensor_dev_name; + const char *sensor_dev_desc; + + enum { + TH_SENSOR_NONE, + TH_SENSOR_WACOM, /* _BOM22 */ + TH_SENSOR_ELAN, /* BOM36 */ + TH_SENSOR_GENERIC, + } connected_device; + + /* Touch Host Controller Hid Over Spi Connection Speed + Hid Over Spi Connection Speed - SPI Frequency + */ + uint32_t hidspi_connection_speed; + + /* Touch Host Controller Hid Over Spi Limit PacketSize + When set, limits SPI read & write packet size to 64B. Otherwise, THC uses Max Soc + packet size for SPI Read and Write 0x0- Max Soc Packet Size, 0x11 - 64 Bytes + */ + uint32_t hidspi_limit_packet_size; + + /* Touch Host Controller Hid Over Spi Limit PacketSize + Minimum amount of delay the THC/QUICKSPI driver must wait between end of write operation + and begin of read operation. This value shall be in 10us multiples 0x0: Disabled, + 1-65535 (0xFFFF) - up to 655350 us + */ + uint32_t perform_limit; + + /* Touch Host Controller Hid Over Spi Input Report Header Address */ + uint32_t hidspi_input_report_header_address; + + /* Touch Host Controller Hid Over Spi Input Report Body Address */ + uint32_t hidspi_input_report_body_address; + + /* Touch Host Controller Hid Over Spi Output Report Address */ + uint32_t hidspi_output_report_address; + + /* Touch Host Controller Hid Over Spi Read Opcode */ + uint32_t hidspi_read_opcode; + + /* Touch Host Controller Hid Over Spi Write Opcode */ + uint32_t hidspi_write_opcode; + + /* Touch Host Controller Hid Over Spi Flags + Hid Over Spi Flags 0x0:Single SPI Mode, 0x4000:Dual SPI Mode, 0x8000:Quad SPI Mode + Bit 0-12: Reserved + Bit 13: SPI Write Mode. + 0b0 - Writes are carried in single SPI mode + 0b1 - Writes are carried out in Multi-SPI mode as specified by bit 14-15 + Bit 14-15: Multi-SPI Mode + 0b00 - Single SPI Mode + 0b01 - Dual SPI Mode + 0b10 - Quad SPI Mode + 0b11 - Reserved + */ + enum { + HIDSPI_WRITE_MODE_SINGLE, + HIDSPI_WRITE_MODE_MULTI_SINGLE_SPI, + HIDSPI_WRITE_MODE_MULTI_DUAL_SPI, + HIDSPI_WRITE_MODE_MULTI_QUAD_SPI + } hidspi_flags; + + /* Touch Host Controller Hid Over Spi Reset Sequencing Delay [ms] + Policy control for reset sequencing delay (ACPI _INI, _RST) default 300ms + */ + uint16_t reset_sequencing_delay; + + uint16_t frame_sync_period; + + + /* Touch Host Controller Active Ltr */ + uint32_t active_ltr; + + /* Touch Host Controller Idle Ltr */ + uint32_t idle_ltr; + + /* used in THC_HID_I2C mode */ + uint16_t hidi2c_dev_addr; + + /* Add `DmaProperty` in _DSD */ + bool add_acpi_dma_property; +}; + +uint32_t touch_get_hidspi_input_rpt_hdr_addr(const struct drivers_intel_touch_config *config); +uint32_t touch_get_hidspi_input_rpt_bdy_addr(const struct drivers_intel_touch_config *config); +uint32_t touch_get_hidspi_output_rpt_addr(const struct drivers_intel_touch_config *config); +uint32_t touch_get_hidspi_rd_opcode(const struct drivers_intel_touch_config *config); +uint32_t touch_get_hidspi_wr_opcode(const struct drivers_intel_touch_config *config); +uint32_t touch_get_hidspi_flags(const struct drivers_intel_touch_config *config); +uint32_t touch_get_intf_conn_spd(const struct drivers_intel_touch_config *config); +uint32_t touch_get_limit_packet_size(const struct drivers_intel_touch_config *config); +uint32_t touch_get_perform_limit(const struct drivers_intel_touch_config *config); +uint32_t touch_get_rst_seq_dly(const struct drivers_intel_touch_config *config); +uint32_t touch_get_active_ltr(const struct drivers_intel_touch_config *config); +uint32_t touch_get_idle_ltr(const struct drivers_intel_touch_config *config); + +#endif /* __DRIVERS_INTEL_TOUCH_CHIP_H__ */ diff --git a/src/drivers/intel/touch/elan.h b/src/drivers/intel/touch/elan.h new file mode 100644 index 0000000..84819d9 --- /dev/null +++ b/src/drivers/intel/touch/elan.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __DRIVERS_TOUCH_DEV_ELAN_H__ +#define __DRIVERS_TOUCH_DEV_ELAN_H__ + +#define ELAN_DEV_NAME "ELAN Touch Sensor Device" +#define ELAN_ACTIVE_LTR 10 +#define ELAN_IDLE_LTR 20 +#define ELAN_RST_SEQ_DLY 50 + +#define ELAN_HIDSPI_INPUT_RPT_HDR_ADDR 0x1000 +#define ELAN_HIDSPI_INPUT_RPT_BDY_ADDR 0x1100 +#define ELAN_HIDSPI_OUTPUT_RPT_ADDR 0x2000 + +// #define ELAN_CONNECTION_SPEED 17000000 +#define ELAN_CONNECTION_SPEED 32000000 + +#define ELAN_HIDSPI_RD_OPCODE 0xB +#define ELAN_HIDSPI_WR_OPCODE 0x2 + +/* 0 = no limit */ +#define ELAN_HIDSPI_LIMIT_PKT_SZ 0 +#define ELAN_PERFORMANCE_LIMIT 0 + +#endif /* __DRIVERS_TOUCH_DEV_ELAN_H__ */ diff --git a/src/drivers/intel/touch/touch.c b/src/drivers/intel/touch/touch.c new file mode 100644 index 0000000..6be0fa0 --- /dev/null +++ b/src/drivers/intel/touch/touch.c @@ -0,0 +1,744 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi_device.h> +#include <acpi/acpigen.h> +#include <acpi/acpigen_pci.h> +#include <console/console.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "chip.h" +#include "wacom.h" +#include "elan.h" + +#define TOUCH_HID_UUID "6E2AC436-0FCF-41AF-A265-B32A220DCFAB" +#define TOUCH_INTF_UUID "300D35B7-AC20-413E-8E9C-92E4DAFD0AFE" +#define TOUCH_LTR_UUID "84005682-5B71-41A4-8D66-8130F787A138" +#define TOUCH_FRAME_UUID "9B1E77C4-53DB-43BD-A276-F7287604D1BD" +#define TOUCH_HIDI2C_UUID "3CDFF6F7-4267-4555-AD05-B30A3D8938DE" + +#define TOUCH_MUTEX "THMX" + +/* functions also used in FSP */ +uint32_t touch_get_hidspi_input_rpt_hdr_addr(const struct drivers_intel_touch_config *config) +{ + if (config->connected_device != TH_SENSOR_GENERIC && + config->hidspi_input_report_header_address) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_DEBUG, "WACOM in rpt hdr addr = 0x%x\n", WACOM_HIDSPI_INPUT_RPT_HDR_ADDR); + return WACOM_HIDSPI_INPUT_RPT_HDR_ADDR; + case TH_SENSOR_ELAN: + return ELAN_HIDSPI_INPUT_RPT_HDR_ADDR; + case TH_SENSOR_GENERIC: + return config->hidspi_input_report_header_address; + default: + return 0; + } +} + +uint32_t touch_get_hidspi_input_rpt_bdy_addr(const struct drivers_intel_touch_config *config) +{ + if (config->connected_device != TH_SENSOR_GENERIC && + config->hidspi_input_report_body_address) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_DEBUG, "WACOM in rpt bdy addr = 0x%x\n", WACOM_HIDSPI_INPUT_RPT_BDY_ADDR); + return WACOM_HIDSPI_INPUT_RPT_BDY_ADDR; + case TH_SENSOR_ELAN: + return ELAN_HIDSPI_INPUT_RPT_BDY_ADDR; + case TH_SENSOR_GENERIC: + return config->hidspi_input_report_body_address; + default: + return 0; + } +} + +uint32_t touch_get_hidspi_output_rpt_addr(const struct drivers_intel_touch_config *config) +{ + if (config->connected_device != TH_SENSOR_GENERIC && + config->hidspi_output_report_address) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_DEBUG, "WACOM out rpt addr = 0x%x\n", WACOM_HIDSPI_OUTPUT_RPT_ADDR); + return WACOM_HIDSPI_OUTPUT_RPT_ADDR; + case TH_SENSOR_ELAN: + return ELAN_HIDSPI_OUTPUT_RPT_ADDR; + case TH_SENSOR_GENERIC: + return config->hidspi_output_report_address; + default: + return 0; + } +} + +uint32_t touch_get_hidspi_rd_opcode(const struct drivers_intel_touch_config *config) +{ + if (config->connected_device != TH_SENSOR_GENERIC && + config->hidspi_read_opcode) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_DEBUG, "WACOM RD OP code = 0x%x\n", WACOM_HIDSPI_RD_OPCODE); + return WACOM_HIDSPI_RD_OPCODE; + case TH_SENSOR_ELAN: + return ELAN_HIDSPI_RD_OPCODE; + case TH_SENSOR_GENERIC: + return config->hidspi_read_opcode; + default: + return 0; + } +} + +uint32_t touch_get_hidspi_wr_opcode(const struct drivers_intel_touch_config *config) +{ + if (config->connected_device != TH_SENSOR_GENERIC && + config->hidspi_write_opcode) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_INFO, "use WACOM Write Opcode\n"); + return WACOM_HIDSPI_WR_OPCODE; + case TH_SENSOR_ELAN: + return ELAN_HIDSPI_WR_OPCODE; + case TH_SENSOR_GENERIC: + return config->hidspi_write_opcode; + default: + return 0; + } +} + +uint32_t touch_get_hidspi_flags(const struct drivers_intel_touch_config *config) +{ + switch (config->hidspi_flags) { + case HIDSPI_WRITE_MODE_SINGLE: + return TOUCH_FLGS_SPI_WRITE_MODE_SINGLE; + case HIDSPI_WRITE_MODE_MULTI_SINGLE_SPI: + return TOUCH_FLGS_SPI_WRITE_MODE_MULTI_SINGLE_SPI; + case HIDSPI_WRITE_MODE_MULTI_DUAL_SPI: + return TOUCH_FLGS_SPI_WRITE_MODE_MULTI_DUAL_SPI; + case HIDSPI_WRITE_MODE_MULTI_QUAD_SPI: + return TOUCH_FLGS_SPI_WRITE_MODE_MULTI_QUAD_SPI; + default: + return 0; + } +} + +/* NOTE: This function returns the max speed for the device. + * However, the actual speed might be determined by the SOC. + */ +uint32_t touch_get_intf_conn_spd(const struct drivers_intel_touch_config *config) +{ + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_DEBUG, "use WACOM connection speed %d\n", WACOM_CONNECTION_SPEED); + return WACOM_CONNECTION_SPEED; + case TH_SENSOR_ELAN: + return ELAN_CONNECTION_SPEED; + case TH_SENSOR_GENERIC: + return config->hidspi_connection_speed; + default: + return 0; + } +} + +uint32_t touch_get_limit_packet_size(const struct drivers_intel_touch_config *config) +{ + switch (config->connected_device) { + case TH_SENSOR_WACOM: + return WACOM_HIDSPI_LIMIT_PKT_SZ; + case TH_SENSOR_ELAN: + return ELAN_HIDSPI_LIMIT_PKT_SZ; + case TH_SENSOR_GENERIC: + return config->hidspi_limit_packet_size; + default: + return 0; + } +} + +uint32_t touch_get_perform_limit(const struct drivers_intel_touch_config *config) +{ + switch (config->connected_device) { + case TH_SENSOR_WACOM: + return WACOM_PERFORMANCE_LIMIT; + case TH_SENSOR_ELAN: + return ELAN_PERFORMANCE_LIMIT; + case TH_SENSOR_GENERIC: + return config->perform_limit; + default: + return 0; + } +} + +uint32_t touch_get_active_ltr(const struct drivers_intel_touch_config *config) +{ + uint32_t ltr; + + if (config->connected_device != TH_SENSOR_GENERIC && + config->active_ltr) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + ltr = WACOM_ACTIVE_LTR; + printk(BIOS_DEBUG, "use WACOM Active LTR value 0x%x\n", ltr); + break; + case TH_SENSOR_ELAN: + ltr = ELAN_ACTIVE_LTR; + break; + case TH_SENSOR_GENERIC: + if (config->active_ltr) + ltr = config->active_ltr; + else + ltr = 0xffffffff; + break; + default: + ltr = 0xffffffff; + } + return ltr; +} + +uint32_t touch_get_idle_ltr(const struct drivers_intel_touch_config *config) +{ + uint32_t ltr; + + if (config->connected_device != TH_SENSOR_GENERIC && config->idle_ltr) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + ltr = WACOM_IDLE_LTR; + printk(BIOS_DEBUG, "use WACOM Idle LTR value 0x%x\n", ltr); + break; + case TH_SENSOR_ELAN: + ltr = ELAN_IDLE_LTR; + break; + case TH_SENSOR_GENERIC: + if (config->idle_ltr) + ltr = config->idle_ltr; + else + ltr = 0xffffffff; + break; + default: + ltr = 0xffffffff; + } + return ltr; +} + +uint32_t touch_get_rst_seq_dly(const struct drivers_intel_touch_config *config) +{ + if (config->connected_device != TH_SENSOR_GENERIC && + config->reset_sequencing_delay) + printk(BIOS_WARNING, + "Use TH_SENSOR_GENERIC for parameters from the devicetree!\n"); + switch (config->connected_device) { + case TH_SENSOR_WACOM: + printk(BIOS_DEBUG, "use WACOM reset sequence delay value\n"); + return WACOM_RST_SEQ_DLY; + case TH_SENSOR_ELAN: + return ELAN_RST_SEQ_DLY; + case TH_SENSOR_GENERIC: + return config->reset_sequencing_delay; + default: + return 0; + } +} + +static const char *touch_acpi_name(const struct device *dev) +{ + struct drivers_intel_touch_config *config = dev->chip_info; + + return config->name ? config->name : INTEL_THC0_NAME; +} + +/* acpigen_ */ +static void touch_acpigen_hidspi_input_rpt_hdr_addr(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t addr = touch_get_hidspi_input_rpt_hdr_addr(config); + + acpigen_write_debug_sprintf("%s: HID SPI Input Report Header Address = %d\n", + dev_name(dev), addr); + acpigen_write_return_integer(addr); +} + +static void touch_acpigen_hidspi_input_rpt_bdy_addr(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t addr = touch_get_hidspi_input_rpt_bdy_addr(config); + + acpigen_write_debug_sprintf("%s: HID SPI Input Report Body Address = %d\n", + dev_name(dev), addr); + acpigen_write_return_integer(addr); +} + +static void touch_acpigen_hidspi_output_rpt_addr(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t addr = touch_get_hidspi_output_rpt_addr(config); + + acpigen_write_debug_sprintf("%s: HID SPI Output Report Address = %d\n", touch_acpi_name(dev), addr); + acpigen_write_return_integer(addr); +} + +static void touch_acpigen_hidspi_rd_opcode(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t opcode = touch_get_hidspi_rd_opcode(config); + + acpigen_write_debug_sprintf("%s: HID SPI Read Opcode = %d\n", touch_acpi_name(dev), opcode); + acpigen_write_return_singleton_buffer(opcode); +} + +static void touch_acpigen_hidspi_wr_opcode(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t opcode = touch_get_hidspi_wr_opcode(config); + + acpigen_write_debug_sprintf("%s: HID SPI Write Opcode = %d\n", touch_acpi_name(dev), opcode); + acpigen_write_return_singleton_buffer(opcode); +} + +static void touch_acpigen_hidspi_wr_mode(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t flags = touch_get_hidspi_flags(config); + acpigen_write_debug_sprintf("%s: HID SPI Write Mode (flags) = 0x%x\n", touch_acpi_name(dev), flags); + acpigen_write_return_integer(flags); +} + +static void touch_acpigen_intf_conn_spd(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t spd = touch_get_intf_conn_spd(config); + + acpigen_write_debug_sprintf("%s: connection speed = %d\n", touch_acpi_name(dev), spd); + acpigen_write_return_integer(spd); +} + +static void touch_acpigen_intf_lmt_pkt_sz(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t pkt_sz = touch_get_limit_packet_size(config); + + acpigen_write_debug_sprintf("%s: limit packet size = %d\n", touch_acpi_name(dev), pkt_sz); + acpigen_write_return_integer(pkt_sz); +} + +static void touch_acpigen_intf_perf_lmt(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + uint32_t perform_limit = touch_get_perform_limit(config); + + acpigen_write_debug_sprintf("%s: performance limit = %d\n", touch_acpi_name(dev), perform_limit); + acpigen_write_return_integer(config->perform_limit); +} + +static void touch_acpigen_ltr_active(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + config = ((const struct device *)dev)->chip_info; + uint32_t active_ltr = touch_get_active_ltr(config); + + acpigen_write_debug_sprintf("%s: Active LTR = %d\n", touch_acpi_name(dev), active_ltr); + acpigen_write_return_integer(active_ltr); +} + +static void touch_acpigen_ltr_idle(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + config = ((const struct device *)dev)->chip_info; + uint32_t idle_ltr = touch_get_idle_ltr(config); + + acpigen_write_debug_sprintf("%s: Idle LTR = %d\n", touch_acpi_name(dev), idle_ltr); + acpigen_write_return_integer(idle_ltr); +} + +static void touch_acpigen_frame_sync_period(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + + acpigen_write_debug_sprintf("%s: frame sync period = %d\n", touch_acpi_name(dev), config->frame_sync_period); + acpigen_write_return_integer(config->frame_sync_period); +} + +static void touch_acpigen_hidi2c_dev_addr(void *thc_dev) +{ + const struct device *dev = (const struct device *)thc_dev; + struct drivers_intel_touch_config *config = dev->chip_info; + + acpigen_write_debug_sprintf("%s: HID I2C device address = 0x%x\n", touch_acpi_name(dev), config->hidi2c_dev_addr); + acpigen_write_return_integer(config->hidi2c_dev_addr); +} + +static void +touch_generate_acpi_ini( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + acpigen_write_method_serialized("_INI", 0); + { + acpigen_write_debug_sprintf("%s: _INI()\n", touch_acpi_name(dev)); + } + acpigen_write_method_end(); /* Method */ +} + +static void (*touch_hidspi[])(void *) = { + NULL, /* enumerate functions (autogenerated) */ + touch_acpigen_hidspi_input_rpt_hdr_addr, /* HID-SPI input report header address */ + touch_acpigen_hidspi_input_rpt_bdy_addr, /* HID-SPI input report header address */ + touch_acpigen_hidspi_output_rpt_addr, /* HID-SPI output report header address */ + touch_acpigen_hidspi_rd_opcode, /* HID-SPI Read Opcode */ + touch_acpigen_hidspi_wr_opcode, /* HID-SPI Write Opcode */ + touch_acpigen_hidspi_wr_mode, /* HID-SPI SPI mode */ +}; + +static void (*touch_intf[])(void *) = { + NULL, /* enumerate functions (autogenerated) */ + touch_acpigen_intf_conn_spd, /* connection speed */ + touch_acpigen_intf_lmt_pkt_sz, /* limit packet size */ + touch_acpigen_intf_perf_lmt, /* performance limitation */ +}; + +static void (*touch_ltr[])(void *) = { + NULL, /* enumerate functions (autogenerated) */ + touch_acpigen_ltr_active, /* Active LTR */ + touch_acpigen_ltr_idle, /* Idle LTR */ +}; + +static void (*touch_frame[])(void *) = { + NULL, /* enumerate functions (autogenerated) */ + touch_acpigen_frame_sync_period, /* HID frame info */ +}; + +static void (*touch_hidi2c[])(void *) = { + NULL, /* enumerate functions (autogenerated) */ + touch_acpigen_hidi2c_dev_addr, /* HID-I2C device address */ +}; + +static void +touch_generate_acpi_dsm( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + size_t uuid_count; + int num_touch_hidspi_func = 0; + int num_touch_intf_func = 0; + int num_touch_ltr_func = 0; + int num_touch_frame_func = 0; + int num_touch_hidi2c_func = 0; + + if (config->connected_device != TH_SENSOR_NONE) { + num_touch_hidspi_func = ARRAY_SIZE(touch_hidspi); + num_touch_intf_func = ARRAY_SIZE(touch_intf); + num_touch_ltr_func = ARRAY_SIZE(touch_ltr); + num_touch_frame_func = ARRAY_SIZE(touch_frame); + num_touch_hidi2c_func = ARRAY_SIZE(touch_hidi2c); + } + + if (config->mode == THC_HID_SPI_MODE) { + + struct dsm_uuid ids[] = { + DSM_UUID(TOUCH_HID_UUID, touch_hidspi, num_touch_hidspi_func, (void *)dev), + DSM_UUID(TOUCH_INTF_UUID, touch_intf, num_touch_intf_func, (void *)dev), + DSM_UUID(TOUCH_LTR_UUID, touch_ltr, num_touch_ltr_func, (void *)dev), + DSM_UUID(TOUCH_FRAME_UUID, touch_frame, num_touch_frame_func, (void *)dev), + }; + uuid_count = 4; + acpigen_write_dsm_uuid_arr(ids, uuid_count); + } else if (config->mode == THC_HID_I2C_MODE) { + struct dsm_uuid ids[] = { + DSM_UUID(TOUCH_INTF_UUID, touch_intf, num_touch_intf_func, (void *)dev), + DSM_UUID(TOUCH_LTR_UUID, touch_ltr, num_touch_ltr_func, (void *)dev), + DSM_UUID(TOUCH_FRAME_UUID, touch_frame, num_touch_frame_func, (void *)dev), + DSM_UUID(TOUCH_HIDI2C_UUID, touch_hidi2c, num_touch_hidi2c_func, (void *)dev), + }; + uuid_count = 4; + acpigen_write_dsm_uuid_arr(ids, uuid_count); + } +} + +static void +touch_generate_acpi_crs( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + if (config->mode == THC_HID_SPI_MODE) { + if (config->wake_on_touch) { + printk(BIOS_DEBUG, "%s Creating _CRS for HID SPI touch wake\n", touch_acpi_name(dev)); + acpigen_write_name("_CRS"); + acpigen_write_resourcetemplate_header(); + acpi_device_write_interrupt(&config->wake_irq); + acpigen_write_resourcetemplate_footer(); + } else + printk(BIOS_DEBUG, "%s Skip _CRS for HID SPI touch since no wake is enabled\n", touch_acpi_name(dev)); + } else + printk(BIOS_DEBUG, "%s _CRS not generated for non-THC HID SPI mode at this time!\n", touch_acpi_name(dev)); +} + +static void +touch_generate_acpi_method_status( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + const struct acpi_gpio *gpio; + + acpigen_write_method("_STA", 0); + { + if (config->connected_device != TH_SENSOR_NONE) { + /* Use enable GPIO for status if provided, otherwise use reset GPIO. */ + if (config->enable_gpio.pin_count) { + gpio = &config->enable_gpio; + /* Read current GPIO state into Local0. */ + acpigen_get_tx_gpio(gpio); + } else { + gpio = &config->reset_gpio; + /* Read current GPIO state into Local0. */ + acpigen_get_tx_gpio(gpio); + acpigen_write_not(LOCAL0_OP, LOCAL0_OP); + } + acpigen_write_return_op(LOCAL0_OP); + } else { + acpigen_write_integer(0); + } + } + acpigen_write_method_end(); /* Method */ +} + +static void +touch_generate_acpi_method_on( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + const struct device *parent_dev = dev->upstream->dev; + char mutex_path[128]; + + snprintf(mutex_path, sizeof(mutex_path), "%s", acpi_device_path_join(parent_dev, TOUCH_MUTEX)); + printk(BIOS_DEBUG, "%s: generating _ON() mutex = %s\n", touch_acpi_name(dev), mutex_path); + acpigen_write_method_serialized("_ON", 0); + { + acpigen_write_debug_sprintf("%s: _ON()\n", touch_acpi_name(dev)); + if (config->connected_device != TH_SENSOR_GENERIC) { + acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT); + acpigen_write_debug_sprintf("%s: _ON() mutex acquired.\n", touch_acpi_name(dev)); + /* ex: SOC_TCHSCR_RST_R_L */ + if (config->reset_gpio.pin_count) { + acpigen_enable_tx_gpio(&config->reset_gpio); + } + /* ex: EN_TCHSCR_PWR */ + if (config->enable_gpio.pin_count) { + acpigen_enable_tx_gpio(&config->enable_gpio); + if (config->enable_delay_ms) + acpigen_write_sleep(config->enable_delay_ms); + } + /* ex: SOC_TCHSCR_RST_R_L */ + if (config->reset_gpio.pin_count) { + acpigen_disable_tx_gpio(&config->reset_gpio); + if (config->reset_delay_ms) + acpigen_write_sleep(config->reset_delay_ms); + } + /* ex: SOC_TCHSCR_RPT_EN */ + if (config->rpt_gpio.pin_count) { + acpigen_enable_tx_gpio(&config->rpt_gpio); + if (config->rpt_delay_ms) + acpigen_write_sleep(config->rpt_delay_ms); + } + acpigen_write_release(mutex_path); + } + acpigen_write_debug_sprintf("%s: _ON() completed\n", touch_acpi_name(dev)); + } + acpigen_write_method_end(); +} + +static void +touch_generate_acpi_method_off( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + const struct device *parent_dev = dev->upstream->dev; + char mutex_path[128]; + + snprintf(mutex_path, sizeof(mutex_path), "%s", acpi_device_path_join(parent_dev, TOUCH_MUTEX)); + acpigen_write_method_serialized("_OFF", 0); + { + acpigen_write_debug_sprintf("%s: _OFF()\n", touch_acpi_name(dev)); + if (config->connected_device != TH_SENSOR_GENERIC) { + acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT); + acpigen_write_debug_sprintf("%s: _ON() mutex acquired.\n", touch_acpi_name(dev)); + /* ex: SOC_TCHSCR_RPT_EN */ + if (config->rpt_gpio.pin_count) { + acpigen_disable_tx_gpio(&config->rpt_gpio); + if (config->rpt_off_delay_ms) + acpigen_write_sleep(config->rpt_off_delay_ms); + } + /* ex: SOC_TCHSCR_RST_R_L */ + if (config->reset_gpio.pin_count) { + acpigen_enable_tx_gpio(&config->reset_gpio); + if (config->reset_off_delay_ms) + acpigen_write_sleep(config->reset_off_delay_ms); + } + /* ex: ==> EN_TCHSCR_PWR */ + if (config->enable_gpio.pin_count) { + acpigen_disable_tx_gpio(&config->enable_gpio); + if (config->enable_off_delay_ms) + acpigen_write_sleep(config->enable_off_delay_ms); + } + acpigen_write_release(mutex_path); + } + acpigen_write_debug_sprintf("%s: _OFF() completed\n", touch_acpi_name(dev)); + } + acpigen_write_method_end(); +} + +static void +touch_generate_acpi_rst( + const struct drivers_intel_touch_config *config, + const struct device *dev) +{ + acpigen_write_method_serialized("_RST", 0); + { + acpigen_write_debug_sprintf("%s: _RST()\n", touch_acpi_name(dev)); + if (config->hidspi_reset_gpio.pin_count) { + acpigen_write_acquire(TOUCH_MUTEX, ACPI_MUTEX_NO_TIMEOUT); + acpigen_write_debug_sprintf("%s: _RST() mutex acquired.\n", touch_acpi_name(dev)); + /* Assert RESET# GPIO. */ + acpigen_enable_tx_gpio(&config->hidspi_reset_gpio); + // XXX TODO acpigen_write_sleep(touch_get_rst_seq_dly(config)); + acpigen_write_sleep(300); + /* De-assert RESET# GPIO. */ + acpigen_disable_tx_gpio(&config->hidspi_reset_gpio); + /* XXX TODO */ + acpigen_write_sleep(100); + acpigen_write_release(TOUCH_MUTEX); + } else + acpigen_write_debug_sprintf("%s: _RST() empty method\n", touch_acpi_name(dev)); + acpigen_write_debug_sprintf("%s: _RST() completed\n", touch_acpi_name(dev)); + } + acpigen_write_method_end(); /* Method */ +} + +static void touch_dev_fill_ssdt_generator(const struct device *dev) +{ + const struct drivers_intel_touch_config *config = dev->chip_info; + const struct device *parent = dev->upstream->dev; + DEVTREE_CONST struct device *domain = dev_find_path(NULL, DEVICE_PATH_DOMAIN); + const char *scope = acpi_device_path(parent); + const char *domain_scope = acpi_device_path(domain); + + static const char *const power_res_states[] = {"_PR0", "_PR3"}; + + if (!config) + return; + + if (!is_dev_enabled(parent)) { + printk(BIOS_ERR, "%s: touch controller is not enabled\n", __func__); + return; + } + if (!scope) { + printk(BIOS_ERR, "%s: touch controller scope not found\n", __func__); + return; + } + printk(BIOS_DEBUG, "fill touch ACPIs: domain scope = %s scope = %s touch dev = %s type= %d\n", + domain_scope, scope, touch_acpi_name(dev), dev->path.type); + + acpigen_write_scope(scope); + { + acpigen_write_device(touch_acpi_name(dev)); + { + acpigen_write_ADR_pci_device(parent); + acpigen_write_mutex(TOUCH_MUTEX, 0); + if (config->connected_device != TH_SENSOR_NONE) { + touch_generate_acpi_crs(config, dev); + } + touch_generate_acpi_ini(config, dev); + touch_generate_acpi_dsm(config, dev); + + if (config->connected_device != TH_SENSOR_NONE) { + + if (config->enable_gpio.pin_count || config->reset_gpio.pin_count) { + + printk(BIOS_DEBUG, "%s generating ACPI power resource.\n", touch_acpi_name(dev)); + /* ACPI Power Resource for controlling the attached device power. */ + acpigen_write_power_res("THPR", 0, 0, power_res_states, ARRAY_SIZE(power_res_states)); + { + touch_generate_acpi_method_status(config, dev); + touch_generate_acpi_method_on(config, dev); + touch_generate_acpi_method_off(config, dev); + } + acpigen_write_power_res_end(); /* PowerResource */ + } else { + printk(BIOS_WARNING, "%s: No Enable and/or Reset GPIO specified for %s. No power resource created\n", + touch_acpi_name(dev), scope); + } + if (config->mode == THC_HID_SPI_MODE) { + touch_generate_acpi_rst(config, dev); + } + } else { + printk(BIOS_DEBUG, "No sensor device for device = %s. skip _INI & _RST.\n", + touch_acpi_name(dev)); + } + } + acpigen_write_device_end(); /* Device */ + } + acpigen_write_scope_end(); /* Scope */ +} + +static struct device_operations touch_dev_ops = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .acpi_fill_ssdt = touch_dev_fill_ssdt_generator, + .acpi_name = touch_acpi_name +}; + +static void touch_dev_enable(struct device *dev) +{ + /* This dev is a generic device that is a child to the THC device */ + dev->ops = &touch_dev_ops; +} + +/* Copy of default_pci_ops_dev with scan_bus addition */ +static const struct device_operations pci_thc_device_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = pci_dev_init, + .scan_bus = &scan_generic_bus, /* Non-default */ + .ops_pci = &pci_dev_ops_pci, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DID_INTEL_MTL_THC0_1, + PCI_DID_INTEL_MTL_THC0_2, + PCI_DID_INTEL_MTL_THC1_1, + PCI_DID_INTEL_MTL_THC1_2, + 0 +}; + +static const struct pci_driver intel_touch_driver __pci_driver = { + .ops = &pci_thc_device_ops, + .vendor = PCI_VID_INTEL, + .devices = pci_device_ids, +}; + +struct chip_operations drivers_intel_touch_ops = { + .name = "Intel Touch Controller & Sensor Device", + .enable_dev = touch_dev_enable, +}; diff --git a/src/drivers/intel/touch/wacom.h b/src/drivers/intel/touch/wacom.h new file mode 100644 index 0000000..e321a85 --- /dev/null +++ b/src/drivers/intel/touch/wacom.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __DRIVERS_TOUCH_DEV_WACOM_H__ +#define __DRIVERS_TOUCH_DEV_WACOM_H__ + +#define WACOM_DEV_NAME "Wacom Touch Sensor Device" + +#define WACOM_HID "WACOM530D" +#define WACOM_CID "PNP0C51" + +#define WACOM_ACTIVE_LTR 10 +#define WACOM_IDLE_LTR 20 +#define WACOM_RST_SEQ_DLY 50 + +#define WACOM_HIDSPI_INPUT_RPT_HDR_ADDR 0x0 +#define WACOM_HIDSPI_INPUT_RPT_BDY_ADDR 0x1000 +#define WACOM_HIDSPI_OUTPUT_RPT_ADDR 0x1000 + +#define WACOM_CONNECTION_SPEED 32000000 + +#define WACOM_HIDSPI_RD_OPCODE 0xB +#define WACOM_HIDSPI_WR_OPCODE 0x2 + +/* 0 = no limit */ +#define WACOM_HIDSPI_LIMIT_PKT_SZ 1 +#define WACOM_PERFORMANCE_LIMIT 0 + +#endif /* __DRIVERS_TOUCH_DEV_WACOM_H__ */