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

ltc2632.c (12724B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * LTC2632 Digital to analog convertors spi driver
      4 *
      5 * Copyright 2017 Maxime Roussin-BĂ©langer
      6 * expanded by Silvan Murer <silvan.murer@gmail.com>
      7 */
      8
      9#include <linux/device.h>
     10#include <linux/spi/spi.h>
     11#include <linux/module.h>
     12#include <linux/iio/iio.h>
     13#include <linux/property.h>
     14#include <linux/regulator/consumer.h>
     15
     16#include <asm/unaligned.h>
     17
     18#define LTC2632_CMD_WRITE_INPUT_N               0x0
     19#define LTC2632_CMD_UPDATE_DAC_N                0x1
     20#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL    0x2
     21#define LTC2632_CMD_WRITE_INPUT_N_UPDATE_N      0x3
     22#define LTC2632_CMD_POWERDOWN_DAC_N             0x4
     23#define LTC2632_CMD_POWERDOWN_CHIP              0x5
     24#define LTC2632_CMD_INTERNAL_REFER              0x6
     25#define LTC2632_CMD_EXTERNAL_REFER              0x7
     26
     27/**
     28 * struct ltc2632_chip_info - chip specific information
     29 * @channels:		channel spec for the DAC
     30 * @num_channels:	DAC channel count of the chip
     31 * @vref_mv:		internal reference voltage
     32 */
     33struct ltc2632_chip_info {
     34	const struct iio_chan_spec *channels;
     35	const size_t num_channels;
     36	const int vref_mv;
     37};
     38
     39/**
     40 * struct ltc2632_state - driver instance specific data
     41 * @spi_dev:			pointer to the spi_device struct
     42 * @powerdown_cache_mask:	used to show current channel powerdown state
     43 * @vref_mv:			used reference voltage (internal or external)
     44 * @vref_reg:		regulator for the reference voltage
     45 */
     46struct ltc2632_state {
     47	struct spi_device *spi_dev;
     48	unsigned int powerdown_cache_mask;
     49	int vref_mv;
     50	struct regulator *vref_reg;
     51};
     52
     53enum ltc2632_supported_device_ids {
     54	ID_LTC2632L12,
     55	ID_LTC2632L10,
     56	ID_LTC2632L8,
     57	ID_LTC2632H12,
     58	ID_LTC2632H10,
     59	ID_LTC2632H8,
     60	ID_LTC2634L12,
     61	ID_LTC2634L10,
     62	ID_LTC2634L8,
     63	ID_LTC2634H12,
     64	ID_LTC2634H10,
     65	ID_LTC2634H8,
     66	ID_LTC2636L12,
     67	ID_LTC2636L10,
     68	ID_LTC2636L8,
     69	ID_LTC2636H12,
     70	ID_LTC2636H10,
     71	ID_LTC2636H8,
     72};
     73
     74static int ltc2632_spi_write(struct spi_device *spi,
     75			     u8 cmd, u8 addr, u16 val, u8 shift)
     76{
     77	u32 data;
     78	u8 msg[3];
     79
     80	/*
     81	 * The input shift register is 24 bits wide.
     82	 * The next four are the command bits, C3 to C0,
     83	 * followed by the 4-bit DAC address, A3 to A0, and then the
     84	 * 12-, 10-, 8-bit data-word. The data-word comprises the 12-,
     85	 * 10-, 8-bit input code followed by 4, 6, or 8 don't care bits.
     86	 */
     87	data = (cmd << 20) | (addr << 16) | (val << shift);
     88	put_unaligned_be24(data, &msg[0]);
     89
     90	return spi_write(spi, msg, sizeof(msg));
     91}
     92
     93static int ltc2632_read_raw(struct iio_dev *indio_dev,
     94			    struct iio_chan_spec const *chan,
     95			    int *val,
     96			    int *val2,
     97			    long m)
     98{
     99	const struct ltc2632_state *st = iio_priv(indio_dev);
    100
    101	switch (m) {
    102	case IIO_CHAN_INFO_SCALE:
    103		*val = st->vref_mv;
    104		*val2 = chan->scan_type.realbits;
    105		return IIO_VAL_FRACTIONAL_LOG2;
    106	}
    107	return -EINVAL;
    108}
    109
    110static int ltc2632_write_raw(struct iio_dev *indio_dev,
    111			     struct iio_chan_spec const *chan,
    112			     int val,
    113			     int val2,
    114			     long mask)
    115{
    116	struct ltc2632_state *st = iio_priv(indio_dev);
    117
    118	switch (mask) {
    119	case IIO_CHAN_INFO_RAW:
    120		if (val >= (1 << chan->scan_type.realbits) || val < 0)
    121			return -EINVAL;
    122
    123		return ltc2632_spi_write(st->spi_dev,
    124					 LTC2632_CMD_WRITE_INPUT_N_UPDATE_N,
    125					 chan->address, val,
    126					 chan->scan_type.shift);
    127	default:
    128		return -EINVAL;
    129	}
    130}
    131
    132static ssize_t ltc2632_read_dac_powerdown(struct iio_dev *indio_dev,
    133					  uintptr_t private,
    134					  const struct iio_chan_spec *chan,
    135					  char *buf)
    136{
    137	struct ltc2632_state *st = iio_priv(indio_dev);
    138
    139	return sysfs_emit(buf, "%d\n",
    140			  !!(st->powerdown_cache_mask & (1 << chan->channel)));
    141}
    142
    143static ssize_t ltc2632_write_dac_powerdown(struct iio_dev *indio_dev,
    144					   uintptr_t private,
    145					   const struct iio_chan_spec *chan,
    146					   const char *buf,
    147					   size_t len)
    148{
    149	bool pwr_down;
    150	int ret;
    151	struct ltc2632_state *st = iio_priv(indio_dev);
    152
    153	ret = kstrtobool(buf, &pwr_down);
    154	if (ret)
    155		return ret;
    156
    157	if (pwr_down)
    158		st->powerdown_cache_mask |= (1 << chan->channel);
    159	else
    160		st->powerdown_cache_mask &= ~(1 << chan->channel);
    161
    162	ret = ltc2632_spi_write(st->spi_dev,
    163				LTC2632_CMD_POWERDOWN_DAC_N,
    164				chan->channel, 0, 0);
    165
    166	return ret ? ret : len;
    167}
    168
    169static const struct iio_info ltc2632_info = {
    170	.write_raw	= ltc2632_write_raw,
    171	.read_raw	= ltc2632_read_raw,
    172};
    173
    174static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
    175	{
    176		.name = "powerdown",
    177		.read = ltc2632_read_dac_powerdown,
    178		.write = ltc2632_write_dac_powerdown,
    179		.shared = IIO_SEPARATE,
    180	},
    181	{ },
    182};
    183
    184#define LTC2632_CHANNEL(_chan, _bits) { \
    185		.type = IIO_VOLTAGE, \
    186		.indexed = 1, \
    187		.output = 1, \
    188		.channel = (_chan), \
    189		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
    190		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
    191		.address = (_chan), \
    192		.scan_type = { \
    193			.realbits	= (_bits), \
    194			.shift		= 16 - (_bits), \
    195		}, \
    196		.ext_info = ltc2632_ext_info, \
    197}
    198
    199#define DECLARE_LTC2632_CHANNELS(_name, _bits) \
    200	const struct iio_chan_spec _name ## _channels[] = { \
    201		LTC2632_CHANNEL(0, _bits), \
    202		LTC2632_CHANNEL(1, _bits), \
    203		LTC2632_CHANNEL(2, _bits), \
    204		LTC2632_CHANNEL(3, _bits), \
    205		LTC2632_CHANNEL(4, _bits), \
    206		LTC2632_CHANNEL(5, _bits), \
    207		LTC2632_CHANNEL(6, _bits), \
    208		LTC2632_CHANNEL(7, _bits), \
    209	}
    210
    211static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12);
    212static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10);
    213static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8);
    214
    215static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = {
    216	[ID_LTC2632L12] = {
    217		.channels	= ltc2632x12_channels,
    218		.num_channels	= 2,
    219		.vref_mv	= 2500,
    220	},
    221	[ID_LTC2632L10] = {
    222		.channels	= ltc2632x10_channels,
    223		.num_channels	= 2,
    224		.vref_mv	= 2500,
    225	},
    226	[ID_LTC2632L8] =  {
    227		.channels	= ltc2632x8_channels,
    228		.num_channels	= 2,
    229		.vref_mv	= 2500,
    230	},
    231	[ID_LTC2632H12] = {
    232		.channels	= ltc2632x12_channels,
    233		.num_channels	= 2,
    234		.vref_mv	= 4096,
    235	},
    236	[ID_LTC2632H10] = {
    237		.channels	= ltc2632x10_channels,
    238		.num_channels	= 2,
    239		.vref_mv	= 4096,
    240	},
    241	[ID_LTC2632H8] =  {
    242		.channels	= ltc2632x8_channels,
    243		.num_channels	= 2,
    244		.vref_mv	= 4096,
    245	},
    246	[ID_LTC2634L12] = {
    247		.channels	= ltc2632x12_channels,
    248		.num_channels	= 4,
    249		.vref_mv	= 2500,
    250	},
    251	[ID_LTC2634L10] = {
    252		.channels	= ltc2632x10_channels,
    253		.num_channels	= 4,
    254		.vref_mv	= 2500,
    255	},
    256	[ID_LTC2634L8] =  {
    257		.channels	= ltc2632x8_channels,
    258		.num_channels	= 4,
    259		.vref_mv	= 2500,
    260	},
    261	[ID_LTC2634H12] = {
    262		.channels	= ltc2632x12_channels,
    263		.num_channels	= 4,
    264		.vref_mv	= 4096,
    265	},
    266	[ID_LTC2634H10] = {
    267		.channels	= ltc2632x10_channels,
    268		.num_channels	= 4,
    269		.vref_mv	= 4096,
    270	},
    271	[ID_LTC2634H8] =  {
    272		.channels	= ltc2632x8_channels,
    273		.num_channels	= 4,
    274		.vref_mv	= 4096,
    275	},
    276	[ID_LTC2636L12] = {
    277		.channels	= ltc2632x12_channels,
    278		.num_channels	= 8,
    279		.vref_mv	= 2500,
    280	},
    281	[ID_LTC2636L10] = {
    282		.channels	= ltc2632x10_channels,
    283		.num_channels	= 8,
    284		.vref_mv	= 2500,
    285	},
    286	[ID_LTC2636L8] =  {
    287		.channels	= ltc2632x8_channels,
    288		.num_channels	= 8,
    289		.vref_mv	= 2500,
    290	},
    291	[ID_LTC2636H12] = {
    292		.channels	= ltc2632x12_channels,
    293		.num_channels	= 8,
    294		.vref_mv	= 4096,
    295	},
    296	[ID_LTC2636H10] = {
    297		.channels	= ltc2632x10_channels,
    298		.num_channels	= 8,
    299		.vref_mv	= 4096,
    300	},
    301	[ID_LTC2636H8] =  {
    302		.channels	= ltc2632x8_channels,
    303		.num_channels	= 8,
    304		.vref_mv	= 4096,
    305	},
    306};
    307
    308static int ltc2632_probe(struct spi_device *spi)
    309{
    310	struct ltc2632_state *st;
    311	struct iio_dev *indio_dev;
    312	struct ltc2632_chip_info *chip_info;
    313	int ret;
    314
    315	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
    316	if (!indio_dev)
    317		return -ENOMEM;
    318
    319	st = iio_priv(indio_dev);
    320
    321	spi_set_drvdata(spi, indio_dev);
    322	st->spi_dev = spi;
    323
    324	chip_info = (struct ltc2632_chip_info *)
    325			spi_get_device_id(spi)->driver_data;
    326
    327	st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
    328	if (PTR_ERR(st->vref_reg) == -ENODEV) {
    329		/* use internal reference voltage */
    330		st->vref_reg = NULL;
    331		st->vref_mv = chip_info->vref_mv;
    332
    333		ret = ltc2632_spi_write(spi, LTC2632_CMD_INTERNAL_REFER,
    334				0, 0, 0);
    335		if (ret) {
    336			dev_err(&spi->dev,
    337				"Set internal reference command failed, %d\n",
    338				ret);
    339			return ret;
    340		}
    341	} else if (IS_ERR(st->vref_reg)) {
    342		dev_err(&spi->dev,
    343				"Error getting voltage reference regulator\n");
    344		return PTR_ERR(st->vref_reg);
    345	} else {
    346		/* use external reference voltage */
    347		ret = regulator_enable(st->vref_reg);
    348		if (ret) {
    349			dev_err(&spi->dev,
    350				"enable reference regulator failed, %d\n",
    351				ret);
    352			return ret;
    353		}
    354		st->vref_mv = regulator_get_voltage(st->vref_reg) / 1000;
    355
    356		ret = ltc2632_spi_write(spi, LTC2632_CMD_EXTERNAL_REFER,
    357				0, 0, 0);
    358		if (ret) {
    359			dev_err(&spi->dev,
    360				"Set external reference command failed, %d\n",
    361				ret);
    362			return ret;
    363		}
    364	}
    365
    366	indio_dev->name = fwnode_get_name(dev_fwnode(&spi->dev)) ?: spi_get_device_id(spi)->name;
    367	indio_dev->info = &ltc2632_info;
    368	indio_dev->modes = INDIO_DIRECT_MODE;
    369	indio_dev->channels = chip_info->channels;
    370	indio_dev->num_channels = chip_info->num_channels;
    371
    372	return iio_device_register(indio_dev);
    373}
    374
    375static void ltc2632_remove(struct spi_device *spi)
    376{
    377	struct iio_dev *indio_dev = spi_get_drvdata(spi);
    378	struct ltc2632_state *st = iio_priv(indio_dev);
    379
    380	iio_device_unregister(indio_dev);
    381
    382	if (st->vref_reg)
    383		regulator_disable(st->vref_reg);
    384}
    385
    386static const struct spi_device_id ltc2632_id[] = {
    387	{ "ltc2632-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L12] },
    388	{ "ltc2632-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L10] },
    389	{ "ltc2632-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632L8] },
    390	{ "ltc2632-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H12] },
    391	{ "ltc2632-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H10] },
    392	{ "ltc2632-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H8] },
    393	{ "ltc2634-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L12] },
    394	{ "ltc2634-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L10] },
    395	{ "ltc2634-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634L8] },
    396	{ "ltc2634-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H12] },
    397	{ "ltc2634-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H10] },
    398	{ "ltc2634-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2634H8] },
    399	{ "ltc2636-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L12] },
    400	{ "ltc2636-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L10] },
    401	{ "ltc2636-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L8] },
    402	{ "ltc2636-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H12] },
    403	{ "ltc2636-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H10] },
    404	{ "ltc2636-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H8] },
    405	{}
    406};
    407MODULE_DEVICE_TABLE(spi, ltc2632_id);
    408
    409static const struct of_device_id ltc2632_of_match[] = {
    410	{
    411		.compatible = "lltc,ltc2632-l12",
    412		.data = &ltc2632_chip_info_tbl[ID_LTC2632L12]
    413	}, {
    414		.compatible = "lltc,ltc2632-l10",
    415		.data = &ltc2632_chip_info_tbl[ID_LTC2632L10]
    416	}, {
    417		.compatible = "lltc,ltc2632-l8",
    418		.data = &ltc2632_chip_info_tbl[ID_LTC2632L8]
    419	}, {
    420		.compatible = "lltc,ltc2632-h12",
    421		.data = &ltc2632_chip_info_tbl[ID_LTC2632H12]
    422	}, {
    423		.compatible = "lltc,ltc2632-h10",
    424		.data = &ltc2632_chip_info_tbl[ID_LTC2632H10]
    425	}, {
    426		.compatible = "lltc,ltc2632-h8",
    427		.data = &ltc2632_chip_info_tbl[ID_LTC2632H8]
    428	}, {
    429		.compatible = "lltc,ltc2634-l12",
    430		.data = &ltc2632_chip_info_tbl[ID_LTC2634L12]
    431	}, {
    432		.compatible = "lltc,ltc2634-l10",
    433		.data = &ltc2632_chip_info_tbl[ID_LTC2634L10]
    434	}, {
    435		.compatible = "lltc,ltc2634-l8",
    436		.data = &ltc2632_chip_info_tbl[ID_LTC2634L8]
    437	}, {
    438		.compatible = "lltc,ltc2634-h12",
    439		.data = &ltc2632_chip_info_tbl[ID_LTC2634H12]
    440	}, {
    441		.compatible = "lltc,ltc2634-h10",
    442		.data = &ltc2632_chip_info_tbl[ID_LTC2634H10]
    443	}, {
    444		.compatible = "lltc,ltc2634-h8",
    445		.data = &ltc2632_chip_info_tbl[ID_LTC2634H8]
    446	}, {
    447		.compatible = "lltc,ltc2636-l12",
    448		.data = &ltc2632_chip_info_tbl[ID_LTC2636L12]
    449	}, {
    450		.compatible = "lltc,ltc2636-l10",
    451		.data = &ltc2632_chip_info_tbl[ID_LTC2636L10]
    452	}, {
    453		.compatible = "lltc,ltc2636-l8",
    454		.data = &ltc2632_chip_info_tbl[ID_LTC2636L8]
    455	}, {
    456		.compatible = "lltc,ltc2636-h12",
    457		.data = &ltc2632_chip_info_tbl[ID_LTC2636H12]
    458	}, {
    459		.compatible = "lltc,ltc2636-h10",
    460		.data = &ltc2632_chip_info_tbl[ID_LTC2636H10]
    461	}, {
    462		.compatible = "lltc,ltc2636-h8",
    463		.data = &ltc2632_chip_info_tbl[ID_LTC2636H8]
    464	},
    465	{}
    466};
    467MODULE_DEVICE_TABLE(of, ltc2632_of_match);
    468
    469static struct spi_driver ltc2632_driver = {
    470	.driver		= {
    471		.name	= "ltc2632",
    472		.of_match_table = ltc2632_of_match,
    473	},
    474	.probe		= ltc2632_probe,
    475	.remove		= ltc2632_remove,
    476	.id_table	= ltc2632_id,
    477};
    478module_spi_driver(ltc2632_driver);
    479
    480MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
    481MODULE_DESCRIPTION("LTC2632 DAC SPI driver");
    482MODULE_LICENSE("GPL v2");