]> Git Repo - linux.git/blob - drivers/iio/light/hid-sensor-als.c
net: wan: Add framer framework support
[linux.git] / drivers / iio / light / hid-sensor-als.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 {
17         CHANNEL_SCAN_INDEX_INTENSITY,
18         CHANNEL_SCAN_INDEX_ILLUM,
19         CHANNEL_SCAN_INDEX_COLOR_TEMP,
20         CHANNEL_SCAN_INDEX_CHROMATICITY_X,
21         CHANNEL_SCAN_INDEX_CHROMATICITY_Y,
22         CHANNEL_SCAN_INDEX_MAX
23 };
24
25 #define CHANNEL_SCAN_INDEX_TIMESTAMP CHANNEL_SCAN_INDEX_MAX
26
27 struct als_state {
28         struct hid_sensor_hub_callbacks callbacks;
29         struct hid_sensor_common common_attributes;
30         struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX];
31         struct {
32                 u32 illum[CHANNEL_SCAN_INDEX_MAX];
33                 u64 timestamp __aligned(8);
34         } scan;
35         int scale_pre_decml;
36         int scale_post_decml;
37         int scale_precision;
38         int value_offset;
39         s64 timestamp;
40 };
41
42 static const u32 als_sensitivity_addresses[] = {
43         HID_USAGE_SENSOR_DATA_LIGHT,
44         HID_USAGE_SENSOR_LIGHT_ILLUM,
45 };
46
47 /* Channel definitions */
48 static const struct iio_chan_spec als_channels[] = {
49         {
50                 .type = IIO_INTENSITY,
51                 .modified = 1,
52                 .channel2 = IIO_MOD_LIGHT_BOTH,
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                 BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
59                 .scan_index = CHANNEL_SCAN_INDEX_INTENSITY,
60         },
61         {
62                 .type = IIO_LIGHT,
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                 BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
69                 .scan_index = CHANNEL_SCAN_INDEX_ILLUM,
70         },
71         {
72                 .type = IIO_COLORTEMP,
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                 BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
79                 .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP,
80         },
81         {
82                 .type = IIO_CHROMATICITY,
83                 .modified = 1,
84                 .channel2 = IIO_MOD_X,
85                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
86                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
87                 BIT(IIO_CHAN_INFO_SCALE) |
88                 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
89                 BIT(IIO_CHAN_INFO_HYSTERESIS) |
90                 BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
91                 .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X,
92         },
93         {
94                 .type = IIO_CHROMATICITY,
95                 .modified = 1,
96                 .channel2 = IIO_MOD_Y,
97                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
98                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
99                 BIT(IIO_CHAN_INFO_SCALE) |
100                 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
101                 BIT(IIO_CHAN_INFO_HYSTERESIS) |
102                 BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
103                 .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y,
104         },
105         IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
106 };
107
108 /* Adjust channel real bits based on report descriptor */
109 static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels,
110                                         int channel, int size)
111 {
112         channels[channel].scan_type.sign = 's';
113         /* Real storage bits will change based on the report desc. */
114         channels[channel].scan_type.realbits = size * 8;
115         /* Maximum size of a sample to capture is u32 */
116         channels[channel].scan_type.storagebits = sizeof(u32) * 8;
117 }
118
119 /* Channel read_raw handler */
120 static int als_read_raw(struct iio_dev *indio_dev,
121                               struct iio_chan_spec const *chan,
122                               int *val, int *val2,
123                               long mask)
124 {
125         struct als_state *als_state = iio_priv(indio_dev);
126         struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev;
127         int report_id = -1;
128         u32 address;
129         int ret_type;
130         s32 min;
131
132         *val = 0;
133         *val2 = 0;
134         switch (mask) {
135         case IIO_CHAN_INFO_RAW:
136                 switch (chan->scan_index) {
137                 case  CHANNEL_SCAN_INDEX_INTENSITY:
138                 case  CHANNEL_SCAN_INDEX_ILLUM:
139                         report_id = als_state->als[chan->scan_index].report_id;
140                         min = als_state->als[chan->scan_index].logical_minimum;
141                         address = HID_USAGE_SENSOR_LIGHT_ILLUM;
142                         break;
143                 case  CHANNEL_SCAN_INDEX_COLOR_TEMP:
144                         report_id = als_state->als[chan->scan_index].report_id;
145                         min = als_state->als[chan->scan_index].logical_minimum;
146                         address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE;
147                         break;
148                 case  CHANNEL_SCAN_INDEX_CHROMATICITY_X:
149                         report_id = als_state->als[chan->scan_index].report_id;
150                         min = als_state->als[chan->scan_index].logical_minimum;
151                         address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X;
152                         break;
153                 case  CHANNEL_SCAN_INDEX_CHROMATICITY_Y:
154                         report_id = als_state->als[chan->scan_index].report_id;
155                         min = als_state->als[chan->scan_index].logical_minimum;
156                         address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y;
157                         break;
158                 default:
159                         report_id = -1;
160                         break;
161                 }
162                 if (report_id >= 0) {
163                         hid_sensor_power_state(&als_state->common_attributes,
164                                                 true);
165                         *val = sensor_hub_input_attr_get_raw_value(
166                                         hsdev, hsdev->usage, address, report_id,
167                                         SENSOR_HUB_SYNC, min < 0);
168                         hid_sensor_power_state(&als_state->common_attributes,
169                                                 false);
170                 } else {
171                         *val = 0;
172                         return -EINVAL;
173                 }
174                 ret_type = IIO_VAL_INT;
175                 break;
176         case IIO_CHAN_INFO_SCALE:
177                 *val = als_state->scale_pre_decml;
178                 *val2 = als_state->scale_post_decml;
179                 ret_type = als_state->scale_precision;
180                 break;
181         case IIO_CHAN_INFO_OFFSET:
182                 *val = als_state->value_offset;
183                 ret_type = IIO_VAL_INT;
184                 break;
185         case IIO_CHAN_INFO_SAMP_FREQ:
186                 ret_type = hid_sensor_read_samp_freq_value(
187                                 &als_state->common_attributes, val, val2);
188                 break;
189         case IIO_CHAN_INFO_HYSTERESIS:
190                 ret_type = hid_sensor_read_raw_hyst_value(
191                                 &als_state->common_attributes, val, val2);
192                 break;
193         case IIO_CHAN_INFO_HYSTERESIS_RELATIVE:
194                 ret_type = hid_sensor_read_raw_hyst_rel_value(
195                                 &als_state->common_attributes, val, val2);
196                 break;
197         default:
198                 ret_type = -EINVAL;
199                 break;
200         }
201
202         return ret_type;
203 }
204
205 /* Channel write_raw handler */
206 static int als_write_raw(struct iio_dev *indio_dev,
207                                struct iio_chan_spec const *chan,
208                                int val,
209                                int val2,
210                                long mask)
211 {
212         struct als_state *als_state = iio_priv(indio_dev);
213         int ret = 0;
214
215         switch (mask) {
216         case IIO_CHAN_INFO_SAMP_FREQ:
217                 ret = hid_sensor_write_samp_freq_value(
218                                 &als_state->common_attributes, val, val2);
219                 break;
220         case IIO_CHAN_INFO_HYSTERESIS:
221                 ret = hid_sensor_write_raw_hyst_value(
222                                 &als_state->common_attributes, val, val2);
223                 break;
224         case IIO_CHAN_INFO_HYSTERESIS_RELATIVE:
225                 ret = hid_sensor_write_raw_hyst_rel_value(
226                                 &als_state->common_attributes, val, val2);
227                 break;
228         default:
229                 ret = -EINVAL;
230         }
231
232         return ret;
233 }
234
235 static const struct iio_info als_info = {
236         .read_raw = &als_read_raw,
237         .write_raw = &als_write_raw,
238 };
239
240 /* Callback handler to send event after all samples are received and captured */
241 static int als_proc_event(struct hid_sensor_hub_device *hsdev,
242                                 unsigned usage_id,
243                                 void *priv)
244 {
245         struct iio_dev *indio_dev = platform_get_drvdata(priv);
246         struct als_state *als_state = iio_priv(indio_dev);
247
248         dev_dbg(&indio_dev->dev, "als_proc_event\n");
249         if (atomic_read(&als_state->common_attributes.data_ready)) {
250                 if (!als_state->timestamp)
251                         als_state->timestamp = iio_get_time_ns(indio_dev);
252
253                 iio_push_to_buffers_with_timestamp(indio_dev, &als_state->scan,
254                                                    als_state->timestamp);
255                 als_state->timestamp = 0;
256         }
257
258         return 0;
259 }
260
261 /* Capture samples in local storage */
262 static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
263                                 unsigned usage_id,
264                                 size_t raw_len, char *raw_data,
265                                 void *priv)
266 {
267         struct iio_dev *indio_dev = platform_get_drvdata(priv);
268         struct als_state *als_state = iio_priv(indio_dev);
269         int ret = -EINVAL;
270         u32 sample_data = *(u32 *)raw_data;
271
272         switch (usage_id) {
273         case HID_USAGE_SENSOR_LIGHT_ILLUM:
274                 als_state->scan.illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data;
275                 als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
276                 ret = 0;
277                 break;
278         case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE:
279                 als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data;
280                 ret = 0;
281                 break;
282         case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X:
283                 als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data;
284                 ret = 0;
285                 break;
286         case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y:
287                 als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data;
288                 ret = 0;
289                 break;
290         case HID_USAGE_SENSOR_TIME_TIMESTAMP:
291                 als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
292                                                                     *(s64 *)raw_data);
293                 break;
294         default:
295                 break;
296         }
297
298         return ret;
299 }
300
301 /* Parse report which is specific to an usage id*/
302 static int als_parse_report(struct platform_device *pdev,
303                                 struct hid_sensor_hub_device *hsdev,
304                                 struct iio_chan_spec *channels,
305                                 unsigned usage_id,
306                                 struct als_state *st)
307 {
308         int ret;
309         int i;
310
311         for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) {
312                 ret = sensor_hub_input_get_attribute_info(hsdev,
313                                                 HID_INPUT_REPORT,
314                                                 usage_id,
315                                                 HID_USAGE_SENSOR_LIGHT_ILLUM,
316                                                 &st->als[i]);
317                 if (ret < 0)
318                         return ret;
319                 als_adjust_channel_bit_mask(channels, i, st->als[i].size);
320
321                 dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
322                         st->als[i].report_id);
323         }
324
325         ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
326                                 usage_id,
327                                 HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE,
328                                 &st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP]);
329         if (ret < 0)
330                 return ret;
331         als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_COLOR_TEMP,
332                                 st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].size);
333
334         dev_dbg(&pdev->dev, "als %x:%x\n",
335                 st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].index,
336                 st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].report_id);
337
338         for (i = 0; i < 2; i++) {
339                 int next_scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X + i;
340
341                 ret = sensor_hub_input_get_attribute_info(hsdev,
342                                 HID_INPUT_REPORT, usage_id,
343                                 HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X + i,
344                                 &st->als[next_scan_index]);
345                 if (ret < 0)
346                         return ret;
347
348                 als_adjust_channel_bit_mask(channels,
349                                         CHANNEL_SCAN_INDEX_CHROMATICITY_X + i,
350                                         st->als[next_scan_index].size);
351
352                 dev_dbg(&pdev->dev, "als %x:%x\n",
353                         st->als[next_scan_index].index,
354                         st->als[next_scan_index].report_id);
355         }
356
357         st->scale_precision = hid_sensor_format_scale(usage_id,
358                                 &st->als[CHANNEL_SCAN_INDEX_INTENSITY],
359                                 &st->scale_pre_decml, &st->scale_post_decml);
360
361         return ret;
362 }
363
364 /* Function to initialize the processing for usage id */
365 static int hid_als_probe(struct platform_device *pdev)
366 {
367         int ret = 0;
368         static const char *name = "als";
369         struct iio_dev *indio_dev;
370         struct als_state *als_state;
371         struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
372
373         indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state));
374         if (!indio_dev)
375                 return -ENOMEM;
376         platform_set_drvdata(pdev, indio_dev);
377
378         als_state = iio_priv(indio_dev);
379         als_state->common_attributes.hsdev = hsdev;
380         als_state->common_attributes.pdev = pdev;
381
382         ret = hid_sensor_parse_common_attributes(hsdev,
383                                         hsdev->usage,
384                                         &als_state->common_attributes,
385                                         als_sensitivity_addresses,
386                                         ARRAY_SIZE(als_sensitivity_addresses));
387         if (ret) {
388                 dev_err(&pdev->dev, "failed to setup common attributes\n");
389                 return ret;
390         }
391
392         indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels,
393                                            sizeof(als_channels), GFP_KERNEL);
394         if (!indio_dev->channels) {
395                 dev_err(&pdev->dev, "failed to duplicate channels\n");
396                 return -ENOMEM;
397         }
398
399         ret = als_parse_report(pdev, hsdev,
400                                (struct iio_chan_spec *)indio_dev->channels,
401                                hsdev->usage,
402                                als_state);
403         if (ret) {
404                 dev_err(&pdev->dev, "failed to setup attributes\n");
405                 return ret;
406         }
407
408         indio_dev->num_channels =
409                                 ARRAY_SIZE(als_channels);
410         indio_dev->info = &als_info;
411         indio_dev->name = name;
412         indio_dev->modes = INDIO_DIRECT_MODE;
413
414         atomic_set(&als_state->common_attributes.data_ready, 0);
415
416         ret = hid_sensor_setup_trigger(indio_dev, name,
417                                 &als_state->common_attributes);
418         if (ret < 0) {
419                 dev_err(&pdev->dev, "trigger setup failed\n");
420                 return ret;
421         }
422
423         ret = iio_device_register(indio_dev);
424         if (ret) {
425                 dev_err(&pdev->dev, "device register failed\n");
426                 goto error_remove_trigger;
427         }
428
429         als_state->callbacks.send_event = als_proc_event;
430         als_state->callbacks.capture_sample = als_capture_sample;
431         als_state->callbacks.pdev = pdev;
432         ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks);
433         if (ret < 0) {
434                 dev_err(&pdev->dev, "callback reg failed\n");
435                 goto error_iio_unreg;
436         }
437
438         return ret;
439
440 error_iio_unreg:
441         iio_device_unregister(indio_dev);
442 error_remove_trigger:
443         hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
444         return ret;
445 }
446
447 /* Function to deinitialize the processing for usage id */
448 static void hid_als_remove(struct platform_device *pdev)
449 {
450         struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
451         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
452         struct als_state *als_state = iio_priv(indio_dev);
453
454         sensor_hub_remove_callback(hsdev, hsdev->usage);
455         iio_device_unregister(indio_dev);
456         hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
457 }
458
459 static const struct platform_device_id hid_als_ids[] = {
460         {
461                 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
462                 .name = "HID-SENSOR-200041",
463         },
464         {
465                 /* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */
466                 .name = "HID-SENSOR-LISS-0041",
467         },
468         { /* sentinel */ }
469 };
470 MODULE_DEVICE_TABLE(platform, hid_als_ids);
471
472 static struct platform_driver hid_als_platform_driver = {
473         .id_table = hid_als_ids,
474         .driver = {
475                 .name   = KBUILD_MODNAME,
476                 .pm     = &hid_sensor_pm_ops,
477         },
478         .probe          = hid_als_probe,
479         .remove_new     = hid_als_remove,
480 };
481 module_platform_driver(hid_als_platform_driver);
482
483 MODULE_DESCRIPTION("HID Sensor ALS");
484 MODULE_AUTHOR("Srinivas Pandruvada <[email protected]>");
485 MODULE_LICENSE("GPL");
486 MODULE_IMPORT_NS(IIO_HID);
This page took 0.061635 seconds and 4 git commands to generate.