Skip to content

Commit 93ce5e0

Browse files
basuamdJiri Kosina
authored andcommitted
HID: amd_sfh: Implement SFH1.1 functionality
Newer AMD SOCs use SFH1.1 memory access with new PCI-id. Hence add new sfh1_1 sub directory to implement SFH1.1 functionality by defining new PCI id, interface functions, descriptor functions and handlers which invokes sfh1.1. Signed-off-by: Basavaraj Natikar <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 014730c commit 93ce5e0

File tree

8 files changed

+895
-0
lines changed

8 files changed

+895
-0
lines changed

drivers/hid/amd-sfh-hid/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ amd_sfh-objs := amd_sfh_hid.o
99
amd_sfh-objs += amd_sfh_client.o
1010
amd_sfh-objs += amd_sfh_pcie.o
1111
amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o
12+
amd_sfh-objs += sfh1_1/amd_sfh_init.o
13+
amd_sfh-objs += sfh1_1/amd_sfh_interface.o
14+
amd_sfh-objs += sfh1_1/amd_sfh_desc.o
1215

1316
ccflags-y += -I $(srctree)/$(src)/

drivers/hid/amd-sfh-hid/amd_sfh_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "amd_sfh_hid.h"
1515

1616
#define PCI_DEVICE_ID_AMD_MP2 0x15E4
17+
#define PCI_DEVICE_ID_AMD_MP2_1_1 0x164A
1718

1819
#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
1920
#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4))
@@ -40,6 +41,8 @@ struct amd_mp2_dev {
4041
struct pci_dev *pdev;
4142
struct amdtp_cl_data *cl_data;
4243
void __iomem *mmio;
44+
void __iomem *vsbase;
45+
const struct amd_sfh1_1_ops *sfh1_1_ops;
4346
struct amd_mp2_ops *mp2_ops;
4447
struct amd_input_data in_data;
4548
/* mp2 active control status */

drivers/hid/amd-sfh-hid/amd_sfh_pcie.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/slab.h>
2020

2121
#include "amd_sfh_pcie.h"
22+
#include "sfh1_1/amd_sfh_init.h"
2223

2324
#define DRIVER_NAME "pcie_mp2_amd"
2425
#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
@@ -318,6 +319,14 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
318319
if (!privdata->cl_data)
319320
return -ENOMEM;
320321

322+
privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data;
323+
if (privdata->sfh1_1_ops) {
324+
rc = privdata->sfh1_1_ops->init(privdata);
325+
if (rc)
326+
return rc;
327+
goto init_done;
328+
}
329+
321330
mp2_select_ops(privdata);
322331

323332
rc = amd_sfh_irq_init(privdata);
@@ -333,6 +342,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
333342
return rc;
334343
}
335344

345+
init_done:
336346
amd_sfh_clear_intr(privdata);
337347

338348
return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata);
@@ -361,6 +371,8 @@ static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend,
361371

