aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/common/hid-sensors
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/common/hid-sensors')
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-attributes.c151
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c17
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.h1
3 files changed, 163 insertions, 6 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..403dd3d8986e 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;
@@ -113,6 +147,26 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)
113 return value; 147 return value;
114} 148}
115 149
150s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
151{
152 s32 value = 0;
153 int ret;
154
155 ret = sensor_hub_get_feature(st->hsdev,
156 st->poll.report_id,
157 st->poll.index, &value);
158
159 if (ret < 0 || value < 0) {
160 return -EINVAL;
161 } else {
162 if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
163 value = value * 1000;
164 }
165
166 return value;
167}
168EXPORT_SYMBOL(hid_sensor_read_poll_value);
169
116int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, 170int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
117 int *val1, int *val2) 171 int *val1, int *val2)
118{ 172{
@@ -209,15 +263,108 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
209} 263}
210EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); 264EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value);
211 265
212int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, 266/*
267 * This fuction applies the unit exponent to the scale.
268 * For example:
269 * 9.806650 ->exp:2-> val0[980]val1[665000]
270 * 9.000806 ->exp:2-> val0[900]val1[80600]
271 * 0.174535 ->exp:2-> val0[17]val1[453500]
272 * 1.001745 ->exp:0-> val0[1]val1[1745]
273 * 1.001745 ->exp:2-> val0[100]val1[174500]
274 * 1.001745 ->exp:4-> val0[10017]val1[450000]
275 * 9.806650 ->exp:-2-> val0[0]val1[98066]
276 */
277static void adjust_exponent_micro(int *val0, int *val1, int scale0,
278 int scale1, int exp)
279{
280 int i;
281 int x;
282 int res;
283 int rem;
284
285 if (exp > 0) {
286 *val0 = scale0 * pow_10(exp);
287 res = 0;
288 if (exp > 6) {
289 *val1 = 0;
290 return;
291 }
292 for (i = 0; i < exp; ++i) {
293 x = scale1 / pow_10(5 - i);
294 res += (pow_10(exp - 1 - i) * x);
295 scale1 = scale1 % pow_10(5 - i);
296 }
297 *val0 += res;
298 *val1 = scale1 * pow_10(exp);
299 } else if (exp < 0) {
300 exp = abs(exp);
301 if (exp > 6) {
302 *val0 = *val1 = 0;
303 return;
304 }
305 *val0 = scale0 / pow_10(exp);
306 rem = scale0 % pow_10(exp);
307 res = 0;
308 for (i = 0; i < (6 - exp); ++i) {
309 x = scale1 / pow_10(5 - i);
310 res += (pow_10(5 - exp - i) * x);
311 scale1 = scale1 % pow_10(5 - i);
312 }
313 *val1 = rem * pow_10(6 - exp) + res;
314 } else {
315 *val0 = scale0;
316 *val1 = scale1;
317 }
318}
319
320int hid_sensor_format_scale(u32 usage_id,
321 struct hid_sensor_hub_attribute_info *attr_info,
322 int *val0, int *val1)
323{
324 int i;
325 int exp;
326
327 *val0 = 1;
328 *val1 = 0;
329
330 for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) {
331 if (unit_conversion[i].usage_id == usage_id &&
332 unit_conversion[i].unit == attr_info->units) {
333 exp = hid_sensor_convert_exponent(
334 attr_info->unit_expo);
335 adjust_exponent_micro(val0, val1,
336 unit_conversion[i].scale_val0,
337 unit_conversion[i].scale_val1, exp);
338 break;
339 }
340 }
341
342 return IIO_VAL_INT_PLUS_MICRO;
343}
344EXPORT_SYMBOL(hid_sensor_format_scale);
345
346int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
213 u32 usage_id, 347 u32 usage_id,
214 struct hid_sensor_common *st) 348 struct hid_sensor_common *st)
215{ 349{
216
217 sensor_hub_input_get_attribute_info(hsdev, 350 sensor_hub_input_get_attribute_info(hsdev,
218 HID_FEATURE_REPORT, usage_id, 351 HID_FEATURE_REPORT, usage_id,
219 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL, 352 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,
220 &st->poll); 353 &st->poll);
354 /* Default unit of measure is milliseconds */
355 if (st->poll.units == 0)
356 st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND;
357 return 0;
358
359}
360
361int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
362 u32 usage_id,
363 struct hid_sensor_common *st)
364{
365
366
367 hid_sensor_get_reporting_interval(hsdev, usage_id, st);
221 368
222 sensor_hub_input_get_attribute_info(hsdev, 369 sensor_hub_input_get_attribute_info(hsdev,
223 HID_FEATURE_REPORT, usage_id, 370 HID_FEATURE_REPORT, usage_id,
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index dbefbdaf7cd1..73282cee0c81 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -28,16 +28,17 @@
28#include <linux/iio/sysfs.h> 28#include <linux/iio/sysfs.h>
29#include "hid-sensor-trigger.h" 29#include "hid-sensor-trigger.h"
30 30
31static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, 31int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
32 bool state)
33{ 32{
34 struct hid_sensor_common *st = iio_trigger_get_drvdata(trig);
35 int state_val; 33 int state_val;
36 int report_val; 34 int report_val;
37 35
38 if (state) { 36 if (state) {
39 if (sensor_hub_device_open(st->hsdev)) 37 if (sensor_hub_device_open(st->hsdev))
40 return -EIO; 38 return -EIO;
39
40 atomic_inc(&st->data_ready);
41
41 state_val = hid_sensor_get_usage_index(st->hsdev, 42 state_val = hid_sensor_get_usage_index(st->hsdev,
42 st->power_state.report_id, 43 st->power_state.report_id,
43 st->power_state.index, 44 st->power_state.index,
@@ -47,6 +48,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
47 st->report_state.index, 48 st->report_state.index,
48 HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM); 49 HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
49 } else { 50 } else {
51 if (!atomic_dec_and_test(&st->data_ready))
52 return 0;
50 sensor_hub_device_close(st->hsdev); 53 sensor_hub_device_close(st->hsdev);
51 state_val = hid_sensor_get_usage_index(st->hsdev, 54 state_val = hid_sensor_get_usage_index(st->hsdev,
52 st->power_state.report_id, 55 st->power_state.report_id,
@@ -57,7 +60,6 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
57 st->report_state.index, 60 st->report_state.index,
58 HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM); 61 HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
59 } 62 }
60 st->data_ready = state;
61 63
62 if (state_val >= 0) { 64 if (state_val >= 0) {
63 state_val += st->power_state.logical_minimum; 65 state_val += st->power_state.logical_minimum;
@@ -75,6 +77,13 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
75 77
76 return 0; 78 return 0;
77} 79}
80EXPORT_SYMBOL(hid_sensor_power_state);
81
82static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
83 bool state)
84{
85 return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
86}
78 87
79void hid_sensor_remove_trigger(struct hid_sensor_common *attrb) 88void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
80{ 89{
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index ca02f7811aa8..0f8e78c249d3 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -22,5 +22,6 @@
22int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, 22int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
23 struct hid_sensor_common *attrb); 23 struct hid_sensor_common *attrb);
24void hid_sensor_remove_trigger(struct hid_sensor_common *attrb); 24void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
25int hid_sensor_power_state(struct hid_sensor_common *st, bool state);
25 26
26#endif 27#endif