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

admv8818.c (15520B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ADMV8818 driver
      4 *
      5 * Copyright 2021 Analog Devices Inc.
      6 */
      7
      8#include <linux/bitfield.h>
      9#include <linux/bits.h>
     10#include <linux/clk.h>
     11#include <linux/device.h>
     12#include <linux/iio/iio.h>
     13#include <linux/module.h>
     14#include <linux/mod_devicetable.h>
     15#include <linux/mutex.h>
     16#include <linux/notifier.h>
     17#include <linux/regmap.h>
     18#include <linux/spi/spi.h>
     19#include <linux/units.h>
     20
     21/* ADMV8818 Register Map */
     22#define ADMV8818_REG_SPI_CONFIG_A		0x0
     23#define ADMV8818_REG_SPI_CONFIG_B		0x1
     24#define ADMV8818_REG_CHIPTYPE			0x3
     25#define ADMV8818_REG_PRODUCT_ID_L		0x4
     26#define ADMV8818_REG_PRODUCT_ID_H		0x5
     27#define ADMV8818_REG_FAST_LATCH_POINTER		0x10
     28#define ADMV8818_REG_FAST_LATCH_STOP		0x11
     29#define ADMV8818_REG_FAST_LATCH_START		0x12
     30#define ADMV8818_REG_FAST_LATCH_DIRECTION	0x13
     31#define ADMV8818_REG_FAST_LATCH_STATE		0x14
     32#define ADMV8818_REG_WR0_SW			0x20
     33#define ADMV8818_REG_WR0_FILTER			0x21
     34#define ADMV8818_REG_WR1_SW			0x22
     35#define ADMV8818_REG_WR1_FILTER			0x23
     36#define ADMV8818_REG_WR2_SW			0x24
     37#define ADMV8818_REG_WR2_FILTER			0x25
     38#define ADMV8818_REG_WR3_SW			0x26
     39#define ADMV8818_REG_WR3_FILTER			0x27
     40#define ADMV8818_REG_WR4_SW			0x28
     41#define ADMV8818_REG_WR4_FILTER			0x29
     42#define ADMV8818_REG_LUT0_SW			0x100
     43#define ADMV8818_REG_LUT0_FILTER		0x101
     44#define ADMV8818_REG_LUT127_SW			0x1FE
     45#define ADMV8818_REG_LUT127_FILTER		0x1FF
     46
     47/* ADMV8818_REG_SPI_CONFIG_A Map */
     48#define ADMV8818_SOFTRESET_N_MSK		BIT(7)
     49#define ADMV8818_LSB_FIRST_N_MSK		BIT(6)
     50#define ADMV8818_ENDIAN_N_MSK			BIT(5)
     51#define ADMV8818_SDOACTIVE_N_MSK		BIT(4)
     52#define ADMV8818_SDOACTIVE_MSK			BIT(3)
     53#define ADMV8818_ENDIAN_MSK			BIT(2)
     54#define ADMV8818_LSBFIRST_MSK			BIT(1)
     55#define ADMV8818_SOFTRESET_MSK			BIT(0)
     56
     57/* ADMV8818_REG_SPI_CONFIG_B Map */
     58#define ADMV8818_SINGLE_INSTRUCTION_MSK		BIT(7)
     59#define ADMV8818_CSB_STALL_MSK			BIT(6)
     60#define ADMV8818_MASTER_SLAVE_RB_MSK		BIT(5)
     61#define ADMV8818_MASTER_SLAVE_TRANSFER_MSK	BIT(0)
     62
     63/* ADMV8818_REG_WR0_SW Map */
     64#define ADMV8818_SW_IN_SET_WR0_MSK		BIT(7)
     65#define ADMV8818_SW_OUT_SET_WR0_MSK		BIT(6)
     66#define ADMV8818_SW_IN_WR0_MSK			GENMASK(5, 3)
     67#define ADMV8818_SW_OUT_WR0_MSK			GENMASK(2, 0)
     68
     69/* ADMV8818_REG_WR0_FILTER Map */
     70#define ADMV8818_HPF_WR0_MSK			GENMASK(7, 4)
     71#define ADMV8818_LPF_WR0_MSK			GENMASK(3, 0)
     72
     73enum {
     74	ADMV8818_BW_FREQ,
     75	ADMV8818_CENTER_FREQ
     76};
     77
     78enum {
     79	ADMV8818_AUTO_MODE,
     80	ADMV8818_MANUAL_MODE,
     81};
     82
     83struct admv8818_state {
     84	struct spi_device	*spi;
     85	struct regmap		*regmap;
     86	struct clk		*clkin;
     87	struct notifier_block	nb;
     88	/* Protect against concurrent accesses to the device and data content*/
     89	struct mutex		lock;
     90	unsigned int		filter_mode;
     91	u64			cf_hz;
     92};
     93
     94static const unsigned long long freq_range_hpf[4][2] = {
     95	{1750000000ULL, 3550000000ULL},
     96	{3400000000ULL, 7250000000ULL},
     97	{6600000000, 12000000000},
     98	{12500000000, 19900000000}
     99};
    100
    101static const unsigned long long freq_range_lpf[4][2] = {
    102	{2050000000ULL, 3850000000ULL},
    103	{3350000000ULL, 7250000000ULL},
    104	{7000000000, 13000000000},
    105	{12550000000, 18500000000}
    106};
    107
    108static const struct regmap_config admv8818_regmap_config = {
    109	.reg_bits = 16,
    110	.val_bits = 8,
    111	.read_flag_mask = 0x80,
    112	.max_register = 0x1FF,
    113};
    114
    115static const char * const admv8818_modes[] = {
    116	[0] = "auto",
    117	[1] = "manual"
    118};
    119
    120static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq)
    121{
    122	unsigned int hpf_step = 0, hpf_band = 0, i, j;
    123	u64 freq_step;
    124	int ret;
    125
    126	if (freq < freq_range_hpf[0][0])
    127		goto hpf_write;
    128
    129	if (freq > freq_range_hpf[3][1]) {
    130		hpf_step = 15;
    131		hpf_band = 4;
    132
    133		goto hpf_write;
    134	}
    135
    136	for (i = 0; i < 4; i++) {
    137		freq_step = div_u64((freq_range_hpf[i][1] -
    138			freq_range_hpf[i][0]), 15);
    139
    140		if (freq > freq_range_hpf[i][0] &&
    141		    (freq < freq_range_hpf[i][1] + freq_step)) {
    142			hpf_band = i + 1;
    143
    144			for (j = 1; j <= 16; j++) {
    145				if (freq < (freq_range_hpf[i][0] + (freq_step * j))) {
    146					hpf_step = j - 1;
    147					break;
    148				}
    149			}
    150			break;
    151		}
    152	}
    153
    154	/* Close HPF frequency gap between 12 and 12.5 GHz */
    155	if (freq >= 12000 * HZ_PER_MHZ && freq <= 12500 * HZ_PER_MHZ) {
    156		hpf_band = 3;
    157		hpf_step = 15;
    158	}
    159
    160hpf_write:
    161	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
    162				 ADMV8818_SW_IN_SET_WR0_MSK |
    163				 ADMV8818_SW_IN_WR0_MSK,
    164				 FIELD_PREP(ADMV8818_SW_IN_SET_WR0_MSK, 1) |
    165				 FIELD_PREP(ADMV8818_SW_IN_WR0_MSK, hpf_band));
    166	if (ret)
    167		return ret;
    168
    169	return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
    170				  ADMV8818_HPF_WR0_MSK,
    171				  FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_step));
    172}
    173
    174static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)
    175{
    176	int ret;
    177
    178	mutex_lock(&st->lock);
    179	ret = __admv8818_hpf_select(st, freq);
    180	mutex_unlock(&st->lock);
    181
    182	return ret;
    183}
    184
    185static int __admv8818_lpf_select(struct admv8818_state *st, u64 freq)
    186{
    187	unsigned int lpf_step = 0, lpf_band = 0, i, j;
    188	u64 freq_step;
    189	int ret;
    190
    191	if (freq > freq_range_lpf[3][1])
    192		goto lpf_write;
    193
    194	if (freq < freq_range_lpf[0][0]) {
    195		lpf_band = 1;
    196
    197		goto lpf_write;
    198	}
    199
    200	for (i = 0; i < 4; i++) {
    201		if (freq > freq_range_lpf[i][0] && freq < freq_range_lpf[i][1]) {
    202			lpf_band = i + 1;
    203			freq_step = div_u64((freq_range_lpf[i][1] - freq_range_lpf[i][0]), 15);
    204
    205			for (j = 0; j <= 15; j++) {
    206				if (freq < (freq_range_lpf[i][0] + (freq_step * j))) {
    207					lpf_step = j;
    208					break;
    209				}
    210			}
    211			break;
    212		}
    213	}
    214
    215lpf_write:
    216	ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
    217				 ADMV8818_SW_OUT_SET_WR0_MSK |
    218				 ADMV8818_SW_OUT_WR0_MSK,
    219				 FIELD_PREP(ADMV8818_SW_OUT_SET_WR0_MSK, 1) |
    220				 FIELD_PREP(ADMV8818_SW_OUT_WR0_MSK, lpf_band));
    221	if (ret)
    222		return ret;
    223
    224	return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
    225				  ADMV8818_LPF_WR0_MSK,
    226				  FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_step));
    227}
    228
    229static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)
    230{
    231	int ret;
    232
    233	mutex_lock(&st->lock);
    234	ret = __admv8818_lpf_select(st, freq);
    235	mutex_unlock(&st->lock);
    236
    237	return ret;
    238}
    239
    240static int admv8818_rfin_band_select(struct admv8818_state *st)
    241{
    242	int ret;
    243
    244	st->cf_hz = clk_get_rate(st->clkin);
    245
    246	mutex_lock(&st->lock);
    247
    248	ret = __admv8818_hpf_select(st, st->cf_hz);
    249	if (ret)
    250		goto exit;
    251
    252	ret = __admv8818_lpf_select(st, st->cf_hz);
    253exit:
    254	mutex_unlock(&st->lock);
    255	return ret;
    256}
    257
    258static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
    259{
    260	unsigned int data, hpf_band, hpf_state;
    261	int ret;
    262
    263	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_SW, &data);
    264	if (ret)
    265		return ret;
    266
    267	hpf_band = FIELD_GET(ADMV8818_SW_IN_WR0_MSK, data);
    268	if (!hpf_band) {
    269		*hpf_freq = 0;
    270		return ret;
    271	}
    272
    273	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_FILTER, &data);
    274	if (ret)
    275		return ret;
    276
    277	hpf_state = FIELD_GET(ADMV8818_HPF_WR0_MSK, data);
    278
    279	*hpf_freq = div_u64(freq_range_hpf[hpf_band - 1][1] - freq_range_hpf[hpf_band - 1][0], 15);
    280	*hpf_freq = freq_range_hpf[hpf_band - 1][0] + (*hpf_freq * hpf_state);
    281
    282	return ret;
    283}
    284
    285static int admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
    286{
    287	int ret;
    288
    289	mutex_lock(&st->lock);
    290	ret = __admv8818_read_hpf_freq(st, hpf_freq);
    291	mutex_unlock(&st->lock);
    292
    293	return ret;
    294}
    295
    296static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
    297{
    298	unsigned int data, lpf_band, lpf_state;
    299	int ret;
    300
    301	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_SW, &data);
    302	if (ret)
    303		return ret;
    304
    305	lpf_band = FIELD_GET(ADMV8818_SW_OUT_WR0_MSK, data);
    306	if (!lpf_band) {
    307		*lpf_freq = 0;
    308		return ret;
    309	}
    310
    311	ret = regmap_read(st->regmap, ADMV8818_REG_WR0_FILTER, &data);
    312	if (ret)
    313		return ret;
    314
    315	lpf_state = FIELD_GET(ADMV8818_LPF_WR0_MSK, data);
    316
    317	*lpf_freq = div_u64(freq_range_lpf[lpf_band - 1][1] - freq_range_lpf[lpf_band - 1][0], 15);
    318	*lpf_freq = freq_range_lpf[lpf_band - 1][0] + (*lpf_freq * lpf_state);
    319
    320	return ret;
    321}
    322
    323static int admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
    324{
    325	int ret;
    326
    327	mutex_lock(&st->lock);
    328	ret = __admv8818_read_lpf_freq(st, lpf_freq);
    329	mutex_unlock(&st->lock);
    330
    331	return ret;
    332}
    333
    334static int admv8818_write_raw(struct iio_dev *indio_dev,
    335			      struct iio_chan_spec const *chan,
    336			      int val, int val2, long info)
    337{
    338	struct admv8818_state *st = iio_priv(indio_dev);
    339
    340	u64 freq = ((u64)val2 << 32 | (u32)val);
    341
    342	switch (info) {
    343	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
    344		return admv8818_lpf_select(st, freq);
    345	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
    346		return admv8818_hpf_select(st, freq);
    347	default:
    348		return -EINVAL;
    349	}
    350}
    351
    352static int admv8818_read_raw(struct iio_dev *indio_dev,
    353			     struct iio_chan_spec const *chan,
    354			     int *val, int *val2, long info)
    355{
    356	struct admv8818_state *st = iio_priv(indio_dev);
    357	int ret;
    358	u64 freq;
    359
    360	switch (info) {
    361	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
    362		ret = admv8818_read_lpf_freq(st, &freq);
    363		if (ret)
    364			return ret;
    365
    366		*val = (u32)freq;
    367		*val2 = (u32)(freq >> 32);
    368
    369		return IIO_VAL_INT_64;
    370	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
    371		ret = admv8818_read_hpf_freq(st, &freq);
    372		if (ret)
    373			return ret;
    374
    375		*val = (u32)freq;
    376		*val2 = (u32)(freq >> 32);
    377
    378		return IIO_VAL_INT_64;
    379	default:
    380		return -EINVAL;
    381	}
    382}
    383
    384static int admv8818_reg_access(struct iio_dev *indio_dev,
    385			       unsigned int reg,
    386			       unsigned int write_val,
    387			       unsigned int *read_val)
    388{
    389	struct admv8818_state *st = iio_priv(indio_dev);
    390
    391	if (read_val)
    392		return regmap_read(st->regmap, reg, read_val);
    393	else
    394		return regmap_write(st->regmap, reg, write_val);
    395}
    396
    397static int admv8818_get_mode(struct iio_dev *indio_dev,
    398			     const struct iio_chan_spec *chan)
    399{
    400	struct admv8818_state *st = iio_priv(indio_dev);
    401
    402	return st->filter_mode;
    403}
    404
    405static int admv8818_set_mode(struct iio_dev *indio_dev,
    406			     const struct iio_chan_spec *chan,
    407			     unsigned int mode)
    408{
    409	struct admv8818_state *st = iio_priv(indio_dev);
    410	int ret = 0;
    411
    412	if (!st->clkin) {
    413		if (mode == ADMV8818_MANUAL_MODE)
    414			return 0;
    415
    416		return -EINVAL;
    417	}
    418
    419	switch (mode) {
    420	case ADMV8818_AUTO_MODE:
    421		if (!st->filter_mode)
    422			return 0;
    423
    424		ret = clk_prepare_enable(st->clkin);
    425		if (ret)
    426			return ret;
    427
    428		ret = clk_notifier_register(st->clkin, &st->nb);
    429		if (ret) {
    430			clk_disable_unprepare(st->clkin);
    431
    432			return ret;
    433		}
    434
    435		break;
    436	case ADMV8818_MANUAL_MODE:
    437		if (st->filter_mode)
    438			return 0;
    439
    440		clk_disable_unprepare(st->clkin);
    441
    442		ret = clk_notifier_unregister(st->clkin, &st->nb);
    443		if (ret)
    444			return ret;
    445
    446		break;
    447	default:
    448		return -EINVAL;
    449	}
    450
    451	st->filter_mode = mode;
    452
    453	return ret;
    454}
    455
    456static const struct iio_info admv8818_info = {
    457	.write_raw = admv8818_write_raw,
    458	.read_raw = admv8818_read_raw,
    459	.debugfs_reg_access = &admv8818_reg_access,
    460};
    461
    462static const struct iio_enum admv8818_mode_enum = {
    463	.items = admv8818_modes,
    464	.num_items = ARRAY_SIZE(admv8818_modes),
    465	.get = admv8818_get_mode,
    466	.set = admv8818_set_mode,
    467};
    468
    469static const struct iio_chan_spec_ext_info admv8818_ext_info[] = {
    470	IIO_ENUM("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),
    471	IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),
    472	{ },
    473};
    474
    475#define ADMV8818_CHAN(_channel) {				\
    476	.type = IIO_ALTVOLTAGE,					\
    477	.output = 1,						\
    478	.indexed = 1,						\
    479	.channel = _channel,					\
    480	.info_mask_separate =					\
    481		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
    482		BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) \
    483}
    484
    485#define ADMV8818_CHAN_BW_CF(_channel, _admv8818_ext_info) {	\
    486	.type = IIO_ALTVOLTAGE,					\
    487	.output = 1,						\
    488	.indexed = 1,						\
    489	.channel = _channel,					\
    490	.ext_info = _admv8818_ext_info,				\
    491}
    492
    493static const struct iio_chan_spec admv8818_channels[] = {
    494	ADMV8818_CHAN(0),
    495	ADMV8818_CHAN_BW_CF(0, admv8818_ext_info),
    496};
    497
    498static int admv8818_freq_change(struct notifier_block *nb, unsigned long action, void *data)
    499{
    500	struct admv8818_state *st = container_of(nb, struct admv8818_state, nb);
    501
    502	if (action == POST_RATE_CHANGE)
    503		return notifier_from_errno(admv8818_rfin_band_select(st));
    504
    505	return NOTIFY_OK;
    506}
    507
    508static void admv8818_clk_notifier_unreg(void *data)
    509{
    510	struct admv8818_state *st = data;
    511
    512	if (st->filter_mode == 0)
    513		clk_notifier_unregister(st->clkin, &st->nb);
    514}
    515
    516static void admv8818_clk_disable(void *data)
    517{
    518	struct admv8818_state *st = data;
    519
    520	if (st->filter_mode == 0)
    521		clk_disable_unprepare(st->clkin);
    522}
    523
    524static int admv8818_init(struct admv8818_state *st)
    525{
    526	int ret;
    527	struct spi_device *spi = st->spi;
    528	unsigned int chip_id;
    529
    530	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_A,
    531				 ADMV8818_SOFTRESET_N_MSK |
    532				 ADMV8818_SOFTRESET_MSK,
    533				 FIELD_PREP(ADMV8818_SOFTRESET_N_MSK, 1) |
    534				 FIELD_PREP(ADMV8818_SOFTRESET_MSK, 1));
    535	if (ret) {
    536		dev_err(&spi->dev, "ADMV8818 Soft Reset failed.\n");
    537		return ret;
    538	}
    539
    540	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_A,
    541				 ADMV8818_SDOACTIVE_N_MSK |
    542				 ADMV8818_SDOACTIVE_MSK,
    543				 FIELD_PREP(ADMV8818_SDOACTIVE_N_MSK, 1) |
    544				 FIELD_PREP(ADMV8818_SDOACTIVE_MSK, 1));
    545	if (ret) {
    546		dev_err(&spi->dev, "ADMV8818 SDO Enable failed.\n");
    547		return ret;
    548	}
    549
    550	ret = regmap_read(st->regmap, ADMV8818_REG_CHIPTYPE, &chip_id);
    551	if (ret) {
    552		dev_err(&spi->dev, "ADMV8818 Chip ID read failed.\n");
    553		return ret;
    554	}
    555
    556	if (chip_id != 0x1) {
    557		dev_err(&spi->dev, "ADMV8818 Invalid Chip ID.\n");
    558		return -EINVAL;
    559	}
    560
    561	ret = regmap_update_bits(st->regmap, ADMV8818_REG_SPI_CONFIG_B,
    562				 ADMV8818_SINGLE_INSTRUCTION_MSK,
    563				 FIELD_PREP(ADMV8818_SINGLE_INSTRUCTION_MSK, 1));
    564	if (ret) {
    565		dev_err(&spi->dev, "ADMV8818 Single Instruction failed.\n");
    566		return ret;
    567	}
    568
    569	if (st->clkin)
    570		return admv8818_rfin_band_select(st);
    571	else
    572		return 0;
    573}
    574
    575static int admv8818_clk_setup(struct admv8818_state *st)
    576{
    577	struct spi_device *spi = st->spi;
    578	int ret;
    579
    580	st->clkin = devm_clk_get_optional(&spi->dev, "rf_in");
    581	if (IS_ERR(st->clkin))
    582		return dev_err_probe(&spi->dev, PTR_ERR(st->clkin),
    583				     "failed to get the input clock\n");
    584	else if (!st->clkin)
    585		return 0;
    586
    587	ret = clk_prepare_enable(st->clkin);
    588	if (ret)
    589		return ret;
    590
    591	ret = devm_add_action_or_reset(&spi->dev, admv8818_clk_disable, st);
    592	if (ret)
    593		return ret;
    594
    595	st->nb.notifier_call = admv8818_freq_change;
    596	ret = clk_notifier_register(st->clkin, &st->nb);
    597	if (ret < 0)
    598		return ret;
    599
    600	return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st);
    601}
    602
    603static int admv8818_probe(struct spi_device *spi)
    604{
    605	struct iio_dev *indio_dev;
    606	struct regmap *regmap;
    607	struct admv8818_state *st;
    608	int ret;
    609
    610	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
    611	if (!indio_dev)
    612		return -ENOMEM;
    613
    614	regmap = devm_regmap_init_spi(spi, &admv8818_regmap_config);
    615	if (IS_ERR(regmap))
    616		return PTR_ERR(regmap);
    617
    618	st = iio_priv(indio_dev);
    619	st->regmap = regmap;
    620
    621	indio_dev->info = &admv8818_info;
    622	indio_dev->name = "admv8818";
    623	indio_dev->channels = admv8818_channels;
    624	indio_dev->num_channels = ARRAY_SIZE(admv8818_channels);
    625
    626	st->spi = spi;
    627
    628	ret = admv8818_clk_setup(st);
    629	if (ret)
    630		return ret;
    631
    632	mutex_init(&st->lock);
    633
    634	ret = admv8818_init(st);
    635	if (ret)
    636		return ret;
    637
    638	return devm_iio_device_register(&spi->dev, indio_dev);
    639}
    640
    641static const struct spi_device_id admv8818_id[] = {
    642	{ "admv8818", 0 },
    643	{}
    644};
    645MODULE_DEVICE_TABLE(spi, admv8818_id);
    646
    647static const struct of_device_id admv8818_of_match[] = {
    648	{ .compatible = "adi,admv8818" },
    649	{}
    650};
    651MODULE_DEVICE_TABLE(of, admv8818_of_match);
    652
    653static struct spi_driver admv8818_driver = {
    654	.driver = {
    655		.name = "admv8818",
    656		.of_match_table = admv8818_of_match,
    657	},
    658	.probe = admv8818_probe,
    659	.id_table = admv8818_id,
    660};
    661module_spi_driver(admv8818_driver);
    662
    663MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");
    664MODULE_DESCRIPTION("Analog Devices ADMV8818");
    665MODULE_LICENSE("GPL v2");