3 * Copyright (c) 2012, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <linux/device.h>
20 #include <linux/platform_device.h>
21 #include <linux/module.h>
22 #include <linux/interrupt.h>
23 #include <linux/irq.h>
24 #include <linux/slab.h>
25 #include <linux/hid-sensor-hub.h>
26 #include <linux/iio/iio.h>
27 #include <linux/iio/sysfs.h>
31 int unit
; /* 0 for default others from HID sensor spec */
32 int scale_val0
; /* scale, whole number */
33 int scale_val1
; /* scale, fraction in nanos */
34 } unit_conversion
[] = {
35 {HID_USAGE_SENSOR_ACCEL_3D
, 0, 9, 806650000},
36 {HID_USAGE_SENSOR_ACCEL_3D
,
37 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD
, 1, 0},
38 {HID_USAGE_SENSOR_ACCEL_3D
,
39 HID_USAGE_SENSOR_UNITS_G
, 9, 806650000},
41 {HID_USAGE_SENSOR_GRAVITY_VECTOR
, 0, 9, 806650000},
42 {HID_USAGE_SENSOR_GRAVITY_VECTOR
,
43 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD
, 1, 0},
44 {HID_USAGE_SENSOR_GRAVITY_VECTOR
,
45 HID_USAGE_SENSOR_UNITS_G
, 9, 806650000},
47 {HID_USAGE_SENSOR_GYRO_3D
, 0, 0, 17453293},
48 {HID_USAGE_SENSOR_GYRO_3D
,
49 HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND
, 1, 0},
50 {HID_USAGE_SENSOR_GYRO_3D
,
51 HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND
, 0, 17453293},
53 {HID_USAGE_SENSOR_COMPASS_3D
, 0, 0, 1000000},
54 {HID_USAGE_SENSOR_COMPASS_3D
, HID_USAGE_SENSOR_UNITS_GAUSS
, 1, 0},
56 {HID_USAGE_SENSOR_INCLINOMETER_3D
, 0, 0, 17453293},
57 {HID_USAGE_SENSOR_INCLINOMETER_3D
,
58 HID_USAGE_SENSOR_UNITS_DEGREES
, 0, 17453293},
59 {HID_USAGE_SENSOR_INCLINOMETER_3D
,
60 HID_USAGE_SENSOR_UNITS_RADIANS
, 1, 0},
62 {HID_USAGE_SENSOR_ALS
, 0, 1, 0},
63 {HID_USAGE_SENSOR_ALS
, HID_USAGE_SENSOR_UNITS_LUX
, 1, 0},
65 {HID_USAGE_SENSOR_PRESSURE
, 0, 100, 0},
66 {HID_USAGE_SENSOR_PRESSURE
, HID_USAGE_SENSOR_UNITS_PASCAL
, 0, 1000000},
68 {HID_USAGE_SENSOR_TIME_TIMESTAMP
, 0, 1000000000, 0},
69 {HID_USAGE_SENSOR_TIME_TIMESTAMP
, HID_USAGE_SENSOR_UNITS_MILLISECOND
,
72 {HID_USAGE_SENSOR_DEVICE_ORIENTATION
, 0, 1, 0},
74 {HID_USAGE_SENSOR_RELATIVE_ORIENTATION
, 0, 1, 0},
76 {HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION
, 0, 1, 0},
78 {HID_USAGE_SENSOR_TEMPERATURE
, 0, 1000, 0},
79 {HID_USAGE_SENSOR_TEMPERATURE
, HID_USAGE_SENSOR_UNITS_DEGREES
, 1000, 0},
81 {HID_USAGE_SENSOR_HUMIDITY
, 0, 1000, 0},
84 static int pow_10(unsigned power
)
88 for (i
= 0; i
< power
; ++i
)
94 static void simple_div(int dividend
, int divisor
, int *whole
,
105 *whole
= dividend
/divisor
;
106 rem
= dividend
% divisor
;
108 while (rem
<= divisor
) {
112 *micro_frac
= (rem
/ divisor
) * pow_10(6-exp
);
116 static void split_micro_fraction(unsigned int no
, int exp
, int *val1
, int *val2
)
118 *val1
= no
/pow_10(exp
);
119 *val2
= no
%pow_10(exp
) * pow_10(6-exp
);
123 VTF format uses exponent and variable size format.
124 For example if the size is 2 bytes
125 0x0067 with VTF16E14 format -> +1.03
126 To convert just change to 0x67 to decimal and use two decimal as E14 stands
128 Negative numbers are 2's complement
130 static void convert_from_vtf_format(u32 value
, int size
, int exp
,
131 int *val1
, int *val2
)
135 if (value
& BIT(size
*8 - 1)) {
136 value
= ((1LL << (size
* 8)) - value
);
139 exp
= hid_sensor_convert_exponent(exp
);
141 *val1
= sign
* value
* pow_10(exp
);
144 split_micro_fraction(value
, -exp
, val1
, val2
);
146 *val1
= sign
* (*val1
);
148 *val2
= sign
* (*val2
);
152 static u32
convert_to_vtf_format(int size
, int exp
, int val1
, int val2
)
157 if (val1
< 0 || val2
< 0)
159 exp
= hid_sensor_convert_exponent(exp
);
161 value
= abs(val1
) * pow_10(-exp
);
162 value
+= abs(val2
) / pow_10(6+exp
);
164 value
= abs(val1
) / pow_10(exp
);
166 value
= ((1LL << (size
* 8)) - value
);
171 s32
hid_sensor_read_poll_value(struct hid_sensor_common
*st
)
176 ret
= sensor_hub_get_feature(st
->hsdev
,
178 st
->poll
.index
, sizeof(value
), &value
);
180 if (ret
< 0 || value
< 0) {
183 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
184 value
= value
* 1000;
189 EXPORT_SYMBOL(hid_sensor_read_poll_value
);
191 int hid_sensor_read_samp_freq_value(struct hid_sensor_common
*st
,
192 int *val1
, int *val2
)
197 ret
= sensor_hub_get_feature(st
->hsdev
,
199 st
->poll
.index
, sizeof(value
), &value
);
200 if (ret
< 0 || value
< 0) {
204 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_MILLISECOND
)
205 simple_div(1000, value
, val1
, val2
);
206 else if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
207 simple_div(1, value
, val1
, val2
);
214 return IIO_VAL_INT_PLUS_MICRO
;
216 EXPORT_SYMBOL(hid_sensor_read_samp_freq_value
);
218 int hid_sensor_write_samp_freq_value(struct hid_sensor_common
*st
,
224 if (val1
< 0 || val2
< 0)
227 value
= val1
* pow_10(6) + val2
;
229 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_MILLISECOND
)
230 value
= pow_10(9)/value
;
231 else if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
232 value
= pow_10(6)/value
;
236 ret
= sensor_hub_set_feature(st
->hsdev
, st
->poll
.report_id
,
237 st
->poll
.index
, sizeof(value
), &value
);
238 if (ret
< 0 || value
< 0)
241 ret
= sensor_hub_get_feature(st
->hsdev
,
243 st
->poll
.index
, sizeof(value
), &value
);
244 if (ret
< 0 || value
< 0)
247 st
->poll_interval
= value
;
251 EXPORT_SYMBOL(hid_sensor_write_samp_freq_value
);
253 int hid_sensor_read_raw_hyst_value(struct hid_sensor_common
*st
,
254 int *val1
, int *val2
)
259 ret
= sensor_hub_get_feature(st
->hsdev
,
260 st
->sensitivity
.report_id
,
261 st
->sensitivity
.index
, sizeof(value
),
263 if (ret
< 0 || value
< 0) {
267 convert_from_vtf_format(value
, st
->sensitivity
.size
,
268 st
->sensitivity
.unit_expo
,
272 return IIO_VAL_INT_PLUS_MICRO
;
274 EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value
);
276 int hid_sensor_write_raw_hyst_value(struct hid_sensor_common
*st
,
282 if (val1
< 0 || val2
< 0)
285 value
= convert_to_vtf_format(st
->sensitivity
.size
,
286 st
->sensitivity
.unit_expo
,
288 ret
= sensor_hub_set_feature(st
->hsdev
, st
->sensitivity
.report_id
,
289 st
->sensitivity
.index
, sizeof(value
),
291 if (ret
< 0 || value
< 0)
294 ret
= sensor_hub_get_feature(st
->hsdev
,
295 st
->sensitivity
.report_id
,
296 st
->sensitivity
.index
, sizeof(value
),
298 if (ret
< 0 || value
< 0)
301 st
->raw_hystersis
= value
;
305 EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value
);
308 * This fuction applies the unit exponent to the scale.
310 * 9.806650000 ->exp:2-> val0[980]val1[665000000]
311 * 9.000806000 ->exp:2-> val0[900]val1[80600000]
312 * 0.174535293 ->exp:2-> val0[17]val1[453529300]
313 * 1.001745329 ->exp:0-> val0[1]val1[1745329]
314 * 1.001745329 ->exp:2-> val0[100]val1[174532900]
315 * 1.001745329 ->exp:4-> val0[10017]val1[453290000]
316 * 9.806650000 ->exp:-2-> val0[0]val1[98066500]
318 static void adjust_exponent_nano(int *val0
, int *val1
, int scale0
,
327 *val0
= scale0
* pow_10(exp
);
333 for (i
= 0; i
< exp
; ++i
) {
334 x
= scale1
/ pow_10(8 - i
);
335 res
+= (pow_10(exp
- 1 - i
) * x
);
336 scale1
= scale1
% pow_10(8 - i
);
339 *val1
= scale1
* pow_10(exp
);
340 } else if (exp
< 0) {
346 *val0
= scale0
/ pow_10(exp
);
347 rem
= scale0
% pow_10(exp
);
349 for (i
= 0; i
< (9 - exp
); ++i
) {
350 x
= scale1
/ pow_10(8 - i
);
351 res
+= (pow_10(8 - exp
- i
) * x
);
352 scale1
= scale1
% pow_10(8 - i
);
354 *val1
= rem
* pow_10(9 - exp
) + res
;
361 int hid_sensor_format_scale(u32 usage_id
,
362 struct hid_sensor_hub_attribute_info
*attr_info
,
363 int *val0
, int *val1
)
371 for (i
= 0; i
< ARRAY_SIZE(unit_conversion
); ++i
) {
372 if (unit_conversion
[i
].usage_id
== usage_id
&&
373 unit_conversion
[i
].unit
== attr_info
->units
) {
374 exp
= hid_sensor_convert_exponent(
375 attr_info
->unit_expo
);
376 adjust_exponent_nano(val0
, val1
,
377 unit_conversion
[i
].scale_val0
,
378 unit_conversion
[i
].scale_val1
, exp
);
383 return IIO_VAL_INT_PLUS_NANO
;
385 EXPORT_SYMBOL(hid_sensor_format_scale
);
387 int64_t hid_sensor_convert_timestamp(struct hid_sensor_common
*st
,
390 return st
->timestamp_ns_scale
* raw_value
;
392 EXPORT_SYMBOL(hid_sensor_convert_timestamp
);
395 int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device
*hsdev
,
397 struct hid_sensor_common
*st
)
399 sensor_hub_input_get_attribute_info(hsdev
,
400 HID_FEATURE_REPORT
, usage_id
,
401 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL
,
403 /* Default unit of measure is milliseconds */
404 if (st
->poll
.units
== 0)
405 st
->poll
.units
= HID_USAGE_SENSOR_UNITS_MILLISECOND
;
407 st
->poll_interval
= -1;
413 static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device
*hsdev
,
415 struct hid_sensor_common
*st
)
417 sensor_hub_input_get_attribute_info(hsdev
, HID_FEATURE_REPORT
,
419 HID_USAGE_SENSOR_PROP_REPORT_LATENCY
,
420 &st
->report_latency
);
422 hid_dbg(hsdev
->hdev
, "Report latency attributes: %x:%x\n",
423 st
->report_latency
.index
, st
->report_latency
.report_id
);
426 int hid_sensor_get_report_latency(struct hid_sensor_common
*st
)
431 ret
= sensor_hub_get_feature(st
->hsdev
, st
->report_latency
.report_id
,
432 st
->report_latency
.index
, sizeof(value
),
439 EXPORT_SYMBOL(hid_sensor_get_report_latency
);
441 int hid_sensor_set_report_latency(struct hid_sensor_common
*st
, int latency_ms
)
443 return sensor_hub_set_feature(st
->hsdev
, st
->report_latency
.report_id
,
444 st
->report_latency
.index
,
445 sizeof(latency_ms
), &latency_ms
);
447 EXPORT_SYMBOL(hid_sensor_set_report_latency
);
449 bool hid_sensor_batch_mode_supported(struct hid_sensor_common
*st
)
451 return st
->report_latency
.index
> 0 && st
->report_latency
.report_id
> 0;
453 EXPORT_SYMBOL(hid_sensor_batch_mode_supported
);
455 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device
*hsdev
,
457 struct hid_sensor_common
*st
)
460 struct hid_sensor_hub_attribute_info timestamp
;
464 hid_sensor_get_reporting_interval(hsdev
, usage_id
, st
);
466 sensor_hub_input_get_attribute_info(hsdev
,
467 HID_FEATURE_REPORT
, usage_id
,
468 HID_USAGE_SENSOR_PROP_REPORT_STATE
,
471 sensor_hub_input_get_attribute_info(hsdev
,
472 HID_FEATURE_REPORT
, usage_id
,
473 HID_USAGE_SENSOR_PROY_POWER_STATE
,
476 st
->power_state
.logical_minimum
= 1;
477 st
->report_state
.logical_minimum
= 1;
479 sensor_hub_input_get_attribute_info(hsdev
,
480 HID_FEATURE_REPORT
, usage_id
,
481 HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS
,
484 st
->raw_hystersis
= -1;
486 sensor_hub_input_get_attribute_info(hsdev
,
487 HID_INPUT_REPORT
, usage_id
,
488 HID_USAGE_SENSOR_TIME_TIMESTAMP
,
490 if (timestamp
.index
>= 0 && timestamp
.report_id
) {
493 hid_sensor_format_scale(HID_USAGE_SENSOR_TIME_TIMESTAMP
,
494 ×tamp
, &val0
, &val1
);
495 st
->timestamp_ns_scale
= val0
;
497 st
->timestamp_ns_scale
= 1000000000;
499 hid_sensor_get_report_latency_info(hsdev
, usage_id
, st
);
501 hid_dbg(hsdev
->hdev
, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n",
502 st
->poll
.index
, st
->poll
.report_id
,
503 st
->report_state
.index
, st
->report_state
.report_id
,
504 st
->power_state
.index
, st
->power_state
.report_id
,
505 st
->sensitivity
.index
, st
->sensitivity
.report_id
,
506 timestamp
.index
, timestamp
.report_id
);
508 ret
= sensor_hub_get_feature(hsdev
,
509 st
->power_state
.report_id
,
510 st
->power_state
.index
, sizeof(value
), &value
);
518 EXPORT_SYMBOL(hid_sensor_parse_common_attributes
);
520 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
521 MODULE_DESCRIPTION("HID Sensor common attribute processing");
522 MODULE_LICENSE("GPL");