brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · 59a38bf Raw
397 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 gyro_3d_channel {17	CHANNEL_SCAN_INDEX_X,18	CHANNEL_SCAN_INDEX_Y,19	CHANNEL_SCAN_INDEX_Z,20	GYRO_3D_CHANNEL_MAX,21};22 23#define CHANNEL_SCAN_INDEX_TIMESTAMP GYRO_3D_CHANNEL_MAX24struct gyro_3d_state {25	struct hid_sensor_hub_callbacks callbacks;26	struct hid_sensor_common common_attributes;27	struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX];28	struct {29		u32 gyro_val[GYRO_3D_CHANNEL_MAX];30		u64 timestamp __aligned(8);31	} scan;32	int scale_pre_decml;33	int scale_post_decml;34	int scale_precision;35	int value_offset;36	s64 timestamp;37};38 39static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {40	HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS,41	HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS,42	HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS43};44 45static const u32 gryo_3d_sensitivity_addresses[] = {46	HID_USAGE_SENSOR_DATA_ANGL_VELOCITY,47};48 49/* Channel definitions */50static const struct iio_chan_spec gyro_3d_channels[] = {51	{52		.type = IIO_ANGL_VEL,53		.modified = 1,54		.channel2 = IIO_MOD_X,55		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),56		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |57		BIT(IIO_CHAN_INFO_SCALE) |58		BIT(IIO_CHAN_INFO_SAMP_FREQ) |59		BIT(IIO_CHAN_INFO_HYSTERESIS),60		.scan_index = CHANNEL_SCAN_INDEX_X,61	}, {62		.type = IIO_ANGL_VEL,63		.modified = 1,64		.channel2 = IIO_MOD_Y,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		.scan_index = CHANNEL_SCAN_INDEX_Y,71	}, {72		.type = IIO_ANGL_VEL,73		.modified = 1,74		.channel2 = IIO_MOD_Z,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		.scan_index = CHANNEL_SCAN_INDEX_Z,81	},82	IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)83};84 85/* Adjust channel real bits based on report descriptor */86static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,87						int channel, int size)88{89	channels[channel].scan_type.sign = 's';90	/* Real storage bits will change based on the report desc. */91	channels[channel].scan_type.realbits = size * 8;92	/* Maximum size of a sample to capture is u32 */93	channels[channel].scan_type.storagebits = sizeof(u32) * 8;94}95 96/* Channel read_raw handler */97static int gyro_3d_read_raw(struct iio_dev *indio_dev,98			      struct iio_chan_spec const *chan,99			      int *val, int *val2,100			      long mask)101{102	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);103	int report_id = -1;104	u32 address;105	int ret_type;106	s32 min;107 108	*val = 0;109	*val2 = 0;110	switch (mask) {111	case IIO_CHAN_INFO_RAW:112		hid_sensor_power_state(&gyro_state->common_attributes, true);113		report_id = gyro_state->gyro[chan->scan_index].report_id;114		min = gyro_state->gyro[chan->scan_index].logical_minimum;115		address = gyro_3d_addresses[chan->scan_index];116		if (report_id >= 0)117			*val = sensor_hub_input_attr_get_raw_value(118					gyro_state->common_attributes.hsdev,119					HID_USAGE_SENSOR_GYRO_3D, address,120					report_id,121					SENSOR_HUB_SYNC,122					min < 0);123		else {124			*val = 0;125			hid_sensor_power_state(&gyro_state->common_attributes,126						false);127			return -EINVAL;128		}129		hid_sensor_power_state(&gyro_state->common_attributes, false);130		ret_type = IIO_VAL_INT;131		break;132	case IIO_CHAN_INFO_SCALE:133		*val = gyro_state->scale_pre_decml;134		*val2 = gyro_state->scale_post_decml;135		ret_type = gyro_state->scale_precision;136		break;137	case IIO_CHAN_INFO_OFFSET:138		*val = gyro_state->value_offset;139		ret_type = IIO_VAL_INT;140		break;141	case IIO_CHAN_INFO_SAMP_FREQ:142		ret_type = hid_sensor_read_samp_freq_value(143			&gyro_state->common_attributes, val, val2);144		break;145	case IIO_CHAN_INFO_HYSTERESIS:146		ret_type = hid_sensor_read_raw_hyst_value(147			&gyro_state->common_attributes, val, val2);148		break;149	default:150		ret_type = -EINVAL;151		break;152	}153 154	return ret_type;155}156 157/* Channel write_raw handler */158static int gyro_3d_write_raw(struct iio_dev *indio_dev,159			       struct iio_chan_spec const *chan,160			       int val,161			       int val2,162			       long mask)163{164	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);165	int ret = 0;166 167	switch (mask) {168	case IIO_CHAN_INFO_SAMP_FREQ:169		ret = hid_sensor_write_samp_freq_value(170				&gyro_state->common_attributes, val, val2);171		break;172	case IIO_CHAN_INFO_HYSTERESIS:173		ret = hid_sensor_write_raw_hyst_value(174				&gyro_state->common_attributes, val, val2);175		break;176	default:177		ret = -EINVAL;178	}179 180	return ret;181}182 183static const struct iio_info gyro_3d_info = {184	.read_raw = &gyro_3d_read_raw,185	.write_raw = &gyro_3d_write_raw,186};187 188/* Callback handler to send event after all samples are received and captured */189static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,190				unsigned usage_id,191				void *priv)192{193	struct iio_dev *indio_dev = platform_get_drvdata(priv);194	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);195 196	dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n");197	if (atomic_read(&gyro_state->common_attributes.data_ready)) {198		if (!gyro_state->timestamp)199			gyro_state->timestamp = iio_get_time_ns(indio_dev);200 201		iio_push_to_buffers_with_timestamp(indio_dev, &gyro_state->scan,202						   gyro_state->timestamp);203 204		gyro_state->timestamp = 0;205	}206 207	return 0;208}209 210/* Capture samples in local storage */211static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,212				unsigned usage_id,213				size_t raw_len, char *raw_data,214				void *priv)215{216	struct iio_dev *indio_dev = platform_get_drvdata(priv);217	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);218	int offset;219	int ret = -EINVAL;220 221	switch (usage_id) {222	case HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS:223	case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS:224	case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS:225		offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS;226		gyro_state->scan.gyro_val[CHANNEL_SCAN_INDEX_X + offset] =227				*(u32 *)raw_data;228		ret = 0;229	break;230	case HID_USAGE_SENSOR_TIME_TIMESTAMP:231		gyro_state->timestamp =232			hid_sensor_convert_timestamp(&gyro_state->common_attributes,233						     *(s64 *)raw_data);234		ret = 0;235	break;236	default:237		break;238	}239 240	return ret;241}242 243/* Parse report which is specific to an usage id*/244static int gyro_3d_parse_report(struct platform_device *pdev,245				struct hid_sensor_hub_device *hsdev,246				struct iio_chan_spec *channels,247				unsigned usage_id,248				struct gyro_3d_state *st)249{250	int ret;251	int i;252 253	for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {254		ret = sensor_hub_input_get_attribute_info(hsdev,255				HID_INPUT_REPORT,256				usage_id,257				HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i,258				&st->gyro[CHANNEL_SCAN_INDEX_X + i]);259		if (ret < 0)260			break;261		gyro_3d_adjust_channel_bit_mask(channels,262				CHANNEL_SCAN_INDEX_X + i,263				st->gyro[CHANNEL_SCAN_INDEX_X + i].size);264	}265	dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",266			st->gyro[0].index,267			st->gyro[0].report_id,268			st->gyro[1].index, st->gyro[1].report_id,269			st->gyro[2].index, st->gyro[2].report_id);270 271	st->scale_precision = hid_sensor_format_scale(272				HID_USAGE_SENSOR_GYRO_3D,273				&st->gyro[CHANNEL_SCAN_INDEX_X],274				&st->scale_pre_decml, &st->scale_post_decml);275 276	return ret;277}278 279/* Function to initialize the processing for usage id */280static int hid_gyro_3d_probe(struct platform_device *pdev)281{282	int ret = 0;283	static const char *name = "gyro_3d";284	struct iio_dev *indio_dev;285	struct gyro_3d_state *gyro_state;286	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;287 288	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));289	if (!indio_dev)290		return -ENOMEM;291	platform_set_drvdata(pdev, indio_dev);292 293	gyro_state = iio_priv(indio_dev);294	gyro_state->common_attributes.hsdev = hsdev;295	gyro_state->common_attributes.pdev = pdev;296 297	ret = hid_sensor_parse_common_attributes(hsdev,298						HID_USAGE_SENSOR_GYRO_3D,299						&gyro_state->common_attributes,300						gryo_3d_sensitivity_addresses,301						ARRAY_SIZE(gryo_3d_sensitivity_addresses));302	if (ret) {303		dev_err(&pdev->dev, "failed to setup common attributes\n");304		return ret;305	}306 307	indio_dev->channels = devm_kmemdup(&pdev->dev, gyro_3d_channels,308					   sizeof(gyro_3d_channels), GFP_KERNEL);309	if (!indio_dev->channels) {310		dev_err(&pdev->dev, "failed to duplicate channels\n");311		return -ENOMEM;312	}313 314	ret = gyro_3d_parse_report(pdev, hsdev,315				   (struct iio_chan_spec *)indio_dev->channels,316				   HID_USAGE_SENSOR_GYRO_3D, gyro_state);317	if (ret) {318		dev_err(&pdev->dev, "failed to setup attributes\n");319		return ret;320	}321 322	indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);323	indio_dev->info = &gyro_3d_info;324	indio_dev->name = name;325	indio_dev->modes = INDIO_DIRECT_MODE;326 327	atomic_set(&gyro_state->common_attributes.data_ready, 0);328 329	ret = hid_sensor_setup_trigger(indio_dev, name,330					&gyro_state->common_attributes);331	if (ret < 0) {332		dev_err(&pdev->dev, "trigger setup failed\n");333		return ret;334	}335 336	ret = iio_device_register(indio_dev);337	if (ret) {338		dev_err(&pdev->dev, "device register failed\n");339		goto error_remove_trigger;340	}341 342	gyro_state->callbacks.send_event = gyro_3d_proc_event;343	gyro_state->callbacks.capture_sample = gyro_3d_capture_sample;344	gyro_state->callbacks.pdev = pdev;345	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,346					&gyro_state->callbacks);347	if (ret < 0) {348		dev_err(&pdev->dev, "callback reg failed\n");349		goto error_iio_unreg;350	}351 352	return ret;353 354error_iio_unreg:355	iio_device_unregister(indio_dev);356error_remove_trigger:357	hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);358	return ret;359}360 361/* Function to deinitialize the processing for usage id */362static void hid_gyro_3d_remove(struct platform_device *pdev)363{364	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;365	struct iio_dev *indio_dev = platform_get_drvdata(pdev);366	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);367 368	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);369	iio_device_unregister(indio_dev);370	hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);371}372 373static const struct platform_device_id hid_gyro_3d_ids[] = {374	{375		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */376		.name = "HID-SENSOR-200076",377	},378	{ /* sentinel */ }379};380MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids);381 382static struct platform_driver hid_gyro_3d_platform_driver = {383	.id_table = hid_gyro_3d_ids,384	.driver = {385		.name	= KBUILD_MODNAME,386		.pm	= &hid_sensor_pm_ops,387	},388	.probe		= hid_gyro_3d_probe,389	.remove_new	= hid_gyro_3d_remove,390};391module_platform_driver(hid_gyro_3d_platform_driver);392 393MODULE_DESCRIPTION("HID Sensor Gyroscope 3D");394MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");395MODULE_LICENSE("GPL");396MODULE_IMPORT_NS(IIO_HID);397