Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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/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 "../common/hid-sensors/hid-sensor-trigger.h"
18
19enum {
20 CHANNEL_SCAN_INDEX_INTENSITY = 0,
21 CHANNEL_SCAN_INDEX_ILLUM = 1,
22 CHANNEL_SCAN_INDEX_MAX
23};
24
25#define CHANNEL_SCAN_INDEX_TIMESTAMP CHANNEL_SCAN_INDEX_MAX
26
27struct als_state {
28 struct hid_sensor_hub_callbacks callbacks;
29 struct hid_sensor_common common_attributes;
30 struct hid_sensor_hub_attribute_info als_illum;
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/* Channel definitions */
43static const struct iio_chan_spec als_channels[] = {
44 {
45 .type = IIO_INTENSITY,
46 .modified = 1,
47 .channel2 = IIO_MOD_LIGHT_BOTH,
48 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
49 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
50 BIT(IIO_CHAN_INFO_SCALE) |
51 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
52 BIT(IIO_CHAN_INFO_HYSTERESIS),
53 .scan_index = CHANNEL_SCAN_INDEX_INTENSITY,
54 },
55 {
56 .type = IIO_LIGHT,
57 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
58 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
59 BIT(IIO_CHAN_INFO_SCALE) |
60 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
61 BIT(IIO_CHAN_INFO_HYSTERESIS),
62 .scan_index = CHANNEL_SCAN_INDEX_ILLUM,
63 },
64 IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
65};
66
67/* Adjust channel real bits based on report descriptor */
68static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels,
69 int channel, int size)
70{
71 channels[channel].scan_type.sign = 's';
72 /* Real storage bits will change based on the report desc. */
73 channels[channel].scan_type.realbits = size * 8;
74 /* Maximum size of a sample to capture is u32 */
75 channels[channel].scan_type.storagebits = sizeof(u32) * 8;
76}
77
78/* Channel read_raw handler */
79static int als_read_raw(struct iio_dev *indio_dev,
80 struct iio_chan_spec const *chan,
81 int *val, int *val2,
82 long mask)
83{
84 struct als_state *als_state = iio_priv(indio_dev);
85 int report_id = -1;
86 u32 address;
87 int ret_type;
88 s32 min;
89
90 *val = 0;
91 *val2 = 0;
92 switch (mask) {
93 case IIO_CHAN_INFO_RAW:
94 switch (chan->scan_index) {
95 case CHANNEL_SCAN_INDEX_INTENSITY:
96 case CHANNEL_SCAN_INDEX_ILLUM:
97 report_id = als_state->als_illum.report_id;
98 min = als_state->als_illum.logical_minimum;
99 address = HID_USAGE_SENSOR_LIGHT_ILLUM;
100 break;
101 default:
102 report_id = -1;
103 break;
104 }
105 if (report_id >= 0) {
106 hid_sensor_power_state(&als_state->common_attributes,
107 true);
108 *val = sensor_hub_input_attr_get_raw_value(
109 als_state->common_attributes.hsdev,
110 HID_USAGE_SENSOR_ALS, address,
111 report_id,
112 SENSOR_HUB_SYNC,
113 min < 0);
114 hid_sensor_power_state(&als_state->common_attributes,
115 false);
116 } else {
117 *val = 0;
118 return -EINVAL;
119 }
120 ret_type = IIO_VAL_INT;
121 break;
122 case IIO_CHAN_INFO_SCALE:
123 *val = als_state->scale_pre_decml;
124 *val2 = als_state->scale_post_decml;
125 ret_type = als_state->scale_precision;
126 break;
127 case IIO_CHAN_INFO_OFFSET:
128 *val = als_state->value_offset;
129 ret_type = IIO_VAL_INT;
130 break;
131 case IIO_CHAN_INFO_SAMP_FREQ:
132 ret_type = hid_sensor_read_samp_freq_value(
133 &als_state->common_attributes, val, val2);
134 break;
135 case IIO_CHAN_INFO_HYSTERESIS:
136 ret_type = hid_sensor_read_raw_hyst_value(
137 &als_state->common_attributes, val, val2);
138 break;
139 default:
140 ret_type = -EINVAL;
141 break;
142 }
143
144 return ret_type;
145}
146
147/* Channel write_raw handler */
148static int als_write_raw(struct iio_dev *indio_dev,
149 struct iio_chan_spec const *chan,
150 int val,
151 int val2,
152 long mask)
153{
154 struct als_state *als_state = iio_priv(indio_dev);
155 int ret = 0;
156
157 switch (mask) {
158 case IIO_CHAN_INFO_SAMP_FREQ:
159 ret = hid_sensor_write_samp_freq_value(
160 &als_state->common_attributes, val, val2);
161 break;
162 case IIO_CHAN_INFO_HYSTERESIS:
163 ret = hid_sensor_write_raw_hyst_value(
164 &als_state->common_attributes, val, val2);
165 break;
166 default:
167 ret = -EINVAL;
168 }
169
170 return ret;
171}
172
173static const struct iio_info als_info = {
174 .read_raw = &als_read_raw,
175 .write_raw = &als_write_raw,
176};
177
178/* Callback handler to send event after all samples are received and captured */
179static int als_proc_event(struct hid_sensor_hub_device *hsdev,
180 unsigned usage_id,
181 void *priv)
182{
183 struct iio_dev *indio_dev = platform_get_drvdata(priv);
184 struct als_state *als_state = iio_priv(indio_dev);
185
186 dev_dbg(&indio_dev->dev, "als_proc_event\n");
187 if (atomic_read(&als_state->common_attributes.data_ready)) {
188 if (!als_state->timestamp)
189 als_state->timestamp = iio_get_time_ns(indio_dev);
190
191 iio_push_to_buffers_with_timestamp(indio_dev, &als_state->scan,
192 als_state->timestamp);
193 als_state->timestamp = 0;
194 }
195
196 return 0;
197}
198
199/* Capture samples in local storage */
200static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
201 unsigned usage_id,
202 size_t raw_len, char *raw_data,
203 void *priv)
204{
205 struct iio_dev *indio_dev = platform_get_drvdata(priv);
206 struct als_state *als_state = iio_priv(indio_dev);
207 int ret = -EINVAL;
208 u32 sample_data = *(u32 *)raw_data;
209
210 switch (usage_id) {
211 case HID_USAGE_SENSOR_LIGHT_ILLUM:
212 als_state->scan.illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data;
213 als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
214 ret = 0;
215 break;
216 case HID_USAGE_SENSOR_TIME_TIMESTAMP:
217 als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
218 *(s64 *)raw_data);
219 break;
220 default:
221 break;
222 }
223
224 return ret;
225}
226
227/* Parse report which is specific to an usage id*/
228static int als_parse_report(struct platform_device *pdev,
229 struct hid_sensor_hub_device *hsdev,
230 struct iio_chan_spec *channels,
231 unsigned usage_id,
232 struct als_state *st)
233{
234 int ret;
235
236 ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
237 usage_id,
238 HID_USAGE_SENSOR_LIGHT_ILLUM,
239 &st->als_illum);
240 if (ret < 0)
241 return ret;
242 als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_INTENSITY,
243 st->als_illum.size);
244 als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM,
245 st->als_illum.size);
246
247 dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
248 st->als_illum.report_id);
249
250 st->scale_precision = hid_sensor_format_scale(
251 HID_USAGE_SENSOR_ALS,
252 &st->als_illum,
253 &st->scale_pre_decml, &st->scale_post_decml);
254
255 /* Set Sensitivity field ids, when there is no individual modifier */
256 if (st->common_attributes.sensitivity.index < 0) {
257 sensor_hub_input_get_attribute_info(hsdev,
258 HID_FEATURE_REPORT, usage_id,
259 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
260 HID_USAGE_SENSOR_DATA_LIGHT,
261 &st->common_attributes.sensitivity);
262 dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
263 st->common_attributes.sensitivity.index,
264 st->common_attributes.sensitivity.report_id);
265 }
266 return ret;
267}
268
269/* Function to initialize the processing for usage id */
270static int hid_als_probe(struct platform_device *pdev)
271{
272 int ret = 0;
273 static const char *name = "als";
274 struct iio_dev *indio_dev;
275 struct als_state *als_state;
276 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
277
278 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state));
279 if (!indio_dev)
280 return -ENOMEM;
281 platform_set_drvdata(pdev, indio_dev);
282
283 als_state = iio_priv(indio_dev);
284 als_state->common_attributes.hsdev = hsdev;
285 als_state->common_attributes.pdev = pdev;
286
287 ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS,
288 &als_state->common_attributes);
289 if (ret) {
290 dev_err(&pdev->dev, "failed to setup common attributes\n");
291 return ret;
292 }
293
294 indio_dev->channels = kmemdup(als_channels,
295 sizeof(als_channels), GFP_KERNEL);
296 if (!indio_dev->channels) {
297 dev_err(&pdev->dev, "failed to duplicate channels\n");
298 return -ENOMEM;
299 }
300
301 ret = als_parse_report(pdev, hsdev,
302 (struct iio_chan_spec *)indio_dev->channels,
303 HID_USAGE_SENSOR_ALS, als_state);
304 if (ret) {
305 dev_err(&pdev->dev, "failed to setup attributes\n");
306 goto error_free_dev_mem;
307 }
308
309 indio_dev->num_channels =
310 ARRAY_SIZE(als_channels);
311 indio_dev->info = &als_info;
312 indio_dev->name = name;
313 indio_dev->modes = INDIO_DIRECT_MODE;
314
315 atomic_set(&als_state->common_attributes.data_ready, 0);
316
317 ret = hid_sensor_setup_trigger(indio_dev, name,
318 &als_state->common_attributes);
319 if (ret < 0) {
320 dev_err(&pdev->dev, "trigger setup failed\n");
321 goto error_free_dev_mem;
322 }
323
324 ret = iio_device_register(indio_dev);
325 if (ret) {
326 dev_err(&pdev->dev, "device register failed\n");
327 goto error_remove_trigger;
328 }
329
330 als_state->callbacks.send_event = als_proc_event;
331 als_state->callbacks.capture_sample = als_capture_sample;
332 als_state->callbacks.pdev = pdev;
333 ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
334 &als_state->callbacks);
335 if (ret < 0) {
336 dev_err(&pdev->dev, "callback reg failed\n");
337 goto error_iio_unreg;
338 }
339
340 return ret;
341
342error_iio_unreg:
343 iio_device_unregister(indio_dev);
344error_remove_trigger:
345 hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
346error_free_dev_mem:
347 kfree(indio_dev->channels);
348 return ret;
349}
350
351/* Function to deinitialize the processing for usage id */
352static int hid_als_remove(struct platform_device *pdev)
353{
354 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
355 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
356 struct als_state *als_state = iio_priv(indio_dev);
357
358 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
359 iio_device_unregister(indio_dev);
360 hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
361 kfree(indio_dev->channels);
362
363 return 0;
364}
365
366static const struct platform_device_id hid_als_ids[] = {
367 {
368 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
369 .name = "HID-SENSOR-200041",
370 },
371 { /* sentinel */ }
372};
373MODULE_DEVICE_TABLE(platform, hid_als_ids);
374
375static struct platform_driver hid_als_platform_driver = {
376 .id_table = hid_als_ids,
377 .driver = {
378 .name = KBUILD_MODNAME,
379 .pm = &hid_sensor_pm_ops,
380 },
381 .probe = hid_als_probe,
382 .remove = hid_als_remove,
383};
384module_platform_driver(hid_als_platform_driver);
385
386MODULE_DESCRIPTION("HID Sensor ALS");
387MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
388MODULE_LICENSE("GPL");