brintos

brintos / linux-shallow public Read only

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