Linux 6.7-rc7
[linux-modified.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                 ret = 0;
284         break;
285         default:
286                 break;
287         }
288
289         return ret;
290 }
291
292 /* Parse report which is specific to an usage id*/
293 static int accel_3d_parse_report(struct platform_device *pdev,
294                                 struct hid_sensor_hub_device *hsdev,
295                                 struct iio_chan_spec *channels,
296                                 unsigned usage_id,
297                                 struct accel_3d_state *st)
298 {
299         int ret;
300         int i;
301
302         for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
303                 ret = sensor_hub_input_get_attribute_info(hsdev,
304                                 HID_INPUT_REPORT,
305                                 usage_id,
306                                 HID_USAGE_SENSOR_ACCEL_X_AXIS + i,
307                                 &st->accel[CHANNEL_SCAN_INDEX_X + i]);
308                 if (ret < 0)
309                         break;
310                 accel_3d_adjust_channel_bit_mask(channels,
311                                 CHANNEL_SCAN_INDEX_X + i,
312                                 st->accel[CHANNEL_SCAN_INDEX_X + i].size);
313         }
314         dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
315                         st->accel[0].index,
316                         st->accel[0].report_id,
317                         st->accel[1].index, st->accel[1].report_id,
318                         st->accel[2].index, st->accel[2].report_id);
319
320         st->scale_precision = hid_sensor_format_scale(
321                                 hsdev->usage,
322                                 &st->accel[CHANNEL_SCAN_INDEX_X],
323                                 &st->scale_pre_decml, &st->scale_post_decml);
324
325         return ret;
326 }
327
328 /* Function to initialize the processing for usage id */
329 static int hid_accel_3d_probe(struct platform_device *pdev)
330 {
331         int ret = 0;
332         const char *name;
333         struct iio_dev *indio_dev;
334         struct accel_3d_state *accel_state;
335         const struct iio_chan_spec *channel_spec;
336         int channel_size;
337
338         struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
339
340         indio_dev = devm_iio_device_alloc(&pdev->dev,
341                                           sizeof(struct accel_3d_state));
342         if (indio_dev == NULL)
343                 return -ENOMEM;
344
345         platform_set_drvdata(pdev, indio_dev);
346
347         accel_state = iio_priv(indio_dev);
348         accel_state->common_attributes.hsdev = hsdev;
349         accel_state->common_attributes.pdev = pdev;
350
351         if (hsdev->usage == HID_USAGE_SENSOR_ACCEL_3D) {
352                 name = "accel_3d";
353                 channel_spec = accel_3d_channels;
354                 channel_size = sizeof(accel_3d_channels);
355                 indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
356         } else {
357                 name = "gravity";
358                 channel_spec = gravity_channels;
359                 channel_size = sizeof(gravity_channels);
360                 indio_dev->num_channels = ARRAY_SIZE(gravity_channels);
361         }
362         ret = hid_sensor_parse_common_attributes(hsdev,
363                                                  hsdev->usage,
364                                                  &accel_state->common_attributes,
365                                                  accel_3d_sensitivity_addresses,
366                                                  ARRAY_SIZE(accel_3d_sensitivity_addresses));
367         if (ret) {
368                 dev_err(&pdev->dev, "failed to setup common attributes\n");
369                 return ret;
370         }
371         indio_dev->channels = devm_kmemdup(&pdev->dev, channel_spec,
372                                            channel_size, GFP_KERNEL);
373
374         if (!indio_dev->channels) {
375                 dev_err(&pdev->dev, "failed to duplicate channels\n");
376                 return -ENOMEM;
377         }
378         ret = accel_3d_parse_report(pdev, hsdev,
379                                 (struct iio_chan_spec *)indio_dev->channels,
380                                 hsdev->usage, accel_state);
381         if (ret) {
382                 dev_err(&pdev->dev, "failed to setup attributes\n");
383                 return ret;
384         }
385
386         indio_dev->info = &accel_3d_info;
387         indio_dev->name = name;
388         indio_dev->modes = INDIO_DIRECT_MODE;
389
390         atomic_set(&accel_state->common_attributes.data_ready, 0);
391
392         ret = hid_sensor_setup_trigger(indio_dev, name,
393                                         &accel_state->common_attributes);
394         if (ret < 0) {
395                 dev_err(&pdev->dev, "trigger setup failed\n");
396                 return ret;
397         }
398
399         ret = iio_device_register(indio_dev);
400         if (ret) {
401                 dev_err(&pdev->dev, "device register failed\n");
402                 goto error_remove_trigger;
403         }
404
405         accel_state->callbacks.send_event = accel_3d_proc_event;
406         accel_state->callbacks.capture_sample = accel_3d_capture_sample;
407         accel_state->callbacks.pdev = pdev;
408         ret = sensor_hub_register_callback(hsdev, hsdev->usage,
409                                         &accel_state->callbacks);
410         if (ret < 0) {
411                 dev_err(&pdev->dev, "callback reg failed\n");
412                 goto error_iio_unreg;
413         }
414
415         return ret;
416
417 error_iio_unreg:
418         iio_device_unregister(indio_dev);
419 error_remove_trigger:
420         hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
421         return ret;
422 }
423
424 /* Function to deinitialize the processing for usage id */
425 static void hid_accel_3d_remove(struct platform_device *pdev)
426 {
427         struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
428         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
429         struct accel_3d_state *accel_state = iio_priv(indio_dev);
430
431         sensor_hub_remove_callback(hsdev, hsdev->usage);
432         iio_device_unregister(indio_dev);
433         hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
434 }
435
436 static const struct platform_device_id hid_accel_3d_ids[] = {
437         {
438                 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
439                 .name = "HID-SENSOR-200073",
440         },
441         {       /* gravity sensor */
442                 .name = "HID-SENSOR-20007b",
443         },
444         { /* sentinel */ }
445 };
446 MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
447
448 static struct platform_driver hid_accel_3d_platform_driver = {
449         .id_table = hid_accel_3d_ids,
450         .driver = {
451                 .name   = KBUILD_MODNAME,
452                 .pm     = &hid_sensor_pm_ops,
453         },
454         .probe          = hid_accel_3d_probe,
455         .remove_new     = hid_accel_3d_remove,
456 };
457 module_platform_driver(hid_accel_3d_platform_driver);
458
459 MODULE_DESCRIPTION("HID Sensor Accel 3D");
460 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
461 MODULE_LICENSE("GPL");
462 MODULE_IMPORT_NS(IIO_HID);