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>
29 static int pow_10(unsigned power
)
33 for (i
= 0; i
< power
; ++i
)
39 static void simple_div(int dividend
, int divisor
, int *whole
,
50 *whole
= dividend
/divisor
;
51 rem
= dividend
% divisor
;
53 while (rem
<= divisor
) {
57 *micro_frac
= (rem
/ divisor
) * pow_10(6-exp
);
61 static void split_micro_fraction(unsigned int no
, int exp
, int *val1
, int *val2
)
63 *val1
= no
/pow_10(exp
);
64 *val2
= no
%pow_10(exp
) * pow_10(6-exp
);
68 VTF format uses exponent and variable size format.
69 For example if the size is 2 bytes
70 0x0067 with VTF16E14 format -> +1.03
71 To convert just change to 0x67 to decimal and use two decimal as E14 stands
73 Negative numbers are 2's complement
75 static void convert_from_vtf_format(u32 value
, int size
, int exp
,
80 if (value
& BIT(size
*8 - 1)) {
81 value
= ((1LL << (size
* 8)) - value
);
84 exp
= hid_sensor_convert_exponent(exp
);
86 *val1
= sign
* value
* pow_10(exp
);
89 split_micro_fraction(value
, -exp
, val1
, val2
);
91 *val1
= sign
* (*val1
);
93 *val2
= sign
* (*val2
);
97 static u32
convert_to_vtf_format(int size
, int exp
, int val1
, int val2
)
102 if (val1
< 0 || val2
< 0)
104 exp
= hid_sensor_convert_exponent(exp
);
106 value
= abs(val1
) * pow_10(-exp
);
107 value
+= abs(val2
) / pow_10(6+exp
);
109 value
= abs(val1
) / pow_10(exp
);
111 value
= ((1LL << (size
* 8)) - value
);
116 int hid_sensor_read_samp_freq_value(struct hid_sensor_common
*st
,
117 int *val1
, int *val2
)
122 ret
= sensor_hub_get_feature(st
->hsdev
,
124 st
->poll
.index
, &value
);
125 if (ret
< 0 || value
< 0) {
129 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_MILLISECOND
)
130 simple_div(1000, value
, val1
, val2
);
131 else if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
132 simple_div(1, value
, val1
, val2
);
139 return IIO_VAL_INT_PLUS_MICRO
;
141 EXPORT_SYMBOL(hid_sensor_read_samp_freq_value
);
143 int hid_sensor_write_samp_freq_value(struct hid_sensor_common
*st
,
149 if (val1
< 0 || val2
< 0)
152 value
= val1
* pow_10(6) + val2
;
154 if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_MILLISECOND
)
155 value
= pow_10(9)/value
;
156 else if (st
->poll
.units
== HID_USAGE_SENSOR_UNITS_SECOND
)
157 value
= pow_10(6)/value
;
161 ret
= sensor_hub_set_feature(st
->hsdev
,
163 st
->poll
.index
, value
);
164 if (ret
< 0 || value
< 0)
169 EXPORT_SYMBOL(hid_sensor_write_samp_freq_value
);
171 int hid_sensor_read_raw_hyst_value(struct hid_sensor_common
*st
,
172 int *val1
, int *val2
)
177 ret
= sensor_hub_get_feature(st
->hsdev
,
178 st
->sensitivity
.report_id
,
179 st
->sensitivity
.index
, &value
);
180 if (ret
< 0 || value
< 0) {
184 convert_from_vtf_format(value
, st
->sensitivity
.size
,
185 st
->sensitivity
.unit_expo
,
189 return IIO_VAL_INT_PLUS_MICRO
;
191 EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value
);
193 int hid_sensor_write_raw_hyst_value(struct hid_sensor_common
*st
,
199 value
= convert_to_vtf_format(st
->sensitivity
.size
,
200 st
->sensitivity
.unit_expo
,
202 ret
= sensor_hub_set_feature(st
->hsdev
,
203 st
->sensitivity
.report_id
,
204 st
->sensitivity
.index
, value
);
205 if (ret
< 0 || value
< 0)
210 EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value
);
212 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device
*hsdev
,
214 struct hid_sensor_common
*st
)
217 sensor_hub_input_get_attribute_info(hsdev
,
218 HID_FEATURE_REPORT
, usage_id
,
219 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL
,
222 sensor_hub_input_get_attribute_info(hsdev
,
223 HID_FEATURE_REPORT
, usage_id
,
224 HID_USAGE_SENSOR_PROP_REPORT_STATE
,
227 sensor_hub_input_get_attribute_info(hsdev
,
228 HID_FEATURE_REPORT
, usage_id
,
229 HID_USAGE_SENSOR_PROY_POWER_STATE
,
232 sensor_hub_input_get_attribute_info(hsdev
,
233 HID_FEATURE_REPORT
, usage_id
,
234 HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS
,
237 hid_dbg(hsdev
->hdev
, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
238 st
->poll
.index
, st
->poll
.report_id
,
239 st
->report_state
.index
, st
->report_state
.report_id
,
240 st
->power_state
.index
, st
->power_state
.report_id
,
241 st
->sensitivity
.index
, st
->sensitivity
.report_id
);
245 EXPORT_SYMBOL(hid_sensor_parse_common_attributes
);
247 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
248 MODULE_DESCRIPTION("HID Sensor common attribute processing");
249 MODULE_LICENSE("GPL");