aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/pressure
diff options
context:
space:
mode:
authorArchana Patni <archana.patni@linux.intel.com>2014-02-20 01:30:00 -0500
committerJonathan Cameron <jic23@kernel.org>2014-02-22 08:07:06 -0500
commitf64a799b8a49e3e26497b26ea78af01fc6302874 (patch)
tree2d16c045f55baa802a1e3a6e3e351a341eb45e15 /drivers/iio/pressure
parent39a3a0138f6113805dc9e0813214cd4b03bd8ac0 (diff)
iio: hid-sensors: Added Pressure Sensor driver
Added usage id processing for Pressure Sensor. 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/pressure')
-rw-r--r--drivers/iio/pressure/Kconfig14
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c376
3 files changed, 391 insertions, 0 deletions
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index a8b9cae5c173..6215761b3c53 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -5,6 +5,20 @@
5 5
6menu "Pressure sensors" 6menu "Pressure sensors"
7 7
8config HID_SENSOR_PRESS
9 depends on HID_SENSOR_HUB
10 select IIO_BUFFER
11 select IIO_TRIGGERED_BUFFER
12 select HID_SENSOR_IIO_COMMON
13 select HID_SENSOR_IIO_TRIGGER
14 tristate "HID PRESS"
15 help
16 Say yes here to build support for the HID SENSOR
17 Pressure driver
18
19 To compile this driver as a module, choose M here: the module
20 will be called hid-sensor-press.
21
8config MPL3115 22config MPL3115
9 tristate "Freescale MPL3115A2 pressure sensor driver" 23 tristate "Freescale MPL3115A2 pressure sensor driver"
10 depends on I2C 24 depends on I2C
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index 42bb9fcf5436..4a57bf65b04b 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5# When adding new entries keep the list in alphabetical order 5# When adding new entries keep the list in alphabetical order
6obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
6obj-$(CONFIG_MPL3115) += mpl3115.o 7obj-$(CONFIG_MPL3115) += mpl3115.o
7obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o 8obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
8st_pressure-y := st_pressure_core.o 9st_pressure-y := st_pressure_core.o
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
new file mode 100644
index 000000000000..e0e6409aa94e
--- /dev/null
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -0,0 +1,376 @@
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_PRESSURE 0
33
34struct press_state {
35 struct hid_sensor_hub_callbacks callbacks;
36 struct hid_sensor_common common_attributes;
37 struct hid_sensor_hub_attribute_info press_attr;
38 u32 press_data;
39};
40
41/* Channel definitions */
42static const struct iio_chan_spec press_channels[] = {
43 {
44 .type = IIO_PRESSURE,
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_PRESSURE,
53 }
54};
55
56/* Adjust channel real bits based on report descriptor */
57static void press_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 press_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 press_state *press_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_PRESSURE:
85 report_id = press_state->press_attr.report_id;
86 address =
87 HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE;
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 press_state->common_attributes.hsdev,
96 HID_USAGE_SENSOR_PRESSURE, 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 = press_state->press_attr.units;
106 ret_type = IIO_VAL_INT;
107 break;
108 case IIO_CHAN_INFO_OFFSET:
109 *val = hid_sensor_convert_exponent(
110 press_state->press_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 &press_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 &press_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 press_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 press_state *press_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 &press_state->common_attributes, val, val2);
145 break;
146 case IIO_CHAN_INFO_HYSTERESIS:
147 ret = hid_sensor_write_raw_hyst_value(
148 &press_state->common_attributes, val, val2);
149 break;
150 default:
151 ret = -EINVAL;
152 }
153
154 return ret;
155}
156
157static const struct iio_info press_info = {
158 .driver_module = THIS_MODULE,
159 .read_raw = &press_read_raw,
160 .write_raw = &press_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 press_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 press_state *press_state = iio_priv(indio_dev);
178
179 dev_dbg(&indio_dev->dev, "press_proc_event [%d]\n",
180 press_state->common_attributes.data_ready);
181 if (press_state->common_attributes.data_ready)
182 hid_sensor_push_data(indio_dev,
183 &press_state->press_data,
184 sizeof(press_state->press_data));
185
186 return 0;
187}
188
189/* Capture samples in local storage */
190static int press_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 press_state *press_state = iio_priv(indio_dev);
197 int ret = -EINVAL;
198
199 switch (usage_id) {
200 case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE:
201 press_state->press_data = *(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 press_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 press_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_ATMOSPHERIC_PRESSURE,
223 &st->press_attr);
224 if (ret < 0)
225 return ret;
226 press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE,
227 st->press_attr.size);
228
229 dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index,
230 st->press_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_ATMOSPHERIC_PRESSURE,
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_press_probe(struct platform_device *pdev)
248{
249 int ret = 0;
250 static const char *name = "press";
251 struct iio_dev *indio_dev;
252 struct press_state *press_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 press_state));
258 if (!indio_dev)
259 return -ENOMEM;
260 platform_set_drvdata(pdev, indio_dev);
261
262 press_state = iio_priv(indio_dev);
263 press_state->common_attributes.hsdev = hsdev;
264 press_state->common_attributes.pdev = pdev;
265
266 ret = hid_sensor_parse_common_attributes(hsdev,
267 HID_USAGE_SENSOR_PRESSURE,
268 &press_state->common_attributes);
269 if (ret) {
270 dev_err(&pdev->dev, "failed to setup common attributes\n");
271 return ret;
272 }
273
274 channels = kmemdup(press_channels, sizeof(press_channels), GFP_KERNEL);
275 if (!channels) {
276 dev_err(&pdev->dev, "failed to duplicate channels\n");
277 return -ENOMEM;
278 }
279
280 ret = press_parse_report(pdev, hsdev, channels,
281 HID_USAGE_SENSOR_PRESSURE, press_state);
282 if (ret) {
283 dev_err(&pdev->dev, "failed to setup attributes\n");
284 goto error_free_dev_mem;
285 }
286
287 indio_dev->channels = channels;
288 indio_dev->num_channels =
289 ARRAY_SIZE(press_channels);
290 indio_dev->dev.parent = &pdev->dev;
291 indio_dev->info = &press_info;
292 indio_dev->name = name;
293 indio_dev->modes = INDIO_DIRECT_MODE;
294
295 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
296 NULL, NULL);
297 if (ret) {
298 dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
299 goto error_free_dev_mem;
300 }
301 press_state->common_attributes.data_ready = false;
302 ret = hid_sensor_setup_trigger(indio_dev, name,
303 &press_state->common_attributes);
304 if (ret) {
305 dev_err(&pdev->dev, "trigger setup failed\n");
306 goto error_unreg_buffer_funcs;
307 }
308
309 ret = iio_device_register(indio_dev);
310 if (ret) {
311 dev_err(&pdev->dev, "device register failed\n");
312 goto error_remove_trigger;
313 }
314
315 press_state->callbacks.send_event = press_proc_event;
316 press_state->callbacks.capture_sample = press_capture_sample;
317 press_state->callbacks.pdev = pdev;
318 ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE,
319 &press_state->callbacks);
320 if (ret < 0) {
321 dev_err(&pdev->dev, "callback reg failed\n");
322 goto error_iio_unreg;
323 }
324
325 return ret;
326
327error_iio_unreg:
328 iio_device_unregister(indio_dev);
329error_remove_trigger:
330 hid_sensor_remove_trigger(&press_state->common_attributes);
331error_unreg_buffer_funcs:
332 iio_triggered_buffer_cleanup(indio_dev);
333error_free_dev_mem:
334 kfree(indio_dev->channels);
335 return ret;
336}
337
338/* Function to deinitialize the processing for usage id */
339static int hid_press_remove(struct platform_device *pdev)
340{
341 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
342 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
343 struct press_state *press_state = iio_priv(indio_dev);
344
345 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
346 iio_device_unregister(indio_dev);
347 hid_sensor_remove_trigger(&press_state->common_attributes);
348 iio_triggered_buffer_cleanup(indio_dev);
349 kfree(indio_dev->channels);
350
351 return 0;
352}
353
354static struct platform_device_id hid_press_ids[] = {
355 {
356 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
357 .name = "HID-SENSOR-200031",
358 },
359 { /* sentinel */ }
360};
361MODULE_DEVICE_TABLE(platform, hid_press_ids);
362
363static struct platform_driver hid_press_platform_driver = {
364 .id_table = hid_press_ids,
365 .driver = {
366 .name = KBUILD_MODNAME,
367 .owner = THIS_MODULE,
368 },
369 .probe = hid_press_probe,
370 .remove = hid_press_remove,
371};
372module_platform_driver(hid_press_platform_driver);
373
374MODULE_DESCRIPTION("HID Sensor Pressure");
375MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
376MODULE_LICENSE("GPL");