diff options
Diffstat (limited to 'drivers/iio/common/hid-sensors')
| -rw-r--r-- | drivers/iio/common/hid-sensors/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-attributes.c | 162 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-attributes.h | 57 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 73 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-trigger.h | 5 |
5 files changed, 212 insertions, 94 deletions
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig index 1178121b55b..39188b72cd3 100644 --- a/drivers/iio/common/hid-sensors/Kconfig +++ b/drivers/iio/common/hid-sensors/Kconfig @@ -25,13 +25,4 @@ config HID_SENSOR_IIO_TRIGGER If this driver is compiled as a module, it will be named hid-sensor-trigger. -config HID_SENSOR_ENUM_BASE_QUIRKS - bool "ENUM base quirks for HID Sensor IIO drivers" - depends on HID_SENSOR_IIO_COMMON - help - Say yes here to build support for sensor hub FW using - enumeration, which is using 1 as base instead of 0. - Since logical minimum is still set 0 instead of 1, - there is no easy way to differentiate. - endmenu diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 75374955cab..403dd3d8986 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -25,7 +25,40 @@ #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include "hid-sensor-attributes.h" + +struct { + u32 usage_id; + int unit; /* 0 for default others from HID sensor spec */ + int scale_val0; /* scale, whole number */ + int scale_val1; /* scale, fraction in micros */ +} static unit_conversion[] = { + {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650}, + {HID_USAGE_SENSOR_ACCEL_3D, + HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, + {HID_USAGE_SENSOR_ACCEL_3D, + HID_USAGE_SENSOR_UNITS_G, 9, 806650}, + + {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453}, + {HID_USAGE_SENSOR_GYRO_3D, + HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0}, + {HID_USAGE_SENSOR_GYRO_3D, + HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453}, + + {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000}, + {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0}, + + {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453}, + {HID_USAGE_SENSOR_INCLINOMETER_3D, + HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453}, + {HID_USAGE_SENSOR_INCLINOMETER_3D, + HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0}, + + {HID_USAGE_SENSOR_ALS, 0, 1, 0}, + {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0}, + + {HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0}, + {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0}, +}; static int pow_10(unsigned power) { @@ -114,7 +147,27 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) return value; } -int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st, +s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) +{ + s32 value = 0; + int ret; + + ret = sensor_hub_get_feature(st->hsdev, + st->poll.report_id, + st->poll.index, &value); + + if (ret < 0 || value < 0) { + return -EINVAL; + } else { + if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) + value = value * 1000; + } + + return value; +} +EXPORT_SYMBOL(hid_sensor_read_poll_value); + +int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, int *val1, int *val2) { s32 value; @@ -141,7 +194,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st, } EXPORT_SYMBOL(hid_sensor_read_samp_freq_value); -int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st, +int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, int val1, int val2) { s32 value; @@ -169,7 +222,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st, } EXPORT_SYMBOL(hid_sensor_write_samp_freq_value); -int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st, +int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, int *val1, int *val2) { s32 value; @@ -191,7 +244,7 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st, } EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value); -int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st, +int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, int val1, int val2) { s32 value; @@ -210,15 +263,108 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st, } EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); -int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - struct hid_sensor_iio_common *st) +/* + * This fuction applies the unit exponent to the scale. + * For example: + * 9.806650 ->exp:2-> val0[980]val1[665000] + * 9.000806 ->exp:2-> val0[900]val1[80600] + * 0.174535 ->exp:2-> val0[17]val1[453500] + * 1.001745 ->exp:0-> val0[1]val1[1745] + * 1.001745 ->exp:2-> val0[100]val1[174500] + * 1.001745 ->exp:4-> val0[10017]val1[450000] + * 9.806650 ->exp:-2-> val0[0]val1[98066] + */ +static void adjust_exponent_micro(int *val0, int *val1, int scale0, + int scale1, int exp) +{ + int i; + int x; + int res; + int rem; + + if (exp > 0) { + *val0 = scale0 * pow_10(exp); + res = 0; + if (exp > 6) { + *val1 = 0; + return; + } + for (i = 0; i < exp; ++i) { + x = scale1 / pow_10(5 - i); + res += (pow_10(exp - 1 - i) * x); + scale1 = scale1 % pow_10(5 - i); + } + *val0 += res; + *val1 = scale1 * pow_10(exp); + } else if (exp < 0) { + exp = abs(exp); + if (exp > 6) { + *val0 = *val1 = 0; + return; + } + *val0 = scale0 / pow_10(exp); + rem = scale0 % pow_10(exp); + res = 0; + for (i = 0; i < (6 - exp); ++i) { + x = scale1 / pow_10(5 - i); + res += (pow_10(5 - exp - i) * x); + scale1 = scale1 % pow_10(5 - i); + } + *val1 = rem * pow_10(6 - exp) + res; + } else { + *val0 = scale0; + *val1 = scale1; + } +} + +int hid_sensor_format_scale(u32 usage_id, + struct hid_sensor_hub_attribute_info *attr_info, + int *val0, int *val1) { + int i; + int exp; + + *val0 = 1; + *val1 = 0; + + for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) { + if (unit_conversion[i].usage_id == usage_id && + unit_conversion[i].unit == attr_info->units) { + exp = hid_sensor_convert_exponent( + attr_info->unit_expo); + adjust_exponent_micro(val0, val1, + unit_conversion[i].scale_val0, + unit_conversion[i].scale_val1, exp); + break; + } + } + return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_format_scale); + +int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_common *st) +{ sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, HID_USAGE_SENSOR_PROP_REPORT_INTERVAL, &st->poll); + /* Default unit of measure is milliseconds */ + if (st->poll.units == 0) + st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND; + return 0; + +} + +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_common *st) +{ + + + hid_sensor_get_reporting_interval(hsdev, usage_id, st); sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, usage_id, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/iio/common/hid-sensors/hid-sensor-attributes.h deleted file mode 100644 index a4676a0c3de..00000000000 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * HID Sensors Driver - * Copyright (c) 2012, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifndef _HID_SENSORS_ATTRIBUTES_H -#define _HID_SENSORS_ATTRIBUTES_H - -/* Common hid sensor iio structure */ -struct hid_sensor_iio_common { - struct hid_sensor_hub_device *hsdev; - struct platform_device *pdev; - unsigned usage_id; - bool data_ready; - struct hid_sensor_hub_attribute_info poll; - struct hid_sensor_hub_attribute_info report_state; - struct hid_sensor_hub_attribute_info power_state; - struct hid_sensor_hub_attribute_info sensitivity; -}; - -/*Convert from hid unit expo to regular exponent*/ -static inline int hid_sensor_convert_exponent(int unit_expo) -{ - if (unit_expo < 0x08) - return unit_expo; - else if (unit_expo <= 0x0f) - return -(0x0f-unit_expo+1); - else - return 0; -} - -int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, - u32 usage_id, - struct hid_sensor_iio_common *st); -int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st, - int val1, int val2); -int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st, - int *val1, int *val2); -int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st, - int val1, int val2); -int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st, - int *val1, int *val2); - -#endif diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index d60198a6ca2..a3109a6f4d8 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -26,35 +26,72 @@ #include <linux/iio/iio.h> #include <linux/iio/trigger.h> #include <linux/iio/sysfs.h> -#include "hid-sensor-attributes.h" #include "hid-sensor-trigger.h" -static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) +int hid_sensor_power_state(struct hid_sensor_common *st, bool state) { - struct hid_sensor_iio_common *st = trig->private_data; int state_val; + int report_val; + + if (state) { + if (sensor_hub_device_open(st->hsdev)) + return -EIO; + + atomic_inc(&st->data_ready); - state_val = state ? 1 : 0; - if (IS_ENABLED(CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS)) - ++state_val; - st->data_ready = state; - sensor_hub_set_feature(st->hsdev, st->power_state.report_id, + state_val = hid_sensor_get_usage_index(st->hsdev, + st->power_state.report_id, + st->power_state.index, + HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM); + report_val = hid_sensor_get_usage_index(st->hsdev, + st->report_state.report_id, + st->report_state.index, + HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM); + } else { + if (!atomic_dec_and_test(&st->data_ready)) + return 0; + sensor_hub_device_close(st->hsdev); + state_val = hid_sensor_get_usage_index(st->hsdev, + st->power_state.report_id, + st->power_state.index, + HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM); + report_val = hid_sensor_get_usage_index(st->hsdev, + st->report_state.report_id, + st->report_state.index, + HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM); + } + + if (state_val >= 0) { + state_val += st->power_state.logical_minimum; + sensor_hub_set_feature(st->hsdev, st->power_state.report_id, st->power_state.index, (s32)state_val); + } - sensor_hub_set_feature(st->hsdev, st->report_state.report_id, + if (report_val >= 0) { + report_val += st->report_state.logical_minimum; + sensor_hub_set_feature(st->hsdev, st->report_state.report_id, st->report_state.index, - (s32)state_val); + (s32)report_val); + } + sensor_hub_get_feature(st->hsdev, st->power_state.report_id, + st->power_state.index, + &state_val); return 0; } +EXPORT_SYMBOL(hid_sensor_power_state); + +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state); +} -void hid_sensor_remove_trigger(struct iio_dev *indio_dev) +void hid_sensor_remove_trigger(struct hid_sensor_common *attrb) { - iio_trigger_unregister(indio_dev->trig); - iio_trigger_free(indio_dev->trig); - indio_dev->trig = NULL; + iio_trigger_unregister(attrb->trigger); + iio_trigger_free(attrb->trigger); } EXPORT_SYMBOL(hid_sensor_remove_trigger); @@ -64,7 +101,7 @@ static const struct iio_trigger_ops hid_sensor_trigger_ops = { }; int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, - struct hid_sensor_iio_common *attrb) + struct hid_sensor_common *attrb) { int ret; struct iio_trigger *trig; @@ -77,7 +114,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, } trig->dev.parent = indio_dev->dev.parent; - trig->private_data = attrb; + iio_trigger_set_drvdata(trig, attrb); trig->ops = &hid_sensor_trigger_ops; ret = iio_trigger_register(trig); @@ -85,7 +122,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, dev_err(&indio_dev->dev, "Trigger Register Failed\n"); goto error_free_trig; } - indio_dev->trig = trig; + indio_dev->trig = attrb->trigger = trig; return ret; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h index fd982971b1b..0f8e78c249d 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -20,7 +20,8 @@ #define _HID_SENSOR_TRIGGER_H int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, - struct hid_sensor_iio_common *attrb); -void hid_sensor_remove_trigger(struct iio_dev *indio_dev); + struct hid_sensor_common *attrb); +void hid_sensor_remove_trigger(struct hid_sensor_common *attrb); +int hid_sensor_power_state(struct hid_sensor_common *st, bool state); #endif |
