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

ti-adc161s626.c (5537B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * ti-adc161s626.c - Texas Instruments ADC161S626 1-channel differential ADC
      4 *
      5 * ADC Devices Supported:
      6 *  adc141s626 - 14-bit ADC
      7 *  adc161s626 - 16-bit ADC
      8 *
      9 * Copyright (C) 2016-2018
     10 * Author: Matt Ranostay <matt.ranostay@konsulko.com>
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/mod_devicetable.h>
     15#include <linux/init.h>
     16#include <linux/err.h>
     17#include <linux/spi/spi.h>
     18#include <linux/iio/iio.h>
     19#include <linux/iio/trigger.h>
     20#include <linux/iio/buffer.h>
     21#include <linux/iio/trigger_consumer.h>
     22#include <linux/iio/triggered_buffer.h>
     23#include <linux/regulator/consumer.h>
     24
     25#define TI_ADC_DRV_NAME	"ti-adc161s626"
     26
     27enum {
     28	TI_ADC141S626,
     29	TI_ADC161S626,
     30};
     31
     32static const struct iio_chan_spec ti_adc141s626_channels[] = {
     33	{
     34		.type = IIO_VOLTAGE,
     35		.channel = 0,
     36		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
     37				      BIT(IIO_CHAN_INFO_SCALE) |
     38				      BIT(IIO_CHAN_INFO_OFFSET),
     39		.scan_index = 0,
     40		.scan_type = {
     41			.sign = 's',
     42			.realbits = 14,
     43			.storagebits = 16,
     44		},
     45	},
     46	IIO_CHAN_SOFT_TIMESTAMP(1),
     47};
     48
     49static const struct iio_chan_spec ti_adc161s626_channels[] = {
     50	{
     51		.type = IIO_VOLTAGE,
     52		.channel = 0,
     53		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
     54				      BIT(IIO_CHAN_INFO_SCALE) |
     55				      BIT(IIO_CHAN_INFO_OFFSET),
     56		.scan_index = 0,
     57		.scan_type = {
     58			.sign = 's',
     59			.realbits = 16,
     60			.storagebits = 16,
     61		},
     62	},
     63	IIO_CHAN_SOFT_TIMESTAMP(1),
     64};
     65
     66struct ti_adc_data {
     67	struct iio_dev *indio_dev;
     68	struct spi_device *spi;
     69	struct regulator *ref;
     70
     71	u8 read_size;
     72	u8 shift;
     73
     74	u8 buffer[16] ____cacheline_aligned;
     75};
     76
     77static int ti_adc_read_measurement(struct ti_adc_data *data,
     78				   struct iio_chan_spec const *chan, int *val)
     79{
     80	int ret;
     81
     82	switch (data->read_size) {
     83	case 2: {
     84		__be16 buf;
     85
     86		ret = spi_read(data->spi, (void *) &buf, 2);
     87		if (ret)
     88			return ret;
     89
     90		*val = be16_to_cpu(buf);
     91		break;
     92	}
     93	case 3: {
     94		__be32 buf;
     95
     96		ret = spi_read(data->spi, (void *) &buf, 3);
     97		if (ret)
     98			return ret;
     99
    100		*val = be32_to_cpu(buf) >> 8;
    101		break;
    102	}
    103	default:
    104		return -EINVAL;
    105	}
    106
    107	*val = sign_extend32(*val >> data->shift, chan->scan_type.realbits - 1);
    108
    109	return 0;
    110}
    111
    112static irqreturn_t ti_adc_trigger_handler(int irq, void *private)
    113{
    114	struct iio_poll_func *pf = private;
    115	struct iio_dev *indio_dev = pf->indio_dev;
    116	struct ti_adc_data *data = iio_priv(indio_dev);
    117	int ret;
    118
    119	ret = ti_adc_read_measurement(data, &indio_dev->channels[0],
    120				     (int *) &data->buffer);
    121	if (!ret)
    122		iio_push_to_buffers_with_timestamp(indio_dev,
    123					data->buffer,
    124					iio_get_time_ns(indio_dev));
    125
    126	iio_trigger_notify_done(indio_dev->trig);
    127
    128	return IRQ_HANDLED;
    129}
    130
    131static int ti_adc_read_raw(struct iio_dev *indio_dev,
    132			   struct iio_chan_spec const *chan,
    133			   int *val, int *val2, long mask)
    134{
    135	struct ti_adc_data *data = iio_priv(indio_dev);
    136	int ret;
    137
    138	switch (mask) {
    139	case IIO_CHAN_INFO_RAW:
    140		ret = iio_device_claim_direct_mode(indio_dev);
    141		if (ret)
    142			return ret;
    143
    144		ret = ti_adc_read_measurement(data, chan, val);
    145		iio_device_release_direct_mode(indio_dev);
    146
    147		if (ret)
    148			return ret;
    149
    150		return IIO_VAL_INT;
    151	case IIO_CHAN_INFO_SCALE:
    152		ret = regulator_get_voltage(data->ref);
    153		if (ret < 0)
    154			return ret;
    155
    156		*val = ret / 1000;
    157		*val2 = chan->scan_type.realbits;
    158
    159		return IIO_VAL_FRACTIONAL_LOG2;
    160	case IIO_CHAN_INFO_OFFSET:
    161		*val = 1 << (chan->scan_type.realbits - 1);
    162		return IIO_VAL_INT;
    163	}
    164
    165	return 0;
    166}
    167
    168static const struct iio_info ti_adc_info = {
    169	.read_raw = ti_adc_read_raw,
    170};
    171
    172static void ti_adc_reg_disable(void *reg)
    173{
    174	regulator_disable(reg);
    175}
    176
    177static int ti_adc_probe(struct spi_device *spi)
    178{
    179	struct iio_dev *indio_dev;
    180	struct ti_adc_data *data;
    181	int ret;
    182
    183	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
    184	if (!indio_dev)
    185		return -ENOMEM;
    186
    187	indio_dev->info = &ti_adc_info;
    188	indio_dev->name = TI_ADC_DRV_NAME;
    189	indio_dev->modes = INDIO_DIRECT_MODE;
    190
    191	data = iio_priv(indio_dev);
    192	data->spi = spi;
    193
    194	switch (spi_get_device_id(spi)->driver_data) {
    195	case TI_ADC141S626:
    196		indio_dev->channels = ti_adc141s626_channels;
    197		indio_dev->num_channels = ARRAY_SIZE(ti_adc141s626_channels);
    198		data->shift = 0;
    199		data->read_size = 2;
    200		break;
    201	case TI_ADC161S626:
    202		indio_dev->channels = ti_adc161s626_channels;
    203		indio_dev->num_channels = ARRAY_SIZE(ti_adc161s626_channels);
    204		data->shift = 6;
    205		data->read_size = 3;
    206		break;
    207	}
    208
    209	data->ref = devm_regulator_get(&spi->dev, "vdda");
    210	if (IS_ERR(data->ref))
    211		return PTR_ERR(data->ref);
    212
    213	ret = regulator_enable(data->ref);
    214	if (ret < 0)
    215		return ret;
    216
    217	ret = devm_add_action_or_reset(&spi->dev, ti_adc_reg_disable,
    218				       data->ref);
    219	if (ret)
    220		return ret;
    221
    222	ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
    223					      ti_adc_trigger_handler, NULL);
    224	if (ret)
    225		return ret;
    226
    227	return devm_iio_device_register(&spi->dev, indio_dev);
    228}
    229
    230static const struct of_device_id ti_adc_dt_ids[] = {
    231	{ .compatible = "ti,adc141s626", },
    232	{ .compatible = "ti,adc161s626", },
    233	{}
    234};
    235MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
    236
    237static const struct spi_device_id ti_adc_id[] = {
    238	{"adc141s626", TI_ADC141S626},
    239	{"adc161s626", TI_ADC161S626},
    240	{},
    241};
    242MODULE_DEVICE_TABLE(spi, ti_adc_id);
    243
    244static struct spi_driver ti_adc_driver = {
    245	.driver = {
    246		.name	= TI_ADC_DRV_NAME,
    247		.of_match_table = ti_adc_dt_ids,
    248	},
    249	.probe		= ti_adc_probe,
    250	.id_table	= ti_adc_id,
    251};
    252module_spi_driver(ti_adc_driver);
    253
    254MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
    255MODULE_DESCRIPTION("Texas Instruments ADC1x1S 1-channel differential ADC");
    256MODULE_LICENSE("GPL");