linux/drivers/iio/position/hid-sensor-custom-intel-hinge.c
<<
>>
Prefs
   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
  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_MAX
  23
  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 received
 190 * 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 int 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        return 0;
 356}
 357
 358static const struct platform_device_id hid_hinge_ids[] = {
 359        {
 360                /* Format: HID-SENSOR-INT-usage_id_in_hex_lowercase */
 361                .name = "HID-SENSOR-INT-020b",
 362        },
 363        { /* sentinel */ }
 364};
 365MODULE_DEVICE_TABLE(platform, hid_hinge_ids);
 366
 367static struct platform_driver hid_hinge_platform_driver = {
 368        .id_table = hid_hinge_ids,
 369        .driver = {
 370                .name   = KBUILD_MODNAME,
 371                .pm     = &hid_sensor_pm_ops,
 372        },
 373        .probe          = hid_hinge_probe,
 374        .remove         = hid_hinge_remove,
 375};
 376module_platform_driver(hid_hinge_platform_driver);
 377
 378MODULE_DESCRIPTION("HID Sensor INTEL Hinge");
 379MODULE_AUTHOR("Ye Xiang <xiang.ye@intel.com>");
 380MODULE_LICENSE("GPL");
 381MODULE_IMPORT_NS(IIO_HID);
 382