All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] HID-Sensor v4
@ 2012-07-04 19:52 srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 1/8] HID-Sensors: Documentation srinivas pandruvada
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

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


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 1/8] HID-Sensors: Documentation
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
@ 2012-07-04 19:52 ` srinivas pandruvada
       [not found]   ` <1341431532-15060-2-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
  2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

Added a summary of HID sensor framework.

Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 2/8] HID Sensors: Add to special driver list
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 1/8] HID-Sensors: Documentation srinivas pandruvada
@ 2012-07-04 19:52 ` srinivas pandruvada
       [not found] ` <1341431532-15060-1-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
  2012-07-04 19:52 ` [PATCH 6/8] HID-Sensors: Added Gyroscope 3D srinivas pandruvada
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

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

Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 3/8] HID-Sensors: Sensor framework
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
@ 2012-07-04 19:52     ` srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	srinivas pandruvada

Adding processing for HID Sensor usage table as defined by
HID 1.12, Request #: HUTRR39, dated 05 May, 2011.
This driver uses HID driver framework to register, send and
receive events.
This uses MFD framework, so that actual processing for a
specific usage id can be done in a different driver. For
example an accelerometer driver can be a separate driver and
use the interface provided by this driver to register for
events.

Signed-off-by: srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 drivers/hid/Kconfig            |   12 +
 drivers/hid/Makefile           |    1 +
 drivers/hid/hid-sensor-hub.c   |  630 ++++++++++++++++++++++++++++++++++++++++
 include/linux/hid-sensor-hub.h |   72 +++++
 include/linux/hid-sensor-ids.h |  116 ++++++++
 5 files changed, 831 insertions(+), 0 deletions(-)
 create mode 100644 drivers/hid/hid-sensor-hub.c
 create mode 100644 include/linux/hid-sensor-hub.h
 create mode 100644 include/linux/hid-sensor-ids.h

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 034c80a..1d0d42d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -660,6 +660,18 @@ config HID_ZYDACRON
 	---help---
 	Support for Zydacron remote control.
 
+config HID_SENSOR_HUB
+	tristate "HID Sensors framework support"
+	depends on USB_HID
+	select MFD_CORE
+	default n
+	-- help---
+	  Support for HID Sensor framework. This will provide MFD framework for
+	  adding different sensors, using HID sensor usage table. This defines
+	  a set of interface functions to register callbacks for events so
+	  that the events are transferred to user space using either input
+	  or IIO ineterfaces.
+
 endmenu
 
 endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index ca6cc9f..08f9d8f 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
 obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
+obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
 
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
new file mode 100644
index 0000000..4e2c021
--- /dev/null
+++ b/drivers/hid/hid-sensor-hub.c
@@ -0,0 +1,630 @@
+/*
+ * 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/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/list.h>
+#include <linux/hid-sensor-ids.h>
+#include <linux/hid-sensor-hub.h>
+
+#include "hid-ids.h"
+
+#define MAX_HUB_SENSORS	20
+#define MAX_DRIVER_NAME_SIZE 30
+#define RAW_BUFFER_SIZE	128
+#define sensor_hub_in_report(id, dev) sensor_hub_report(id, dev,\
+							HID_INPUT_REPORT)
+#define sensor_hub_out_report(id, dev) sensor_hub_report(id, dev,\
+							HID_OUTPUT_REPORT)
+#define sensor_hub_feature_report(id, dev) sensor_hub_report(id, dev,\
+							HID_FEATURE_REPORT)
+
+/* Description of in-progress IO operation, used for operations
+ * that trigger response from device */
+struct sensor_hub_pending {
+	struct completion ready;
+	u32 usage_id;
+	u32 attr_usage_id;
+	int raw_size;
+	u8 raw_data[RAW_BUFFER_SIZE];
+};
+
+struct sensor_hub_data {
+	struct hid_sensor_hub_device *hsdev;
+	struct mutex mutex;
+	spinlock_t lock;
+	struct sensor_hub_pending *pending;
+	struct list_head dyn_callback_list;
+	spinlock_t dyn_lock;
+	struct mfd_cell hid_sensor_hub_client_devs[MAX_HUB_SENSORS];
+	int hid_sensor_client_cnt;
+};
+
+struct hid_sensor_hub_callbacks_list {
+	struct list_head list;
+	u32 usage_id;
+	struct hid_sensor_hub_callbacks *usage_callback;
+	int initialized;
+	void *priv;
+};
+
+static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
+{
+	int i;
+	int ret = -EINVAL;
+
+	for (i = 0; i < hdev->maxcollection; i++) {
+		struct hid_collection *col = &hdev->collection[i];
+		if (col->type == HID_COLLECTION_PHYSICAL &&
+		   (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
+						int dir)
+{
+	struct list_head *feature_report_list =
+					&hdev->report_enum[dir].report_list;
+	struct hid_report *report = NULL;
+
+	list_for_each_entry(report, feature_report_list, list) {
+		if (report->id == id)
+			return report;
+	}
+	hid_warn(hdev, "No report with id 0x%x found\n", id);
+	return NULL;
+}
+
+static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
+					struct hid_device *hdev,
+					u32 usage_id, void **priv)
+{
+	struct hid_sensor_hub_callbacks_list *callback = NULL;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+
+
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			*priv = callback->priv;
+			spin_unlock(&pdata->dyn_lock);
+			return callback->usage_callback;
+		}
+	spin_unlock(&pdata->dyn_lock);
+	return NULL;
+}
+
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback)
+{
+	struct hid_sensor_hub_callbacks_list *callback;
+	struct sensor_hub_data *pdata =
+		(struct sensor_hub_data *)hid_get_drvdata(hsdev->hdev);
+
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			spin_unlock(&pdata->dyn_lock);
+			return -EINVAL;
+		}
+	callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+	if (!callback) {
+		spin_unlock(&pdata->dyn_lock);
+		return -ENOMEM;
+	}
+	callback->usage_callback = usage_callback;
+	callback->usage_id = usage_id;
+	callback->priv = NULL;
+	list_add_tail(&callback->list, &pdata->dyn_callback_list);
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_register_callback);
+
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+				u32 usage_id)
+{
+	struct hid_sensor_hub_callbacks_list *callback, *n;
+	struct sensor_hub_data *pdata =
+		(struct sensor_hub_data *)hid_get_drvdata(hsdev->hdev);
+
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry_safe(callback, n,
+				&pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			list_del(&callback->list);
+			kfree(callback);
+			break;
+		}
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
+
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+				u32 field_index, s32 value)
+{
+	struct hid_report *report;
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	int ret = 0;
+
+	if (report_id < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+	report = sensor_hub_feature_report(report_id, hsdev->hdev);
+	if (!report) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	if (field_index >=  report->maxfield) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	hid_set_field(report->field[field_index], 0, value);
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
+	usbhid_wait_io(hsdev->hdev);
+done_proc:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
+
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+				u32 field_index, s32 *value)
+{
+	struct hid_report *report;
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	int ret = 0;
+
+	if (report_id < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+	report = sensor_hub_feature_report(report_id, hsdev->hdev);
+	if (!report) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	if (field_index >=  report->maxfield) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hsdev->hdev);
+	*value = report->field[field_index]->value[0];
+done_proc:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
+
+
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					u32 attr_usage_id, u32 report_id)
+{
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	struct sensor_hub_pending *work;
+	unsigned long flags;
+	struct hid_report *report;
+	int ret_val = 0;
+
+	if (report_id < 0)
+		return -EINVAL;
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work)
+		return ret_val;
+
+	init_completion(&work->ready);
+	work->usage_id = usage_id;
+	work->attr_usage_id = attr_usage_id;
+	work->raw_size = 0;
+
+	mutex_lock(&data->mutex);
+	spin_lock_irqsave(&data->lock, flags);
+	data->pending = work;
+	report = sensor_hub_in_report(report_id, hsdev->hdev);
+	if (!report)
+		goto err_free;
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+	spin_unlock_irqrestore(&data->lock, flags);
+	wait_for_completion_interruptible_timeout(&work->ready, HZ*5);
+	if (work->raw_size)
+		ret_val = *(u32 *)work->raw_data;
+
+err_free:
+	data->pending = NULL;
+	mutex_unlock(&data->mutex);
+
+	kfree(work);
+	return ret_val;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
+
+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)
+{
+	int ret = -1;
+	int i, j;
+	int collection_index = -1;
+	struct hid_report *report;
+	struct hid_field *field;
+	struct hid_report_enum *report_enum;
+	struct hid_device *hdev = hsdev->hdev;
+
+	/* Initialize with defaults */
+	info->usage_id = usage_id;
+	info->attrib_id =  attr_usage_id;
+	info->report_id = -1;
+	info->index = -1;
+	info->units = -1;
+	info->unit_expo = -1;
+
+	for (i = 0; i < hdev->maxcollection; ++i) {
+		struct hid_collection *collection = &hdev->collection[i];
+		if (usage_id == collection->usage) {
+			collection_index = i;
+			break;
+		}
+	}
+	if (collection_index == -1)
+		goto err_ret;
+
+	report_enum = &hdev->report_enum[type];
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		for (i = 0; i < report->maxfield; ++i) {
+			field = report->field[i];
+			if (field->physical == usage_id &&
+				field->logical == attr_usage_id) {
+				info->index = i;
+				info->report_id = report->id;
+				info->units = field->unit;
+				info->unit_expo = field->unit_exponent;
+				info->size = field->report_size/8;
+				ret = 0;
+			} else {
+				for (j = 0; j < field->maxusage; ++j) {
+					if (field->usage[j].hid ==
+					attr_usage_id &&
+					field->usage[j].collection_index ==
+					collection_index)  {
+						info->index = i;
+						info->report_id = report->id;
+						info->units = field->unit;
+						info->unit_expo =
+							field->unit_exponent;
+						info->size =
+							field->report_size/8;
+						ret = 0;
+						break;
+					}
+				}
+			}
+			if (ret == 0)
+				break;
+		}
+	}
+err_ret:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
+
+#ifdef CONFIG_PM
+static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
+{
+	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
+	struct hid_sensor_hub_callbacks_list *callback;
+
+	hid_dbg(hdev, " sensor_hub_suspend\n");
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
+		if (callback->initialized && callback->usage_callback->suspend)
+			callback->usage_callback->suspend(
+					pdata->hsdev, callback->priv);
+	}
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+
+static int sensor_hub_resume(struct hid_device *hdev)
+{
+	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
+	struct hid_sensor_hub_callbacks_list *callback;
+
+	hid_dbg(hdev, " sensor_hub_resume\n");
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
+		if (callback->initialized && callback->usage_callback->resume)
+			callback->usage_callback->resume(
+					pdata->hsdev, callback->priv);
+	}
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+
+static int sensor_hub_reset_resume(struct hid_device *hdev)
+{
+	return 0;
+}
+#endif
+/*
+ * Handle raw report as sent by device
+ */
+static int sensor_hub_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	int i;
+	u8 *ptr;
+	int sz;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+	unsigned long flags;
+	struct hid_sensor_hub_callbacks *callback = NULL;
+	struct hid_collection *collection = NULL;
+	void *priv = NULL;
+
+	hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
+			 report->id, size, report->type);
+	hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
+	if (report->type != HID_INPUT_REPORT)
+		return 1;
+
+	ptr = raw_data;
+	ptr++; /*Skip report id*/
+
+	if (!report)
+		goto err_report;
+
+	spin_lock_irqsave(&pdata->lock, flags);
+
+	for (i = 0; i < report->maxfield; ++i) {
+
+		hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
+				i, report->field[i]->usage->collection_index,
+				report->field[i]->usage->hid,
+				report->field[i]->report_size/8);
+
+		sz = report->field[i]->report_size/8;
+		if (pdata->pending && pdata->pending->attr_usage_id ==
+				report->field[i]->usage->hid) {
+			hid_dbg(hdev, "data was pending ...\n");
+			sz = (sz > RAW_BUFFER_SIZE) ? RAW_BUFFER_SIZE : sz;
+			memcpy(pdata->pending->raw_data, ptr, sz);
+			pdata->pending->raw_size  = sz;
+			complete(&pdata->pending->ready);
+		}
+		collection = &hdev->collection[
+				report->field[i]->usage->collection_index];
+		hid_dbg(hdev, "collection->usage %x\n",
+					collection->usage);
+		callback = sensor_hub_get_callback(pdata->hsdev->hdev,
+						report->field[i]->physical,
+							&priv);
+		if (callback && callback->capture_sample) {
+			if (report->field[i]->logical)
+				callback->capture_sample(pdata->hsdev,
+					report->field[i]->logical, sz, ptr,
+					callback->pdev);
+			else
+				callback->capture_sample(pdata->hsdev,
+					report->field[i]->usage->hid, sz, ptr,
+					callback->pdev);
+		}
+		ptr += sz;
+	}
+	if (callback && collection && callback->send_event)
+		callback->send_event(pdata->hsdev, collection->usage,
+				callback->pdev);
+	spin_unlock_irqrestore(&pdata->lock, flags);
+
+err_report:
+	return 1;
+}
+
+static int sensor_hub_probe(struct hid_device *hdev,
+				const struct hid_device_id *id)
+{
+	int ret;
+	struct sensor_hub_data *sd;
+	int i;
+	char *name;
+	struct hid_report *report;
+	struct hid_report_enum *report_enum;
+	struct hid_field *field;
+
+	sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
+	if (!sd) {
+		hid_err(hdev, "cannot allocate Sensor data\n");
+		return -ENOMEM;
+	}
+	sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL);
+	if (!sd->hsdev) {
+		hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
+		ret = -ENOMEM;
+		goto err_free_hub;
+	}
+	hid_set_drvdata(hdev, sd);
+	sd->hsdev->hdev = hdev;
+	sd->hsdev->vendor_id = hdev->vendor;
+	sd->hsdev->product_id = hdev->product;
+	spin_lock_init(&sd->lock);
+	spin_lock_init(&sd->dyn_lock);
+	mutex_init(&sd->mutex);
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+	if (sensor_hub_check_for_sensor_page(hdev) < 0) {
+		hid_err(hdev, "sensor page not found\n");
+		goto err_free;
+	}
+	INIT_LIST_HEAD(&hdev->inputs);
+
+	hdev->claimed = HID_CLAIMED_INPUT;
+	ret = hid_hw_start(hdev, 0);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+	ret = hid_hw_open(hdev);
+	if (ret) {
+		hid_err(hdev, "failed to open input interrupt pipe\n");
+		goto err_stop_hw;
+	}
+
+	INIT_LIST_HEAD(&sd->dyn_callback_list);
+	sd->hid_sensor_client_cnt = 0;
+	report_enum = &hdev->report_enum[HID_INPUT_REPORT];
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		hid_dbg(hdev, "Report id:%x\n", report->id);
+		field = report->field[0];
+		if (report->maxfield && field &&
+					field->physical) {
+			name = kmalloc(MAX_DRIVER_NAME_SIZE+1,
+					GFP_KERNEL);
+			if (name  == NULL) {
+				hid_err(hdev,
+					"Failed MFD device name\n");
+					ret = -ENOMEM;
+					goto err_close;
+			}
+			snprintf(name, MAX_DRIVER_NAME_SIZE,
+					"HID-SENSOR-%x",
+					field->physical);
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].name = name;
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].platform_data =
+						&sd->hsdev;
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].pdata_size =
+						sizeof(sd->hsdev);
+			hid_dbg(hdev, "Adding %s:%x\n", name,
+					(unsigned int)sd);
+			sd->hid_sensor_client_cnt++;
+		}
+	}
+	ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
+		sd->hid_sensor_client_cnt, NULL, 0);
+	if (ret < 0) {
+		for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
+			kfree(sd->hid_sensor_hub_client_devs[i].name);
+		goto err_close;
+	}
+
+	return ret;
+
+err_close:
+	hid_hw_stop(hdev);
+	hid_hw_close(hdev);
+err_stop_hw:
+	hid_hw_stop(hdev);
+err_free:
+	kfree(sd->hsdev);
+err_free_hub:
+	kfree(sd);
+
+	return ret;
+}
+
+static void sensor_hub_remove(struct hid_device *hdev)
+{
+	struct sensor_hub_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+	int i;
+
+	hid_dbg(hdev, " hardware removed\n");
+	hdev->claimed &= ~HID_CLAIMED_INPUT;
+	hid_hw_stop(hdev);
+	hid_hw_close(hdev);
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->pending)
+		complete(&data->pending->ready);
+	spin_unlock_irqrestore(&data->lock, flags);
+	mfd_remove_devices(&hdev->dev);
+	for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
+		kfree(data->hid_sensor_hub_client_devs[i].name);
+	hid_set_drvdata(hdev, NULL);
+	mutex_destroy(&data->mutex);
+	kfree(data->hsdev);
+	kfree(data);
+}
+
+static const struct hid_device_id sensor_hub_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+			USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+			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_09FA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+			USB_DEVICE_ID_SENSOR_HUB_7014) },
+	{ }
+};
+
+static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
+	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
+};
+
+static struct hid_driver sensor_hub_driver = {
+	.name = "hid-sensor-hub",
+	.id_table = sensor_hub_devices,
+	.probe = sensor_hub_probe,
+	.remove = sensor_hub_remove,
+	.raw_event = sensor_hub_raw_event,
+#ifdef CONFIG_PM
+	.suspend = sensor_hub_suspend,
+	.resume =  sensor_hub_resume,
+	.reset_resume =  sensor_hub_reset_resume,
+#endif
+};
+
+static int __init sensor_hub_init(void)
+{
+	return hid_register_driver(&sensor_hub_driver);
+}
+
+static void __exit sensor_hub_exit(void)
+{
+	hid_unregister_driver(&sensor_hub_driver);
+}
+
+module_init(sensor_hub_init);
+module_exit(sensor_hub_exit);
+
+MODULE_DESCRIPTION("HID Sensor Hub driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
new file mode 100644
index 0000000..b63fe85
--- /dev/null
+++ b/include/linux/hid-sensor-hub.h
@@ -0,0 +1,72 @@
+/*
+ * 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_HUB_H
+#define _HID_SENSORS_HUB_H
+
+#include <linux/hid.h>
+#include <linux/hid-sensor-ids.h>
+
+struct hid_sensor_hub_attribute_info {
+	u32 usage_id;
+	u32 attrib_id;
+	s32 report_id;
+	s32 index;
+	s32 units;
+	s32 unit_expo;
+	s32 size;
+};
+
+struct hid_sensor_hub_device {
+	struct hid_device *hdev;
+	u32 vendor_id;
+	u32 product_id;
+};
+
+
+struct hid_sensor_hub_callbacks {
+	struct platform_device *pdev;
+	int (*suspend)(struct hid_sensor_hub_device *hsdev, void *priv);
+	int (*resume)(struct hid_sensor_hub_device *hsdev, void *priv);
+	int (*capture_sample)(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id, size_t raw_len, char *raw_data,
+			void *priv);
+	int (*send_event)(struct hid_sensor_hub_device *hsdev, u32 usage_id,
+			 void *priv);
+};
+
+/* Registeration functions */
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback);
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id);
+
+/* Hid sensor hub core interfaces */
+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);
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			u32 attr_usage_id, u32 report_id);
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 value);
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 *value);
+#endif
diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
new file mode 100644
index 0000000..34cc779
--- /dev/null
+++ b/include/linux/hid-sensor-ids.h
@@ -0,0 +1,116 @@
+/*
+ * 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_IDS_H
+#define _HID_SENSORS_IDS_H
+
+#define HID_UP_SENSOR		0x00200000
+#define HID_SENSOR_POLLING      0x0020030E
+#define HID_SENSOR_REPORT_STATE 0x00200316
+#define HID_SENSOR_POWER_STATE  0x00200319
+
+
+/* Accel 3D (200073) */
+#define HID_USAGE_SENSOR_ACCEL_3D				0x200073
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS	0x200453
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS	0x200454
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS	0x200455
+
+/* ALS (200041) */
+#define HID_USAGE_SENSOR_ALS				        0x200041
+#define HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE			0x2004d1
+
+/* Compass 3D: (200083) */
+
+/* Gyro 3D: (200076) */
+#define HID_USAGE_SENSOR_GYRO_3D				0x200076
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS	0x200457
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS	0x200458
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS	0x200459
+
+/*ORIENTATION: Compass 3D: (200083) */
+#define HID_USAGE_SENSOR_COMPASS_3D				0x200083
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING	0x200471
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_X	0x200472
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Y	0x200473
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Z	0x200474
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_MAGNETIC_NORTH 0x200475
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_TRUE_NORTH 0x200476
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_NORTH	0x200477
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TRUE_NORTH		0x200478
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE		0x200479
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_X		0x20047A
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Y		0x20047B
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Z		0x20047C
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_OUT_OF_RANGE 0x20047D
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT			0x20047E
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_X		0x20047F
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Y		0x200480
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Z		0x200481
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_ROTATION_MATRIX	0x200482
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_QUATERNION		0x200483
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX		0x200484
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS	0x200485
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS	0x200486
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS	0x200487
+
+/* Units */
+#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED			0x00
+#define HID_USAGE_SENSOR_UNITS_LUX				0x01
+#define HID_USAGE_SENSOR_UNITS_KELVIN				0x01000100
+#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT			0x03000100
+#define HID_USAGE_SENSOR_UNITS_PASCAL				0xF1E1
+#define HID_USAGE_SENSOR_UNITS_NEWTON				0x11E1
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND		0x11F0
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD		0x11E0
+#define HID_USAGE_SENSOR_UNITS_FARAD				0xE14F2000
+#define HID_USAGE_SENSOR_UNITS_AMPERE				0x01001000
+#define HID_USAGE_SENSOR_UNITS_WATT				0x21d1
+#define HID_USAGE_SENSOR_UNITS_HENRY				0x21E1E000
+#define HID_USAGE_SENSOR_UNITS_OHM				0x21D1E000
+#define HID_USAGE_SENSOR_UNITS_VOLT				0x21D1F000
+#define HID_USAGE_SENSOR_UNITS_HERTZ				0x01F0
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD		0x14E0
+#define HID_USAGE_SENSOR_UNITS_RADIANS				0x12
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND		0x12F0
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD		0x12E0
+#define HID_USAGE_SENSOR_UNITS_SECOND				0x0110
+#define HID_USAGE_SENSOR_UNITS_GAUSS				0x01E1F000
+#define HID_USAGE_SENSOR_UNITS_GRAM				0x0101
+#define HID_USAGE_SENSOR_UNITS_CENTIMETER			0x11
+#define HID_USAGE_SENSOR_UNITS_G				0x1A
+#define HID_USAGE_SENSOR_UNITS_MILLISECOND			0x19
+#define HID_USAGE_SENSOR_UNITS_PERCENT				0x17
+#define HID_USAGE_SENSOR_UNITS_DEGREES				0x14
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND		0x15
+
+/* Common selectors */
+#define HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL		0x20030E
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS	0x20030F
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_RANGE_PCT	0x200310
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_REL_PCT	0x200311
+#define HID_USAGE_SENSOR_PROPERTY_ACCURACY			0x200312
+#define HID_USAGE_SENSOR_PROPERTY_RESOLUTION			0x200313
+#define HID_USAGE_SENSOR_PROPERTY_RANGE_MAXIMUM			0x200314
+#define HID_USAGE_SENSOR_PROPERTY_RANGE_MINIMUM			0x200315
+#define HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE		0x200316
+
+#endif
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 3/8] HID-Sensors: Sensor framework
@ 2012-07-04 19:52     ` srinivas pandruvada
  0 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

Adding processing for HID Sensor usage table as defined by
HID 1.12, Request #: HUTRR39, dated 05 May, 2011.
This driver uses HID driver framework to register, send and
receive events.
This uses MFD framework, so that actual processing for a
specific usage id can be done in a different driver. For
example an accelerometer driver can be a separate driver and
use the interface provided by this driver to register for
events.

Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
 drivers/hid/Kconfig            |   12 +
 drivers/hid/Makefile           |    1 +
 drivers/hid/hid-sensor-hub.c   |  630 ++++++++++++++++++++++++++++++++++++++++
 include/linux/hid-sensor-hub.h |   72 +++++
 include/linux/hid-sensor-ids.h |  116 ++++++++
 5 files changed, 831 insertions(+), 0 deletions(-)
 create mode 100644 drivers/hid/hid-sensor-hub.c
 create mode 100644 include/linux/hid-sensor-hub.h
 create mode 100644 include/linux/hid-sensor-ids.h

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 034c80a..1d0d42d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -660,6 +660,18 @@ config HID_ZYDACRON
 	---help---
 	Support for Zydacron remote control.
 
+config HID_SENSOR_HUB
+	tristate "HID Sensors framework support"
+	depends on USB_HID
+	select MFD_CORE
+	default n
+	-- help---
+	  Support for HID Sensor framework. This will provide MFD framework for
+	  adding different sensors, using HID sensor usage table. This defines
+	  a set of interface functions to register callbacks for events so
+	  that the events are transferred to user space using either input
+	  or IIO ineterfaces.
+
 endmenu
 
 endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index ca6cc9f..08f9d8f 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
 obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
+obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
 
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
new file mode 100644
index 0000000..4e2c021
--- /dev/null
+++ b/drivers/hid/hid-sensor-hub.c
@@ -0,0 +1,630 @@
+/*
+ * 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/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/list.h>
+#include <linux/hid-sensor-ids.h>
+#include <linux/hid-sensor-hub.h>
+
+#include "hid-ids.h"
+
+#define MAX_HUB_SENSORS	20
+#define MAX_DRIVER_NAME_SIZE 30
+#define RAW_BUFFER_SIZE	128
+#define sensor_hub_in_report(id, dev) sensor_hub_report(id, dev,\
+							HID_INPUT_REPORT)
+#define sensor_hub_out_report(id, dev) sensor_hub_report(id, dev,\
+							HID_OUTPUT_REPORT)
+#define sensor_hub_feature_report(id, dev) sensor_hub_report(id, dev,\
+							HID_FEATURE_REPORT)
+
+/* Description of in-progress IO operation, used for operations
+ * that trigger response from device */
+struct sensor_hub_pending {
+	struct completion ready;
+	u32 usage_id;
+	u32 attr_usage_id;
+	int raw_size;
+	u8 raw_data[RAW_BUFFER_SIZE];
+};
+
+struct sensor_hub_data {
+	struct hid_sensor_hub_device *hsdev;
+	struct mutex mutex;
+	spinlock_t lock;
+	struct sensor_hub_pending *pending;
+	struct list_head dyn_callback_list;
+	spinlock_t dyn_lock;
+	struct mfd_cell hid_sensor_hub_client_devs[MAX_HUB_SENSORS];
+	int hid_sensor_client_cnt;
+};
+
+struct hid_sensor_hub_callbacks_list {
+	struct list_head list;
+	u32 usage_id;
+	struct hid_sensor_hub_callbacks *usage_callback;
+	int initialized;
+	void *priv;
+};
+
+static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
+{
+	int i;
+	int ret = -EINVAL;
+
+	for (i = 0; i < hdev->maxcollection; i++) {
+		struct hid_collection *col = &hdev->collection[i];
+		if (col->type == HID_COLLECTION_PHYSICAL &&
+		   (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
+						int dir)
+{
+	struct list_head *feature_report_list =
+					&hdev->report_enum[dir].report_list;
+	struct hid_report *report = NULL;
+
+	list_for_each_entry(report, feature_report_list, list) {
+		if (report->id == id)
+			return report;
+	}
+	hid_warn(hdev, "No report with id 0x%x found\n", id);
+	return NULL;
+}
+
+static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
+					struct hid_device *hdev,
+					u32 usage_id, void **priv)
+{
+	struct hid_sensor_hub_callbacks_list *callback = NULL;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+
+
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			*priv = callback->priv;
+			spin_unlock(&pdata->dyn_lock);
+			return callback->usage_callback;
+		}
+	spin_unlock(&pdata->dyn_lock);
+	return NULL;
+}
+
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback)
+{
+	struct hid_sensor_hub_callbacks_list *callback;
+	struct sensor_hub_data *pdata =
+		(struct sensor_hub_data *)hid_get_drvdata(hsdev->hdev);
+
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			spin_unlock(&pdata->dyn_lock);
+			return -EINVAL;
+		}
+	callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+	if (!callback) {
+		spin_unlock(&pdata->dyn_lock);
+		return -ENOMEM;
+	}
+	callback->usage_callback = usage_callback;
+	callback->usage_id = usage_id;
+	callback->priv = NULL;
+	list_add_tail(&callback->list, &pdata->dyn_callback_list);
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_register_callback);
+
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+				u32 usage_id)
+{
+	struct hid_sensor_hub_callbacks_list *callback, *n;
+	struct sensor_hub_data *pdata =
+		(struct sensor_hub_data *)hid_get_drvdata(hsdev->hdev);
+
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry_safe(callback, n,
+				&pdata->dyn_callback_list, list)
+		if (callback->usage_id == usage_id) {
+			list_del(&callback->list);
+			kfree(callback);
+			break;
+		}
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
+
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+				u32 field_index, s32 value)
+{
+	struct hid_report *report;
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	int ret = 0;
+
+	if (report_id < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+	report = sensor_hub_feature_report(report_id, hsdev->hdev);
+	if (!report) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	if (field_index >=  report->maxfield) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	hid_set_field(report->field[field_index], 0, value);
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
+	usbhid_wait_io(hsdev->hdev);
+done_proc:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
+
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+				u32 field_index, s32 *value)
+{
+	struct hid_report *report;
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	int ret = 0;
+
+	if (report_id < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+	report = sensor_hub_feature_report(report_id, hsdev->hdev);
+	if (!report) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	if (field_index >=  report->maxfield) {
+		ret = -EINVAL;
+		goto done_proc;
+	}
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+	usbhid_wait_io(hsdev->hdev);
+	*value = report->field[field_index]->value[0];
+done_proc:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
+
+
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					u32 attr_usage_id, u32 report_id)
+{
+	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
+	struct sensor_hub_pending *work;
+	unsigned long flags;
+	struct hid_report *report;
+	int ret_val = 0;
+
+	if (report_id < 0)
+		return -EINVAL;
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work)
+		return ret_val;
+
+	init_completion(&work->ready);
+	work->usage_id = usage_id;
+	work->attr_usage_id = attr_usage_id;
+	work->raw_size = 0;
+
+	mutex_lock(&data->mutex);
+	spin_lock_irqsave(&data->lock, flags);
+	data->pending = work;
+	report = sensor_hub_in_report(report_id, hsdev->hdev);
+	if (!report)
+		goto err_free;
+	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+	spin_unlock_irqrestore(&data->lock, flags);
+	wait_for_completion_interruptible_timeout(&work->ready, HZ*5);
+	if (work->raw_size)
+		ret_val = *(u32 *)work->raw_data;
+
+err_free:
+	data->pending = NULL;
+	mutex_unlock(&data->mutex);
+
+	kfree(work);
+	return ret_val;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
+
+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)
+{
+	int ret = -1;
+	int i, j;
+	int collection_index = -1;
+	struct hid_report *report;
+	struct hid_field *field;
+	struct hid_report_enum *report_enum;
+	struct hid_device *hdev = hsdev->hdev;
+
+	/* Initialize with defaults */
+	info->usage_id = usage_id;
+	info->attrib_id =  attr_usage_id;
+	info->report_id = -1;
+	info->index = -1;
+	info->units = -1;
+	info->unit_expo = -1;
+
+	for (i = 0; i < hdev->maxcollection; ++i) {
+		struct hid_collection *collection = &hdev->collection[i];
+		if (usage_id == collection->usage) {
+			collection_index = i;
+			break;
+		}
+	}
+	if (collection_index == -1)
+		goto err_ret;
+
+	report_enum = &hdev->report_enum[type];
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		for (i = 0; i < report->maxfield; ++i) {
+			field = report->field[i];
+			if (field->physical == usage_id &&
+				field->logical == attr_usage_id) {
+				info->index = i;
+				info->report_id = report->id;
+				info->units = field->unit;
+				info->unit_expo = field->unit_exponent;
+				info->size = field->report_size/8;
+				ret = 0;
+			} else {
+				for (j = 0; j < field->maxusage; ++j) {
+					if (field->usage[j].hid ==
+					attr_usage_id &&
+					field->usage[j].collection_index ==
+					collection_index)  {
+						info->index = i;
+						info->report_id = report->id;
+						info->units = field->unit;
+						info->unit_expo =
+							field->unit_exponent;
+						info->size =
+							field->report_size/8;
+						ret = 0;
+						break;
+					}
+				}
+			}
+			if (ret == 0)
+				break;
+		}
+	}
+err_ret:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
+
+#ifdef CONFIG_PM
+static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
+{
+	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
+	struct hid_sensor_hub_callbacks_list *callback;
+
+	hid_dbg(hdev, " sensor_hub_suspend\n");
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
+		if (callback->initialized && callback->usage_callback->suspend)
+			callback->usage_callback->suspend(
+					pdata->hsdev, callback->priv);
+	}
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+
+static int sensor_hub_resume(struct hid_device *hdev)
+{
+	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
+	struct hid_sensor_hub_callbacks_list *callback;
+
+	hid_dbg(hdev, " sensor_hub_resume\n");
+	spin_lock(&pdata->dyn_lock);
+	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
+		if (callback->initialized && callback->usage_callback->resume)
+			callback->usage_callback->resume(
+					pdata->hsdev, callback->priv);
+	}
+	spin_unlock(&pdata->dyn_lock);
+	return 0;
+}
+
+static int sensor_hub_reset_resume(struct hid_device *hdev)
+{
+	return 0;
+}
+#endif
+/*
+ * Handle raw report as sent by device
+ */
+static int sensor_hub_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	int i;
+	u8 *ptr;
+	int sz;
+	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+	unsigned long flags;
+	struct hid_sensor_hub_callbacks *callback = NULL;
+	struct hid_collection *collection = NULL;
+	void *priv = NULL;
+
+	hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
+			 report->id, size, report->type);
+	hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
+	if (report->type != HID_INPUT_REPORT)
+		return 1;
+
+	ptr = raw_data;
+	ptr++; /*Skip report id*/
+
+	if (!report)
+		goto err_report;
+
+	spin_lock_irqsave(&pdata->lock, flags);
+
+	for (i = 0; i < report->maxfield; ++i) {
+
+		hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
+				i, report->field[i]->usage->collection_index,
+				report->field[i]->usage->hid,
+				report->field[i]->report_size/8);
+
+		sz = report->field[i]->report_size/8;
+		if (pdata->pending && pdata->pending->attr_usage_id ==
+				report->field[i]->usage->hid) {
+			hid_dbg(hdev, "data was pending ...\n");
+			sz = (sz > RAW_BUFFER_SIZE) ? RAW_BUFFER_SIZE : sz;
+			memcpy(pdata->pending->raw_data, ptr, sz);
+			pdata->pending->raw_size  = sz;
+			complete(&pdata->pending->ready);
+		}
+		collection = &hdev->collection[
+				report->field[i]->usage->collection_index];
+		hid_dbg(hdev, "collection->usage %x\n",
+					collection->usage);
+		callback = sensor_hub_get_callback(pdata->hsdev->hdev,
+						report->field[i]->physical,
+							&priv);
+		if (callback && callback->capture_sample) {
+			if (report->field[i]->logical)
+				callback->capture_sample(pdata->hsdev,
+					report->field[i]->logical, sz, ptr,
+					callback->pdev);
+			else
+				callback->capture_sample(pdata->hsdev,
+					report->field[i]->usage->hid, sz, ptr,
+					callback->pdev);
+		}
+		ptr += sz;
+	}
+	if (callback && collection && callback->send_event)
+		callback->send_event(pdata->hsdev, collection->usage,
+				callback->pdev);
+	spin_unlock_irqrestore(&pdata->lock, flags);
+
+err_report:
+	return 1;
+}
+
+static int sensor_hub_probe(struct hid_device *hdev,
+				const struct hid_device_id *id)
+{
+	int ret;
+	struct sensor_hub_data *sd;
+	int i;
+	char *name;
+	struct hid_report *report;
+	struct hid_report_enum *report_enum;
+	struct hid_field *field;
+
+	sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
+	if (!sd) {
+		hid_err(hdev, "cannot allocate Sensor data\n");
+		return -ENOMEM;
+	}
+	sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL);
+	if (!sd->hsdev) {
+		hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
+		ret = -ENOMEM;
+		goto err_free_hub;
+	}
+	hid_set_drvdata(hdev, sd);
+	sd->hsdev->hdev = hdev;
+	sd->hsdev->vendor_id = hdev->vendor;
+	sd->hsdev->product_id = hdev->product;
+	spin_lock_init(&sd->lock);
+	spin_lock_init(&sd->dyn_lock);
+	mutex_init(&sd->mutex);
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+	if (sensor_hub_check_for_sensor_page(hdev) < 0) {
+		hid_err(hdev, "sensor page not found\n");
+		goto err_free;
+	}
+	INIT_LIST_HEAD(&hdev->inputs);
+
+	hdev->claimed = HID_CLAIMED_INPUT;
+	ret = hid_hw_start(hdev, 0);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+	ret = hid_hw_open(hdev);
+	if (ret) {
+		hid_err(hdev, "failed to open input interrupt pipe\n");
+		goto err_stop_hw;
+	}
+
+	INIT_LIST_HEAD(&sd->dyn_callback_list);
+	sd->hid_sensor_client_cnt = 0;
+	report_enum = &hdev->report_enum[HID_INPUT_REPORT];
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		hid_dbg(hdev, "Report id:%x\n", report->id);
+		field = report->field[0];
+		if (report->maxfield && field &&
+					field->physical) {
+			name = kmalloc(MAX_DRIVER_NAME_SIZE+1,
+					GFP_KERNEL);
+			if (name  == NULL) {
+				hid_err(hdev,
+					"Failed MFD device name\n");
+					ret = -ENOMEM;
+					goto err_close;
+			}
+			snprintf(name, MAX_DRIVER_NAME_SIZE,
+					"HID-SENSOR-%x",
+					field->physical);
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].name = name;
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].platform_data =
+						&sd->hsdev;
+			sd->hid_sensor_hub_client_devs[
+				sd->hid_sensor_client_cnt].pdata_size =
+						sizeof(sd->hsdev);
+			hid_dbg(hdev, "Adding %s:%x\n", name,
+					(unsigned int)sd);
+			sd->hid_sensor_client_cnt++;
+		}
+	}
+	ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
+		sd->hid_sensor_client_cnt, NULL, 0);
+	if (ret < 0) {
+		for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
+			kfree(sd->hid_sensor_hub_client_devs[i].name);
+		goto err_close;
+	}
+
+	return ret;
+
+err_close:
+	hid_hw_stop(hdev);
+	hid_hw_close(hdev);
+err_stop_hw:
+	hid_hw_stop(hdev);
+err_free:
+	kfree(sd->hsdev);
+err_free_hub:
+	kfree(sd);
+
+	return ret;
+}
+
+static void sensor_hub_remove(struct hid_device *hdev)
+{
+	struct sensor_hub_data *data = hid_get_drvdata(hdev);
+	unsigned long flags;
+	int i;
+
+	hid_dbg(hdev, " hardware removed\n");
+	hdev->claimed &= ~HID_CLAIMED_INPUT;
+	hid_hw_stop(hdev);
+	hid_hw_close(hdev);
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->pending)
+		complete(&data->pending->ready);
+	spin_unlock_irqrestore(&data->lock, flags);
+	mfd_remove_devices(&hdev->dev);
+	for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
+		kfree(data->hid_sensor_hub_client_devs[i].name);
+	hid_set_drvdata(hdev, NULL);
+	mutex_destroy(&data->mutex);
+	kfree(data->hsdev);
+	kfree(data);
+}
+
+static const struct hid_device_id sensor_hub_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+			USB_DEVICE_ID_SENSOR_HUB_1020) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+			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_09FA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+			USB_DEVICE_ID_SENSOR_HUB_7014) },
+	{ }
+};
+
+static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
+	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
+};
+
+static struct hid_driver sensor_hub_driver = {
+	.name = "hid-sensor-hub",
+	.id_table = sensor_hub_devices,
+	.probe = sensor_hub_probe,
+	.remove = sensor_hub_remove,
+	.raw_event = sensor_hub_raw_event,
+#ifdef CONFIG_PM
+	.suspend = sensor_hub_suspend,
+	.resume =  sensor_hub_resume,
+	.reset_resume =  sensor_hub_reset_resume,
+#endif
+};
+
+static int __init sensor_hub_init(void)
+{
+	return hid_register_driver(&sensor_hub_driver);
+}
+
+static void __exit sensor_hub_exit(void)
+{
+	hid_unregister_driver(&sensor_hub_driver);
+}
+
+module_init(sensor_hub_init);
+module_exit(sensor_hub_exit);
+
+MODULE_DESCRIPTION("HID Sensor Hub driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
new file mode 100644
index 0000000..b63fe85
--- /dev/null
+++ b/include/linux/hid-sensor-hub.h
@@ -0,0 +1,72 @@
+/*
+ * 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_HUB_H
+#define _HID_SENSORS_HUB_H
+
+#include <linux/hid.h>
+#include <linux/hid-sensor-ids.h>
+
+struct hid_sensor_hub_attribute_info {
+	u32 usage_id;
+	u32 attrib_id;
+	s32 report_id;
+	s32 index;
+	s32 units;
+	s32 unit_expo;
+	s32 size;
+};
+
+struct hid_sensor_hub_device {
+	struct hid_device *hdev;
+	u32 vendor_id;
+	u32 product_id;
+};
+
+
+struct hid_sensor_hub_callbacks {
+	struct platform_device *pdev;
+	int (*suspend)(struct hid_sensor_hub_device *hsdev, void *priv);
+	int (*resume)(struct hid_sensor_hub_device *hsdev, void *priv);
+	int (*capture_sample)(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id, size_t raw_len, char *raw_data,
+			void *priv);
+	int (*send_event)(struct hid_sensor_hub_device *hsdev, u32 usage_id,
+			 void *priv);
+};
+
+/* Registeration functions */
+int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			struct hid_sensor_hub_callbacks *usage_callback);
+int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id);
+
+/* Hid sensor hub core interfaces */
+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);
+int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
+			u32 usage_id,
+			u32 attr_usage_id, u32 report_id);
+int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 value);
+int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
+			u32 field_index, s32 *value);
+#endif
diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
new file mode 100644
index 0000000..34cc779
--- /dev/null
+++ b/include/linux/hid-sensor-ids.h
@@ -0,0 +1,116 @@
+/*
+ * 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_IDS_H
+#define _HID_SENSORS_IDS_H
+
+#define HID_UP_SENSOR		0x00200000
+#define HID_SENSOR_POLLING      0x0020030E
+#define HID_SENSOR_REPORT_STATE 0x00200316
+#define HID_SENSOR_POWER_STATE  0x00200319
+
+
+/* Accel 3D (200073) */
+#define HID_USAGE_SENSOR_ACCEL_3D				0x200073
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS	0x200453
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS	0x200454
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS	0x200455
+
+/* ALS (200041) */
+#define HID_USAGE_SENSOR_ALS				        0x200041
+#define HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE			0x2004d1
+
+/* Compass 3D: (200083) */
+
+/* Gyro 3D: (200076) */
+#define HID_USAGE_SENSOR_GYRO_3D				0x200076
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS	0x200457
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS	0x200458
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS	0x200459
+
+/*ORIENTATION: Compass 3D: (200083) */
+#define HID_USAGE_SENSOR_COMPASS_3D				0x200083
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING	0x200471
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_X	0x200472
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Y	0x200473
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Z	0x200474
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_MAGNETIC_NORTH 0x200475
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_TRUE_NORTH 0x200476
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_NORTH	0x200477
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TRUE_NORTH		0x200478
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE		0x200479
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_X		0x20047A
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Y		0x20047B
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Z		0x20047C
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_OUT_OF_RANGE 0x20047D
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT			0x20047E
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_X		0x20047F
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Y		0x200480
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Z		0x200481
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_ROTATION_MATRIX	0x200482
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_QUATERNION		0x200483
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX		0x200484
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS	0x200485
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS	0x200486
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS	0x200487
+
+/* Units */
+#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED			0x00
+#define HID_USAGE_SENSOR_UNITS_LUX				0x01
+#define HID_USAGE_SENSOR_UNITS_KELVIN				0x01000100
+#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT			0x03000100
+#define HID_USAGE_SENSOR_UNITS_PASCAL				0xF1E1
+#define HID_USAGE_SENSOR_UNITS_NEWTON				0x11E1
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND		0x11F0
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD		0x11E0
+#define HID_USAGE_SENSOR_UNITS_FARAD				0xE14F2000
+#define HID_USAGE_SENSOR_UNITS_AMPERE				0x01001000
+#define HID_USAGE_SENSOR_UNITS_WATT				0x21d1
+#define HID_USAGE_SENSOR_UNITS_HENRY				0x21E1E000
+#define HID_USAGE_SENSOR_UNITS_OHM				0x21D1E000
+#define HID_USAGE_SENSOR_UNITS_VOLT				0x21D1F000
+#define HID_USAGE_SENSOR_UNITS_HERTZ				0x01F0
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD		0x14E0
+#define HID_USAGE_SENSOR_UNITS_RADIANS				0x12
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND		0x12F0
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD		0x12E0
+#define HID_USAGE_SENSOR_UNITS_SECOND				0x0110
+#define HID_USAGE_SENSOR_UNITS_GAUSS				0x01E1F000
+#define HID_USAGE_SENSOR_UNITS_GRAM				0x0101
+#define HID_USAGE_SENSOR_UNITS_CENTIMETER			0x11
+#define HID_USAGE_SENSOR_UNITS_G				0x1A
+#define HID_USAGE_SENSOR_UNITS_MILLISECOND			0x19
+#define HID_USAGE_SENSOR_UNITS_PERCENT				0x17
+#define HID_USAGE_SENSOR_UNITS_DEGREES				0x14
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND		0x15
+
+/* Common selectors */
+#define HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL		0x20030E
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS	0x20030F
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_RANGE_PCT	0x200310
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_REL_PCT	0x200311
+#define HID_USAGE_SENSOR_PROPERTY_ACCURACY			0x200312
+#define HID_USAGE_SENSOR_PROPERTY_RESOLUTION			0x200313
+#define HID_USAGE_SENSOR_PROPERTY_RANGE_MAXIMUM			0x200314
+#define HID_USAGE_SENSOR_PROPERTY_RANGE_MINIMUM			0x200315
+#define HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE		0x200316
+
+#endif
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 4/8] HID-Sensors: Common attribute and trigger
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
@ 2012-07-04 19:52     ` srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	srinivas pandruvada

This patch contains the common code, which is used by all HID sensors.
There are some common set of attributes, which every hid sensor
needs it. This patch contains all such attributes processing.
Also the trigger interface is common among all HID sensors. This
patch contains common trigger functions utilized by all HID sensors.

Signed-off-by: srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 drivers/staging/iio/Kconfig                        |    1 +
 drivers/staging/iio/Makefile                       |    1 +
 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 +++
 10 files changed, 413 insertions(+), 0 deletions(-)
 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

diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 04cd6ec..7b058f4 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -29,6 +29,7 @@ source "drivers/staging/iio/accel/Kconfig"
 source "drivers/staging/iio/adc/Kconfig"
 source "drivers/staging/iio/addac/Kconfig"
 source "drivers/staging/iio/cdc/Kconfig"
+source "drivers/staging/iio/common/Kconfig"
 source "drivers/staging/iio/frequency/Kconfig"
 source "drivers/staging/iio/gyro/Kconfig"
 source "drivers/staging/iio/impedance-analyzer/Kconfig"
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index fa6937d..c7ca152 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -17,6 +17,7 @@ obj-y += accel/
 obj-y += adc/
 obj-y += addac/
 obj-y += cdc/
+obj-y += common/
 obj-y += frequency/
 obj-y += gyro/
 obj-y += impedance-analyzer/
