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