1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * HID Sensors Driver |
4 | * Copyright (c) 2020, Intel Corporation. |
5 | */ |
6 | #include <linux/hid-sensor-hub.h> |
7 | #include <linux/iio/buffer.h> |
8 | #include <linux/iio/iio.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/module.h> |
11 | #include <linux/mod_devicetable.h> |
12 | |
13 | #include "../common/hid-sensors/hid-sensor-trigger.h" |
14 | |
15 | enum hinge_channel { |
16 | CHANNEL_SCAN_INDEX_HINGE_ANGLE, |
17 | CHANNEL_SCAN_INDEX_SCREEN_ANGLE, |
18 | CHANNEL_SCAN_INDEX_KEYBOARD_ANGLE, |
19 | CHANNEL_SCAN_INDEX_MAX, |
20 | }; |
21 | |
22 | #define CHANNEL_SCAN_INDEX_TIMESTAMP CHANNEL_SCAN_INDEX_MAX |
23 | |
24 | static const u32 hinge_addresses[CHANNEL_SCAN_INDEX_MAX] = { |
25 | HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1), |
26 | HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(2), |
27 | HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(3) |
28 | }; |
29 | |
30 | static const char *const hinge_labels[CHANNEL_SCAN_INDEX_MAX] = { "hinge" , |
31 | "screen" , |
32 | "keyboard" }; |
33 | |
34 | struct hinge_state { |
35 | struct iio_dev *indio_dev; |
36 | struct hid_sensor_hub_attribute_info hinge[CHANNEL_SCAN_INDEX_MAX]; |
37 | struct hid_sensor_hub_callbacks callbacks; |
38 | struct hid_sensor_common common_attributes; |
39 | const char *labels[CHANNEL_SCAN_INDEX_MAX]; |
40 | struct { |
41 | u32 hinge_val[3]; |
42 | u64 timestamp __aligned(8); |
43 | } scan; |
44 | |
45 | int scale_pre_decml; |
46 | int scale_post_decml; |
47 | int scale_precision; |
48 | int value_offset; |
49 | u64 timestamp; |
50 | }; |
51 | |
52 | static const u32 hinge_sensitivity_addresses[] = { |
53 | HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1), |
54 | }; |
55 | |
56 | /* Channel definitions */ |
57 | static const struct iio_chan_spec hinge_channels[] = { |
58 | { |
59 | .type = IIO_ANGL, |
60 | .indexed = 1, |
61 | .channel = 0, |
62 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
63 | .info_mask_shared_by_type = |
64 | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | |
65 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), |
66 | .scan_index = CHANNEL_SCAN_INDEX_HINGE_ANGLE, |
67 | .scan_type = { |
68 | .sign = 's', |
69 | .storagebits = 32, |
70 | }, |
71 | }, { |
72 | .type = IIO_ANGL, |
73 | .indexed = 1, |
74 | .channel = 1, |
75 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
76 | .info_mask_shared_by_type = |
77 | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | |
78 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), |
79 | .scan_index = CHANNEL_SCAN_INDEX_SCREEN_ANGLE, |
80 | .scan_type = { |
81 | .sign = 's', |
82 | .storagebits = 32, |
83 | }, |
84 | }, { |
85 | .type = IIO_ANGL, |
86 | .indexed = 1, |
87 | .channel = 2, |
88 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
89 | .info_mask_shared_by_type = |
90 | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | |
91 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), |
92 | .scan_index = CHANNEL_SCAN_INDEX_KEYBOARD_ANGLE, |
93 | .scan_type = { |
94 | .sign = 's', |
95 | .storagebits = 32, |
96 | }, |
97 | }, |
98 | IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) |
99 | }; |
100 | |
101 | /* Adjust channel real bits based on report descriptor */ |
102 | static void hinge_adjust_channel_realbits(struct iio_chan_spec *channels, |
103 | int channel, int size) |
104 | { |
105 | channels[channel].scan_type.realbits = size * 8; |
106 | } |
107 | |
108 | /* Channel read_raw handler */ |
109 | static int hinge_read_raw(struct iio_dev *indio_dev, |
110 | struct iio_chan_spec const *chan, int *val, int *val2, |
111 | long mask) |
112 | { |
113 | struct hinge_state *st = iio_priv(indio_dev); |
114 | struct hid_sensor_hub_device *hsdev; |
115 | int report_id; |
116 | s32 min; |
117 | |
118 | hsdev = st->common_attributes.hsdev; |
119 | switch (mask) { |
120 | case IIO_CHAN_INFO_RAW: |
121 | hid_sensor_power_state(st: &st->common_attributes, state: true); |
122 | report_id = st->hinge[chan->scan_index].report_id; |
123 | min = st->hinge[chan->scan_index].logical_minimum; |
124 | if (report_id < 0) { |
125 | hid_sensor_power_state(st: &st->common_attributes, state: false); |
126 | return -EINVAL; |
127 | } |
128 | |
129 | *val = sensor_hub_input_attr_get_raw_value(hsdev: st->common_attributes.hsdev, |
130 | usage_id: hsdev->usage, |
131 | attr_usage_id: hinge_addresses[chan->scan_index], |
132 | report_id, |
133 | flag: SENSOR_HUB_SYNC, is_signed: min < 0); |
134 | |
135 | hid_sensor_power_state(st: &st->common_attributes, state: false); |
136 | return IIO_VAL_INT; |
137 | case IIO_CHAN_INFO_SCALE: |
138 | *val = st->scale_pre_decml; |
139 | *val2 = st->scale_post_decml; |
140 | return st->scale_precision; |
141 | case IIO_CHAN_INFO_OFFSET: |
142 | *val = st->value_offset; |
143 | return IIO_VAL_INT; |
144 | case IIO_CHAN_INFO_SAMP_FREQ: |
145 | return hid_sensor_read_samp_freq_value(st: &st->common_attributes, |
146 | val1: val, val2); |
147 | case IIO_CHAN_INFO_HYSTERESIS: |
148 | return hid_sensor_read_raw_hyst_value(st: &st->common_attributes, |
149 | val1: val, val2); |
150 | default: |
151 | return -EINVAL; |
152 | } |
153 | } |
154 | |
155 | /* Channel write_raw handler */ |
156 | static int hinge_write_raw(struct iio_dev *indio_dev, |
157 | struct iio_chan_spec const *chan, int val, int val2, |
158 | long mask) |
159 | { |
160 | struct hinge_state *st = iio_priv(indio_dev); |
161 | |
162 | switch (mask) { |
163 | case IIO_CHAN_INFO_SAMP_FREQ: |
164 | return hid_sensor_write_samp_freq_value(st: &st->common_attributes, |
165 | val1: val, val2); |
166 | case IIO_CHAN_INFO_HYSTERESIS: |
167 | return hid_sensor_write_raw_hyst_value(st: &st->common_attributes, |
168 | val1: val, val2); |
169 | default: |
170 | return -EINVAL; |
171 | } |
172 | } |
173 | |
174 | static int hinge_read_label(struct iio_dev *indio_dev, |
175 | struct iio_chan_spec const *chan, char *label) |
176 | { |
177 | struct hinge_state *st = iio_priv(indio_dev); |
178 | |
179 | return sprintf(buf: label, fmt: "%s\n" , st->labels[chan->channel]); |
180 | } |
181 | |
182 | static const struct iio_info hinge_info = { |
183 | .read_raw = hinge_read_raw, |
184 | .write_raw = hinge_write_raw, |
185 | .read_label = hinge_read_label, |
186 | }; |
187 | |
188 | /* |
189 | * Callback handler to send event after all samples are received |
190 | * and captured. |
191 | */ |
192 | static int hinge_proc_event(struct hid_sensor_hub_device *hsdev, |
193 | unsigned int usage_id, void *priv) |
194 | { |
195 | struct iio_dev *indio_dev = platform_get_drvdata(pdev: priv); |
196 | struct hinge_state *st = iio_priv(indio_dev); |
197 | |
198 | if (atomic_read(v: &st->common_attributes.data_ready)) { |
199 | if (!st->timestamp) |
200 | st->timestamp = iio_get_time_ns(indio_dev); |
201 | |
202 | iio_push_to_buffers_with_timestamp(indio_dev, data: &st->scan, |
203 | timestamp: st->timestamp); |
204 | |
205 | st->timestamp = 0; |
206 | } |
207 | return 0; |
208 | } |
209 | |
210 | /* Capture samples in local storage */ |
211 | static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev, |
212 | unsigned int usage_id, size_t raw_len, |
213 | char *raw_data, void *priv) |
214 | { |
215 | struct iio_dev *indio_dev = platform_get_drvdata(pdev: priv); |
216 | struct hinge_state *st = iio_priv(indio_dev); |
217 | int offset; |
218 | |
219 | switch (usage_id) { |
220 | case HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1): |
221 | case HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(2): |
222 | case HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(3): |
223 | offset = usage_id - HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1); |
224 | st->scan.hinge_val[offset] = *(u32 *)raw_data; |
225 | return 0; |
226 | case HID_USAGE_SENSOR_TIME_TIMESTAMP: |
227 | st->timestamp = hid_sensor_convert_timestamp(st: &st->common_attributes, |
228 | raw_value: *(int64_t *)raw_data); |
229 | return 0; |
230 | default: |
231 | return -EINVAL; |
232 | } |
233 | } |
234 | |
235 | /* Parse report which is specific to an usage id */ |
236 | static int hinge_parse_report(struct platform_device *pdev, |
237 | struct hid_sensor_hub_device *hsdev, |
238 | struct iio_chan_spec *channels, |
239 | unsigned int usage_id, struct hinge_state *st) |
240 | { |
241 | int ret; |
242 | int i; |
243 | |
244 | for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; ++i) { |
245 | ret = sensor_hub_input_get_attribute_info(hsdev, |
246 | type: HID_INPUT_REPORT, |
247 | usage_id, |
248 | attr_usage_id: hinge_addresses[i], |
249 | info: &st->hinge[i]); |
250 | if (ret < 0) |
251 | return ret; |
252 | |
253 | hinge_adjust_channel_realbits(channels, channel: i, size: st->hinge[i].size); |
254 | } |
255 | |
256 | st->scale_precision = hid_sensor_format_scale(HID_USAGE_SENSOR_HINGE, |
257 | attr_info: &st->hinge[CHANNEL_SCAN_INDEX_HINGE_ANGLE], |
258 | val0: &st->scale_pre_decml, val1: &st->scale_post_decml); |
259 | |
260 | return ret; |
261 | } |
262 | |
263 | /* Function to initialize the processing for usage id */ |
264 | static int hid_hinge_probe(struct platform_device *pdev) |
265 | { |
266 | struct hinge_state *st; |
267 | struct iio_dev *indio_dev; |
268 | struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; |
269 | int ret; |
270 | int i; |
271 | |
272 | indio_dev = devm_iio_device_alloc(parent: &pdev->dev, sizeof_priv: sizeof(*st)); |
273 | if (!indio_dev) |
274 | return -ENOMEM; |
275 | |
276 | platform_set_drvdata(pdev, data: indio_dev); |
277 | |
278 | st = iio_priv(indio_dev); |
279 | st->common_attributes.hsdev = hsdev; |
280 | st->common_attributes.pdev = pdev; |
281 | st->indio_dev = indio_dev; |
282 | for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; i++) |
283 | st->labels[i] = hinge_labels[i]; |
284 | |
285 | ret = hid_sensor_parse_common_attributes(hsdev, usage_id: hsdev->usage, |
286 | st: &st->common_attributes, |
287 | sensitivity_addresses: hinge_sensitivity_addresses, |
288 | ARRAY_SIZE(hinge_sensitivity_addresses)); |
289 | if (ret) { |
290 | dev_err(&pdev->dev, "failed to setup common attributes\n" ); |
291 | return ret; |
292 | } |
293 | |
294 | indio_dev->num_channels = ARRAY_SIZE(hinge_channels); |
295 | indio_dev->channels = devm_kmemdup(dev: &indio_dev->dev, src: hinge_channels, |
296 | len: sizeof(hinge_channels), GFP_KERNEL); |
297 | if (!indio_dev->channels) |
298 | return -ENOMEM; |
299 | |
300 | ret = hinge_parse_report(pdev, hsdev, |
301 | channels: (struct iio_chan_spec *)indio_dev->channels, |
302 | usage_id: hsdev->usage, st); |
303 | if (ret) { |
304 | dev_err(&pdev->dev, "failed to setup attributes\n" ); |
305 | return ret; |
306 | } |
307 | |
308 | indio_dev->info = &hinge_info; |
309 | indio_dev->name = "hinge" ; |
310 | indio_dev->modes = INDIO_DIRECT_MODE; |
311 | |
312 | atomic_set(v: &st->common_attributes.data_ready, i: 0); |
313 | ret = hid_sensor_setup_trigger(indio_dev, name: indio_dev->name, |
314 | attrb: &st->common_attributes); |
315 | if (ret < 0) { |
316 | dev_err(&pdev->dev, "trigger setup failed\n" ); |
317 | return ret; |
318 | } |
319 | |
320 | st->callbacks.send_event = hinge_proc_event; |
321 | st->callbacks.capture_sample = hinge_capture_sample; |
322 | st->callbacks.pdev = pdev; |
323 | ret = sensor_hub_register_callback(hsdev, usage_id: hsdev->usage, usage_callback: &st->callbacks); |
324 | if (ret < 0) { |
325 | dev_err(&pdev->dev, "callback reg failed\n" ); |
326 | goto error_remove_trigger; |
327 | } |
328 | |
329 | ret = iio_device_register(indio_dev); |
330 | if (ret) { |
331 | dev_err(&pdev->dev, "device register failed\n" ); |
332 | goto error_remove_callback; |
333 | } |
334 | |
335 | return ret; |
336 | |
337 | error_remove_callback: |
338 | sensor_hub_remove_callback(hsdev, usage_id: hsdev->usage); |
339 | error_remove_trigger: |
340 | hid_sensor_remove_trigger(indio_dev, attrb: &st->common_attributes); |
341 | return ret; |
342 | } |
343 | |
344 | /* Function to deinitialize the processing for usage id */ |
345 | static void hid_hinge_remove(struct platform_device *pdev) |
346 | { |
347 | struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; |
348 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); |
349 | struct hinge_state *st = iio_priv(indio_dev); |
350 | |
351 | iio_device_unregister(indio_dev); |
352 | sensor_hub_remove_callback(hsdev, usage_id: hsdev->usage); |
353 | hid_sensor_remove_trigger(indio_dev, attrb: &st->common_attributes); |
354 | } |
355 | |
356 | static const struct platform_device_id hid_hinge_ids[] = { |
357 | { |
358 | /* Format: HID-SENSOR-INT-usage_id_in_hex_lowercase */ |
359 | .name = "HID-SENSOR-INT-020b" , |
360 | }, |
361 | { /* sentinel */ } |
362 | }; |
363 | MODULE_DEVICE_TABLE(platform, hid_hinge_ids); |
364 | |
365 | static struct platform_driver hid_hinge_platform_driver = { |
366 | .id_table = hid_hinge_ids, |
367 | .driver = { |
368 | .name = KBUILD_MODNAME, |
369 | .pm = &hid_sensor_pm_ops, |
370 | }, |
371 | .probe = hid_hinge_probe, |
372 | .remove_new = hid_hinge_remove, |
373 | }; |
374 | module_platform_driver(hid_hinge_platform_driver); |
375 | |
376 | MODULE_DESCRIPTION("HID Sensor INTEL Hinge" ); |
377 | MODULE_AUTHOR("Ye Xiang <xiang.ye@intel.com>" ); |
378 | MODULE_LICENSE("GPL" ); |
379 | MODULE_IMPORT_NS(IIO_HID); |
380 | |