linux/drivers/iio/magnetometer/hid-sensor-magn-3d.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * HID Sensors Driver
   4 * Copyright (c) 2012, Intel Corporation.
   5 */
   6#include <linux/device.h>
   7#include <linux/platform_device.h>
   8#include <linux/module.h>
   9#include <linux/interrupt.h>
  10#include <linux/irq.h>
  11#include <linux/slab.h>
  12#include <linux/delay.h>
  13#include <linux/hid-sensor-hub.h>
  14#include <linux/iio/iio.h>
  15#include <linux/iio/sysfs.h>
  16#include <linux/iio/buffer.h>
  17#include <linux/iio/trigger_consumer.h>
  18#include <linux/iio/triggered_buffer.h>
  19#include "../common/hid-sensors/hid-sensor-trigger.h"
  20
  21enum magn_3d_channel {
  22        CHANNEL_SCAN_INDEX_X,
  23        CHANNEL_SCAN_INDEX_Y,
  24        CHANNEL_SCAN_INDEX_Z,
  25        CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP,
  26        CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
  27        CHANNEL_SCAN_INDEX_NORTH_MAGN,
  28        CHANNEL_SCAN_INDEX_NORTH_TRUE,
  29        MAGN_3D_CHANNEL_MAX,
  30};
  31
  32struct common_attributes {
  33        int scale_pre_decml;
  34        int scale_post_decml;
  35        int scale_precision;
  36        int value_offset;
  37};
  38
  39struct magn_3d_state {
  40        struct hid_sensor_hub_callbacks callbacks;
  41        struct hid_sensor_common magn_flux_attributes;
  42        struct hid_sensor_common rot_attributes;
  43        struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
  44
  45        /* dynamically sized array to hold sensor values */
  46        u32 *iio_vals;
  47        /* array of pointers to sensor value */
  48        u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX];
  49
  50        struct common_attributes magn_flux_attr;
  51        struct common_attributes rot_attr;
  52};
  53
  54static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
  55        HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS,
  56        HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS,
  57        HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS,
  58        HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
  59        HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH,
  60        HID_USAGE_SENSOR_ORIENT_MAGN_NORTH,
  61        HID_USAGE_SENSOR_ORIENT_TRUE_NORTH,
  62};
  63
  64/* Channel definitions */
  65static const struct iio_chan_spec magn_3d_channels[] = {
  66        {
  67                .type = IIO_MAGN,
  68                .modified = 1,
  69                .channel2 = IIO_MOD_X,
  70                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  71                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  72                BIT(IIO_CHAN_INFO_SCALE) |
  73                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
  74                BIT(IIO_CHAN_INFO_HYSTERESIS),
  75        }, {
  76                .type = IIO_MAGN,
  77                .modified = 1,
  78                .channel2 = IIO_MOD_Y,
  79                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  80                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  81                BIT(IIO_CHAN_INFO_SCALE) |
  82                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
  83                BIT(IIO_CHAN_INFO_HYSTERESIS),
  84        }, {
  85                .type = IIO_MAGN,
  86                .modified = 1,
  87                .channel2 = IIO_MOD_Z,
  88                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  89                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  90                BIT(IIO_CHAN_INFO_SCALE) |
  91                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
  92                BIT(IIO_CHAN_INFO_HYSTERESIS),
  93        }, {
  94                .type = IIO_ROT,
  95                .modified = 1,
  96                .channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP,
  97                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  98                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  99                BIT(IIO_CHAN_INFO_SCALE) |
 100                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 101                BIT(IIO_CHAN_INFO_HYSTERESIS),
 102        }, {
 103                .type = IIO_ROT,
 104                .modified = 1,
 105                .channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP,
 106                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 107                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 108                BIT(IIO_CHAN_INFO_SCALE) |
 109                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 110                BIT(IIO_CHAN_INFO_HYSTERESIS),
 111        }, {
 112                .type = IIO_ROT,
 113                .modified = 1,
 114                .channel2 = IIO_MOD_NORTH_MAGN,
 115                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 116                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 117                BIT(IIO_CHAN_INFO_SCALE) |
 118                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 119                BIT(IIO_CHAN_INFO_HYSTERESIS),
 120        }, {
 121                .type = IIO_ROT,
 122                .modified = 1,
 123                .channel2 = IIO_MOD_NORTH_TRUE,
 124                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 125                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 126                BIT(IIO_CHAN_INFO_SCALE) |
 127                BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 128                BIT(IIO_CHAN_INFO_HYSTERESIS),
 129        }
 130};
 131
 132/* Adjust channel real bits based on report descriptor */
 133static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
 134                                                int channel, int size)
 135{
 136        channels[channel].scan_type.sign = 's';
 137        /* Real storage bits will change based on the report desc. */
 138        channels[channel].scan_type.realbits = size * 8;
 139        /* Maximum size of a sample to capture is u32 */
 140        channels[channel].scan_type.storagebits = sizeof(u32) * 8;
 141}
 142
 143/* Channel read_raw handler */
 144static int magn_3d_read_raw(struct iio_dev *indio_dev,
 145                              struct iio_chan_spec const *chan,
 146                              int *val, int *val2,
 147                              long mask)
 148{
 149        struct magn_3d_state *magn_state = iio_priv(indio_dev);
 150        int report_id = -1;
 151        u32 address;
 152        int ret_type;
 153        s32 min;
 154
 155        *val = 0;
 156        *val2 = 0;
 157        switch (mask) {
 158        case IIO_CHAN_INFO_RAW:
 159                hid_sensor_power_state(&magn_state->magn_flux_attributes, true);
 160                report_id = magn_state->magn[chan->address].report_id;
 161                min = magn_state->magn[chan->address].logical_minimum;
 162                address = magn_3d_addresses[chan->address];
 163                if (report_id >= 0)
 164                        *val = sensor_hub_input_attr_get_raw_value(
 165                                magn_state->magn_flux_attributes.hsdev,
 166                                HID_USAGE_SENSOR_COMPASS_3D, address,
 167                                report_id,
 168                                SENSOR_HUB_SYNC,
 169                                min < 0);
 170                else {
 171                        *val = 0;
 172                        hid_sensor_power_state(
 173                                &magn_state->magn_flux_attributes,
 174                                false);
 175                        return -EINVAL;
 176                }
 177                hid_sensor_power_state(&magn_state->magn_flux_attributes,
 178                                        false);
 179                ret_type = IIO_VAL_INT;
 180                break;
 181        case IIO_CHAN_INFO_SCALE:
 182                switch (chan->type) {
 183                case IIO_MAGN:
 184                        *val = magn_state->magn_flux_attr.scale_pre_decml;
 185                        *val2 = magn_state->magn_flux_attr.scale_post_decml;
 186                        ret_type = magn_state->magn_flux_attr.scale_precision;
 187                        break;
 188                case IIO_ROT:
 189                        *val = magn_state->rot_attr.scale_pre_decml;
 190                        *val2 = magn_state->rot_attr.scale_post_decml;
 191                        ret_type = magn_state->rot_attr.scale_precision;
 192                        break;
 193                default:
 194                        ret_type = -EINVAL;
 195                }
 196                break;
 197        case IIO_CHAN_INFO_OFFSET:
 198                switch (chan->type) {
 199                case IIO_MAGN:
 200                        *val = magn_state->magn_flux_attr.value_offset;
 201                        ret_type = IIO_VAL_INT;
 202                        break;
 203                case IIO_ROT:
 204                        *val = magn_state->rot_attr.value_offset;
 205                        ret_type = IIO_VAL_INT;
 206                        break;
 207                default:
 208                        ret_type = -EINVAL;
 209                }
 210                break;
 211        case IIO_CHAN_INFO_SAMP_FREQ:
 212                ret_type = hid_sensor_read_samp_freq_value(
 213                        &magn_state->magn_flux_attributes, val, val2);
 214                break;
 215        case IIO_CHAN_INFO_HYSTERESIS:
 216                switch (chan->type) {
 217                case IIO_MAGN:
 218                        ret_type = hid_sensor_read_raw_hyst_value(
 219                                &magn_state->magn_flux_attributes, val, val2);
 220                        break;
 221                case IIO_ROT:
 222                        ret_type = hid_sensor_read_raw_hyst_value(
 223                                &magn_state->rot_attributes, val, val2);
 224                        break;
 225                default:
 226                        ret_type = -EINVAL;
 227                }
 228                break;
 229        default:
 230                ret_type = -EINVAL;
 231                break;
 232        }
 233
 234        return ret_type;
 235}
 236
 237/* Channel write_raw handler */
 238static int magn_3d_write_raw(struct iio_dev *indio_dev,
 239                               struct iio_chan_spec const *chan,
 240                               int val,
 241                               int val2,
 242                               long mask)
 243{
 244        struct magn_3d_state *magn_state = iio_priv(indio_dev);
 245        int ret = 0;
 246
 247        switch (mask) {
 248        case IIO_CHAN_INFO_SAMP_FREQ:
 249                ret = hid_sensor_write_samp_freq_value(
 250                                &magn_state->magn_flux_attributes, val, val2);
 251                break;
 252        case IIO_CHAN_INFO_HYSTERESIS:
 253                switch (chan->type) {
 254                case IIO_MAGN:
 255                        ret = hid_sensor_write_raw_hyst_value(
 256                                &magn_state->magn_flux_attributes, val, val2);
 257                        break;
 258                case IIO_ROT:
 259                        ret = hid_sensor_write_raw_hyst_value(
 260                                &magn_state->rot_attributes, val, val2);
 261                        break;
 262                default:
 263                        ret = -EINVAL;
 264                }
 265                break;
 266        default:
 267                ret = -EINVAL;
 268        }
 269
 270        return ret;
 271}
 272
 273static const struct iio_info magn_3d_info = {
 274        .read_raw = &magn_3d_read_raw,
 275        .write_raw = &magn_3d_write_raw,
 276};
 277
 278/* Function to push data to buffer */
 279static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data)
 280{
 281        dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
 282        iio_push_to_buffers(indio_dev, data);
 283}
 284
 285/* Callback handler to send event after all samples are received and captured */
 286static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
 287                                unsigned usage_id,
 288                                void *priv)
 289{
 290        struct iio_dev *indio_dev = platform_get_drvdata(priv);
 291        struct magn_3d_state *magn_state = iio_priv(indio_dev);
 292
 293        dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
 294        if (atomic_read(&magn_state->magn_flux_attributes.data_ready))
 295                hid_sensor_push_data(indio_dev, magn_state->iio_vals);
 296
 297        return 0;
 298}
 299
 300/* Capture samples in local storage */
 301static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
 302                                unsigned usage_id,
 303                                size_t raw_len, char *raw_data,
 304                                void *priv)
 305{
 306        struct iio_dev *indio_dev = platform_get_drvdata(priv);
 307        struct magn_3d_state *magn_state = iio_priv(indio_dev);
 308        int offset;
 309        int ret = 0;
 310        u32 *iio_val = NULL;
 311
 312        switch (usage_id) {
 313        case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
 314        case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
 315        case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
 316                offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS)
 317                                + CHANNEL_SCAN_INDEX_X;
 318        break;
 319        case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH:
 320        case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH:
 321        case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH:
 322        case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH:
 323                offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH)
 324                                + CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP;
 325        break;
 326        default:
 327                return -EINVAL;
 328        }
 329
 330        iio_val = magn_state->magn_val_addr[offset];
 331
 332        if (iio_val != NULL)
 333                *iio_val = *((u32 *)raw_data);
 334        else
 335                ret = -EINVAL;
 336
 337        return ret;
 338}
 339
 340/* Parse report which is specific to an usage id*/
 341static int magn_3d_parse_report(struct platform_device *pdev,
 342                                struct hid_sensor_hub_device *hsdev,
 343                                struct iio_chan_spec **channels,
 344                                int *chan_count,
 345                                unsigned usage_id,
 346                                struct magn_3d_state *st)
 347{
 348        int i;
 349        int attr_count = 0;
 350        struct iio_chan_spec *_channels;
 351
 352        /* Scan for each usage attribute supported */
 353        for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) {
 354                int status;
 355                u32 address = magn_3d_addresses[i];
 356
 357                /* Check if usage attribute exists in the sensor hub device */
 358                status = sensor_hub_input_get_attribute_info(hsdev,
 359                        HID_INPUT_REPORT,
 360                        usage_id,
 361                        address,
 362                        &(st->magn[i]));
 363                if (!status)
 364                        attr_count++;
 365        }
 366
 367        if (attr_count <= 0) {
 368                dev_err(&pdev->dev,
 369                        "failed to find any supported usage attributes in report\n");
 370                return  -EINVAL;
 371        }
 372
 373        dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
 374                        attr_count);
 375        dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
 376                        st->magn[0].index,
 377                        st->magn[0].report_id,
 378                        st->magn[1].index, st->magn[1].report_id,
 379                        st->magn[2].index, st->magn[2].report_id);
 380
 381        /* Setup IIO channel array */
 382        _channels = devm_kcalloc(&pdev->dev, attr_count,
 383                                sizeof(struct iio_chan_spec),
 384                                GFP_KERNEL);
 385        if (!_channels) {
 386                dev_err(&pdev->dev,
 387                        "failed to allocate space for iio channels\n");
 388                return -ENOMEM;
 389        }
 390
 391        st->iio_vals = devm_kcalloc(&pdev->dev, attr_count,
 392                                sizeof(u32),
 393                                GFP_KERNEL);
 394        if (!st->iio_vals) {
 395                dev_err(&pdev->dev,
 396                        "failed to allocate space for iio values array\n");
 397                return -ENOMEM;
 398        }
 399
 400        for (i = 0, *chan_count = 0;
 401        i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count;
 402        i++){
 403                if (st->magn[i].index >= 0) {
 404                        /* Setup IIO channel struct */
 405                        (_channels[*chan_count]) = magn_3d_channels[i];
 406                        (_channels[*chan_count]).scan_index = *chan_count;
 407                        (_channels[*chan_count]).address = i;
 408
 409                        /* Set magn_val_addr to iio value address */
 410                        st->magn_val_addr[i] = &(st->iio_vals[*chan_count]);
 411                        magn_3d_adjust_channel_bit_mask(_channels,
 412                                                        *chan_count,
 413                                                        st->magn[i].size);
 414                        (*chan_count)++;
 415                }
 416        }
 417
 418        if (*chan_count <= 0) {
 419                dev_err(&pdev->dev,
 420                        "failed to find any magnetic channels setup\n");
 421                return -EINVAL;
 422        }
 423
 424        *channels = _channels;
 425
 426        dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
 427                        *chan_count);
 428
 429        st->magn_flux_attr.scale_precision = hid_sensor_format_scale(
 430                                HID_USAGE_SENSOR_COMPASS_3D,
 431                                &st->magn[CHANNEL_SCAN_INDEX_X],
 432                                &st->magn_flux_attr.scale_pre_decml,
 433                                &st->magn_flux_attr.scale_post_decml);
 434        st->rot_attr.scale_precision
 435                = hid_sensor_format_scale(
 436                        HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
 437                        &st->magn[CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP],
 438                        &st->rot_attr.scale_pre_decml,
 439                        &st->rot_attr.scale_post_decml);
 440
 441        /* Set Sensitivity field ids, when there is no individual modifier */
 442        if (st->magn_flux_attributes.sensitivity.index < 0) {
 443                sensor_hub_input_get_attribute_info(hsdev,
 444                        HID_FEATURE_REPORT, usage_id,
 445                        HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 446                        HID_USAGE_SENSOR_DATA_ORIENTATION,
 447                        &st->magn_flux_attributes.sensitivity);
 448                dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
 449                        st->magn_flux_attributes.sensitivity.index,
 450                        st->magn_flux_attributes.sensitivity.report_id);
 451        }
 452        if (st->magn_flux_attributes.sensitivity.index < 0) {
 453                sensor_hub_input_get_attribute_info(hsdev,
 454                        HID_FEATURE_REPORT, usage_id,
 455                        HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 456                        HID_USAGE_SENSOR_ORIENT_MAGN_FLUX,
 457                        &st->magn_flux_attributes.sensitivity);
 458                dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
 459                        st->magn_flux_attributes.sensitivity.index,
 460                        st->magn_flux_attributes.sensitivity.report_id);
 461        }
 462        if (st->rot_attributes.sensitivity.index < 0) {
 463                sensor_hub_input_get_attribute_info(hsdev,
 464                        HID_FEATURE_REPORT, usage_id,
 465                        HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 466                        HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
 467                        &st->rot_attributes.sensitivity);
 468                dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
 469                        st->rot_attributes.sensitivity.index,
 470                        st->rot_attributes.sensitivity.report_id);
 471        }
 472
 473        return 0;
 474}
 475
 476/* Function to initialize the processing for usage id */
 477static int hid_magn_3d_probe(struct platform_device *pdev)
 478{
 479        int ret = 0;
 480        static char *name = "magn_3d";
 481        struct iio_dev *indio_dev;
 482        struct magn_3d_state *magn_state;
 483        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 484        struct iio_chan_spec *channels;
 485        int chan_count = 0;
 486
 487        indio_dev = devm_iio_device_alloc(&pdev->dev,
 488                                          sizeof(struct magn_3d_state));
 489        if (indio_dev == NULL)
 490                return -ENOMEM;
 491
 492        platform_set_drvdata(pdev, indio_dev);
 493
 494        magn_state = iio_priv(indio_dev);
 495        magn_state->magn_flux_attributes.hsdev = hsdev;
 496        magn_state->magn_flux_attributes.pdev = pdev;
 497
 498        ret = hid_sensor_parse_common_attributes(hsdev,
 499                                HID_USAGE_SENSOR_COMPASS_3D,
 500                                &magn_state->magn_flux_attributes);
 501        if (ret) {
 502                dev_err(&pdev->dev, "failed to setup common attributes\n");
 503                return ret;
 504        }
 505        magn_state->rot_attributes = magn_state->magn_flux_attributes;
 506
 507        ret = magn_3d_parse_report(pdev, hsdev,
 508                                &channels, &chan_count,
 509                                HID_USAGE_SENSOR_COMPASS_3D, magn_state);
 510        if (ret) {
 511                dev_err(&pdev->dev, "failed to parse report\n");
 512                return ret;
 513        }
 514
 515        indio_dev->channels = channels;
 516        indio_dev->num_channels = chan_count;
 517        indio_dev->dev.parent = &pdev->dev;
 518        indio_dev->info = &magn_3d_info;
 519        indio_dev->name = name;
 520        indio_dev->modes = INDIO_DIRECT_MODE;
 521
 522        ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
 523                NULL, NULL);
 524        if (ret) {
 525                dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
 526                return ret;
 527        }
 528        atomic_set(&magn_state->magn_flux_attributes.data_ready, 0);
 529        ret = hid_sensor_setup_trigger(indio_dev, name,
 530                                        &magn_state->magn_flux_attributes);
 531        if (ret < 0) {
 532                dev_err(&pdev->dev, "trigger setup failed\n");
 533                goto error_unreg_buffer_funcs;
 534        }
 535
 536        ret = iio_device_register(indio_dev);
 537        if (ret) {
 538                dev_err(&pdev->dev, "device register failed\n");
 539                goto error_remove_trigger;
 540        }
 541
 542        magn_state->callbacks.send_event = magn_3d_proc_event;
 543        magn_state->callbacks.capture_sample = magn_3d_capture_sample;
 544        magn_state->callbacks.pdev = pdev;
 545        ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D,
 546                                        &magn_state->callbacks);
 547        if (ret < 0) {
 548                dev_err(&pdev->dev, "callback reg failed\n");
 549                goto error_iio_unreg;
 550        }
 551
 552        return ret;
 553
 554error_iio_unreg:
 555        iio_device_unregister(indio_dev);
 556error_remove_trigger:
 557        hid_sensor_remove_trigger(&magn_state->magn_flux_attributes);
 558error_unreg_buffer_funcs:
 559        iio_triggered_buffer_cleanup(indio_dev);
 560        return ret;
 561}
 562
 563/* Function to deinitialize the processing for usage id */
 564static int hid_magn_3d_remove(struct platform_device *pdev)
 565{
 566        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 567        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 568        struct magn_3d_state *magn_state = iio_priv(indio_dev);
 569
 570        sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D);
 571        iio_device_unregister(indio_dev);
 572        hid_sensor_remove_trigger(&magn_state->magn_flux_attributes);
 573        iio_triggered_buffer_cleanup(indio_dev);
 574
 575        return 0;
 576}
 577
 578static const struct platform_device_id hid_magn_3d_ids[] = {
 579        {
 580                /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 581                .name = "HID-SENSOR-200083",
 582        },
 583        { /* sentinel */ }
 584};
 585MODULE_DEVICE_TABLE(platform, hid_magn_3d_ids);
 586
 587static struct platform_driver hid_magn_3d_platform_driver = {
 588        .id_table = hid_magn_3d_ids,
 589        .driver = {
 590                .name   = KBUILD_MODNAME,
 591                .pm     = &hid_sensor_pm_ops,
 592        },
 593        .probe          = hid_magn_3d_probe,
 594        .remove         = hid_magn_3d_remove,
 595};
 596module_platform_driver(hid_magn_3d_platform_driver);
 597
 598MODULE_DESCRIPTION("HID Sensor Magnetometer 3D");
 599MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
 600MODULE_LICENSE("GPL");
 601