[PATCH 0/8] HID-Sensor v4

STALE5220d

4 messages, 1 author, 2012-07-04 · open the first message on its own page

[PATCH 0/8] HID-Sensor v4

From: srinivas pandruvada <hidden>
Date: 2012-07-04 20:02:46

v4:
Addressed comments from Lars-Peter Clausen and Jiri Kosina.
- Added Documentation/hid/hid-sensor.txt
- As suggested, created iio/common folder which can contain common code for iio sensor driver.This contain common module to process trigger and attributes
- Removed empty callback functions.
- Duplicating channel structure for an IIO driver instance.

v3 :
- Using TRIGGERRED BUFFER
- Using MFD framework
The sensor hub driver is submiited to drivers/hid. This contains core processing of hid sensor
usage table, registers as an hid driver and adds registration function for routing data
to individual sensor driver. So core driver independent of user mode interface method (IIO/input etc.)

- Submiiting four drivers for Accelerometer-3D, Gyro-3D, Compass-3D and ALS. These uses IIO triggered
buffer interface. They are childrens of hid sensor hub driver.
They reside in iio/accel, iio/gyro iio/magnetometer and iio/light.

- Still using driver/staging/iio. Not able to test with driver/iio.

v2 :
- Replaced Ring-SW with KFiFO
- Accel-3d, Gyro-3D and Compass-3D uses 3 different channels for X, Y and Z
- SysFS (
--- Changed "polling_interval" to sampling_frequency (IIO_DEV_ATTR_SAMP_FREQ) with units HZ
--- Changed "sensitivity" to hyst_raw, which is already used by some ADC modules
--- Removed "Activate". No longer need this. Using trigger state to activate/deactivate
)
- Removed sysfs attributes for "xxx_offset". Instead using mask 0 in read_raw. So each
sensor have only channels, sampling_frequency and hyst_raw as the ABI.
- Additional patch to enable ST Micro sensor hub-

v1:
Base implementation for comments


srinivas pandruvada (8):
  HID-Sensors: Documentation
  HID Sensors: Add to special driver list
  HID-Sensors: Sensor framework
  HID-Sensors: Common attribute and trigger
  HID-Sensors: Added accelerometer 3D
  HID-Sensors: Added Gyroscope 3D
  HID-Sensors: Added Compass/Magnetometer 3D
  HID-Sensors: Added ALS

 Documentation/hid/hid-sensor.txt                   |  139 +++++
 drivers/hid/Kconfig                                |   12 +
 drivers/hid/Makefile                               |    1 +
 drivers/hid/hid-core.c                             |   10 +
 drivers/hid/hid-ids.h                              |    6 +
 drivers/hid/hid-sensor-hub.c                       |  630 ++++++++++++++++++++
 drivers/staging/iio/Kconfig                        |    1 +
 drivers/staging/iio/Makefile                       |    1 +
 drivers/staging/iio/accel/Kconfig                  |   10 +
 drivers/staging/iio/accel/Makefile                 |    3 +
 drivers/staging/iio/accel/hid-sensor-accel-3d.c    |  451 ++++++++++++++
 drivers/staging/iio/common/Kconfig                 |    6 +
 drivers/staging/iio/common/Makefile                |    5 +
 drivers/staging/iio/common/hid-sensors/Kconfig     |   21 +
 drivers/staging/iio/common/hid-sensors/Makefile    |    6 +
 .../iio/common/hid-sensors/hid-sensor-attributes.c |  182 ++++++
 .../iio/common/hid-sensors/hid-sensor-attributes.h |   60 ++
 .../iio/common/hid-sensors/hid-sensor-trigger.c    |  104 ++++
 .../iio/common/hid-sensors/hid-sensor-trigger.h    |   27 +
 drivers/staging/iio/gyro/Kconfig                   |   10 +
 drivers/staging/iio/gyro/Makefile                  |    3 +
 drivers/staging/iio/gyro/hid-sensor-gyro-3d.c      |  451 ++++++++++++++
 drivers/staging/iio/light/Kconfig                  |   10 +
 drivers/staging/iio/light/Makefile                 |    3 +
 drivers/staging/iio/light/hid-sensor-als.c         |  380 ++++++++++++
 drivers/staging/iio/magnetometer/Kconfig           |   10 +
 drivers/staging/iio/magnetometer/Makefile          |    3 +
 .../staging/iio/magnetometer/hid-sensor-magn-3d.c  |  451 ++++++++++++++
 include/linux/hid-sensor-hub.h                     |   72 +++
 include/linux/hid-sensor-ids.h                     |  116 ++++
 30 files changed, 3184 insertions(+), 0 deletions(-)
 create mode 100755 Documentation/hid/hid-sensor.txt
 create mode 100644 drivers/hid/hid-sensor-hub.c
 create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
 create mode 100644 drivers/staging/iio/common/Kconfig
 create mode 100644 drivers/staging/iio/common/Makefile
 create mode 100644 drivers/staging/iio/common/hid-sensors/Kconfig
 create mode 100644 drivers/staging/iio/common/hid-sensors/Makefile
 create mode 100644 drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
 create mode 100644 drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
 create mode 100644 drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
 create mode 100644 drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
 create mode 100644 drivers/staging/iio/gyro/hid-sensor-gyro-3d.c
 create mode 100644 drivers/staging/iio/light/hid-sensor-als.c
 create mode 100644 drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c
 create mode 100644 include/linux/hid-sensor-hub.h
 create mode 100644 include/linux/hid-sensor-ids.h

