Commit 2e455c27 authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-4.1/sensor-hub' into for-linus

Conflicts:
	drivers/iio/common/hid-sensors/hid-sensor-trigger.c
	include/linux/hid-sensor-hub.h
parents 05f6d025 b2eafd72
...@@ -138,3 +138,87 @@ accelerometer wants to poll X axis value, then it can call this function with ...@@ -138,3 +138,87 @@ accelerometer wants to poll X axis value, then it can call this function with
the usage id of X axis. HID sensors can provide events, so this is not necessary the usage id of X axis. HID sensors can provide events, so this is not necessary
to poll for any field. If there is some new sample, the core driver will call to poll for any field. If there is some new sample, the core driver will call
registered callback function to process the sample. registered callback function to process the sample.
----------
HID Custom and generic Sensors
HID Sensor specification defines two special sensor usage types. Since they
don't represent a standard sensor, it is not possible to define using Linux IIO
type interfaces.
The purpose of these sensors is to extend the functionality or provide a
way to obfuscate the data being communicated by a sensor. Without knowing the
mapping between the data and its encapsulated form, it is difficult for
an application/driver to determine what data is being communicated by the sensor.
This allows some differentiating use cases, where vendor can provide applications.
Some common use cases are debug other sensors or to provide some events like
keyboard attached/detached or lid open/close.
To allow application to utilize these sensors, here they are exported uses sysfs
attribute groups, attributes and misc device interface.
An example of this representation on sysfs:
/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
.
????????? enable_sensor
????????? feature-0-200316
??????? ????????? feature-0-200316-maximum
??????? ????????? feature-0-200316-minimum
??????? ????????? feature-0-200316-name
??????? ????????? feature-0-200316-size
??????? ????????? feature-0-200316-unit-expo
??????? ????????? feature-0-200316-units
??????? ????????? feature-0-200316-value
????????? feature-1-200201
??????? ????????? feature-1-200201-maximum
??????? ????????? feature-1-200201-minimum
??????? ????????? feature-1-200201-name
??????? ????????? feature-1-200201-size
??????? ????????? feature-1-200201-unit-expo
??????? ????????? feature-1-200201-units
??????? ????????? feature-1-200201-value
????????? input-0-200201
??????? ????????? input-0-200201-maximum
??????? ????????? input-0-200201-minimum
??????? ????????? input-0-200201-name
??????? ????????? input-0-200201-size
??????? ????????? input-0-200201-unit-expo
??????? ????????? input-0-200201-units
??????? ????????? input-0-200201-value
????????? input-1-200202
??????? ????????? input-1-200202-maximum
??????? ????????? input-1-200202-minimum
??????? ????????? input-1-200202-name
??????? ????????? input-1-200202-size
??????? ????????? input-1-200202-unit-expo
??????? ????????? input-1-200202-units
??????? ????????? input-1-200202-value
Here there is a custom sensors with four fields, two feature and two inputs.
Each field is represented by a set of attributes. All fields except the "value"
are read only. The value field is a RW field.
Example
/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
feature-0-200316-maximum:6
feature-0-200316-minimum:0
feature-0-200316-name:property-reporting-state
feature-0-200316-size:1
feature-0-200316-unit-expo:0
feature-0-200316-units:25
feature-0-200316-value:1
How to enable such sensor?
By default sensor can be power gated. To enable sysfs attribute "enable" can be
used.
$ echo 1 > enable_sensor
Once enabled and powered on, sensor can report value using HID reports.
These reports are pushed using misc device interface in a FIFO order.
/dev$ tree | grep HID-SENSOR-2000e1.6.auto
??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
????????? HID-SENSOR-2000e1.6.auto
Each reports can be of variable length preceded by a header. This header
consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
data.
...@@ -878,6 +878,21 @@ config HID_SENSOR_HUB ...@@ -878,6 +878,21 @@ config HID_SENSOR_HUB
for events and handle data streams. Each sensor driver can format for events and handle data streams. Each sensor driver can format
data and present to user mode using input or IIO interface. data and present to user mode using input or IIO interface.
config HID_SENSOR_CUSTOM_SENSOR
tristate "HID Sensors hub custom sensor support"
depends on HID_SENSOR_HUB
default n
---help---
HID Sensor hub specification allows definition of some custom and
generic sensors. Unlike other HID sensors, they can't be exported
via Linux IIO because of custom fields. This is up to the manufacturer
to decide how to interpret these special sensor ids and process in
the user space. Currently some manufacturers are using these ids for
sensor calibration and debugging other sensors. Manufacturers
should't use these special custom sensor ids to export any of the
standard sensors.
Select this config option for custom/generic sensor support.
endmenu endmenu
endif # HID endif # HID
......
...@@ -100,6 +100,7 @@ obj-$(CONFIG_HID_WACOM) += wacom.o ...@@ -100,6 +100,7 @@ obj-$(CONFIG_HID_WACOM) += wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/
......
This diff is collapsed.
This diff is collapsed.
...@@ -123,7 +123,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, ...@@ -123,7 +123,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
accel_state->common_attributes.hsdev, accel_state->common_attributes.hsdev,
HID_USAGE_SENSOR_ACCEL_3D, address, HID_USAGE_SENSOR_ACCEL_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
*val = 0; *val = 0;
hid_sensor_power_state(&accel_state->common_attributes, hid_sensor_power_state(&accel_state->common_attributes,
......
...@@ -154,7 +154,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) ...@@ -154,7 +154,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id, st->poll.report_id,
st->poll.index, &value); st->poll.index, sizeof(value), &value);
if (ret < 0 || value < 0) { if (ret < 0 || value < 0) {
return -EINVAL; return -EINVAL;
...@@ -175,7 +175,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, ...@@ -175,7 +175,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id, st->poll.report_id,
st->poll.index, &value); st->poll.index, sizeof(value), &value);
if (ret < 0 || value < 0) { if (ret < 0 || value < 0) {
*val1 = *val2 = 0; *val1 = *val2 = 0;
return -EINVAL; return -EINVAL;
...@@ -212,9 +212,8 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, ...@@ -212,9 +212,8 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
else else
value = 0; value = 0;
} }
ret = sensor_hub_set_feature(st->hsdev, ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id,
st->poll.report_id, st->poll.index, sizeof(value), &value);
st->poll.index, value);
if (ret < 0 || value < 0) if (ret < 0 || value < 0)
ret = -EINVAL; ret = -EINVAL;
...@@ -230,7 +229,8 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, ...@@ -230,7 +229,8 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id, st->sensitivity.report_id,
st->sensitivity.index, &value); st->sensitivity.index, sizeof(value),
&value);
if (ret < 0 || value < 0) { if (ret < 0 || value < 0) {
*val1 = *val2 = 0; *val1 = *val2 = 0;
return -EINVAL; return -EINVAL;
...@@ -253,9 +253,9 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, ...@@ -253,9 +253,9 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
value = convert_to_vtf_format(st->sensitivity.size, value = convert_to_vtf_format(st->sensitivity.size,
st->sensitivity.unit_expo, st->sensitivity.unit_expo,
val1, val2); val1, val2);
ret = sensor_hub_set_feature(st->hsdev, ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id,
st->sensitivity.report_id, st->sensitivity.index, sizeof(value),
st->sensitivity.index, value); &value);
if (ret < 0 || value < 0) if (ret < 0 || value < 0)
ret = -EINVAL; ret = -EINVAL;
......
...@@ -68,20 +68,21 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) ...@@ -68,20 +68,21 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
if (state_val >= 0) { if (state_val >= 0) {
state_val += st->power_state.logical_minimum; state_val += st->power_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id, sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index, st->power_state.index, sizeof(state_val),
(s32)state_val); &state_val);
} }
if (report_val >= 0) { if (report_val >= 0) {
report_val += st->report_state.logical_minimum; report_val += st->report_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->report_state.report_id, sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index, st->report_state.index,
(s32)report_val); sizeof(report_val),
&report_val);
} }
sensor_hub_get_feature(st->hsdev, st->power_state.report_id, sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index, st->power_state.index,
&state_val); sizeof(state_val), &state_val);
if (state && poll_value) if (state && poll_value)
msleep_interruptible(poll_value * 2); msleep_interruptible(poll_value * 2);
......
...@@ -123,7 +123,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, ...@@ -123,7 +123,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
gyro_state->common_attributes.hsdev, gyro_state->common_attributes.hsdev,
HID_USAGE_SENSOR_GYRO_3D, address, HID_USAGE_SENSOR_GYRO_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
*val = 0; *val = 0;
hid_sensor_power_state(&gyro_state->common_attributes, hid_sensor_power_state(&gyro_state->common_attributes,
......
...@@ -101,7 +101,8 @@ static int als_read_raw(struct iio_dev *indio_dev, ...@@ -101,7 +101,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
als_state->common_attributes.hsdev, als_state->common_attributes.hsdev,
HID_USAGE_SENSOR_ALS, address, HID_USAGE_SENSOR_ALS, address,
report_id); report_id,
SENSOR_HUB_SYNC);
hid_sensor_power_state(&als_state->common_attributes, hid_sensor_power_state(&als_state->common_attributes,
false); false);
} else { } else {
......
...@@ -96,7 +96,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, ...@@ -96,7 +96,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
prox_state->common_attributes.hsdev, prox_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PROX, address, HID_USAGE_SENSOR_PROX, address,
report_id); report_id,
SENSOR_HUB_SYNC);
hid_sensor_power_state(&prox_state->common_attributes, hid_sensor_power_state(&prox_state->common_attributes,
false); false);
} else { } else {
......
...@@ -170,7 +170,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, ...@@ -170,7 +170,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
magn_state->common_attributes.hsdev, magn_state->common_attributes.hsdev,
HID_USAGE_SENSOR_COMPASS_3D, address, HID_USAGE_SENSOR_COMPASS_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
*val = 0; *val = 0;
hid_sensor_power_state(&magn_state->common_attributes, hid_sensor_power_state(&magn_state->common_attributes,
......
...@@ -124,7 +124,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, ...@@ -124,7 +124,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
incl_state->common_attributes.hsdev, incl_state->common_attributes.hsdev,
HID_USAGE_SENSOR_INCLINOMETER_3D, address, HID_USAGE_SENSOR_INCLINOMETER_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
hid_sensor_power_state(&incl_state->common_attributes, hid_sensor_power_state(&incl_state->common_attributes,
false); false);
......
...@@ -100,7 +100,8 @@ static int press_read_raw(struct iio_dev *indio_dev, ...@@ -100,7 +100,8 @@ static int press_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
press_state->common_attributes.hsdev, press_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PRESSURE, address, HID_USAGE_SENSOR_PRESSURE, address,
report_id); report_id,
SENSOR_HUB_SYNC);
hid_sensor_power_state(&press_state->common_attributes, hid_sensor_power_state(&press_state->common_attributes,
false); false);
} else { } else {
......
...@@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* get a report with all values through requesting one value */ /* get a report with all values through requesting one value */
sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev,
HID_USAGE_SENSOR_TIME, hid_time_addresses[0], HID_USAGE_SENSOR_TIME, hid_time_addresses[0],
time_state->info[0].report_id); time_state->info[0].report_id, SENSOR_HUB_SYNC);
/* wait for all values (event) */ /* wait for all values (event) */
ret = wait_for_completion_killable_timeout( ret = wait_for_completion_killable_timeout(
&time_state->comp_last_time, HZ*6); &time_state->comp_last_time, HZ*6);
......
...@@ -48,20 +48,44 @@ struct hid_sensor_hub_attribute_info { ...@@ -48,20 +48,44 @@ struct hid_sensor_hub_attribute_info {
s32 logical_maximum; s32 logical_maximum;
}; };
/**
* struct sensor_hub_pending - Synchronous read pending information
* @status: Pending status true/false.
* @ready: Completion synchronization data.
* @usage_id: Usage id for physical device, E.g. Gyro usage id.
* @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro.
* @raw_size: Response size for a read request.
* @raw_data: Place holder for received response.
*/
struct sensor_hub_pending {
bool status;
struct completion ready;
u32 usage_id;
u32 attr_usage_id;
int raw_size;
u8 *raw_data;
};
/** /**
* struct hid_sensor_hub_device - Stores the hub instance data * struct hid_sensor_hub_device - Stores the hub instance data
* @hdev: Stores the hid instance. * @hdev: Stores the hid instance.
* @vendor_id: Vendor id of hub device. * @vendor_id: Vendor id of hub device.
* @product_id: Product id of hub device. * @product_id: Product id of hub device.
* @usage: Usage id for this hub device instance.
* @start_collection_index: Starting index for a phy type collection * @start_collection_index: Starting index for a phy type collection
* @end_collection_index: Last index for a phy type collection * @end_collection_index: Last index for a phy type collection
* @mutex: synchronizing mutex.
* @pending: Holds information of pending sync read request.
*/ */
struct hid_sensor_hub_device { struct hid_sensor_hub_device {
struct hid_device *hdev; struct hid_device *hdev;
u32 vendor_id; u32 vendor_id;
u32 product_id; u32 product_id;
u32 usage;
int start_collection_index; int start_collection_index;
int end_collection_index; int end_collection_index;
struct mutex mutex;
struct sensor_hub_pending pending;
}; };
/** /**
...@@ -152,40 +176,51 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, ...@@ -152,40 +176,51 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
* @usage_id: Attribute usage id of parent physical device as per spec * @usage_id: Attribute usage id of parent physical device as per spec
* @attr_usage_id: Attribute usage id as per spec * @attr_usage_id: Attribute usage id as per spec
* @report_id: Report id to look for * @report_id: Report id to look for
* @flag: Synchronous or asynchronous read
* *
* Issues a synchronous read request for an input attribute. Returns * Issues a synchronous or asynchronous read request for an input attribute.
* data upto 32 bits. Since client can get events, so this call should * Returns data upto 32 bits.
* not be used for data paths, this will impact performance.
*/ */
enum sensor_hub_read_flags {
SENSOR_HUB_SYNC,
SENSOR_HUB_ASYNC,
};
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id, u32 usage_id,
u32 attr_usage_id, u32 report_id); u32 attr_usage_id, u32 report_id,
enum sensor_hub_read_flags flag
);
/** /**
* sensor_hub_set_feature() - Feature set request * sensor_hub_set_feature() - Feature set request
* @hsdev: Hub device instance. * @hsdev: Hub device instance.
* @report_id: Report id to look for * @report_id: Report id to look for
* @field_index: Field index inside a report * @field_index: Field index inside a report
* @value: Value to set * @buffer_size: size of the buffer
* @buffer: buffer to use in the feature set
* *
* Used to set a field in feature report. For example this can set polling * Used to set a field in feature report. For example this can set polling
* interval, sensitivity, activate/deactivate state. * interval, sensitivity, activate/deactivate state.
*/ */
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 value); u32 field_index, int buffer_size, void *buffer);
/** /**
* sensor_hub_get_feature() - Feature get request * sensor_hub_get_feature() - Feature get request
* @hsdev: Hub device instance. * @hsdev: Hub device instance.
* @report_id: Report id to look for * @report_id: Report id to look for
* @field_index: Field index inside a report * @field_index: Field index inside a report
* @value: Place holder for return value * @buffer_size: size of the buffer
* @buffer: buffer to copy output
* *
* Used to get a field in feature report. For example this can get polling * Used to get a field in feature report. For example this can get polling
* interval, sensitivity, activate/deactivate state. * interval, sensitivity, activate/deactivate state. On success it returns
* number of bytes copied to buffer. On failure, it returns value < 0.
*/ */
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
u32 field_index, s32 *value); u32 field_index, int buffer_size, void *buffer);
/* hid-sensor-attributes */ /* hid-sensor-attributes */
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#define HID_MAX_PHY_DEVICES 0xFF #define HID_MAX_PHY_DEVICES 0xFF
#define HID_USAGE_SENSOR_COLLECTION 0x200001
/* Accel 3D (200073) */ /* Accel 3D (200073) */
#define HID_USAGE_SENSOR_ACCEL_3D 0x200073 #define HID_USAGE_SENSOR_ACCEL_3D 0x200073
#define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452 #define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment