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

ad5761.c (9405B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AD5721, AD5721R, AD5761, AD5761R, Voltage Output Digital to Analog Converter
      4 *
      5 * Copyright 2016 Qtechnology A/S
      6 * 2016 Ricardo Ribalda <ribalda@kernel.org>
      7 */
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/spi/spi.h>
     11#include <linux/bitops.h>
     12#include <linux/iio/iio.h>
     13#include <linux/iio/sysfs.h>
     14#include <linux/regulator/consumer.h>
     15#include <linux/platform_data/ad5761.h>
     16
     17#define AD5761_ADDR(addr)		((addr & 0xf) << 16)
     18#define AD5761_ADDR_NOOP		0x0
     19#define AD5761_ADDR_DAC_WRITE		0x3
     20#define AD5761_ADDR_CTRL_WRITE_REG	0x4
     21#define AD5761_ADDR_SW_DATA_RESET	0x7
     22#define AD5761_ADDR_DAC_READ		0xb
     23#define AD5761_ADDR_CTRL_READ_REG	0xc
     24#define AD5761_ADDR_SW_FULL_RESET	0xf
     25
     26#define AD5761_CTRL_USE_INTVREF		BIT(5)
     27#define AD5761_CTRL_ETS			BIT(6)
     28
     29/**
     30 * struct ad5761_chip_info - chip specific information
     31 * @int_vref:	Value of the internal reference voltage in mV - 0 if external
     32 *		reference voltage is used
     33 * @channel:	channel specification
     34*/
     35
     36struct ad5761_chip_info {
     37	unsigned long int_vref;
     38	const struct iio_chan_spec channel;
     39};
     40
     41struct ad5761_range_params {
     42	int m;
     43	int c;
     44};
     45
     46enum ad5761_supported_device_ids {
     47	ID_AD5721,
     48	ID_AD5721R,
     49	ID_AD5761,
     50	ID_AD5761R,
     51};
     52
     53/**
     54 * struct ad5761_state - driver instance specific data
     55 * @spi:		spi_device
     56 * @vref_reg:		reference voltage regulator
     57 * @use_intref:		true when the internal voltage reference is used
     58 * @vref:		actual voltage reference in mVolts
     59 * @range:		output range mode used
     60 * @lock:		lock to protect the data buffer during SPI ops
     61 * @data:		cache aligned spi buffer
     62 */
     63struct ad5761_state {
     64	struct spi_device		*spi;
     65	struct regulator		*vref_reg;
     66	struct mutex			lock;
     67
     68	bool use_intref;
     69	int vref;
     70	enum ad5761_voltage_range range;
     71
     72	/*
     73	 * DMA (thus cache coherency maintenance) requires the
     74	 * transfer buffers to live in their own cache lines.
     75	 */
     76	union {
     77		__be32 d32;
     78		u8 d8[4];
     79	} data[3] ____cacheline_aligned;
     80};
     81
     82static const struct ad5761_range_params ad5761_range_params[] = {
     83	[AD5761_VOLTAGE_RANGE_M10V_10V] = {
     84		.m = 80,
     85		.c = 40,
     86	},
     87	[AD5761_VOLTAGE_RANGE_0V_10V] = {
     88		.m = 40,
     89		.c = 0,
     90	},
     91	[AD5761_VOLTAGE_RANGE_M5V_5V] = {
     92		.m = 40,
     93		.c = 20,
     94	},
     95	[AD5761_VOLTAGE_RANGE_0V_5V] = {
     96		.m = 20,
     97		.c = 0,
     98	},
     99	[AD5761_VOLTAGE_RANGE_M2V5_7V5] = {
    100		.m = 40,
    101		.c = 10,
    102	},
    103	[AD5761_VOLTAGE_RANGE_M3V_3V] = {
    104		.m = 24,
    105		.c = 12,
    106	},
    107	[AD5761_VOLTAGE_RANGE_0V_16V] = {
    108		.m = 64,
    109		.c = 0,
    110	},
    111	[AD5761_VOLTAGE_RANGE_0V_20V] = {
    112		.m = 80,
    113		.c = 0,
    114	},
    115};
    116
    117static int _ad5761_spi_write(struct ad5761_state *st, u8 addr, u16 val)
    118{
    119	st->data[0].d32 = cpu_to_be32(AD5761_ADDR(addr) | val);
    120
    121	return spi_write(st->spi, &st->data[0].d8[1], 3);
    122}
    123
    124static int ad5761_spi_write(struct iio_dev *indio_dev, u8 addr, u16 val)
    125{
    126	struct ad5761_state *st = iio_priv(indio_dev);
    127	int ret;
    128
    129	mutex_lock(&st->lock);
    130	ret = _ad5761_spi_write(st, addr, val);
    131	mutex_unlock(&st->lock);
    132
    133	return ret;
    134}
    135
    136static int _ad5761_spi_read(struct ad5761_state *st, u8 addr, u16 *val)
    137{
    138	int ret;
    139	struct spi_transfer xfers[] = {
    140		{
    141			.tx_buf = &st->data[0].d8[1],
    142			.bits_per_word = 8,
    143			.len = 3,
    144			.cs_change = true,
    145		}, {
    146			.tx_buf = &st->data[1].d8[1],
    147			.rx_buf = &st->data[2].d8[1],
    148			.bits_per_word = 8,
    149			.len = 3,
    150		},
    151	};
    152
    153	st->data[0].d32 = cpu_to_be32(AD5761_ADDR(addr));
    154	st->data[1].d32 = cpu_to_be32(AD5761_ADDR(AD5761_ADDR_NOOP));
    155
    156	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
    157
    158	*val = be32_to_cpu(st->data[2].d32);
    159
    160	return ret;
    161}
    162
    163static int ad5761_spi_read(struct iio_dev *indio_dev, u8 addr, u16 *val)
    164{
    165	struct ad5761_state *st = iio_priv(indio_dev);
    166	int ret;
    167
    168	mutex_lock(&st->lock);
    169	ret = _ad5761_spi_read(st, addr, val);
    170	mutex_unlock(&st->lock);
    171
    172	return ret;
    173}
    174
    175static int ad5761_spi_set_range(struct ad5761_state *st,
    176				enum ad5761_voltage_range range)
    177{
    178	u16 aux;
    179	int ret;
    180
    181	aux = (range & 0x7) | AD5761_CTRL_ETS;
    182
    183	if (st->use_intref)
    184		aux |= AD5761_CTRL_USE_INTVREF;
    185
    186	ret = _ad5761_spi_write(st, AD5761_ADDR_SW_FULL_RESET, 0);
    187	if (ret)
    188		return ret;
    189
    190	ret = _ad5761_spi_write(st, AD5761_ADDR_CTRL_WRITE_REG, aux);
    191	if (ret)
    192		return ret;
    193
    194	st->range = range;
    195
    196	return 0;
    197}
    198
    199static int ad5761_read_raw(struct iio_dev *indio_dev,
    200			   struct iio_chan_spec const *chan,
    201			   int *val,
    202			   int *val2,
    203			   long mask)
    204{
    205	struct ad5761_state *st;
    206	int ret;
    207	u16 aux;
    208
    209	switch (mask) {
    210	case IIO_CHAN_INFO_RAW:
    211		ret = ad5761_spi_read(indio_dev, AD5761_ADDR_DAC_READ, &aux);
    212		if (ret)
    213			return ret;
    214		*val = aux >> chan->scan_type.shift;
    215		return IIO_VAL_INT;
    216	case IIO_CHAN_INFO_SCALE:
    217		st = iio_priv(indio_dev);
    218		*val = st->vref * ad5761_range_params[st->range].m;
    219		*val /= 10;
    220		*val2 = chan->scan_type.realbits;
    221		return IIO_VAL_FRACTIONAL_LOG2;
    222	case IIO_CHAN_INFO_OFFSET:
    223		st = iio_priv(indio_dev);
    224		*val = -(1 << chan->scan_type.realbits);
    225		*val *=	ad5761_range_params[st->range].c;
    226		*val /=	ad5761_range_params[st->range].m;
    227		return IIO_VAL_INT;
    228	default:
    229		return -EINVAL;
    230	}
    231}
    232
    233static int ad5761_write_raw(struct iio_dev *indio_dev,
    234			    struct iio_chan_spec const *chan,
    235			    int val,
    236			    int val2,
    237			    long mask)
    238{
    239	u16 aux;
    240
    241	if (mask != IIO_CHAN_INFO_RAW)
    242		return -EINVAL;
    243
    244	if (val2 || (val << chan->scan_type.shift) > 0xffff || val < 0)
    245		return -EINVAL;
    246
    247	aux = val << chan->scan_type.shift;
    248
    249	return ad5761_spi_write(indio_dev, AD5761_ADDR_DAC_WRITE, aux);
    250}
    251
    252static const struct iio_info ad5761_info = {
    253	.read_raw = &ad5761_read_raw,
    254	.write_raw = &ad5761_write_raw,
    255};
    256
    257#define AD5761_CHAN(_bits) {				\
    258	.type = IIO_VOLTAGE,				\
    259	.output = 1,					\
    260	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
    261	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
    262		BIT(IIO_CHAN_INFO_OFFSET),		\
    263	.scan_type = {					\
    264		.sign = 'u',				\
    265		.realbits = (_bits),			\
    266		.storagebits = 16,			\
    267		.shift = 16 - (_bits),			\
    268	},						\
    269}
    270
    271static const struct ad5761_chip_info ad5761_chip_infos[] = {
    272	[ID_AD5721] = {
    273		.int_vref = 0,
    274		.channel = AD5761_CHAN(12),
    275	},
    276	[ID_AD5721R] = {
    277		.int_vref = 2500,
    278		.channel = AD5761_CHAN(12),
    279	},
    280	[ID_AD5761] = {
    281		.int_vref = 0,
    282		.channel = AD5761_CHAN(16),
    283	},
    284	[ID_AD5761R] = {
    285		.int_vref = 2500,
    286		.channel = AD5761_CHAN(16),
    287	},
    288};
    289
    290static int ad5761_get_vref(struct ad5761_state *st,
    291			   const struct ad5761_chip_info *chip_info)
    292{
    293	int ret;
    294
    295	st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref");
    296	if (PTR_ERR(st->vref_reg) == -ENODEV) {
    297		/* Use Internal regulator */
    298		if (!chip_info->int_vref) {
    299			dev_err(&st->spi->dev,
    300				"Voltage reference not found\n");
    301			return -EIO;
    302		}
    303
    304		st->use_intref = true;
    305		st->vref = chip_info->int_vref;
    306		return 0;
    307	}
    308
    309	if (IS_ERR(st->vref_reg)) {
    310		dev_err(&st->spi->dev,
    311			"Error getting voltage reference regulator\n");
    312		return PTR_ERR(st->vref_reg);
    313	}
    314
    315	ret = regulator_enable(st->vref_reg);
    316	if (ret) {
    317		dev_err(&st->spi->dev,
    318			 "Failed to enable voltage reference\n");
    319		return ret;
    320	}
    321
    322	ret = regulator_get_voltage(st->vref_reg);
    323	if (ret < 0) {
    324		dev_err(&st->spi->dev,
    325			 "Failed to get voltage reference value\n");
    326		goto disable_regulator_vref;
    327	}
    328
    329	if (ret < 2000000 || ret > 3000000) {
    330		dev_warn(&st->spi->dev,
    331			 "Invalid external voltage ref. value %d uV\n", ret);
    332		ret = -EIO;
    333		goto disable_regulator_vref;
    334	}
    335
    336	st->vref = ret / 1000;
    337	st->use_intref = false;
    338
    339	return 0;
    340
    341disable_regulator_vref:
    342	regulator_disable(st->vref_reg);
    343	st->vref_reg = NULL;
    344	return ret;
    345}
    346
    347static int ad5761_probe(struct spi_device *spi)
    348{
    349	struct iio_dev *iio_dev;
    350	struct ad5761_state *st;
    351	int ret;
    352	const struct ad5761_chip_info *chip_info =
    353		&ad5761_chip_infos[spi_get_device_id(spi)->driver_data];
    354	enum ad5761_voltage_range voltage_range = AD5761_VOLTAGE_RANGE_0V_5V;
    355	struct ad5761_platform_data *pdata = dev_get_platdata(&spi->dev);
    356
    357	iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
    358	if (!iio_dev)
    359		return -ENOMEM;
    360
    361	st = iio_priv(iio_dev);
    362
    363	st->spi = spi;
    364	spi_set_drvdata(spi, iio_dev);
    365
    366	ret = ad5761_get_vref(st, chip_info);
    367	if (ret)
    368		return ret;
    369
    370	if (pdata)
    371		voltage_range = pdata->voltage_range;
    372
    373	mutex_init(&st->lock);
    374
    375	ret = ad5761_spi_set_range(st, voltage_range);
    376	if (ret)
    377		goto disable_regulator_err;
    378
    379	iio_dev->info = &ad5761_info;
    380	iio_dev->modes = INDIO_DIRECT_MODE;
    381	iio_dev->channels = &chip_info->channel;
    382	iio_dev->num_channels = 1;
    383	iio_dev->name = spi_get_device_id(st->spi)->name;
    384	ret = iio_device_register(iio_dev);
    385	if (ret)
    386		goto disable_regulator_err;
    387
    388	return 0;
    389
    390disable_regulator_err:
    391	if (!IS_ERR_OR_NULL(st->vref_reg))
    392		regulator_disable(st->vref_reg);
    393
    394	return ret;
    395}
    396
    397static void ad5761_remove(struct spi_device *spi)
    398{
    399	struct iio_dev *iio_dev = spi_get_drvdata(spi);
    400	struct ad5761_state *st = iio_priv(iio_dev);
    401
    402	iio_device_unregister(iio_dev);
    403
    404	if (!IS_ERR_OR_NULL(st->vref_reg))
    405		regulator_disable(st->vref_reg);
    406}
    407
    408static const struct spi_device_id ad5761_id[] = {
    409	{"ad5721", ID_AD5721},
    410	{"ad5721r", ID_AD5721R},
    411	{"ad5761", ID_AD5761},
    412	{"ad5761r", ID_AD5761R},
    413	{}
    414};
    415MODULE_DEVICE_TABLE(spi, ad5761_id);
    416
    417static struct spi_driver ad5761_driver = {
    418	.driver = {
    419		   .name = "ad5761",
    420		   },
    421	.probe = ad5761_probe,
    422	.remove = ad5761_remove,
    423	.id_table = ad5761_id,
    424};
    425module_spi_driver(ad5761_driver);
    426
    427MODULE_AUTHOR("Ricardo Ribalda <ribalda@kernel.org>");
    428MODULE_DESCRIPTION("Analog Devices AD5721, AD5721R, AD5761, AD5761R driver");
    429MODULE_LICENSE("GPL v2");