diff --git a/drivers/staging/iio/common/Kconfig b/drivers/staging/iio/common/Kconfig
new file mode 100644
index 0000000..bed569a
--- /dev/null
+++ b/drivers/staging/iio/common/Kconfig
@@ -0,0 +1,6 @@
+#
+# IIO common modules
+#
+
+source "drivers/staging/iio/common/hid-sensors/Kconfig"
+
diff --git a/drivers/staging/iio/common/Makefile b/drivers/staging/iio/common/Makefile
new file mode 100644
index 0000000..23852b6
--- /dev/null
+++ b/drivers/staging/iio/common/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IIO common modules.
+#
+
+obj-y += hid-sensors/
diff --git a/drivers/staging/iio/common/hid-sensors/Kconfig b/drivers/staging/iio/common/hid-sensors/Kconfig
new file mode 100644
index 0000000..da64fef
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/Kconfig
@@ -0,0 +1,21 @@
+#
+# Hid Sensor common modules
+#
+menu "Hid Sensor IIO Common"
+
+config HID_SENSOR_IIO_COMMON
+	tristate "Common modules for all HID Sensor IIO drivers"
+	depends on HID_SENSOR_HUB
+	select IIO_TRIGGER if IIO_BUFFER
+	help
+	  Say yes here to build support for HID sensor to use
+	  HID sensor common processing for attributes and IIO triggers.
+
+config HID_SENSOR_ENUM_BASE_QUIRKS
+	tristate "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.
+
+endmenu
diff --git a/drivers/staging/iio/common/hid-sensors/Makefile b/drivers/staging/iio/common/hid-sensors/Makefile
new file mode 100644
index 0000000..1f463e0
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Hid sensor common modules.
+#
+
+obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
+hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
new file mode 100644
index 0000000..d39c93e
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -0,0 +1,182 @@
+/*
+ * 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/sysfs.h>
+#include "hid-sensor-attributes.h"
+
+#define MAXIMUM_SAMP_FREQUENCY 1000
+
+ssize_t hid_sensor_read_samp_freq(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	s32 value;
+	int len;
+	int ret;
+	int conv_value;
+
+	ret = sensor_hub_get_feature(st->hsdev,
+			st->poll.report_id,
+			st->poll.index, &value);
+	if (ret < 0 || value <= 0)
+		len = sprintf(buf, "0\n");
+	else {
+		if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
+			conv_value = 1000/value;
+		else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
+			conv_value = 1/value;
+		else
+			conv_value = value; /*Assume HZ*/
+		len = sprintf(buf, "%d\n", conv_value);
+	}
+	return len;
+}
+EXPORT_SYMBOL(hid_sensor_read_samp_freq);
+
+ssize_t hid_sensor_write_samp_freq(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	int value;
+	int conv_value;
+	int ret;
+
+	if (kstrtoint(buf, 10, &value) < 0)
+		return -EINVAL;
+
+	if (value > MAXIMUM_SAMP_FREQUENCY)
+		value = MAXIMUM_SAMP_FREQUENCY;
+
+	if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
+		conv_value = 1000/value;
+	else if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
+		conv_value = 1/value;
+	else
+		conv_value = value; /*Assume HZ*/
+
+	ret = sensor_hub_set_feature(st->hsdev,
+		st->poll.report_id,
+		st->poll.index,
+		conv_value);
+
+	if (ret < 0)
+		return ret;
+	return strlen(buf);
+}
+EXPORT_SYMBOL(hid_sensor_write_samp_freq);
+
+ssize_t hid_sensor_read_hyst_raw(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	s32 value;
+	int len;
+	int ret;
+
+	ret = sensor_hub_get_feature(st->hsdev,
+		st->sensitivity.report_id,
+		st->sensitivity.index, &value);
+	if (ret < 0 || value < 0)
+		len = sprintf(buf, "0\n");
+	else
+		len = sprintf(buf, "units:%d,exp:%d,value:%d\n",
+				st->sensitivity.units,
+				st->sensitivity.unit_expo, value);
+	return len;
+}
+EXPORT_SYMBOL(hid_sensor_read_hyst_raw);
+
+ssize_t hid_sensor_write_hyst_raw(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	int value;
+	int ret;
+
+	if (kstrtoint(buf, 10, &value) < 0)
+		return -EINVAL;
+
+	if (value <= 0)
+		value = 0;
+	ret = sensor_hub_set_feature(st->hsdev,
+		st->sensitivity.report_id,
+		st->sensitivity.index,
+		value);
+
+	if (ret < 0)
+		return ret;
+
+	return strlen(buf);
+}
+EXPORT_SYMBOL(hid_sensor_write_hyst_raw);
+
+int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					struct hid_sensor_attributes *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_SENSOR_POLLING, &st->poll);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_SENSOR_REPORT_STATE,
+					&st->report_state);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_SENSOR_POWER_STATE,
+					&st->power_state);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+			HID_FEATURE_REPORT, usage_id,
+			HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS,
+			 &st->sensitivity);
+
+	hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
+			st->poll.index, st->poll.report_id,
+			st->report_state.index, st->report_state.report_id,
+			st->power_state.index, st->power_state.report_id,
+			st->sensitivity.index, st->sensitivity.report_id);
+
+	return 0;
+}
+EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
+MODULE_DESCRIPTION("HID Sensor common attribute processing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
new file mode 100644
index 0000000..c859b7e
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
@@ -0,0 +1,60 @@
+/*
+ * 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
+
+/**
+ * IIO_DEV_ATTR_HYSTERESIS - sets hysterisis value
+ * @_mode: sysfs file mode/permissions
+ * @_show: output method for the attribute
+ * @_store: input method for the attribute
+ **/
+#define IIO_DEV_ATTR_HYSTERESIS(_mode, _show, _store)        \
+	IIO_DEVICE_ATTR(hyst_raw, _mode, _show, _store, 0)
+
+/* Common sysfs attributes for HID sensors */
+struct hid_sensor_attributes {
+	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;
+	void *private;
+};
+
+int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					struct hid_sensor_attributes *st);
+ssize_t hid_sensor_read_hyst_raw(struct device *dev,
+				struct device_attribute *attr,
+				char *buf);
+ssize_t hid_sensor_write_hyst_raw(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len);
+ssize_t hid_sensor_read_samp_freq(struct device *dev,
+				struct device_attribute *attr,
+				char *buf);
+ssize_t hid_sensor_write_samp_freq(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len);
+
+#endif
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
new file mode 100644
index 0000000..bef5560
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -0,0 +1,104 @@
+/*
+ * 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/trigger_consumer.h>
+#include <linux/iio/trigger.h>
+#include "hid-sensor-attributes.h"
+
+static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
+						bool state)
+{
+	struct iio_dev *indio_dev = trig->private_data;
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	int ret;
+	int state_val;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_data_rdy_trigger_set_state %d\n",
+			state);
+	state_val = state ? 1 : 0;
+#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
+	(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
+	hid_dbg(st->hsdev, " Using ENUM base FW QUIRKS\n");
+	++state_val;
+#endif
+	st->data_ready = state;
+	ret = sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
+					st->power_state.index,
+					(s32)state_val);
+
+	ret = sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
+					st->report_state.index,
+					(s32)state_val);
+	return ret;
+}
+
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
+{
+	iio_trigger_unregister(indio_dev->trig);
+	iio_trigger_free(indio_dev->trig);
+}
+EXPORT_SYMBOL(hid_sensor_remove_trigger);
+
+static const struct iio_trigger_ops hid_sensor_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
+};
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name)
+{
+	int ret;
+	struct iio_trigger *trig;
+
+	trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
+	if (trig == NULL) {
+		dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	trig->dev.parent = indio_dev->dev.parent;
+	trig->private_data = (void *)indio_dev;
+	trig->ops = &hid_sensor_trigger_ops;
+	ret = iio_trigger_register(trig);
+
+	if (ret) {
+		dev_err(&indio_dev->dev, "Trigger Register Failed\n");
+		goto error_free_trig;
+	}
+	indio_dev->trig = trig;
+
+	return ret;
+
+error_free_trig:
+	iio_trigger_free(trig);
+error_ret:
+	return ret;
+}
+EXPORT_SYMBOL(hid_sensor_setup_trigger);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
+MODULE_DESCRIPTION("HID Sensor trigger processing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
new file mode 100644
index 0000000..9ff3d02
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -0,0 +1,27 @@
+/*
+ * 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_SENSOR_TRIGGER_H
+#define _HID_SENSOR_TRIGGER_H
+
+
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
+
+#endif
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 4/8] HID-Sensors: Common attribute and trigger
@ 2012-07-04 19:52     ` srinivas pandruvada
  0 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

This patch contains the common code, which is used by all HID sensors.
There are some common set of attributes, which every hid sensor
needs it. This patch contains all such attributes processing.
Also the trigger interface is common among all HID sensors. This
patch contains common trigger functions utilized by all HID sensors.

Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
 drivers/staging/iio/Kconfig                        |    1 +
 drivers/staging/iio/Makefile                       |    1 +
 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 +++
 10 files changed, 413 insertions(+), 0 deletions(-)
 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

diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 04cd6ec..7b058f4 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -29,6 +29,7 @@ source "drivers/staging/iio/accel/Kconfig"
 source "drivers/staging/iio/adc/Kconfig"
 source "drivers/staging/iio/addac/Kconfig"
 source "drivers/staging/iio/cdc/Kconfig"
+source "drivers/staging/iio/common/Kconfig"
 source "drivers/staging/iio/frequency/Kconfig"
 source "drivers/staging/iio/gyro/Kconfig"
 source "drivers/staging/iio/impedance-analyzer/Kconfig"
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index fa6937d..c7ca152 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -17,6 +17,7 @@ obj-y += accel/
 obj-y += adc/
 obj-y += addac/
 obj-y += cdc/
+obj-y += common/
 obj-y += frequency/
 obj-y += gyro/
 obj-y += impedance-analyzer/
diff --git a/drivers/staging/iio/common/Kconfig b/drivers/staging/iio/common/Kconfig
new file mode 100644
index 0000000..bed569a
--- /dev/null
+++ b/drivers/staging/iio/common/Kconfig
@@ -0,0 +1,6 @@
+#
+# IIO common modules
+#
+
+source "drivers/staging/iio/common/hid-sensors/Kconfig"
+
diff --git a/drivers/staging/iio/common/Makefile b/drivers/staging/iio/common/Makefile
new file mode 100644
index 0000000..23852b6
--- /dev/null
+++ b/drivers/staging/iio/common/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IIO common modules.
+#
+
+obj-y += hid-sensors/
diff --git a/drivers/staging/iio/common/hid-sensors/Kconfig b/drivers/staging/iio/common/hid-sensors/Kconfig
new file mode 100644
index 0000000..da64fef
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/Kconfig
@@ -0,0 +1,21 @@
+#
+# Hid Sensor common modules
+#
+menu "Hid Sensor IIO Common"
+
+config HID_SENSOR_IIO_COMMON
+	tristate "Common modules for all HID Sensor IIO drivers"
+	depends on HID_SENSOR_HUB
+	select IIO_TRIGGER if IIO_BUFFER
+	help
+	  Say yes here to build support for HID sensor to use
+	  HID sensor common processing for attributes and IIO triggers.
+
+config HID_SENSOR_ENUM_BASE_QUIRKS
+	tristate "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.
+
+endmenu
diff --git a/drivers/staging/iio/common/hid-sensors/Makefile b/drivers/staging/iio/common/hid-sensors/Makefile
new file mode 100644
index 0000000..1f463e0
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Hid sensor common modules.
+#
+
+obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
+hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
new file mode 100644
index 0000000..d39c93e
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
@@ -0,0 +1,182 @@
+/*
+ * 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/sysfs.h>
+#include "hid-sensor-attributes.h"
+
+#define MAXIMUM_SAMP_FREQUENCY 1000
+
+ssize_t hid_sensor_read_samp_freq(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	s32 value;
+	int len;
+	int ret;
+	int conv_value;
+
+	ret = sensor_hub_get_feature(st->hsdev,
+			st->poll.report_id,
+			st->poll.index, &value);
+	if (ret < 0 || value <= 0)
+		len = sprintf(buf, "0\n");
+	else {
+		if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
+			conv_value = 1000/value;
+		else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
+			conv_value = 1/value;
+		else
+			conv_value = value; /*Assume HZ*/
+		len = sprintf(buf, "%d\n", conv_value);
+	}
+	return len;
+}
+EXPORT_SYMBOL(hid_sensor_read_samp_freq);
+
+ssize_t hid_sensor_write_samp_freq(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	int value;
+	int conv_value;
+	int ret;
+
+	if (kstrtoint(buf, 10, &value) < 0)
+		return -EINVAL;
+
+	if (value > MAXIMUM_SAMP_FREQUENCY)
+		value = MAXIMUM_SAMP_FREQUENCY;
+
+	if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
+		conv_value = 1000/value;
+	else if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
+		conv_value = 1/value;
+	else
+		conv_value = value; /*Assume HZ*/
+
+	ret = sensor_hub_set_feature(st->hsdev,
+		st->poll.report_id,
+		st->poll.index,
+		conv_value);
+
+	if (ret < 0)
+		return ret;
+	return strlen(buf);
+}
+EXPORT_SYMBOL(hid_sensor_write_samp_freq);
+
+ssize_t hid_sensor_read_hyst_raw(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	s32 value;
+	int len;
+	int ret;
+
+	ret = sensor_hub_get_feature(st->hsdev,
+		st->sensitivity.report_id,
+		st->sensitivity.index, &value);
+	if (ret < 0 || value < 0)
+		len = sprintf(buf, "0\n");
+	else
+		len = sprintf(buf, "units:%d,exp:%d,value:%d\n",
+				st->sensitivity.units,
+				st->sensitivity.unit_expo, value);
+	return len;
+}
+EXPORT_SYMBOL(hid_sensor_read_hyst_raw);
+
+ssize_t hid_sensor_write_hyst_raw(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	int value;
+	int ret;
+
+	if (kstrtoint(buf, 10, &value) < 0)
+		return -EINVAL;
+
+	if (value <= 0)
+		value = 0;
+	ret = sensor_hub_set_feature(st->hsdev,
+		st->sensitivity.report_id,
+		st->sensitivity.index,
+		value);
+
+	if (ret < 0)
+		return ret;
+
+	return strlen(buf);
+}
+EXPORT_SYMBOL(hid_sensor_write_hyst_raw);
+
+int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					struct hid_sensor_attributes *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_SENSOR_POLLING, &st->poll);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_SENSOR_REPORT_STATE,
+					&st->report_state);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+					HID_FEATURE_REPORT, usage_id,
+					HID_SENSOR_POWER_STATE,
+					&st->power_state);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev,
+			HID_FEATURE_REPORT, usage_id,
+			HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS,
+			 &st->sensitivity);
+
+	hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
+			st->poll.index, st->poll.report_id,
+			st->report_state.index, st->report_state.report_id,
+			st->power_state.index, st->power_state.report_id,
+			st->sensitivity.index, st->sensitivity.report_id);
+
+	return 0;
+}
+EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_DESCRIPTION("HID Sensor common attribute processing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
new file mode 100644
index 0000000..c859b7e
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
@@ -0,0 +1,60 @@
+/*
+ * 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
+
+/**
+ * IIO_DEV_ATTR_HYSTERESIS - sets hysterisis value
+ * @_mode: sysfs file mode/permissions
+ * @_show: output method for the attribute
+ * @_store: input method for the attribute
+ **/
+#define IIO_DEV_ATTR_HYSTERESIS(_mode, _show, _store)        \
+	IIO_DEVICE_ATTR(hyst_raw, _mode, _show, _store, 0)
+
+/* Common sysfs attributes for HID sensors */
+struct hid_sensor_attributes {
+	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;
+	void *private;
+};
+
+int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
+					u32 usage_id,
+					struct hid_sensor_attributes *st);
+ssize_t hid_sensor_read_hyst_raw(struct device *dev,
+				struct device_attribute *attr,
+				char *buf);
+ssize_t hid_sensor_write_hyst_raw(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len);
+ssize_t hid_sensor_read_samp_freq(struct device *dev,
+				struct device_attribute *attr,
+				char *buf);
+ssize_t hid_sensor_write_samp_freq(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t len);
+
+#endif
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
new file mode 100644
index 0000000..bef5560
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -0,0 +1,104 @@
+/*
+ * 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/trigger_consumer.h>
+#include <linux/iio/trigger.h>
+#include "hid-sensor-attributes.h"
+
+static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
+						bool state)
+{
+	struct iio_dev *indio_dev = trig->private_data;
+	struct hid_sensor_attributes *st = iio_priv(indio_dev);
+	int ret;
+	int state_val;
+
+	dev_dbg(&indio_dev->dev, "hid_sensor_data_rdy_trigger_set_state %d\n",
+			state);
+	state_val = state ? 1 : 0;
+#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
+	(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
+	hid_dbg(st->hsdev, " Using ENUM base FW QUIRKS\n");
+	++state_val;
+#endif
+	st->data_ready = state;
+	ret = sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
+					st->power_state.index,
+					(s32)state_val);
+
+	ret = sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
+					st->report_state.index,
+					(s32)state_val);
+	return ret;
+}
+
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
+{
+	iio_trigger_unregister(indio_dev->trig);
+	iio_trigger_free(indio_dev->trig);
+}
+EXPORT_SYMBOL(hid_sensor_remove_trigger);
+
+static const struct iio_trigger_ops hid_sensor_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
+};
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name)
+{
+	int ret;
+	struct iio_trigger *trig;
+
+	trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
+	if (trig == NULL) {
+		dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	trig->dev.parent = indio_dev->dev.parent;
+	trig->private_data = (void *)indio_dev;
+	trig->ops = &hid_sensor_trigger_ops;
+	ret = iio_trigger_register(trig);
+
+	if (ret) {
+		dev_err(&indio_dev->dev, "Trigger Register Failed\n");
+		goto error_free_trig;
+	}
+	indio_dev->trig = trig;
+
+	return ret;
+
+error_free_trig:
+	iio_trigger_free(trig);
+error_ret:
+	return ret;
+}
+EXPORT_SYMBOL(hid_sensor_setup_trigger);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_DESCRIPTION("HID Sensor trigger processing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
new file mode 100644
index 0000000..9ff3d02
--- /dev/null
+++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -0,0 +1,27 @@
+/*
+ * 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_SENSOR_TRIGGER_H
+#define _HID_SENSOR_TRIGGER_H
+
+
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
+
+#endif
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 5/8] HID-Sensors: Added accelerometer 3D
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
@ 2012-07-04 19:52     ` srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	srinivas pandruvada

Added usage id processing for Accelerometer 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 <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 drivers/staging/iio/accel/Kconfig               |   10 +
 drivers/staging/iio/accel/Makefile              |    3 +
 drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 +++++++++++++++++++++++
 3 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c

diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index 5ab7167..6ab1efa 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -102,4 +102,14 @@ config SCA3000
 	  Say yes here to build support for the VTI SCA3000 series of SPI
 	  accelerometers. These devices use a hardware ring buffer.
 
+config HID_SENSOR_ACCEL_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Acelerometers 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  accelerometers 3G.
+
 endmenu
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index 95c6666..2ae9865 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -33,3 +33,6 @@ obj-$(CONFIG_LIS3L02DQ)	+= lis3l02dq.o
 
 sca3000-y		:= sca3000_core.o sca3000_ring.o
 obj-$(CONFIG_SCA3000)	+= sca3000.o
+
+hid-sensor-accel-3d-drv-y := hid-sensor-accel-3d.o
+obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d-drv.o
diff --git a/drivers/staging/iio/accel/hid-sensor-accel-3d.c b/drivers/staging/iio/accel/hid-sensor-accel-3d.c
new file mode 100644
index 0000000..1ee65ce
--- /dev/null
+++ b/drivers/staging/iio/accel/hid-sensor-accel-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-200073"
+
+#define CHANNEL_SCAN_INDEX_X 0
+#define CHANNEL_SCAN_INDEX_Y 1
+#define CHANNEL_SCAN_INDEX_Z 2
+
+struct accel_3d_sample {
+	u32 accel_x;
+	u32 accel_y;
+	u32 accel_z;
+} __packed;
+
+struct accel_3d_state {
+	struct hid_sensor_hub_attribute_info accel_x;
+	struct hid_sensor_hub_attribute_info accel_y;
+	struct hid_sensor_hub_attribute_info accel_z;
+	struct accel_3d_sample accel_sample_data;
+};
+
+/* Channel definitions */
+static struct iio_chan_spec accel_3d_channels[] = {
+	{
+		.type = IIO_ACCEL,
+		.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_ACCEL,
+		.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_ACCEL,
+		.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 accel_3d_adjust_channel_bit_mask(int channel, int size)
+{
+	accel_3d_channels[channel].scan_type.sign = 's';
+	accel_3d_channels[channel].scan_type.realbits = size * 8;
+	accel_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int accel_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 accel_3d_state *accel_state =
+			(struct accel_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 = accel_state->accel_x.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Y:
+			report_id = accel_state->accel_y.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Z:
+			report_id = accel_state->accel_z.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_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_ACCEL_3D, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = accel_state->accel_x.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = accel_state->accel_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 *accel_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 accel_3d_attribute_group = {
+	.attrs = accel_3d_attributes,
+};
+
+static const struct iio_info accel_3d_info = {
+	.attrs = &accel_3d_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &accel_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 accel_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 accel_3d_state *accel_state =
+			(struct accel_3d_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n", st->data_ready);
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&accel_state->accel_sample_data,
+				sizeof(struct accel_3d_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int accel_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 accel_3d_state *accel_state =
+			(struct accel_3d_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
+		accel_state->accel_sample_data.accel_x =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
+		accel_state->accel_sample_data.accel_y =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
+		accel_state->accel_sample_data.accel_z =
+		*(u32 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int accel_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct accel_3d_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
+			&st->accel_x);
+	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
+					st->accel_x.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
+			&st->accel_y);
+	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
+					st->accel_y.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
+			&st->accel_z);
+	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
+					st->accel_z.size);
+
+	dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
+			st->accel_x.index,
+			st->accel_x.report_id,
+			st->accel_y.index, st->accel_y.report_id,
+			st->accel_z.index, st->accel_z.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int accel_3d_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "accel_3d";
+	struct iio_dev *indio_dev;
+	struct accel_3d_state *accel_state;
+	struct hid_sensor_attributes *st;
+
+	accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
+	if (accel_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 *)accel_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 = accel_3d_parse_report(pdev, hsdev, usage_id, accel_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(accel_3d_channels,
+					sizeof(accel_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(accel_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &accel_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(accel_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int accel_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 accel_3d_state *accel_state =
+			(struct accel_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(accel_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks accel_3d_callbacks = {
+	.send_event = accel_3d_proc_event,
+	.capture_sample = accel_3d_capture_sample,
+};
+
+static int __devinit hid_accel_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 = accel_3d_init(pdev, hsdev, HID_USAGE_SENSOR_ACCEL_3D);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "accel_3d_init failed\n");
+		return ret;
+	}
+	accel_3d_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
+					&accel_3d_callbacks);
+	return 0;
+}
+
+static int __devinit hid_accel_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;
+	accel_3d_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
+}
+
+static struct platform_driver hid_accel_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_accel_3d_probe,
+	.remove		= hid_accel_3d_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_accel_3d_init(void)
+{
+	return platform_driver_register(&hid_accel_3d_platform_driver);
+}
+
+static void __exit hid_accel_3d_exit(void)
+{
+	platform_driver_unregister(&hid_accel_3d_platform_driver);
+}
+
+module_init(hid_accel_3d_init);
+module_exit(hid_accel_3d_exit);
+
+MODULE_DESCRIPTION("HID Sensor Accel 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 5/8] HID-Sensors: Added accelerometer 3D
@ 2012-07-04 19:52     ` srinivas pandruvada
  0 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

Added usage id processing for Accelerometer 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 <srinivas.pandruvada@intel.com>
---
 drivers/staging/iio/accel/Kconfig               |   10 +
 drivers/staging/iio/accel/Makefile              |    3 +
 drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 +++++++++++++++++++++++
 3 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c

diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index 5ab7167..6ab1efa 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -102,4 +102,14 @@ config SCA3000
 	  Say yes here to build support for the VTI SCA3000 series of SPI
 	  accelerometers. These devices use a hardware ring buffer.
 
+config HID_SENSOR_ACCEL_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Acelerometers 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  accelerometers 3G.
+
 endmenu
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index 95c6666..2ae9865 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -33,3 +33,6 @@ obj-$(CONFIG_LIS3L02DQ)	+= lis3l02dq.o
 
 sca3000-y		:= sca3000_core.o sca3000_ring.o
 obj-$(CONFIG_SCA3000)	+= sca3000.o
+
+hid-sensor-accel-3d-drv-y := hid-sensor-accel-3d.o
+obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d-drv.o
diff --git a/drivers/staging/iio/accel/hid-sensor-accel-3d.c b/drivers/staging/iio/accel/hid-sensor-accel-3d.c
new file mode 100644
index 0000000..1ee65ce
--- /dev/null
+++ b/drivers/staging/iio/accel/hid-sensor-accel-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-200073"
+
+#define CHANNEL_SCAN_INDEX_X 0
+#define CHANNEL_SCAN_INDEX_Y 1
+#define CHANNEL_SCAN_INDEX_Z 2
+
+struct accel_3d_sample {
+	u32 accel_x;
+	u32 accel_y;
+	u32 accel_z;
+} __packed;
+
+struct accel_3d_state {
+	struct hid_sensor_hub_attribute_info accel_x;
+	struct hid_sensor_hub_attribute_info accel_y;
+	struct hid_sensor_hub_attribute_info accel_z;
+	struct accel_3d_sample accel_sample_data;
+};
+
+/* Channel definitions */
+static struct iio_chan_spec accel_3d_channels[] = {
+	{
+		.type = IIO_ACCEL,
+		.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_ACCEL,
+		.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_ACCEL,
+		.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 accel_3d_adjust_channel_bit_mask(int channel, int size)
+{
+	accel_3d_channels[channel].scan_type.sign = 's';
+	accel_3d_channels[channel].scan_type.realbits = size * 8;
+	accel_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int accel_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 accel_3d_state *accel_state =
+			(struct accel_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 = accel_state->accel_x.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Y:
+			report_id = accel_state->accel_y.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Z:
+			report_id = accel_state->accel_z.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_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_ACCEL_3D, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = accel_state->accel_x.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = accel_state->accel_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 *accel_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 accel_3d_attribute_group = {
+	.attrs = accel_3d_attributes,
+};
+
+static const struct iio_info accel_3d_info = {
+	.attrs = &accel_3d_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &accel_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 accel_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 accel_3d_state *accel_state =
+			(struct accel_3d_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n", st->data_ready);
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&accel_state->accel_sample_data,
+				sizeof(struct accel_3d_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int accel_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 accel_3d_state *accel_state =
+			(struct accel_3d_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
+		accel_state->accel_sample_data.accel_x =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
+		accel_state->accel_sample_data.accel_y =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
+		accel_state->accel_sample_data.accel_z =
+		*(u32 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int accel_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct accel_3d_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
+			&st->accel_x);
+	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
+					st->accel_x.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
+			&st->accel_y);
+	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
+					st->accel_y.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
+			&st->accel_z);
+	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
+					st->accel_z.size);
+
+	dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
+			st->accel_x.index,
+			st->accel_x.report_id,
+			st->accel_y.index, st->accel_y.report_id,
+			st->accel_z.index, st->accel_z.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int accel_3d_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "accel_3d";
+	struct iio_dev *indio_dev;
+	struct accel_3d_state *accel_state;
+	struct hid_sensor_attributes *st;
+
+	accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
+	if (accel_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 *)accel_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 = accel_3d_parse_report(pdev, hsdev, usage_id, accel_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(accel_3d_channels,
+					sizeof(accel_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(accel_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &accel_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(accel_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int accel_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 accel_3d_state *accel_state =
+			(struct accel_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(accel_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks accel_3d_callbacks = {
+	.send_event = accel_3d_proc_event,
+	.capture_sample = accel_3d_capture_sample,
+};
+
+static int __devinit hid_accel_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 = accel_3d_init(pdev, hsdev, HID_USAGE_SENSOR_ACCEL_3D);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "accel_3d_init failed\n");
+		return ret;
+	}
+	accel_3d_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
+					&accel_3d_callbacks);
+	return 0;
+}
+
+static int __devinit hid_accel_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;
+	accel_3d_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
+}
+
+static struct platform_driver hid_accel_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_accel_3d_probe,
+	.remove		= hid_accel_3d_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_accel_3d_init(void)
+{
+	return platform_driver_register(&hid_accel_3d_platform_driver);
+}
+
+static void __exit hid_accel_3d_exit(void)
+{
+	platform_driver_unregister(&hid_accel_3d_platform_driver);
+}
+
+module_init(hid_accel_3d_init);
+module_exit(hid_accel_3d_exit);
+
+MODULE_DESCRIPTION("HID Sensor Accel 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 6/8] HID-Sensors: Added Gyroscope 3D
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
                   ` (2 preceding siblings ...)
       [not found] ` <1341431532-15060-1-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
@ 2012-07-04 19:52 ` srinivas pandruvada
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

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 <srinivas.pandruvada@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 7/8] HID-Sensors: Added Compass/Magnetometer 3D
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
@ 2012-07-04 19:52     ` srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	srinivas pandruvada

Added usage id processing for Compass 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 <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 drivers/staging/iio/magnetometer/Kconfig           |   10 +
 drivers/staging/iio/magnetometer/Makefile          |    3 +
 .../staging/iio/magnetometer/hid-sensor-magn-3d.c  |  451 ++++++++++++++++++++
 3 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c

diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index df5e0d4..ad6edd5 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -24,4 +24,14 @@ config SENSORS_HMC5843
 	  To compile this driver as a module, choose M here: the module
 	  will be called hmc5843.
 
+config HID_SENSOR_MAGNETOMETER_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Magenetometer 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Magnetometer 3G.
+
 endmenu
diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
index f2a753f..d14f05e 100644
--- a/drivers/staging/iio/magnetometer/Makefile
+++ b/drivers/staging/iio/magnetometer/Makefile
@@ -4,3 +4,6 @@
 
 obj-$(CONFIG_SENSORS_AK8975)	+= ak8975.o
 obj-$(CONFIG_SENSORS_HMC5843)	+= hmc5843.o
+
+hid-sensor-magn-3d-drv-y := hid-sensor-magn-3d.o
+obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d-drv.o
diff --git a/drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c
new file mode 100644
index 0000000..333a2c5
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/hid-sensor-magn-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-200083"
+
+#define CHANNEL_SCAN_INDEX_X 0
+#define CHANNEL_SCAN_INDEX_Y 1
+#define CHANNEL_SCAN_INDEX_Z 2
+
+struct magn_3d_sample {
+	u32 magn_x;
+	u32 magn_y;
+	u32 magn_z;
+} __packed;
+
+struct magn_3d_state {
+	struct hid_sensor_hub_attribute_info magn_x;
+	struct hid_sensor_hub_attribute_info magn_y;
+	struct hid_sensor_hub_attribute_info magn_z;
+	struct magn_3d_sample magn_sample_data;
+};
+
+/* Channel definitions */
+static struct iio_chan_spec magn_3d_channels[] = {
+	{
+		.type = IIO_MAGN,
+		.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_MAGN,
+		.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_MAGN,
+		.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 magn_3d_adjust_channel_bit_mask(int channel, int size)
+{
+	magn_3d_channels[channel].scan_type.sign = 's';
+	magn_3d_channels[channel].scan_type.realbits = size * 8;
+	magn_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int magn_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 magn_3d_state *magn_state =
+			(struct magn_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 = magn_state->magn_x.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Y:
+			report_id = magn_state->magn_y.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Z:
+			report_id = magn_state->magn_z.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_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_COMPASS_3D, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = magn_state->magn_x.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = magn_state->magn_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 *magn_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 magn_3d_attribute_group = {
+	.attrs = magn_3d_attributes,
+};
+
+static const struct iio_info magn_3d_info = {
+	.attrs = &magn_3d_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &magn_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 magn_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 magn_3d_state *magn_state =
+			(struct magn_3d_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "magn_3d_proc_event [%d]\n", st->data_ready);
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&magn_state->magn_sample_data,
+				sizeof(struct magn_3d_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int magn_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 magn_3d_state *magn_state =
+			(struct magn_3d_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS:
+		magn_state->magn_sample_data.magn_x =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS:
+		magn_state->magn_sample_data.magn_y =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS:
+		magn_state->magn_sample_data.magn_z =
+		*(u32 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int magn_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct magn_3d_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS,
+			&st->magn_x);
+	magn_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
+					st->magn_x.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS,
+			&st->magn_y);
+	magn_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
+					st->magn_y.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS,
+			&st->magn_z);
+	magn_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
+					st->magn_z.size);
+
+	dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
+			st->magn_x.index,
+			st->magn_x.report_id,
+			st->magn_y.index, st->magn_y.report_id,
+			st->magn_z.index, st->magn_z.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int magn_3d_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "compass_3d";
+	struct iio_dev *indio_dev;
+	struct magn_3d_state *magn_state;
+	struct hid_sensor_attributes *st;
+
+	magn_state = kzalloc(sizeof(struct magn_3d_state), GFP_KERNEL);
+	if (magn_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 *)magn_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 = magn_3d_parse_report(pdev, hsdev, usage_id, magn_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(magn_3d_channels,
+					sizeof(magn_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(magn_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &magn_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(magn_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int magn_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 magn_3d_state *magn_state =
+			(struct magn_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(magn_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks magn_3d_callbacks = {
+	.send_event = magn_3d_proc_event,
+	.capture_sample = magn_3d_capture_sample,
+};
+
+static int __devinit hid_magn_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 = magn_3d_init(pdev, hsdev, HID_USAGE_SENSOR_COMPASS_3D);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "magn_3d_init failed\n");
+		return ret;
+	}
+	magn_3d_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D,
+					&magn_3d_callbacks);
+	return 0;
+}
+
+static int __devinit hid_magn_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;
+	magn_3d_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
+}
+
+static struct platform_driver hid_magn_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_magn_3d_probe,
+	.remove		= hid_magn_3d_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_magn_3d_init(void)
+{
+	return platform_driver_register(&hid_magn_3d_platform_driver);
+}
+
+static void __exit hid_magn_3d_exit(void)
+{
+	platform_driver_unregister(&hid_magn_3d_platform_driver);
+}
+
+module_init(hid_magn_3d_init);
+module_exit(hid_magn_3d_exit);
+
+MODULE_DESCRIPTION("HID Sensor Magnetometer 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 7/8] HID-Sensors: Added Compass/Magnetometer 3D
@ 2012-07-04 19:52     ` srinivas pandruvada
  0 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

Added usage id processing for Compass 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 <srinivas.pandruvada@intel.com>
---
 drivers/staging/iio/magnetometer/Kconfig           |   10 +
 drivers/staging/iio/magnetometer/Makefile          |    3 +
 .../staging/iio/magnetometer/hid-sensor-magn-3d.c  |  451 ++++++++++++++++++++
 3 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c

diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index df5e0d4..ad6edd5 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -24,4 +24,14 @@ config SENSORS_HMC5843
 	  To compile this driver as a module, choose M here: the module
 	  will be called hmc5843.
 
+config HID_SENSOR_MAGNETOMETER_3D
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID Magenetometer 3D"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Magnetometer 3G.
+
 endmenu
diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
index f2a753f..d14f05e 100644
--- a/drivers/staging/iio/magnetometer/Makefile
+++ b/drivers/staging/iio/magnetometer/Makefile
@@ -4,3 +4,6 @@
 
 obj-$(CONFIG_SENSORS_AK8975)	+= ak8975.o
 obj-$(CONFIG_SENSORS_HMC5843)	+= hmc5843.o
+
+hid-sensor-magn-3d-drv-y := hid-sensor-magn-3d.o
+obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d-drv.o
diff --git a/drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/staging/iio/magnetometer/hid-sensor-magn-3d.c
new file mode 100644
index 0000000..333a2c5
--- /dev/null
+++ b/drivers/staging/iio/magnetometer/hid-sensor-magn-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-200083"
+
+#define CHANNEL_SCAN_INDEX_X 0
+#define CHANNEL_SCAN_INDEX_Y 1
+#define CHANNEL_SCAN_INDEX_Z 2
+
+struct magn_3d_sample {
+	u32 magn_x;
+	u32 magn_y;
+	u32 magn_z;
+} __packed;
+
+struct magn_3d_state {
+	struct hid_sensor_hub_attribute_info magn_x;
+	struct hid_sensor_hub_attribute_info magn_y;
+	struct hid_sensor_hub_attribute_info magn_z;
+	struct magn_3d_sample magn_sample_data;
+};
+
+/* Channel definitions */
+static struct iio_chan_spec magn_3d_channels[] = {
+	{
+		.type = IIO_MAGN,
+		.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_MAGN,
+		.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_MAGN,
+		.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 magn_3d_adjust_channel_bit_mask(int channel, int size)
+{
+	magn_3d_channels[channel].scan_type.sign = 's';
+	magn_3d_channels[channel].scan_type.realbits = size * 8;
+	magn_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+/* Channel read_raw handler */
+static int magn_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 magn_3d_state *magn_state =
+			(struct magn_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 = magn_state->magn_x.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Y:
+			report_id = magn_state->magn_y.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS;
+			break;
+		case  CHANNEL_SCAN_INDEX_Z:
+			report_id = magn_state->magn_z.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_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_COMPASS_3D, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = magn_state->magn_x.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = magn_state->magn_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 *magn_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 magn_3d_attribute_group = {
+	.attrs = magn_3d_attributes,
+};
+
+static const struct iio_info magn_3d_info = {
+	.attrs = &magn_3d_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &magn_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 magn_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 magn_3d_state *magn_state =
+			(struct magn_3d_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "magn_3d_proc_event [%d]\n", st->data_ready);
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&magn_state->magn_sample_data,
+				sizeof(struct magn_3d_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int magn_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 magn_3d_state *magn_state =
+			(struct magn_3d_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS:
+		magn_state->magn_sample_data.magn_x =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS:
+		magn_state->magn_sample_data.magn_y =
+		*(u32 *)raw_data;
+		break;
+	case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS:
+		magn_state->magn_sample_data.magn_z =
+		*(u32 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int magn_3d_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct magn_3d_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS,
+			&st->magn_x);
+	magn_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
+					st->magn_x.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS,
+			&st->magn_y);
+	magn_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
+					st->magn_y.size);
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS,
+			&st->magn_z);
+	magn_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
+					st->magn_z.size);
+
+	dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
+			st->magn_x.index,
+			st->magn_x.report_id,
+			st->magn_y.index, st->magn_y.report_id,
+			st->magn_z.index, st->magn_z.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int magn_3d_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "compass_3d";
+	struct iio_dev *indio_dev;
+	struct magn_3d_state *magn_state;
+	struct hid_sensor_attributes *st;
+
+	magn_state = kzalloc(sizeof(struct magn_3d_state), GFP_KERNEL);
+	if (magn_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 *)magn_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 = magn_3d_parse_report(pdev, hsdev, usage_id, magn_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(magn_3d_channels,
+					sizeof(magn_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(magn_3d_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &magn_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(magn_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int magn_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 magn_3d_state *magn_state =
+			(struct magn_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(magn_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks magn_3d_callbacks = {
+	.send_event = magn_3d_proc_event,
+	.capture_sample = magn_3d_capture_sample,
+};
+
+static int __devinit hid_magn_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 = magn_3d_init(pdev, hsdev, HID_USAGE_SENSOR_COMPASS_3D);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "magn_3d_init failed\n");
+		return ret;
+	}
+	magn_3d_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D,
+					&magn_3d_callbacks);
+	return 0;
+}
+
+static int __devinit hid_magn_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;
+	magn_3d_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
+}
+
+static struct platform_driver hid_magn_3d_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_magn_3d_probe,
+	.remove		= hid_magn_3d_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_magn_3d_init(void)
+{
+	return platform_driver_register(&hid_magn_3d_platform_driver);
+}
+
+static void __exit hid_magn_3d_exit(void)
+{
+	platform_driver_unregister(&hid_magn_3d_platform_driver);
+}
+
+module_init(hid_magn_3d_init);
+module_exit(hid_magn_3d_exit);
+
+MODULE_DESCRIPTION("HID Sensor Magnetometer 3D");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 8/8] HID-Sensors: Added ALS
  2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
@ 2012-07-04 19:52     ` srinivas pandruvada
  2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw,
	srinivas pandruvada

Added usage id processing for ALS. 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 <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 drivers/staging/iio/light/Kconfig          |   10 +
 drivers/staging/iio/light/Makefile         |    3 +
 drivers/staging/iio/light/hid-sensor-als.c |  380 ++++++++++++++++++++++++++++
 3 files changed, 393 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/light/hid-sensor-als.c

diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index 4bed30e..c131fe9 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -50,4 +50,14 @@ config TSL2x7x
 	 tmd2672, tsl2772, tmd2772 devices.
 	 Provides iio_events and direct access via sysfs.
 
+config HID_SENSOR_ALS
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID ALS"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Ambient light sensor.
+
 endmenu
diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile
index 141af1e..71f21be 100644
--- a/drivers/staging/iio/light/Makefile
+++ b/drivers/staging/iio/light/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_SENSORS_ISL29018)	+= isl29018.o
 obj-$(CONFIG_SENSORS_ISL29028)	+= isl29028.o
 obj-$(CONFIG_TSL2583)	+= tsl2583.o
 obj-$(CONFIG_TSL2x7x)	+= tsl2x7x_core.o
+
+hid-sensor-als-drv-y := hid-sensor-als.o
+obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als-drv.o
diff --git a/drivers/staging/iio/light/hid-sensor-als.c b/drivers/staging/iio/light/hid-sensor-als.c
new file mode 100644
index 0000000..e2560ec
--- /dev/null
+++ b/drivers/staging/iio/light/hid-sensor-als.c
@@ -0,0 +1,380 @@
+/*
+ * 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-200041"
+
+#define CHANNEL_SCAN_INDEX_ILLUM 0
+
+struct als_sample {
+	u16 illum;
+};
+
+struct als_state {
+	struct hid_sensor_hub_attribute_info als_illum;
+	struct als_sample als_sample_data;
+};
+
+static struct iio_chan_spec als_channels[] = {
+	{
+		.type = IIO_INTENSITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_LIGHT_BOTH,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
+	}
+};
+
+static void als_adjust_channel_bit_mask(int channel, int size)
+{
+	als_channels[channel].scan_type.sign = 's';
+	als_channels[channel].scan_type.realbits = size * 8;
+	als_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+static int als_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 als_state *als_state = (struct als_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_ILLUM:
+			report_id = als_state->als_illum.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE;
+			break;
+		default:
+			report_id = -1;
+			break;
+		}
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				st->hsdev,
+				HID_USAGE_SENSOR_ALS, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = als_state->als_illum.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = als_state->als_illum.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 *als_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 als_attribute_group = {
+	.attrs = als_attributes,
+};
+
+static const struct iio_info als_info = {
+	.attrs = &als_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &als_read_raw,
+};
+
+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;
+
+	if (!buffer)
+		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);
+}
+
+/* Function to push data to IIO buffer */
+int als_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 als_state *als_state = (struct als_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "als_proc_event\n");
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&als_state->als_sample_data,
+				sizeof(struct als_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int als_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 als_state *als_state = (struct als_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE:
+		als_state->als_sample_data.illum =
+		*(u16 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int als_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct als_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE,
+			&st->als_illum);
+	als_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_ILLUM,
+					st->als_illum.size);
+
+	dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
+			st->als_illum.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int als_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "als";
+	struct iio_dev *indio_dev;
+	struct als_state *als_state;
+	struct hid_sensor_attributes *st;
+
+	als_state = kzalloc(sizeof(struct als_state), GFP_KERNEL);
+	if (als_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 *)als_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 = als_parse_report(pdev, hsdev, usage_id, als_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(als_channels,
+					sizeof(als_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(als_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &als_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_ILLUM);
+	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(als_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int als_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 als_state *als_state =
+			(struct als_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(als_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks als_callbacks = {
+	.send_event = als_proc_event,
+	.capture_sample = als_capture_sample,
+};
+
+static int __devinit hid_als_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 = als_init(pdev, hsdev, HID_USAGE_SENSOR_ALS);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "als_init failed\n");
+		return ret;
+	}
+	als_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
+					&als_callbacks);
+	return 0;
+}
+
+static int __devinit hid_als_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;
+	als_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
+}
+
+static struct platform_driver hid_als_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_als_probe,
+	.remove		= hid_als_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_als_init(void)
+{
+	return platform_driver_register(&hid_als_platform_driver);
+}
+
+static void __exit hid_als_exit(void)
+{
+	platform_driver_unregister(&hid_als_platform_driver);
+}
+
+module_init(hid_als_init);
+module_exit(hid_als_exit);
+
+MODULE_DESCRIPTION("HID Sensor ALS");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 8/8] HID-Sensors: Added ALS
@ 2012-07-04 19:52     ` srinivas pandruvada
  0 siblings, 0 replies; 27+ messages in thread
From: srinivas pandruvada @ 2012-07-04 19:52 UTC (permalink / raw)
  To: linux-iio; +Cc: linux-input, jkosina, lars, jic23, srinivas pandruvada

Added usage id processing for ALS. 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 <srinivas.pandruvada@intel.com>
---
 drivers/staging/iio/light/Kconfig          |   10 +
 drivers/staging/iio/light/Makefile         |    3 +
 drivers/staging/iio/light/hid-sensor-als.c |  380 ++++++++++++++++++++++++++++
 3 files changed, 393 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/iio/light/hid-sensor-als.c

diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index 4bed30e..c131fe9 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -50,4 +50,14 @@ config TSL2x7x
 	 tmd2672, tsl2772, tmd2772 devices.
 	 Provides iio_events and direct access via sysfs.
 
+config HID_SENSOR_ALS
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	tristate "HID ALS"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Ambient light sensor.
+
 endmenu
diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile
index 141af1e..71f21be 100644
--- a/drivers/staging/iio/light/Makefile
+++ b/drivers/staging/iio/light/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_SENSORS_ISL29018)	+= isl29018.o
 obj-$(CONFIG_SENSORS_ISL29028)	+= isl29028.o
 obj-$(CONFIG_TSL2583)	+= tsl2583.o
 obj-$(CONFIG_TSL2x7x)	+= tsl2x7x_core.o
+
+hid-sensor-als-drv-y := hid-sensor-als.o
+obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als-drv.o
diff --git a/drivers/staging/iio/light/hid-sensor-als.c b/drivers/staging/iio/light/hid-sensor-als.c
new file mode 100644
index 0000000..e2560ec
--- /dev/null
+++ b/drivers/staging/iio/light/hid-sensor-als.c
@@ -0,0 +1,380 @@
+/*
+ * 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-200041"
+
+#define CHANNEL_SCAN_INDEX_ILLUM 0
+
+struct als_sample {
+	u16 illum;
+};
+
+struct als_state {
+	struct hid_sensor_hub_attribute_info als_illum;
+	struct als_sample als_sample_data;
+};
+
+static struct iio_chan_spec als_channels[] = {
+	{
+		.type = IIO_INTENSITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_LIGHT_BOTH,
+		.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,
+		.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
+	}
+};
+
+static void als_adjust_channel_bit_mask(int channel, int size)
+{
+	als_channels[channel].scan_type.sign = 's';
+	als_channels[channel].scan_type.realbits = size * 8;
+	als_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+}
+
+static int als_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 als_state *als_state = (struct als_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_ILLUM:
+			report_id = als_state->als_illum.report_id;
+			address =
+			HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE;
+			break;
+		default:
+			report_id = -1;
+			break;
+		}
+		if (report_id >= 0)
+			*val = sensor_hub_input_attr_get_raw_value(
+				st->hsdev,
+				HID_USAGE_SENSOR_ALS, address,
+				report_id);
+		else
+			*val = 0;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = als_state->als_illum.units;
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = als_state->als_illum.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 *als_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 als_attribute_group = {
+	.attrs = als_attributes,
+};
+
+static const struct iio_info als_info = {
+	.attrs = &als_attribute_group,
+	.driver_module = THIS_MODULE,
+	.read_raw = &als_read_raw,
+};
+
+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;
+
+	if (!buffer)
+		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);
+}
+
+/* Function to push data to IIO buffer */
+int als_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 als_state *als_state = (struct als_state *)st->private;
+
+	dev_dbg(&indio_dev->dev, "als_proc_event\n");
+	if (st->data_ready)
+		hid_sensor_push_data(indio_dev,
+				(u8 *)&als_state->als_sample_data,
+				sizeof(struct als_sample));
+	return 0;
+}
+
+/* Capture samples in local storage */
+int als_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 als_state *als_state = (struct als_state *)st->private;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE:
+		als_state->als_sample_data.illum =
+		*(u16 *)raw_data;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/* Parse report which is specific to an usage id*/
+static int als_parse_report(struct platform_device *pdev,
+				struct hid_sensor_hub_device *hsdev,
+				unsigned usage_id,
+				struct als_state *st)
+{
+	int ret;
+
+	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
+			usage_id,
+			HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE,
+			&st->als_illum);
+	als_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_ILLUM,
+					st->als_illum.size);
+
+	dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
+			st->als_illum.report_id);
+
+	return 0;
+}
+
+/* Function to initialize the processing for usage id */
+static int als_init(struct platform_device *pdev,
+			struct hid_sensor_hub_device *hsdev,
+			unsigned usage_id)
+{
+	int ret = 0;
+	static char *name = "als";
+	struct iio_dev *indio_dev;
+	struct als_state *als_state;
+	struct hid_sensor_attributes *st;
+
+	als_state = kzalloc(sizeof(struct als_state), GFP_KERNEL);
+	if (als_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 *)als_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 = als_parse_report(pdev, hsdev, usage_id, als_state);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to setup attributes\n");
+		goto error_free_dev;
+	}
+
+	indio_dev->channels = kmemdup(als_channels,
+					sizeof(als_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(als_channels);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &als_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_ILLUM);
+	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(als_state);
+error_ret:
+	return ret;
+}
+
+/* Function to deinitialize the processing for usage id */
+static int als_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 als_state *als_state =
+			(struct als_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(als_state);
+	return ret;
+}
+
+static struct hid_sensor_hub_callbacks als_callbacks = {
+	.send_event = als_proc_event,
+	.capture_sample = als_capture_sample,
+};
+
+static int __devinit hid_als_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 = als_init(pdev, hsdev, HID_USAGE_SENSOR_ALS);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "als_init failed\n");
+		return ret;
+	}
+	als_callbacks.pdev = pdev;
+	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
+					&als_callbacks);
+	return 0;
+}
+
+static int __devinit hid_als_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;
+	als_exit(pdev);
+	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
+}
+
+static struct platform_driver hid_als_platform_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= hid_als_probe,
+	.remove		= hid_als_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init hid_als_init(void)
+{
+	return platform_driver_register(&hid_als_platform_driver);
+}
+
+static void __exit hid_als_exit(void)
+{
+	platform_driver_unregister(&hid_als_platform_driver);
+}
+
+module_init(hid_als_init);
+module_exit(hid_als_exit);
+
+MODULE_DESCRIPTION("HID Sensor ALS");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH 5/8] HID-Sensors: Added accelerometer 3D
  2012-07-04 19:52     ` srinivas pandruvada
@ 2012-07-04 21:27         ` David Herrmann
  -1 siblings, 0 replies; 27+ messages in thread
