linux/drivers/iio/orientation/hid-sensor-rotation.c
<<
>>
Prefs
   1/*
   2 * HID Sensors Driver
   3 * Copyright (c) 2014, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 */
  14
  15#include <linux/device.h>
  16#include <linux/platform_device.h>
  17#include <linux/module.h>
  18#include <linux/interrupt.h>
  19#include <linux/irq.h>
  20#include <linux/slab.h>
  21#include <linux/hid-sensor-hub.h>
  22#include <linux/iio/iio.h>
  23#include <linux/iio/sysfs.h>
  24#include <linux/iio/buffer.h>
  25#include <linux/iio/trigger_consumer.h>
  26#include <linux/iio/triggered_buffer.h>
  27#include "../common/hid-sensors/hid-sensor-trigger.h"
  28
  29struct dev_rot_state {
  30        struct hid_sensor_hub_callbacks callbacks;
  31        struct hid_sensor_common common_attributes;
  32        struct hid_sensor_hub_attribute_info quaternion;
  33        u32 sampled_vals[4];
  34        int scale_pre_decml;
  35        int scale_post_decml;
  36        int scale_precision;
  37        int value_offset;
  38};
  39
  40/* Channel definitions */
  41static const struct iio_chan_spec dev_rot_channels[] = {
  42        {
  43                .type = IIO_ROT,
  44                .modified = 1,
  45                .channel2 = IIO_MOD_QUATERNION,
  46                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  47                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
  48                                        BIT(IIO_CHAN_INFO_OFFSET) |
  49                                        BIT(IIO_CHAN_INFO_SCALE) |
  50                                        BIT(IIO_CHAN_INFO_HYSTERESIS)
  51        }
  52};
  53
  54/* Adjust channel real bits based on report descriptor */
  55static void dev_rot_adjust_channel_bit_mask(struct iio_chan_spec *chan,
  56                                                int size)
  57{
  58        chan->scan_type.sign = 's';
  59        /* Real storage bits will change based on the report desc. */
  60        chan->scan_type.realbits = size * 8;
  61        /* Maximum size of a sample to capture is u32 */
  62        chan->scan_type.storagebits = sizeof(u32) * 8;
  63        chan->scan_type.repeat = 4;
  64}
  65
  66/* Channel read_raw handler */
  67static int dev_rot_read_raw(struct iio_dev *indio_dev,
  68                                struct iio_chan_spec const *chan,
  69                                int size, int *vals, int *val_len,
  70                                long mask)
  71{
  72        struct dev_rot_state *rot_state = iio_priv(indio_dev);
  73        int ret_type;
  74        int i;
  75
  76        vals[0] = 0;
  77        vals[1] = 0;
  78
  79        switch (mask) {
  80        case IIO_CHAN_INFO_RAW:
  81                if (size >= 4) {
  82                        for (i = 0; i < 4; ++i)
  83                                vals[i] = rot_state->sampled_vals[i];
  84                        ret_type = IIO_VAL_INT_MULTIPLE;
  85                        *val_len =  4;
  86                } else
  87                        ret_type = -EINVAL;
  88                break;
  89        case IIO_CHAN_INFO_SCALE:
  90                vals[0] = rot_state->scale_pre_decml;
  91                vals[1] = rot_state->scale_post_decml;
  92                return rot_state->scale_precision;
  93
  94        case IIO_CHAN_INFO_OFFSET:
  95                *vals = rot_state->value_offset;
  96                return IIO_VAL_INT;
  97
  98        case IIO_CHAN_INFO_SAMP_FREQ:
  99                ret_type = hid_sensor_read_samp_freq_value(
 100                        &rot_state->common_attributes, &vals[0], &vals[1]);
 101                break;
 102        case IIO_CHAN_INFO_HYSTERESIS:
 103                ret_type = hid_sensor_read_raw_hyst_value(
 104                        &rot_state->common_attributes, &vals[0], &vals[1]);
 105                break;
 106        default:
 107                ret_type = -EINVAL;
 108                break;
 109        }
 110
 111        return ret_type;
 112}
 113
 114/* Channel write_raw handler */
 115static int dev_rot_write_raw(struct iio_dev *indio_dev,
 116                               struct iio_chan_spec const *chan,
 117                               int val,
 118                               int val2,
 119                               long mask)
 120{
 121        struct dev_rot_state *rot_state = iio_priv(indio_dev);
 122        int ret;
 123
 124        switch (mask) {
 125        case IIO_CHAN_INFO_SAMP_FREQ:
 126                ret = hid_sensor_write_samp_freq_value(
 127                                &rot_state->common_attributes, val, val2);
 128                break;
 129        case IIO_CHAN_INFO_HYSTERESIS:
 130                ret = hid_sensor_write_raw_hyst_value(
 131                                &rot_state->common_attributes, val, val2);
 132                break;
 133        default:
 134                ret = -EINVAL;
 135        }
 136
 137        return ret;
 138}
 139
 140static const struct iio_info dev_rot_info = {
 141        .read_raw_multi = &dev_rot_read_raw,
 142        .write_raw = &dev_rot_write_raw,
 143};
 144
 145/* Function to push data to buffer */
 146static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
 147{
 148        dev_dbg(&indio_dev->dev, "hid_sensor_push_data >>\n");
 149        iio_push_to_buffers(indio_dev, (u8 *)data);
 150        dev_dbg(&indio_dev->dev, "hid_sensor_push_data <<\n");
 151
 152}
 153
 154/* Callback handler to send event after all samples are received and captured */
 155static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
 156                                unsigned usage_id,
 157                                void *priv)
 158{
 159        struct iio_dev *indio_dev = platform_get_drvdata(priv);
 160        struct dev_rot_state *rot_state = iio_priv(indio_dev);
 161
 162        dev_dbg(&indio_dev->dev, "dev_rot_proc_event\n");
 163        if (atomic_read(&rot_state->common_attributes.data_ready))
 164                hid_sensor_push_data(indio_dev,
 165                                (u8 *)rot_state->sampled_vals,
 166                                sizeof(rot_state->sampled_vals));
 167
 168        return 0;
 169}
 170
 171/* Capture samples in local storage */
 172static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
 173                                unsigned usage_id,
 174                                size_t raw_len, char *raw_data,
 175                                void *priv)
 176{
 177        struct iio_dev *indio_dev = platform_get_drvdata(priv);
 178        struct dev_rot_state *rot_state = iio_priv(indio_dev);
 179
 180        if (usage_id == HID_USAGE_SENSOR_ORIENT_QUATERNION) {
 181                memcpy(rot_state->sampled_vals, raw_data,
 182                                        sizeof(rot_state->sampled_vals));
 183                dev_dbg(&indio_dev->dev, "Recd Quat len:%zu::%zu\n", raw_len,
 184                                        sizeof(rot_state->sampled_vals));
 185        }
 186
 187        return 0;
 188}
 189
 190/* Parse report which is specific to an usage id*/
 191static int dev_rot_parse_report(struct platform_device *pdev,
 192                                struct hid_sensor_hub_device *hsdev,
 193                                struct iio_chan_spec *channels,
 194                                unsigned usage_id,
 195                                struct dev_rot_state *st)
 196{
 197        int ret;
 198
 199        ret = sensor_hub_input_get_attribute_info(hsdev,
 200                                HID_INPUT_REPORT,
 201                                usage_id,
 202                                HID_USAGE_SENSOR_ORIENT_QUATERNION,
 203                                &st->quaternion);
 204        if (ret)
 205                return ret;
 206
 207        dev_rot_adjust_channel_bit_mask(&channels[0],
 208                st->quaternion.size / 4);
 209
 210        dev_dbg(&pdev->dev, "dev_rot %x:%x\n", st->quaternion.index,
 211                st->quaternion.report_id);
 212
 213        dev_dbg(&pdev->dev, "dev_rot: attrib size %d\n",
 214                                st->quaternion.size);
 215
 216        st->scale_precision = hid_sensor_format_scale(
 217                                hsdev->usage,
 218                                &st->quaternion,
 219                                &st->scale_pre_decml, &st->scale_post_decml);
 220
 221        /* Set Sensitivity field ids, when there is no individual modifier */
 222        if (st->common_attributes.sensitivity.index < 0) {
 223                sensor_hub_input_get_attribute_info(hsdev,
 224                        HID_FEATURE_REPORT, usage_id,
 225                        HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 226                        HID_USAGE_SENSOR_DATA_ORIENTATION,
 227                        &st->common_attributes.sensitivity);
 228                dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
 229                        st->common_attributes.sensitivity.index,
 230                        st->common_attributes.sensitivity.report_id);
 231        }
 232
 233        return 0;
 234}
 235
 236/* Function to initialize the processing for usage id */
 237static int hid_dev_rot_probe(struct platform_device *pdev)
 238{
 239        int ret;
 240        char *name;
 241        struct iio_dev *indio_dev;
 242        struct dev_rot_state *rot_state;
 243        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 244
 245        indio_dev = devm_iio_device_alloc(&pdev->dev,
 246                                          sizeof(struct dev_rot_state));
 247        if (indio_dev == NULL)
 248                return -ENOMEM;
 249
 250        platform_set_drvdata(pdev, indio_dev);
 251
 252        rot_state = iio_priv(indio_dev);
 253        rot_state->common_attributes.hsdev = hsdev;
 254        rot_state->common_attributes.pdev = pdev;
 255
 256        switch (hsdev->usage) {
 257        case HID_USAGE_SENSOR_DEVICE_ORIENTATION:
 258                name = "dev_rotation";
 259                break;
 260        case HID_USAGE_SENSOR_RELATIVE_ORIENTATION:
 261                name = "relative_orientation";
 262                break;
 263        case HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION:
 264                name = "geomagnetic_orientation";
 265                break;
 266        default:
 267                return -EINVAL;
 268        }
 269
 270        ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
 271                                &rot_state->common_attributes);
 272        if (ret) {
 273                dev_err(&pdev->dev, "failed to setup common attributes\n");
 274                return ret;
 275        }
 276
 277        indio_dev->channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
 278                                           sizeof(dev_rot_channels),
 279                                           GFP_KERNEL);
 280        if (!indio_dev->channels) {
 281                dev_err(&pdev->dev, "failed to duplicate channels\n");
 282                return -ENOMEM;
 283        }
 284
 285        ret = dev_rot_parse_report(pdev, hsdev,
 286                                   (struct iio_chan_spec *)indio_dev->channels,
 287                                        hsdev->usage, rot_state);
 288        if (ret) {
 289                dev_err(&pdev->dev, "failed to setup attributes\n");
 290                return ret;
 291        }
 292
 293        indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels);
 294        indio_dev->dev.parent = &pdev->dev;
 295        indio_dev->info = &dev_rot_info;
 296        indio_dev->name = name;
 297        indio_dev->modes = INDIO_DIRECT_MODE;
 298
 299        ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
 300                NULL, NULL);
 301        if (ret) {
 302                dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
 303                return ret;
 304        }
 305        atomic_set(&rot_state->common_attributes.data_ready, 0);
 306        ret = hid_sensor_setup_trigger(indio_dev, name,
 307                                        &rot_state->common_attributes);
 308        if (ret) {
 309                dev_err(&pdev->dev, "trigger setup failed\n");
 310                goto error_unreg_buffer_funcs;
 311        }
 312
 313        ret = iio_device_register(indio_dev);
 314        if (ret) {
 315                dev_err(&pdev->dev, "device register failed\n");
 316                goto error_remove_trigger;
 317        }
 318
 319        rot_state->callbacks.send_event = dev_rot_proc_event;
 320        rot_state->callbacks.capture_sample = dev_rot_capture_sample;
 321        rot_state->callbacks.pdev = pdev;
 322        ret = sensor_hub_register_callback(hsdev, hsdev->usage,
 323                                        &rot_state->callbacks);
 324        if (ret) {
 325                dev_err(&pdev->dev, "callback reg failed\n");
 326                goto error_iio_unreg;
 327        }
 328
 329        return 0;
 330
 331error_iio_unreg:
 332        iio_device_unregister(indio_dev);
 333error_remove_trigger:
 334        hid_sensor_remove_trigger(&rot_state->common_attributes);
 335error_unreg_buffer_funcs:
 336        iio_triggered_buffer_cleanup(indio_dev);
 337        return ret;
 338}
 339
 340/* Function to deinitialize the processing for usage id */
 341static int hid_dev_rot_remove(struct platform_device *pdev)
 342{
 343        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 344        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 345        struct dev_rot_state *rot_state = iio_priv(indio_dev);
 346
 347        sensor_hub_remove_callback(hsdev, hsdev->usage);
 348        iio_device_unregister(indio_dev);
 349        hid_sensor_remove_trigger(&rot_state->common_attributes);
 350        iio_triggered_buffer_cleanup(indio_dev);
 351
 352        return 0;
 353}
 354
 355static const struct platform_device_id hid_dev_rot_ids[] = {
 356        {
 357                /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 358                .name = "HID-SENSOR-20008a",
 359        },
 360        {
 361                /* Relative orientation(AG) sensor */
 362                .name = "HID-SENSOR-20008e",
 363        },
 364        {
 365                /* Geomagnetic orientation(AM) sensor */
 366                .name = "HID-SENSOR-2000c1",
 367        },
 368        { /* sentinel */ }
 369};
 370MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids);
 371
 372static struct platform_driver hid_dev_rot_platform_driver = {
 373        .id_table = hid_dev_rot_ids,
 374        .driver = {
 375                .name   = KBUILD_MODNAME,
 376                .pm     = &hid_sensor_pm_ops,
 377        },
 378        .probe          = hid_dev_rot_probe,
 379        .remove         = hid_dev_rot_remove,
 380};
 381module_platform_driver(hid_dev_rot_platform_driver);
 382
 383MODULE_DESCRIPTION("HID Sensor Device Rotation");
 384MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 385MODULE_LICENSE("GPL");
 386