Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* AMD MP2 1.1 communication driver
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/delay.h>
12
#include <linux/hid.h>
13
14
#include "amd_sfh_init.h"
15
#include "amd_sfh_interface.h"
16
#include "../hid_descriptor/amd_sfh_hid_desc.h"
17
18
static int amd_sfh_get_sensor_num(struct amd_mp2_dev *mp2, u8 *sensor_id)
19
{
20
struct sfh_sensor_list *slist;
21
struct sfh_base_info binfo;
22
int num_of_sensors = 0;
23
int i;
24
25
memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
26
slist = &binfo.sbase.s_list;
27
28
for (i = 0; i < MAX_IDX; i++) {
29
switch (i) {
30
case ACCEL_IDX:
31
case GYRO_IDX:
32
case MAG_IDX:
33
case SRA_IDX:
34
case ALS_IDX:
35
case HPD_IDX:
36
if (BIT(i) & slist->sl.sensors)
37
sensor_id[num_of_sensors++] = i;
38
break;
39
}
40
}
41
42
return num_of_sensors;
43
}
44
45
static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
46
{
47
if (mp2->mp2_ops->response)
48
return mp2->mp2_ops->response(mp2, sid, cmd_id);
49
50
return 0;
51
}
52
53
static const char *get_sensor_name(int idx)
54
{
55
switch (idx) {
56
case ACCEL_IDX:
57
return "accelerometer";
58
case GYRO_IDX:
59
return "gyroscope";
60
case MAG_IDX:
61
return "magnetometer";
62
case SRA_IDX:
63
return "SRA";
64
case ALS_IDX:
65
return "ALS";
66
case HPD_IDX:
67
return "HPD";
68
default:
69
return "unknown sensor type";
70
}
71
}
72
73
static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
74
{
75
struct amdtp_cl_data *cl_data = privdata->cl_data;
76
int i, status;
77
78
for (i = 0; i < cl_data->num_hid_devices; i++) {
79
switch (cl_data->sensor_idx[i]) {
80
case HPD_IDX:
81
privdata->dev_en.is_hpd_present = false;
82
break;
83
case ALS_IDX:
84
privdata->dev_en.is_als_present = false;
85
break;
86
case SRA_IDX:
87
privdata->dev_en.is_sra_present = false;
88
break;
89
}
90
91
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
92
privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
93
status = amd_sfh_wait_for_response
94
(privdata, cl_data->sensor_idx[i], DISABLE_SENSOR);
95
if (status == 0)
96
cl_data->sensor_sts[i] = SENSOR_DISABLED;
97
dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",
98
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
99
cl_data->sensor_sts[i]);
100
}
101
}
102
103
cancel_delayed_work_sync(&cl_data->work);
104
cancel_delayed_work_sync(&cl_data->work_buffer);
105
amdtp_hid_remove(cl_data);
106
107
return 0;
108
}
109
110
static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
111
{
112
struct amd_input_data *in_data = &privdata->in_data;
113
struct amdtp_cl_data *cl_data = privdata->cl_data;
114
struct amd_mp2_ops *mp2_ops = privdata->mp2_ops;
115
struct amd_mp2_sensor_info info;
116
struct request_list *req_list;
117
u32 feature_report_size;
118
u32 input_report_size;
119
struct device *dev;
120
int rc, i, status;
121
u8 cl_idx;
122
123
req_list = &cl_data->req_list;
124
dev = &privdata->pdev->dev;
125
amd_sfh1_1_set_desc_ops(mp2_ops);
126
127
cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
128
if (cl_data->num_hid_devices == 0)
129
return -ENODEV;
130
cl_data->is_any_sensor_enabled = false;
131
132
INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
133
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
134
INIT_LIST_HEAD(&req_list->list);
135
cl_data->in_data = in_data;
136
137
for (i = 0; i < cl_data->num_hid_devices; i++) {
138
cl_data->sensor_sts[i] = SENSOR_DISABLED;
139
140
if (cl_data->sensor_idx[i] == SRA_IDX) {
141
info.sensor_idx = cl_data->sensor_idx[i];
142
writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
143
mp2_ops->start(privdata, info);
144
status = amd_sfh_wait_for_response
145
(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);
146
147
cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;
148
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
149
cl_data->is_any_sensor_enabled = true;
150
privdata->dev_en.is_sra_present = true;
151
}
152
continue;
153
}
154
155
cl_data->sensor_requested_cnt[i] = 0;
156
cl_data->cur_hid_dev = i;
157
cl_idx = cl_data->sensor_idx[i];
158
159
cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size);
160
if (!cl_data->report_descr_sz[i]) {
161
rc = -EINVAL;
162
goto cleanup;
163
}
164
feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size);
165
if (!feature_report_size) {
166
rc = -EINVAL;
167
goto cleanup;
168
}
169
input_report_size = mp2_ops->get_desc_sz(cl_idx, input_size);
170
if (!input_report_size) {
171
rc = -EINVAL;
172
goto cleanup;
173
}
174
cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL);
175
if (!cl_data->feature_report[i]) {
176
rc = -ENOMEM;
177
goto cleanup;
178
}
179
in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
180
if (!in_data->input_report[i]) {
181
rc = -ENOMEM;
182
goto cleanup;
183
}
184
185
info.sensor_idx = cl_idx;
186
187
cl_data->report_descr[i] =
188
devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL);
189
if (!cl_data->report_descr[i]) {
190
rc = -ENOMEM;
191
goto cleanup;
192
}
193
rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);
194
if (rc)
195
goto cleanup;
196
197
writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
198
mp2_ops->start(privdata, info);
199
status = amd_sfh_wait_for_response
200
(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);
201
202
cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;
203
}
204
205
for (i = 0; i < cl_data->num_hid_devices; i++) {
206
if (cl_data->sensor_idx[i] == SRA_IDX)
207
continue;
208
cl_data->cur_hid_dev = i;
209
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
210
cl_data->is_any_sensor_enabled = true;
211
rc = amdtp_hid_probe(i, cl_data);
212
if (rc)
213
goto cleanup;
214
switch (cl_data->sensor_idx[i]) {
215
case HPD_IDX:
216
privdata->dev_en.is_hpd_present = true;
217
privdata->dev_en.is_hpd_enabled = true;
218
amd_sfh_toggle_hpd(privdata, false);
219
break;
220
case ALS_IDX:
221
privdata->dev_en.is_als_present = true;
222
break;
223
}
224
}
225
dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
226
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
227
cl_data->sensor_sts[i]);
228
}
229
230
if (!cl_data->is_any_sensor_enabled) {
231
dev_warn(dev, "No sensor registered, sensors not enabled is %d\n",
232
cl_data->is_any_sensor_enabled);
233
rc = -EOPNOTSUPP;
234
goto cleanup;
235
}
236
237
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
238
return 0;
239
240
cleanup:
241
amd_sfh_hid_client_deinit(privdata);
242
for (i = 0; i < cl_data->num_hid_devices; i++) {
243
if (cl_data->sensor_idx[i] == SRA_IDX)
244
continue;
245
devm_kfree(dev, cl_data->feature_report[i]);
246
devm_kfree(dev, in_data->input_report[i]);
247
devm_kfree(dev, cl_data->report_descr[i]);
248
}
249
return rc;
250
}
251
252
static void amd_sfh_resume(struct amd_mp2_dev *mp2)
253
{
254
struct amdtp_cl_data *cl_data = mp2->cl_data;
255
struct amd_mp2_sensor_info info;
256
int i, status;
257
258
if (!cl_data->is_any_sensor_enabled) {
259
amd_sfh_clear_intr(mp2);
260
return;
261
}
262
263
for (i = 0; i < cl_data->num_hid_devices; i++) {
264
/* leave HPD alone; policy is controlled by sysfs */
265
if (cl_data->sensor_idx[i] == HPD_IDX)
266
continue;
267
268
if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
269
info.sensor_idx = cl_data->sensor_idx[i];
270
mp2->mp2_ops->start(mp2, info);
271
status = amd_sfh_wait_for_response
272
(mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);
273
if (status == 0)
274
status = SENSOR_ENABLED;
275
if (status == SENSOR_ENABLED)
276
cl_data->sensor_sts[i] = SENSOR_ENABLED;
277
dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n",
278
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
279
cl_data->sensor_sts[i]);
280
}
281
}
282
283
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
284
amd_sfh_clear_intr(mp2);
285
}
286
287
static void amd_sfh_suspend(struct amd_mp2_dev *mp2)
288
{
289
struct amdtp_cl_data *cl_data = mp2->cl_data;
290
int i, status;
291
292
if (!cl_data->is_any_sensor_enabled) {
293
amd_sfh_clear_intr(mp2);
294
return;
295
}
296
297
for (i = 0; i < cl_data->num_hid_devices; i++) {
298
/* leave HPD alone; policy is controlled by sysfs */
299
if (cl_data->sensor_idx[i] == HPD_IDX)
300
continue;
301
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
302
mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
303
status = amd_sfh_wait_for_response
304
(mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);
305
if (status == 0)
306
status = SENSOR_DISABLED;
307
if (status != SENSOR_ENABLED)
308
cl_data->sensor_sts[i] = SENSOR_DISABLED;
309
dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n",
310
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
311
cl_data->sensor_sts[i]);
312
}
313
}
314
315
cancel_delayed_work_sync(&cl_data->work_buffer);
316
amd_sfh_clear_intr(mp2);
317
}
318
319
void amd_sfh_toggle_hpd(struct amd_mp2_dev *mp2, bool enabled)
320
{
321
struct amdtp_cl_data *cl_data = mp2->cl_data;
322
struct amd_mp2_sensor_info info;
323
int i, status;
324
325
if (mp2->dev_en.is_hpd_enabled == enabled)
326
return;
327
328
for (i = 0; i < cl_data->num_hid_devices; i++) {
329
if (cl_data->sensor_idx[i] != HPD_IDX)
330
continue;
331
info.sensor_idx = cl_data->sensor_idx[i];
332
if (enabled) {
333
mp2->mp2_ops->start(mp2, info);
334
status = amd_sfh_wait_for_response
335
(mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);
336
if (status == 0)
337
status = SENSOR_ENABLED;
338
if (status == SENSOR_ENABLED)
339
cl_data->sensor_sts[i] = SENSOR_ENABLED;
340
} else {
341
mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
342
status = amd_sfh_wait_for_response
343
(mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);
344
if (status == 0)
345
status = SENSOR_DISABLED;
346
if (status != SENSOR_ENABLED)
347
cl_data->sensor_sts[i] = SENSOR_DISABLED;
348
}
349
dev_dbg(&mp2->pdev->dev, "toggle sid 0x%x (%s) status 0x%x\n",
350
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
351
cl_data->sensor_sts[i]);
352
break;
353
}
354
mp2->dev_en.is_hpd_enabled = enabled;
355
}
356
357
static void amd_mp2_pci_remove(void *privdata)
358
{
359
struct amd_mp2_dev *mp2 = privdata;
360
361
sfh_deinit_emp2();
362
amd_sfh_hid_client_deinit(privdata);
363
mp2->mp2_ops->stop_all(mp2);
364
pcim_intx(mp2->pdev, false);
365
amd_sfh_clear_intr(mp2);
366
}
367
368
static void amd_sfh_set_ops(struct amd_mp2_dev *mp2)
369
{
370
struct amd_mp2_ops *mp2_ops;
371
372
sfh_interface_init(mp2);
373
mp2_ops = mp2->mp2_ops;
374
mp2_ops->clear_intr = amd_sfh_clear_intr_v2;
375
mp2_ops->init_intr = amd_sfh_irq_init_v2;
376
mp2_ops->suspend = amd_sfh_suspend;
377
mp2_ops->resume = amd_sfh_resume;
378
mp2_ops->remove = amd_mp2_pci_remove;
379
}
380
381
int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
382
{
383
u32 phy_base = readl(mp2->mmio + amd_get_c2p_val(mp2, 22));
384
struct device *dev = &mp2->pdev->dev;
385
struct sfh_base_info binfo;
386
int rc;
387
388
phy_base <<= 21;
389
if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) {
390
dev_dbg(dev, "can't reserve mmio registers\n");
391
return -ENOMEM;
392
}
393
394
mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024);
395
if (!mp2->vsbase) {
396
dev_dbg(dev, "failed to remap vsbase\n");
397
return -ENOMEM;
398
}
399
400
/* Before accessing give time for SFH firmware for processing configuration */
401
msleep(5000);
402
403
memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
404
if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) {
405
dev_dbg(dev, "No sensor registered\n");
406
return -EOPNOTSUPP;
407
}
408
dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver);
409
410
amd_sfh_set_ops(mp2);
411
412
rc = amd_sfh_irq_init(mp2);
413
if (rc) {
414
sfh_deinit_emp2();
415
dev_err(dev, "amd_sfh_irq_init failed\n");
416
return rc;
417
}
418
419
rc = amd_sfh1_1_hid_client_init(mp2);
420
if (rc) {
421
sfh_deinit_emp2();
422
if ((rc != -ENODEV) && (rc != -EOPNOTSUPP))
423
dev_err(dev, "amd_sfh1_1_hid_client_init failed\n");
424
return rc;
425
}
426
427
return rc;
428
}
429
430