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