Skip to content

Commit 5282e45

Browse files
EvenxfJiri Kosina
authored andcommitted
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>
1 parent ba38d7f commit 5282e45

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed

drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
/* Copyright (c) 2024 Intel Corporation */
33

4+
#include <linux/acpi.h>
45
#include <linux/device.h>
56
#include <linux/dma-mapping.h>
67
#include <linux/err.h>
@@ -9,9 +10,185 @@
910
#include <linux/pci.h>
1011

1112
#include "intel-thc-dev.h"
13+
#include "intel-thc-hw.h"
1214

1315
#include "quicki2c-dev.h"
1416

17+
/* THC QuickI2C ACPI method to get device properties */
18+
/* HIDI2C device method */
19+
static guid_t i2c_hid_guid =
20+
GUID_INIT(0x3cdff6f7, 0x4267, 0x4555, 0xad, 0x05, 0xb3, 0x0a, 0x3d, 0x89, 0x38, 0xde);
21+
22+
/* platform method */
23+
static guid_t thc_platform_guid =
24+
GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38);
25+
26+
/**
27+
* quicki2c_acpi_get_dsm_property - Query device ACPI DSM parameter
28+
*
29+
* @adev: point to ACPI device
30+
* @guid: ACPI method's guid
31+
* @rev: ACPI method's revision
32+
* @func: ACPI method's function number
33+
* @type: ACPI parameter's data type
34+
* @prop_buf: point to return buffer
35+
*
36+
* This is a helper function for device to query its ACPI DSM parameters.
37+
*
38+
* Return: 0 if success or ENODEV on failed.
39+
*/
40+
static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t *guid,
41+
u64 rev, u64 func, acpi_object_type type, void *prop_buf)
42+
{
43+
acpi_handle handle = acpi_device_handle(adev);
44+
union acpi_object *obj;
45+
46+
obj = acpi_evaluate_dsm_typed(handle, guid, rev, func, NULL, type);
47+
if (!obj) {
48+
acpi_handle_err(handle,
49+
"Error _DSM call failed, rev: %d, func: %d, type: %d\n",
50+
(int)rev, (int)func, (int)type);
51+
return -ENODEV;
52+
}
53+
54+
if (type == ACPI_TYPE_INTEGER)
55+
*(u32 *)prop_buf = (u32)obj->integer.value;
56+
else if (type == ACPI_TYPE_BUFFER)
57+
memcpy(prop_buf, obj->buffer.pointer, obj->buffer.length);
58+
59+
ACPI_FREE(obj);
60+
61+
return 0;
62+
}
63+
64+
/**
65+
* quicki2c_acpi_get_dsd_property - Query device ACPI DSD parameter
66+
*
67+
* @adev: point to ACPI device
68+
* @dsd_method_name: ACPI method's property name
69+
* @type: ACPI parameter's data type
70+
* @prop_buf: point to return buffer
71+
*
72+
* This is a helper function for device to query its ACPI DSD parameters.
73+
*
74+
* Return: 0 if success or ENODEV on failed.
75+
*/
76+
static int quicki2c_acpi_get_dsd_property(struct acpi_device *adev, acpi_string dsd_method_name,
77+
acpi_object_type type, void *prop_buf)
78+
{
79+
acpi_handle handle = acpi_device_handle(adev);
80+
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
81+
union acpi_object obj = { .type = type };
82+
struct acpi_object_list arg_list = {
83+
.count = 1,
84+
.pointer = &obj,
85+
};
86+
union acpi_object *ret_obj;
87+
acpi_status status;
88+
89+
status = acpi_evaluate_object(handle, dsd_method_name, &arg_list, &buffer);
90+
if (ACPI_FAILURE(status)) {
91+
acpi_handle_err(handle,
92+
"Can't evaluate %s method: %d\n", dsd_method_name, status);
93+
return -ENODEV;
94+
}
95+
96+
ret_obj = buffer.pointer;
97+
98+
memcpy(prop_buf, ret_obj->buffer.pointer, ret_obj->buffer.length);
99+
100+
return 0;
101+
}
102+
103+
/**
104+
* quicki2c_get_acpi_resources - Query all quicki2c devices' ACPI parameters
105+
*
106+
* @qcdev: point to quicki2c device
107+
*
108+
* This function gets all quicki2c devices' ACPI resource.
109+
*
110+
* Return: 0 if success or error code on failed.
111+
*/
112+
static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
113+
{
114+
struct acpi_device *adev = ACPI_COMPANION(qcdev->dev);
115+
struct quicki2c_subip_acpi_parameter i2c_param;
116+
struct quicki2c_subip_acpi_config i2c_config;
117+
int ret = -EINVAL;
118+
119+
if (!adev) {
120+
dev_err(qcdev->dev, "Invalid acpi device pointer\n");
121+
return ret;
122+
}
123+
124+
qcdev->acpi_dev = adev;
125+
126+
ret = quicki2c_acpi_get_dsm_property(adev, &i2c_hid_guid,
127+
QUICKI2C_ACPI_REVISION_NUM,
128+
QUICKI2C_ACPI_FUNC_NUM_HID_DESC_ADDR,
129+
ACPI_TYPE_INTEGER,
130+
&qcdev->hid_desc_addr);
131+
if (ret)
132+
return ret;
133+
134+
ret = quicki2c_acpi_get_dsm_property(adev, &thc_platform_guid,
135+
QUICKI2C_ACPI_REVISION_NUM,
136+
QUICKI2C_ACPI_FUNC_NUM_ACTIVE_LTR_VAL,
137+
ACPI_TYPE_INTEGER,
138+
&qcdev->active_ltr_val);
139+
if (ret)
140+
return ret;
141+
142+
ret = quicki2c_acpi_get_dsm_property(adev, &thc_platform_guid,
143+
QUICKI2C_ACPI_REVISION_NUM,
144+
QUICKI2C_ACPI_FUNC_NUM_LP_LTR_VAL,
145+
ACPI_TYPE_INTEGER,
146+
&qcdev->low_power_ltr_val);
147+
if (ret)
148+
return ret;
149+
150+
ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ICRS,
151+
ACPI_TYPE_BUFFER, &i2c_param);
152+
if (ret)
153+
return ret;
154+
155+
if (i2c_param.addressing_mode != HIDI2C_ADDRESSING_MODE_7BIT)
156+
return -EOPNOTSUPP;
157+
158+
qcdev->i2c_slave_addr = i2c_param.device_address;
159+
160+
ret = quicki2c_acpi_get_dsd_property(adev, QUICKI2C_ACPI_METHOD_NAME_ISUB,
161+
ACPI_TYPE_BUFFER, &i2c_config);
162+
if (ret)
163+
return ret;
164+
165+
if (i2c_param.connection_speed > 0 &&
166+
i2c_param.connection_speed <= QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED) {
167+
qcdev->i2c_speed_mode = THC_I2C_STANDARD;
168+
qcdev->i2c_clock_hcnt = i2c_config.SMHX;
169+
qcdev->i2c_clock_lcnt = i2c_config.SMLX;
170+
} else if (i2c_param.connection_speed > QUICKI2C_SUBIP_STANDARD_MODE_MAX_SPEED &&
171+
i2c_param.connection_speed <= QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED) {
172+
qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS;
173+
qcdev->i2c_clock_hcnt = i2c_config.FMHX;
174+
qcdev->i2c_clock_lcnt = i2c_config.FMLX;
175+
} else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FAST_MODE_MAX_SPEED &&
176+
i2c_param.connection_speed <= QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED) {
177+
qcdev->i2c_speed_mode = THC_I2C_FAST_AND_PLUS;
178+
qcdev->i2c_clock_hcnt = i2c_config.FPHX;
179+
qcdev->i2c_clock_lcnt = i2c_config.FPLX;
180+
} else if (i2c_param.connection_speed > QUICKI2C_SUBIP_FASTPLUS_MODE_MAX_SPEED &&
181+
i2c_param.connection_speed <= QUICKI2C_SUBIP_HIGH_SPEED_MODE_MAX_SPEED) {
182+
qcdev->i2c_speed_mode = THC_I2C_HIGH_SPEED;
183+
qcdev->i2c_clock_hcnt = i2c_config.HMHX;
184+
qcdev->i2c_clock_lcnt = i2c_config.HMLX;
185+
} else {
186+
return -EOPNOTSUPP;
187+
}
188+
189+
return 0;
190+
}
191+
15192
/**
16193
* quicki2c_irq_quick_handler - The ISR of the quicki2c driver
17194
*
@@ -92,12 +269,25 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io
92269
return ERR_PTR(ret);
93270
}
94271

272+
ret = quicki2c_get_acpi_resources(qcdev);
273+
if (ret) {
274+
dev_err_once(dev, "Get ACPI resources failed, ret = %d\n", ret);
275+
return ERR_PTR(ret);
276+
}
277+
95278
ret = thc_port_select(qcdev->thc_hw, THC_PORT_TYPE_I2C);
96279
if (ret) {
97280
dev_err_once(dev, "Failed to select THC port, ret = %d.\n", ret);
98281
return ERR_PTR(ret);
99282
}
100283

284+
ret = thc_i2c_subip_init(qcdev->thc_hw, qcdev->i2c_slave_addr,
285+
qcdev->i2c_speed_mode,
286+
qcdev->i2c_clock_hcnt,
287+
qcdev->i2c_clock_lcnt);
288+
if (ret)
289+
return ERR_PTR(ret);
290+
101291
thc_interrupt_config(qcdev->thc_hw);
102292

103293
thc_interrupt_enable(qcdev->thc_hw, true);

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

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,25 @@
1616
/* Packet size value, the unit is 16 bytes */
1717
#define MAX_PACKET_SIZE_VALUE_LNL 256
1818

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+
1938
enum quicki2c_dev_state {
2039
QUICKI2C_NONE,
2140
QUICKI2C_RESETING,
@@ -25,33 +44,121 @@ enum quicki2c_dev_state {
2544
QUICKI2C_DISABLED,
2645
};
2746

47+
enum {
48+
HIDI2C_ADDRESSING_MODE_7BIT,
49+
HIDI2C_ADDRESSING_MODE_10BIT,
50+
};
51+
52+
/**
53+
* struct quicki2c_subip_acpi_parameter - QuickI2C ACPI DSD parameters
54+
* @device_address: I2C device slave address
55+
* @connection_speed: I2C device expected connection speed
56+
* @addressing_mode: I2C device slave address mode, 7bit or 10bit
57+
*
58+
* Those properties get from QUICKI2C_ACPI_METHOD_NAME_ICRS method, used for
59+
* Bus parameter.
60+
*/
61+
struct quicki2c_subip_acpi_parameter {
62+
u16 device_address;
63+
u64 connection_speed;
64+
u8 addressing_mode;
65+
} __packed;
66+
67+
/**
68+
* struct quicki2c_subip_acpi_config - QuickI2C ACPI DSD parameters
69+
* @SMHX: Standard Mode (100 kbit/s) Serial Clock Line HIGH Period
70+
* @SMLX: Standard Mode (100 kbit/s) Serial Clock Line LOW Period
71+
* @SMTD: Standard Mode (100 kbit/s) Serial Data Line Transmit Hold Period
72+
* @SMRD: Standard Mode (100 kbit/s) Serial Data Receive Hold Period
73+
* @FMHX: Fast Mode (400 kbit/s) Serial Clock Line HIGH Period
74+
* @FMLX: Fast Mode (400 kbit/s) Serial Clock Line LOW Period
75+
* @FMTD: Fast Mode (400 kbit/s) Serial Data Line Transmit Hold Period
76+
* @FMRD: Fast Mode (400 kbit/s) Serial Data Line Receive Hold Period
77+
* @FMSL: Maximum length (in ic_clk_cycles) of suppressed spikes
78+
* in Standard Mode, Fast Mode and Fast Mode Plus
79+
* @FPHX: Fast Mode Plus (1Mbit/sec) Serial Clock Line HIGH Period
80+
* @FPLX: Fast Mode Plus (1Mbit/sec) Serial Clock Line LOW Period
81+
* @FPTD: Fast Mode Plus (1Mbit/sec) Serial Data Line Transmit HOLD Period
82+
* @FPRD: Fast Mode Plus (1Mbit/sec) Serial Data Line Receive HOLD Period
83+
* @HMHX: High Speed Mode Plus (3.4Mbits/sec) Serial Clock Line HIGH Period
84+
* @HMLX: High Speed Mode Plus (3.4Mbits/sec) Serial Clock Line LOW Period
85+
* @HMTD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Transmit HOLD Period
86+
* @HMRD: High Speed Mode Plus (3.4Mbits/sec) Serial Data Line Receive HOLD Period
87+
* @HMSL: Maximum length (in ic_clk_cycles) of suppressed spikes in High Speed Mode
88+
*
89+
* Those properties get from QUICKI2C_ACPI_METHOD_NAME_ISUB method, used for
90+
* I2C timing configure.
91+
*/
92+
struct quicki2c_subip_acpi_config {
93+
u64 SMHX;
94+
u64 SMLX;
95+
u64 SMTD;
96+
u64 SMRD;
97+
98+
u64 FMHX;
99+
u64 FMLX;
100+
u64 FMTD;
101+
u64 FMRD;
102+
u64 FMSL;
103+
104+
u64 FPHX;
105+
u64 FPLX;
106+
u64 FPTD;
107+
u64 FPRD;
108+
109+
u64 HMHX;
110+
u64 HMLX;
111+
u64 HMTD;
112+
u64 HMRD;
113+
u64 HMSL;
114+
};
115+
28116
struct device;
29117
struct pci_dev;
30118
struct thc_device;
31119
struct hid_device;
120+
struct acpi_device;
32121

33122
/**
34123
* struct quicki2c_device - THC QuickI2C device struct
35124
* @dev: point to kernel device
36125
* @pdev: point to PCI device
37126
* @thc_hw: point to THC device
38127
* @hid_dev: point to hid device
128+
* @acpi_dev: point to ACPI device
39129
* @driver_data: point to quicki2c specific driver data
40130
* @state: THC I2C device state
41131
* @mem_addr: MMIO memory address
42132
* @dev_desc: device descriptor for HIDI2C protocol
133+
* @i2c_slave_addr: HIDI2C device slave address
134+
* @hid_desc_addr: Register address for retrieve HID device descriptor
135+
* @active_ltr_val: THC active LTR value
136+
* @low_power_ltr_val: THC low power LTR value
137+
* @i2c_speed_mode: 0 - standard mode, 1 - fast mode, 2 - fast mode plus
138+
* @i2c_clock_hcnt: I2C CLK high period time (unit in cycle count)
139+
* @i2c_clock_lcnt: I2C CLK low period time (unit in cycle count)
43140
* @report_descriptor: store a copy of device report descriptor
44141
*/
45142
struct quicki2c_device {
46143
struct device *dev;
47144
struct pci_dev *pdev;
48145
struct thc_device *thc_hw;
49146
struct hid_device *hid_dev;
147+
struct acpi_device *acpi_dev;
50148
enum quicki2c_dev_state state;
51149

52150
void __iomem *mem_addr;
53151

54152
struct hidi2c_dev_descriptor dev_desc;
153+
u8 i2c_slave_addr;
154+
u16 hid_desc_addr;
155+
156+
u32 active_ltr_val;
157+
u32 low_power_ltr_val;
158+
159+
u32 i2c_speed_mode;
160+
u32 i2c_clock_hcnt;
161+
u32 i2c_clock_lcnt;
55162

56163
u8 *report_descriptor;
57164
};

0 commit comments

Comments
 (0)