From: David Herrmann @ 2012-07-04 21:27 UTC (permalink / raw)
  To: srinivas pandruvada
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw

Hi Srinivas

On Wed, Jul 4, 2012 at 9:52 PM, srinivas pandruvada
<srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> wrote:
> Added usage id processing for Accelerometer 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 <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/staging/iio/accel/Kconfig               |   10 +
>  drivers/staging/iio/accel/Makefile              |    3 +
>  drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 +++++++++++++++++++++++
>  3 files changed, 464 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
>
> diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
> index 5ab7167..6ab1efa 100644
> --- a/drivers/staging/iio/accel/Kconfig
> +++ b/drivers/staging/iio/accel/Kconfig
> @@ -102,4 +102,14 @@ config SCA3000
>           Say yes here to build support for the VTI SCA3000 series of SPI
>           accelerometers. These devices use a hardware ring buffer.
>
> +config HID_SENSOR_ACCEL_3D
> +       depends on HID_SENSOR_HUB
> +       select IIO_BUFFER
> +       select IIO_TRIGGERED_BUFFER
> +       select HID_SENSOR_IIO_COMMON
> +       tristate "HID Acelerometers 3D"
> +       help
> +         Say yes here to build support for the HID SENSOR
> +         accelerometers 3G.

Maybe it's just me missing something, but why do all the Kconfig
entries mention "3G" instead of "3D"? I couldn't find any other place
where "3G" is used, only lots of "3D". What does 3G stand for?