-- 
1.7.7.6

[PATCH 1/8] HID-Sensors: Documentation

From: srinivas pandruvada <hidden>
Date: 2012-07-04 20:02:45

Added a summary of HID sensor framework.

Signed-off-by: srinivas pandruvada <redacted>
---
 Documentation/hid/hid-sensor.txt |  139 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 139 insertions(+), 0 deletions(-)
 create mode 100755 Documentation/hid/hid-sensor.txt
diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.txt
new file mode 100755
index 0000000..a4b565f
--- /dev/null
+++ b/Documentation/hid/hid-sensor.txt
@@ -0,0 +1,139 @@
+
+HID Sensors Framework
+======================
+HID sensor framework provides necessary interfaces to implement sensor drivers,
+which are connected to a sensor hub. The sensor hub is HID device and it provides
+a report descriptor confirming to HID 1.12 sensor usage tables.
+
+Description from the HID 1.12 "HID Sensor Usages" specification:
+"Standardization of HID usages for sensors would allow (but not require) sensor
+hardware vendors to provide a consistent Plug And Play interface at the USB boundary,
+Thereby enabling some operating systems to incorporate common device drivers that
+could be reused between vendors, alleviating any need for the vendors to provide
+the drivers themselves."
+
+This specification describes many usage IDs, which describe the type of sensor
+and also the individual data fields. Each sensor can have variable number of
+data fields and length and order is specified in the report descriptor. For
+example a part of report descriptor can look like:
+
+   INPUT(1)[INPUT]
+ ..
+    Field(2)
+      Physical(0020.0073)
+      Usage(1)
+        0020.045f
+      Logical Minimum(-32767)
+      Logical Maximum(32767)
+      Report Size(8)
+      Report Count(1)
+      Report Offset(16)
+      Flags(Variable Absolute)
+..
+..
+
+The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73).
+This accelerometer-3D has some fields. Here for example field 2 is motion intensity
+(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The
+order of fields and length of each field is important as the input event raw
+data will use this format.
+
+
+Implementation
+=================
+
+This specification defines many different types of sensors with different set of
+data fields. It is difficult to have a common input event to user space applications,
+for different sensors. For example an accelerometer can send X,Y and Z data, whereas
+an ambient light sensor can send illumination data. 
+So the implementation has two parts:
+- Core hid driver
+- Individual sensor processing part (sensor drivers)
+
+Core driver
+-----------
+The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
+report descriptors and identifies all the sensors present. It adds an MFD device
+with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
+For example 
+HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
+So if any driver with this name is inserted, then the probe routine for that
+function will be called. So an accelerometer processing driver can register
+with this name and will be probed if there is an accelerometer-3D is detected.
+
+The core driver provides a set of APIs which can be used by the processing
+drivers to register and get events for that usage id. Also it provides a parsing
+functions, get and set each input/feature/output report.
+
+Individual sensor processing part (sensor drivers)
+-----------
+The processing driver will use interface provided by core driver to parse
+the report and get the indexes of the fields and also can get events. This driver
+can use IIO interface to use the standard ABI defined for a type of sensor.
+
+
+Core driver Interface
+=====================
+
+Callback structure:
+Each processing driver can use this structure to set some callbacks.
+	int (*suspend)(..): Callback when HID suspend is received
+	int (*resume)(..): Callback when HID resume is received
+	int (*capture_sample)(..): Capture a sample for one of its data field
+	int (*send_event)(..): One complete event is received which can have
+                               multiple data fields. 
+
+
+Registration functions:
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback):
+
+Registers callbacks for an usage id.
+
+
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id):
+
+Removes callbacks for an usage id.
+
+
+Parsing function:
+int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
+			u8 type,
+			u32 usage_id, u32 attr_usage_id,
+			struct hid_sensor_hub_attribute_info *info);
+
+A processing driver can look for some field of interest and check if it exists
+in a report descriptor. If it exists the it will store necessary information
+so that that field can be set or get individually.
+These indexes avoid searching every time and getting field index to get or set.
+
+
+Set Feature report
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 value);
+
+This interface is used to set a value for a field in feature report. For example
+if there is a field report_interval, which is parsed by a call to 
+sensor_hub_input_get_attribute_info before, then it can directly set that individual
+field.
+
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 *value);
+
+
+This interface is used to get a value for a field in input report. For example
+if there is a field report_interval, which is parsed by a call to 
+sensor_hub_input_get_attribute_info before, then it can directly get that individual
+field value.
+
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			u32 attr_usage_id, u32 report_id);
+
+This is used to get a particular field value through input reports. For example
+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
+to poll for any field. If there is some new sample, the core driver will call
+registered callback function to process the sample.
-- 
1.7.7.6

