aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2014-04-18 19:22:00 -0400
committerJonathan Cameron <jic23@kernel.org>2014-05-05 05:59:44 -0400
commit5d02edfc3957446fd625c0b018e14c6631a791f4 (patch)
tree3601d52baa45ff006e6bf7b2d13436c8046fa71e
parentc7eeea93ac60aba3c037af8933a7ffc96ccd495c (diff)
iio: hid-sensors: Convert units and exponent
HID sensor hub specify a default unit and alternative units. This along with unit exponent can be used adjust scale. This change change HID sensor data units to IIO defined units for each sensor type. So in this way user space can use a simply use: "(data + offset) * scale" to get final result. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c114
-rw-r--r--include/linux/hid-sensor-hub.h4
2 files changed, 118 insertions, 0 deletions
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
index 75b54730a963..e61b1faa1e06 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -26,6 +26,40 @@
26#include <linux/iio/iio.h> 26#include <linux/iio/iio.h>
27#include <linux/iio/sysfs.h> 27#include <linux/iio/sysfs.h>
28 28
29struct {
30 u32 usage_id;
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 micros */
34} static unit_conversion[] = {
35 {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650},
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, 806650},
40
41 {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453},
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, 17453},
46
47 {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000},
48 {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0},
49
50 {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453},
51 {HID_USAGE_SENSOR_INCLINOMETER_3D,
52 HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453},
53 {HID_USAGE_SENSOR_INCLINOMETER_3D,
54 HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0},
55
56 {HID_USAGE_SENSOR_ALS, 0, 1, 0},
57 {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
58
59 {HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0},
60 {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0},
61};
62
29static int pow_10(unsigned power) 63static int pow_10(unsigned power)
30{ 64{
31 int i; 65 int i;
@@ -209,6 +243,86 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
209} 243}
210EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); 244EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
211 245
246/*
247 * This fuction applies the unit exponent to the scale.
248 * For example:
249 * 9.806650 ->exp:2-> val0[980]val1[665000]
250 * 9.000806 ->exp:2-> val0[900]val1[80600]
251 * 0.174535 ->exp:2-> val0[17]val1[453500]
252 * 1.001745 ->exp:0-> val0[1]val1[1745]
253 * 1.001745 ->exp:2-> val0[100]val1[174500]
254 * 1.001745 ->exp:4-> val0[10017]val1[450000]
255 * 9.806650 ->exp:-2-> val0[0]val1[98066]
256 */
257static void adjust_exponent_micro(int *val0, int *val1, int scale0,
258 int scale1, int exp)
259{
260 int i;
261 int x;
262 int res;
263 int rem;
264
265 if (exp > 0) {
266 *val0 = scale0 * pow_10(exp);
267 res = 0;
268 if (exp > 6) {
269 *val1 = 0;
270 return;
271 }
272 for (i = 0; i < exp; ++i) {
273 x = scale1 / pow_10(5 - i);
274 res += (pow_10(exp - 1 - i) * x);
275 scale1 = scale1 % pow_10(5 - i);
276 }
277 *val0 += res;
278 *val1 = scale1 * pow_10(exp);
279 } else if (exp < 0) {
280 exp = abs(exp);
281 if (exp > 6) {
282 *val0 = *val1 = 0;
283 return;
284 }
285 *val0 = scale0 / pow_10(exp);
286 rem = scale0 % pow_10(exp);
287 res = 0;
288 for (i = 0; i < (6 - exp); ++i) {
289 x = scale1 / pow_10(5 - i);
290 res += (pow_10(5 - exp - i) * x);
291 scale1 = scale1 % pow_10(5 - i);
292 }
293 *val1 = rem * pow_10(6 - exp) + res;
294 } else {
295 *val0 = scale0;
296 *val1 = scale1;
297 }
298}
299
300int hid_sensor_format_scale(u32 usage_id,
301 struct hid_sensor_hub_attribute_info *attr_info,
302 int *val0, int *val1)
303{
304 int i;
305 int exp;
306
307 *val0 = 1;
308 *val1 = 0;
309
310 for (i = 0; ARRAY_SIZE(unit_conversion); ++i) {
311 if (unit_conversion[i].usage_id == usage_id &&
312 unit_conversion[i].unit == attr_info->units) {
313 exp = hid_sensor_convert_exponent(
314 attr_info->unit_expo);
315 adjust_exponent_micro(val0, val1,
316 unit_conversion[i].scale_val0,
317 unit_conversion[i].scale_val1, exp);
318 break;
319 }
320 }
321
322 return IIO_VAL_INT_PLUS_MICRO;
323}
324EXPORT_SYMBOL(hid_sensor_format_scale);
325
212int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, 326int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
213 u32 usage_id, 327 u32 usage_id,
214 struct hid_sensor_common *st) 328 struct hid_sensor_common *st)
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
index b70cfd7ff29c..89626b23c246 100644
--- a/include/linux/hid-sensor-hub.h
+++ b/include/linux/hid-sensor-hub.h
@@ -223,4 +223,8 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
223int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev, 223int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev,
224 u32 report_id, int field_index, u32 usage_id); 224 u32 report_id, int field_index, u32 usage_id);
225 225
226int hid_sensor_format_scale(u32 usage_id,
227 struct hid_sensor_hub_attribute_info *attr_info,
228 int *val0, int *val1);
229
226#endif 230#endif