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

ad8366.c (7113B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * AD8366 and similar Gain Amplifiers
      4 * This driver supports the following gain amplifiers:
      5 *   AD8366 Dual-Digital Variable Gain Amplifier (VGA)
      6 *   ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
      7 *   ADL5240 Digitally controlled variable gain amplifier (VGA)
      8 *   HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
      9 *
     10 * Copyright 2012-2019 Analog Devices Inc.
     11 */
     12
     13#include <linux/device.h>
     14#include <linux/kernel.h>
     15#include <linux/slab.h>
     16#include <linux/sysfs.h>
     17#include <linux/spi/spi.h>
     18#include <linux/regulator/consumer.h>
     19#include <linux/gpio/consumer.h>
     20#include <linux/err.h>
     21#include <linux/module.h>
     22#include <linux/bitrev.h>
     23
     24#include <linux/iio/iio.h>
     25#include <linux/iio/sysfs.h>
     26
     27enum ad8366_type {
     28	ID_AD8366,
     29	ID_ADA4961,
     30	ID_ADL5240,
     31	ID_HMC1119,
     32};
     33
     34struct ad8366_info {
     35	int gain_min;
     36	int gain_max;
     37};
     38
     39struct ad8366_state {
     40	struct spi_device	*spi;
     41	struct regulator	*reg;
     42	struct mutex            lock; /* protect sensor state */
     43	struct gpio_desc	*reset_gpio;
     44	unsigned char		ch[2];
     45	enum ad8366_type	type;
     46	struct ad8366_info	*info;
     47	/*
     48	 * DMA (thus cache coherency maintenance) requires the
     49	 * transfer buffers to live in their own cache lines.
     50	 */
     51	unsigned char		data[2] ____cacheline_aligned;
     52};
     53
     54static struct ad8366_info ad8366_infos[] = {
     55	[ID_AD8366] = {
     56		.gain_min = 4500,
     57		.gain_max = 20500,
     58	},
     59	[ID_ADA4961] = {
     60		.gain_min = -6000,
     61		.gain_max = 15000,
     62	},
     63	[ID_ADL5240] = {
     64		.gain_min = -11500,
     65		.gain_max = 20000,
     66	},
     67	[ID_HMC1119] = {
     68		.gain_min = -31750,
     69		.gain_max = 0,
     70	},
     71};
     72
     73static int ad8366_write(struct iio_dev *indio_dev,
     74			unsigned char ch_a, unsigned char ch_b)
     75{
     76	struct ad8366_state *st = iio_priv(indio_dev);
     77	int ret;
     78
     79	switch (st->type) {
     80	case ID_AD8366:
     81		ch_a = bitrev8(ch_a & 0x3F);
     82		ch_b = bitrev8(ch_b & 0x3F);
     83
     84		st->data[0] = ch_b >> 4;
     85		st->data[1] = (ch_b << 4) | (ch_a >> 2);
     86		break;
     87	case ID_ADA4961:
     88		st->data[0] = ch_a & 0x1F;
     89		break;
     90	case ID_ADL5240:
     91		st->data[0] = (ch_a & 0x3F);
     92		break;
     93	case ID_HMC1119:
     94		st->data[0] = ch_a;
     95		break;
     96	}
     97
     98	ret = spi_write(st->spi, st->data, indio_dev->num_channels);
     99	if (ret < 0)
    100		dev_err(&indio_dev->dev, "write failed (%d)", ret);
    101
    102	return ret;
    103}
    104
    105static int ad8366_read_raw(struct iio_dev *indio_dev,
    106			   struct iio_chan_spec const *chan,
    107			   int *val,
    108			   int *val2,
    109			   long m)
    110{
    111	struct ad8366_state *st = iio_priv(indio_dev);
    112	int ret;
    113	int code, gain = 0;
    114
    115	mutex_lock(&st->lock);
    116	switch (m) {
    117	case IIO_CHAN_INFO_HARDWAREGAIN:
    118		code = st->ch[chan->channel];
    119
    120		switch (st->type) {
    121		case ID_AD8366:
    122			gain = code * 253 + 4500;
    123			break;
    124		case ID_ADA4961:
    125			gain = 15000 - code * 1000;
    126			break;
    127		case ID_ADL5240:
    128			gain = 20000 - 31500 + code * 500;
    129			break;
    130		case ID_HMC1119:
    131			gain = -1 * code * 250;
    132			break;
    133		}
    134
    135		/* Values in dB */
    136		*val = gain / 1000;
    137		*val2 = (gain % 1000) * 1000;
    138
    139		ret = IIO_VAL_INT_PLUS_MICRO_DB;
    140		break;
    141	default:
    142		ret = -EINVAL;
    143	}
    144	mutex_unlock(&st->lock);
    145
    146	return ret;
    147};
    148
    149static int ad8366_write_raw(struct iio_dev *indio_dev,
    150			    struct iio_chan_spec const *chan,
    151			    int val,
    152			    int val2,
    153			    long mask)
    154{
    155	struct ad8366_state *st = iio_priv(indio_dev);
    156	struct ad8366_info *inf = st->info;
    157	int code = 0, gain;
    158	int ret;
    159
    160	/* Values in dB */
    161	if (val < 0)
    162		gain = (val * 1000) - (val2 / 1000);
    163	else
    164		gain = (val * 1000) + (val2 / 1000);
    165
    166	if (gain > inf->gain_max || gain < inf->gain_min)
    167		return -EINVAL;
    168
    169	switch (st->type) {
    170	case ID_AD8366:
    171		code = (gain - 4500) / 253;
    172		break;
    173	case ID_ADA4961:
    174		code = (15000 - gain) / 1000;
    175		break;
    176	case ID_ADL5240:
    177		code = ((gain - 500 - 20000) / 500) & 0x3F;
    178		break;
    179	case ID_HMC1119:
    180		code = (abs(gain) / 250) & 0x7F;
    181		break;
    182	}
    183
    184	mutex_lock(&st->lock);
    185	switch (mask) {
    186	case IIO_CHAN_INFO_HARDWAREGAIN:
    187		st->ch[chan->channel] = code;
    188		ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
    189		break;
    190	default:
    191		ret = -EINVAL;
    192	}
    193	mutex_unlock(&st->lock);
    194
    195	return ret;
    196}
    197
    198static int ad8366_write_raw_get_fmt(struct iio_dev *indio_dev,
    199				    struct iio_chan_spec const *chan,
    200				    long mask)
    201{
    202	switch (mask) {
    203	case IIO_CHAN_INFO_HARDWAREGAIN:
    204		return IIO_VAL_INT_PLUS_MICRO_DB;
    205	default:
    206		return -EINVAL;
    207	}
    208}
    209
    210static const struct iio_info ad8366_info = {
    211	.read_raw = &ad8366_read_raw,
    212	.write_raw = &ad8366_write_raw,
    213	.write_raw_get_fmt = &ad8366_write_raw_get_fmt,
    214};
    215
    216#define AD8366_CHAN(_channel) {				\
    217	.type = IIO_VOLTAGE,				\
    218	.output = 1,					\
    219	.indexed = 1,					\
    220	.channel = _channel,				\
    221	.info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),\
    222}
    223
    224static const struct iio_chan_spec ad8366_channels[] = {
    225	AD8366_CHAN(0),
    226	AD8366_CHAN(1),
    227};
    228
    229static const struct iio_chan_spec ada4961_channels[] = {
    230	AD8366_CHAN(0),
    231};
    232
    233static int ad8366_probe(struct spi_device *spi)
    234{
    235	struct iio_dev *indio_dev;
    236	struct ad8366_state *st;
    237	int ret;
    238
    239	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
    240	if (indio_dev == NULL)
    241		return -ENOMEM;
    242
    243	st = iio_priv(indio_dev);
    244
    245	st->reg = devm_regulator_get(&spi->dev, "vcc");
    246	if (!IS_ERR(st->reg)) {
    247		ret = regulator_enable(st->reg);
    248		if (ret)
    249			return ret;
    250	}
    251
    252	spi_set_drvdata(spi, indio_dev);
    253	mutex_init(&st->lock);
    254	st->spi = spi;
    255	st->type = spi_get_device_id(spi)->driver_data;
    256
    257	switch (st->type) {
    258	case ID_AD8366:
    259		indio_dev->channels = ad8366_channels;
    260		indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
    261		break;
    262	case ID_ADA4961:
    263	case ID_ADL5240:
    264	case ID_HMC1119:
    265		st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH);
    266		if (IS_ERR(st->reset_gpio)) {
    267			ret = PTR_ERR(st->reset_gpio);
    268			goto error_disable_reg;
    269		}
    270		indio_dev->channels = ada4961_channels;
    271		indio_dev->num_channels = ARRAY_SIZE(ada4961_channels);
    272		break;
    273	default:
    274		dev_err(&spi->dev, "Invalid device ID\n");
    275		ret = -EINVAL;
    276		goto error_disable_reg;
    277	}
    278
    279	st->info = &ad8366_infos[st->type];
    280	indio_dev->name = spi_get_device_id(spi)->name;
    281	indio_dev->info = &ad8366_info;
    282	indio_dev->modes = INDIO_DIRECT_MODE;
    283
    284	ret = ad8366_write(indio_dev, 0 , 0);
    285	if (ret < 0)
    286		goto error_disable_reg;
    287
    288	ret = iio_device_register(indio_dev);
    289	if (ret)
    290		goto error_disable_reg;
    291
    292	return 0;
    293
    294error_disable_reg:
    295	if (!IS_ERR(st->reg))
    296		regulator_disable(st->reg);
    297
    298	return ret;
    299}
    300
    301static void ad8366_remove(struct spi_device *spi)
    302{
    303	struct iio_dev *indio_dev = spi_get_drvdata(spi);
    304	struct ad8366_state *st = iio_priv(indio_dev);
    305	struct regulator *reg = st->reg;
    306
    307	iio_device_unregister(indio_dev);
    308
    309	if (!IS_ERR(reg))
    310		regulator_disable(reg);
    311}
    312
    313static const struct spi_device_id ad8366_id[] = {
    314	{"ad8366",  ID_AD8366},
    315	{"ada4961", ID_ADA4961},
    316	{"adl5240", ID_ADL5240},
    317	{"hmc1119", ID_HMC1119},
    318	{}
    319};
    320MODULE_DEVICE_TABLE(spi, ad8366_id);
    321
    322static struct spi_driver ad8366_driver = {
    323	.driver = {
    324		.name	= KBUILD_MODNAME,
    325	},
    326	.probe		= ad8366_probe,
    327	.remove		= ad8366_remove,
    328	.id_table	= ad8366_id,
    329};
    330
    331module_spi_driver(ad8366_driver);
    332
    333MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
    334MODULE_DESCRIPTION("Analog Devices AD8366 and similar Gain Amplifiers");
    335MODULE_LICENSE("GPL v2");