[PATCH 2/8] HID Sensors: Add to special driver list

From: srinivas pandruvada <hidden>
Date: 2012-07-04 20:02:46

Adding Intel and STM sensor hub in the list of drivers with
specialized driver.

Signed-off-by: srinivas pandruvada <redacted>
---
 drivers/hid/hid-core.c |   10 ++++++++++
 drivers/hid/hid-ids.h  |    6 ++++++
 2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8e3a6b2..36c8007 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1536,6 +1536,14 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+					USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+					USB_DEVICE_ID_SENSOR_HUB_09FA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+					USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+					USB_DEVICE_ID_SENSOR_HUB_09FA) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1626,6 +1634,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+			 USB_DEVICE_ID_SENSOR_HUB_7014) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9373f53..2f1dc5b 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -407,6 +407,11 @@
 #define USB_VENDOR_ID_IMATION		0x0718
 #define USB_DEVICE_ID_DISC_STAKKA	0xd000
 
+#define USB_VENDOR_ID_INTEL_8086	0x8086
+#define USB_VENDOR_ID_INTEL_8087	0x8087
+#define USB_DEVICE_ID_SENSOR_HUB_1020	0x1020
+#define USB_DEVICE_ID_SENSOR_HUB_09FA	0x09FA
+
 #define USB_VENDOR_ID_IRTOUCHSYSTEMS	0x6615
 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB	0x0070
 
@@ -670,6 +675,7 @@
 
 #define USB_VENDOR_ID_STANTUM_STM		0x0483
 #define USB_DEVICE_ID_MTP_STM		0x3261
