linux/drivers/iio/common/ssp_sensors/ssp_dev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (C) 2014, Samsung Electronics Co. Ltd. All Rights Reserved.
   4 */
   5
   6#include <linux/iio/iio.h>
   7#include <linux/interrupt.h>
   8#include <linux/io.h>
   9#include <linux/mfd/core.h>
  10#include <linux/module.h>
  11#include <linux/of.h>
  12#include <linux/of_platform.h>
  13#include "ssp.h"
  14
  15#define SSP_WDT_TIME                    10000
  16#define SSP_LIMIT_RESET_CNT             20
  17#define SSP_LIMIT_TIMEOUT_CNT           3
  18
  19/* It is possible that it is max clk rate for version 1.0 of bootcode */
  20#define SSP_BOOT_SPI_HZ 400000
  21
  22/*
  23 * These fields can look enigmatic but this structure is used mainly to flat
  24 * some values and depends on command type.
  25 */
  26struct ssp_instruction {
  27        __le32 a;
  28        __le32 b;
  29        u8 c;
  30} __attribute__((__packed__));
  31
  32static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67,
  33        208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171,
  34        243, 13, 45, 250};
  35
  36static const struct ssp_sensorhub_info ssp_rinato_info = {
  37        .fw_name = "ssp_B2.fw",
  38        .fw_crashed_name = "ssp_crashed.fw",
  39        .fw_rev = 14052300,
  40        .mag_table = ssp_magnitude_table,
  41        .mag_length = ARRAY_SIZE(ssp_magnitude_table),
  42};
  43
  44static const struct ssp_sensorhub_info ssp_thermostat_info = {
  45        .fw_name = "thermostat_B2.fw",
  46        .fw_crashed_name = "ssp_crashed.fw",
  47        .fw_rev = 14080600,
  48        .mag_table = ssp_magnitude_table,
  49        .mag_length = ARRAY_SIZE(ssp_magnitude_table),
  50};
  51
  52static const struct mfd_cell sensorhub_sensor_devs[] = {
  53        {
  54                .name = "ssp-accelerometer",
  55        },
  56        {
  57                .name = "ssp-gyroscope",
  58        },
  59};
  60
  61static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)
  62{
  63        gpiod_set_value(data->mcu_reset_gpiod, 0);
  64        usleep_range(1000, 1200);
  65        gpiod_set_value(data->mcu_reset_gpiod, 1);
  66        msleep(50);
  67}
  68
  69static void ssp_sync_available_sensors(struct ssp_data *data)
  70{
  71        int i, ret;
  72
  73        for (i = 0; i < SSP_SENSOR_MAX; ++i) {
  74                if (data->available_sensors & BIT(i)) {
  75                        ret = ssp_enable_sensor(data, i, data->delay_buf[i]);
  76                        if (ret < 0) {
  77                                dev_err(&data->spi->dev,
  78                                        "Sync sensor nr: %d fail\n", i);
  79                                continue;
  80                        }
  81                }
  82        }
  83
  84        ret = ssp_command(data, SSP_MSG2SSP_AP_MCU_SET_DUMPMODE,
  85                          data->mcu_dump_mode);
  86        if (ret < 0)
  87                dev_err(&data->spi->dev,
  88                        "SSP_MSG2SSP_AP_MCU_SET_DUMPMODE failed\n");
  89}
  90
  91static void ssp_enable_mcu(struct ssp_data *data, bool enable)
  92{
  93        dev_info(&data->spi->dev, "current shutdown = %d, old = %d\n", enable,
  94                 data->shut_down);
  95
  96        if (enable && data->shut_down) {
  97                data->shut_down = false;
  98                enable_irq(data->spi->irq);
  99                enable_irq_wake(data->spi->irq);
 100        } else if (!enable && !data->shut_down) {
 101                data->shut_down = true;
 102                disable_irq(data->spi->irq);
 103                disable_irq_wake(data->spi->irq);
 104        } else {
 105                dev_warn(&data->spi->dev, "current shutdown = %d, old = %d\n",
 106                         enable, data->shut_down);
 107        }
 108}
 109
 110/*
 111 * This function is the first one which communicates with the mcu so it is
 112 * possible that the first attempt will fail
 113 */
 114static int ssp_check_fwbl(struct ssp_data *data)
 115{
 116        int retries = 0;
 117
 118        while (retries++ < 5) {
 119                data->cur_firm_rev = ssp_get_firmware_rev(data);
 120                if (data->cur_firm_rev == SSP_INVALID_REVISION ||
 121                    data->cur_firm_rev == SSP_INVALID_REVISION2) {
 122                        dev_warn(&data->spi->dev,
 123                                 "Invalid revision, trying %d time\n", retries);
 124                } else {
 125                        break;
 126                }
 127        }
 128
 129        if (data->cur_firm_rev == SSP_INVALID_REVISION ||
 130            data->cur_firm_rev == SSP_INVALID_REVISION2) {
 131                dev_err(&data->spi->dev, "SSP_INVALID_REVISION\n");
 132                return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
 133        }
 134
 135        dev_info(&data->spi->dev,
 136                 "MCU Firm Rev : Old = %8u, New = %8u\n",
 137                 data->cur_firm_rev,
 138                 data->sensorhub_info->fw_rev);
 139
 140        if (data->cur_firm_rev != data->sensorhub_info->fw_rev)
 141                return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
 142
 143        return SSP_FW_DL_STATE_NONE;
 144}
 145
 146static void ssp_reset_mcu(struct ssp_data *data)
 147{
 148        ssp_enable_mcu(data, false);
 149        ssp_clean_pending_list(data);
 150        ssp_toggle_mcu_reset_gpio(data);
 151        ssp_enable_mcu(data, true);
 152}
 153
 154static void ssp_wdt_work_func(struct work_struct *work)
 155{
 156        struct ssp_data *data = container_of(work, struct ssp_data, work_wdt);
 157
 158        dev_err(&data->spi->dev, "%s - Sensor state: 0x%x, RC: %u, CC: %u\n",
 159                __func__, data->available_sensors, data->reset_cnt,
 160                data->com_fail_cnt);
 161
 162        ssp_reset_mcu(data);
 163        data->com_fail_cnt = 0;
 164        data->timeout_cnt = 0;
 165}
 166
 167static void ssp_wdt_timer_func(struct timer_list *t)
 168{
 169        struct ssp_data *data = from_timer(data, t, wdt_timer);
 170
 171        switch (data->fw_dl_state) {
 172        case SSP_FW_DL_STATE_FAIL:
 173        case SSP_FW_DL_STATE_DOWNLOADING:
 174        case SSP_FW_DL_STATE_SYNC:
 175                goto _mod;
 176        }
 177
 178        if (data->timeout_cnt > SSP_LIMIT_TIMEOUT_CNT ||
 179            data->com_fail_cnt > SSP_LIMIT_RESET_CNT)
 180                queue_work(system_power_efficient_wq, &data->work_wdt);
 181_mod:
 182        mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
 183}
 184
 185static void ssp_enable_wdt_timer(struct ssp_data *data)
 186{
 187        mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
 188}
 189
 190static void ssp_disable_wdt_timer(struct ssp_data *data)
 191{
 192        del_timer_sync(&data->wdt_timer);
 193        cancel_work_sync(&data->work_wdt);
 194}
 195
 196/**
 197 * ssp_get_sensor_delay() - gets sensor data acquisition period
 198 * @data:       sensorhub structure
 199 * @type:       SSP sensor type
 200 *
 201 * Returns acquisition period in ms
 202 */
 203u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type)
 204{
 205        return data->delay_buf[type];
 206}
 207EXPORT_SYMBOL(ssp_get_sensor_delay);
 208
 209/**
 210 * ssp_enable_sensor() - enables data acquisition for sensor
 211 * @data:       sensorhub structure
 212 * @type:       SSP sensor type
 213 * @delay:      delay in ms
 214 *
 215 * Returns 0 or negative value in case of error
 216 */
 217int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,
 218                      u32 delay)
 219{
 220        int ret;
 221        struct ssp_instruction to_send;
 222
 223        to_send.a = cpu_to_le32(delay);
 224        to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
 225        to_send.c = data->batch_opt_buf[type];
 226
 227        switch (data->check_status[type]) {
 228        case SSP_INITIALIZATION_STATE:
 229                /* do calibration step, now just enable */
 230        case SSP_ADD_SENSOR_STATE:
 231                ret = ssp_send_instruction(data,
 232                                           SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD,
 233                                           type,
 234                                           (u8 *)&to_send, sizeof(to_send));
 235                if (ret < 0) {
 236                        dev_err(&data->spi->dev, "Enabling sensor failed\n");
 237                        data->check_status[type] = SSP_NO_SENSOR_STATE;
 238                        goto derror;
 239                }
 240
 241                data->sensor_enable |= BIT(type);
 242                data->check_status[type] = SSP_RUNNING_SENSOR_STATE;
 243                break;
 244        case SSP_RUNNING_SENSOR_STATE:
 245                ret = ssp_send_instruction(data,
 246                                           SSP_MSG2SSP_INST_CHANGE_DELAY, type,
 247                                           (u8 *)&to_send, sizeof(to_send));
 248                if (ret < 0) {
 249                        dev_err(&data->spi->dev,
 250                                "Changing sensor delay failed\n");
 251                        goto derror;
 252                }
 253                break;
 254        default:
 255                data->check_status[type] = SSP_ADD_SENSOR_STATE;
 256                break;
 257        }
 258
 259        data->delay_buf[type] = delay;
 260
 261        if (atomic_inc_return(&data->enable_refcount) == 1)
 262                ssp_enable_wdt_timer(data);
 263
 264        return 0;
 265
 266derror:
 267        return ret;
 268}
 269EXPORT_SYMBOL(ssp_enable_sensor);
 270
 271/**
 272 * ssp_change_delay() - changes data acquisition for sensor
 273 * @data:       sensorhub structure
 274 * @type:       SSP sensor type
 275 * @delay:      delay in ms
 276 *
 277 * Returns 0 or negative value in case of error
 278 */
 279int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,
 280                     u32 delay)
 281{
 282        int ret;
 283        struct ssp_instruction to_send;
 284
 285        to_send.a = cpu_to_le32(delay);
 286        to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
 287        to_send.c = data->batch_opt_buf[type];
 288
 289        ret = ssp_send_instruction(data, SSP_MSG2SSP_INST_CHANGE_DELAY, type,
 290                                   (u8 *)&to_send, sizeof(to_send));
 291        if (ret < 0) {
 292                dev_err(&data->spi->dev, "Changing sensor delay failed\n");
 293                return ret;
 294        }
 295
 296        data->delay_buf[type] = delay;
 297
 298        return 0;
 299}
 300EXPORT_SYMBOL(ssp_change_delay);
 301
 302/**
 303 * ssp_disable_sensor() - disables sensor
 304 *
 305 * @data:       sensorhub structure
 306 * @type:       SSP sensor type
 307 *
 308 * Returns 0 or negative value in case of error
 309 */
 310int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type)
 311{
 312        int ret;
 313        __le32 command;
 314
 315        if (data->sensor_enable & BIT(type)) {
 316                command = cpu_to_le32(data->delay_buf[type]);
 317
 318                ret = ssp_send_instruction(data,
 319                                           SSP_MSG2SSP_INST_BYPASS_SENSOR_RM,
 320                                           type, (u8 *)&command,
 321                                           sizeof(command));
 322                if (ret < 0) {
 323                        dev_err(&data->spi->dev, "Remove sensor fail\n");
 324                        return ret;
 325                }
 326
 327                data->sensor_enable &= ~BIT(type);
 328        }
 329
 330        data->check_status[type] = SSP_ADD_SENSOR_STATE;
 331
 332        if (atomic_dec_and_test(&data->enable_refcount))
 333                ssp_disable_wdt_timer(data);
 334
 335        return 0;
 336}
 337EXPORT_SYMBOL(ssp_disable_sensor);
 338
 339static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id)
 340{
 341        struct ssp_data *data = dev_id;
 342
 343        /*
 344         * This wrapper is done to preserve error path for ssp_irq_msg, also
 345         * it is defined in different file.
 346         */
 347        ssp_irq_msg(data);
 348
 349        return IRQ_HANDLED;
 350}
 351
 352static int ssp_initialize_mcu(struct ssp_data *data)
 353{
 354        int ret;
 355
 356        ssp_clean_pending_list(data);
 357
 358        ret = ssp_get_chipid(data);
 359        if (ret != SSP_DEVICE_ID) {
 360                dev_err(&data->spi->dev, "%s - MCU %s ret = %d\n", __func__,
 361                        ret < 0 ? "is not working" : "identification failed",
 362                        ret);
 363                return ret < 0 ? ret : -ENODEV;
 364        }
 365
 366        dev_info(&data->spi->dev, "MCU device ID = %d\n", ret);
 367
 368        /*
 369         * needs clarification, for now do not want to export all transfer
 370         * methods to sensors' drivers
 371         */
 372        ret = ssp_set_magnetic_matrix(data);
 373        if (ret < 0) {
 374                dev_err(&data->spi->dev,
 375                        "%s - ssp_set_magnetic_matrix failed\n", __func__);
 376                return ret;
 377        }
 378
 379        data->available_sensors = ssp_get_sensor_scanning_info(data);
 380        if (data->available_sensors == 0) {
 381                dev_err(&data->spi->dev,
 382                        "%s - ssp_get_sensor_scanning_info failed\n", __func__);
 383                return -EIO;
 384        }
 385
 386        data->cur_firm_rev = ssp_get_firmware_rev(data);
 387        dev_info(&data->spi->dev, "MCU Firm Rev : New = %8u\n",
 388                 data->cur_firm_rev);
 389
 390        return ssp_command(data, SSP_MSG2SSP_AP_MCU_DUMP_CHECK, 0);
 391}
 392
 393/*
 394 * sensorhub can request its reinitialization as some brutal and rare error
 395 * handling. It can be requested from the MCU.
 396 */
 397static void ssp_refresh_task(struct work_struct *work)
 398{
 399        struct ssp_data *data = container_of((struct delayed_work *)work,
 400                                             struct ssp_data, work_refresh);
 401
 402        dev_info(&data->spi->dev, "refreshing\n");
 403
 404        data->reset_cnt++;
 405
 406        if (ssp_initialize_mcu(data) >= 0) {
 407                ssp_sync_available_sensors(data);
 408                if (data->last_ap_state != 0)
 409                        ssp_command(data, data->last_ap_state, 0);
 410
 411                if (data->last_resume_state != 0)
 412                        ssp_command(data, data->last_resume_state, 0);
 413
 414                data->timeout_cnt = 0;
 415                data->com_fail_cnt = 0;
 416        }
 417}
 418
 419int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
 420{
 421        cancel_delayed_work_sync(&data->work_refresh);
 422
 423        return queue_delayed_work(system_power_efficient_wq,
 424                                  &data->work_refresh,
 425                                  msecs_to_jiffies(delay));
 426}
 427
 428#ifdef CONFIG_OF
 429static const struct of_device_id ssp_of_match[] = {
 430        {
 431                .compatible     = "samsung,sensorhub-rinato",
 432                .data           = &ssp_rinato_info,
 433        }, {
 434                .compatible     = "samsung,sensorhub-thermostat",
 435                .data           = &ssp_thermostat_info,
 436        },
 437        {},
 438};
 439MODULE_DEVICE_TABLE(of, ssp_of_match);
 440
 441static struct ssp_data *ssp_parse_dt(struct device *dev)
 442{
 443        struct ssp_data *data;
 444        struct device_node *node = dev->of_node;
 445        const struct of_device_id *match;
 446
 447        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 448        if (!data)
 449                return NULL;
 450
 451        data->mcu_ap_gpiod = devm_gpiod_get(dev, "mcu-ap", GPIOD_IN);
 452        if (IS_ERR(data->mcu_ap_gpiod))
 453                return NULL;
 454
 455        data->ap_mcu_gpiod = devm_gpiod_get(dev, "ap-mcu", GPIOD_OUT_HIGH);
 456        if (IS_ERR(data->ap_mcu_gpiod))
 457                return NULL;
 458
 459        data->mcu_reset_gpiod = devm_gpiod_get(dev, "mcu-reset",
 460                                               GPIOD_OUT_HIGH);
 461        if (IS_ERR(data->mcu_reset_gpiod))
 462                return NULL;
 463
 464        match = of_match_node(ssp_of_match, node);
 465        if (!match)
 466                return NULL;
 467
 468        data->sensorhub_info = match->data;
 469
 470        dev_set_drvdata(dev, data);
 471
 472        return data;
 473}
 474#else
 475static struct ssp_data *ssp_parse_dt(struct device *pdev)
 476{
 477        return NULL;
 478}
 479#endif
 480
 481/**
 482 * ssp_register_consumer() - registers iio consumer in ssp framework
 483 *
 484 * @indio_dev:  consumer iio device
 485 * @type:       ssp sensor type
 486 */
 487void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type)
 488{
 489        struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
 490
 491        data->sensor_devs[type] = indio_dev;
 492}
 493EXPORT_SYMBOL(ssp_register_consumer);
 494
 495static int ssp_probe(struct spi_device *spi)
 496{
 497        int ret, i;
 498        struct ssp_data *data;
 499
 500        data = ssp_parse_dt(&spi->dev);
 501        if (!data) {
 502                dev_err(&spi->dev, "Failed to find platform data\n");
 503                return -ENODEV;
 504        }
 505
 506        ret = mfd_add_devices(&spi->dev, PLATFORM_DEVID_NONE,
 507                              sensorhub_sensor_devs,
 508                              ARRAY_SIZE(sensorhub_sensor_devs), NULL, 0, NULL);
 509        if (ret < 0) {
 510                dev_err(&spi->dev, "mfd add devices fail\n");
 511                return ret;
 512        }
 513
 514        spi->mode = SPI_MODE_1;
 515        ret = spi_setup(spi);
 516        if (ret < 0) {
 517                dev_err(&spi->dev, "Failed to setup spi\n");
 518                return ret;
 519        }
 520
 521        data->fw_dl_state = SSP_FW_DL_STATE_NONE;
 522        data->spi = spi;
 523        spi_set_drvdata(spi, data);
 524
 525        mutex_init(&data->comm_lock);
 526
 527        for (i = 0; i < SSP_SENSOR_MAX; ++i) {
 528                data->delay_buf[i] = SSP_DEFAULT_POLLING_DELAY;
 529                data->batch_latency_buf[i] = 0;
 530                data->batch_opt_buf[i] = 0;
 531                data->check_status[i] = SSP_INITIALIZATION_STATE;
 532        }
 533
 534        data->delay_buf[SSP_BIO_HRM_LIB] = 100;
 535
 536        data->time_syncing = true;
 537
 538        mutex_init(&data->pending_lock);
 539        INIT_LIST_HEAD(&data->pending_list);
 540
 541        atomic_set(&data->enable_refcount, 0);
 542
 543        INIT_WORK(&data->work_wdt, ssp_wdt_work_func);
 544        INIT_DELAYED_WORK(&data->work_refresh, ssp_refresh_task);
 545
 546        timer_setup(&data->wdt_timer, ssp_wdt_timer_func, 0);
 547
 548        ret = request_threaded_irq(data->spi->irq, NULL,
 549                                   ssp_irq_thread_fn,
 550                                   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 551                                   "SSP_Int", data);
 552        if (ret < 0) {
 553                dev_err(&spi->dev, "Irq request fail\n");
 554                goto err_setup_irq;
 555        }
 556
 557        /* Let's start with enabled one so irq balance could be ok */
 558        data->shut_down = false;
 559
 560        /* just to avoid unbalanced irq set wake up */
 561        enable_irq_wake(data->spi->irq);
 562
 563        data->fw_dl_state = ssp_check_fwbl(data);
 564        if (data->fw_dl_state == SSP_FW_DL_STATE_NONE) {
 565                ret = ssp_initialize_mcu(data);
 566                if (ret < 0) {
 567                        dev_err(&spi->dev, "Initialize_mcu failed\n");
 568                        goto err_read_reg;
 569                }
 570        } else {
 571                dev_err(&spi->dev, "Firmware version not supported\n");
 572                ret = -EPERM;
 573                goto err_read_reg;
 574        }
 575
 576        return 0;
 577
 578err_read_reg:
 579        free_irq(data->spi->irq, data);
 580err_setup_irq:
 581        mutex_destroy(&data->pending_lock);
 582        mutex_destroy(&data->comm_lock);
 583
 584        dev_err(&spi->dev, "Probe failed!\n");
 585
 586        return ret;
 587}
 588
 589static int ssp_remove(struct spi_device *spi)
 590{
 591        struct ssp_data *data = spi_get_drvdata(spi);
 592
 593        if (ssp_command(data, SSP_MSG2SSP_AP_STATUS_SHUTDOWN, 0) < 0)
 594                dev_err(&data->spi->dev,
 595                        "SSP_MSG2SSP_AP_STATUS_SHUTDOWN failed\n");
 596
 597        ssp_enable_mcu(data, false);
 598        ssp_disable_wdt_timer(data);
 599
 600        ssp_clean_pending_list(data);
 601
 602        free_irq(data->spi->irq, data);
 603
 604        del_timer_sync(&data->wdt_timer);
 605        cancel_work_sync(&data->work_wdt);
 606
 607        mutex_destroy(&data->comm_lock);
 608        mutex_destroy(&data->pending_lock);
 609
 610        mfd_remove_devices(&spi->dev);
 611
 612        return 0;
 613}
 614
 615#ifdef CONFIG_PM_SLEEP
 616static int ssp_suspend(struct device *dev)
 617{
 618        int ret;
 619        struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
 620
 621        data->last_resume_state = SSP_MSG2SSP_AP_STATUS_SUSPEND;
 622
 623        if (atomic_read(&data->enable_refcount) > 0)
 624                ssp_disable_wdt_timer(data);
 625
 626        ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_SUSPEND, 0);
 627        if (ret < 0) {
 628                dev_err(&data->spi->dev,
 629                        "%s SSP_MSG2SSP_AP_STATUS_SUSPEND failed\n", __func__);
 630
 631                ssp_enable_wdt_timer(data);
 632                return ret;
 633        }
 634
 635        data->time_syncing = false;
 636        disable_irq(data->spi->irq);
 637
 638        return 0;
 639}
 640
 641static int ssp_resume(struct device *dev)
 642{
 643        int ret;
 644        struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
 645
 646        enable_irq(data->spi->irq);
 647
 648        if (atomic_read(&data->enable_refcount) > 0)
 649                ssp_enable_wdt_timer(data);
 650
 651        ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_RESUME, 0);
 652        if (ret < 0) {
 653                dev_err(&data->spi->dev,
 654                        "%s SSP_MSG2SSP_AP_STATUS_RESUME failed\n", __func__);
 655                ssp_disable_wdt_timer(data);
 656                return ret;
 657        }
 658
 659        /* timesyncing is set by MCU */
 660        data->last_resume_state = SSP_MSG2SSP_AP_STATUS_RESUME;
 661
 662        return 0;
 663}
 664#endif /* CONFIG_PM_SLEEP */
 665
 666static const struct dev_pm_ops ssp_pm_ops = {
 667        SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
 668};
 669
 670static struct spi_driver ssp_driver = {
 671        .probe = ssp_probe,
 672        .remove = ssp_remove,
 673        .driver = {
 674                .pm = &ssp_pm_ops,
 675                .of_match_table = of_match_ptr(ssp_of_match),
 676                .name = "sensorhub"
 677        },
 678};
 679
 680module_spi_driver(ssp_driver);
 681
 682MODULE_DESCRIPTION("ssp sensorhub driver");
 683MODULE_AUTHOR("Samsung Electronics");
 684MODULE_LICENSE("GPL");
 685