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

ltc2497-core.c (6137B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ltc2497-core.c - Common code for Analog Devices/Linear Technology
      4 * LTC2496 and LTC2497 ADCs
      5 *
      6 * Copyright (C) 2017 Analog Devices Inc.
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/iio/iio.h>
     11#include <linux/iio/driver.h>
     12#include <linux/module.h>
     13#include <linux/regulator/consumer.h>
     14
     15#include "ltc2497.h"
     16
     17#define LTC2497_SGL			BIT(4)
     18#define LTC2497_DIFF			0
     19#define LTC2497_SIGN			BIT(3)
     20
     21static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata)
     22{
     23	s64 time_elapsed;
     24
     25	time_elapsed = ktime_ms_delta(ktime_get(), ddata->time_prev);
     26
     27	if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
     28		/* delay if conversion time not passed
     29		 * since last read or write
     30		 */
     31		if (msleep_interruptible(
     32		    LTC2497_CONVERSION_TIME_MS - time_elapsed))
     33			return -ERESTARTSYS;
     34
     35		return 0;
     36	}
     37
     38	if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
     39		/* We're in automatic mode -
     40		 * so the last reading is still not outdated
     41		 */
     42		return 0;
     43	}
     44
     45	return 1;
     46}
     47
     48static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, int *val)
     49{
     50	int ret;
     51
     52	ret = ltc2497core_wait_conv(ddata);
     53	if (ret < 0)
     54		return ret;
     55
     56	if (ret || ddata->addr_prev != address) {
     57		ret = ddata->result_and_measure(ddata, address, NULL);
     58		if (ret < 0)
     59			return ret;
     60		ddata->addr_prev = address;
     61
     62		if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
     63			return -ERESTARTSYS;
     64	}
     65
     66	ret = ddata->result_and_measure(ddata, address, val);
     67	if (ret < 0)
     68		return ret;
     69
     70	ddata->time_prev = ktime_get();
     71
     72	return ret;
     73}
     74
     75static int ltc2497core_read_raw(struct iio_dev *indio_dev,
     76			    struct iio_chan_spec const *chan,
     77			    int *val, int *val2, long mask)
     78{
     79	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
     80	int ret;
     81
     82	switch (mask) {
     83	case IIO_CHAN_INFO_RAW:
     84		mutex_lock(&indio_dev->mlock);
     85		ret = ltc2497core_read(ddata, chan->address, val);
     86		mutex_unlock(&indio_dev->mlock);
     87		if (ret < 0)
     88			return ret;
     89
     90		return IIO_VAL_INT;
     91
     92	case IIO_CHAN_INFO_SCALE:
     93		ret = regulator_get_voltage(ddata->ref);
     94		if (ret < 0)
     95			return ret;
     96
     97		*val = ret / 1000;
     98		*val2 = 17;
     99
    100		return IIO_VAL_FRACTIONAL_LOG2;
    101
    102	default:
    103		return -EINVAL;
    104	}
    105}
    106
    107#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
    108	.type = IIO_VOLTAGE, \
    109	.indexed = 1, \
    110	.channel = (_chan), \
    111	.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
    112	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
    113	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
    114	.datasheet_name = (_ds_name), \
    115}
    116
    117#define LTC2497_CHAN_DIFF(_chan, _addr) { \
    118	.type = IIO_VOLTAGE, \
    119	.indexed = 1, \
    120	.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
    121	.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
    122	.address = (_addr | _chan), \
    123	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
    124	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
    125	.differential = 1, \
    126}
    127
    128static const struct iio_chan_spec ltc2497core_channel[] = {
    129	LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
    130	LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
    131	LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
    132	LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
    133	LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
    134	LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
    135	LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
    136	LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
    137	LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
    138	LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
    139	LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
    140	LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
    141	LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
    142	LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
    143	LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
    144	LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
    145	LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
    146	LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
    147	LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
    148	LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
    149	LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
    150	LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
    151	LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
    152	LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
    153	LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
    154	LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
    155	LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
    156	LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
    157	LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
    158	LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
    159	LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
    160	LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
    161};
    162
    163static const struct iio_info ltc2497core_info = {
    164	.read_raw = ltc2497core_read_raw,
    165};
    166
    167int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
    168{
    169	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
    170	int ret;
    171
    172	indio_dev->name = dev_name(dev);
    173	indio_dev->info = &ltc2497core_info;
    174	indio_dev->modes = INDIO_DIRECT_MODE;
    175	indio_dev->channels = ltc2497core_channel;
    176	indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
    177
    178	ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);
    179	if (ret < 0)
    180		return ret;
    181
    182	ddata->ref = devm_regulator_get(dev, "vref");
    183	if (IS_ERR(ddata->ref))
    184		return dev_err_probe(dev, PTR_ERR(ddata->ref),
    185				     "Failed to get vref regulator\n");
    186
    187	ret = regulator_enable(ddata->ref);
    188	if (ret < 0) {
    189		dev_err(dev, "Failed to enable vref regulator: %pe\n",
    190			ERR_PTR(ret));
    191		return ret;
    192	}
    193
    194	if (dev->platform_data) {
    195		struct iio_map *plat_data;
    196
    197		plat_data = (struct iio_map *)dev->platform_data;
    198
    199		ret = iio_map_array_register(indio_dev, plat_data);
    200		if (ret) {
    201			dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
    202			goto err_regulator_disable;
    203		}
    204	}
    205
    206	ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
    207	ddata->time_prev = ktime_get();
    208
    209	ret = iio_device_register(indio_dev);
    210	if (ret < 0)
    211		goto err_array_unregister;
    212
    213	return 0;
    214
    215err_array_unregister:
    216	iio_map_array_unregister(indio_dev);
    217
    218err_regulator_disable:
    219	regulator_disable(ddata->ref);
    220
    221	return ret;
    222}
    223EXPORT_SYMBOL_NS(ltc2497core_probe, LTC2497);
    224
    225void ltc2497core_remove(struct iio_dev *indio_dev)
    226{
    227	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
    228
    229	iio_device_unregister(indio_dev);
    230
    231	iio_map_array_unregister(indio_dev);
    232
    233	regulator_disable(ddata->ref);
    234}
    235EXPORT_SYMBOL_NS(ltc2497core_remove, LTC2497);
    236
    237MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers");
    238MODULE_LICENSE("GPL v2");