aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorsrinivas pandruvada <srinivas.pandruvada@intel.com>2012-09-05 08:56:00 -0400
committerJonathan Cameron <jic23@kernel.org>2012-09-06 14:24:15 -0400
commited5514c925a0e1266e70630092a77bd0c89aee1f (patch)
tree2d7398ba5e7427b8454d4e079cb236f7fd7c8903 /drivers/iio
parentbc1d57ba0669877819822c05861961bb1f348840 (diff)
iio: hid-sensors: Added ALS
Added usage id processing for ALS. This uses IIO interfaces for triggered 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> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/light/Kconfig10
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/hid-sensor-als.c386
5 files changed, 399 insertions, 0 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index fc937aca71fb..6e3f143fc71d 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -62,6 +62,7 @@ source "drivers/iio/frequency/Kconfig"
62source "drivers/iio/dac/Kconfig" 62source "drivers/iio/dac/Kconfig"
63source "drivers/iio/common/Kconfig" 63source "drivers/iio/common/Kconfig"
64source "drivers/iio/gyro/Kconfig" 64source "drivers/iio/gyro/Kconfig"
65source "drivers/iio/light/Kconfig"
65source "drivers/iio/magnetometer/Kconfig" 66source "drivers/iio/magnetometer/Kconfig"
66 67
67endif # IIO 68endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 761f2b65ac52..f7fa3c0867b4 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -18,4 +18,5 @@ obj-y += frequency/
18obj-y += dac/ 18obj-y += dac/
19obj-y += common/ 19obj-y += common/
20obj-y += gyro/ 20obj-y += gyro/
21obj-y += light/
21obj-y += magnetometer/ 22obj-y += magnetometer/
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 91d15d2f694f..1763c9bcb98a 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -42,4 +42,14 @@ config VCNL4000
42 To compile this driver as a module, choose M here: the 42 To compile this driver as a module, choose M here: the
43 module will be called vcnl4000. 43 module will be called vcnl4000.
44 44
45config HID_SENSOR_ALS
46 depends on HID_SENSOR_HUB
47 select IIO_BUFFER
48 select IIO_TRIGGERED_BUFFER
49 select HID_SENSOR_IIO_COMMON
50 tristate "HID ALS"
51 help
52 Say yes here to build support for the HID SENSOR
53 Ambient light sensor.
54
45endmenu 55endmenu
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 13f8a782d292..21a8f0df1407 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -5,3 +5,4 @@
5obj-$(CONFIG_ADJD_S311) += adjd_s311.o 5obj-$(CONFIG_ADJD_S311) += adjd_s311.o
6obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o 6obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
7obj-$(CONFIG_VCNL4000) += vcnl4000.o 7obj-$(CONFIG_VCNL4000) += vcnl4000.o
8obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
new file mode 100644
index 000000000000..2cff7d5167b2
--- /dev/null
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -0,0 +1,386 @@
1/*
2 * HID Sensors Driver
3 * Copyright (c) 2012, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 */
19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/module.h>
22#include <linux/interrupt.h>
23#include <linux/irq.h>
24#include <linux/slab.h>
25#include <linux/hid-sensor-hub.h>
26#include <linux/iio/iio.h>
27#include <linux/iio/sysfs.h>
28#include <linux/iio/buffer.h>
29#include <linux/iio/trigger_consumer.h>
30#include <linux/iio/triggered_buffer.h>
31#include "../common/hid-sensors/hid-sensor-attributes.h"
32#include "../common/hid-sensors/hid-sensor-trigger.h"
33
34/*Format: HID-SENSOR-usage_id_in_hex*/
35/*Usage ID from spec for Accelerometer-3D: 0x200041*/
36#define DRIVER_NAME "HID-SENSOR-200041"
37
38#define CHANNEL_SCAN_INDEX_ILLUM 0
39
40struct als_state {
41 struct hid_sensor_hub_callbacks callbacks;
42 struct hid_sensor_iio_common common_attributes;
43 struct hid_sensor_hub_attribute_info als_illum;
44 u32 illum;
45};
46
47/* Channel definitions */
48static const struct iio_chan_spec als_channels[] = {
49 {
50 .type = IIO_INTENSITY,
51 .modified = 1,
52 .channel2 = IIO_MOD_LIGHT_BOTH,
53 .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
54 IIO_CHAN_INFO_SCALE_SHARED_BIT |
55 IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
56 IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
57 .scan_index = CHANNEL_SCAN_INDEX_ILLUM,
58 }
59};
60
61/* Adjust channel real bits based on report descriptor */
62static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels,
63 int channel, int size)
64{
65 channels[channel].scan_type.sign = 's';
66 /* Real storage bits will change based on the report desc. */
67 channels[channel].scan_type.realbits = size * 8;
68 /* Maximum size of a sample to capture is u32 */
69 channels[channel].scan_type.storagebits = sizeof(u32) * 8;
70}
71
72/* Channel read_raw handler */
73static int als_read_raw(struct iio_dev *indio_dev,
74 struct iio_chan_spec const *chan,
75 int *val, int *val2,
76 long mask)
77{
78 struct als_state *als_state = iio_priv(indio_dev);
79 int report_id = -1;
80 u32 address;
81 int ret;
82 int ret_type;
83
84 *val = 0;
85 *val2 = 0;
86 switch (mask) {
87 case 0:
88 switch (chan->scan_index) {
89 case CHANNEL_SCAN_INDEX_ILLUM:
90 report_id = als_state->als_illum.report_id;
91 address =
92 HID_USAGE_SENSOR_LIGHT_ILLUM;
93 break;
94 default:
95 report_id = -1;
96 break;
97 }
98 if (report_id >= 0)
99 *val = sensor_hub_input_attr_get_raw_value(
100 als_state->common_attributes.hsdev,
101 HID_USAGE_SENSOR_ALS, address,
102 report_id);
103 else {
104 *val = 0;
105 return -EINVAL;
106 }
107 ret_type = IIO_VAL_INT;
108 break;
109 case IIO_CHAN_INFO_SCALE:
110 *val = als_state->als_illum.units;
111 ret_type = IIO_VAL_INT;
112 break;
113 case IIO_CHAN_INFO_OFFSET:
114 *val = hid_sensor_convert_exponent(
115 als_state->als_illum.unit_expo);
116 ret_type = IIO_VAL_INT;
117 break;
118 case IIO_CHAN_INFO_SAMP_FREQ:
119 ret = hid_sensor_read_samp_freq_value(
120 &als_state->common_attributes, val, val2);
121 ret_type = IIO_VAL_INT_PLUS_MICRO;
122 break;
123 case IIO_CHAN_INFO_HYSTERESIS:
124 ret = hid_sensor_read_raw_hyst_value(
125 &als_state->common_attributes, val, val2);
126 ret_type = IIO_VAL_INT_PLUS_MICRO;
127 break;
128 default:
129 ret_type = -EINVAL;
130 break;
131 }
132
133 return ret_type;
134}
135
136/* Channel write_raw handler */
137static int als_write_raw(struct iio_dev *indio_dev,
138 struct iio_chan_spec const *chan,
139 int val,
140 int val2,
141 long mask)
142{
143 struct als_state *als_state = iio_priv(indio_dev);
144 int ret = 0;
145
146 switch (mask) {
147 case IIO_CHAN_INFO_SAMP_FREQ:
148 ret = hid_sensor_write_samp_freq_value(
149 &als_state->common_attributes, val, val2);
150 break;
151 case IIO_CHAN_INFO_HYSTERESIS:
152 ret = hid_sensor_write_raw_hyst_value(
153 &als_state->common_attributes, val, val2);
154 break;
155 default:
156 ret = -EINVAL;
157 }
158
159 return ret;
160}
161
162static int als_write_raw_get_fmt(struct iio_dev *indio_dev,
163 struct iio_chan_spec const *chan,
164 long mask)
165{
166 return IIO_VAL_INT_PLUS_MICRO;
167}
168
169static const struct iio_info als_info = {
170 .driver_module = THIS_MODULE,
171 .read_raw = &als_read_raw,
172 .write_raw = &als_write_raw,
173 .write_raw_get_fmt = &als_write_raw_get_fmt,
174};
175
176/* Function to push data to buffer */
177static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
178{
179 struct iio_buffer *buffer = indio_dev->buffer;
180 s64 timestamp = iio_get_time_ns();
181 int datum_sz;
182
183 dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
184 if (!buffer) {
185 dev_err(&indio_dev->dev, "Buffer == NULL\n");
186 return;
187 }
188 datum_sz = buffer->access->get_bytes_per_datum(buffer);
189 if (len > datum_sz) {
190 dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
191 datum_sz);
192 return;
193 }
194 buffer->access->store_to(buffer, (u8 *)data, timestamp);
195}
196
197/* Callback handler to send event after all samples are received and captured */
198static int als_proc_event(struct hid_sensor_hub_device *hsdev,
199 unsigned usage_id,
200 void *priv)
201{
202 struct iio_dev *indio_dev = platform_get_drvdata(priv);
203 struct als_state *als_state = iio_priv(indio_dev);
204
205 dev_dbg(&indio_dev->dev, "als_proc_event [%d]\n",
206 als_state->common_attributes.data_ready);
207 if (als_state->common_attributes.data_ready)
208 hid_sensor_push_data(indio_dev,
209 (u8 *)&als_state->illum,
210 sizeof(als_state->illum));
211
212 return 0;
213}
214
215/* Capture samples in local storage */
216static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
217 unsigned usage_id,
218 size_t raw_len, char *raw_data,
219 void *priv)
220{
221 struct iio_dev *indio_dev = platform_get_drvdata(priv);
222 struct als_state *als_state = iio_priv(indio_dev);
223 int ret = -EINVAL;
224
225 switch (usage_id) {
226 case HID_USAGE_SENSOR_LIGHT_ILLUM:
227 als_state->illum = *(u32 *)raw_data;
228 ret = 0;
229 break;
230 default:
231 break;
232 }
233
234 return ret;
235}
236
237/* Parse report which is specific to an usage id*/
238static int als_parse_report(struct platform_device *pdev,
239 struct hid_sensor_hub_device *hsdev,
240 struct iio_chan_spec *channels,
241 unsigned usage_id,
242 struct als_state *st)
243{
244 int ret;
245
246 ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
247 usage_id,
248 HID_USAGE_SENSOR_LIGHT_ILLUM,
249 &st->als_illum);
250 if (ret < 0)
251 return ret;
252 als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM,
253 st->als_illum.size);
254
255 dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
256 st->als_illum.report_id);
257
258 return ret;
259}
260
261/* Function to initialize the processing for usage id */
262static int __devinit hid_als_probe(struct platform_device *pdev)
263{
264 int ret = 0;
265 static const char *name = "als";
266 struct iio_dev *indio_dev;
267 struct als_state *als_state;
268 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
269 struct iio_chan_spec *channels;
270
271 indio_dev = iio_device_alloc(sizeof(struct als_state));
272 if (indio_dev == NULL) {
273 ret = -ENOMEM;
274 goto error_ret;
275 }
276 platform_set_drvdata(pdev, indio_dev);
277
278 als_state = iio_priv(indio_dev);
279 als_state->common_attributes.hsdev = hsdev;
280 als_state->common_attributes.pdev = pdev;
281
282 ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS,
283 &als_state->common_attributes);
284 if (ret) {
285 dev_err(&pdev->dev, "failed to setup common attributes\n");
286 goto error_free_dev;
287 }
288
289 channels = kmemdup(als_channels,
290 sizeof(als_channels),
291 GFP_KERNEL);
292 if (!channels) {
293 dev_err(&pdev->dev, "failed to duplicate channels\n");
294 goto error_free_dev;
295 }
296
297 ret = als_parse_report(pdev, hsdev, channels,
298 HID_USAGE_SENSOR_ALS, als_state);
299 if (ret) {
300 dev_err(&pdev->dev, "failed to setup attributes\n");
301 goto error_free_dev_mem;
302 }
303
304 indio_dev->channels = channels;
305 indio_dev->num_channels =
306 ARRAY_SIZE(als_channels);
307 indio_dev->dev.parent = &pdev->dev;
308 indio_dev->info = &als_info;
309 indio_dev->name = name;
310 indio_dev->modes = INDIO_DIRECT_MODE;
311
312 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
313 NULL, NULL);
314 if (ret) {
315 dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
316 goto error_free_dev_mem;
317 }
318 als_state->common_attributes.data_ready = false;
319 ret = hid_sensor_setup_trigger(indio_dev, name,
320 &als_state->common_attributes);
321 if (ret < 0) {
322 dev_err(&pdev->dev, "trigger setup failed\n");
323 goto error_unreg_buffer_funcs;
324 }
325
326 ret = iio_device_register(indio_dev);
327 if (ret) {
328 dev_err(&pdev->dev, "device register failed\n");
329 goto error_remove_trigger;
330 }
331
332 als_state->callbacks.send_event = als_proc_event;
333 als_state->callbacks.capture_sample = als_capture_sample;
334 als_state->callbacks.pdev = pdev;
335 ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
336 &als_state->callbacks);
337 if (ret < 0) {
338 dev_err(&pdev->dev, "callback reg failed\n");
339 goto error_iio_unreg;
340 }
341
342 return ret;
343
344error_iio_unreg:
345 iio_device_unregister(indio_dev);
346error_remove_trigger:
347 hid_sensor_remove_trigger(indio_dev);
348error_unreg_buffer_funcs:
349 iio_triggered_buffer_cleanup(indio_dev);
350error_free_dev_mem:
351 kfree(indio_dev->channels);
352error_free_dev:
353 iio_device_free(indio_dev);
354error_ret:
355 return ret;
356}
357
358/* Function to deinitialize the processing for usage id */
359static int __devinit hid_als_remove(struct platform_device *pdev)
360{
361 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
362 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
363
364 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
365 iio_device_unregister(indio_dev);
366 hid_sensor_remove_trigger(indio_dev);
367 iio_triggered_buffer_cleanup(indio_dev);
368 kfree(indio_dev->channels);
369 iio_device_free(indio_dev);
370
371 return 0;
372}
373
374static struct platform_driver hid_als_platform_driver = {
375 .driver = {
376 .name = DRIVER_NAME,
377 .owner = THIS_MODULE,
378 },
379 .probe = hid_als_probe,
380 .remove = hid_als_remove,
381};
382module_platform_driver(hid_als_platform_driver);
383
384MODULE_DESCRIPTION("HID Sensor ALS");
385MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
386MODULE_LICENSE("GPL");