This source file includes following definitions.
- accel_3d_adjust_channel_bit_mask
- accel_3d_read_raw
- accel_3d_write_raw
- hid_sensor_push_data
- accel_3d_proc_event
- accel_3d_capture_sample
- accel_3d_parse_report
- hid_accel_3d_probe
- hid_accel_3d_remove
1
2
3
4
5
6 #include <linux/device.h>
7 #include <linux/platform_device.h>
8 #include <linux/module.h>
9 #include <linux/interrupt.h>
10 #include <linux/irq.h>
11 #include <linux/slab.h>
12 #include <linux/delay.h>
13 #include <linux/hid-sensor-hub.h>
14 #include <linux/iio/iio.h>
15 #include <linux/iio/sysfs.h>
16 #include <linux/iio/buffer.h>
17 #include <linux/iio/trigger_consumer.h>
18 #include <linux/iio/triggered_buffer.h>
19 #include "../common/hid-sensors/hid-sensor-trigger.h"
20
21 enum accel_3d_channel {
22 CHANNEL_SCAN_INDEX_X,
23 CHANNEL_SCAN_INDEX_Y,
24 CHANNEL_SCAN_INDEX_Z,
25 ACCEL_3D_CHANNEL_MAX,
26 };
27
28 struct accel_3d_state {
29 struct hid_sensor_hub_callbacks callbacks;
30 struct hid_sensor_common common_attributes;
31 struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
32
33 u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3];
34 int scale_pre_decml;
35 int scale_post_decml;
36 int scale_precision;
37 int value_offset;
38 int64_t timestamp;
39 };
40
41 static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
42 HID_USAGE_SENSOR_ACCEL_X_AXIS,
43 HID_USAGE_SENSOR_ACCEL_Y_AXIS,
44 HID_USAGE_SENSOR_ACCEL_Z_AXIS
45 };
46
47
48 static const struct iio_chan_spec accel_3d_channels[] = {
49 {
50 .type = IIO_ACCEL,
51 .modified = 1,
52 .channel2 = IIO_MOD_X,
53 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
54 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
55 BIT(IIO_CHAN_INFO_SCALE) |
56 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
57 BIT(IIO_CHAN_INFO_HYSTERESIS),
58 .scan_index = CHANNEL_SCAN_INDEX_X,
59 }, {
60 .type = IIO_ACCEL,
61 .modified = 1,
62 .channel2 = IIO_MOD_Y,
63 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
64 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
65 BIT(IIO_CHAN_INFO_SCALE) |
66 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
67 BIT(IIO_CHAN_INFO_HYSTERESIS),
68 .scan_index = CHANNEL_SCAN_INDEX_Y,
69 }, {
70 .type = IIO_ACCEL,
71 .modified = 1,
72 .channel2 = IIO_MOD_Z,
73 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
74 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
75 BIT(IIO_CHAN_INFO_SCALE) |
76 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
77 BIT(IIO_CHAN_INFO_HYSTERESIS),
78 .scan_index = CHANNEL_SCAN_INDEX_Z,
79 },
80 IIO_CHAN_SOFT_TIMESTAMP(3)
81 };
82
83
84 static const struct iio_chan_spec gravity_channels[] = {
85 {
86 .type = IIO_GRAVITY,
87 .modified = 1,
88 .channel2 = IIO_MOD_X,
89 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
90 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
91 BIT(IIO_CHAN_INFO_SCALE) |
92 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
93 BIT(IIO_CHAN_INFO_HYSTERESIS),
94 .scan_index = CHANNEL_SCAN_INDEX_X,
95 }, {
96 .type = IIO_GRAVITY,
97 .modified = 1,
98 .channel2 = IIO_MOD_Y,
99 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
100 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
101 BIT(IIO_CHAN_INFO_SCALE) |
102 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
103 BIT(IIO_CHAN_INFO_HYSTERESIS),
104 .scan_index = CHANNEL_SCAN_INDEX_Y,
105 }, {
106 .type = IIO_GRAVITY,
107 .modified = 1,
108 .channel2 = IIO_MOD_Z,
109 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
110 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
111 BIT(IIO_CHAN_INFO_SCALE) |
112 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
113 BIT(IIO_CHAN_INFO_HYSTERESIS),
114 .scan_index = CHANNEL_SCAN_INDEX_Z,
115 }
116 };
117
118
119 static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
120 int channel, int size)
121 {
122 channels[channel].scan_type.sign = 's';
123
124 channels[channel].scan_type.realbits = size * 8;
125
126 channels[channel].scan_type.storagebits = sizeof(u32) * 8;
127 }
128
129
130 static int accel_3d_read_raw(struct iio_dev *indio_dev,
131 struct iio_chan_spec const *chan,
132 int *val, int *val2,
133 long mask)
134 {
135 struct accel_3d_state *accel_state = iio_priv(indio_dev);
136 int report_id = -1;
137 u32 address;
138 int ret_type;
139 s32 min;
140 struct hid_sensor_hub_device *hsdev =
141 accel_state->common_attributes.hsdev;
142
143 *val = 0;
144 *val2 = 0;
145 switch (mask) {
146 case IIO_CHAN_INFO_RAW:
147 hid_sensor_power_state(&accel_state->common_attributes, true);
148 report_id = accel_state->accel[chan->scan_index].report_id;
149 min = accel_state->accel[chan->scan_index].logical_minimum;
150 address = accel_3d_addresses[chan->scan_index];
151 if (report_id >= 0)
152 *val = sensor_hub_input_attr_get_raw_value(
153 accel_state->common_attributes.hsdev,
154 hsdev->usage, address, report_id,
155 SENSOR_HUB_SYNC,
156 min < 0);
157 else {
158 *val = 0;
159 hid_sensor_power_state(&accel_state->common_attributes,
160 false);
161 return -EINVAL;
162 }
163 hid_sensor_power_state(&accel_state->common_attributes, false);
164 ret_type = IIO_VAL_INT;
165 break;
166 case IIO_CHAN_INFO_SCALE:
167 *val = accel_state->scale_pre_decml;
168 *val2 = accel_state->scale_post_decml;
169 ret_type = accel_state->scale_precision;
170 break;
171 case IIO_CHAN_INFO_OFFSET:
172 *val = accel_state->value_offset;
173 ret_type = IIO_VAL_INT;
174 break;
175 case IIO_CHAN_INFO_SAMP_FREQ:
176 ret_type = hid_sensor_read_samp_freq_value(
177 &accel_state->common_attributes, val, val2);
178 break;
179 case IIO_CHAN_INFO_HYSTERESIS:
180 ret_type = hid_sensor_read_raw_hyst_value(
181 &accel_state->common_attributes, val, val2);
182 break;
183 default:
184 ret_type = -EINVAL;
185 break;
186 }
187
188 return ret_type;
189 }
190
191
192 static int accel_3d_write_raw(struct iio_dev *indio_dev,
193 struct iio_chan_spec const *chan,
194 int val,
195 int val2,
196 long mask)
197 {
198 struct accel_3d_state *accel_state = iio_priv(indio_dev);
199 int ret = 0;
200
201 switch (mask) {
202 case IIO_CHAN_INFO_SAMP_FREQ:
203 ret = hid_sensor_write_samp_freq_value(
204 &accel_state->common_attributes, val, val2);
205 break;
206 case IIO_CHAN_INFO_HYSTERESIS:
207 ret = hid_sensor_write_raw_hyst_value(
208 &accel_state->common_attributes, val, val2);
209 break;
210 default:
211 ret = -EINVAL;
212 }
213
214 return ret;
215 }
216
217 static const struct iio_info accel_3d_info = {
218 .read_raw = &accel_3d_read_raw,
219 .write_raw = &accel_3d_write_raw,
220 };
221
222
223 static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data,
224 int len, int64_t timestamp)
225 {
226 dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
227 iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
228 }
229
230
231 static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
232 unsigned usage_id,
233 void *priv)
234 {
235 struct iio_dev *indio_dev = platform_get_drvdata(priv);
236 struct accel_3d_state *accel_state = iio_priv(indio_dev);
237
238 dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n");
239 if (atomic_read(&accel_state->common_attributes.data_ready)) {
240 if (!accel_state->timestamp)
241 accel_state->timestamp = iio_get_time_ns(indio_dev);
242
243 hid_sensor_push_data(indio_dev,
244 accel_state->accel_val,
245 sizeof(accel_state->accel_val),
246 accel_state->timestamp);
247
248 accel_state->timestamp = 0;
249 }
250
251 return 0;
252 }
253
254
255 static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
256 unsigned usage_id,
257 size_t raw_len, char *raw_data,
258 void *priv)
259 {
260 struct iio_dev *indio_dev = platform_get_drvdata(priv);
261 struct accel_3d_state *accel_state = iio_priv(indio_dev);
262 int offset;
263 int ret = -EINVAL;
264
265 switch (usage_id) {
266 case HID_USAGE_SENSOR_ACCEL_X_AXIS:
267 case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
268 case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
269 offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
270 accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
271 *(u32 *)raw_data;
272 ret = 0;
273 break;
274 case HID_USAGE_SENSOR_TIME_TIMESTAMP:
275 accel_state->timestamp =
276 hid_sensor_convert_timestamp(
277 &accel_state->common_attributes,
278 *(int64_t *)raw_data);
279 break;
280 default:
281 break;
282 }
283
284 return ret;
285 }
286
287
288 static int accel_3d_parse_report(struct platform_device *pdev,
289 struct hid_sensor_hub_device *hsdev,
290 struct iio_chan_spec *channels,
291 unsigned usage_id,
292 struct accel_3d_state *st)
293 {
294 int ret;
295 int i;
296
297 for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
298 ret = sensor_hub_input_get_attribute_info(hsdev,
299 HID_INPUT_REPORT,
300 usage_id,
301 HID_USAGE_SENSOR_ACCEL_X_AXIS + i,
302 &st->accel[CHANNEL_SCAN_INDEX_X + i]);
303 if (ret < 0)
304 break;
305 accel_3d_adjust_channel_bit_mask(channels,
306 CHANNEL_SCAN_INDEX_X + i,
307 st->accel[CHANNEL_SCAN_INDEX_X + i].size);
308 }
309 dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
310 st->accel[0].index,
311 st->accel[0].report_id,
312 st->accel[1].index, st->accel[1].report_id,
313 st->accel[2].index, st->accel[2].report_id);
314
315 st->scale_precision = hid_sensor_format_scale(
316 hsdev->usage,
317 &st->accel[CHANNEL_SCAN_INDEX_X],
318 &st->scale_pre_decml, &st->scale_post_decml);
319
320
321 if (st->common_attributes.sensitivity.index < 0) {
322 sensor_hub_input_get_attribute_info(hsdev,
323 HID_FEATURE_REPORT, usage_id,
324 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
325 HID_USAGE_SENSOR_DATA_ACCELERATION,
326 &st->common_attributes.sensitivity);
327 dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
328 st->common_attributes.sensitivity.index,
329 st->common_attributes.sensitivity.report_id);
330 }
331
332 return ret;
333 }
334
335
336 static int hid_accel_3d_probe(struct platform_device *pdev)
337 {
338 int ret = 0;
339 const char *name;
340 struct iio_dev *indio_dev;
341 struct accel_3d_state *accel_state;
342 const struct iio_chan_spec *channel_spec;
343 int channel_size;
344
345 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
346
347 indio_dev = devm_iio_device_alloc(&pdev->dev,
348 sizeof(struct accel_3d_state));
349 if (indio_dev == NULL)
350 return -ENOMEM;
351
352 platform_set_drvdata(pdev, indio_dev);
353
354 accel_state = iio_priv(indio_dev);
355 accel_state->common_attributes.hsdev = hsdev;
356 accel_state->common_attributes.pdev = pdev;
357
358 if (hsdev->usage == HID_USAGE_SENSOR_ACCEL_3D) {
359 name = "accel_3d";
360 channel_spec = accel_3d_channels;
361 channel_size = sizeof(accel_3d_channels);
362 indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
363 } else {
364 name = "gravity";
365 channel_spec = gravity_channels;
366 channel_size = sizeof(gravity_channels);
367 indio_dev->num_channels = ARRAY_SIZE(gravity_channels);
368 }
369 ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
370 &accel_state->common_attributes);
371 if (ret) {
372 dev_err(&pdev->dev, "failed to setup common attributes\n");
373 return ret;
374 }
375 indio_dev->channels = kmemdup(channel_spec, channel_size, GFP_KERNEL);
376
377 if (!indio_dev->channels) {
378 dev_err(&pdev->dev, "failed to duplicate channels\n");
379 return -ENOMEM;
380 }
381 ret = accel_3d_parse_report(pdev, hsdev,
382 (struct iio_chan_spec *)indio_dev->channels,
383 hsdev->usage, accel_state);
384 if (ret) {
385 dev_err(&pdev->dev, "failed to setup attributes\n");
386 goto error_free_dev_mem;
387 }
388
389 indio_dev->dev.parent = &pdev->dev;
390 indio_dev->info = &accel_3d_info;
391 indio_dev->name = name;
392 indio_dev->modes = INDIO_DIRECT_MODE;
393
394 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
395 NULL, NULL);
396 if (ret) {
397 dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
398 goto error_free_dev_mem;
399 }
400 atomic_set(&accel_state->common_attributes.data_ready, 0);
401 ret = hid_sensor_setup_trigger(indio_dev, name,
402 &accel_state->common_attributes);
403 if (ret < 0) {
404 dev_err(&pdev->dev, "trigger setup failed\n");
405 goto error_unreg_buffer_funcs;
406 }
407
408 ret = iio_device_register(indio_dev);
409 if (ret) {
410 dev_err(&pdev->dev, "device register failed\n");
411 goto error_remove_trigger;
412 }
413
414 accel_state->callbacks.send_event = accel_3d_proc_event;
415 accel_state->callbacks.capture_sample = accel_3d_capture_sample;
416 accel_state->callbacks.pdev = pdev;
417 ret = sensor_hub_register_callback(hsdev, hsdev->usage,
418 &accel_state->callbacks);
419 if (ret < 0) {
420 dev_err(&pdev->dev, "callback reg failed\n");
421 goto error_iio_unreg;
422 }
423
424 return ret;
425
426 error_iio_unreg:
427 iio_device_unregister(indio_dev);
428 error_remove_trigger:
429 hid_sensor_remove_trigger(&accel_state->common_attributes);
430 error_unreg_buffer_funcs:
431 iio_triggered_buffer_cleanup(indio_dev);
432 error_free_dev_mem:
433 kfree(indio_dev->channels);
434 return ret;
435 }
436
437
438 static int hid_accel_3d_remove(struct platform_device *pdev)
439 {
440 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
441 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
442 struct accel_3d_state *accel_state = iio_priv(indio_dev);
443
444 sensor_hub_remove_callback(hsdev, hsdev->usage);
445 iio_device_unregister(indio_dev);
446 hid_sensor_remove_trigger(&accel_state->common_attributes);
447 iio_triggered_buffer_cleanup(indio_dev);
448 kfree(indio_dev->channels);
449
450 return 0;
451 }
452
453 static const struct platform_device_id hid_accel_3d_ids[] = {
454 {
455
456 .name = "HID-SENSOR-200073",
457 },
458 {
459 .name = "HID-SENSOR-20007b",
460 },
461 { }
462 };
463 MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
464
465 static struct platform_driver hid_accel_3d_platform_driver = {
466 .id_table = hid_accel_3d_ids,
467 .driver = {
468 .name = KBUILD_MODNAME,
469 .pm = &hid_sensor_pm_ops,
470 },
471 .probe = hid_accel_3d_probe,
472 .remove = hid_accel_3d_remove,
473 };
474 module_platform_driver(hid_accel_3d_platform_driver);
475
476 MODULE_DESCRIPTION("HID Sensor Accel 3D");
477 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
478 MODULE_LICENSE("GPL");