362372
static const struct pci_device_id amd_mp2_pci_tbl[] = {
363373
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
374+
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2_1_1),
375+
.driver_data = (kernel_ulong_t)&sfh1_1_ops },
364376
{ }
365377
};
366378
MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* AMD MP2 1.1 descriptor interfaces
4+
*
5+
* Copyright (c) 2022, Advanced Micro Devices, Inc.
6+
* All Rights Reserved.
7+
*
8+
* Author: Basavaraj Natikar <[email protected]>
9+
*/
10+
11+
#include <linux/hid-sensor-ids.h>
12+
13+
#include "amd_sfh_interface.h"
14+
#include "../hid_descriptor/amd_sfh_hid_desc.h"
15+
#include "../hid_descriptor/amd_sfh_hid_report_desc.h"
16+
17+
#define SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41
18+
#define SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51
19+
#define HID_DEFAULT_REPORT_INTERVAL 0x50
20+
#define HID_DEFAULT_MIN_VALUE 0X7F
21+
#define HID_DEFAULT_MAX_VALUE 0x80
22+
#define HID_DEFAULT_SENSITIVITY 0x7F
23+
#define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01
24+
/* state enums */
25+
#define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02
26+
#define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05
27+
#define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04
28+
29+
static int get_report_desc(int sensor_idx, u8 *rep_desc)
30+
{
31+
switch (sensor_idx) {
32+
case ACCEL_IDX: /* accelerometer */
33+
memset(rep_desc, 0, sizeof(accel3_report_descriptor));
34+
memcpy(rep_desc, accel3_report_descriptor,
35+
sizeof(accel3_report_descriptor));
36+
break;
37+
case GYRO_IDX: /* gyroscope */
38+
memset(rep_desc, 0, sizeof(gyro3_report_descriptor));
39+
memcpy(rep_desc, gyro3_report_descriptor,
40+
sizeof(gyro3_report_descriptor));
41+
break;
42+
case MAG_IDX: /* magnetometer */
43+
memset(rep_desc, 0, sizeof(comp3_report_descriptor));
44+
memcpy(rep_desc, comp3_report_descriptor,
45+
sizeof(comp3_report_descriptor));
46+
break;
47+
case ALS_IDX: /* ambient light sensor */
48+
memset(rep_desc, 0, sizeof(als_report_descriptor));
49+
memcpy(rep_desc, als_report_descriptor,
50+
sizeof(als_report_descriptor));
51+
break;
52+
case HPD_IDX: /* HPD sensor */
53+
memset(rep_desc, 0, sizeof(hpd_report_descriptor));
54+
memcpy(rep_desc, hpd_report_descriptor,
55+
sizeof(hpd_report_descriptor));
56+
break;
57+
}
58+
return 0;
59+
}
60+
61+
static void get_common_features(struct common_feature_property *common, int report_id)
62+
{
63+
common->report_id = report_id;
64+
common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
65+
common->report_state = SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
66+
common->power_state = SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
67+
common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
68+
common->report_interval = HID_DEFAULT_REPORT_INTERVAL;
69+
}
70+
71+
static u8 get_feature_rep(int sensor_idx, int report_id, u8 *feature_report)
72+
{
73+
struct magno_feature_report magno_feature;
74+
struct accel3_feature_report acc_feature;
75+
struct gyro_feature_report gyro_feature;
76+
struct hpd_feature_report hpd_feature;
77+
struct als_feature_report als_feature;
78+
u8 report_size = 0;
79+
80+
if (!feature_report)
81+
return report_size;
82+
83+
switch (sensor_idx) {
84+
case ACCEL_IDX: /* accelerometer */
85+
get_common_features(&acc_feature.common_property, report_id);
86+
acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
87+
acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE;
88+
acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE;
89+
memcpy(feature_report, &acc_feature, sizeof(acc_feature));
90+
report_size = sizeof(acc_feature);
91+
break;
92+
case GYRO_IDX: /* gyroscope */
93+
get_common_features(&gyro_feature.common_property, report_id);
94+
gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
95+
gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE;
96+
gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE;
97+
memcpy(feature_report, &gyro_feature, sizeof(gyro_feature));
98+
report_size = sizeof(gyro_feature);
99+
break;
100+
case MAG_IDX: /* magnetometer */
101+
get_common_features(&magno_feature.common_property, report_id);
102+
magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY;
103+
magno_feature.heading_min = HID_DEFAULT_MIN_VALUE;
104+
magno_feature.heading_max = HID_DEFAULT_MAX_VALUE;
105+
magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE;
106+
magno_feature.flux_min = HID_DEFAULT_MIN_VALUE;
107+
magno_feature.flux_max = HID_DEFAULT_MAX_VALUE;
108+
memcpy(feature_report, &magno_feature, sizeof(magno_feature));
109+
report_size = sizeof(magno_feature);
110+
break;
111+
case ALS_IDX: /* ambient light sensor */
112+
get_common_features(&als_feature.common_property, report_id);
113+
als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
114+
als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE;
115+
als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE;
116+
memcpy(feature_report, &als_feature, sizeof(als_feature));
117+
report_size = sizeof(als_feature);
118+
break;
119+
case HPD_IDX: /* human presence detection sensor */
120+
get_common_features(&hpd_feature.common_property, report_id);
121+
memcpy(feature_report, &hpd_feature, sizeof(hpd_feature));
122+
report_size = sizeof(hpd_feature);
123+
break;
124+
}
125+
return report_size;
126+
}
127+
128+
static void get_common_inputs(struct common_input_property *common, int report_id)
129+
{
130+
common->report_id = report_id;
131+
common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM;
132+
common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
133+
}
134+
135+
static int float_to_int(u32 float32)
136+
{
137+
int fraction, shift, mantissa, sign, exp, zeropre;
138+
139+
mantissa = float32 & GENMASK(22, 0);
140+
sign = (float32 & BIT(31)) ? -1 : 1;
141+
exp = (float32 & ~BIT(31)) >> 23;
142+
143+
if (!exp && !mantissa)
144+
return 0;
145+
146+
exp -= 127;
147+
if (exp < 0) {
148+
exp = -exp;
149+
zeropre = (((BIT(23) + mantissa) * 100) >> 23) >> exp;
150+
return zeropre >= 50 ? sign : 0;
151+
}
152+
153+
shift = 23 - exp;
154+
float32 = BIT(exp) + (mantissa >> shift);
155+
fraction = mantissa & GENMASK(shift - 1, 0);
156+
157+
return (((fraction * 100) >> shift) >= 50) ? sign * (float32 + 1) : sign * float32;
158+
}
159+
160+
static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
161+
struct amd_input_data *in_data)
162+
{
163+
struct amd_mp2_dev *mp2 = container_of(in_data, struct amd_mp2_dev, in_data);
164+
u8 *input_report = in_data->input_report[current_index];
165+
struct magno_input_report magno_input;
166+
struct accel3_input_report acc_input;
167+
struct gyro_input_report gyro_input;
168+
struct als_input_report als_input;
169+
struct hpd_input_report hpd_input;
170+
struct sfh_accel_data accel_data;
171+
struct sfh_gyro_data gyro_data;
172+
struct sfh_mag_data mag_data;
173+
struct sfh_als_data als_data;
174+
struct hpd_status hpdstatus;
175+
void __iomem *sensoraddr;
176+
u8 report_size = 0;
177+
178+
if (!input_report)
179+
return report_size;
180+
181+
switch (sensor_idx) {
182+
case ACCEL_IDX: /* accelerometer */
183+
sensoraddr = mp2->vsbase + (ACCEL_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
184+
OFFSET_SENSOR_DATA_DEFAULT;
185+
memcpy_fromio(&accel_data, sensoraddr, sizeof(struct sfh_accel_data));
186+
get_common_inputs(&acc_input.common_property, report_id);
187+
acc_input.in_accel_x_value = float_to_int(accel_data.acceldata.x) / 100;
188+
acc_input.in_accel_y_value = float_to_int(accel_data.acceldata.y) / 100;
189+
acc_input.in_accel_z_value = float_to_int(accel_data.acceldata.z) / 100;
190+
memcpy(input_report, &acc_input, sizeof(acc_input));
191+
report_size = sizeof(acc_input);
192+
break;
193+
case GYRO_IDX: /* gyroscope */
194+
sensoraddr = mp2->vsbase + (GYRO_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
195+
OFFSET_SENSOR_DATA_DEFAULT;
196+
memcpy_fromio(&gyro_data, sensoraddr, sizeof(struct sfh_gyro_data));
197+
get_common_inputs(&gyro_input.common_property, report_id);
198+
gyro_input.in_angel_x_value = float_to_int(gyro_data.gyrodata.x) / 1000;
199+
gyro_input.in_angel_y_value = float_to_int(gyro_data.gyrodata.y) / 1000;
200+
gyro_input.in_angel_z_value = float_to_int(gyro_data.gyrodata.z) / 1000;
201+
memcpy(input_report, &gyro_input, sizeof(gyro_input));
202+
report_size = sizeof(gyro_input);
203+
break;
204+
case MAG_IDX: /* magnetometer */
205+
sensoraddr = mp2->vsbase + (MAG_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
206+
OFFSET_SENSOR_DATA_DEFAULT;
207+
memcpy_fromio(&mag_data, sensoraddr, sizeof(struct sfh_mag_data));
208+
get_common_inputs(&magno_input.common_property, report_id);
209+
magno_input.in_magno_x = float_to_int(mag_data.magdata.x) / 100;
210+
magno_input.in_magno_y = float_to_int(mag_data.magdata.y) / 100;
211+
magno_input.in_magno_z = float_to_int(mag_data.magdata.z) / 100;
212+
magno_input.in_magno_accuracy = mag_data.accuracy / 100;
213+
memcpy(input_report, &magno_input, sizeof(magno_input));
214+
report_size = sizeof(magno_input);
215+
break;
216+
case ALS_IDX:
217+
sensoraddr = mp2->vsbase + (ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
218+
OFFSET_SENSOR_DATA_DEFAULT;
219+
memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
220+
get_common_inputs(&als_input.common_property, report_id);
221+
als_input.illuminance_value = als_data.lux;
222+
report_size = sizeof(als_input);
223+
memcpy(input_report, &als_input, sizeof(als_input));
224+
break;
225+
case HPD_IDX:
226+
get_common_inputs(&hpd_input.common_property, report_id);
227+
hpdstatus.val = readl(mp2->mmio + AMD_C2P_MSG(4));
228+
hpd_input.human_presence = hpdstatus.shpd.presence;
229+
report_size = sizeof(hpd_input);
230+
memcpy(input_report, &hpd_input, sizeof(hpd_input));
231+
break;
232+
}
233+
return report_size;
234+
}
235+
236+
static u32 get_desc_size(int sensor_idx, int descriptor_name)
237+
{
238+
switch (sensor_idx) {
239+
case ACCEL_IDX:
240+
switch (descriptor_name) {
241+
case descr_size:
242+
return sizeof(accel3_report_descriptor);
243+
case input_size:
244+
return sizeof(struct accel3_input_report);
245+
case feature_size:
246+
return sizeof(struct accel3_feature_report);
247+
}
248+
break;
249+
case GYRO_IDX:
250+
switch (descriptor_name) {
251+
case descr_size:
252+
return sizeof(gyro3_report_descriptor);
253+
case input_size:
254+
return sizeof(struct gyro_input_report);
255+
case feature_size:
256+
return sizeof(struct gyro_feature_report);
257+
}
258+
break;
259+
case MAG_IDX:
260+
switch (descriptor_name) {
261+
case descr_size:
262+
return sizeof(comp3_report_descriptor);
263+
case input_size:
264+
return sizeof(struct magno_input_report);
265+
case feature_size:
266+
return sizeof(struct magno_feature_report);
267+
}
268+
break;
269+
case ALS_IDX:
270+
switch (descriptor_name) {
271+
case descr_size:
272+
return sizeof(als_report_descriptor);
273+
case input_size:
274+
return sizeof(struct als_input_report);
275+
case feature_size:
276+
return sizeof(struct als_feature_report);
277+
}
278+
break;
279+
case HPD_IDX:
280+
switch (descriptor_name) {
281+
case descr_size:
282+
return sizeof(hpd_report_descriptor);
283+
case input_size:
284+
return sizeof(struct hpd_input_report);
285+
case feature_size:
286+
return sizeof(struct hpd_feature_report);
287+
}
288+
break;
289+
}
290+
291+
return 0;
292+
}
293+
294+
void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops)
295+
{
296+
mp2_ops->get_rep_desc = get_report_desc;
297+
mp2_ops->get_feat_rep = get_feature_rep;
298+
mp2_ops->get_desc_sz = get_desc_size;
299+
mp2_ops->get_in_rep = get_input_rep;
300+
}

0 commit comments

Comments
 (0)