xref: /linux/drivers/iio/light/hid-sensor-als.c (revision 3df692169e8486fc3dd91fcd5ea81c27a0bac033)
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 <srinivas.pandruvada@intel.com>");
485 MODULE_LICENSE("GPL");
486 MODULE_IMPORT_NS(IIO_HID);
487