+#define USB_DEVICE_ID_SENSOR_HUB_7014	0x7014
 
 #define USB_VENDOR_ID_STANTUM_SITRONIX		0x1403
 #define USB_DEVICE_ID_MTP_SITRONIX		0x5001
-- 
1.7.7.6

[PATCH 6/8] HID-Sensors: Added Gyroscope 3D

From: srinivas pandruvada <hidden>
Date: 2012-07-04 20:02:48

Added usage id processing for Gyroscope 3D. This uses IIO
interfaces for triggerred buffer to present data to user
mode.This uses HID sensor framework for registering callback
events from the sensor hub.

Signed-off-by: srinivas pandruvada <redacted>
---
 drivers/staging/iio/gyro/Kconfig              |   10 +
 drivers/staging/iio/gyro/Makefile             |    3 +
 drivers/staging/iio/gyro/hid-sensor-gyro-3d.c |  451 +++++++++++++++++++++++++
 3 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/gyro/hid-sensor-gyro-3d.c
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig
index ea295b2..a02e7dc 100644
--- a/drivers/staging/iio/gyro/Kconfig
+++ b/drivers/staging/iio/gyro/Kconfig
@@ -46,4 +46,14 @@ config ADXRS450
 	  This driver can also be built as a module.  If so, the module
 	  will be called adxrs450.
 
+config HID_SENSOR_GYRO_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Gyroscope 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Gyroscope 3G.
+
 endmenu
diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile
index 9ba5ec1..9d30039 100644
--- a/drivers/staging/iio/gyro/Makefile
+++ b/drivers/staging/iio/gyro/Makefile
@@ -20,3 +20,6 @@ obj-$(CONFIG_ADIS16251) += adis16251.o
 
 adxrs450-y             := adxrs450_core.o
 obj-$(CONFIG_ADXRS450) += adxrs450.o
