aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorArchana Patni <archana.patni@linux.intel.com>2014-02-20 01:29:00 -0500
committerJonathan Cameron <jic23@kernel.org>2014-02-22 08:07:01 -0500
commit39a3a0138f6113805dc9e0813214cd4b03bd8ac0 (patch)
tree22d4649c5340abe1e868bc32bfef6d6f4751270f /drivers/iio
parent7bbcf7e13695c70f13b2cae59392016c0fa2e7a6 (diff)
iio: hid-sensors: Added Proximity Sensor Driver
Added usage id processing for Proximity (Human Presence). 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: Archana Patni <archana.patni@intel.com> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/light/Kconfig14
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/hid-sensor-prox.c375
3 files changed, 390 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 3a7a5d9f03a3..c89740d4748f 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -73,6 +73,20 @@ config HID_SENSOR_ALS
73 Say yes here to build support for the HID SENSOR 73 Say yes here to build support for the HID SENSOR
74 Ambient light sensor. 74 Ambient light sensor.
75 75
76config HID_SENSOR_PROX
77 depends on HID_SENSOR_HUB
78 select IIO_BUFFER
79 select IIO_TRIGGERED_BUFFER
80 select HID_SENSOR_IIO_COMMON
81 select HID_SENSOR_IIO_TRIGGER
82 tristate "HID PROX"
83 help
84 Say yes here to build support for the HID SENSOR
85 Proximity sensor.
86
87 To compile this driver as a module, choose M here: the
88 module will be called hid-sensor-prox.
89
76config SENSORS_LM3533 90config SENSORS_LM3533
77 tristate "LM3533 ambient light sensor" 91 tristate "LM3533 ambient light sensor"
78 depends on MFD_LM3533 92 depends on MFD_LM3533
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 924530597f83..3eb36e5151fa 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CM32181) += cm32181.o
9obj-$(CONFIG_CM36651) += cm36651.o 9obj-$(CONFIG_CM36651) += cm36651.o
10obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o 10obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
11obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o 11obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
12obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
12obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o 13obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
13obj-$(CONFIG_LTR501) += ltr501.o 14obj-$(CONFIG_LTR501) += ltr501.o
14obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o 15obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
new file mode 100644
index 000000000000..1894ab196f97
--- /dev/null
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -0,0 +1,375 @@
1/*
2 * HID Sensors Driver
3 * Copyright (c) 2014, 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.
16 *
17 */
18#include <linux/device.h>
19#include <linux/platform_device.h>
20#include <linux/module.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/slab.h>
24#include <linux/hid-sensor-hub.h>
25#include <linux/iio/iio.h>
26#include <linux/iio/sysfs.h>
27#include <linux/iio/buffer.h>
28#include <linux/iio/trigger_consumer.h>
29#include <linux/iio/triggered_buffer.h>
30#include "../common/hid-sensors/hid-sensor-trigger.h"
31
32#define CHANNEL_SCAN_INDEX_PRESENCE 0
33
34struct prox_state {
35 struct hid_sensor_hub_callbacks callbacks;
36 struct hid_sensor_common common_attributes;
37 struct hid_sensor_hub_attribute_info prox_attr;
38 u32 human_presence;
39};
40
41/* Channel definitions */
42static const struct iio_chan_spec prox_channels[] = {
43 {
44 .type = IIO_PROXIMITY,
45 .modified = 1,
46 .channel2 = IIO_NO_MOD,
47 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
48 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
49 BIT(IIO_CHAN_INFO_SCALE) |
50 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
51 BIT(IIO_CHAN_INFO_HYSTERESIS),
52 .scan_index = CHANNEL_SCAN_INDEX_PRESENCE,
53 }
54};
55
56/* Adjust channel real bits based on report descriptor */
57static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels,
58 int channel, int size)
59{
60 channels[channel].scan_type.sign = 's';
61 /* Real storage bits will change based on the report desc. */
62 channels[channel].scan_type.realbits = size * 8;
63 /* Maximum size of a sample to capture is u32 */
64 channels[channel].scan_type.storagebits = sizeof(u32) * 8;
65}
66
67/* Channel read_raw handler */
68static int prox_read_raw(struct iio_dev *indio_dev,
69 struct iio_chan_spec const *chan,
70 int *val, int *val2,
71 long mask)
72{
73 struct prox_state *prox_state = iio_priv(indio_dev);
74 int report_id = -1;
75 u32 address;
76 int ret;
77 int ret_type;
78
79 *val = 0;
80 *val2 = 0;
81 switch (mask) {
82 case IIO_CHAN_INFO_RAW:
83 switch (chan->scan_index) {
84 case CHANNEL_SCAN_INDEX_PRESENCE:
85 report_id = prox_state->prox_attr.report_id;
86 address =
87 HID_USAGE_SENSOR_HUMAN_PRESENCE;
88 break;
89 default:
90 report_id = -1;
91 break;
92 }
93 if (report_id >= 0)
94 *val = sensor_hub_input_attr_get_raw_value(
95 prox_state->common_attributes.hsdev,
96 HID_USAGE_SENSOR_PROX, address,
97 report_id);
98 else {
99 *val = 0;
100 return -EINVAL;
101 }
102 ret_type = IIO_VAL_INT;
103 break;
104 case IIO_CHAN_INFO_SCALE:
105 *val = prox_state->prox_attr.units;
106 ret_type = IIO_VAL_INT;
107 break;
108 case IIO_CHAN_INFO_OFFSET:
109 *val = hid_sensor_convert_exponent(
110 prox_state->prox_attr.unit_expo);
111 ret_type = IIO_VAL_INT;
112 break;
113 case IIO_CHAN_INFO_SAMP_FREQ:
114 ret = hid_sensor_read_samp_freq_value(
115 &prox_state->common_attributes, val, val2);
116 ret_type = IIO_VAL_INT_PLUS_MICRO;
117 break;
118 case IIO_CHAN_INFO_HYSTERESIS:
119 ret = hid_sensor_read_raw_hyst_value(
120 &prox_state->common_attributes, val, val2);
121 ret_type = IIO_VAL_INT_PLUS_MICRO;
122 break;
123 default:
124 ret_type = -EINVAL;
125 break;
126 }
127
128 return ret_type;
129}
130
131/* Channel write_raw handler */
132static int prox_write_raw(struct iio_dev *indio_dev,
133 struct iio_chan_spec const *chan,
134 int val,
135 int val2,
136 long mask)
137{
138 struct prox_state *prox_state = iio_priv(indio_dev);
139 int ret = 0;
140
141 switch (mask) {
142 case IIO_CHAN_INFO_SAMP_FREQ:
143 ret = hid_sensor_write_samp_freq_value(
144 &prox_state->common_attributes, val, val2);
145 break;
146 case IIO_CHAN_INFO_HYSTERESIS:
147 ret = hid_sensor_write_raw_hyst_value(
148 &prox_state->common_attributes, val, val2);
149 break;
150 default:
151 ret = -EINVAL;
152 }
153
154 return ret;
155}
156
157static const struct iio_info prox_info = {
158 .driver_module = THIS_MODULE,
159 .read_raw = &prox_read_raw,
160 .write_raw = &prox_write_raw,
161};
162
163/* Function to push data to buffer */
164static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
165 int len)
166{
167 dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
168 iio_push_to_buffers(indio_dev, data);
169}
170
171/* Callback handler to send event after all samples are received and captured */
172static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
173 unsigned usage_id,
174 void *priv)
175{
176 struct iio_dev *indio_dev = platform_get_drvdata(priv);
177 struct prox_state *prox_state = iio_priv(indio_dev);
178
179 dev_dbg(&indio_dev->dev, "prox_proc_event [%d]\n",
180 prox_state->common_attributes.data_ready);
181 if (prox_state->common_attributes.data_ready)
182 hid_sensor_push_data(indio_dev,
183 &prox_state->human_presence,
184 sizeof(prox_state->human_presence));
185
186 return 0;
187}
188
189/* Capture samples in local storage */
190static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
191 unsigned usage_id,
192 size_t raw_len, char *raw_data,
193 void *priv)
194{
195 struct iio_dev *indio_dev = platform_get_drvdata(priv);
196 struct prox_state *prox_state = iio_priv(indio_dev);
197 int ret = -EINVAL;
198
199 switch (usage_id) {
200 case HID_USAGE_SENSOR_HUMAN_PRESENCE:
201 prox_state->human_presence = *(u32 *)raw_data;
202 ret = 0;
203 break;
204 default:
205 break;
206 }
207
208 return ret;
209}
210
211/* Parse report which is specific to an usage id*/
212static int prox_parse_report(struct platform_device *pdev,
213 struct hid_sensor_hub_device *hsdev,
214 struct iio_chan_spec *channels,
215 unsigned usage_id,
216 struct prox_state *st)
217{
218 int ret;
219
220 ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
221 usage_id,
222 HID_USAGE_SENSOR_HUMAN_PRESENCE,
223 &st->prox_attr);
224 if (ret < 0)
225 return ret;
226 prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE,
227 st->prox_attr.size);
228
229 dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index,
230 st->prox_attr.report_id);
231
232 /* Set Sensitivity field ids, when there is no individual modifier */
233 if (st->common_attributes.sensitivity.index < 0) {
234 sensor_hub_input_get_attribute_info(hsdev,
235 HID_FEATURE_REPORT, usage_id,
236 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
237 HID_USAGE_SENSOR_DATA_PRESENCE,
238 &st->common_attributes.sensitivity);
239 dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
240 st->common_attributes.sensitivity.index,
241 st->common_attributes.sensitivity.report_id);
242 }
243 return ret;
244}
245
246/* Function to initialize the processing for usage id */
247static int hid_prox_probe(struct platform_device *pdev)
248{
249 int ret = 0;
250 static const char *name = "prox";
251 struct iio_dev *indio_dev;
252 struct prox_state *prox_state;
253 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
254 struct iio_chan_spec *channels;
255
256 indio_dev = devm_iio_device_alloc(&pdev->dev,
257 sizeof(struct prox_state));
258 if (!indio_dev)
259 return -ENOMEM;
260 platform_set_drvdata(pdev, indio_dev);
261
262 prox_state = iio_priv(indio_dev);
263 prox_state->common_attributes.hsdev = hsdev;
264 prox_state->common_attributes.pdev = pdev;
265
266 ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX,
267 &prox_state->common_attributes);
268 if (ret) {
269 dev_err(&pdev->dev, "failed to setup common attributes\n");
270 return ret;
271 }
272
273 channels = kmemdup(prox_channels, sizeof(prox_channels), GFP_KERNEL);
274 if (!channels) {
275 dev_err(&pdev->dev, "failed to duplicate channels\n");
276 return -ENOMEM;
277 }
278
279 ret = prox_parse_report(pdev, hsdev, channels,
280 HID_USAGE_SENSOR_PROX, prox_state);
281 if (ret) {
282 dev_err(&pdev->dev, "failed to setup attributes\n");
283 goto error_free_dev_mem;
284 }
285
286 indio_dev->channels = channels;
287 indio_dev->num_channels =
288 ARRAY_SIZE(prox_channels);
289 indio_dev->dev.parent = &pdev->dev;
290 indio_dev->info = &prox_info;
291 indio_dev->name = name;
292 indio_dev->modes = INDIO_DIRECT_MODE;
293
294 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
295 NULL, NULL);
296 if (ret) {
297 dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
298 goto error_free_dev_mem;
299 }
300 prox_state->common_attributes.data_ready = false;
301 ret = hid_sensor_setup_trigger(indio_dev, name,
302 &prox_state->common_attributes);
303 if (ret) {
304 dev_err(&pdev->dev, "trigger setup failed\n");
305 goto error_unreg_buffer_funcs;
306 }
307
308 ret = iio_device_register(indio_dev);
309 if (ret) {
310 dev_err(&pdev->dev, "device register failed\n");
311 goto error_remove_trigger;
312 }
313
314 prox_state->callbacks.send_event = prox_proc_event;
315 prox_state->callbacks.capture_sample = prox_capture_sample;
316 prox_state->callbacks.pdev = pdev;
317 ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX,
318 &prox_state->callbacks);
319 if (ret < 0) {
320 dev_err(&pdev->dev, "callback reg failed\n");
321 goto error_iio_unreg;
322 }
323
324 return ret;
325
326error_iio_unreg:
327 iio_device_unregister(indio_dev);
328error_remove_trigger:
329 hid_sensor_remove_trigger(&prox_state->common_attributes);
330error_unreg_buffer_funcs:
331 iio_triggered_buffer_cleanup(indio_dev);
332error_free_dev_mem:
333 kfree(indio_dev->channels);
334 return ret;
335}
336
337/* Function to deinitialize the processing for usage id */
338static int hid_prox_remove(struct platform_device *pdev)
339{
340 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
341 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
342 struct prox_state *prox_state = iio_priv(indio_dev);
343
344 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
345 iio_device_unregister(indio_dev);
346 hid_sensor_remove_trigger(&prox_state->common_attributes);
347 iio_triggered_buffer_cleanup(indio_dev);
348 kfree(indio_dev->channels);
349
350 return 0;
351}
352
353static struct platform_device_id hid_prox_ids[] = {
354 {
355 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
356 .name = "HID-SENSOR-200011",
357 },
358 { /* sentinel */ }
359};
360MODULE_DEVICE_TABLE(platform, hid_prox_ids);
361
362static struct platform_driver hid_prox_platform_driver = {
363 .id_table = hid_prox_ids,
364 .driver = {
365 .name = KBUILD_MODNAME,
366 .owner = THIS_MODULE,
367 },
368 .probe = hid_prox_probe,
369 .remove = hid_prox_remove,
370};
371module_platform_driver(hid_prox_platform_driver);
372
373MODULE_DESCRIPTION("HID Sensor Proximity");
374MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
375MODULE_LICENSE("GPL");