cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ssp_dev.c (16173B)


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