+
+hid-sensor-gyro-3d-drv-y := hid-sensor-gyro-3d.o
+obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d-drv.o
diff --git a/drivers/staging/iio/gyro/hid-sensor-gyro-3d.c b/drivers/staging/iio/gyro/hid-sensor-gyro-3d.c
new file mode 100644
index 0000000..c5bd126
--- /dev/null
+++ b/drivers/staging/iio/gyro/hid-sensor-gyro-3d.c
@@ -0,0 +1,451 @@
+/*
+ * 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.
+ *
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/hid-sensor-hub.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/sysfs.h>
+#include "../common/hid-sensors/hid-sensor-attributes.h"
+#include "../common/hid-sensors/hid-sensor-trigger.h"
+
+/*Format: HID-SENSOR-usage_id_in_hex*/
+#define DRIVER_NAME "HID-SENSOR-200076"
+
+#define CHANNEL_SCAN_INDEX_X 0
+#define CHANNEL_SCAN_INDEX_Y 1
+#define CHANNEL_SCAN_INDEX_Z 2
+
+struct gyro_3d_sample {
+	u32 gyro_x;
+	u32 gyro_y;
+	u32 gyro_z;
+} __packed;
+
+struct gyro_3d_state {
+	struct hid_sensor_hub_attribute_info gyro_x;
+	struct hid_sensor_hub_attribute_info gyro_y;
+	struct hid_sensor_hub_attribute_info gyro_z;
+	struct gyro_3d_sample gyro_sample_data;
+};
+
+/* Channel definitions */
+static struct iio_chan_spec gyro_3d_channels[] = {
+	{
+		.type = IIO_ANGL_VEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_X,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_X,
+	}, {
+		.type = IIO_ANGL_VEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Y,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Y,
+	}, {
+		.type = IIO_ANGL_VEL,
+		.modified = 1,
+		.channel2 = IIO_MOD_Z,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_Z,
+	}
+};
+
+/* Adjust channel real bits based on report descriptor */
+static void gyro_3d_adjust_channel_bit_mask(int channel, int size)
+{
+	gyro_3d_channels[channel].scan_type.sign = 's';
+	gyro_3d_channels[channel].scan_type.realbits = size * 8;
+	gyro_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int gyro_3d_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2,
+			      long mask)
+{
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	struct gyro_3d_state *gyro_state =
+			(struct gyro_3d_state *)st->private;
+	int report_id = -1;
+	u32 address;
+
+	*val = 0;
+	*val2 = 0;
+	switch (mask) {
+	case 0:
+		switch (chan->scan_index) {
+		case  CHANNEL_SCAN_INDEX_X:
+			report_id = gyro_state->gyro_x.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Y:
+			report_id = gyro_state->gyro_y.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Z:
+			report_id = gyro_state->gyro_z.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS;
+			break;
+		default:
+			report_id = -1;
+			break;
+		}
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				st->hsdev,
+				HID_USAGE_SENSOR_GYRO_3D, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = gyro_state->gyro_x.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = gyro_state->gyro_x.unit_expo;
+		break;
+	default:
+		break;
+	}
+	return IIO_VAL_INT;
+}
+
+
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+			hid_sensor_read_samp_freq,
+			hid_sensor_write_samp_freq);
+
+static IIO_DEV_ATTR_HYSTERESIS(S_IWUSR | S_IRUSR,
+			hid_sensor_read_hyst_raw,
+			hid_sensor_write_hyst_raw);
+
+static struct attribute *gyro_3d_attributes[] = {
+	/* common attributes */
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	&iio_dev_attr_hyst_raw.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group gyro_3d_attribute_group = {
+	.attrs = gyro_3d_attributes,
+};
+
+static const struct iio_info gyro_3d_info = {
+	.attrs = &gyro_3d_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &gyro_3d_read_raw,
+};
+
+/* Function to push data to buffer */
+void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	s64 timestamp = iio_get_time_ns();
+	int datum_sz;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
+	if (!buffer) {
+		dev_err(&indio_dev->dev, "Buffer == NULL\n");
+		return;
+	}
+	datum_sz = buffer->access->get_bytes_per_datum(buffer);
+	if (len > datum_sz) {
+		dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
+				datum_sz);
+		return;
+	}
+	buffer->access->store_to(buffer, (u8 *)data, timestamp);
+}
+
+/* Callback handler to send event after all samples are received and captured */
+int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id,
+			void *priv)
+{
+	struct iio_dev *indio_dev =
+				(struct iio_dev *)platform_get_drvdata(priv);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	struct gyro_3d_state *gyro_state =
+			(struct gyro_3d_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "gyro_3d_proc_event [%d]\n", st->data_ready);
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&gyro_state->gyro_sample_data,
+				sizeof(struct gyro_3d_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				size_t raw_len, char *raw_data,
+				void *priv)
+{
+	struct iio_dev *indio_dev =
+			(struct iio_dev *)platform_get_drvdata(priv);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	struct gyro_3d_state *gyro_state =
+			(struct gyro_3d_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS:
+		gyro_state->gyro_sample_data.gyro_x =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS:
+		gyro_state->gyro_sample_data.gyro_y =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS:
+		gyro_state->gyro_sample_data.gyro_z =
+		*(u32 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int gyro_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct gyro_3d_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS,
+			&st->gyro_x);
+	gyro_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
+					st->gyro_x.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS,
+			&st->gyro_y);
+	gyro_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
+					st->gyro_y.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS,
+			&st->gyro_z);
+	gyro_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
+					st->gyro_z.size);
+
+	dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",
+			st->gyro_x.index,
+			st->gyro_x.report_id,
+			st->gyro_y.index, st->gyro_y.report_id,
+			st->gyro_z.index, st->gyro_z.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int gyro_3d_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "gyro_3d";
+	struct iio_dev *indio_dev;
+	struct gyro_3d_state *gyro_state;
+	struct hid_sensor_attributes *st;
+
+	gyro_state = kzalloc(sizeof(struct gyro_3d_state), GFP_KERNEL);
+	if (gyro_state == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	indio_dev = iio_device_alloc(sizeof(struct hid_sensor_attributes));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_free_state;
+	}
+	platform_set_drvdata(pdev, indio_dev);
+	st = iio_priv(indio_dev);
+	st->hsdev = hsdev;
+	st->pdev = pdev;
+	st->private = (void *)gyro_state;
+
+	ret = hid_sensor_parse_common_attributes(hsdev, usage_id, st);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup common attributes\n");
+		goto error_free_dev;
+	}
+
+	ret = gyro_3d_parse_report(pdev, hsdev, usage_id, gyro_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(gyro_3d_channels,
+					sizeof(gyro_3d_channels),
+					GFP_KERNEL);
+	if (!indio_dev->channels) {
+		dev_err(&pdev->dev, "failed to duplicate channels\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->num_channels =
+				ARRAY_SIZE(gyro_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &gyro_3d_info;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+		NULL, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
+		goto error_free_dev_mem;
+	}
+	iio_scan_mask_set(indio_dev, indio_dev->buffer,
+			   CHANNEL_SCAN_INDEX_X);
+	iio_scan_mask_set(indio_dev, indio_dev->buffer,
+			   CHANNEL_SCAN_INDEX_Y);
+	iio_scan_mask_set(indio_dev, indio_dev->buffer,
+			   CHANNEL_SCAN_INDEX_Z);
+	st->data_ready = false;
+	ret = hid_sensor_setup_trigger(indio_dev, name);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "trigger setup failed\n");
+		goto error_unreg_buffer_funcs;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "device register failed\n");
+		goto error_remove_trigger;
+	}
+	return ret;
+
+error_remove_trigger:
+	hid_sensor_remove_trigger(indio_dev);
+error_unreg_buffer_funcs:
+	iio_triggered_buffer_cleanup(indio_dev);
+error_free_dev_mem:
+	kfree(indio_dev->channels);
+error_free_dev:
+	iio_device_free(indio_dev);
+error_free_state:
+	kfree(gyro_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int gyro_3d_exit(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	struct gyro_3d_state *gyro_state =
+			(struct gyro_3d_state *)st->private;
+
+	iio_device_unregister(indio_dev);
+	hid_sensor_remove_trigger(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	kfree(indio_dev->channels);
+	iio_device_free(indio_dev);
+	kfree(gyro_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks gyro_3d_callbacks = {
+	.send_event = gyro_3d_proc_event,
+	.capture_sample = gyro_3d_capture_sample,
+};
+
+static int __devinit hid_gyro_3d_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 *pdata = (u32 *)pdev->dev.platform_data;
+	struct hid_sensor_hub_device *hsdev;
+
+	hsdev = (struct hid_sensor_hub_device *)*pdata;
+	ret = gyro_3d_init(pdev, hsdev, HID_USAGE_SENSOR_GYRO_3D);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "gyro_3d_init failed\n");
+		return ret;
+	}
+	gyro_3d_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,
+					&gyro_3d_callbacks);
+	return 0;
+}
+
+static int __devinit hid_gyro_3d_remove(struct platform_device *pdev)
+{
+	u32 *pdata = (u32 *)pdev->dev.platform_data;
+	struct hid_sensor_hub_device *hsdev;
+
+	hsdev = (struct hid_sensor_hub_device *)*pdata;
+	gyro_3d_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
+}
+
+static struct platform_driver hid_gyro_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_gyro_3d_probe,
+	.remove		= hid_gyro_3d_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_gyro_3d_init(void)
+{
+	return platform_driver_register(&hid_gyro_3d_platform_driver);
+}
+
+static void __exit hid_gyro_3d_exit(void)
+{
+	platform_driver_unregister(&hid_gyro_3d_platform_driver);
+}
+
+module_init(hid_gyro_3d_init);
+module_exit(hid_gyro_3d_exit);
+
+MODULE_DESCRIPTION("HID Sensor Gyro 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help