Or maybe I just didn't pay enough attention.. ;)
Regards
David

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 5/8] HID-Sensors: Added accelerometer 3D
@ 2012-07-04 21:27         ` David Herrmann
  0 siblings, 0 replies; 27+ messages in thread
From: David Herrmann @ 2012-07-04 21:27 UTC (permalink / raw)
  To: srinivas pandruvada; +Cc: linux-iio, linux-input, jkosina, lars, jic23

Hi Srinivas

On Wed, Jul 4, 2012 at 9:52 PM, srinivas pandruvada
<srinivas.pandruvada@intel.com> wrote:
> Added usage id processing for Accelerometer 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 <srinivas.pandruvada@intel.com>
> ---
>  drivers/staging/iio/accel/Kconfig               |   10 +
>  drivers/staging/iio/accel/Makefile              |    3 +
>  drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 +++++++++++++++++++++++
>  3 files changed, 464 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
>
> diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
> index 5ab7167..6ab1efa 100644
> --- a/drivers/staging/iio/accel/Kconfig
> +++ b/drivers/staging/iio/accel/Kconfig
> @@ -102,4 +102,14 @@ config SCA3000
>           Say yes here to build support for the VTI SCA3000 series of SPI
>           accelerometers. These devices use a hardware ring buffer.
>
> +config HID_SENSOR_ACCEL_3D
> +       depends on HID_SENSOR_HUB
> +       select IIO_BUFFER
> +       select IIO_TRIGGERED_BUFFER
> +       select HID_SENSOR_IIO_COMMON
> +       tristate "HID Acelerometers 3D"
> +       help
> +         Say yes here to build support for the HID SENSOR
> +         accelerometers 3G.

Maybe it's just me missing something, but why do all the Kconfig
entries mention "3G" instead of "3D"? I couldn't find any other place
where "3G" is used, only lots of "3D". What does 3G stand for?

Or maybe I just didn't pay enough attention.. ;)
Regards
David

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 1/8] HID-Sensors: Documentation
  2012-07-04 19:52 ` [PATCH 1/8] HID-Sensors: Documentation srinivas pandruvada
@ 2012-07-05  0:56       ` Peter Meerwald
  0 siblings, 0 replies; 27+ messages in thread
From: Peter Meerwald @ 2012-07-05  0:56 UTC (permalink / raw)
  To: srinivas pandruvada
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw


nitpicking below

> Added a summary of HID sensor framework.
> 
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  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
is a HID device
> +a report descriptor confirming to HID 1.12 sensor usage tables.
conforming
> +
> +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
thereby
> +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
maybe a comma after fields?
> +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
sets
> +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.
accelerometer-3D 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.
Also it provides parsing functions which get and set eaach 
input/feature/output report. ??
> +
> +Individual sensor processing part (sensor drivers)
> +-----------
> +The processing driver will use interface provided by core driver to parse
an interface provided by the core driver
> +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
fields
> +	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
it exists it will
> +so that that field can be set or get individually.
so that fields
> +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.
> 

-- 

Peter Meerwald
+43-664-2444418 (mobile)

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 1/8] HID-Sensors: Documentation
@ 2012-07-05  0:56       ` Peter Meerwald
  0 siblings, 0 replies; 27+ messages in thread
From: Peter Meerwald @ 2012-07-05  0:56 UTC (permalink / raw)
  To: srinivas pandruvada; +Cc: linux-iio, linux-input, jkosina, lars, jic23


nitpicking below

> Added a summary of HID sensor framework.
> 
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
> ---
>  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
is a HID device
> +a report descriptor confirming to HID 1.12 sensor usage tables.
conforming
> +
> +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
thereby
> +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
maybe a comma after fields?
> +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
sets
> +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.
accelerometer-3D 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.
Also it provides parsing functions which get and set eaach 
input/feature/output report. ??
> +
> +Individual sensor processing part (sensor drivers)
> +-----------
> +The processing driver will use interface provided by core driver to parse
an interface provided by the core driver
> +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
fields
> +	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
it exists it will
> +so that that field can be set or get individually.
so that fields
> +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.
> 

-- 

Peter Meerwald
+43-664-2444418 (mobile)

^ permalink raw reply	[flat|nested] 27+ messages in thread

* RE: [PATCH 5/8] HID-Sensors: Added accelerometer 3D
  2012-07-04 21:27         ` David Herrmann
@ 2012-07-05 15:32             ` Pandruvada, Srinivas
  -1 siblings, 0 replies; 27+ messages in thread
From: Pandruvada, Srinivas @ 2012-07-05 15:32 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw

Hi David,

It is a typo. There are three places in Kconfig Help, "3G" is typed instead of "3D". I will correct this.

Thanks,
Srinivas

-----Original Message-----
From: linux-iio-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org [mailto:linux-iio-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org] On Behalf Of David Herrmann
Sent: Wednesday, July 04, 2012 2:28 PM
To: Pandruvada, Srinivas
Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; jkosina-AlSwsSmVLrQ@public.gmane.org; lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org; jic23-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org
Subject: Re: [PATCH 5/8] HID-Sensors: Added accelerometer 3D

Hi Srinivas

On Wed, Jul 4, 2012 at 9:52 PM, srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org> wrote:
> Added usage id processing for Accelerometer 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 <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/staging/iio/accel/Kconfig               |   10 +
>  drivers/staging/iio/accel/Makefile              |    3 +
>  drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 
> +++++++++++++++++++++++
>  3 files changed, 464 insertions(+), 0 deletions(-)  create mode 
> 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
>
> diff --git a/drivers/staging/iio/accel/Kconfig 
> b/drivers/staging/iio/accel/Kconfig
> index 5ab7167..6ab1efa 100644
> --- a/drivers/staging/iio/accel/Kconfig
> +++ b/drivers/staging/iio/accel/Kconfig
> @@ -102,4 +102,14 @@ config SCA3000
>           Say yes here to build support for the VTI SCA3000 series of SPI
>           accelerometers. These devices use a hardware ring buffer.
>
> +config HID_SENSOR_ACCEL_3D
> +       depends on HID_SENSOR_HUB
> +       select IIO_BUFFER
> +       select IIO_TRIGGERED_BUFFER
> +       select HID_SENSOR_IIO_COMMON
> +       tristate "HID Acelerometers 3D"
> +       help
> +         Say yes here to build support for the HID SENSOR
> +         accelerometers 3G.

Maybe it's just me missing something, but why do all the Kconfig entries mention "3G" instead of "3D"? I couldn't find any other place where "3G" is used, only lots of "3D". What does 3G stand for?

Or maybe I just didn't pay enough attention.. ;) Regards David
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* RE: [PATCH 5/8] HID-Sensors: Added accelerometer 3D
@ 2012-07-05 15:32             ` Pandruvada, Srinivas
  0 siblings, 0 replies; 27+ messages in thread
From: Pandruvada, Srinivas @ 2012-07-05 15:32 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-iio, linux-input, jkosina, lars, jic23

Hi David,

It is a typo. There are three places in Kconfig Help, "3G" is typed instead=
 of "3D". I will correct this.

Thanks,
Srinivas

-----Original Message-----
From: linux-iio-owner@vger.kernel.org [mailto:linux-iio-owner@vger.kernel.o=
rg] On Behalf Of David Herrmann
Sent: Wednesday, July 04, 2012 2:28 PM
To: Pandruvada, Srinivas
Cc: linux-iio@vger.kernel.org; linux-input@vger.kernel.org; jkosina@suse.cz=
; lars@metafoo.de; jic23@cam.ac.uk
Subject: Re: [PATCH 5/8] HID-Sensors: Added accelerometer 3D

Hi Srinivas

On Wed, Jul 4, 2012 at 9:52 PM, srinivas pandruvada <srinivas.pandruvada@in=
tel.com> wrote:
> Added usage id processing for Accelerometer 3D.This uses IIO=20
> interfaces for triggerred buffer to present data to user mode.This=20
> uses HID sensor framework for registering callback events from the=20
> sensor hub.
>
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
> ---
>  drivers/staging/iio/accel/Kconfig               |   10 +
>  drivers/staging/iio/accel/Makefile              |    3 +
>  drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451=20
> +++++++++++++++++++++++
>  3 files changed, 464 insertions(+), 0 deletions(-)  create mode=20
> 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
>
> diff --git a/drivers/staging/iio/accel/Kconfig=20
> b/drivers/staging/iio/accel/Kconfig
> index 5ab7167..6ab1efa 100644
> --- a/drivers/staging/iio/accel/Kconfig
> +++ b/drivers/staging/iio/accel/Kconfig
> @@ -102,4 +102,14 @@ config SCA3000
>           Say yes here to build support for the VTI SCA3000 series of SPI
>           accelerometers. These devices use a hardware ring buffer.
>
> +config HID_SENSOR_ACCEL_3D
> +       depends on HID_SENSOR_HUB
> +       select IIO_BUFFER
> +       select IIO_TRIGGERED_BUFFER
> +       select HID_SENSOR_IIO_COMMON
> +       tristate "HID Acelerometers 3D"
> +       help
> +         Say yes here to build support for the HID SENSOR
> +         accelerometers 3G.

Maybe it's just me missing something, but why do all the Kconfig entries me=
ntion "3G" instead of "3D"? I couldn't find any other place where "3G" is u=
sed, only lots of "3D". What does 3G stand for?

Or maybe I just didn't pay enough attention.. ;) Regards David
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the=
 body of a message to majordomo@vger.kernel.org More majordomo info at  htt=
p://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 1/8] HID-Sensors: Documentation
  2012-07-04 19:52 ` [PATCH 1/8] HID-Sensors: Documentation srinivas pandruvada
@ 2012-07-08 17:11       ` Jonathan Cameron
  0 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 17:11 UTC (permalink / raw)
  To: srinivas pandruvada
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> Added a summary of HID sensor framework.
> 
A nice description.  One additional nitpick (I think) on top of Peters.
(and mine really is a nitpick ;)
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  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);
> +
nitpick. Inconsistent blank lines (2 here, 1 in other similar loations).
> +
> +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.
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 1/8] HID-Sensors: Documentation
@ 2012-07-08 17:11       ` Jonathan Cameron
  0 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 17:11 UTC (permalink / raw)
  To: srinivas pandruvada; +Cc: linux-iio, linux-input, jkosina, lars, jic23

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> Added a summary of HID sensor framework.
> 
A nice description.  One additional nitpick (I think) on top of Peters.
(and mine really is a nitpick ;)
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
> ---
>  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);
> +
nitpick. Inconsistent blank lines (2 here, 1 in other similar loations).
> +
> +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.
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 3/8] HID-Sensors: Sensor framework
  2012-07-04 19:52     ` srinivas pandruvada
  (?)
@ 2012-07-08 18:05     ` Jonathan Cameron
  -1 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 18:05 UTC (permalink / raw)
  To: srinivas pandruvada; +Cc: linux-iio, linux-input, jkosina, lars, jic23

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> Adding processing for HID Sensor usage table as defined by
> HID 1.12, Request #: HUTRR39, dated 05 May, 2011.
> This driver uses HID driver framework to register, send and
> receive events.
> This uses MFD framework, so that actual processing for a
> specific usage id can be done in a different driver. For
> example an accelerometer driver can be a separate driver and
> use the interface provided by this driver to register for
> events.
> 
Generally looks pretty good to me.

