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_GYRO_3D
, 0, 0, 17453293},
42 {HID_USAGE_SENSOR_GYRO_3D
,
43 HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND
, 1, 0},
44 {HID_USAGE_SENSOR_GYRO_3D
,
45 HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND
, 0, 17453293},
47 {HID_USAGE_SENSOR_COMPASS_3D
, 0, 0, 1000000},
48 {HID_USAGE_SENSOR_COMPASS_3D
, HID_USAGE_SENSOR_UNITS_GAUSS
, 1, 0},
50 {HID_USAGE_SENSOR_INCLINOMETER_3D
, 0, 0, 17453293},
51 {HID_USAGE_SENSOR_INCLINOMETER_3D
,
52 HID_USAGE_SENSOR_UNITS_DEGREES
, 0, 17453293},
53 {HID_USAGE_SENSOR_INCLINOMETER_3D
,
54 HID_USAGE_SENSOR_UNITS_RADIANS
, 1, 0},
56 {HID_USAGE_SENSOR_ALS
, 0, 1, 0},
57 {HID_USAGE_SENSOR_ALS
, HID_USAGE_SENSOR_UNITS_LUX
, 1, 0},
59 {HID_USAGE_SENSOR_PRESSURE
, 0, 100, 0},
60 {HID_USAGE_SENSOR_PRESSURE
, HID_USAGE_SENSOR_UNITS_PASCAL
, 0, 1000000},
63 static int pow_10(unsigned power
)
67 for (i
= 0; i
< power
; ++i
)
73 static void simple_div(int dividend
, int divisor
, int *whole
,
84 *whole
= dividend
/divisor
;
85 rem
= dividend
% divisor
;
87 while (rem
<= divisor
) {
91 *micro_frac
= (rem
/ divisor
) * pow_10(6-exp
);
95 static void split_micro_fraction(unsigned int no
, int exp
, int *val1
, int *val2
)
97 *val1
= no
/pow_10(exp
);
98 *val2
= no
%pow_10(exp
) * pow_10(6-exp
);
102 VTF format uses exponent and variable size format.
103 For example if the size is 2 bytes
104 0x0067 with VTF16E14 format -> +1.03
105 To convert just change to 0x67 to decimal and use two decimal as E14 stands
107 Negative numbers are 2's complement
109 static void convert_from_vtf_format(u32 value
, int size
, int exp
,
110 int *val1
, int *val2
)
114 if (value
& BIT(size
*8 - 1)) {
115 value
= ((1LL << (size
* 8)) - value
);
118 exp
= hid_sensor_convert_exponent(exp
);
120 *val1
= sign
* value
* pow_10(exp
);
123 split_micro_fraction(value
, -exp
, val1
, val2
);
125 *val1
= sign
* (*val1
);
127 *val2
= sign
* (*val2
);
131 static u32
convert_to_vtf_format(int size
, int exp
, int val1
, int val2
)
136 if (val1
< 0 || val2
< 0)
138 exp
= hid_sensor_convert_exponent(exp
);
140 value
= abs(val1
) * pow_10(-exp
);
141 value
+= abs(val2
) / pow_10(6+exp
);
143 value
= abs(val1
) / pow_10(exp
);
145 value
= ((1LL << (size
* 8)) - value
);
150 s32
hid_sensor_read_poll_value(struct hid_sensor_common
*st
)
155 ret
= sensor_hub_get_feature(st
->hsdev
,
157 st
->poll
.index
, sizeof(value
), &value
);
159 if (ret
< 0 || value
< 0) {
162 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
163 value
= value
* 1000;
168 EXPORT_SYMBOL(hid_sensor_read_poll_value
);
170 int hid_sensor_read_samp_freq_value(struct hid_sensor_common
*st
,
171 int *val1
, int *val2
)
176 ret
= sensor_hub_get_feature(st
->hsdev
,
178 st
->poll
.index
, sizeof(value
), &value
);
179 if (ret
< 0 || value
< 0) {
183 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_MILLISECOND
)
184 simple_div(1000, value
, val1
, val2
);
185 else if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
186 simple_div(1, value
, val1
, val2
);
193 return IIO_VAL_INT_PLUS_MICRO
;
195 EXPORT_SYMBOL(hid_sensor_read_samp_freq_value
);
197 int hid_sensor_write_samp_freq_value(struct hid_sensor_common
*st
,
203 if (val1
< 0 || val2
< 0)
206 value
= val1
* pow_10(6) + val2
;
208 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_MILLISECOND
)
209 value
= pow_10(9)/value
;
210 else if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
211 value
= pow_10(6)/value
;
215 ret
= sensor_hub_set_feature(st
->hsdev
, st
->poll
.report_id
,
216 st
->poll
.index
, sizeof(value
), &value
);
217 if (ret
< 0 || value
< 0)
222 EXPORT_SYMBOL(hid_sensor_write_samp_freq_value
);
224 int hid_sensor_read_raw_hyst_value(struct hid_sensor_common
*st
,
225 int *val1
, int *val2
)
230 ret
= sensor_hub_get_feature(st
->hsdev
,
231 st
->sensitivity
.report_id
,
232 st
->sensitivity
.index
, sizeof(value
),
234 if (ret
< 0 || value
< 0) {
238 convert_from_vtf_format(value
, st
->sensitivity
.size
,
239 st
->sensitivity
.unit_expo
,
243 return IIO_VAL_INT_PLUS_MICRO
;
245 EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value
);
247 int hid_sensor_write_raw_hyst_value(struct hid_sensor_common
*st
,
253 if (val1
< 0 || val2
< 0)
256 value
= convert_to_vtf_format(st
->sensitivity
.size
,
257 st
->sensitivity
.unit_expo
,
259 ret
= sensor_hub_set_feature(st
->hsdev
, st
->sensitivity
.report_id
,
260 st
->sensitivity
.index
, sizeof(value
),
262 if (ret
< 0 || value
< 0)
267 EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value
);
270 * This fuction applies the unit exponent to the scale.
272 * 9.806650000 ->exp:2-> val0[980]val1[665000000]
273 * 9.000806000 ->exp:2-> val0[900]val1[80600000]
274 * 0.174535293 ->exp:2-> val0[17]val1[453529300]
275 * 1.001745329 ->exp:0-> val0[1]val1[1745329]
276 * 1.001745329 ->exp:2-> val0[100]val1[174532900]
277 * 1.001745329 ->exp:4-> val0[10017]val1[453290000]
278 * 9.806650000 ->exp:-2-> val0[0]val1[98066500]
280 static void adjust_exponent_nano(int *val0
, int *val1
, int scale0
,
289 *val0
= scale0
* pow_10(exp
);
295 for (i
= 0; i
< exp
; ++i
) {
296 x
= scale1
/ pow_10(8 - i
);
297 res
+= (pow_10(exp
- 1 - i
) * x
);
298 scale1
= scale1
% pow_10(8 - i
);
301 *val1
= scale1
* pow_10(exp
);
302 } else if (exp
< 0) {
308 *val0
= scale0
/ pow_10(exp
);
309 rem
= scale0
% pow_10(exp
);
311 for (i
= 0; i
< (9 - exp
); ++i
) {
312 x
= scale1
/ pow_10(8 - i
);
313 res
+= (pow_10(8 - exp
- i
) * x
);
314 scale1
= scale1
% pow_10(8 - i
);
316 *val1
= rem
* pow_10(9 - exp
) + res
;
323 int hid_sensor_format_scale(u32 usage_id
,
324 struct hid_sensor_hub_attribute_info
*attr_info
,
325 int *val0
, int *val1
)
333 for (i
= 0; i
< ARRAY_SIZE(unit_conversion
); ++i
) {
334 if (unit_conversion
[i
].usage_id
== usage_id
&&
335 unit_conversion
[i
].unit
== attr_info
->units
) {
336 exp
= hid_sensor_convert_exponent(
337 attr_info
->unit_expo
);
338 adjust_exponent_nano(val0
, val1
,
339 unit_conversion
[i
].scale_val0
,
340 unit_conversion
[i
].scale_val1
, exp
);
345 return IIO_VAL_INT_PLUS_NANO
;
347 EXPORT_SYMBOL(hid_sensor_format_scale
);
350 int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device
*hsdev
,
352 struct hid_sensor_common
*st
)
354 sensor_hub_input_get_attribute_info(hsdev
,
355 HID_FEATURE_REPORT
, usage_id
,
356 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL
,
358 /* Default unit of measure is milliseconds */
359 if (st
->poll
.units
== 0)
360 st
->poll
.units
= HID_USAGE_SENSOR_UNITS_MILLISECOND
;
365 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device
*hsdev
,
367 struct hid_sensor_common
*st
)
371 hid_sensor_get_reporting_interval(hsdev
, usage_id
, st
);
373 sensor_hub_input_get_attribute_info(hsdev
,
374 HID_FEATURE_REPORT
, usage_id
,
375 HID_USAGE_SENSOR_PROP_REPORT_STATE
,
378 sensor_hub_input_get_attribute_info(hsdev
,
379 HID_FEATURE_REPORT
, usage_id
,
380 HID_USAGE_SENSOR_PROY_POWER_STATE
,
383 sensor_hub_input_get_attribute_info(hsdev
,
384 HID_FEATURE_REPORT
, usage_id
,
385 HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS
,
388 hid_dbg(hsdev
->hdev
, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
389 st
->poll
.index
, st
->poll
.report_id
,
390 st
->report_state
.index
, st
->report_state
.report_id
,
391 st
->power_state
.index
, st
->power_state
.report_id
,
392 st
->sensitivity
.index
, st
->sensitivity
.report_id
);
396 EXPORT_SYMBOL(hid_sensor_parse_common_attributes
);
398 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
399 MODULE_DESCRIPTION("HID Sensor common attribute processing");
400 MODULE_LICENSE("GPL");