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