Various comments inline.
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
> ---
>  drivers/hid/Kconfig            |   12 +
>  drivers/hid/Makefile           |    1 +
>  drivers/hid/hid-sensor-hub.c   |  630 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/hid-sensor-hub.h |   72 +++++
>  include/linux/hid-sensor-ids.h |  116 ++++++++
>  5 files changed, 831 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/hid/hid-sensor-hub.c
>  create mode 100644 include/linux/hid-sensor-hub.h
>  create mode 100644 include/linux/hid-sensor-ids.h
> 
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 034c80a..1d0d42d 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -660,6 +660,18 @@ config HID_ZYDACRON
>  	---help---
>  	Support for Zydacron remote control.
>  
> +config HID_SENSOR_HUB
> +	tristate "HID Sensors framework support"
> +	depends on USB_HID
> +	select MFD_CORE
> +	default n
> +	-- help---
> +	  Support for HID Sensor framework. This will provide MFD framework for
> +	  adding different sensors, using HID sensor usage table. This defines
> +	  a set of interface functions to register callbacks for events so
> +	  that the events are transferred to user space using either input
> +	  or IIO ineterfaces.
Perhaps make it more explicit that there will be one MFD instance per
'sensor hub / usb device', off which will hang multiple drivers to handle
the different data streams.
> +
>  endmenu
>  
>  endif # HID_SUPPORT
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index ca6cc9f..08f9d8f 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -87,6 +87,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
>  obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
>  obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
>  obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
> +obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
>  
>  obj-$(CONFIG_USB_HID)		+= usbhid/
>  obj-$(CONFIG_USB_MOUSE)		+= usbhid/
> diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
> new file mode 100644
> index 0000000..4e2c021
> --- /dev/null
> +++ b/drivers/hid/hid-sensor-hub.c
> @@ -0,0 +1,630 @@
> +/*
> + * 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/hid.h>
> +#include <linux/usb.h>
> +#include "usbhid/usbhid.h"
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/mfd/core.h>
> +#include <linux/list.h>
> +#include <linux/hid-sensor-ids.h>
> +#include <linux/hid-sensor-hub.h>
> +
> +#include "hid-ids.h"
> +
Having had the error of my own ways pointed out many times
I'm anti any arbitary size restrictions like this.
> +#define MAX_HUB_SENSORS	20
To avoid this one I guess the easiest option is to use a list.

> +#define MAX_DRIVER_NAME_SIZE 30
use kasprintf and this is irrelevant unless higher layers care,
but if they do then they should provide this constraint.

> +#define RAW_BUFFER_SIZE	128
Might not be worth making this one flexible...  Is it defined
by the spec, or is it just bigger than anything you've seen yet?

> +#define sensor_hub_in_report(id, dev) sensor_hub_report(id, dev,\
> +							HID_INPUT_REPORT)
I'd break these lines differently for length
#define sensor_hub_in_report(id, dev) \
	sensor_hub_report(id, dev, HID_INPUT_REPORT);
Actually do they add any real value anyway?  I guess it depends on how
often they get used...

> +#define sensor_hub_out_report(id, dev) sensor_hub_report(id, dev,\
> +							HID_OUTPUT_REPORT)
> +#define sensor_hub_feature_report(id, dev) sensor_hub_report(id, dev,\
> +							HID_FEATURE_REPORT)
> +
> +/* Description of in-progress IO operation, used for operations
> + * that trigger response from device */
> +struct sensor_hub_pending {
> +	struct completion ready;
> +	u32 usage_id;
> +	u32 attr_usage_id;
> +	int raw_size;
> +	u8 raw_data[RAW_BUFFER_SIZE];
> +};
> +
I would like to see kerneldoc for this structure. It's
not immediately obvious what they various locks etc are
for, hence documentation here would be good.
> +struct sensor_hub_data {
> +	struct hid_sensor_hub_device *hsdev;
> +	struct mutex mutex;
> +	spinlock_t lock;
> +	struct sensor_hub_pending *pending;
Given there is only (I think) one request ever in flight, would
it be simpler to just embed pending here directly and avoid
the dynamic allocation on each request?

I'm not sure either way on this one.
> +	struct list_head dyn_callback_list;
> +	spinlock_t dyn_lock;
> +	struct mfd_cell hid_sensor_hub_client_devs[MAX_HUB_SENSORS];
> +	int hid_sensor_client_cnt;
> +};
> +
Perhaps document that this corresponds to the interface to a child
of the mfd?
> +struct hid_sensor_hub_callbacks_list {
> +	struct list_head list;
> +	u32 usage_id;
> +	struct hid_sensor_hub_callbacks *usage_callback;

Looking so far only at this patch I'm not entirely sure when
intialized gets set.  Definitely could do with some documentation.
> +	int initialized;
> +	void *priv;
> +};
> +
> +static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
> +{
> +	int i;
> +	int ret = -EINVAL;
> +
> +	for (i = 0; i < hdev->maxcollection; i++) {
> +		struct hid_collection *col = &hdev->collection[i];
> +		if (col->type == HID_COLLECTION_PHYSICAL &&
> +		   (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
> +			ret = 0;
> +			break;
> +		}
> +	}
blank line before the return. (It's Sunday evening, I'm allowed to be
petty;)
> +	return ret;
> +}
> +
> +static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
> +						int dir)
> +{
> +	struct list_head *feature_report_list =
> +					&hdev->report_enum[dir].report_list;
Only used in one place, I'd just use it directly there.
     list_for_each_entry(report, &hdev->report_enum[dir].report_list,
			 list) {
}


> +	struct hid_report *report = NULL;
why set it to NULL?
> +
> +	list_for_each_entry(report, feature_report_list, list) {
> +		if (report->id == id)
> +			return report;
> +	}
> +	hid_warn(hdev, "No report with id 0x%x found\n", id);
convention puts a blank line here.
> +	return NULL;
> +}
> +
> +static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
> +					struct hid_device *hdev,
> +					u32 usage_id, void **priv)
> +{
> +	struct hid_sensor_hub_callbacks_list *callback = NULL;
Why set to NULL? (don't think I'm missing a reason for it)
> +	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
> +
> +
one blank line only please.
> +	spin_lock(&pdata->dyn_lock);
> +	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
> +		if (callback->usage_id == usage_id) {
> +			*priv = callback->priv;
> +			spin_unlock(&pdata->dyn_lock);
> +			return callback->usage_callback;
> +		}
> +	spin_unlock(&pdata->dyn_lock);
blank line here please and everywhere similar.
> +	return NULL;
> +}
> +
> +int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
> +			u32 usage_id,
> +			struct hid_sensor_hub_callbacks *usage_callback)
> +{
> +	struct hid_sensor_hub_callbacks_list *callback;
> +	struct sensor_hub_data *pdata =
> +		(struct sensor_hub_data *)hid_get_drvdata(hsdev->hdev);
Don't need type cast from a void *
> +
> +	spin_lock(&pdata->dyn_lock);
> +	list_for_each_entry(callback, &pdata->dyn_callback_list, list)
> +		if (callback->usage_id == usage_id) {
> +			spin_unlock(&pdata->dyn_lock);
> +			return -EINVAL;
> +		}
> +	callback = kzalloc(sizeof(*callback), GFP_KERNEL);
> +	if (!callback) {
> +		spin_unlock(&pdata->dyn_lock);
> +		return -ENOMEM;
> +	}
> +	callback->usage_callback = usage_callback;
> +	callback->usage_id = usage_id;
> +	callback->priv = NULL;
> +	list_add_tail(&callback->list, &pdata->dyn_callback_list);
> +	spin_unlock(&pdata->dyn_lock);
blank line.
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(sensor_hub_register_callback);
> +
> +int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
> +				u32 usage_id)
> +{
> +	struct hid_sensor_hub_callbacks_list *callback, *n;
> +	struct sensor_hub_data *pdata =
> +		(struct sensor_hub_data *)hid_get_drvdata(hsdev->hdev);
> +
> +	spin_lock(&pdata->dyn_lock);
you don't need the safe for as you aren't carrying on after deletion
(which is where the list will get messed up otherwise.)
> +	list_for_each_entry_safe(callback, n,
> +				&pdata->dyn_callback_list, list)
> +		if (callback->usage_id == usage_id) {
> +			list_del(&callback->list);
> +			kfree(callback);
> +			break;
> +		}
> +	spin_unlock(&pdata->dyn_lock);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
> +
> +int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> +				u32 field_index, s32 value)
> +{
> +	struct hid_report *report;
> +	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
> +	int ret = 0;
> +
> +	if (report_id < 0)
> +		return -EINVAL;
> +
> +	mutex_lock(&data->mutex);
> +	report = sensor_hub_feature_report(report_id, hsdev->hdev);

hmm. Two error conditions with the same path?
if (!report || (field_index >= report->maxfield))
> +	if (!report) {
> +		ret = -EINVAL;
> +		goto done_proc;
> +	}
> +	if (field_index >=  report->maxfield) {
> +		ret = -EINVAL;
> +		goto done_proc;
> +	}
> +	hid_set_field(report->field[field_index], 0, value);
> +	usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
> +	usbhid_wait_io(hsdev->hdev);
> +done_proc:
> +	mutex_unlock(&data->mutex);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
> +
> +int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> +				u32 field_index, s32 *value)
> +{
> +	struct hid_report *report;
> +	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
> +	int ret = 0;
> +
> +	if (report_id < 0)
> +		return -EINVAL;
> +
> +	mutex_lock(&data->mutex);
> +	report = sensor_hub_feature_report(report_id, hsdev->hdev);
same as above.
> +	if (!report) {
> +		ret = -EINVAL;
> +		goto done_proc;
> +	}
> +	if (field_index >=  report->maxfield) {
> +		ret = -EINVAL;
> +		goto done_proc;
> +	}
> +	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
> +	usbhid_wait_io(hsdev->hdev);
> +	*value = report->field[field_index]->value[0];
> +done_proc:
> +	mutex_unlock(&data->mutex);
one of many blank lines convention would put in before return statements..
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
> +
only one blank line here please.
> +
> +int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
> +					u32 usage_id,
> +					u32 attr_usage_id, u32 report_id)
> +{
> +	struct sensor_hub_data *data =  hid_get_drvdata(hsdev->hdev);
> +	struct sensor_hub_pending *work;
Now I'm not remotely familiar with usb cacheline requirements etc, but
could you just have..

struct sensor_hub_pending work = {
       .usage_id = usage_id,
       .attr_usage_id = attr_usage_id,
       .raw_size = 0,
};

given this function both creates and frees the structure...
(whatever else goes on inbetween).

As mentioned elsewhere I can't immediately see why you don't
just embed this in sensor_hub_data and avoid the allocation
entirely.

> +	unsigned long flags;
> +	struct hid_report *report;
> +	int ret_val = 0;
> +
> +	if (report_id < 0)
> +		return -EINVAL;
> +
> +	work = kzalloc(sizeof(*work), GFP_KERNEL);
> +	if (!work)
> +		return ret_val;
> +
> +	init_completion(&work->ready);
> +	work->usage_id = usage_id;
> +	work->attr_usage_id = attr_usage_id;
> +	work->raw_size = 0;
> +
> +	mutex_lock(&data->mutex);
> +	spin_lock_irqsave(&data->lock, flags);
> +	data->pending = work;
> +	report = sensor_hub_in_report(report_id, hsdev->hdev);
> +	if (!report)
> +		goto err_free;
> +	usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
> +	spin_unlock_irqrestore(&data->lock, flags);
> +	wait_for_completion_interruptible_timeout(&work->ready, HZ*5);
> +	if (work->raw_size)
> +		ret_val = *(u32 *)work->raw_data;
> +
> +err_free:
> +	data->pending = NULL;
> +	mutex_unlock(&data->mutex);
> +
> +	kfree(work);
> +	return ret_val;
> +}
> +EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
> +
> +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)
> +{
> +	int ret = -1;
> +	int i, j;
> +	int collection_index = -1;
> +	struct hid_report *report;
> +	struct hid_field *field;
> +	struct hid_report_enum *report_enum;
> +	struct hid_device *hdev = hsdev->hdev;
> +
> +	/* Initialize with defaults */
> +	info->usage_id = usage_id;
> +	info->attrib_id =  attr_usage_id;
> +	info->report_id = -1;
> +	info->index = -1;
> +	info->units = -1;
> +	info->unit_expo = -1;
> +
> +	for (i = 0; i < hdev->maxcollection; ++i) {
  	       why the temporary variable?
> +		struct hid_collection *collection = &hdev->collection[i];
> +		if (usage_id == collection->usage) {
> +			collection_index = i;
> +			break;
> +		}
> +	}
> +	if (collection_index == -1)
> +		goto err_ret;
> +
> +	report_enum = &hdev->report_enum[type];
> +	list_for_each_entry(report, &report_enum->report_list, list) {
> +		for (i = 0; i < report->maxfield; ++i) {
> +			field = report->field[i];
> +			if (field->physical == usage_id &&
> +				field->logical == attr_usage_id) {
> +				info->index = i;
> +				info->report_id = report->id;
> +				info->units = field->unit;
> +				info->unit_expo = field->unit_exponent;
> +				info->size = field->report_size/8;
> +				ret = 0;
> +			} else {
Perhaps add a few util functions to avoid the massive indentation?
> +				for (j = 0; j < field->maxusage; ++j) {
> +					if (field->usage[j].hid ==
> +					attr_usage_id &&
> +					field->usage[j].collection_index ==
> +					collection_index)  {
> +						info->index = i;
> +						info->report_id = report->id;
> +						info->units = field->unit;
> +						info->unit_expo =
> +							field->unit_exponent;
> +						info->size =
> +							field->report_size/8;
> +						ret = 0;
> +						break;
> +					}
> +				}
> +			}
> +			if (ret == 0)
> +				break;
> +		}
> +	}
> +err_ret:
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
> +
> +#ifdef CONFIG_PM
> +static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
> +{
> +	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
> +	struct hid_sensor_hub_callbacks_list *callback;
> +
> +	hid_dbg(hdev, " sensor_hub_suspend\n");
> +	spin_lock(&pdata->dyn_lock);
> +	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
> +		if (callback->initialized && callback->usage_callback->suspend)
> +			callback->usage_callback->suspend(
> +					pdata->hsdev, callback->priv);
> +	}
> +	spin_unlock(&pdata->dyn_lock);
> +	return 0;
> +}
> +
> +static int sensor_hub_resume(struct hid_device *hdev)
> +{
> +	struct sensor_hub_data *pdata =  hid_get_drvdata(hdev);
> +	struct hid_sensor_hub_callbacks_list *callback;
> +
> +	hid_dbg(hdev, " sensor_hub_resume\n");
> +	spin_lock(&pdata->dyn_lock);
> +	list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
> +		if (callback->initialized && callback->usage_callback->resume)
> +			callback->usage_callback->resume(
> +					pdata->hsdev, callback->priv);
> +	}
> +	spin_unlock(&pdata->dyn_lock);
> +	return 0;
> +}
> +
> +static int sensor_hub_reset_resume(struct hid_device *hdev)
> +{
> +	return 0;
> +}
> +#endif
> +/*
> + * Handle raw report as sent by device
> + */
> +static int sensor_hub_raw_event(struct hid_device *hdev,
> +		struct hid_report *report, u8 *raw_data, int size)
> +{
> +	int i;
> +	u8 *ptr;
> +	int sz;
> +	struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
> +	unsigned long flags;
> +	struct hid_sensor_hub_callbacks *callback = NULL;
> +	struct hid_collection *collection = NULL;
> +	void *priv = NULL;
> +
> +	hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
> +			 report->id, size, report->type);
> +	hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
> +	if (report->type != HID_INPUT_REPORT)
> +		return 1;
> +
> +	ptr = raw_data;
> +	ptr++; /*Skip report id*/
> +
> +	if (!report)
> +		goto err_report;
> +
> +	spin_lock_irqsave(&pdata->lock, flags);
> +
> +	for (i = 0; i < report->maxfield; ++i) {
> +
> +		hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
> +				i, report->field[i]->usage->collection_index,
> +				report->field[i]->usage->hid,
> +				report->field[i]->report_size/8);
> +
> +		sz = report->field[i]->report_size/8;
> +		if (pdata->pending && pdata->pending->attr_usage_id ==
> +				report->field[i]->usage->hid) {
> +			hid_dbg(hdev, "data was pending ...\n");
> +			sz = (sz > RAW_BUFFER_SIZE) ? RAW_BUFFER_SIZE : sz;
> +			memcpy(pdata->pending->raw_data, ptr, sz);
> +			pdata->pending->raw_size  = sz;
> +			complete(&pdata->pending->ready);
> +		}
> +		collection = &hdev->collection[
> +				report->field[i]->usage->collection_index];
> +		hid_dbg(hdev, "collection->usage %x\n",
> +					collection->usage);
> +		callback = sensor_hub_get_callback(pdata->hsdev->hdev,
> +						report->field[i]->physical,
> +							&priv);
> +		if (callback && callback->capture_sample) {
> +			if (report->field[i]->logical)
> +				callback->capture_sample(pdata->hsdev,
> +					report->field[i]->logical, sz, ptr,
> +					callback->pdev);
> +			else
> +				callback->capture_sample(pdata->hsdev,
> +					report->field[i]->usage->hid, sz, ptr,
> +					callback->pdev);
> +		}
> +		ptr += sz;
> +	}
> +	if (callback && collection && callback->send_event)
> +		callback->send_event(pdata->hsdev, collection->usage,
> +				callback->pdev);
> +	spin_unlock_irqrestore(&pdata->lock, flags);
> +
> +err_report:
> +	return 1;
> +}
> +
> +static int sensor_hub_probe(struct hid_device *hdev,
> +				const struct hid_device_id *id)
> +{
> +	int ret;
> +	struct sensor_hub_data *sd;
> +	int i;
> +	char *name;
> +	struct hid_report *report;
> +	struct hid_report_enum *report_enum;
> +	struct hid_field *field;
> +
> +	sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
> +	if (!sd) {
> +		hid_err(hdev, "cannot allocate Sensor data\n");
> +		return -ENOMEM;
> +	}
> +	sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL);
> +	if (!sd->hsdev) {
> +		hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
> +		ret = -ENOMEM;
> +		goto err_free_hub;
> +	}
> +	hid_set_drvdata(hdev, sd);
> +	sd->hsdev->hdev = hdev;
> +	sd->hsdev->vendor_id = hdev->vendor;
> +	sd->hsdev->product_id = hdev->product;
> +	spin_lock_init(&sd->lock);
> +	spin_lock_init(&sd->dyn_lock);
> +	mutex_init(&sd->mutex);
> +	ret = hid_parse(hdev);
> +	if (ret) {
> +		hid_err(hdev, "parse failed\n");
> +		goto err_free;
> +	}
> +	if (sensor_hub_check_for_sensor_page(hdev) < 0) {
> +		hid_err(hdev, "sensor page not found\n");
> +		goto err_free;
> +	}
> +	INIT_LIST_HEAD(&hdev->inputs);
> +
> +	hdev->claimed = HID_CLAIMED_INPUT;
> +	ret = hid_hw_start(hdev, 0);
> +	if (ret) {
> +		hid_err(hdev, "hw start failed\n");
> +		goto err_free;
> +	}
> +	ret = hid_hw_open(hdev);
> +	if (ret) {
> +		hid_err(hdev, "failed to open input interrupt pipe\n");
> +		goto err_stop_hw;
> +	}
> +
> +	INIT_LIST_HEAD(&sd->dyn_callback_list);
> +	sd->hid_sensor_client_cnt = 0;
> +	report_enum = &hdev->report_enum[HID_INPUT_REPORT];
> +	list_for_each_entry(report, &report_enum->report_list, list) {
> +		hid_dbg(hdev, "Report id:%x\n", report->id);
> +		field = report->field[0];
> +		if (report->maxfield && field &&
> +					field->physical) {
> +			name = kmalloc(MAX_DRIVER_NAME_SIZE+1,
> +					GFP_KERNEL);
> +			if (name  == NULL) {
> +				hid_err(hdev,
> +					"Failed MFD device name\n");
> +					ret = -ENOMEM;
> +					goto err_close;
> +			}
> +			snprintf(name, MAX_DRIVER_NAME_SIZE,
> +					"HID-SENSOR-%x",
> +					field->physical);
kasprintf

> +			sd->hid_sensor_hub_client_devs[
> +				sd->hid_sensor_client_cnt].name = name;
> +			sd->hid_sensor_hub_client_devs[
> +				sd->hid_sensor_client_cnt].platform_data =
> +						&sd->hsdev;
> +			sd->hid_sensor_hub_client_devs[
> +				sd->hid_sensor_client_cnt].pdata_size =
> +						sizeof(sd->hsdev);
> +			hid_dbg(hdev, "Adding %s:%x\n", name,
> +					(unsigned int)sd);
> +			sd->hid_sensor_client_cnt++;
> +		}
> +	}
> +	ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
> +		sd->hid_sensor_client_cnt, NULL, 0);
> +	if (ret < 0) {
would rather see this under an additional goto than here.
> +		for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
> +			kfree(sd->hid_sensor_hub_client_devs[i].name);
> +		goto err_close;
> +	}
> +
> +	return ret;
> +
> +err_close:
> +	hid_hw_stop(hdev);
> +	hid_hw_close(hdev);
> +err_stop_hw:
> +	hid_hw_stop(hdev);
> +err_free:
> +	kfree(sd->hsdev);
> +err_free_hub:
> +	kfree(sd);
> +
> +	return ret;
> +}
> +
> +static void sensor_hub_remove(struct hid_device *hdev)
> +{
> +	struct sensor_hub_data *data = hid_get_drvdata(hdev);
> +	unsigned long flags;
> +	int i;
> +
> +	hid_dbg(hdev, " hardware removed\n");
> +	hdev->claimed &= ~HID_CLAIMED_INPUT;
> +	hid_hw_stop(hdev);
> +	hid_hw_close(hdev);
> +	spin_lock_irqsave(&data->lock, flags);
> +	if (data->pending)
> +		complete(&data->pending->ready);
> +	spin_unlock_irqrestore(&data->lock, flags);
> +	mfd_remove_devices(&hdev->dev);
> +	for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
> +		kfree(data->hid_sensor_hub_client_devs[i].name);
> +	hid_set_drvdata(hdev, NULL);
> +	mutex_destroy(&data->mutex);
> +	kfree(data->hsdev);
> +	kfree(data);
> +}
> +
> +static const struct hid_device_id sensor_hub_devices[] = {
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
> +			USB_DEVICE_ID_SENSOR_HUB_1020) },
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
> +			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_09FA) },
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
> +			USB_DEVICE_ID_SENSOR_HUB_7014) },
> +	{ }
> +};
> +
> +static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
> +	{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
> +	{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
> +};
> +
> +static struct hid_driver sensor_hub_driver = {
> +	.name = "hid-sensor-hub",
> +	.id_table = sensor_hub_devices,
> +	.probe = sensor_hub_probe,
> +	.remove = sensor_hub_remove,
> +	.raw_event = sensor_hub_raw_event,
> +#ifdef CONFIG_PM
> +	.suspend = sensor_hub_suspend,
> +	.resume =  sensor_hub_resume,
> +	.reset_resume =  sensor_hub_reset_resume,
> +#endif
> +};
> +
> +static int __init sensor_hub_init(void)
> +{
> +	return hid_register_driver(&sensor_hub_driver);
> +}
> +
> +static void __exit sensor_hub_exit(void)
> +{
> +	hid_unregister_driver(&sensor_hub_driver);
> +}
> +
Hid looks in need of a variant on module_i2c_driver etc.

> +module_init(sensor_hub_init);
> +module_exit(sensor_hub_exit);
> +
> +MODULE_DESCRIPTION("HID Sensor Hub driver");
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
> new file mode 100644
> index 0000000..b63fe85
> --- /dev/null
> +++ b/include/linux/hid-sensor-hub.h
> @@ -0,0 +1,72 @@
> +/*
> + * 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_HUB_H
> +#define _HID_SENSORS_HUB_H
> +
> +#include <linux/hid.h>
> +#include <linux/hid-sensor-ids.h>
> +
kernel-doc for all these structures please.
Actually whole file could do with more docs.

> +struct hid_sensor_hub_attribute_info {
> +	u32 usage_id;
> +	u32 attrib_id;
> +	s32 report_id;
> +	s32 index;
> +	s32 units;
> +	s32 unit_expo;
> +	s32 size;
> +};
> +
> +struct hid_sensor_hub_device {
> +	struct hid_device *hdev;
> +	u32 vendor_id;
> +	u32 product_id;
> +};
> +
one blank line only probably.
> +
> +struct hid_sensor_hub_callbacks {
> +	struct platform_device *pdev;
> +	int (*suspend)(struct hid_sensor_hub_device *hsdev, void *priv);
> +	int (*resume)(struct hid_sensor_hub_device *hsdev, void *priv);
> +	int (*capture_sample)(struct hid_sensor_hub_device *hsdev,
> +			u32 usage_id, size_t raw_len, char *raw_data,
> +			void *priv);
> +	int (*send_event)(struct hid_sensor_hub_device *hsdev, u32 usage_id,
> +			 void *priv);
> +};
> +
> +/* Registeration functions */
> +int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
> +			u32 usage_id,
> +			struct hid_sensor_hub_callbacks *usage_callback);
> +int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
> +			u32 usage_id);
> +
> +/* Hid sensor hub core interfaces */
> +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);
> +int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
> +			u32 usage_id,
> +			u32 attr_usage_id, u32 report_id);
> +int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> +			u32 field_index, s32 value);
> +int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
> +			u32 field_index, s32 *value);
> +#endif
> diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
> new file mode 100644
> index 0000000..34cc779
> --- /dev/null
> +++ b/include/linux/hid-sensor-ids.h
> @@ -0,0 +1,116 @@
> +/*
> + * 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_IDS_H
> +#define _HID_SENSORS_IDS_H
> +
Some of these defines are really really long.  I'd normally
be in favour of nice clear naming, but these are going to
get really unweildy.  Is there any clear structure to them?

i.e. can we build them up from smaller parts?

Otherwise, obvious abreivations such as ORIENTATION -> ORIENT and
ANGULAR_VELOCITY -> ANG_VEL shouldn't loose too much detail.

> +#define HID_UP_SENSOR		0x00200000
> +#define HID_SENSOR_POLLING      0x0020030E
> +#define HID_SENSOR_REPORT_STATE 0x00200316
> +#define HID_SENSOR_POWER_STATE  0x00200319
> +
> +
> +/* Accel 3D (200073) */
> +#define HID_USAGE_SENSOR_ACCEL_3D				0x200073
> +#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS	0x200453
> +#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS	0x200454
> +#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS	0x200455
> +
> +/* ALS (200041) */
> +#define HID_USAGE_SENSOR_ALS				        0x200041
> +#define HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE			0x2004d1
> +
> +/* Compass 3D: (200083) */
> +
> +/* Gyro 3D: (200076) */
> +#define HID_USAGE_SENSOR_GYRO_3D				0x200076
> +#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS	0x200457
> +#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS	0x200458
> +#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS	0x200459
> +
> +/*ORIENTATION: Compass 3D: (200083) */
> +#define HID_USAGE_SENSOR_COMPASS_3D				0x200083
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING	0x200471
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_X	0x200472
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Y	0x200473
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Z	0x200474
> +
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_MAGNETIC_NORTH 0x200475
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_TRUE_NORTH 0x200476
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_NORTH	0x200477
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_TRUE_NORTH		0x200478
> +
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE		0x200479
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_X		0x20047A
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Y		0x20047B
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Z		0x20047C
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_OUT_OF_RANGE 0x20047D
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT			0x20047E
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_X		0x20047F
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Y		0x200480
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Z		0x200481
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_ROTATION_MATRIX	0x200482
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_QUATERNION		0x200483
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX		0x200484
> +
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS	0x200485
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS	0x200486
> +#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS	0x200487
> +
> +/* Units */
> +#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED			0x00
> +#define HID_USAGE_SENSOR_UNITS_LUX				0x01
> +#define HID_USAGE_SENSOR_UNITS_KELVIN				0x01000100
> +#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT			0x03000100
> +#define HID_USAGE_SENSOR_UNITS_PASCAL				0xF1E1
> +#define HID_USAGE_SENSOR_UNITS_NEWTON				0x11E1
> +#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND		0x11F0
> +#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD		0x11E0
> +#define HID_USAGE_SENSOR_UNITS_FARAD				0xE14F2000
> +#define HID_USAGE_SENSOR_UNITS_AMPERE				0x01001000
> +#define HID_USAGE_SENSOR_UNITS_WATT				0x21d1
> +#define HID_USAGE_SENSOR_UNITS_HENRY				0x21E1E000
> +#define HID_USAGE_SENSOR_UNITS_OHM				0x21D1E000
> +#define HID_USAGE_SENSOR_UNITS_VOLT				0x21D1F000
> +#define HID_USAGE_SENSOR_UNITS_HERTZ				0x01F0
> +#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD		0x14E0
> +#define HID_USAGE_SENSOR_UNITS_RADIANS				0x12
> +#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND		0x12F0
> +#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD		0x12E0
> +#define HID_USAGE_SENSOR_UNITS_SECOND				0x0110
> +#define HID_USAGE_SENSOR_UNITS_GAUSS				0x01E1F000
> +#define HID_USAGE_SENSOR_UNITS_GRAM				0x0101
> +#define HID_USAGE_SENSOR_UNITS_CENTIMETER			0x11
> +#define HID_USAGE_SENSOR_UNITS_G				0x1A
> +#define HID_USAGE_SENSOR_UNITS_MILLISECOND			0x19
> +#define HID_USAGE_SENSOR_UNITS_PERCENT				0x17
> +#define HID_USAGE_SENSOR_UNITS_DEGREES				0x14
> +#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND		0x15
> +
> +/* Common selectors */
> +#define HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL		0x20030E
> +#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS	0x20030F
> +#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_RANGE_PCT	0x200310
> +#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_REL_PCT	0x200311
> +#define HID_USAGE_SENSOR_PROPERTY_ACCURACY			0x200312
> +#define HID_USAGE_SENSOR_PROPERTY_RESOLUTION			0x200313
> +#define HID_USAGE_SENSOR_PROPERTY_RANGE_MAXIMUM			0x200314
> +#define HID_USAGE_SENSOR_PROPERTY_RANGE_MINIMUM			0x200315
> +#define HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE		0x200316
> +
> +#endif
> 



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 4/8] HID-Sensors: Common attribute and trigger
  2012-07-04 19:52     ` srinivas pandruvada
@ 2012-07-08 18:23         ` Jonathan Cameron
  -1 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 18:23 UTC (permalink / raw)
  To: srinivas pandruvada
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> This patch contains the common code, which is used by all HID sensors.
> There are some common set of attributes, which every hid sensor
> needs it. This patch contains all such attributes processing.
> Also the trigger interface is common among all HID sensors. This
> patch contains common trigger functions utilized by all HID sensors.
> 
This patch is rather less well cleaned up that the previous.

