1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright 2020 Advanced Micro Devices, Inc.
5 * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>
6 * Sandeep Singh <Sandeep.singh@amd.com>
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>
16 #include "hid_descriptor/amd_sfh_hid_desc.h"
17 #include "amd_sfh_pcie.h"
18 #include "amd_sfh_hid.h"
20 #define AMD_SFH_IDLE_LOOP 200
23 struct hid_device
*hid
;
24 struct list_head list
;
31 static struct request_list req_list
;
33 void amd_sfh_set_report(struct hid_device
*hid
, int report_id
,
36 struct amdtp_hid_data
*hid_data
= hid
->driver_data
;
37 struct amdtp_cl_data
*cli_data
= hid_data
->cli_data
;
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
;
46 amdtp_hid_wakeup(hid
);
49 int amd_sfh_get_report(struct hid_device
*hid
, int report_id
, int report_type
)
51 struct amdtp_hid_data
*hid_data
= hid
->driver_data
;
52 struct amdtp_cl_data
*cli_data
= hid_data
->cli_data
;
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
);
62 new->current_index
= i
;
63 new->sensor_idx
= cli_data
->sensor_idx
[i
];
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
);
73 schedule_delayed_work(&cli_data
->work
, 0);
77 static void amd_sfh_work(struct work_struct
*work
)
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
;
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
;
92 if (node_type
== HID_FEATURE_REPORT
) {
93 report_size
= get_feature_report(sensor_index
, report_id
,
94 cli_data
->feature_report
[current_index
]);
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);
100 pr_err("AMDSFH: Invalid report size\n");
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
]);
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);
111 pr_err("AMDSFH: Invalid report size\n");
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
]);
118 static void amd_sfh_work_buffer(struct work_struct
*work
)
120 struct amdtp_cl_data
*cli_data
= container_of(work
, struct amdtp_cl_data
, work_buffer
.work
);
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);
131 schedule_delayed_work(&cli_data
->work_buffer
, msecs_to_jiffies(AMD_SFH_IDLE_LOOP
));
134 int amd_sfh_hid_client_init(struct amd_mp2_dev
*privdata
)
136 struct amdtp_cl_data
*cl_data
= privdata
->cl_data
;
137 struct amd_mp2_sensor_info info
;
139 u32 feature_report_size
;
140 u32 input_report_size
;
144 dev
= &privdata
->pdev
->dev
;
145 cl_data
= kzalloc(sizeof(*cl_data
), GFP_KERNEL
);
149 cl_data
->num_hid_devices
= amd_mp2_get_sensor_num(privdata
, &cl_data
->sensor_idx
[0]);
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
);
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
],
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
]) {
168 feature_report_size
= get_descr_sz(cl_idx
, feature_size
);
169 if (!feature_report_size
) {
173 input_report_size
= get_descr_sz(cl_idx
, input_size
);
174 if (!input_report_size
) {
178 cl_data
->feature_report
[i
] = kzalloc(feature_report_size
, GFP_KERNEL
);
179 if (!cl_data
->feature_report
[i
]) {
183 cl_data
->input_report
[i
] = kzalloc(input_report_size
, GFP_KERNEL
);
184 if (!cl_data
->input_report
[i
]) {
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
];
192 cl_data
->report_descr
[i
] = kzalloc(cl_data
->report_descr_sz
[i
], GFP_KERNEL
);
193 if (!cl_data
->report_descr
[i
]) {
197 rc
= get_report_descriptor(cl_idx
, cl_data
->report_descr
[i
]);
200 rc
= amdtp_hid_probe(cl_data
->cur_hid_dev
, cl_data
);
203 amd_start_sensor(privdata
, info
);
204 cl_data
->sensor_sts
[i
] = 1;
206 privdata
->cl_data
= cl_data
;
207 schedule_delayed_work(&cl_data
->work_buffer
, msecs_to_jiffies(AMD_SFH_IDLE_LOOP
));
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
]);
217 kfree(cl_data
->feature_report
[i
]);
218 kfree(cl_data
->input_report
[i
]);
219 kfree(cl_data
->report_descr
[i
]);
225 int amd_sfh_hid_client_deinit(struct amd_mp2_dev
*privdata
)
227 struct amdtp_cl_data
*cl_data
= privdata
->cl_data
;
230 for (i
= 0; i
< cl_data
->num_hid_devices
; i
++)
231 amd_stop_sensor(privdata
, i
);
233 cancel_delayed_work_sync(&cl_data
->work
);
234 cancel_delayed_work_sync(&cl_data
->work_buffer
);
235 amdtp_hid_remove(cl_data
);
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
]);