blob: 2b2225654fb7371824e553113644ae9cf193fbcf [file] [log] [blame]
rbandi127f7ad2018-09-06 16:28:40 -07001/*
Kedi Xu8e929032019-02-22 14:29:46 +08002 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
rbandi127f7ad2018-09-06 16:28:40 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/kobject.h>
16#include <linux/string.h>
17#include <linux/sysfs.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/msm_ion.h>
21#include <linux/usb.h>
22#include <linux/slab.h>
23#include <linux/hid.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/input.h>
27#include <linux/hiddev.h>
28#include <linux/hid-debug.h>
29#include <linux/hidraw.h>
30#include <linux/device.h>
31#include <linux/of_gpio.h>
32#include <linux/of_irq.h>
33#include <linux/gpio.h>
34#include <linux/timekeeping.h>
35#include <linux/ion.h>
36#include "../soc/qcom/smp2p_private.h"
37#include "hid-ids.h"
38#include "hid-qvr.h"
rbandi32f19a62018-10-18 11:31:32 -070039#include "hid-trace.h"
rbandi127f7ad2018-09-06 16:28:40 -070040
41static struct ion_handle *handle;
42static struct ion_client *client;
43static void *vaddr;
44static size_t vsize;
45static uint64_t ts_base;
46static uint64_t ts_offset;
47static int msg_size = 368;
48
49struct gpio_info {
50 int gpio_base_id;
51 int irq_base_id;
52};
53
54
55/* GPIO Inbound/Outbound callback info */
56struct gpio_inout {
57 struct gpio_info in;
58 struct gpio_info out;
59};
60
61static struct gpio_inout gpio_info[SMP2P_NUM_PROCS];
62static struct gpio_info *in_gpio_info_ptr;
63static struct gpio_info *out_gpio_info_ptr;
64
65
66static struct hid_driver qvr_external_sensor_driver;
67static int fd;
68
69
70struct ion_handle {
71 struct kref ref;
72 unsigned int user_ref_count;
73 struct ion_client *client;
74 struct ion_buffer *buffer;
75 struct rb_node node;
76 unsigned int kmap_cnt;
77 int id;
78};
79
80struct qvr_buf_index {
81 int most_recent_index;
82 uint8_t padding[60];
83};
84
85struct qvr_sensor_t {
86 uint64_t gts;
87 uint64_t ats;
88 uint64_t mts;
89 s32 gx;
90 s32 gy;
91 s32 gz;
92 s32 ax;
93 s32 ay;
94 s32 az;
95 s32 mx;
96 s32 my;
97 s32 mz;
98 uint8_t padding[4];
99};
100
101
102int qvr_send_package_wrap(u8 *message, int msize, struct hid_device *hid)
103{
104 struct qvr_sensor_t *sensor_buf;
105 struct qvr_sensor_t *data;
106 static int buf_index;
107 struct external_imu_format imuData = { 0 };
108 struct qvr_buf_index *index_buf;
109
110 /*
111 * Actual message size is 369 bytes
112 * to make it 8 byte aligned we created a structure of size 368 bytes.
113 * Ignoring the first byte 'report id' (which is always 1)
114 *
115 */
116 memcpy((void *)&imuData, (void *)message + 1, msg_size);
117
118 if (!ts_base)
119 ts_base = ktime_to_ns(ktime_get_boottime());
120 if (!ts_offset)
121 ts_offset = imuData.gts0;
122 index_buf = (struct qvr_buf_index *)
123 ((uintptr_t)vaddr + (vsize / 2) + (8 * sizeof(*sensor_buf)));
124 sensor_buf = (struct qvr_sensor_t *)((uintptr_t)vaddr + (vsize / 2));
125
126 data = (struct qvr_sensor_t *)&(sensor_buf[buf_index]);
127 if (ts_offset > imuData.gts0)
128 data->ats = ts_base + ((ts_offset - imuData.gts0) * 100);
129 else
130 data->ats = ts_base + ((imuData.gts0 - ts_offset) * 100);
131 if (imuData.mts0 == 0)
132 data->mts = 0;
133 else
134 data->mts = data->ats;
135 data->gts = data->ats;
136 data->ax = -imuData.ax0;
137 data->ay = imuData.ay0;
138 data->az = -imuData.az0;
139 data->gx = -imuData.gx0;
140 data->gy = imuData.gy0;
141 data->gz = -imuData.gz0;
Kedi Xu8e929032019-02-22 14:29:46 +0800142 data->mx = -imuData.my0;
143 data->my = -imuData.mx0;
rbandi127f7ad2018-09-06 16:28:40 -0700144 data->mz = -imuData.mz0;
145
rbandi32f19a62018-10-18 11:31:32 -0700146 trace_qvr_recv_sensor("gyro", data->gts, data->gx, data->gy, data->gz);
147 trace_qvr_recv_sensor("accel", data->ats, data->ax, data->ay, data->az);
148
rbandi127f7ad2018-09-06 16:28:40 -0700149 pr_debug("%s: gts= %llu, gx= %d, gy=%d, gz=%d", __func__,
150 data->gts, data->gx, data->gy, data->gz);
151 pr_debug("%s: ats= %llu, ax= %d, ay=%d, az=%d", __func__,
152 data->ats, data->ax, data->ay, data->az);
153 pr_debug("%s: mts= %llu, mx= %d, my=%d, mz=%d", __func__,
154 data->mts, data->mx, data->my, data->mz);
155
156 index_buf->most_recent_index = buf_index;
157 buf_index = (buf_index == (8 - 1)) ? 0 : buf_index + 1;
158 return 0;
159}
160
161static int register_smp2p(char *node_name, struct gpio_info *gpio_info_ptr)
162{
163 struct device_node *node = NULL;
164 int cnt = 0;
165 int id = 0;
166
167 node = of_find_compatible_node(NULL, NULL, node_name);
168 if (node) {
169 cnt = of_gpio_count(node);
170 if (cnt && gpio_info_ptr) {
171 id = of_get_gpio(node, 0);
172 if (id == -EPROBE_DEFER)
173 return id;
174 gpio_info_ptr->gpio_base_id = id;
175 gpio_info_ptr->irq_base_id = gpio_to_irq(id);
176 return 0;
177 }
178 }
179 return -EINVAL;
180}
181
182
183
184static int kernel_map_gyro_buffer(int fd)
185{
186 handle = ion_import_dma_buf_fd(client, fd);
187 if (IS_ERR(handle)) {
188 pr_err("%s: ion_import_dma_buf_fd failed\n", __func__);
189 return -EINVAL;
190 }
191
192 if (ion_handle_get_size(client, handle, &vsize)) {
193 pr_err("%s: Could not dma buf %d size\n", __func__, fd);
194 return -EINVAL;
195 }
196
197 vaddr = ion_map_kernel(client, handle);
198 if (IS_ERR_OR_NULL(vaddr)) {
199 ion_free(client, handle);
200 return -EINVAL;
201 }
202
203 return 0;
204}
205
206
207static void kernel_unmap_gyro_buffer(void)
208{
209 if (!IS_ERR_OR_NULL(vaddr)) {
210 ion_unmap_kernel(client, handle);
211 ion_free(client, handle);
212 vaddr = NULL;
213 }
214}
215
216static ssize_t fd_show(struct kobject *kobj,
217 struct kobj_attribute *attr,
218 char *buf)
219{
220 return snprintf(buf, 16, "%d\n", fd);
221}
222
223static ssize_t fd_store(struct kobject *kobj,
224 struct kobj_attribute *attr,
225 const char *buf, size_t count)
226{
227 int ret;
228
229 ret = kstrtoint(buf, 10, &fd);
230 if (ret < 0)
231 return ret;
232 if (fd == -1)
233 kernel_unmap_gyro_buffer();
234 else
235 kernel_map_gyro_buffer(fd);
236 ts_base = 0;
237 ts_offset = 0;
238
239 return count;
240}
241
242static ssize_t ts_base_show(struct kobject *kobj,
243 struct kobj_attribute *attr, char *buf)
244{
245 return snprintf(buf, 16, "%lld\n", ts_base);
246}
247
248static ssize_t ts_base_store(struct kobject *kobj,
249 struct kobj_attribute *attr,
250 const char *buf, size_t count)
251{
252 return 0;
253}
254
255static ssize_t ts_offset_show(struct kobject *kobj,
256 struct kobj_attribute *attr, char *buf)
257{
258 return snprintf(buf, 16, "%lld\n", ts_offset * 100);
259}
260
261static ssize_t ts_offset_store(struct kobject *kobj,
262 struct kobj_attribute *attr,
263 const char *buf, size_t count)
264{
265 return 0;
266}
267
268static struct kobj_attribute fd_attribute = __ATTR(fd, 0664,
269 fd_show,
270 fd_store);
271static struct kobj_attribute ts_base_attribute = __ATTR(ts_base, 0664,
272 ts_base_show,
273 ts_base_store);
274static struct kobj_attribute ts_offset_attribute = __ATTR(ts_offset, 0664,
275 ts_offset_show,
276 ts_offset_store);
277
278static struct attribute *attrs[] = {
279 &fd_attribute.attr,
280 &ts_base_attribute.attr,
281 &ts_offset_attribute.attr,
282 NULL,
283};
284
285static struct attribute_group attr_group = {
286 .attrs = attrs,
287};
288
289static struct kobject *qvr_external_sensor_kobj;
290
291static int qvr_external_sensor_probe(struct hid_device *hdev,
292 const struct hid_device_id *id)
293{
294 int ret;
295 char *in_node_name = "qcom,smp2pgpio_client_qvrexternal_5_in";
296 char *out_node_name = "qcom,smp2pgpio_client_qvrexternal_5_out";
297 __u8 hid_buf[255] = { 0 };
298 size_t hid_count = 64;
299
300 ret = register_smp2p(in_node_name, in_gpio_info_ptr);
301 if (ret) {
302 pr_err("%s: register_smp2p failed", __func__);
303 goto err_free;
304 }
305 ret = register_smp2p(out_node_name, out_gpio_info_ptr);
306 if (ret) {
307 pr_err("%s: register_smp2p failed", __func__);
308 goto err_free;
309 }
310 ret = hid_open_report(hdev);
311 if (ret) {
312 pr_err("%s: hid_open_report failed", __func__);
313 goto err_free;
314 }
315 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
316 if (ret) {
317 pr_err("%s: hid_hw_start failed", __func__);
318 goto err_free;
319 }
rbandi86740332018-10-22 11:20:30 -0700320 hid_buf[0] = 2;
321 hid_buf[1] = 7;
322 ret = hid_hw_raw_request(hdev, hid_buf[0],
323 hid_buf,
324 hid_count,
325 HID_FEATURE_REPORT,
326 HID_REQ_SET_REPORT);
rbandi127f7ad2018-09-06 16:28:40 -0700327 return 0;
328err_free:
329 return ret;
330
331}
332
333static int qvr_external_sensor_raw_event(struct hid_device *hid,
334 struct hid_report *report,
335 u8 *data, int size)
336{
337 int val;
338 int ret = -1;
339
rbandi86740332018-10-22 11:20:30 -0700340 if (vaddr != NULL && report->id == 0x1) {
rbandi127f7ad2018-09-06 16:28:40 -0700341 ret = qvr_send_package_wrap(data/*hid_value*/, size, hid);
342 if (ret != 0) {
343 pr_err("%s: qvr_send_package_wrap failed", __func__);
344 return ret;
345 }
346 val = 1 ^ gpio_get_value(out_gpio_info_ptr->gpio_base_id + 0);
347 gpio_set_value(out_gpio_info_ptr->gpio_base_id + 0, val);
348 ret = -1;
349 }
350 return ret;
351}
352
353static void qvr_external_sensor_device_remove(struct hid_device *hdev)
354{
355 hid_hw_stop(hdev);
356}
357
358static struct hid_device_id qvr_external_sensor_table[] = {
359 { HID_USB_DEVICE(USB_VENDOR_ID_QVR5, USB_DEVICE_ID_QVR5) },
rbandi86740332018-10-22 11:20:30 -0700360 { HID_USB_DEVICE(USB_VENDOR_ID_QVR32A, USB_DEVICE_ID_QVR32A) },
rbandi127f7ad2018-09-06 16:28:40 -0700361 { }
362};
363MODULE_DEVICE_TABLE(hid, qvr_external_sensor_table);
364
365static struct hid_driver qvr_external_sensor_driver = {
366 .name = "qvr_external_sensor",
367 .id_table = qvr_external_sensor_table,
368 .probe = qvr_external_sensor_probe,
369 .raw_event = qvr_external_sensor_raw_event,
370 .remove = qvr_external_sensor_device_remove,
371};
372
373module_hid_driver(qvr_external_sensor_driver);
374
375static int __init qvr_external_sensor_init(void)
376{
377 const char *device_name = "aoe";
378 int ret = 0;
379
380 in_gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].in;
381 in_gpio_info_ptr->gpio_base_id = -1;
382 out_gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].out;
383 out_gpio_info_ptr->gpio_base_id = -1;
384
385
386 qvr_external_sensor_kobj =
387 kobject_create_and_add("qvr_external_sensor", kernel_kobj);
388
389 if (!qvr_external_sensor_kobj) {
390 pr_err("%s: kobject_create_and_add() fail\n", __func__);
391 return -ENOMEM;
392 }
393
394 ret = sysfs_create_group(qvr_external_sensor_kobj, &attr_group);
395 if (ret) {
396 pr_err("%s: can't register sysfs\n", __func__);
397 return -ENOMEM;
398 }
399
400 client = msm_ion_client_create(device_name);
401 if (client == NULL) {
402 pr_err("msm_ion_client_create failed in %s", __func__);
403 return -EINVAL;
404 }
405
406 return ret;
407}
408
409static void __exit qvr_external_sensor_exit(void)
410{
411 kobject_put(qvr_external_sensor_kobj);
412}
413
414module_init(qvr_external_sensor_init);
415module_exit(qvr_external_sensor_exit);
416MODULE_LICENSE("GPL v2");
417