Main issue is with the data format for hysterisis.  Not a chance
what you have here will go in.  Please format it to a simple
xxxx.yyyy form.
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/staging/iio/Kconfig                        |    1 +
>  drivers/staging/iio/Makefile                       |    1 +
>  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 +++
>  10 files changed, 413 insertions(+), 0 deletions(-)
>  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
> 
> diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
> index 04cd6ec..7b058f4 100644
> --- a/drivers/staging/iio/Kconfig
> +++ b/drivers/staging/iio/Kconfig
> @@ -29,6 +29,7 @@ source "drivers/staging/iio/accel/Kconfig"
>  source "drivers/staging/iio/adc/Kconfig"
>  source "drivers/staging/iio/addac/Kconfig"
>  source "drivers/staging/iio/cdc/Kconfig"
> +source "drivers/staging/iio/common/Kconfig"
>  source "drivers/staging/iio/frequency/Kconfig"
>  source "drivers/staging/iio/gyro/Kconfig"
>  source "drivers/staging/iio/impedance-analyzer/Kconfig"
> diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
> index fa6937d..c7ca152 100644
> --- a/drivers/staging/iio/Makefile
> +++ b/drivers/staging/iio/Makefile
> @@ -17,6 +17,7 @@ obj-y += accel/
>  obj-y += adc/
>  obj-y += addac/
>  obj-y += cdc/
> +obj-y += common/
>  obj-y += frequency/
>  obj-y += gyro/
>  obj-y += impedance-analyzer/
> diff --git a/drivers/staging/iio/common/Kconfig b/drivers/staging/iio/common/Kconfig
> new file mode 100644
> index 0000000..bed569a
> --- /dev/null
> +++ b/drivers/staging/iio/common/Kconfig
> @@ -0,0 +1,6 @@
> +#
> +# IIO common modules
> +#
> +
> +source "drivers/staging/iio/common/hid-sensors/Kconfig"
> +
> diff --git a/drivers/staging/iio/common/Makefile b/drivers/staging/iio/common/Makefile
> new file mode 100644
> index 0000000..23852b6
> --- /dev/null
> +++ b/drivers/staging/iio/common/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the IIO common modules.
I'd be a bit more descriptive bit.

support modules required by various different device types? Something
like that.
> +#
> +
> +obj-y += hid-sensors/
> diff --git a/drivers/staging/iio/common/hid-sensors/Kconfig b/drivers/staging/iio/common/hid-sensors/Kconfig
> new file mode 100644
> index 0000000..da64fef
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/Kconfig
> @@ -0,0 +1,21 @@
> +#
> +# Hid Sensor common modules
> +#
> +menu "Hid Sensor IIO Common"
> +
> +config HID_SENSOR_IIO_COMMON
> +	tristate "Common modules for all HID Sensor IIO drivers"
> +	depends on HID_SENSOR_HUB
> +	select IIO_TRIGGER if IIO_BUFFER
> +	help
> +	  Say yes here to build support for HID sensor to use
> +	  HID sensor common processing for attributes and IIO triggers.
> +
> +config HID_SENSOR_ENUM_BASE_QUIRKS
> +	tristate "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.
No way of detecting that and loosing the config option?
> +
> +endmenu
> diff --git a/drivers/staging/iio/common/hid-sensors/Makefile b/drivers/staging/iio/common/hid-sensors/Makefile
> new file mode 100644
> index 0000000..1f463e0
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for the Hid sensor common modules.
> +#
> +
> +obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
> +hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
> new file mode 100644
> index 0000000..d39c93e
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
> @@ -0,0 +1,182 @@
> +/*
> + * 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/sysfs.h>
> +#include "hid-sensor-attributes.h"
> +
why?  Part of spec?
> +#define MAXIMUM_SAMP_FREQUENCY 1000
> +
> +ssize_t hid_sensor_read_samp_freq(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	s32 value;
> +	int len;
> +	int ret;
> +	int conv_value;
> +
> +	ret = sensor_hub_get_feature(st->hsdev,
> +			st->poll.report_id,
> +			st->poll.index, &value);
> +	if (ret < 0 || value <= 0)
> +		len = sprintf(buf, "0\n");
> +	else {
> +		if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
> +			conv_value = 1000/value;
Not going to be terribly accurate and we do allow decimal places
in the abi.
> +		else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
> +			conv_value = 1/value;
Given we are integer, what do you think that is likely to give?
> +		else
> +			conv_value = value; /*Assume HZ*/
> +		len = sprintf(buf, "%d\n", conv_value);
> +	}
> +	return len;
> +}
> +EXPORT_SYMBOL(hid_sensor_read_samp_freq);
> +
> +ssize_t hid_sensor_write_samp_freq(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	int value;
> +	int conv_value;
> +	int ret;
> +
> +	if (kstrtoint(buf, 10, &value) < 0)
> +		return -EINVAL;
> +
> +	if (value > MAXIMUM_SAMP_FREQUENCY)
> +		value = MAXIMUM_SAMP_FREQUENCY;
> +
> +	if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
> +		conv_value = 1000/value;
> +	else if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
> +		conv_value = 1/value;
> +	else
> +		conv_value = value; /*Assume HZ*/
> +
> +	ret = sensor_hub_set_feature(st->hsdev,
> +		st->poll.report_id,
> +		st->poll.index,
> +		conv_value);
> +
> +	if (ret < 0)
> +		return ret;
> +	return strlen(buf);
> +}
> +EXPORT_SYMBOL(hid_sensor_write_samp_freq);
> +
Hysterisis is common enough we should just add it to
the iio_chan_spec->info_mask and do it through the read_raw
callbacks.  Would you mind doing a patch to do that?
> +ssize_t hid_sensor_read_hyst_raw(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	s32 value;
> +	int len;
> +	int ret;
> +
> +	ret = sensor_hub_get_feature(st->hsdev,
> +		st->sensitivity.report_id,
> +		st->sensitivity.index, &value);
> +	if (ret < 0 || value < 0)
> +		len = sprintf(buf, "0\n");
> +	else
Not happy with this interface at all.

Scale out the units please to get to the relevant base unit.
e.g. accel is m/s^2   The exponents here are simple powers
of 10 I think?  Hence trivial to apply.   This should
be a simple decimal number.  There may be some arguement for
extending the buffered interface to handle the exponents, but
here we have a massive text buffer and it's a slow path
so lets just do it the simple way.

> +		len = sprintf(buf, "units:%d,exp:%d,value:%d\n",
> +				st->sensitivity.units,
> +				st->sensitivity.unit_expo, value);
> +	return len;
> +}
> +EXPORT_SYMBOL(hid_sensor_read_hyst_raw);
> +
> +ssize_t hid_sensor_write_hyst_raw(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	int value;
> +	int ret;
> +
> +	if (kstrtoint(buf, 10, &value) < 0)
> +		return -EINVAL;
> +
> +	if (value <= 0)
> +		value = 0;
> +	ret = sensor_hub_set_feature(st->hsdev,
> +		st->sensitivity.report_id,
> +		st->sensitivity.index,
> +		value);
This looks suspiciously like a magic number is needed.
Please do the relevant conversions to go from a floating point
string input to the right representation.
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return strlen(buf);
not return len;?
> +}
> +EXPORT_SYMBOL(hid_sensor_write_hyst_raw);
> +
> +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
> +					u32 usage_id,
> +					struct hid_sensor_attributes *st)
> +{
> +	int ret;
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +					HID_FEATURE_REPORT, usage_id,
> +					HID_SENSOR_POLLING, &st->poll);
> +
Do something with ret?  Otherwise why have it?
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +					HID_FEATURE_REPORT, usage_id,
> +					HID_SENSOR_REPORT_STATE,
> +					&st->report_state);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +					HID_FEATURE_REPORT, usage_id,
> +					HID_SENSOR_POWER_STATE,
> +					&st->power_state);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +			HID_FEATURE_REPORT, usage_id,
> +			HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS,
> +			 &st->sensitivity);
> +
> +	hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
> +			st->poll.index, st->poll.report_id,
> +			st->report_state.index, st->report_state.report_id,
> +			st->power_state.index, st->power_state.report_id,
> +			st->sensitivity.index, st->sensitivity.report_id);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
> +
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
> +MODULE_DESCRIPTION("HID Sensor common attribute processing");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
> new file mode 100644
> index 0000000..c859b7e
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
> @@ -0,0 +1,60 @@
> +/*
> + * 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
> +
> +/**
> + * IIO_DEV_ATTR_HYSTERESIS - sets hysterisis value
> + * @_mode: sysfs file mode/permissions
> + * @_show: output method for the attribute
> + * @_store: input method for the attribute
> + **/
> +#define IIO_DEV_ATTR_HYSTERESIS(_mode, _show, _store)        \
> +	IIO_DEVICE_ATTR(hyst_raw, _mode, _show, _store, 0)
> +
> +/* Common sysfs attributes for HID sensors */
> +struct hid_sensor_attributes {
> +	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;
> +	void *private;
> +};
> +
> +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
> +					u32 usage_id,
> +					struct hid_sensor_attributes *st);
> +ssize_t hid_sensor_read_hyst_raw(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf);
> +ssize_t hid_sensor_write_hyst_raw(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len);
> +ssize_t hid_sensor_read_samp_freq(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf);
> +ssize_t hid_sensor_write_samp_freq(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len);
> +
> +#endif
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
> new file mode 100644
> index 0000000..bef5560
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
> @@ -0,0 +1,104 @@
> +/*
> + * 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/trigger_consumer.h>
> +#include <linux/iio/trigger.h>
> +#include "hid-sensor-attributes.h"
> +
> +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
> +						bool state)
> +{
> +	struct iio_dev *indio_dev = trig->private_data;
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	int ret;
> +	int state_val;
> +
> +	dev_dbg(&indio_dev->dev, "hid_sensor_data_rdy_trigger_set_state %d\n",
> +			state);
> +	state_val = state ? 1 : 0;
  	bool is defined 0 or 1 with gcc.
> +#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
> +	(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
> +	hid_dbg(st->hsdev, " Using ENUM base FW QUIRKS\n");
> +	++state_val;
> +#endif
> +	st->data_ready = state;
> +	ret = sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
> +					st->power_state.index,
> +					(s32)state_val);
more unhandled return values.  Please clear these up everywhere.
> +
> +	ret = sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
> +					st->report_state.index,
> +					(s32)state_val);
> +	return ret;
> +}
> +
> +void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
> +{
> +	iio_trigger_unregister(indio_dev->trig);
> +	iio_trigger_free(indio_dev->trig);
> +}
> +EXPORT_SYMBOL(hid_sensor_remove_trigger);
> +
> +static const struct iio_trigger_ops hid_sensor_trigger_ops = {
> +	.owner = THIS_MODULE,
> +	.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
> +};
> +
> +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name)
> +{
> +	int ret;
> +	struct iio_trigger *trig;
> +
> +	trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
> +	if (trig == NULL) {
> +		dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
> +		ret = -ENOMEM;
> +		goto error_ret;
> +	}
> +
> +	trig->dev.parent = indio_dev->dev.parent;
> +	trig->private_data = (void *)indio_dev;
> +	trig->ops = &hid_sensor_trigger_ops;
> +	ret = iio_trigger_register(trig);
> +
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "Trigger Register Failed\n");
> +		goto error_free_trig;
> +	}
> +	indio_dev->trig = trig;
> +
> +	return ret;
> +
> +error_free_trig:
> +	iio_trigger_free(trig);
> +error_ret:
> +	return ret;
> +}
> +EXPORT_SYMBOL(hid_sensor_setup_trigger);
> +
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
> +MODULE_DESCRIPTION("HID Sensor trigger processing");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
> new file mode 100644
> index 0000000..9ff3d02
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
> @@ -0,0 +1,27 @@
> +/*
> + * 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_SENSOR_TRIGGER_H
> +#define _HID_SENSOR_TRIGGER_H
> +
one blank line is plenty
> +
> +
> +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
> +void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
> +
> +#endif
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 4/8] HID-Sensors: Common attribute and trigger
@ 2012-07-08 18:23         ` Jonathan Cameron
  0 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 18:23 UTC (permalink / raw)
  To: srinivas pandruvada; +Cc: linux-iio, linux-input, jkosina, lars, jic23

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> This patch contains the common code, which is used by all HID sensors.
> There are some common set of attributes, which every hid sensor
> needs it. This patch contains all such attributes processing.
> Also the trigger interface is common among all HID sensors. This
> patch contains common trigger functions utilized by all HID sensors.
> 
This patch is rather less well cleaned up that the previous.

Main issue is with the data format for hysterisis.  Not a chance
what you have here will go in.  Please format it to a simple
xxxx.yyyy form.
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
> ---
>  drivers/staging/iio/Kconfig                        |    1 +
>  drivers/staging/iio/Makefile                       |    1 +
>  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 +++
>  10 files changed, 413 insertions(+), 0 deletions(-)
>  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
> 
> diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
> index 04cd6ec..7b058f4 100644
> --- a/drivers/staging/iio/Kconfig
> +++ b/drivers/staging/iio/Kconfig
> @@ -29,6 +29,7 @@ source "drivers/staging/iio/accel/Kconfig"
>  source "drivers/staging/iio/adc/Kconfig"
>  source "drivers/staging/iio/addac/Kconfig"
>  source "drivers/staging/iio/cdc/Kconfig"
> +source "drivers/staging/iio/common/Kconfig"
>  source "drivers/staging/iio/frequency/Kconfig"
>  source "drivers/staging/iio/gyro/Kconfig"
>  source "drivers/staging/iio/impedance-analyzer/Kconfig"
> diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
> index fa6937d..c7ca152 100644
> --- a/drivers/staging/iio/Makefile
> +++ b/drivers/staging/iio/Makefile
> @@ -17,6 +17,7 @@ obj-y += accel/
>  obj-y += adc/
>  obj-y += addac/
>  obj-y += cdc/
> +obj-y += common/
>  obj-y += frequency/
>  obj-y += gyro/
>  obj-y += impedance-analyzer/
> diff --git a/drivers/staging/iio/common/Kconfig b/drivers/staging/iio/common/Kconfig
> new file mode 100644
> index 0000000..bed569a
> --- /dev/null
> +++ b/drivers/staging/iio/common/Kconfig
> @@ -0,0 +1,6 @@
> +#
> +# IIO common modules
> +#
> +
> +source "drivers/staging/iio/common/hid-sensors/Kconfig"
> +
> diff --git a/drivers/staging/iio/common/Makefile b/drivers/staging/iio/common/Makefile
> new file mode 100644
> index 0000000..23852b6
> --- /dev/null
> +++ b/drivers/staging/iio/common/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the IIO common modules.
I'd be a bit more descriptive bit.

support modules required by various different device types? Something
like that.
> +#
> +
> +obj-y += hid-sensors/
> diff --git a/drivers/staging/iio/common/hid-sensors/Kconfig b/drivers/staging/iio/common/hid-sensors/Kconfig
> new file mode 100644
> index 0000000..da64fef
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/Kconfig
> @@ -0,0 +1,21 @@
> +#
> +# Hid Sensor common modules
> +#
> +menu "Hid Sensor IIO Common"
> +
> +config HID_SENSOR_IIO_COMMON
> +	tristate "Common modules for all HID Sensor IIO drivers"
> +	depends on HID_SENSOR_HUB
> +	select IIO_TRIGGER if IIO_BUFFER
> +	help
> +	  Say yes here to build support for HID sensor to use
> +	  HID sensor common processing for attributes and IIO triggers.
> +
> +config HID_SENSOR_ENUM_BASE_QUIRKS
> +	tristate "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.
No way of detecting that and loosing the config option?
> +
> +endmenu
> diff --git a/drivers/staging/iio/common/hid-sensors/Makefile b/drivers/staging/iio/common/hid-sensors/Makefile
> new file mode 100644
> index 0000000..1f463e0
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for the Hid sensor common modules.
> +#
> +
> +obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
> +hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
> new file mode 100644
> index 0000000..d39c93e
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.c
> @@ -0,0 +1,182 @@
> +/*
> + * 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/sysfs.h>
> +#include "hid-sensor-attributes.h"
> +
why?  Part of spec?
> +#define MAXIMUM_SAMP_FREQUENCY 1000
> +
> +ssize_t hid_sensor_read_samp_freq(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	s32 value;
> +	int len;
> +	int ret;
> +	int conv_value;
> +
> +	ret = sensor_hub_get_feature(st->hsdev,
> +			st->poll.report_id,
> +			st->poll.index, &value);
> +	if (ret < 0 || value <= 0)
> +		len = sprintf(buf, "0\n");
> +	else {
> +		if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
> +			conv_value = 1000/value;
Not going to be terribly accurate and we do allow decimal places
in the abi.
> +		else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
> +			conv_value = 1/value;
Given we are integer, what do you think that is likely to give?
> +		else
> +			conv_value = value; /*Assume HZ*/
> +		len = sprintf(buf, "%d\n", conv_value);
> +	}
> +	return len;
> +}
> +EXPORT_SYMBOL(hid_sensor_read_samp_freq);
> +
> +ssize_t hid_sensor_write_samp_freq(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	int value;
> +	int conv_value;
> +	int ret;
> +
> +	if (kstrtoint(buf, 10, &value) < 0)
> +		return -EINVAL;
> +
> +	if (value > MAXIMUM_SAMP_FREQUENCY)
> +		value = MAXIMUM_SAMP_FREQUENCY;
> +
> +	if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND)
> +		conv_value = 1000/value;
> +	else if (value && st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND)
> +		conv_value = 1/value;
> +	else
> +		conv_value = value; /*Assume HZ*/
> +
> +	ret = sensor_hub_set_feature(st->hsdev,
> +		st->poll.report_id,
> +		st->poll.index,
> +		conv_value);
> +
> +	if (ret < 0)
> +		return ret;
> +	return strlen(buf);
> +}
> +EXPORT_SYMBOL(hid_sensor_write_samp_freq);
> +
Hysterisis is common enough we should just add it to
the iio_chan_spec->info_mask and do it through the read_raw
callbacks.  Would you mind doing a patch to do that?
> +ssize_t hid_sensor_read_hyst_raw(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	s32 value;
> +	int len;
> +	int ret;
> +
> +	ret = sensor_hub_get_feature(st->hsdev,
> +		st->sensitivity.report_id,
> +		st->sensitivity.index, &value);
> +	if (ret < 0 || value < 0)
> +		len = sprintf(buf, "0\n");
> +	else
Not happy with this interface at all.

Scale out the units please to get to the relevant base unit.
e.g. accel is m/s^2   The exponents here are simple powers
of 10 I think?  Hence trivial to apply.   This should
be a simple decimal number.  There may be some arguement for
extending the buffered interface to handle the exponents, but
here we have a massive text buffer and it's a slow path
so lets just do it the simple way.

> +		len = sprintf(buf, "units:%d,exp:%d,value:%d\n",
> +				st->sensitivity.units,
> +				st->sensitivity.unit_expo, value);
> +	return len;
> +}
> +EXPORT_SYMBOL(hid_sensor_read_hyst_raw);
> +
> +ssize_t hid_sensor_write_hyst_raw(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	int value;
> +	int ret;
> +
> +	if (kstrtoint(buf, 10, &value) < 0)
> +		return -EINVAL;
> +
> +	if (value <= 0)
> +		value = 0;
> +	ret = sensor_hub_set_feature(st->hsdev,
> +		st->sensitivity.report_id,
> +		st->sensitivity.index,
> +		value);
This looks suspiciously like a magic number is needed.
Please do the relevant conversions to go from a floating point
string input to the right representation.
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return strlen(buf);
not return len;?
> +}
> +EXPORT_SYMBOL(hid_sensor_write_hyst_raw);
> +
> +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
> +					u32 usage_id,
> +					struct hid_sensor_attributes *st)
> +{
> +	int ret;
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +					HID_FEATURE_REPORT, usage_id,
> +					HID_SENSOR_POLLING, &st->poll);
> +
Do something with ret?  Otherwise why have it?
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +					HID_FEATURE_REPORT, usage_id,
> +					HID_SENSOR_REPORT_STATE,
> +					&st->report_state);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +					HID_FEATURE_REPORT, usage_id,
> +					HID_SENSOR_POWER_STATE,
> +					&st->power_state);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev,
> +			HID_FEATURE_REPORT, usage_id,
> +			HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS,
> +			 &st->sensitivity);
> +
> +	hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
> +			st->poll.index, st->poll.report_id,
> +			st->report_state.index, st->report_state.report_id,
> +			st->power_state.index, st->power_state.report_id,
> +			st->sensitivity.index, st->sensitivity.report_id);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hid_sensor_parse_common_attributes);
> +
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
> +MODULE_DESCRIPTION("HID Sensor common attribute processing");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
> new file mode 100644
> index 0000000..c859b7e
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-attributes.h
> @@ -0,0 +1,60 @@
> +/*
> + * 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
> +
> +/**
> + * IIO_DEV_ATTR_HYSTERESIS - sets hysterisis value
> + * @_mode: sysfs file mode/permissions
> + * @_show: output method for the attribute
> + * @_store: input method for the attribute
> + **/
> +#define IIO_DEV_ATTR_HYSTERESIS(_mode, _show, _store)        \
> +	IIO_DEVICE_ATTR(hyst_raw, _mode, _show, _store, 0)
> +
> +/* Common sysfs attributes for HID sensors */
> +struct hid_sensor_attributes {
> +	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;
> +	void *private;
> +};
> +
> +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
> +					u32 usage_id,
> +					struct hid_sensor_attributes *st);
> +ssize_t hid_sensor_read_hyst_raw(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf);
> +ssize_t hid_sensor_write_hyst_raw(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len);
> +ssize_t hid_sensor_read_samp_freq(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf);
> +ssize_t hid_sensor_write_samp_freq(struct device *dev,
> +		struct device_attribute *attr,
> +		const char *buf, size_t len);
> +
> +#endif
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
> new file mode 100644
> index 0000000..bef5560
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.c
> @@ -0,0 +1,104 @@
> +/*
> + * 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/trigger_consumer.h>
> +#include <linux/iio/trigger.h>
> +#include "hid-sensor-attributes.h"
> +
> +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
> +						bool state)
> +{
> +	struct iio_dev *indio_dev = trig->private_data;
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	int ret;
> +	int state_val;
> +
> +	dev_dbg(&indio_dev->dev, "hid_sensor_data_rdy_trigger_set_state %d\n",
> +			state);
> +	state_val = state ? 1 : 0;
  	bool is defined 0 or 1 with gcc.
> +#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
> +	(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
> +	hid_dbg(st->hsdev, " Using ENUM base FW QUIRKS\n");
> +	++state_val;
> +#endif
> +	st->data_ready = state;
> +	ret = sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
> +					st->power_state.index,
> +					(s32)state_val);
more unhandled return values.  Please clear these up everywhere.
> +
> +	ret = sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
> +					st->report_state.index,
> +					(s32)state_val);
> +	return ret;
> +}
> +
> +void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
> +{
> +	iio_trigger_unregister(indio_dev->trig);
> +	iio_trigger_free(indio_dev->trig);
> +}
> +EXPORT_SYMBOL(hid_sensor_remove_trigger);
> +
> +static const struct iio_trigger_ops hid_sensor_trigger_ops = {
> +	.owner = THIS_MODULE,
> +	.set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
> +};
> +
> +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name)
> +{
> +	int ret;
> +	struct iio_trigger *trig;
> +
> +	trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id);
> +	if (trig == NULL) {
> +		dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
> +		ret = -ENOMEM;
> +		goto error_ret;
> +	}
> +
> +	trig->dev.parent = indio_dev->dev.parent;
> +	trig->private_data = (void *)indio_dev;
> +	trig->ops = &hid_sensor_trigger_ops;
> +	ret = iio_trigger_register(trig);
> +
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "Trigger Register Failed\n");
> +		goto error_free_trig;
> +	}
> +	indio_dev->trig = trig;
> +
> +	return ret;
> +
> +error_free_trig:
> +	iio_trigger_free(trig);
> +error_ret:
> +	return ret;
> +}
> +EXPORT_SYMBOL(hid_sensor_setup_trigger);
> +
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
> +MODULE_DESCRIPTION("HID Sensor trigger processing");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
> new file mode 100644
> index 0000000..9ff3d02
> --- /dev/null
> +++ b/drivers/staging/iio/common/hid-sensors/hid-sensor-trigger.h
> @@ -0,0 +1,27 @@
> +/*
> + * 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_SENSOR_TRIGGER_H
> +#define _HID_SENSOR_TRIGGER_H
> +
one blank line is plenty
> +
> +
> +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
> +void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
> +
> +#endif
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 5/8] HID-Sensors: Added accelerometer 3D
  2012-07-04 19:52     ` srinivas pandruvada
@ 2012-07-08 18:57         ` Jonathan Cameron
  -1 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 18:57 UTC (permalink / raw)
  To: srinivas pandruvada
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, jkosina-AlSwsSmVLrQ,
	lars-Qo5EllUWu/uELgA04lAiVw, jic23-KWPb1pKIrIJaa/9Udqfwiw

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> Added usage id processing for Accelerometer 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.
> 
Mostly fine, but in need of some cleanup. Various suggestions inline.
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>  drivers/staging/iio/accel/Kconfig               |   10 +
>  drivers/staging/iio/accel/Makefile              |    3 +
>  drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 +++++++++++++++++++++++
>  3 files changed, 464 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
> 
> diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
> index 5ab7167..6ab1efa 100644
> --- a/drivers/staging/iio/accel/Kconfig
> +++ b/drivers/staging/iio/accel/Kconfig
> @@ -102,4 +102,14 @@ config SCA3000
>  	  Say yes here to build support for the VTI SCA3000 series of SPI
>  	  accelerometers. These devices use a hardware ring buffer.
>  
> +config HID_SENSOR_ACCEL_3D
> +	depends on HID_SENSOR_HUB
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
> +	select HID_SENSOR_IIO_COMMON
> +	tristate "HID Acelerometers 3D"
> +	help
> +	  Say yes here to build support for the HID SENSOR
> +	  accelerometers 3G.
> +
>  endmenu
> diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
> index 95c6666..2ae9865 100644
> --- a/drivers/staging/iio/accel/Makefile
> +++ b/drivers/staging/iio/accel/Makefile
> @@ -33,3 +33,6 @@ obj-$(CONFIG_LIS3L02DQ)	+= lis3l02dq.o
>  
>  sca3000-y		:= sca3000_core.o sca3000_ring.o
>  obj-$(CONFIG_SCA3000)	+= sca3000.o
> +
> +hid-sensor-accel-3d-drv-y := hid-sensor-accel-3d.o
> +obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d-drv.o
> diff --git a/drivers/staging/iio/accel/hid-sensor-accel-3d.c b/drivers/staging/iio/accel/hid-sensor-accel-3d.c
> new file mode 100644
> index 0000000..1ee65ce
> --- /dev/null
> +++ b/drivers/staging/iio/accel/hid-sensor-accel-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-200073"
> +
Make this an enum, then....
> +#define CHANNEL_SCAN_INDEX_X 0
> +#define CHANNEL_SCAN_INDEX_Y 1
> +#define CHANNEL_SCAN_INDEX_Z 2

> +
> +struct accel_3d_sample {
> +	u32 accel_x;
> +	u32 accel_y;
> +	u32 accel_z;
> +} __packed;
> +
> +struct accel_3d_state {
struct hid_sensor_hub_attribute_info accel[3]; (using above enum)

> +	struct hid_sensor_hub_attribute_info accel_x;
> +	struct hid_sensor_hub_attribute_info accel_y;
> +	struct hid_sensor_hub_attribute_info accel_z;
> +	struct accel_3d_sample accel_sample_data;
u32 accel_val[3] (also using enum).
> +};
> +
> +/* Channel definitions */
> +static struct iio_chan_spec accel_3d_channels[] = {
> +	{
> +		.type = IIO_ACCEL,
> +		.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_ACCEL,
> +		.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_ACCEL,
> +		.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 accel_3d_adjust_channel_bit_mask(int channel, int size)
> +{
> +	accel_3d_channels[channel].scan_type.sign = 's';
> +	accel_3d_channels[channel].scan_type.realbits = size * 8;
> +	accel_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
Always true?  Can't do 16 bit channels in 16 bits?
> +}
> +
> +/* Channel read_raw handler */
> +static int accel_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 accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
> +	int report_id = -1;
> +	u32 address;
> +
> +	*val = 0;
> +	*val2 = 0;
> +	switch (mask) {
> +	case 0:
With the alternative layout above this becomes
const u32 addresses[3] {
       HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
       HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
       HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS
}; //move this outside as useful elsewhere...
     report_id = accel_state->accel[chan->scan_index].report_id;
     address =  addresses[chan->scan_index];

> +		switch (chan->scan_index) {
> +		case  CHANNEL_SCAN_INDEX_X:
> +			report_id = accel_state->accel_x.report_id;
> +			address =
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS;
> +			break;
> +		case  CHANNEL_SCAN_INDEX_Y:
> +			report_id = accel_state->accel_y.report_id;
> +			address =
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS;
> +			break;
> +		case  CHANNEL_SCAN_INDEX_Z:
> +			report_id = accel_state->accel_z.report_id;
> +			address =
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_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_ACCEL_3D, address,
> +				report_id);
> +		else
> +			*val = 0;
> +		break;
> +	case IIO_CHAN_INFO_SCALE:
This works as they are all the same, but more obviously true
(with the above defines as)
      	  *val = accel_state->accel[chan->scan_index].units;

> +		*val = accel_state->accel_x.units;
> +		break;
> +	case IIO_CHAN_INFO_OFFSET:
> +		*val = accel_state->accel_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);
rant about formatting of hystersis in previous email.
Anyhow, I'd like to have hystersis defined as an
element of the chan_spec info_mask as it keeps coming
up. That cuts us down to just sampling frequency and
we could do that as
accel_sampling_frequency which already exists.

The key thing is that if it isn't in info_mask, then
it pretty much isn't available to any in kernel
users of the device...

> +
> +static struct attribute *accel_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 accel_3d_attribute_group = {
> +	.attrs = accel_3d_attributes,
> +};
> +
> +static const struct iio_info accel_3d_info = {
> +	.attrs = &accel_3d_attribute_group,
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &accel_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 accel_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);
Please clear out all these casts from void *'s just makes for messy code.
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	struct accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
> +
> +	dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n", st->data_ready);
> +	if (st->data_ready)
> +		hid_sensor_push_data(indio_dev,
> +				(u8 *)&accel_state->accel_sample_data,
> +				sizeof(struct accel_3d_sample));
> +	return 0;
> +}
> +
> +/* Capture samples in local storage */
> +int accel_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 accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
> +
Feels like one ought to be able to decode an axis from that usage_id
and make this much shorter. Would have to look back at the earlier
patch to find out what would work and I'm lazy ;)
> +	switch (usage_id) {
> +	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
> +		accel_state->accel_sample_data.accel_x =
> +		*(u32 *)raw_data;
> +		break;
> +	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
> +		accel_state->accel_sample_data.accel_y =
> +		*(u32 *)raw_data;
> +		break;
> +	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
> +		accel_state->accel_sample_data.accel_z =
> +		*(u32 *)raw_data;
> +		break;
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +/* Parse report which is specific to an usage id*/
> +static int accel_3d_parse_report(struct platform_device *pdev,
> +				struct hid_sensor_hub_device *hsdev,
> +				unsigned usage_id,
> +				struct accel_3d_state *st)
> +{
> +	int ret;
> +
Lots of missing error handling.  Fix this.
Structures should also allow this to be a simple loop over the channels.

> +	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
> +			usage_id,
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
> +			&st->accel_x);
> +	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
> +					st->accel_x.size);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
> +			usage_id,
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
> +			&st->accel_y);
> +	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
> +					st->accel_y.size);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
> +			usage_id,
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
> +			&st->accel_z);
> +	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
> +					st->accel_z.size);
> +
> +	dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
> +			st->accel_x.index,
> +			st->accel_x.report_id,
> +			st->accel_y.index, st->accel_y.report_id,
> +			st->accel_z.index, st->accel_z.report_id);
> +
> +	return 0;
> +}
> +
> +/* Function to initialize the processing for usage id */
> +static int accel_3d_init(struct platform_device *pdev,
> +			struct hid_sensor_hub_device *hsdev,
> +			unsigned usage_id)
> +{
> +	int ret = 0;
> +	static char *name = "accel_3d";
> +	struct iio_dev *indio_dev;
> +	struct accel_3d_state *accel_state;
> +	struct hid_sensor_attributes *st;
> +
> +	accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
> +	if (accel_state == NULL) {
> +		ret = -ENOMEM;
> +		goto error_ret;
> +	}
> +
> +	indio_dev = iio_device_alloc(sizeof(struct hid_sensor_attributes));
I'd normally expect accel_state to be in iio_priv(indio_dev)... That
might then embed st.
> +	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 *)accel_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 = accel_3d_parse_report(pdev, hsdev, usage_id, accel_state);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to setup attributes\n");
> +		goto error_free_dev;
> +	}
> +
> +	indio_dev->channels = kmemdup(accel_3d_channels,
> +					sizeof(accel_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(accel_3d_channels);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->info = &accel_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;
> +	}
Convention is to nor enable anything initially. Leaves everything
up to userspace (and avoids some annoying race conditions that
have a habit of showing up!)
> +	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(accel_state);
> +error_ret:
> +	return ret;
> +}
> +
> +/* Function to deinitialize the processing for usage id */
> +static int accel_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 accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
st->private is void * so shouldn't need type cast to assign it
to anything.
> +
> +	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(accel_state);
> +	return ret;
> +}
> +
> +static struct hid_sensor_hub_callbacks accel_3d_callbacks = {
> +	.send_event = accel_3d_proc_event,
> +	.capture_sample = accel_3d_capture_sample,
> +};
> +
> +static int __devinit hid_accel_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 = accel_3d_init(pdev, hsdev, HID_USAGE_SENSOR_ACCEL_3D);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "accel_3d_init failed\n");
> +		return ret;
> +	}
> +	accel_3d_callbacks.pdev = pdev;
> +	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
> +					&accel_3d_callbacks);
> +	return 0;
> +}
> +
> +static int __devinit hid_accel_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;
why all the type casting mess here?  If pdev->dev.platform_data is not
an hid_sensor_hub_device * then we need a really really clear
explation of why not.

