Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C ACPI interfaces

Add functions to query QuickI2C ACPI DSM/DSD parameters and use these
APIs to access all QuickI2C ACPI resources.

Co-developed-by: Xinpeng Sun <xinpeng.sun@intel.com>
Signed-off-by: Xinpeng Sun <xinpeng.sun@intel.com>
Signed-off-by: Even Xu <even.xu@intel.com>
Tested-by: Rui Zhang <rui1.zhang@intel.com>
Tested-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: Mark Pearson <mpearson-lenovo@squebb.ca>
Tested-by: Aaron Ma <aaron.ma@canonical.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>

authored by

Even Xu and committed by
Jiri Kosina
5282e45c ba38d7f8

+297
+190
drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* Copyright (c) 2024 Intel Corporation */ 3 3 4 + #include <linux/acpi.h> 4 5 #include <linux/device.h> 5 6 #include <linux/dma-mapping.h> 6 7 #include <linux/err.h> ··· 10 9 #include <linux/pci.h> 11 10 12 11 #include "intel-thc-dev.h" 12 + #include "intel-thc-hw.h" 13 13 14 14 #include "quicki2c-dev.h" 15 + 16 + /* THC QuickI2C ACPI method to get device properties */ 17 + /* HIDI2C device method */ 18 + static guid_t i2c_hid_guid = 19 + GUID_INIT(0x3cdff6f7, 0x4267, 0x4555, 0xad, 0x05, 0xb3, 0x0a, 0x3d, 0x89, 0x38, 0xde); 20 + 21 + /* platform method */ 22 + static guid_t thc_platform_guid = 23 + GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); 24 + 25 + /** 26 + * quicki2c_acpi_get_dsm_property - Query device ACPI DSM parameter 27 + * 28 + * @adev: point to ACPI device 29 + * @guid: ACPI method's guid 30 + * @rev: ACPI method's revision 31 + * @func: ACPI method's function number 32 + * @type: ACPI parameter's data type 33 + * @prop_buf: point to return buffer 34 + * 35 + * This is a helper function for device to query its ACPI DSM parameters. 36 + * 37 + * Return: 0 if success or ENODEV on failed. 38 + */ 39 + static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t *guid, 40 + u64 rev, u64 func, acpi_object_type type, void *prop_buf) 41 + { 42 + acpi_handle handle = acpi_device_handle(adev); 43 + union acpi_object *obj; 44 + 45 + obj = acpi_evaluate_dsm_typed(handle, guid, rev, func, NULL, type); 46 + if (!obj) { 47 + acpi_handle_err(handle, 48 + "Error _DSM call failed, rev: %d, func: %d, type: %d\n", 49 + (int)rev, (int)func, (int)type); 50 + return -ENODEV; 51 + } 52 + 53 + if (type == ACPI_TYPE_INTEGER) 54 + *(u32 *)prop_buf = (u32)obj->integer.value; 55 + else if (type == ACPI_TYPE_BUFFER) 56 + memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length); 57 + 58 + ACPI_FREE(obj); 59 + 60 + return 0; 61 + } 62 + 63 + /** 64 + * quicki2c_acpi_get_dsd_property - Query device ACPI DSD parameter 65 + * 66 + * @adev: point to ACPI device 67 + * @dsd_method_name: ACPI method's property name 68 + * @type: ACPI parameter's data type 69 + * @prop_buf: point to return buffer 70 + * 71 + * This is a helper function for device to query its ACPI DSD parameters. 72 + * 73 + * Return: 0 if success or ENODEV on failed. 74 + */ 75 + static int quicki2c_acpi_get_dsd_property(struct acpi_device *adev, acpi_string dsd_method_name, 76 + acpi_object_type type, void *prop_buf) 77 + { 78 + acpi_handle handle = acpi_device_handle(adev); 79 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 80 + union acpi_object obj = { .type = type }; 81 + struct acpi_object_list arg_list = { 82 + .count = 1, 83 + .pointer = &obj, 84 + }; 85 + union acpi_object *ret_obj; 86 + acpi_status status; 87 + 88 + status = acpi_evaluate_object(handle, dsd_method_name, &arg_list, &buffer); 89 + if (ACPI_FAILURE(status)) { 90 + acpi_handle_err(handle, 91 + "Can't evaluate %s method: %d\n", dsd_method_name, status); 92 + return -ENODEV; 93 + } 94 + 95 + ret_obj = buffer.pointer; 96 + 97 + memcpy(prop_buf, ret_obj->buffer.pointer, ret_obj->buffer.length); 98 + 99 + return 0; 100 + } 101 + 102 + /** 103 + * quicki2c_get_acpi_resources - Query all quicki2c devices' ACPI parameters 104 + * 105 + * @qcdev: point to quicki2c device 106 + * 107 + * This function gets all quicki2c devices' ACPI resource. 108 + * 109 + * Return: 0 if success or error code on failed. 110 + */ 111 + static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev) 112 + { 113 + struct acpi_device *adev = ACPI_COMPANION(qcdev->dev); 114 + struct quicki2c_subip_acpi_parameter i2c_param; 115 + struct quicki2c_subip_acpi_config i2c_config; 116 + int ret = -EINVAL; 117 + 118 + if (!adev) { 119 + dev_err(qcdev->dev, "Invalid acpi device pointer\n"); 120 + return ret; 121 + } 122 + 123 + qcdev->acpi_dev = adev; 124 + 125 + ret = quicki2c_acpi_get_dsm_property(adev, &i2c_hid_guid, 126 + QUICKI2C_ACPI_REVISION_NUM, 127 + QUICKI2C_ACPI_FUNC_NUM_HID_DESC_ADDR, 128 + ACPI_TYPE_INTEGER, 129 + &qcdev->hid_desc_addr); 130 + if (ret) 131 + return ret; 132 + 133 + ret = quicki2c_acpi_get_dsm_property(adev, &thc_platform_guid, 134 + QUICKI2C_ACPI_REVISION_NUM, 135 + QUICKI2C_ACPI_FUNC_NUM_ACTIVE_LTR_VAL, 136 + ACPI_TYPE_INTEGER, 137 + &qcdev->active_ltr_val); 138 + if (ret) 139 + return ret; 140 + 141 + ret = quicki2c_acpi_get_dsm_property(adev, &thc_platform_guid, 142 + QUICKI2C_ACPI_REVISION_NUM, 143 + QUICKI2C_ACPI_FUNC_NUM_LP_LTR_VAL, 144 + ACPI_TYPE_INTEGER, 145 + &qcdev->low_power_ltr_val); 146 + if (ret) 147 + return ret; 148 + 149 + ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ICRS, 150 + ACPI_TYPE_BUFFER, &i2c_param); 151 + if (ret) 152 + return ret; 153 + 154 + if (i2c_param.addressing_mode != HIDI2C_ADDRESSING_MODE_7BIT) 155 + return -EOPNOTSUPP; 156 + 157 + qcdev->i2c_slave_addr = i2c_param.device_address; 158 + 159 + ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ISUB, 160 + ACPI_TYPE_BUFFER, &i2c_config); 161 + if (ret) 162 + return ret; 163 + 164 + if (i2c_param.connection_speed > 0 && 165 + i2c_param.connection_speed <= QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED) { 166 + qcdev->i2c_speed_mode = THC_I2C_STANDARD; 167 + qcdev->i2c_clock_hcnt = i2c_config.SMHX; 168 + qcdev->i2c_clock_lcnt = i2c_config.SMLX; 169 + } else if (i2c_param.connection_speed > QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED && 170 + i2c_param.connection_speed <= QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED) { 171 + qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS; 172 + qcdev->i2c_clock_hcnt = i2c_config.FMHX; 173 + qcdev->i2c_clock_lcnt = i2c_config.FMLX; 174 + } else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED && 175 + i2c_param.connection_speed <= QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED) { 176 + qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS; 177 + qcdev->i2c_clock_hcnt = i2c_config.FPHX; 178 + qcdev->i2c_clock_lcnt = i2c_config.FPLX; 179 + } else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED && 180 + i2c_param.connection_speed <= QUICKI2C_SUBIP_HIGH_SPEED_MODE_MAX_SPEED) { 181 + qcdev->i2c_speed_mode = THC_I2C_HIGH_SPEED; 182 + qcdev->i2c_clock_hcnt = i2c_config.HMHX; 183 + qcdev->i2c_clock_lcnt = i2c_config.HMLX; 184 + } else { 185 + return -EOPNOTSUPP; 186 + } 187 + 188 + return 0; 189 + } 15 190 16 191 /** 17 192 * quicki2c_irq_quick_handler - The ISR of the quicki2c driver ··· 269 92 return ERR_PTR(ret); 270 93 } 271 94 95 + ret = quicki2c_get_acpi_resources(qcdev); 96 + if (ret) { 97 + dev_err_once(dev, "Get ACPI resources failed, ret = %d\n", ret); 98 + return ERR_PTR(ret); 99 + } 100 + 272 101 ret = thc_port_select(qcdev->thc_hw, THC_PORT_TYPE_I2C); 273 102 if (ret) { 274 103 dev_err_once(dev, "Failed to select THC port, ret = %d.\n", ret); 275 104 return ERR_PTR(ret); 276 105 } 106 + 107 + ret = thc_i2c_subip_init(qcdev->thc_hw, qcdev->i2c_slave_addr, 108 + qcdev->i2c_speed_mode, 109 + qcdev->i2c_clock_hcnt, 110 + qcdev->i2c_clock_lcnt); 111 + if (ret) 112 + return ERR_PTR(ret); 277 113 278 114 thc_interrupt_config(qcdev->thc_hw); 279 115
+107
drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
··· 16 16 /* Packet size value, the unit is 16 bytes */ 17 17 #define MAX_PACKET_SIZE_VALUE_LNL 256 18 18 19 + /* HIDI2C special ACPI parameters DSD name */ 20 + #define QUICKI2C_ACPI_METHOD_NAME_ICRS "ICRS" 21 + #define QUICKI2C_ACPI_METHOD_NAME_ISUB "ISUB" 22 + 23 + /* HIDI2C special ACPI parameters DSM methods */ 24 + #define QUICKI2C_ACPI_REVISION_NUM 1 25 + #define QUICKI2C_ACPI_FUNC_NUM_HID_DESC_ADDR 1 26 + #define QUICKI2C_ACPI_FUNC_NUM_ACTIVE_LTR_VAL 1 27 + #define QUICKI2C_ACPI_FUNC_NUM_LP_LTR_VAL 2 28 + 29 + #define QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED 100000 30 + #define QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED 400000 31 + #define QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED 1000000 32 + #define QUICKI2C_SUBIP_HIGH_SPEED_MODE_MAX_SPEED 3400000 33 + 34 + #define QUICKI2C_DEFAULT_ACTIVE_LTR_VALUE 5 35 + #define QUICKI2C_DEFAULT_LP_LTR_VALUE 500 36 + #define QUICKI2C_RPM_TIMEOUT_MS 500 37 + 19 38 enum quicki2c_dev_state { 20 39 QUICKI2C_NONE, 21 40 QUICKI2C_RESETING, ··· 44 25 QUICKI2C_DISABLED, 45 26 }; 46 27 28 + enum { 29 + HIDI2C_ADDRESSING_MODE_7BIT, 30 + HIDI2C_ADDRESSING_MODE_10BIT, 31 + }; 32 + 33 + /** 34 + * struct quicki2c_subip_acpi_parameter - QuickI2C ACPI DSD parameters 35 + * @device_address: I2C device slave address 36 + * @connection_speed: I2C device expected connection speed 37 + * @addressing_mode: I2C device slave address mode, 7bit or 10bit 38 + * 39 + * Those properties get from QUICKI2C_ACPI_METHOD_NAME_ICRS method, used for 40 + * Bus parameter. 41 + */ 42 + struct quicki2c_subip_acpi_parameter { 43 + u16 device_address; 44 + u64 connection_speed; 45 + u8 addressing_mode; 46 + } __packed; 47 + 48 + /** 49 + * struct quicki2c_subip_acpi_config - QuickI2C ACPI DSD parameters 50 + * @SMHX: Standard Mode (100 kbit/s) Serial Clock Line HIGH Period 51 + * @SMLX: Standard Mode (100 kbit/s) Serial Clock Line LOW Period 52 + * @SMTD: Standard Mode (100 kbit/s) Serial Data Line Transmit Hold Period 53 + * @SMRD: Standard Mode (100 kbit/s) Serial Data Receive Hold Period 54 + * @FMHX: Fast Mode (400 kbit/s) Serial Clock Line HIGH Period 55 + * @FMLX: Fast Mode (400 kbit/s) Serial Clock Line LOW Period 56 + * @FMTD: Fast Mode (400 kbit/s) Serial Data Line Transmit Hold Period 57 + * @FMRD: Fast Mode (400 kbit/s) Serial Data Line Receive Hold Period 58 + * @FMSL: Maximum length (in ic_clk_cycles) of suppressed spikes 59 + * in Standard Mode, Fast Mode and Fast Mode Plus 60 + * @FPHX: Fast Mode Plus (1Mbit/sec) Serial Clock Line HIGH Period 61 + * @FPLX: Fast Mode Plus (1Mbit/sec) Serial Clock Line LOW Period 62 + * @FPTD: Fast Mode Plus (1Mbit/sec) Serial Data Line Transmit HOLD Period 63 + * @FPRD: Fast Mode Plus (1Mbit/sec) Serial Data Line Receive HOLD Period 64 + * @HMHX: High Speed Mode Plus (3.4Mbits/sec) Serial Clock Line HIGH Period 65 + * @HMLX: High Speed Mode Plus (3.4Mbits/sec) Serial Clock Line LOW Period 66 + * @HMTD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Transmit HOLD Period 67 + * @HMRD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Receive HOLD Period 68 + * @HMSL: Maximum length (in ic_clk_cycles) of suppressed spikes in High Speed Mode 69 + * 70 + * Those properties get from QUICKI2C_ACPI_METHOD_NAME_ISUB method, used for 71 + * I2C timing configure. 72 + */ 73 + struct quicki2c_subip_acpi_config { 74 + u64 SMHX; 75 + u64 SMLX; 76 + u64 SMTD; 77 + u64 SMRD; 78 + 79 + u64 FMHX; 80 + u64 FMLX; 81 + u64 FMTD; 82 + u64 FMRD; 83 + u64 FMSL; 84 + 85 + u64 FPHX; 86 + u64 FPLX; 87 + u64 FPTD; 88 + u64 FPRD; 89 + 90 + u64 HMHX; 91 + u64 HMLX; 92 + u64 HMTD; 93 + u64 HMRD; 94 + u64 HMSL; 95 + }; 96 + 47 97 struct device; 48 98 struct pci_dev; 49 99 struct thc_device; 50 100 struct hid_device; 101 + struct acpi_device; 51 102 52 103 /** 53 104 * struct quicki2c_device - THC QuickI2C device struct ··· 125 36 * @pdev: point to PCI device 126 37 * @thc_hw: point to THC device 127 38 * @hid_dev: point to hid device 39 + * @acpi_dev: point to ACPI device 128 40 * @driver_data: point to quicki2c specific driver data 129 41 * @state: THC I2C device state 130 42 * @mem_addr: MMIO memory address 131 43 * @dev_desc: device descriptor for HIDI2C protocol 44 + * @i2c_slave_addr: HIDI2C device slave address 45 + * @hid_desc_addr: Register address for retrieve HID device descriptor 46 + * @active_ltr_val: THC active LTR value 47 + * @low_power_ltr_val: THC low power LTR value 48 + * @i2c_speed_mode: 0 - standard mode, 1 - fast mode, 2 - fast mode plus 49 + * @i2c_clock_hcnt: I2C CLK high period time (unit in cycle count) 50 + * @i2c_clock_lcnt: I2C CLK low period time (unit in cycle count) 132 51 * @report_descriptor: store a copy of device report descriptor 133 52 */ 134 53 struct quicki2c_device { ··· 144 47 struct pci_dev *pdev; 145 48 struct thc_device *thc_hw; 146 49 struct hid_device *hid_dev; 50 + struct acpi_device *acpi_dev; 147 51 enum quicki2c_dev_state state; 148 52 149 53 void __iomem *mem_addr; 150 54 151 55 struct hidi2c_dev_descriptor dev_desc; 56 + u8 i2c_slave_addr; 57 + u16 hid_desc_addr; 58 + 59 + u32 active_ltr_val; 60 + u32 low_power_ltr_val; 61 + 62 + u32 i2c_speed_mode; 63 + u32 i2c_clock_hcnt; 64 + u32 i2c_clock_lcnt; 152 65 153 66 u8 *report_descriptor; 154 67 };