xref: /linux/drivers/iio/gyro/hid-sensor-gyro-3d.c (revision 889600e21e3be388a6817c2a0dac0411df860751)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HID Sensors Driver
4  * Copyright (c) 2012, Intel Corporation.
5  */
6 #include <linux/bitops.h>
7 #include <linux/device.h>
8 #include <linux/platform_device.h>
9 #include <linux/module.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 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_MAX
24 struct 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 		aligned_s64 timestamp;
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 
39 static 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_AXIS
43 };
44 
45 static const u32 gyro_3d_sensitivity_addresses[] = {
46 	HID_USAGE_SENSOR_DATA_ANGL_VELOCITY,
47 };
48 
49 /* Channel definitions */
50 static 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 /* Channel read_raw handler */
gyro_3d_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)86 static int gyro_3d_read_raw(struct iio_dev *indio_dev,
87 			    struct iio_chan_spec const *chan,
88 			    int *val, int *val2, long mask)
89 {
90 	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
91 	int report_id = -1;
92 	u32 address;
93 	int ret_type;
94 	s32 min;
95 
96 	*val = 0;
97 	*val2 = 0;
98 	switch (mask) {
99 	case IIO_CHAN_INFO_RAW:
100 		hid_sensor_power_state(&gyro_state->common_attributes, true);
101 		report_id = gyro_state->gyro[chan->scan_index].report_id;
102 		min = gyro_state->gyro[chan->scan_index].logical_minimum;
103 		address = gyro_3d_addresses[chan->scan_index];
104 		if (report_id >= 0)
105 			*val = sensor_hub_input_attr_get_raw_value(
106 					gyro_state->common_attributes.hsdev,
107 					HID_USAGE_SENSOR_GYRO_3D, address,
108 					report_id,
109 					SENSOR_HUB_SYNC,
110 					min < 0);
111 		else {
112 			*val = 0;
113 			hid_sensor_power_state(&gyro_state->common_attributes, false);
114 			return -EINVAL;
115 		}
116 		hid_sensor_power_state(&gyro_state->common_attributes, false);
117 		ret_type = IIO_VAL_INT;
118 		break;
119 	case IIO_CHAN_INFO_SCALE:
120 		*val = gyro_state->scale_pre_decml;
121 		*val2 = gyro_state->scale_post_decml;
122 		ret_type = gyro_state->scale_precision;
123 		break;
124 	case IIO_CHAN_INFO_OFFSET:
125 		*val = gyro_state->value_offset;
126 		ret_type = IIO_VAL_INT;
127 		break;
128 	case IIO_CHAN_INFO_SAMP_FREQ:
129 		ret_type = hid_sensor_read_samp_freq_value(
130 			&gyro_state->common_attributes, val, val2);
131 		break;
132 	case IIO_CHAN_INFO_HYSTERESIS:
133 		ret_type = hid_sensor_read_raw_hyst_value(
134 			&gyro_state->common_attributes, val, val2);
135 		break;
136 	default:
137 		ret_type = -EINVAL;
138 		break;
139 	}
140 
141 	return ret_type;
142 }
143 
144 /* Channel write_raw handler */
gyro_3d_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)145 static int gyro_3d_write_raw(struct iio_dev *indio_dev,
146 			     struct iio_chan_spec const *chan,
147 			     int val, int val2, long mask)
148 {
149 	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
150 	int ret = 0;
151 
152 	switch (mask) {
153 	case IIO_CHAN_INFO_SAMP_FREQ:
154 		ret = hid_sensor_write_samp_freq_value(
155 				&gyro_state->common_attributes, val, val2);
156 		break;
157 	case IIO_CHAN_INFO_HYSTERESIS:
158 		ret = hid_sensor_write_raw_hyst_value(
159 				&gyro_state->common_attributes, val, val2);
160 		break;
161 	default:
162 		ret = -EINVAL;
163 	}
164 
165 	return ret;
166 }
167 
168 static const struct iio_info gyro_3d_info = {
169 	.read_raw = &gyro_3d_read_raw,
170 	.write_raw = &gyro_3d_write_raw,
171 };
172 
173 /* Callback handler to send event after all samples are received and captured */
gyro_3d_proc_event(struct hid_sensor_hub_device * hsdev,u32 usage_id,void * priv)174 static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
175 			      u32 usage_id, void *priv)
176 {
177 	struct iio_dev *indio_dev = platform_get_drvdata(priv);
178 	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
179 
180 	dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n");
181 	if (atomic_read(&gyro_state->common_attributes.data_ready)) {
182 		if (!gyro_state->timestamp)
183 			gyro_state->timestamp = iio_get_time_ns(indio_dev);
184 
185 		iio_push_to_buffers_with_timestamp(indio_dev, &gyro_state->scan,
186 						   gyro_state->timestamp);
187 
188 		gyro_state->timestamp = 0;
189 	}
190 
191 	return 0;
192 }
193 
194 /* Capture samples in local storage */
gyro_3d_capture_sample(struct hid_sensor_hub_device * hsdev,u32 usage_id,size_t raw_len,char * raw_data,void * priv)195 static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
196 				  u32 usage_id,
197 				  size_t raw_len, char *raw_data,
198 				  void *priv)
199 {
200 	struct iio_dev *indio_dev = platform_get_drvdata(priv);
201 	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
202 	int offset;
203 	int ret = -EINVAL;
204 
205 	switch (usage_id) {
206 	case HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS:
207 	case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS:
208 	case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS:
209 		offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS;
210 		gyro_state->scan.gyro_val[CHANNEL_SCAN_INDEX_X + offset] =
211 				*(u32 *)raw_data;
212 		ret = 0;
213 	break;
214 	case HID_USAGE_SENSOR_TIME_TIMESTAMP:
215 		gyro_state->timestamp =
216 			hid_sensor_convert_timestamp(&gyro_state->common_attributes,
217 						     *(s64 *)raw_data);
218 		ret = 0;
219 	break;
220 	default:
221 		break;
222 	}
223 
224 	return ret;
225 }
226 
227 /* Parse report which is specific to an usage id*/
gyro_3d_parse_report(struct platform_device * pdev,struct hid_sensor_hub_device * hsdev,struct iio_chan_spec * channels,u32 usage_id,struct gyro_3d_state * st)228 static int gyro_3d_parse_report(struct platform_device *pdev,
229 				struct hid_sensor_hub_device *hsdev,
230 				struct iio_chan_spec *channels,
231 				u32 usage_id,
232 				struct gyro_3d_state *st)
233 {
234 	int ret;
235 
236 	for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) {
237 		ret = sensor_hub_input_get_attribute_info(hsdev,
238 				HID_INPUT_REPORT,
239 				usage_id,
240 				HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + ch,
241 				&st->gyro[ch]);
242 		if (ret < 0)
243 			break;
244 		channels[ch].scan_type = (struct iio_scan_type) {
245 			.format = 's',
246 			.realbits = BYTES_TO_BITS(st->gyro[ch].size),
247 			.storagebits = BITS_PER_TYPE(u32),
248 		};
249 	}
250 	dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n",
251 		st->gyro[0].index,
252 		st->gyro[0].report_id,
253 		st->gyro[1].index, st->gyro[1].report_id,
254 		st->gyro[2].index, st->gyro[2].report_id);
255 
256 	st->scale_precision = hid_sensor_format_scale(
257 				HID_USAGE_SENSOR_GYRO_3D,
258 				&st->gyro[CHANNEL_SCAN_INDEX_X],
259 				&st->scale_pre_decml, &st->scale_post_decml);
260 
261 	return ret;
262 }
263 
264 /* Function to initialize the processing for usage id */
hid_gyro_3d_probe(struct platform_device * pdev)265 static int hid_gyro_3d_probe(struct platform_device *pdev)
266 {
267 	struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
268 	int ret = 0;
269 	static const char *name = "gyro_3d";
270 	struct iio_dev *indio_dev;
271 	struct gyro_3d_state *gyro_state;
272 
273 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));
274 	if (!indio_dev)
275 		return -ENOMEM;
276 	platform_set_drvdata(pdev, indio_dev);
277 
278 	gyro_state = iio_priv(indio_dev);
279 	gyro_state->common_attributes.hsdev = hsdev;
280 	gyro_state->common_attributes.pdev = pdev;
281 
282 	ret = hid_sensor_parse_common_attributes(hsdev,
283 						HID_USAGE_SENSOR_GYRO_3D,
284 						&gyro_state->common_attributes,
285 						gyro_3d_sensitivity_addresses,
286 						ARRAY_SIZE(gyro_3d_sensitivity_addresses));
287 	if (ret) {
288 		dev_err(&pdev->dev, "failed to setup common attributes\n");
289 		return ret;
290 	}
291 
292 	indio_dev->channels = devm_kmemdup(&pdev->dev, gyro_3d_channels,
293 					   sizeof(gyro_3d_channels), GFP_KERNEL);
294 	if (!indio_dev->channels) {
295 		dev_err(&pdev->dev, "failed to duplicate channels\n");
296 		return -ENOMEM;
297 	}
298 
299 	ret = gyro_3d_parse_report(pdev, hsdev,
300 				   (struct iio_chan_spec *)indio_dev->channels,
301 				   HID_USAGE_SENSOR_GYRO_3D, gyro_state);
302 	if (ret) {
303 		dev_err(&pdev->dev, "failed to setup attributes\n");
304 		return ret;
305 	}
306 
307 	indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
308 	indio_dev->info = &gyro_3d_info;
309 	indio_dev->name = name;
310 	indio_dev->modes = INDIO_DIRECT_MODE;
311 
312 	atomic_set(&gyro_state->common_attributes.data_ready, 0);
313 
314 	ret = hid_sensor_setup_trigger(indio_dev, name,
315 				       &gyro_state->common_attributes);
316 	if (ret < 0) {
317 		dev_err(&pdev->dev, "trigger setup failed\n");
318 		return ret;
319 	}
320 
321 	gyro_state->callbacks.send_event = gyro_3d_proc_event;
322 	gyro_state->callbacks.capture_sample = gyro_3d_capture_sample;
323 	gyro_state->callbacks.pdev = pdev;
324 	ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D,
325 					   &gyro_state->callbacks);
326 	if (ret < 0) {
327 		dev_err(&pdev->dev, "callback reg failed\n");
328 		goto error_remove_trigger;
329 	}
330 
331 	ret = iio_device_register(indio_dev);
332 	if (ret) {
333 		dev_err(&pdev->dev, "device register failed\n");
334 		goto error_remove_callback;
335 	}
336 
337 	return ret;
338 
339 error_remove_callback:
340 	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
341 error_remove_trigger:
342 	hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
343 	return ret;
344 }
345 
346 /* Function to deinitialize the processing for usage id */
hid_gyro_3d_remove(struct platform_device * pdev)347 static void hid_gyro_3d_remove(struct platform_device *pdev)
348 {
349 	struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
350 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
351 	struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
352 
353 	iio_device_unregister(indio_dev);
354 	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
355 	hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
356 }
357 
358 static const struct platform_device_id hid_gyro_3d_ids[] = {
359 	{
360 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
361 		.name = "HID-SENSOR-200076",
362 	},
363 	{ }
364 };
365 MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids);
366 
367 static struct platform_driver hid_gyro_3d_platform_driver = {
368 	.id_table = hid_gyro_3d_ids,
369 	.driver = {
370 		.name	= KBUILD_MODNAME,
371 		.pm	= &hid_sensor_pm_ops,
372 	},
373 	.probe		= hid_gyro_3d_probe,
374 	.remove		= hid_gyro_3d_remove,
375 };
376 module_platform_driver(hid_gyro_3d_platform_driver);
377 
378 MODULE_DESCRIPTION("HID Sensor Gyroscope 3D");
379 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
380 MODULE_LICENSE("GPL");
381 MODULE_IMPORT_NS("IIO_HID");
382