Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / iio / common / hid-sensors / hid-sensor-attributes.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HID Sensors Driver
4  * Copyright (c) 2012, Intel Corporation.
5  */
6 #include <linux/device.h>
7 #include <linux/platform_device.h>
8 #include <linux/module.h>
9 #include <linux/interrupt.h>
10 #include <linux/irq.h>
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
13 #include <linux/time.h>
14
15 #include <linux/hid-sensor-hub.h>
16 #include <linux/iio/iio.h>
17 #include <linux/iio/sysfs.h>
18
19 #define HZ_PER_MHZ      1000000L
20
21 static struct {
22         u32 usage_id;
23         int unit; /* 0 for default others from HID sensor spec */
24         int scale_val0; /* scale, whole number */
25         int scale_val1; /* scale, fraction in nanos */
26 } unit_conversion[] = {
27         {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650000},
28         {HID_USAGE_SENSOR_ACCEL_3D,
29                 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
30         {HID_USAGE_SENSOR_ACCEL_3D,
31                 HID_USAGE_SENSOR_UNITS_G, 9, 806650000},
32
33         {HID_USAGE_SENSOR_GRAVITY_VECTOR, 0, 9, 806650000},
34         {HID_USAGE_SENSOR_GRAVITY_VECTOR,
35                 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
36         {HID_USAGE_SENSOR_GRAVITY_VECTOR,
37                 HID_USAGE_SENSOR_UNITS_G, 9, 806650000},
38
39         {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453293},
40         {HID_USAGE_SENSOR_GYRO_3D,
41                 HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
42         {HID_USAGE_SENSOR_GYRO_3D,
43                 HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453293},
44
45         {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000000},
46         {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0},
47
48         {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453293},
49         {HID_USAGE_SENSOR_INCLINOMETER_3D,
50                 HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293},
51         {HID_USAGE_SENSOR_INCLINOMETER_3D,
52                 HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0},
53
54         {HID_USAGE_SENSOR_ALS, 0, 1, 0},
55         {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
56
57         {HID_USAGE_SENSOR_PRESSURE, 0, 100, 0},
58         {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000000},
59
60         {HID_USAGE_SENSOR_TIME_TIMESTAMP, 0, 1000000000, 0},
61         {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND,
62                 1000000, 0},
63
64         {HID_USAGE_SENSOR_DEVICE_ORIENTATION, 0, 1, 0},
65
66         {HID_USAGE_SENSOR_RELATIVE_ORIENTATION, 0, 1, 0},
67
68         {HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION, 0, 1, 0},
69
70         {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0},
71         {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0},
72
73         {HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0},
74 };
75
76 static void simple_div(int dividend, int divisor, int *whole,
77                                 int *micro_frac)
78 {
79         int rem;
80         int exp = 0;
81
82         *micro_frac = 0;
83         if (divisor == 0) {
84                 *whole = 0;
85                 return;
86         }
87         *whole = dividend/divisor;
88         rem = dividend % divisor;
89         if (rem) {
90                 while (rem <= divisor) {
91                         rem *= 10;
92                         exp++;
93                 }
94                 *micro_frac = (rem / divisor) * int_pow(10, 6 - exp);
95         }
96 }
97
98 static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2)
99 {
100         int divisor = int_pow(10, exp);
101
102         *val1 = no / divisor;
103         *val2 = no % divisor * int_pow(10, 6 - exp);
104 }
105
106 /*
107 VTF format uses exponent and variable size format.
108 For example if the size is 2 bytes
109 0x0067 with VTF16E14 format -> +1.03
110 To convert just change to 0x67 to decimal and use two decimal as E14 stands
111 for 10^-2.
112 Negative numbers are 2's complement
113 */
114 static void convert_from_vtf_format(u32 value, int size, int exp,
115                                         int *val1, int *val2)
116 {
117         int sign = 1;
118
119         if (value & BIT(size*8 - 1)) {
120                 value =  ((1LL << (size * 8)) - value);
121                 sign = -1;
122         }
123         exp = hid_sensor_convert_exponent(exp);
124         if (exp >= 0) {
125                 *val1 = sign * value * int_pow(10, exp);
126                 *val2 = 0;
127         } else {
128                 split_micro_fraction(value, -exp, val1, val2);
129                 if (*val1)
130                         *val1 = sign * (*val1);
131                 else
132                         *val2 = sign * (*val2);
133         }
134 }
135
136 static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
137 {
138         int divisor;
139         u32 value;
140         int sign = 1;
141
142         if (val1 < 0 || val2 < 0)
143                 sign = -1;
144         exp = hid_sensor_convert_exponent(exp);
145         if (exp < 0) {
146                 divisor = int_pow(10, 6 + exp);
147                 value = abs(val1) * int_pow(10, -exp);
148                 value += abs(val2) / divisor;
149         } else {
150                 divisor = int_pow(10, exp);
151                 value = abs(val1) / divisor;
152         }
153         if (sign < 0)
154                 value =  ((1LL << (size * 8)) - value);
155
156         return value;
157 }
158
159 s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
160 {
161         s32 value = 0;
162         int ret;
163
164         ret = sensor_hub_get_feature(st->hsdev,
165                                      st->poll.report_id,
166                                      st->poll.index, sizeof(value), &value);
167
168         if (ret < 0 || value < 0) {
169                 return -EINVAL;
170         } else {
171                 if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
172                         value = value * 1000;
173         }
174
175         return value;
176 }
177 EXPORT_SYMBOL(hid_sensor_read_poll_value);
178
179 int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
180                                 int *val1, int *val2)
181 {
182         s32 value;
183         int ret;
184
185         ret = sensor_hub_get_feature(st->hsdev,
186                                      st->poll.report_id,
187                                      st->poll.index, sizeof(value), &value);
188         if (ret < 0 || value < 0) {
189                 *val1 = *val2 = 0;
190                 return -EINVAL;
191         } else {
192                 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
193                         simple_div(1000, value, val1, val2);
194                 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
195                         simple_div(1, value, val1, val2);
196                 else {
197                         *val1 = *val2 = 0;
198                         return -EINVAL;
199                 }
200         }
201
202         return IIO_VAL_INT_PLUS_MICRO;
203 }
204 EXPORT_SYMBOL(hid_sensor_read_samp_freq_value);
205
206 int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
207                                 int val1, int val2)
208 {
209         s32 value;
210         int ret;
211
212         if (val1 < 0 || val2 < 0)
213                 return -EINVAL;
214
215         value = val1 * HZ_PER_MHZ + val2;
216         if (value) {
217                 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
218                         value = NSEC_PER_SEC / value;
219                 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
220                         value = USEC_PER_SEC / value;
221                 else
222                         value = 0;
223         }
224         ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id,
225                                      st->poll.index, sizeof(value), &value);
226         if (ret < 0 || value < 0)
227                 return -EINVAL;
228
229         ret = sensor_hub_get_feature(st->hsdev,
230                                      st->poll.report_id,
231                                      st->poll.index, sizeof(value), &value);
232         if (ret < 0 || value < 0)
233                 return -EINVAL;
234
235         st->poll_interval = value;
236
237         return 0;
238 }
239 EXPORT_SYMBOL(hid_sensor_write_samp_freq_value);
240
241 int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
242                                 int *val1, int *val2)
243 {
244         s32 value;
245         int ret;
246
247         ret = sensor_hub_get_feature(st->hsdev,
248                                      st->sensitivity.report_id,
249                                      st->sensitivity.index, sizeof(value),
250                                      &value);
251         if (ret < 0 || value < 0) {
252                 *val1 = *val2 = 0;
253                 return -EINVAL;
254         } else {
255                 convert_from_vtf_format(value, st->sensitivity.size,
256                                         st->sensitivity.unit_expo,
257                                         val1, val2);
258         }
259
260         return IIO_VAL_INT_PLUS_MICRO;
261 }
262 EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value);
263
264 int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
265                                         int val1, int val2)
266 {
267         s32 value;
268         int ret;
269
270         if (val1 < 0 || val2 < 0)
271                 return -EINVAL;
272
273         value = convert_to_vtf_format(st->sensitivity.size,
274                                 st->sensitivity.unit_expo,
275                                 val1, val2);
276         ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id,
277                                      st->sensitivity.index, sizeof(value),
278                                      &value);
279         if (ret < 0 || value < 0)
280                 return -EINVAL;
281
282         ret = sensor_hub_get_feature(st->hsdev,
283                                      st->sensitivity.report_id,
284                                      st->sensitivity.index, sizeof(value),
285                                      &value);
286         if (ret < 0 || value < 0)
287                 return -EINVAL;
288
289         st->raw_hystersis = value;
290
291         return 0;
292 }
293 EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
294
295 /*
296  * This fuction applies the unit exponent to the scale.
297  * For example:
298  * 9.806650000 ->exp:2-> val0[980]val1[665000000]
299  * 9.000806000 ->exp:2-> val0[900]val1[80600000]
300  * 0.174535293 ->exp:2-> val0[17]val1[453529300]
301  * 1.001745329 ->exp:0-> val0[1]val1[1745329]
302  * 1.001745329 ->exp:2-> val0[100]val1[174532900]
303  * 1.001745329 ->exp:4-> val0[10017]val1[453290000]
304  * 9.806650000 ->exp:-2-> val0[0]val1[98066500]
305  */
306 static void adjust_exponent_nano(int *val0, int *val1, int scale0,
307                                   int scale1, int exp)
308 {
309         int divisor;
310         int i;
311         int x;
312         int res;
313         int rem;
314
315         if (exp > 0) {
316                 *val0 = scale0 * int_pow(10, exp);
317                 res = 0;
318                 if (exp > 9) {
319                         *val1 = 0;
320                         return;
321                 }
322                 for (i = 0; i < exp; ++i) {
323                         divisor = int_pow(10, 8 - i);
324                         x = scale1 / divisor;
325                         res += int_pow(10, exp - 1 - i) * x;
326                         scale1 = scale1 % divisor;
327                 }
328                 *val0 += res;
329                 *val1 = scale1 * int_pow(10, exp);
330         } else if (exp < 0) {
331                 exp = abs(exp);
332                 if (exp > 9) {
333                         *val0 = *val1 = 0;
334                         return;
335                 }
336                 divisor = int_pow(10, exp);
337                 *val0 = scale0 / divisor;
338                 rem = scale0 % divisor;
339                 res = 0;
340                 for (i = 0; i < (9 - exp); ++i) {
341                         divisor = int_pow(10, 8 - i);
342                         x = scale1 / divisor;
343                         res += int_pow(10, 8 - exp - i) * x;
344                         scale1 = scale1 % divisor;
345                 }
346                 *val1 = rem * int_pow(10, 9 - exp) + res;
347         } else {
348                 *val0 = scale0;
349                 *val1 = scale1;
350         }
351 }
352
353 int hid_sensor_format_scale(u32 usage_id,
354                         struct hid_sensor_hub_attribute_info *attr_info,
355                         int *val0, int *val1)
356 {
357         int i;
358         int exp;
359
360         *val0 = 1;
361         *val1 = 0;
362
363         for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) {
364                 if (unit_conversion[i].usage_id == usage_id &&
365                         unit_conversion[i].unit == attr_info->units) {
366                         exp  = hid_sensor_convert_exponent(
367                                                 attr_info->unit_expo);
368                         adjust_exponent_nano(val0, val1,
369                                         unit_conversion[i].scale_val0,
370                                         unit_conversion[i].scale_val1, exp);
371                         break;
372                 }
373         }
374
375         return IIO_VAL_INT_PLUS_NANO;
376 }
377 EXPORT_SYMBOL(hid_sensor_format_scale);
378
379 int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st,
380                                      int64_t raw_value)
381 {
382         return st->timestamp_ns_scale * raw_value;
383 }
384 EXPORT_SYMBOL(hid_sensor_convert_timestamp);
385
386 static
387 int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
388                                         u32 usage_id,
389                                         struct hid_sensor_common *st)
390 {
391         sensor_hub_input_get_attribute_info(hsdev,
392                                         HID_FEATURE_REPORT, usage_id,
393                                         HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
394                                         &st->poll);
395         /* Default unit of measure is milliseconds */
396         if (st->poll.units == 0)
397                 st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND;
398
399         st->poll_interval = -1;
400
401         return 0;
402
403 }
404
405 static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device *hsdev,
406                                                u32 usage_id,
407                                                struct hid_sensor_common *st)
408 {
409         sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,
410                                             usage_id,
411                                             HID_USAGE_SENSOR_PROP_REPORT_LATENCY,
412                                             &st->report_latency);
413
414         hid_dbg(hsdev->hdev, "Report latency attributes: %x:%x\n",
415                 st->report_latency.index, st->report_latency.report_id);
416 }
417
418 int hid_sensor_get_report_latency(struct hid_sensor_common *st)
419 {
420         int ret;
421         int value;
422
423         ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id,
424                                      st->report_latency.index, sizeof(value),
425                                      &value);
426         if (ret < 0)
427                 return ret;
428
429         return value;
430 }
431 EXPORT_SYMBOL(hid_sensor_get_report_latency);
432
433 int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms)
434 {
435         return sensor_hub_set_feature(st->hsdev, st->report_latency.report_id,
436                                       st->report_latency.index,
437                                       sizeof(latency_ms), &latency_ms);
438 }
439 EXPORT_SYMBOL(hid_sensor_set_report_latency);
440
441 bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st)
442 {
443         return st->report_latency.index > 0 && st->report_latency.report_id > 0;
444 }
445 EXPORT_SYMBOL(hid_sensor_batch_mode_supported);
446
447 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
448                                         u32 usage_id,
449                                         struct hid_sensor_common *st)
450 {
451
452         struct hid_sensor_hub_attribute_info timestamp;
453         s32 value;
454         int ret;
455
456         hid_sensor_get_reporting_interval(hsdev, usage_id, st);
457
458         sensor_hub_input_get_attribute_info(hsdev,
459                                         HID_FEATURE_REPORT, usage_id,
460                                         HID_USAGE_SENSOR_PROP_REPORT_STATE,
461                                         &st->report_state);
462
463         sensor_hub_input_get_attribute_info(hsdev,
464                                         HID_FEATURE_REPORT, usage_id,
465                                         HID_USAGE_SENSOR_PROY_POWER_STATE,
466                                         &st->power_state);
467
468         st->power_state.logical_minimum = 1;
469         st->report_state.logical_minimum = 1;
470
471         sensor_hub_input_get_attribute_info(hsdev,
472                         HID_FEATURE_REPORT, usage_id,
473                         HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
474                          &st->sensitivity);
475
476         st->raw_hystersis = -1;
477
478         sensor_hub_input_get_attribute_info(hsdev,
479                                             HID_INPUT_REPORT, usage_id,
480                                             HID_USAGE_SENSOR_TIME_TIMESTAMP,
481                                             &timestamp);
482         if (timestamp.index >= 0 && timestamp.report_id) {
483                 int val0, val1;
484
485                 hid_sensor_format_scale(HID_USAGE_SENSOR_TIME_TIMESTAMP,
486                                         &timestamp, &val0, &val1);
487                 st->timestamp_ns_scale = val0;
488         } else
489                 st->timestamp_ns_scale = 1000000000;
490
491         hid_sensor_get_report_latency_info(hsdev, usage_id, st);
492
493         hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n",
494                 st->poll.index, st->poll.report_id,
495                 st->report_state.index, st->report_state.report_id,
496                 st->power_state.index, st->power_state.report_id,
497                 st->sensitivity.index, st->sensitivity.report_id,
498                 timestamp.index, timestamp.report_id);
499
500         ret = sensor_hub_get_feature(hsdev,
501                                 st->power_state.report_id,
502                                 st->power_state.index, sizeof(value), &value);
503         if (ret < 0)
504                 return ret;
505         if (value < 0)
506                 return -EINVAL;
507
508         return 0;
509 }
510 EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
511
512 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
513 MODULE_DESCRIPTION("HID Sensor common attribute processing");
514 MODULE_LICENSE("GPL");