File Index
Files and directories
Sign in
FILE

hid-sensor-press.c

File preview with syntax highlighting.

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