brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · 26c481d Raw
355 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HID Sensors Driver4 * Copyright (c) 2014, 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#define CHANNEL_SCAN_INDEX_PRESENCE 017 18struct prox_state {19	struct hid_sensor_hub_callbacks callbacks;20	struct hid_sensor_common common_attributes;21	struct hid_sensor_hub_attribute_info prox_attr;22	u32 human_presence;23	int scale_pre_decml;24	int scale_post_decml;25	int scale_precision;26};27 28static const u32 prox_sensitivity_addresses[] = {29	HID_USAGE_SENSOR_HUMAN_PRESENCE,30	HID_USAGE_SENSOR_DATA_PRESENCE,31};32 33/* Channel definitions */34static const struct iio_chan_spec prox_channels[] = {35	{36		.type = IIO_PROXIMITY,37		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),38		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |39		BIT(IIO_CHAN_INFO_SCALE) |40		BIT(IIO_CHAN_INFO_SAMP_FREQ) |41		BIT(IIO_CHAN_INFO_HYSTERESIS),42		.scan_index = CHANNEL_SCAN_INDEX_PRESENCE,43	}44};45 46/* Adjust channel real bits based on report descriptor */47static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels,48					int channel, int size)49{50	channels[channel].scan_type.sign = 's';51	/* Real storage bits will change based on the report desc. */52	channels[channel].scan_type.realbits = size * 8;53	/* Maximum size of a sample to capture is u32 */54	channels[channel].scan_type.storagebits = sizeof(u32) * 8;55}56 57/* Channel read_raw handler */58static int prox_read_raw(struct iio_dev *indio_dev,59			      struct iio_chan_spec const *chan,60			      int *val, int *val2,61			      long mask)62{63	struct prox_state *prox_state = iio_priv(indio_dev);64	struct hid_sensor_hub_device *hsdev;65	int report_id = -1;66	u32 address;67	int ret_type;68	s32 min;69 70	*val = 0;71	*val2 = 0;72	switch (mask) {73	case IIO_CHAN_INFO_RAW:74		switch (chan->scan_index) {75		case  CHANNEL_SCAN_INDEX_PRESENCE:76			report_id = prox_state->prox_attr.report_id;77			min = prox_state->prox_attr.logical_minimum;78			address = HID_USAGE_SENSOR_HUMAN_PRESENCE;79			hsdev = prox_state->common_attributes.hsdev;80			break;81		default:82			report_id = -1;83			break;84		}85		if (report_id >= 0) {86			hid_sensor_power_state(&prox_state->common_attributes,87						true);88			*val = sensor_hub_input_attr_get_raw_value(89				hsdev, hsdev->usage, address, report_id,90				SENSOR_HUB_SYNC, min < 0);91			hid_sensor_power_state(&prox_state->common_attributes,92						false);93		} else {94			*val = 0;95			return -EINVAL;96		}97		ret_type = IIO_VAL_INT;98		break;99	case IIO_CHAN_INFO_SCALE:100		*val = prox_state->scale_pre_decml;101		*val2 = prox_state->scale_post_decml;102		ret_type = prox_state->scale_precision;103		break;104	case IIO_CHAN_INFO_OFFSET:105		*val = hid_sensor_convert_exponent(106				prox_state->prox_attr.unit_expo);107		ret_type = IIO_VAL_INT;108		break;109	case IIO_CHAN_INFO_SAMP_FREQ:110		ret_type = hid_sensor_read_samp_freq_value(111				&prox_state->common_attributes, val, val2);112		break;113	case IIO_CHAN_INFO_HYSTERESIS:114		ret_type = hid_sensor_read_raw_hyst_value(115				&prox_state->common_attributes, val, val2);116		break;117	default:118		ret_type = -EINVAL;119		break;120	}121 122	return ret_type;123}124 125/* Channel write_raw handler */126static int prox_write_raw(struct iio_dev *indio_dev,127			       struct iio_chan_spec const *chan,128			       int val,129			       int val2,130			       long mask)131{132	struct prox_state *prox_state = iio_priv(indio_dev);133	int ret = 0;134 135	switch (mask) {136	case IIO_CHAN_INFO_SAMP_FREQ:137		ret = hid_sensor_write_samp_freq_value(138				&prox_state->common_attributes, val, val2);139		break;140	case IIO_CHAN_INFO_HYSTERESIS:141		ret = hid_sensor_write_raw_hyst_value(142				&prox_state->common_attributes, val, val2);143		break;144	default:145		ret = -EINVAL;146	}147 148	return ret;149}150 151static const struct iio_info prox_info = {152	.read_raw = &prox_read_raw,153	.write_raw = &prox_write_raw,154};155 156/* Function to push data to buffer */157static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,158					int len)159{160	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");161	iio_push_to_buffers(indio_dev, data);162}163 164/* Callback handler to send event after all samples are received and captured */165static int prox_proc_event(struct hid_sensor_hub_device *hsdev,166				unsigned usage_id,167				void *priv)168{169	struct iio_dev *indio_dev = platform_get_drvdata(priv);170	struct prox_state *prox_state = iio_priv(indio_dev);171 172	dev_dbg(&indio_dev->dev, "prox_proc_event\n");173	if (atomic_read(&prox_state->common_attributes.data_ready))174		hid_sensor_push_data(indio_dev,175				&prox_state->human_presence,176				sizeof(prox_state->human_presence));177 178	return 0;179}180 181/* Capture samples in local storage */182static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,183				unsigned usage_id,184				size_t raw_len, char *raw_data,185				void *priv)186{187	struct iio_dev *indio_dev = platform_get_drvdata(priv);188	struct prox_state *prox_state = iio_priv(indio_dev);189	int ret = -EINVAL;190 191	switch (usage_id) {192	case HID_USAGE_SENSOR_HUMAN_PRESENCE:193		switch (raw_len) {194		case 1:195			prox_state->human_presence = *(u8 *)raw_data;196			return 0;197		case 4:198			prox_state->human_presence = *(u32 *)raw_data;199			return 0;200		default:201			break;202		}203		break;204	}205 206	return ret;207}208 209/* Parse report which is specific to an usage id*/210static int prox_parse_report(struct platform_device *pdev,211				struct hid_sensor_hub_device *hsdev,212				struct iio_chan_spec *channels,213				unsigned usage_id,214				struct prox_state *st)215{216	int ret;217 218	ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,219			usage_id,220			HID_USAGE_SENSOR_HUMAN_PRESENCE,221			&st->prox_attr);222	if (ret < 0)223		return ret;224	prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE,225					st->prox_attr.size);226 227	dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index,228			st->prox_attr.report_id);229 230	return ret;231}232 233/* Function to initialize the processing for usage id */234static int hid_prox_probe(struct platform_device *pdev)235{236	int ret = 0;237	static const char *name = "prox";238	struct iio_dev *indio_dev;239	struct prox_state *prox_state;240	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;241 242	indio_dev = devm_iio_device_alloc(&pdev->dev,243				sizeof(struct prox_state));244	if (!indio_dev)245		return -ENOMEM;246	platform_set_drvdata(pdev, indio_dev);247 248	prox_state = iio_priv(indio_dev);249	prox_state->common_attributes.hsdev = hsdev;250	prox_state->common_attributes.pdev = pdev;251 252	ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,253					&prox_state->common_attributes,254					prox_sensitivity_addresses,255					ARRAY_SIZE(prox_sensitivity_addresses));256	if (ret) {257		dev_err(&pdev->dev, "failed to setup common attributes\n");258		return ret;259	}260 261	indio_dev->channels = devm_kmemdup(&pdev->dev, prox_channels,262					   sizeof(prox_channels), GFP_KERNEL);263	if (!indio_dev->channels) {264		dev_err(&pdev->dev, "failed to duplicate channels\n");265		return -ENOMEM;266	}267 268	ret = prox_parse_report(pdev, hsdev,269				(struct iio_chan_spec *)indio_dev->channels,270				hsdev->usage, prox_state);271	if (ret) {272		dev_err(&pdev->dev, "failed to setup attributes\n");273		return ret;274	}275 276	indio_dev->num_channels = ARRAY_SIZE(prox_channels);277	indio_dev->info = &prox_info;278	indio_dev->name = name;279	indio_dev->modes = INDIO_DIRECT_MODE;280 281	atomic_set(&prox_state->common_attributes.data_ready, 0);282 283	ret = hid_sensor_setup_trigger(indio_dev, name,284				&prox_state->common_attributes);285	if (ret) {286		dev_err(&pdev->dev, "trigger setup failed\n");287		return ret;288	}289 290	ret = iio_device_register(indio_dev);291	if (ret) {292		dev_err(&pdev->dev, "device register failed\n");293		goto error_remove_trigger;294	}295 296	prox_state->callbacks.send_event = prox_proc_event;297	prox_state->callbacks.capture_sample = prox_capture_sample;298	prox_state->callbacks.pdev = pdev;299	ret = sensor_hub_register_callback(hsdev, hsdev->usage,300					   &prox_state->callbacks);301	if (ret < 0) {302		dev_err(&pdev->dev, "callback reg failed\n");303		goto error_iio_unreg;304	}305 306	return ret;307 308error_iio_unreg:309	iio_device_unregister(indio_dev);310error_remove_trigger:311	hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);312	return ret;313}314 315/* Function to deinitialize the processing for usage id */316static void hid_prox_remove(struct platform_device *pdev)317{318	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;319	struct iio_dev *indio_dev = platform_get_drvdata(pdev);320	struct prox_state *prox_state = iio_priv(indio_dev);321 322	sensor_hub_remove_callback(hsdev, hsdev->usage);323	iio_device_unregister(indio_dev);324	hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);325}326 327static const struct platform_device_id hid_prox_ids[] = {328	{329		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */330		.name = "HID-SENSOR-200011",331	},332	{333		/* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */334		.name = "HID-SENSOR-LISS-0226",335	},336	{ /* sentinel */ }337};338MODULE_DEVICE_TABLE(platform, hid_prox_ids);339 340static struct platform_driver hid_prox_platform_driver = {341	.id_table = hid_prox_ids,342	.driver = {343		.name	= KBUILD_MODNAME,344		.pm	= &hid_sensor_pm_ops,345	},346	.probe		= hid_prox_probe,347	.remove_new	= hid_prox_remove,348};349module_platform_driver(hid_prox_platform_driver);350 351MODULE_DESCRIPTION("HID Sensor Proximity");352MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");353MODULE_LICENSE("GPL");354MODULE_IMPORT_NS(IIO_HID);355