> +	accel_3d_exit(pdev);
> +	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
> +}
> +
> +static struct platform_driver hid_accel_3d_platform_driver = {
> +	.driver = {
> +		.name	= DRIVER_NAME,
> +		.owner	= THIS_MODULE,
> +	},
> +	.probe		= hid_accel_3d_probe,
> +	.remove		= hid_accel_3d_remove,
> +};
> +
> +/*--------------------------------------------------------------------------*/
> +
> +static int __init hid_accel_3d_init(void)
> +{
> +	return platform_driver_register(&hid_accel_3d_platform_driver);
> +}
> +
> +static void __exit hid_accel_3d_exit(void)
> +{
> +	platform_driver_unregister(&hid_accel_3d_platform_driver);
> +}
> +
> +module_init(hid_accel_3d_init);
> +module_exit(hid_accel_3d_exit);

module_platform_driver

> +
> +MODULE_DESCRIPTION("HID Sensor Accel 3D");
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 5/8] HID-Sensors: Added accelerometer 3D
@ 2012-07-08 18:57         ` Jonathan Cameron
  0 siblings, 0 replies; 27+ messages in thread
From: Jonathan Cameron @ 2012-07-08 18:57 UTC (permalink / raw)
  To: srinivas pandruvada; +Cc: linux-iio, linux-input, jkosina, lars, jic23

On 07/04/2012 08:52 PM, srinivas pandruvada wrote:
> Added usage id processing for Accelerometer 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.
> 
Mostly fine, but in need of some cleanup. Various suggestions inline.
> Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
> ---
>  drivers/staging/iio/accel/Kconfig               |   10 +
>  drivers/staging/iio/accel/Makefile              |    3 +
>  drivers/staging/iio/accel/hid-sensor-accel-3d.c |  451 +++++++++++++++++++++++
>  3 files changed, 464 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/staging/iio/accel/hid-sensor-accel-3d.c
> 
> diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
> index 5ab7167..6ab1efa 100644
> --- a/drivers/staging/iio/accel/Kconfig
> +++ b/drivers/staging/iio/accel/Kconfig
> @@ -102,4 +102,14 @@ config SCA3000
>  	  Say yes here to build support for the VTI SCA3000 series of SPI
>  	  accelerometers. These devices use a hardware ring buffer.
>  
> +config HID_SENSOR_ACCEL_3D
> +	depends on HID_SENSOR_HUB
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
> +	select HID_SENSOR_IIO_COMMON
> +	tristate "HID Acelerometers 3D"
> +	help
> +	  Say yes here to build support for the HID SENSOR
> +	  accelerometers 3G.
> +
>  endmenu
> diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
> index 95c6666..2ae9865 100644
> --- a/drivers/staging/iio/accel/Makefile
> +++ b/drivers/staging/iio/accel/Makefile
> @@ -33,3 +33,6 @@ obj-$(CONFIG_LIS3L02DQ)	+= lis3l02dq.o
>  
>  sca3000-y		:= sca3000_core.o sca3000_ring.o
>  obj-$(CONFIG_SCA3000)	+= sca3000.o
> +
> +hid-sensor-accel-3d-drv-y := hid-sensor-accel-3d.o
> +obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d-drv.o
> diff --git a/drivers/staging/iio/accel/hid-sensor-accel-3d.c b/drivers/staging/iio/accel/hid-sensor-accel-3d.c
> new file mode 100644
> index 0000000..1ee65ce
> --- /dev/null
> +++ b/drivers/staging/iio/accel/hid-sensor-accel-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-200073"
> +
Make this an enum, then....
> +#define CHANNEL_SCAN_INDEX_X 0
> +#define CHANNEL_SCAN_INDEX_Y 1
> +#define CHANNEL_SCAN_INDEX_Z 2

> +
> +struct accel_3d_sample {
> +	u32 accel_x;
> +	u32 accel_y;
> +	u32 accel_z;
> +} __packed;
> +
> +struct accel_3d_state {
struct hid_sensor_hub_attribute_info accel[3]; (using above enum)

> +	struct hid_sensor_hub_attribute_info accel_x;
> +	struct hid_sensor_hub_attribute_info accel_y;
> +	struct hid_sensor_hub_attribute_info accel_z;
> +	struct accel_3d_sample accel_sample_data;
u32 accel_val[3] (also using enum).
> +};
> +
> +/* Channel definitions */
> +static struct iio_chan_spec accel_3d_channels[] = {
> +	{
> +		.type = IIO_ACCEL,
> +		.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_ACCEL,
> +		.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_ACCEL,
> +		.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 accel_3d_adjust_channel_bit_mask(int channel, int size)
> +{
> +	accel_3d_channels[channel].scan_type.sign = 's';
> +	accel_3d_channels[channel].scan_type.realbits = size * 8;
> +	accel_3d_channels[channel].scan_type.storagebits = sizeof(u32) * 8;
Always true?  Can't do 16 bit channels in 16 bits?
> +}
> +
> +/* Channel read_raw handler */
> +static int accel_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 accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
> +	int report_id = -1;
> +	u32 address;
> +
> +	*val = 0;
> +	*val2 = 0;
> +	switch (mask) {
> +	case 0:
With the alternative layout above this becomes
const u32 addresses[3] {
       HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
       HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
       HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS
}; //move this outside as useful elsewhere...
     report_id = accel_state->accel[chan->scan_index].report_id;
     address =  addresses[chan->scan_index];

> +		switch (chan->scan_index) {
> +		case  CHANNEL_SCAN_INDEX_X:
> +			report_id = accel_state->accel_x.report_id;
> +			address =
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS;
> +			break;
> +		case  CHANNEL_SCAN_INDEX_Y:
> +			report_id = accel_state->accel_y.report_id;
> +			address =
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS;
> +			break;
> +		case  CHANNEL_SCAN_INDEX_Z:
> +			report_id = accel_state->accel_z.report_id;
> +			address =
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_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_ACCEL_3D, address,
> +				report_id);
> +		else
> +			*val = 0;
> +		break;
> +	case IIO_CHAN_INFO_SCALE:
This works as they are all the same, but more obviously true
(with the above defines as)
      	  *val = accel_state->accel[chan->scan_index].units;

> +		*val = accel_state->accel_x.units;
> +		break;
> +	case IIO_CHAN_INFO_OFFSET:
> +		*val = accel_state->accel_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);
rant about formatting of hystersis in previous email.
Anyhow, I'd like to have hystersis defined as an
element of the chan_spec info_mask as it keeps coming
up. That cuts us down to just sampling frequency and
we could do that as
accel_sampling_frequency which already exists.

The key thing is that if it isn't in info_mask, then
it pretty much isn't available to any in kernel
users of the device...

> +
> +static struct attribute *accel_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 accel_3d_attribute_group = {
> +	.attrs = accel_3d_attributes,
> +};
> +
> +static const struct iio_info accel_3d_info = {
> +	.attrs = &accel_3d_attribute_group,
> +	.driver_module = THIS_MODULE,
> +	.read_raw = &accel_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 accel_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);
Please clear out all these casts from void *'s just makes for messy code.
> +	struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +	struct accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
> +
> +	dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n", st->data_ready);
> +	if (st->data_ready)
> +		hid_sensor_push_data(indio_dev,
> +				(u8 *)&accel_state->accel_sample_data,
> +				sizeof(struct accel_3d_sample));
> +	return 0;
> +}
> +
> +/* Capture samples in local storage */
> +int accel_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 accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
> +
Feels like one ought to be able to decode an axis from that usage_id
and make this much shorter. Would have to look back at the earlier
patch to find out what would work and I'm lazy ;)
> +	switch (usage_id) {
> +	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
> +		accel_state->accel_sample_data.accel_x =
> +		*(u32 *)raw_data;
> +		break;
> +	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
> +		accel_state->accel_sample_data.accel_y =
> +		*(u32 *)raw_data;
> +		break;
> +	case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
> +		accel_state->accel_sample_data.accel_z =
> +		*(u32 *)raw_data;
> +		break;
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +/* Parse report which is specific to an usage id*/
> +static int accel_3d_parse_report(struct platform_device *pdev,
> +				struct hid_sensor_hub_device *hsdev,
> +				unsigned usage_id,
> +				struct accel_3d_state *st)
> +{
> +	int ret;
> +
Lots of missing error handling.  Fix this.
Structures should also allow this to be a simple loop over the channels.

> +	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
> +			usage_id,
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
> +			&st->accel_x);
> +	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_X,
> +					st->accel_x.size);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
> +			usage_id,
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
> +			&st->accel_y);
> +	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Y,
> +					st->accel_y.size);
> +
> +	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
> +			usage_id,
> +			HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
> +			&st->accel_z);
> +	accel_3d_adjust_channel_bit_mask(CHANNEL_SCAN_INDEX_Z,
> +					st->accel_z.size);
> +
> +	dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
> +			st->accel_x.index,
> +			st->accel_x.report_id,
> +			st->accel_y.index, st->accel_y.report_id,
> +			st->accel_z.index, st->accel_z.report_id);
> +
> +	return 0;
> +}
> +
> +/* Function to initialize the processing for usage id */
> +static int accel_3d_init(struct platform_device *pdev,
> +			struct hid_sensor_hub_device *hsdev,
> +			unsigned usage_id)
> +{
> +	int ret = 0;
> +	static char *name = "accel_3d";
> +	struct iio_dev *indio_dev;
> +	struct accel_3d_state *accel_state;
> +	struct hid_sensor_attributes *st;
> +
> +	accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
> +	if (accel_state == NULL) {
> +		ret = -ENOMEM;
> +		goto error_ret;
> +	}
> +
> +	indio_dev = iio_device_alloc(sizeof(struct hid_sensor_attributes));
I'd normally expect accel_state to be in iio_priv(indio_dev)... That
might then embed st.
> +	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 *)accel_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 = accel_3d_parse_report(pdev, hsdev, usage_id, accel_state);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to setup attributes\n");
> +		goto error_free_dev;
> +	}
> +
> +	indio_dev->channels = kmemdup(accel_3d_channels,
> +					sizeof(accel_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(accel_3d_channels);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->info = &accel_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;
> +	}
Convention is to nor enable anything initially. Leaves everything
up to userspace (and avoids some annoying race conditions that
have a habit of showing up!)
> +	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(accel_state);
> +error_ret:
> +	return ret;
> +}
> +
> +/* Function to deinitialize the processing for usage id */
> +static int accel_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 accel_3d_state *accel_state =
> +			(struct accel_3d_state *)st->private;
st->private is void * so shouldn't need type cast to assign it
to anything.
> +
> +	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(accel_state);
> +	return ret;
> +}
> +
> +static struct hid_sensor_hub_callbacks accel_3d_callbacks = {
> +	.send_event = accel_3d_proc_event,
> +	.capture_sample = accel_3d_capture_sample,
> +};
> +
> +static int __devinit hid_accel_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 = accel_3d_init(pdev, hsdev, HID_USAGE_SENSOR_ACCEL_3D);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "accel_3d_init failed\n");
> +		return ret;
> +	}
> +	accel_3d_callbacks.pdev = pdev;
> +	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
> +					&accel_3d_callbacks);
> +	return 0;
> +}
> +
> +static int __devinit hid_accel_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;
why all the type casting mess here?  If pdev->dev.platform_data is not
an hid_sensor_hub_device * then we need a really really clear
explation of why not.

> +	accel_3d_exit(pdev);
> +	return sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
> +}
> +
> +static struct platform_driver hid_accel_3d_platform_driver = {
> +	.driver = {
> +		.name	= DRIVER_NAME,
> +		.owner	= THIS_MODULE,
> +	},
> +	.probe		= hid_accel_3d_probe,
> +	.remove		= hid_accel_3d_remove,
> +};
> +
> +/*--------------------------------------------------------------------------*/
> +
> +static int __init hid_accel_3d_init(void)
> +{
> +	return platform_driver_register(&hid_accel_3d_platform_driver);
> +}
> +
> +static void __exit hid_accel_3d_exit(void)
> +{
> +	platform_driver_unregister(&hid_accel_3d_platform_driver);
> +}
> +
> +module_init(hid_accel_3d_init);
> +module_exit(hid_accel_3d_exit);

module_platform_driver

> +
> +MODULE_DESCRIPTION("HID Sensor Accel 3D");
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
> +MODULE_LICENSE("GPL");
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2012-07-08 18:57 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-04 19:52 [PATCH 0/8] HID-Sensor v4 srinivas pandruvada
2012-07-04 19:52 ` [PATCH 1/8] HID-Sensors: Documentation srinivas pandruvada
     [not found]   ` <1341431532-15060-2-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2012-07-05  0:56     ` Peter Meerwald
2012-07-05  0:56       ` Peter Meerwald
2012-07-08 17:11     ` Jonathan Cameron
2012-07-08 17:11       ` Jonathan Cameron
2012-07-04 19:52 ` [PATCH 2/8] HID Sensors: Add to special driver list srinivas pandruvada
     [not found] ` <1341431532-15060-1-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2012-07-04 19:52   ` [PATCH 3/8] HID-Sensors: Sensor framework srinivas pandruvada
2012-07-04 19:52     ` srinivas pandruvada
2012-07-08 18:05     ` Jonathan Cameron
2012-07-04 19:52   ` [PATCH 4/8] HID-Sensors: Common attribute and trigger srinivas pandruvada
2012-07-04 19:52     ` srinivas pandruvada
     [not found]     ` <1341431532-15060-5-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2012-07-08 18:23       ` Jonathan Cameron
2012-07-08 18:23         ` Jonathan Cameron
2012-07-04 19:52   ` [PATCH 5/8] HID-Sensors: Added accelerometer 3D srinivas pandruvada
2012-07-04 19:52     ` srinivas pandruvada
     [not found]     ` <1341431532-15060-6-git-send-email-srinivas.pandruvada-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2012-07-04 21:27       ` David Herrmann
2012-07-04 21:27         ` David Herrmann
     [not found]         ` <CANq1E4R8yutQ0QWw_No4fHDwmp=YkCX_xz7KJ7gfRoy2F40CZw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-07-05 15:32           ` Pandruvada, Srinivas
2012-07-05 15:32             ` Pandruvada, Srinivas
2012-07-08 18:57       ` Jonathan Cameron
2012-07-08 18:57         ` Jonathan Cameron
2012-07-04 19:52   ` [PATCH 7/8] HID-Sensors: Added Compass/Magnetometer 3D srinivas pandruvada
2012-07-04 19:52     ` srinivas pandruvada
2012-07-04 19:52   ` [PATCH 8/8] HID-Sensors: Added ALS srinivas pandruvada
2012-07-04 19:52     ` srinivas pandruvada
2012-07-04 19:52 ` [PATCH 6/8] HID-Sensors: Added Gyroscope 3D srinivas pandruvada

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.