Skip to content

Commit 4b2c53d

Browse files
Sandeep SinghJiri Kosina
authored andcommitted
SFH:Transport Driver to add support of AMD Sensor Fusion Hub (SFH)
To support AMD Sensor Fusion Hub (SFH) via the HID client's we need to register the client with the HID framework. Here we mostly address on how to register the client with the framework and define the interfaces for communication. Co-developed-by: Nehal Shah <[email protected]> Signed-off-by: Nehal Shah <[email protected]> Signed-off-by: Sandeep Singh <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 4f567b9 commit 4b2c53d

File tree

3 files changed

+487
-0
lines changed

3 files changed

+487
-0
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* AMD SFH Client Layer
4+
* Copyright 2020 Advanced Micro Devices, Inc.
5+
* Authors: Nehal Bakulchandra Shah <[email protected]>
6+
* Sandeep Singh <[email protected]>
7+
*/
8+
9+
#include <linux/dma-mapping.h>
10+
#include <linux/hid.h>
11+
#include <linux/list.h>
12+
#include <linux/slab.h>
13+
#include <linux/workqueue.h>
14+
#include <linux/errno.h>
15+
16+
#include "hid_descriptor/amd_sfh_hid_desc.h"
17+
#include "amd_sfh_pcie.h"
18+
#include "amd_sfh_hid.h"
19+
20+
#define AMD_SFH_IDLE_LOOP 200
21+
22+
struct request_list {
23+
struct hid_device *hid;
24+
struct list_head list;
25+
u8 report_id;
26+
u8 sensor_idx;
27+
u8 report_type;
28+
u8 current_index;
29+
};
30+
31+
static struct request_list req_list;
32+
33+
void amd_sfh_set_report(struct hid_device *hid, int report_id,
34+
int report_type)
35+
{
36+
struct amdtp_hid_data *hid_data = hid->driver_data;
37+
struct amdtp_cl_data *cli_data = hid_data->cli_data;
38+
int i;
39+
40+
for (i = 0; i < cli_data->num_hid_devices; i++) {
41+
if (cli_data->hid_sensor_hubs[i] == hid) {
42+
cli_data->cur_hid_dev = i;
43+
break;
44+
}
45+
}
46+
amdtp_hid_wakeup(hid);
47+
}
48+
49+
int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
50+
{
51+
struct amdtp_hid_data *hid_data = hid->driver_data;
52+
struct amdtp_cl_data *cli_data = hid_data->cli_data;
53+
int i;
54+
55+
for (i = 0; i < cli_data->num_hid_devices; i++) {
56+
if (cli_data->hid_sensor_hubs[i] == hid) {
57+
struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL);
58+
59+
if (!new)
60+
return -ENOMEM;
61+
62+
new->current_index = i;
63+
new->sensor_idx = cli_data->sensor_idx[i];
64+
new->hid = hid;
65+
new->report_type = report_type;
66+
new->report_id = report_id;
67+
cli_data->report_id[i] = report_id;
68+
cli_data->request_done[i] = false;
69+
list_add(&new->list, &req_list.list);
70+
break;
71+
}
72+
}
73+
schedule_delayed_work(&cli_data->work, 0);
74+
return 0;
75+
}
76+
77+
static void amd_sfh_work(struct work_struct *work)
78+
{
79+
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
80+
struct request_list *req_node;
81+
u8 current_index, sensor_index;
82+
u8 report_id, node_type;
83+
u8 report_size = 0;
84+
85+
req_node = list_last_entry(&req_list.list, struct request_list, list);
86+
list_del(&req_node->list);
87+
current_index = req_node->current_index;
88+
sensor_index = req_node->sensor_idx;
89+
report_id = req_node->report_id;
90+
node_type = req_node->report_type;
91+
92+
if (node_type == HID_FEATURE_REPORT) {
93+
report_size = get_feature_report(sensor_index, report_id,
94+
cli_data->feature_report[current_index]);
95+
if (report_size)
96+
hid_input_report(cli_data->hid_sensor_hubs[current_index],
97+
cli_data->report_type[current_index],
98+
cli_data->feature_report[current_index], report_size, 0);
99+
else
100+
pr_err("AMDSFH: Invalid report size\n");
101+
102+
} else if (node_type == HID_INPUT_REPORT) {
103+
report_size = get_input_report(sensor_index, report_id,
104+
cli_data->input_report[current_index],
105+
cli_data->sensor_virt_addr[current_index]);
106+
if (report_size)
107+
hid_input_report(cli_data->hid_sensor_hubs[current_index],
108+
cli_data->report_type[current_index],
109+
cli_data->input_report[current_index], report_size, 0);
110+
else
111+
pr_err("AMDSFH: Invalid report size\n");
112+
}
113+
cli_data->cur_hid_dev = current_index;
114+
cli_data->sensor_requested_cnt[current_index] = 0;
115+
amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]);
116+
}
117+
118+
static void amd_sfh_work_buffer(struct work_struct *work)
119+
{
120+
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
121+
u8 report_size;
122+
int i;
123+
124+
for (i = 0; i < cli_data->num_hid_devices; i++) {
125+
report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i],
126+
cli_data->input_report[i],
127+
cli_data->sensor_virt_addr[i]);
128+
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
129+
cli_data->input_report[i], report_size, 0);
130+
}
131+
schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
132+
}
133+
134+
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
135+
{
136+
struct amdtp_cl_data *cl_data = privdata->cl_data;
137+
struct amd_mp2_sensor_info info;
138+
struct device *dev;
139+
u32 feature_report_size;
140+
u32 input_report_size;
141+
u8 cl_idx;
142+
int rc, i;
143+
144+
dev = &privdata->pdev->dev;
145+
cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL);
146+
if (!cl_data)
147+
return -ENOMEM;
148+
149+
cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
150+
151+
INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
152+
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
153+
INIT_LIST_HEAD(&req_list.list);
154+
155+
for (i = 0; i < cl_data->num_hid_devices; i++) {
156+
cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
157+
&cl_data->sensor_phys_addr[i],
158+
GFP_KERNEL);
159+
cl_data->sensor_sts[i] = 0;
160+
cl_data->sensor_requested_cnt[i] = 0;
161+
cl_data->cur_hid_dev = i;
162+
cl_idx = cl_data->sensor_idx[i];
163+
cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size);
164+
if (!cl_data->report_descr_sz[i]) {
165+
rc = -EINVAL;
166+
goto cleanup;
167+
}
168+
feature_report_size = get_descr_sz(cl_idx, feature_size);
169+
if (!feature_report_size) {
170+
rc = -EINVAL;
171+
goto cleanup;
172+
}
173+
input_report_size = get_descr_sz(cl_idx, input_size);
174+
if (!input_report_size) {
175+
rc = -EINVAL;
176+
goto cleanup;
177+
}
178+
cl_data->feature_report[i] = kzalloc(feature_report_size, GFP_KERNEL);
179+
if (!cl_data->feature_report[i]) {
180+
rc = -ENOMEM;
181+
goto cleanup;
182+
}
183+
cl_data->input_report[i] = kzalloc(input_report_size, GFP_KERNEL);
184+
if (!cl_data->input_report[i]) {
185+
rc = -ENOMEM;
186+
goto cleanup;
187+
}
188+
info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP);
189+
info.sensor_idx = cl_idx;
190+
info.phys_address = cl_data->sensor_phys_addr[i];
191+
192+
cl_data->report_descr[i] = kzalloc(cl_data->report_descr_sz[i], GFP_KERNEL);
193+
if (!cl_data->report_descr[i]) {
194+
rc = -ENOMEM;
195+
goto cleanup;
196+
}
197+
rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]);
198+
if (rc)
199+
return rc;
200+
rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
201+
if (rc)
202+
return rc;
203+
amd_start_sensor(privdata, info);
204+
cl_data->sensor_sts[i] = 1;
205+
}
206+
privdata->cl_data = cl_data;
207+
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
208+
return 0;
209+
210+
cleanup:
211+
for (i = 0; i < cl_data->num_hid_devices; i++) {
212+
if (cl_data->sensor_virt_addr[i]) {
213+
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
214+
cl_data->sensor_virt_addr[i],
215+
cl_data->sensor_phys_addr[i]);
216+
}
217+
kfree(cl_data->feature_report[i]);
218+
kfree(cl_data->input_report[i]);
219+
kfree(cl_data->report_descr[i]);
220+
}
221+
kfree(cl_data);
222+
return rc;
223+
}
224+
225+
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
226+
{
227+
struct amdtp_cl_data *cl_data = privdata->cl_data;
228+
int i;
229+
230+
for (i = 0; i < cl_data->num_hid_devices; i++)
231+
amd_stop_sensor(privdata, i);
232+
233+
cancel_delayed_work_sync(&cl_data->work);
234+
cancel_delayed_work_sync(&cl_data->work_buffer);
235+
amdtp_hid_remove(cl_data);
236+
237+
for (i = 0; i < cl_data->num_hid_devices; i++) {
238+
if (cl_data->sensor_virt_addr[i]) {
239+
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
240+
cl_data->sensor_virt_addr[i],
241+
cl_data->sensor_phys_addr[i]);
242+
}
243+
}
244+
kfree(cl_data);
245+
return 0;
246+
}

0 commit comments

Comments
 (0)