380 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HID Sensors Driver4 * 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 15enum 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_MAX23 24static 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 30static const char *const hinge_labels[CHANNEL_SCAN_INDEX_MAX] = { "hinge",31 "screen",32 "keyboard" };33 34struct 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 52static const u32 hinge_sensitivity_addresses[] = {53 HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1),54};55 56/* Channel definitions */57static 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 */102static 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 */109static 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->common_attributes, 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->common_attributes, false);126 return -EINVAL;127 }128 129 *val = sensor_hub_input_attr_get_raw_value(st->common_attributes.hsdev,130 hsdev->usage,131 hinge_addresses[chan->scan_index],132 report_id,133 SENSOR_HUB_SYNC, min < 0);134 135 hid_sensor_power_state(&st->common_attributes, 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->common_attributes,146 val, val2);147 case IIO_CHAN_INFO_HYSTERESIS:148 return hid_sensor_read_raw_hyst_value(&st->common_attributes,149 val, val2);150 default:151 return -EINVAL;152 }153}154 155/* Channel write_raw handler */156static 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->common_attributes,165 val, val2);166 case IIO_CHAN_INFO_HYSTERESIS:167 return hid_sensor_write_raw_hyst_value(&st->common_attributes,168 val, val2);169 default:170 return -EINVAL;171 }172}173 174static 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(label, "%s\n", st->labels[chan->channel]);180}181 182static 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 received190 * and captured.191 */192static 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(priv);196 struct hinge_state *st = iio_priv(indio_dev);197 198 if (atomic_read(&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, &st->scan,203 st->timestamp);204 205 st->timestamp = 0;206 }207 return 0;208}209 210/* Capture samples in local storage */211static 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(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->common_attributes,228 *(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 */236static 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 HID_INPUT_REPORT,247 usage_id,248 hinge_addresses[i],249 &st->hinge[i]);250 if (ret < 0)251 return ret;252 253 hinge_adjust_channel_realbits(channels, i, st->hinge[i].size);254 }255 256 st->scale_precision = hid_sensor_format_scale(HID_USAGE_SENSOR_HINGE,257 &st->hinge[CHANNEL_SCAN_INDEX_HINGE_ANGLE],258 &st->scale_pre_decml, &st->scale_post_decml);259 260 return ret;261}262 263/* Function to initialize the processing for usage id */264static 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(&pdev->dev, sizeof(*st));273 if (!indio_dev)274 return -ENOMEM;275 276 platform_set_drvdata(pdev, 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, hsdev->usage,286 &st->common_attributes,287 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(&indio_dev->dev, hinge_channels,296 sizeof(hinge_channels), GFP_KERNEL);297 if (!indio_dev->channels)298 return -ENOMEM;299 300 ret = hinge_parse_report(pdev, hsdev,301 (struct iio_chan_spec *)indio_dev->channels,302 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(&st->common_attributes.data_ready, 0);313 ret = hid_sensor_setup_trigger(indio_dev, indio_dev->name,314 &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, hsdev->usage, &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 337error_remove_callback:338 sensor_hub_remove_callback(hsdev, hsdev->usage);339error_remove_trigger:340 hid_sensor_remove_trigger(indio_dev, &st->common_attributes);341 return ret;342}343 344/* Function to deinitialize the processing for usage id */345static 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, hsdev->usage);353 hid_sensor_remove_trigger(indio_dev, &st->common_attributes);354}355 356static 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};363MODULE_DEVICE_TABLE(platform, hid_hinge_ids);364 365static 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};374module_platform_driver(hid_hinge_platform_driver);375 376MODULE_DESCRIPTION("HID Sensor INTEL Hinge");377MODULE_AUTHOR("Ye Xiang <xiang.ye@intel.com>");378MODULE_LICENSE("GPL");379MODULE_IMPORT_NS(IIO_HID);380